@actuallab/rpc 12.1.115 → 12.2.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/index.cjs +1587 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +342 -25
- package/dist/index.d.ts +342 -25
- package/dist/index.js +1561 -169
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Encoder, Decoder } from '@msgpack/msgpack';
|
|
1
2
|
import { EventHandlerSet, PromiseSource, RetryDelayer } from '@actuallab/core';
|
|
2
3
|
|
|
3
4
|
/** Identifies the type of an RPC call on the wire. */
|
|
@@ -30,6 +31,29 @@ declare const ENVELOPE_DELIMITER = "\n";
|
|
|
30
31
|
declare const ARG_DELIMITER = "\u001F";
|
|
31
32
|
declare const FRAME_DELIMITER = "\n\u001E";
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Registry mapping RPC method wire names to/from their 4-byte XXH3 hashes.
|
|
36
|
+
* Hashes match .NET's RpcMethodRef.ComputeHashCode.
|
|
37
|
+
* Hashes are computed lazily on first access and cached.
|
|
38
|
+
*/
|
|
39
|
+
declare class RpcMethodRegistry {
|
|
40
|
+
private _nameToHash;
|
|
41
|
+
private _hashToName;
|
|
42
|
+
/** Register a method name and compute its hash. */
|
|
43
|
+
register(methodName: string): void;
|
|
44
|
+
/** Register all wire method names from a service definition. */
|
|
45
|
+
registerService(serviceName: string, methods: ReadonlyMap<string, {
|
|
46
|
+
name: string;
|
|
47
|
+
wireArgCount: number;
|
|
48
|
+
}>): void;
|
|
49
|
+
/** Get the hash for a method name. Computes on demand if not registered. */
|
|
50
|
+
getHash(methodName: string): number;
|
|
51
|
+
/** Get the method name for a hash. Returns undefined if not registered. */
|
|
52
|
+
getName(hash: number): string | undefined;
|
|
53
|
+
/** Get the hash for a method name, throwing if not registered. */
|
|
54
|
+
requireHash(methodName: string): number;
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
/** Serializes an RpcMessage + args into the json5 wire format. */
|
|
34
58
|
declare function serializeMessage(message: RpcMessage, args?: unknown[]): string;
|
|
35
59
|
/** Serializes multiple messages into a single WebSocket frame. */
|
|
@@ -41,11 +65,189 @@ declare function deserializeMessage(raw: string): {
|
|
|
41
65
|
message: RpcMessage;
|
|
42
66
|
args: unknown[];
|
|
43
67
|
};
|
|
68
|
+
declare const defaultBinaryEncoder: Encoder<undefined>;
|
|
69
|
+
declare const defaultBinaryDecoder: Decoder<undefined>;
|
|
70
|
+
/** Exposed so connection code can instantiate a matching Encoder
|
|
71
|
+
* with the same initial buffer size without needing to reach into
|
|
72
|
+
* this module's private constants. */
|
|
73
|
+
declare function createBinaryEncoder(): Encoder;
|
|
74
|
+
/**
|
|
75
|
+
* Serializes an RpcMessage + args into V5 binary format (msgpack6np).
|
|
76
|
+
*
|
|
77
|
+
* Layout (NO frame-level size prefix; V5 with PersistsMessageSize=false):
|
|
78
|
+
* envelope + argData
|
|
79
|
+
* Envelope:
|
|
80
|
+
* [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]
|
|
81
|
+
* [LVarSpan methodRef] [4-byte LE argLen]
|
|
82
|
+
* ArgData: concatenated MessagePack-encoded arguments
|
|
83
|
+
*
|
|
84
|
+
* Single-allocation build: pre-encodes args with the supplied reusable
|
|
85
|
+
* `Encoder`, computes the total envelope size, then writes everything
|
|
86
|
+
* into one `Uint8Array`. Eliminates the previous build's intermediate
|
|
87
|
+
* `headerParts` number array + four `Uint8Array` concats per call,
|
|
88
|
+
* which showed up as ~2% self time in the 300-pull profile and
|
|
89
|
+
* pulled the msgpack `resizeBuffer` + `Encoder` constructor along
|
|
90
|
+
* with it for another ~6%.
|
|
91
|
+
*
|
|
92
|
+
* NOTE: `@msgpack/msgpack` `Encoder.encode()` already returns a fresh
|
|
93
|
+
* copy of the internal buffer (there's a separate `encodeSharedRef()`
|
|
94
|
+
* for zero-copy access), so we can push the results straight into
|
|
95
|
+
* `argBufs` without an extra slice. The benefit of reusing the Encoder
|
|
96
|
+
* is that its internal write buffer stays at its high-water mark —
|
|
97
|
+
* once the first ~11 KB frame has grown it to the full size, no
|
|
98
|
+
* subsequent `resizeBuffer` calls are needed.
|
|
99
|
+
*/
|
|
100
|
+
declare function serializeBinaryMessage(message: RpcMessage, args?: unknown[], encoder?: Encoder): Uint8Array;
|
|
101
|
+
/**
|
|
102
|
+
* Deserializes a single V5 binary message starting at `offset`.
|
|
103
|
+
* Returns parsed message, args, and number of bytes consumed.
|
|
104
|
+
*
|
|
105
|
+
* Accepts an optional `Decoder` for reuse across calls on the same
|
|
106
|
+
* connection — avoids constructing a new `@msgpack/msgpack.Decoder`
|
|
107
|
+
* (and its internal resolver/table state) on every inbound message.
|
|
108
|
+
*/
|
|
109
|
+
declare function deserializeBinaryMessage(data: Uint8Array, offset: number, decoder?: Decoder): {
|
|
110
|
+
message: RpcMessage;
|
|
111
|
+
args: unknown[];
|
|
112
|
+
bytesRead: number;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Splits a binary WebSocket frame into individual deserialized messages.
|
|
116
|
+
* V5 envelopes are self-delimiting (header + method + argLen + argData), so
|
|
117
|
+
* multiple envelopes concatenated in a single WebSocket frame can be decoded
|
|
118
|
+
* by iterating with the bytesRead returned from deserializeBinaryMessage.
|
|
119
|
+
*
|
|
120
|
+
* This must stay symmetric with serializeBinaryFrame() (which concatenates
|
|
121
|
+
* multiple envelopes). The .NET server batches outbound RPC messages into a
|
|
122
|
+
* single WebSocket frame via WebSocketChannel/WriteDelayer, so any assumption
|
|
123
|
+
* that a frame is a single envelope silently drops every trailing message.
|
|
124
|
+
*
|
|
125
|
+
* Accepts an optional `Decoder` for reuse across calls on the same
|
|
126
|
+
* connection — forwarded to `deserializeBinaryMessage`.
|
|
127
|
+
*/
|
|
128
|
+
declare function splitBinaryFrame(frame: Uint8Array, decoder?: Decoder): Array<{
|
|
129
|
+
message: RpcMessage;
|
|
130
|
+
args: unknown[];
|
|
131
|
+
}>;
|
|
132
|
+
/**
|
|
133
|
+
* Serializes multiple binary messages into a single WebSocket frame.
|
|
134
|
+
* Simply concatenates the already size-prefixed messages.
|
|
135
|
+
*/
|
|
136
|
+
declare function serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Serializes an RpcMessage + args into V5Compact binary format.
|
|
140
|
+
* Same as V5 except the method is encoded as a 4-byte LE hash
|
|
141
|
+
* instead of an LVar-prefixed UTF-8 string.
|
|
142
|
+
*
|
|
143
|
+
* Layout:
|
|
144
|
+
* [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]
|
|
145
|
+
* [4-byte LE methodHash] [4-byte LE argLen]
|
|
146
|
+
* [argData]
|
|
147
|
+
*/
|
|
148
|
+
declare function serializeCompactBinaryMessage(message: RpcMessage, args?: unknown[], registry?: RpcMethodRegistry, encoder?: Encoder): Uint8Array;
|
|
149
|
+
/**
|
|
150
|
+
* Deserializes a single V5Compact binary message starting at `offset`.
|
|
151
|
+
* Reads a 4-byte LE method hash and resolves it via the registry.
|
|
152
|
+
*/
|
|
153
|
+
declare function deserializeCompactBinaryMessage(data: Uint8Array, offset: number, registry?: RpcMethodRegistry, decoder?: Decoder): {
|
|
154
|
+
message: RpcMessage;
|
|
155
|
+
args: unknown[];
|
|
156
|
+
bytesRead: number;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Splits a compact binary frame into individual deserialized messages.
|
|
160
|
+
*/
|
|
161
|
+
declare function splitCompactBinaryFrame(frame: Uint8Array, registry?: RpcMethodRegistry, decoder?: Decoder): Array<{
|
|
162
|
+
message: RpcMessage;
|
|
163
|
+
args: unknown[];
|
|
164
|
+
}>;
|
|
165
|
+
|
|
166
|
+
/** Parsed inbound message — result of deserialization. */
|
|
167
|
+
interface RpcDeserializedMessage {
|
|
168
|
+
message: RpcMessage;
|
|
169
|
+
args: unknown[];
|
|
170
|
+
}
|
|
171
|
+
/** Wire data produced by serialization — either text or binary. */
|
|
172
|
+
type RpcWireData = string | Uint8Array;
|
|
173
|
+
/**
|
|
174
|
+
* Base class for RPC serialization formats.
|
|
175
|
+
* Instances are immutable singletons — one per format key.
|
|
176
|
+
* State (like method registries) is passed via parameters.
|
|
177
|
+
*/
|
|
178
|
+
declare abstract class RpcSerializationFormat {
|
|
179
|
+
abstract readonly key: string;
|
|
180
|
+
abstract readonly isBinary: boolean;
|
|
181
|
+
/** Whether this format uses compact method hashes (needs RpcMethodRegistry). */
|
|
182
|
+
abstract readonly isCompact: boolean;
|
|
183
|
+
/** Serialize an outbound message. */
|
|
184
|
+
abstract serializeMessage(message: RpcMessage, args?: unknown[], encoder?: Encoder, registry?: RpcMethodRegistry): RpcWireData;
|
|
185
|
+
/** Deserialize a single text message (only called for text formats). */
|
|
186
|
+
abstract deserializeTextMessage(raw: string): RpcDeserializedMessage;
|
|
187
|
+
/** Split + deserialize a binary frame (only called for binary formats). */
|
|
188
|
+
abstract splitBinaryFrame(frame: Uint8Array, decoder?: Decoder, registry?: RpcMethodRegistry): RpcDeserializedMessage[];
|
|
189
|
+
/** Concatenate multiple serialized binary messages into one frame. */
|
|
190
|
+
abstract serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;
|
|
191
|
+
/** Create a reusable binary encoder for this format. Returns undefined for text formats. */
|
|
192
|
+
createEncoder(): Encoder | undefined;
|
|
193
|
+
/** Create a reusable binary decoder for this format. Returns undefined for text formats. */
|
|
194
|
+
createDecoder(): Decoder | undefined;
|
|
195
|
+
private static _all;
|
|
196
|
+
static register(format: RpcSerializationFormat): void;
|
|
197
|
+
static get(key: string): RpcSerializationFormat;
|
|
198
|
+
static tryGet(key: string): RpcSerializationFormat | undefined;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* JSON text format — "json5np" (System.Text.Json, no polymorphism).
|
|
202
|
+
*/
|
|
203
|
+
declare class RpcJsonSerializationFormat extends RpcSerializationFormat {
|
|
204
|
+
readonly key: string;
|
|
205
|
+
readonly isBinary = false;
|
|
206
|
+
readonly isCompact = false;
|
|
207
|
+
constructor(key: string);
|
|
208
|
+
serializeMessage(message: RpcMessage, args?: unknown[]): string;
|
|
209
|
+
deserializeTextMessage(raw: string): RpcDeserializedMessage;
|
|
210
|
+
splitBinaryFrame(): RpcDeserializedMessage[];
|
|
211
|
+
serializeBinaryFrame(): Uint8Array;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* MessagePack binary format — "msgpack6" / "mempack6" (V5 wire format).
|
|
215
|
+
*/
|
|
216
|
+
declare class RpcMessagePackSerializationFormat extends RpcSerializationFormat {
|
|
217
|
+
readonly key: string;
|
|
218
|
+
readonly isBinary = true;
|
|
219
|
+
readonly isCompact = false;
|
|
220
|
+
constructor(key: string);
|
|
221
|
+
serializeMessage(message: RpcMessage, args?: unknown[], encoder?: Encoder): Uint8Array;
|
|
222
|
+
deserializeTextMessage(raw: string): RpcDeserializedMessage;
|
|
223
|
+
splitBinaryFrame(frame: Uint8Array, decoder?: Decoder): RpcDeserializedMessage[];
|
|
224
|
+
serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;
|
|
225
|
+
createEncoder(): Encoder;
|
|
226
|
+
createDecoder(): Decoder;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* MessagePack compact binary format — "msgpack6c" / "mempack6c" (V5Compact).
|
|
230
|
+
* Uses 4-byte method hash instead of full method name.
|
|
231
|
+
* Registry is passed via parameters — format instance is immutable.
|
|
232
|
+
*/
|
|
233
|
+
declare class RpcMessagePackCompactSerializationFormat extends RpcSerializationFormat {
|
|
234
|
+
readonly key: string;
|
|
235
|
+
readonly isBinary = true;
|
|
236
|
+
readonly isCompact = true;
|
|
237
|
+
constructor(key: string);
|
|
238
|
+
serializeMessage(message: RpcMessage, args?: unknown[], encoder?: Encoder, registry?: RpcMethodRegistry): Uint8Array;
|
|
239
|
+
deserializeTextMessage(raw: string): RpcDeserializedMessage;
|
|
240
|
+
splitBinaryFrame(frame: Uint8Array, decoder?: Decoder, registry?: RpcMethodRegistry): RpcDeserializedMessage[];
|
|
241
|
+
serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;
|
|
242
|
+
createEncoder(): Encoder;
|
|
243
|
+
createDecoder(): Decoder;
|
|
244
|
+
}
|
|
44
245
|
|
|
45
246
|
/** Abstract WebSocket interface — works with both browser WebSocket and Node.js ws. */
|
|
46
247
|
interface WebSocketLike {
|
|
47
248
|
readonly readyState: number;
|
|
48
|
-
|
|
249
|
+
binaryType?: string;
|
|
250
|
+
send(data: string | ArrayBufferLike | Uint8Array | ArrayBufferView): void;
|
|
49
251
|
close(code?: number, reason?: string): void;
|
|
50
252
|
onopen: ((ev: unknown) => void) | null;
|
|
51
253
|
onmessage: ((ev: {
|
|
@@ -63,35 +265,72 @@ declare const WebSocketState: {
|
|
|
63
265
|
readonly CLOSING: 2;
|
|
64
266
|
readonly CLOSED: 3;
|
|
65
267
|
};
|
|
268
|
+
/** Received message — either text (string) or binary (already parsed). */
|
|
269
|
+
type RpcReceivedMessage = {
|
|
270
|
+
kind: 'text';
|
|
271
|
+
raw: string;
|
|
272
|
+
} | {
|
|
273
|
+
kind: 'binary';
|
|
274
|
+
message: RpcMessage;
|
|
275
|
+
args: unknown[];
|
|
276
|
+
};
|
|
66
277
|
/** Abstract RPC connection — transport-agnostic interface for sending/receiving messages. */
|
|
67
278
|
interface RpcConnection {
|
|
68
279
|
readonly isOpen: boolean;
|
|
280
|
+
readonly binaryMode: boolean;
|
|
69
281
|
readonly whenConnected: Promise<void>;
|
|
70
|
-
readonly messageReceived: EventHandlerSet<
|
|
282
|
+
readonly messageReceived: EventHandlerSet<RpcReceivedMessage>;
|
|
71
283
|
readonly closed: EventHandlerSet<{
|
|
72
284
|
code: number;
|
|
73
285
|
reason: string;
|
|
74
286
|
}>;
|
|
287
|
+
/** Optional reusable msgpack encoder for outbound binary messages.
|
|
288
|
+
* Callers passing this to `serializeBinaryMessage` skip the per-call
|
|
289
|
+
* Encoder construction + resizeBuffer growth. Implementations that
|
|
290
|
+
* don't support binary serialization can leave it undefined. */
|
|
291
|
+
readonly encoder?: Encoder;
|
|
75
292
|
send(serializedMessage: string): void;
|
|
293
|
+
sendBinary(data: Uint8Array): void;
|
|
76
294
|
close(code?: number, reason?: string): void;
|
|
77
295
|
}
|
|
78
|
-
/** WebSocket-based RpcConnection — handles frame splitting and message queueing. */
|
|
296
|
+
/** WebSocket-based RpcConnection — handles frame splitting, binary/text modes, and message queueing. */
|
|
79
297
|
declare class RpcWebSocketConnection implements RpcConnection {
|
|
80
298
|
private _ws;
|
|
81
299
|
private _sendBuffer;
|
|
82
300
|
private _connected;
|
|
83
|
-
|
|
301
|
+
/** Per-connection msgpack encoder — reused across outbound messages to
|
|
302
|
+
* amortise construction cost and to keep the internal write buffer at
|
|
303
|
+
* its largest observed size (avoids repeated `resizeBuffer` growth on
|
|
304
|
+
* large video frames). See serializeBinaryMessage() for details. */
|
|
305
|
+
private _encoder;
|
|
306
|
+
/** Per-connection msgpack decoder — reused across inbound messages
|
|
307
|
+
* rather than reconstructing one for every `decodeMulti` call. */
|
|
308
|
+
private _decoder;
|
|
309
|
+
/** Exposed for callers who need to encode outbound binary messages
|
|
310
|
+
* through this connection (e.g. `serializeBinaryMessage`). Safe to
|
|
311
|
+
* pass to synchronous encode calls on the same event-loop turn. */
|
|
312
|
+
get encoder(): Encoder;
|
|
313
|
+
get decoder(): Decoder;
|
|
314
|
+
private _format;
|
|
315
|
+
private _methodRegistry;
|
|
316
|
+
readonly binaryMode: boolean;
|
|
317
|
+
readonly messageReceived: EventHandlerSet<RpcReceivedMessage>;
|
|
84
318
|
readonly closed: EventHandlerSet<{
|
|
85
319
|
code: number;
|
|
86
320
|
reason: string;
|
|
87
321
|
}>;
|
|
88
322
|
readonly error: EventHandlerSet<unknown>;
|
|
89
|
-
constructor(ws: WebSocketLike);
|
|
323
|
+
constructor(ws: WebSocketLike, binaryMode?: boolean, format?: RpcSerializationFormat, methodRegistry?: RpcMethodRegistry);
|
|
90
324
|
get isOpen(): boolean;
|
|
91
325
|
get whenConnected(): Promise<void>;
|
|
92
326
|
send(serializedMessage: string): void;
|
|
93
|
-
|
|
327
|
+
sendBinary(data: Uint8Array): void;
|
|
328
|
+
sendTextBatch(messages: string[]): void;
|
|
329
|
+
sendBinaryBatch(messages: Uint8Array[]): void;
|
|
330
|
+
/** Split a binary frame using the format (compact-aware) or default splitter. */
|
|
331
|
+
private _splitBinary;
|
|
94
332
|
close(code?: number, reason?: string): void;
|
|
333
|
+
private _sendRaw;
|
|
95
334
|
private _flush;
|
|
96
335
|
}
|
|
97
336
|
|
|
@@ -99,7 +338,8 @@ declare class RpcWebSocketConnection implements RpcConnection {
|
|
|
99
338
|
declare class RpcMessageChannelConnection implements RpcConnection {
|
|
100
339
|
private _port;
|
|
101
340
|
private _open;
|
|
102
|
-
readonly
|
|
341
|
+
readonly binaryMode = false;
|
|
342
|
+
readonly messageReceived: EventHandlerSet<RpcReceivedMessage>;
|
|
103
343
|
readonly closed: EventHandlerSet<{
|
|
104
344
|
code: number;
|
|
105
345
|
reason: string;
|
|
@@ -108,10 +348,14 @@ declare class RpcMessageChannelConnection implements RpcConnection {
|
|
|
108
348
|
constructor(port: MessagePort);
|
|
109
349
|
get isOpen(): boolean;
|
|
110
350
|
send(serializedMessage: string): void;
|
|
351
|
+
sendBinary(data: Uint8Array): void;
|
|
111
352
|
close(code?: number, reason?: string): void;
|
|
112
353
|
}
|
|
113
354
|
/** Creates a pair of connected RpcMessageChannelConnections for testing. */
|
|
114
|
-
declare function createMessageChannelPair(): [
|
|
355
|
+
declare function createMessageChannelPair(): [
|
|
356
|
+
RpcMessageChannelConnection,
|
|
357
|
+
RpcMessageChannelConnection
|
|
358
|
+
];
|
|
115
359
|
|
|
116
360
|
/** Describes a single method on an RPC service. */
|
|
117
361
|
interface RpcMethodDef {
|
|
@@ -153,8 +397,8 @@ declare class RpcOutboundCall {
|
|
|
153
397
|
/** Whether to remove this call from the tracker on $sys.Ok. Default: true.
|
|
154
398
|
* Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */
|
|
155
399
|
readonly removeOnOk: boolean;
|
|
156
|
-
/** The serialized wire
|
|
157
|
-
|
|
400
|
+
/** The serialized wire data — stored for re-sending on reconnect. */
|
|
401
|
+
serializedWireData: string | Uint8Array;
|
|
158
402
|
constructor(callId: number, method: string);
|
|
159
403
|
/** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */
|
|
160
404
|
onDisconnect(): void;
|
|
@@ -213,20 +457,49 @@ declare class RpcServiceHost {
|
|
|
213
457
|
getMethodDef(wireMethod: string): RpcMethodDef | undefined;
|
|
214
458
|
}
|
|
215
459
|
|
|
216
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Sends system RPC messages — like .NET's RpcSystemCallSender.
|
|
462
|
+
*
|
|
463
|
+
* Hot-path allocation notes: `item`, `batch`, `ack`, and `end` are called
|
|
464
|
+
* once per stream frame (or once per ack window). Naively building a fresh
|
|
465
|
+
* `{ Method, RelatedId }` envelope object plus a fresh two-element arg array
|
|
466
|
+
* on every call showed up as ~2-4% self time + non-trivial GC pressure in
|
|
467
|
+
* the 300-pull video-load-test profile.
|
|
468
|
+
*
|
|
469
|
+
* The sender itself is a per-Hub singleton and `_send`/format.serializeMessage
|
|
470
|
+
* are fully synchronous (no awaits, no re-entrancy on a single-threaded event
|
|
471
|
+
* loop), so we reuse a small pool of preallocated envelope + arg-array slots
|
|
472
|
+
* per hot method. Mutate fields just before the send call; the encoder reads
|
|
473
|
+
* them synchronously and produces a detached copy, after which the slot is
|
|
474
|
+
* free to be mutated again on the next call.
|
|
475
|
+
*/
|
|
217
476
|
declare class RpcSystemCallSender {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
477
|
+
private readonly _itemEnv;
|
|
478
|
+
private readonly _batchEnv;
|
|
479
|
+
private readonly _endEnv;
|
|
480
|
+
private readonly _ackEnv;
|
|
481
|
+
private readonly _ackEndEnv;
|
|
482
|
+
private readonly _itemArgs;
|
|
483
|
+
private readonly _batchArgs;
|
|
484
|
+
private readonly _endArgs;
|
|
485
|
+
private readonly _ackArgs;
|
|
486
|
+
private readonly _ackEndArgs;
|
|
487
|
+
private static readonly NO_ERROR;
|
|
488
|
+
registry?: RpcMethodRegistry;
|
|
489
|
+
private _send;
|
|
490
|
+
handshake(conn: RpcConnection, format: RpcSerializationFormat, peerId: string, hubId: string, index: number): void;
|
|
491
|
+
ok(conn: RpcConnection, format: RpcSerializationFormat, relatedId: number, result: unknown): void;
|
|
492
|
+
error(conn: RpcConnection, format: RpcSerializationFormat, relatedId: number, error: unknown): void;
|
|
493
|
+
cancel(conn: RpcConnection, format: RpcSerializationFormat, relatedId: number): void;
|
|
494
|
+
keepAlive(conn: RpcConnection, format: RpcSerializationFormat, activeCallIds: number[]): void;
|
|
495
|
+
item(conn: RpcConnection, format: RpcSerializationFormat, localId: number, index: number, item: unknown): void;
|
|
496
|
+
batch(conn: RpcConnection, format: RpcSerializationFormat, localId: number, index: number, items: unknown[]): void;
|
|
497
|
+
end(conn: RpcConnection, format: RpcSerializationFormat, localId: number, index: number, error?: {
|
|
498
|
+
TypeRef: string;
|
|
226
499
|
Message: string;
|
|
227
|
-
}
|
|
228
|
-
ack(conn: RpcConnection, localId: number, nextIndex: number, hostId: string): void;
|
|
229
|
-
ackEnd(conn: RpcConnection, localId: number, hostId: string): void;
|
|
500
|
+
}): void;
|
|
501
|
+
ack(conn: RpcConnection, format: RpcSerializationFormat, localId: number, nextIndex: number, hostId: string): void;
|
|
502
|
+
ackEnd(conn: RpcConnection, format: RpcSerializationFormat, localId: number, hostId: string): void;
|
|
230
503
|
}
|
|
231
504
|
|
|
232
505
|
/** Central RPC coordinator — manages peers, services, and configuration. */
|
|
@@ -236,6 +509,9 @@ declare class RpcHub {
|
|
|
236
509
|
readonly serviceHost: RpcServiceHost;
|
|
237
510
|
readonly systemCallSender: RpcSystemCallSender;
|
|
238
511
|
systemCallHandler: RpcSystemCallHandler;
|
|
512
|
+
/** Method registry for compact format hash ↔ name resolution.
|
|
513
|
+
* Created lazily, populated by addService/addClient. */
|
|
514
|
+
readonly registry: RpcMethodRegistry;
|
|
239
515
|
constructor(hubId?: string);
|
|
240
516
|
addPeer(peer: RpcPeer): void;
|
|
241
517
|
removePeer(ref: string): void;
|
|
@@ -281,6 +557,7 @@ declare class RpcRemoteObjectTracker {
|
|
|
281
557
|
private _objects;
|
|
282
558
|
register(obj: IRpcObject): void;
|
|
283
559
|
get(localId: number): IRpcObject | undefined;
|
|
560
|
+
keys(): IterableIterator<number>;
|
|
284
561
|
unregister(obj: IRpcObject): void;
|
|
285
562
|
disconnectAll(): void;
|
|
286
563
|
reconnectAll(): void;
|
|
@@ -292,6 +569,7 @@ declare class RpcSharedObjectTracker {
|
|
|
292
569
|
nextId(): number;
|
|
293
570
|
register(obj: IRpcObject): void;
|
|
294
571
|
get(localId: number): IRpcObject | undefined;
|
|
572
|
+
keys(): IterableIterator<number>;
|
|
295
573
|
unregister(obj: IRpcObject): void;
|
|
296
574
|
disconnectAll(): void;
|
|
297
575
|
}
|
|
@@ -348,11 +626,15 @@ declare abstract class RpcPeer {
|
|
|
348
626
|
get connection(): RpcConnection | undefined;
|
|
349
627
|
get isConnected(): boolean;
|
|
350
628
|
protected setupConnection(conn: RpcConnection): void;
|
|
629
|
+
/** The serialization format used by this peer. Override in subclasses. */
|
|
630
|
+
get format(): RpcSerializationFormat;
|
|
351
631
|
call(method: string, args?: unknown[], options?: RpcCallOptions): RpcOutboundCall;
|
|
352
632
|
callNoWait(method: string, args?: unknown[]): void;
|
|
353
633
|
close(): void;
|
|
354
634
|
/** Send any messages buffered while disconnected. Call after connection + handshake are ready. */
|
|
355
635
|
protected _flushPendingSends(): void;
|
|
636
|
+
/** Send pre-serialized wire data through the current connection. */
|
|
637
|
+
protected _sendWireData(data: string | Uint8Array): void;
|
|
356
638
|
/** Override in subclasses to handle the remote peer's handshake response. */
|
|
357
639
|
protected _onHandshakeReceived(_handshake: RemoteHandshake): void;
|
|
358
640
|
private _handleMessage;
|
|
@@ -394,7 +676,9 @@ declare class RpcClientPeer extends RpcPeer {
|
|
|
394
676
|
readonly reconnectsAtChanged: EventHandlerSet<void>;
|
|
395
677
|
get reconnectsAt(): number;
|
|
396
678
|
private _setReconnectsAt;
|
|
679
|
+
private _format;
|
|
397
680
|
constructor(hub: RpcHub, url: string, serializationFormat?: string);
|
|
681
|
+
get format(): RpcSerializationFormat;
|
|
398
682
|
get connectionKind(): RpcPeerConnectionKind;
|
|
399
683
|
/** One-shot connection for tests — no reconnection loop, no handshake. */
|
|
400
684
|
connectWith(conn: RpcConnection): void;
|
|
@@ -431,6 +715,7 @@ interface RpcStreamRef {
|
|
|
431
715
|
readonly ackPeriod: number;
|
|
432
716
|
readonly ackAdvance: number;
|
|
433
717
|
readonly allowReconnect: boolean;
|
|
718
|
+
readonly isRealTime: boolean;
|
|
434
719
|
}
|
|
435
720
|
/**
|
|
436
721
|
* Parses a stream reference string of the form "{hostId},{localId},{ackPeriod},{ackAdvance}".
|
|
@@ -477,6 +762,7 @@ declare class RpcStream<T> implements AsyncIterable<T>, IRpcObject {
|
|
|
477
762
|
dispose(): void;
|
|
478
763
|
private _notifyConsumer;
|
|
479
764
|
private _maybeSendAck;
|
|
765
|
+
private static readonly _emptyGuid;
|
|
480
766
|
private _sendAck;
|
|
481
767
|
private _sendAckEnd;
|
|
482
768
|
}
|
|
@@ -504,17 +790,21 @@ declare class RpcStreamSender<T> implements IRpcObject {
|
|
|
504
790
|
readonly id: RpcObjectId;
|
|
505
791
|
readonly kind: 0;
|
|
506
792
|
readonly allowReconnect: boolean;
|
|
793
|
+
readonly isRealTime: boolean;
|
|
794
|
+
readonly canSkipTo: (item: T) => boolean;
|
|
507
795
|
readonly peer: RpcPeer;
|
|
508
796
|
readonly ackPeriod: number;
|
|
509
797
|
readonly ackAdvance: number;
|
|
510
798
|
private _nextIndex;
|
|
511
799
|
private _ended;
|
|
512
800
|
private _started;
|
|
513
|
-
|
|
801
|
+
private _lastAckedIndex;
|
|
802
|
+
private _ackWaiting;
|
|
803
|
+
constructor(peer: RpcPeer, ackPeriod?: number, ackAdvance?: number, allowReconnect?: boolean, isRealTime?: boolean, canSkipTo?: (item: T) => boolean);
|
|
514
804
|
/** Returns the stream reference string for the $sys.Ok response. */
|
|
515
805
|
toRef(): string;
|
|
516
806
|
/** Called by system call handler when $sys.Ack is received from the client. */
|
|
517
|
-
onAck(
|
|
807
|
+
onAck(nextIndex: number, _hostId: string): void;
|
|
518
808
|
/** Called by system call handler when $sys.AckEnd is received from the client. */
|
|
519
809
|
onAckEnd(_hostId: string): void;
|
|
520
810
|
/** Send a single item to the client. */
|
|
@@ -526,8 +816,15 @@ declare class RpcStreamSender<T> implements IRpcObject {
|
|
|
526
816
|
/**
|
|
527
817
|
* Consume an AsyncIterable and send all items to the client.
|
|
528
818
|
* Waits for the client's initial Ack before starting to pump items.
|
|
819
|
+
*
|
|
820
|
+
* When `isRealTime` is true, applies flow control based on `ackAdvance`:
|
|
821
|
+
* if the sender is `ackAdvance` items ahead of the last ACK, it enters
|
|
822
|
+
* skip mode — draining the source and discarding items until it finds
|
|
823
|
+
* one where `canSkipTo` returns true.
|
|
529
824
|
*/
|
|
530
825
|
writeFrom(source: AsyncIterable<T>): Promise<void>;
|
|
826
|
+
/** Wait until _nextIndex < _lastAckedIndex + ackAdvance. */
|
|
827
|
+
private _waitForAckBudget;
|
|
531
828
|
reconnect(): void;
|
|
532
829
|
disconnect(): void;
|
|
533
830
|
}
|
|
@@ -596,4 +893,24 @@ declare class RpcPeerStateMonitor {
|
|
|
596
893
|
private _scheduleRecompute;
|
|
597
894
|
}
|
|
598
895
|
|
|
599
|
-
|
|
896
|
+
/**
|
|
897
|
+
* Compute XXH3-64 hash of a byte array. Returns a BigInt (unsigned 64-bit).
|
|
898
|
+
* Pure TypeScript, synchronous, supports any input length.
|
|
899
|
+
*/
|
|
900
|
+
declare function xxh3_64(input: Uint8Array, seed?: bigint): bigint;
|
|
901
|
+
/**
|
|
902
|
+
* Compute XXH3-64 hash of a UTF-8 string. Returns a BigInt (unsigned 64-bit).
|
|
903
|
+
*/
|
|
904
|
+
declare function xxh3_64str(input: string, seed?: bigint): bigint;
|
|
905
|
+
/**
|
|
906
|
+
* Compute the RPC method hash matching .NET's RpcMethodRef.ComputeHashCode.
|
|
907
|
+
* Returns a 32-bit signed integer (lower 32 bits of XXH3-64 of [prefix + utf8Name]).
|
|
908
|
+
*
|
|
909
|
+
* The prefix is uint32 LE of (67211 * utf8Name.length), which ensures methods
|
|
910
|
+
* with different name lengths but similar text produce different hashes.
|
|
911
|
+
*
|
|
912
|
+
* Computed on demand — caller should cache the result per method name.
|
|
913
|
+
*/
|
|
914
|
+
declare function computeMethodHash(methodName: string): number;
|
|
915
|
+
|
|
916
|
+
export { ARG_DELIMITER, DEFAULT_SERIALIZATION_FORMAT, ENVELOPE_DELIMITER, FRAME_DELIMITER, type IRpcObject, type MethodMeta, RPC_CLOSE_CODE_UNSUPPORTED_FORMAT, type RemoteHandshake, type RpcCallOptions, RpcCallTypeId, RpcClientPeer, RpcClientPeerReconnectDelayer, type RpcConnection, type RpcConnectionUrlResolver, type RpcDeserializedMessage, type RpcDispatchContext, RpcHub, RpcInboundCall, RpcInboundCallTracker, RpcJsonSerializationFormat, type RpcMessage, RpcMessageChannelConnection, RpcMessagePackCompactSerializationFormat, RpcMessagePackSerializationFormat, type RpcMethodDef, type RpcMethodDefInput, RpcMethodRegistry, type RpcObjectId, RpcObjectKind, RpcOutboundCall, RpcOutboundCallTracker, RpcPeer, RpcPeerConnectionKind, type RpcPeerState, RpcPeerStateKind, RpcPeerStateMonitor, type RpcReceivedMessage, RpcRemoteObjectTracker, RpcSerializationFormat, RpcServerPeer, type RpcServiceDef, RpcServiceHost, type RpcServiceImpl, RpcSharedObjectTracker, RpcStream, type RpcStreamRef, RpcStreamSender, RpcSystemCallHandler, RpcSystemCallSender, RpcSystemCalls, RpcType, RpcWebSocketConnection, type RpcWireData, type ServiceMeta, type WebSocketLike, type WebSocketServer, WebSocketState, computeMethodHash, createBinaryEncoder, createMessageChannelPair, createRpcClient, defaultBinaryDecoder, defaultBinaryEncoder, defaultConnectionUrlResolver, defineRpcService, deserializeBinaryMessage, deserializeCompactBinaryMessage, deserializeMessage, getMethodsMeta, getServiceMeta, getStateDescription, isConnected, likelyConnected, parseStreamRef, resolveStreamRefs, rpcMethod, rpcService, serializeBinaryFrame, serializeBinaryMessage, serializeCompactBinaryMessage, serializeFrame, serializeMessage, splitBinaryFrame, splitCompactBinaryFrame, splitFrame, wireMethodName, xxh3_64, xxh3_64str };
|