@cortexkit/subc-client 0.12.0 → 0.13.1
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/client.d.ts +13 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +105 -10
- package/dist/client.js.map +1 -1
- package/dist/envelope.d.ts +1 -0
- package/dist/envelope.d.ts.map +1 -1
- package/dist/envelope.js +2 -1
- package/dist/envelope.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/route-handle.d.ts +32 -1
- package/dist/route-handle.d.ts.map +1 -1
- package/dist/route-handle.js +61 -5
- package/dist/route-handle.js.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +171 -11
- package/src/envelope.ts +2 -1
- package/src/index.ts +9 -1
- package/src/route-handle.ts +89 -6
package/src/route-handle.ts
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
1
|
const connectionToken = new WeakMap<RouteHandle, object>();
|
|
2
|
+
const reverseRequests = new WeakMap<RouteHandle, ReverseRequestRegistry>();
|
|
3
|
+
|
|
4
|
+
export interface ReverseRequestContext {
|
|
5
|
+
readonly corr: bigint;
|
|
6
|
+
readonly method: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ReverseRequestHandler = (
|
|
10
|
+
body: Uint8Array,
|
|
11
|
+
ctx: ReverseRequestContext,
|
|
12
|
+
) => Promise<Uint8Array> | Uint8Array;
|
|
13
|
+
|
|
14
|
+
/** A reverse-request registration cannot add a capability after route.open declared its set. */
|
|
15
|
+
export class ReverseRequestRegistrationError extends Error {
|
|
16
|
+
readonly code = "reverse_request_capability_not_declared";
|
|
17
|
+
|
|
18
|
+
constructor(readonly methodFamily: string) {
|
|
19
|
+
super(`reverse-request capability ${JSON.stringify(methodFamily)} was not registered before route.open`);
|
|
20
|
+
this.name = "ReverseRequestRegistrationError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Mutable handler registry prepared before route.open. The client derives
|
|
26
|
+
* consumer_capabilities from its method families and seals that set when the
|
|
27
|
+
* route opens; handlers for declared families may still be replaced afterward.
|
|
28
|
+
*/
|
|
29
|
+
export class ReverseRequestRegistry {
|
|
30
|
+
private readonly handlers = new Map<string, ReverseRequestHandler>();
|
|
31
|
+
private declaredFamilies: ReadonlySet<string> | null = null;
|
|
32
|
+
|
|
33
|
+
onRequest(methodFamily: string, handler: ReverseRequestHandler): void {
|
|
34
|
+
if (!isMethodFamily(methodFamily)) {
|
|
35
|
+
throw new TypeError(`reverse-request method family must be a capability identifier, got ${JSON.stringify(methodFamily)}`);
|
|
36
|
+
}
|
|
37
|
+
if (typeof handler !== "function") throw new TypeError("reverse-request handler must be a function");
|
|
38
|
+
if (this.declaredFamilies && !this.declaredFamilies.has(methodFamily)) {
|
|
39
|
+
throw new ReverseRequestRegistrationError(methodFamily);
|
|
40
|
+
}
|
|
41
|
+
this.handlers.set(methodFamily, handler);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** @internal */
|
|
45
|
+
capabilities(): string[] {
|
|
46
|
+
return [...this.handlers.keys()].sort();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @internal */
|
|
50
|
+
handler(methodFamily: string): ReverseRequestHandler | undefined {
|
|
51
|
+
return this.handlers.get(methodFamily);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** @internal */
|
|
55
|
+
seal(): void {
|
|
56
|
+
this.declaredFamilies ??= new Set(this.handlers.keys());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
2
59
|
|
|
3
60
|
/**
|
|
4
61
|
* Immutable identity for one route binding on one live socket. Only channel and
|
|
@@ -8,7 +65,7 @@ export class RouteHandle {
|
|
|
8
65
|
readonly channel: number;
|
|
9
66
|
readonly epoch: number;
|
|
10
67
|
|
|
11
|
-
private constructor(channel: number, epoch: number, token: object) {
|
|
68
|
+
private constructor(channel: number, epoch: number, token: object, registry: ReverseRequestRegistry) {
|
|
12
69
|
if (!Number.isInteger(channel) || channel <= 0 || channel > 0xffff) {
|
|
13
70
|
throw new RangeError(`route channel must be an integer in 1..65535, got ${channel}`);
|
|
14
71
|
}
|
|
@@ -17,21 +74,47 @@ export class RouteHandle {
|
|
|
17
74
|
}
|
|
18
75
|
this.channel = channel;
|
|
19
76
|
this.epoch = epoch;
|
|
77
|
+
registry.seal();
|
|
20
78
|
connectionToken.set(this, token);
|
|
79
|
+
reverseRequests.set(this, registry);
|
|
21
80
|
Object.freeze(this);
|
|
22
81
|
}
|
|
23
82
|
|
|
24
|
-
|
|
25
|
-
|
|
83
|
+
/** Replace the handler for a capability declared when this route opened. */
|
|
84
|
+
onRequest(methodFamily: string, handler: ReverseRequestHandler): void {
|
|
85
|
+
reverseRequests.get(this)!.onRequest(methodFamily, handler);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private static create(
|
|
89
|
+
channel: number,
|
|
90
|
+
epoch: number,
|
|
91
|
+
token: object,
|
|
92
|
+
registry: ReverseRequestRegistry,
|
|
93
|
+
): RouteHandle {
|
|
94
|
+
return new RouteHandle(channel, epoch, token, registry);
|
|
26
95
|
}
|
|
27
96
|
}
|
|
28
97
|
|
|
29
98
|
/** @internal SDK factory; not re-exported from the package surface. */
|
|
30
|
-
export function createRouteHandle(
|
|
99
|
+
export function createRouteHandle(
|
|
100
|
+
channel: number,
|
|
101
|
+
epoch: number,
|
|
102
|
+
token: object,
|
|
103
|
+
registry = new ReverseRequestRegistry(),
|
|
104
|
+
): RouteHandle {
|
|
31
105
|
const factory = RouteHandle as unknown as {
|
|
32
|
-
create(channel: number, epoch: number, token: object): RouteHandle;
|
|
106
|
+
create(channel: number, epoch: number, token: object, registry: ReverseRequestRegistry): RouteHandle;
|
|
33
107
|
};
|
|
34
|
-
return factory.create(channel, epoch, token);
|
|
108
|
+
return factory.create(channel, epoch, token, registry);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @internal */
|
|
112
|
+
export function reverseRequestHandler(handle: RouteHandle, methodFamily: string): ReverseRequestHandler | undefined {
|
|
113
|
+
return reverseRequests.get(handle)?.handler(methodFamily);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isMethodFamily(value: string): boolean {
|
|
117
|
+
return /^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(value);
|
|
35
118
|
}
|
|
36
119
|
|
|
37
120
|
/** A route handle belongs to another connection or is no longer installed. */
|