@actuallab/rpc 12.3.6 → 12.3.14

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rpc-message.ts","../src/rpc-serialization.ts","../src/rpc-connection.ts","../src/rpc-message-channel-connection.ts","../src/rpc-service-def.ts","../src/rpc-call-tracker.ts","../src/rpc-stream.ts","../src/rpc-object.ts","../src/rpc-stream-sender.ts","../src/rpc-system-call-handler.ts","../src/rpc-system-call-sender.ts","../src/rpc-remote-object-tracker.ts","../src/rpc-shared-object-tracker.ts","../src/rpc-peer.ts","../src/rpc-client-peer-reconnect-delayer.ts","../src/rpc-serialization-format.ts","../src/rpc-service-host.ts","../src/rpc-decorators.ts","../src/rpc-xxhash3.ts","../src/rpc-method-registry.ts","../src/rpc-hub.ts","../src/rpc-client.ts","../src/rpc-peer-state.ts","../src/rpc-peer-state-monitor.ts"],"sourcesContent":["// .NET counterparts:\r\n// RpcMessage — .NET has no single \"message\" type; the wire format is built by\r\n// RpcMessageSerializer / RpcOutboundMessage / RpcInboundMessage. In .NET the\r\n// envelope carries MethodRef, RelatedId, Headers, CallTypeId, and serialized\r\n// argument data as binary or text segments. In TS we use a simpler JSON\r\n// envelope + delimiter-separated args.\r\n//\r\n// Omitted from .NET:\r\n// - RpcCallTypeId Reliable (stage-based reconnection protocol) — the TS client\r\n// is browser-only; reconnection replays entire calls rather than resuming at\r\n// a stage, so Reliable call type adds no value.\r\n// - RpcHeader / RpcHeaders — .NET passes typed header arrays on every message\r\n// (Hash, ActivityContext, etc.). TS has no RPC caching, OpenTelemetry\r\n// propagation, or middleware pipeline, so headers aren't needed yet. The\r\n// Headers field on RpcMessage is reserved for future use.\r\n// - $sys.M (Match) / $sys.NotFound / $sys.Disconnect / Stream calls\r\n// (Ack, AckEnd, I, B, End) — Match is for hash-based response caching\r\n// (bandwidth optimisation); NotFound is a server-side \"service not registered\"\r\n// response; Disconnect is for RpcSharedObject lifetime management; the stream\r\n// calls are for RpcStream (server→client IAsyncEnumerable). None of these\r\n// are needed in the TS client today because:\r\n// * No response caching → no Match.\r\n// * Service-not-found is sent as $sys.Error.\r\n// * No shared-object tracking (server-side concept) → no Disconnect.\r\n// * No RpcStream yet → no Ack/AckEnd/I/B/End.\r\n// They can be added when streaming or caching is ported.\r\n// - Binary serialization variants (RpcByteMessageSerializer) — TS uses\r\n// text (JSON) exclusively; binary MessagePack/MemoryPack require native\r\n// codecs that aren't available in browsers.\r\n\r\n/** Identifies the type of an RPC call on the wire. */\r\nexport const enum RpcCallTypeId {\r\n Regular = 0,\r\n Reliable = 1,\r\n}\r\n\r\n/** Identifies system call methods — names include :argCount suffix for .NET interop. */\r\nexport const RpcSystemCalls = {\r\n handshake: '$sys.Handshake:1',\r\n ok: '$sys.Ok:1',\r\n error: '$sys.Error:1',\r\n cancel: '$sys.Cancel:0',\r\n keepAlive: '$sys.KeepAlive:1',\r\n reconnect: '$sys.Reconnect:3',\r\n ack: '$sys.Ack:2',\r\n ackEnd: '$sys.AckEnd:1',\r\n item: '$sys.I:2',\r\n batch: '$sys.B:2',\r\n end: '$sys.End:2',\r\n} as const;\r\n\r\n/** Wire-format RPC message envelope. */\r\nexport interface RpcMessage {\r\n CallType?: number;\r\n RelatedId?: number;\r\n Method?: string;\r\n Headers?: unknown[];\r\n}\r\n\r\n// Delimiters used in the wire format\r\nexport const ENVELOPE_DELIMITER = '\\n'; // \\x0A between envelope and args\r\nexport const ARG_DELIMITER = '\\x1F'; // Unit Separator between args\r\nexport const FRAME_DELIMITER = '\\n\\x1E'; // \\x0A\\x1E between messages in a frame\r\n","// Serialization for the RPC wire format.\r\n//\r\n// Supports two formats:\r\n// - Text (json5np): JSON envelope + delimiter-separated JSON args (V3 wire format)\r\n// - Binary (msgpack6np): V5 binary envelope + MessagePack-encoded args\r\n//\r\n// The format is selected at connection time via the `f=` query parameter.\r\n\r\nimport {\r\n decode as _msgpackDecode,\r\n Encoder,\r\n Decoder,\r\n type DecodeOptions,\r\n} from '@msgpack/msgpack';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport {\r\n ENVELOPE_DELIMITER,\r\n ARG_DELIMITER,\r\n FRAME_DELIMITER,\r\n} from './rpc-message.js';\r\n\r\n// ============================================================\r\n// Text format (json5np) — V3 wire format\r\n// ============================================================\r\n\r\n/** Serializes an RpcMessage + args into the json5 wire format. */\r\nexport function serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[]\r\n): string {\r\n const envelope = JSON.stringify(message);\r\n if (args === undefined || args.length === 0) {\r\n return envelope + ENVELOPE_DELIMITER;\r\n }\r\n const argsStr = args.map(a => JSON.stringify(a)).join(ARG_DELIMITER);\r\n return envelope + ENVELOPE_DELIMITER + argsStr;\r\n}\r\n\r\n/** Serializes multiple messages into a single WebSocket frame. */\r\nexport function serializeFrame(messages: string[]): string {\r\n return messages.join(FRAME_DELIMITER);\r\n}\r\n\r\n/** Splits a WebSocket text frame into individual message strings. */\r\nexport function splitFrame(frame: string): string[] {\r\n return frame.split(FRAME_DELIMITER);\r\n}\r\n\r\n/** Deserializes a single message string into envelope + args. */\r\nexport function deserializeMessage(raw: string): {\r\n message: RpcMessage;\r\n args: unknown[];\r\n} {\r\n const nlIndex = raw.indexOf(ENVELOPE_DELIMITER);\r\n if (nlIndex === -1) {\r\n return { message: JSON.parse(raw) as RpcMessage, args: [] };\r\n }\r\n\r\n const envelopeStr = raw.substring(0, nlIndex);\r\n const argsStr = raw.substring(nlIndex + 1);\r\n const message = JSON.parse(envelopeStr) as RpcMessage;\r\n\r\n if (argsStr.length === 0) {\r\n return { message, args: [] };\r\n }\r\n\r\n const args = argsStr.split(ARG_DELIMITER).map(s => {\r\n try {\r\n return JSON.parse(s) as unknown;\r\n } catch {\r\n console.warn(\r\n `[RpcSerialization] failed to parse arg as JSON: ${s.substring(0, 100)}`\r\n );\r\n return s; // Return raw string if not valid JSON\r\n }\r\n });\r\n\r\n return { message, args };\r\n}\r\n\r\n// ============================================================\r\n// Binary format (msgpack6np) — V5 wire format\r\n// ============================================================\r\n\r\n// MessagePack decode options\r\nconst _msgpackDecodeOptions: DecodeOptions = {};\r\n\r\nconst textEncoder = new TextEncoder();\r\nconst textDecoder = new TextDecoder();\r\n\r\n/**\r\n * Default module-level encoder/decoder. RpcWebSocketConnection passes its own\r\n * per-connection instances for the hot path; these defaults cover callers\r\n * that don't bother (tests, one-shot uses).\r\n *\r\n * Reusing an Encoder across calls is critical at high message rates because\r\n * - construction cost (internal resolvers, buffer allocation) is nontrivial;\r\n * - the internal write buffer stays at its largest observed size after the\r\n * first few encodes, eliminating `resizeBuffer` growth churn (which was\r\n * ~5% self time in the 300-pull profile).\r\n *\r\n * NOT thread-safe and NOT re-entrant. Safe under Node's single-threaded event\r\n * loop as long as `serializeBinaryMessage` is called synchronously (which it\r\n * always is — no awaits inside).\r\n *\r\n * The `@msgpack/msgpack` Encoder constructor takes positional args:\r\n * (extensionCodec, context, maxDepth, initialBufferSize, sortKeys, ...)\r\n * We only need initialBufferSize here — set large enough to fit a typical\r\n * video frame (~11 KB) + envelope overhead without any resizeBuffer growth.\r\n */\r\nconst INITIAL_ENCODER_BUFFER_SIZE = 32 * 1024;\r\nexport const defaultBinaryEncoder = new Encoder(\r\n undefined,\r\n undefined,\r\n undefined,\r\n INITIAL_ENCODER_BUFFER_SIZE\r\n);\r\nexport const defaultBinaryDecoder = new Decoder();\r\n/** Exposed so connection code can instantiate a matching Encoder\r\n * with the same initial buffer size without needing to reach into\r\n * this module's private constants. */\r\nexport function createBinaryEncoder(): Encoder {\r\n return new Encoder(\r\n undefined,\r\n undefined,\r\n undefined,\r\n INITIAL_ENCODER_BUFFER_SIZE\r\n );\r\n}\r\n\r\n// --- LEB128 VarUInt helpers ---\r\n\r\n/** Number of bytes a VarUint encoding of `value` will occupy. */\r\nfunction varUintByteLen(value: number): number {\r\n if (value < 0) value = 0;\r\n let n = 0;\r\n do {\r\n n++;\r\n value >>>= 7;\r\n } while (value > 0);\r\n return n;\r\n}\r\n\r\n/** Write VarUint directly into a `Uint8Array` at `pos`. Returns new pos. */\r\nfunction writeVarUintInto(out: Uint8Array, pos: number, value: number): number {\r\n if (value < 0) value = 0;\r\n do {\r\n let byte = value & 0x7f;\r\n value >>>= 7;\r\n if (value > 0) byte |= 0x80;\r\n out[pos++] = byte;\r\n } while (value > 0);\r\n return pos;\r\n}\r\n\r\nfunction readVarUint(\r\n data: Uint8Array,\r\n offset: number\r\n): { value: number; bytesRead: number } {\r\n let value = 0,\r\n shift = 0,\r\n bytesRead = 0;\r\n do {\r\n if (offset + bytesRead >= data.length) break;\r\n const byte = data[offset + bytesRead];\r\n value |= (byte & 0x7f) << shift;\r\n bytesRead++;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n } while (shift < 35); // Max 5 bytes for uint32\r\n return { value: value >>> 0, bytesRead };\r\n}\r\n\r\n// --- Binary helpers ---\r\n\r\nfunction concatUint8Arrays(arrays: Uint8Array[]): Uint8Array {\r\n let totalLength = 0;\r\n for (const arr of arrays) totalLength += arr.length;\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Serializes an RpcMessage + args into V5 binary format (msgpack6np).\r\n *\r\n * Layout (NO frame-level size prefix; V5 with PersistsMessageSize=false):\r\n * envelope + argData\r\n * Envelope:\r\n * [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]\r\n * [LVarSpan methodRef] [4-byte LE argLen]\r\n * ArgData: concatenated MessagePack-encoded arguments\r\n *\r\n * Single-allocation build: pre-encodes args with the supplied reusable\r\n * `Encoder`, computes the total envelope size, then writes everything\r\n * into one `Uint8Array`. Eliminates the previous build's intermediate\r\n * `headerParts` number array + four `Uint8Array` concats per call,\r\n * which showed up as ~2% self time in the 300-pull profile and\r\n * pulled the msgpack `resizeBuffer` + `Encoder` constructor along\r\n * with it for another ~6%.\r\n *\r\n * NOTE: `@msgpack/msgpack` `Encoder.encode()` already returns a fresh\r\n * copy of the internal buffer (there's a separate `encodeSharedRef()`\r\n * for zero-copy access), so we can push the results straight into\r\n * `argBufs` without an extra slice. The benefit of reusing the Encoder\r\n * is that its internal write buffer stays at its high-water mark —\r\n * once the first ~11 KB frame has grown it to the full size, no\r\n * subsequent `resizeBuffer` calls are needed.\r\n */\r\nexport function serializeBinaryMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder: Encoder = defaultBinaryEncoder\r\n): Uint8Array {\r\n // 1. Encode each arg. encode() returns a fresh Uint8Array copy per\r\n // call, so the results are safe to retain across subsequent encodes.\r\n let argsDataLen = 0;\r\n let argBufs: Uint8Array[] | null = null;\r\n if (args && args.length > 0) {\r\n argBufs = new Array<Uint8Array>(args.length);\r\n for (let i = 0; i < args.length; i++) {\r\n const buf = encoder.encode(args[i]);\r\n argBufs[i] = buf;\r\n argsDataLen += buf.length;\r\n }\r\n }\r\n\r\n // 2. Compute header sizes without intermediate allocations.\r\n const callType = message.CallType ?? 0;\r\n const relatedId = message.RelatedId ?? 0;\r\n const methodBytes = textEncoder.encode(message.Method ?? '');\r\n const relatedIdLen = varUintByteLen(relatedId);\r\n const methodLenVarintLen = varUintByteLen(methodBytes.length);\r\n const headerSize =\r\n 1 + relatedIdLen + methodLenVarintLen + methodBytes.length;\r\n const totalSize = headerSize + 4 + argsDataLen;\r\n\r\n // 3. Allocate the final wire buffer once and fill it in place.\r\n const out = new Uint8Array(totalSize);\r\n let pos = 0;\r\n out[pos++] = (callType << 5) & 0xe0;\r\n pos = writeVarUintInto(out, pos, relatedId);\r\n pos = writeVarUintInto(out, pos, methodBytes.length);\r\n out.set(methodBytes, pos);\r\n pos += methodBytes.length;\r\n // argLen as int32 LE\r\n out[pos++] = argsDataLen & 0xff;\r\n out[pos++] = (argsDataLen >>> 8) & 0xff;\r\n out[pos++] = (argsDataLen >>> 16) & 0xff;\r\n out[pos++] = (argsDataLen >>> 24) & 0xff;\r\n if (argBufs !== null) {\r\n for (const buf of argBufs) {\r\n out.set(buf, pos);\r\n pos += buf.length;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Deserializes a single V5 binary message starting at `offset`.\r\n * Returns parsed message, args, and number of bytes consumed.\r\n *\r\n * Accepts an optional `Decoder` for reuse across calls on the same\r\n * connection — avoids constructing a new `@msgpack/msgpack.Decoder`\r\n * (and its internal resolver/table state) on every inbound message.\r\n */\r\nexport function deserializeBinaryMessage(\r\n data: Uint8Array,\r\n offset: number,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[]; bytesRead: number } {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // V5: no frame-level size prefix. Parse envelope directly.\r\n let pos = offset;\r\n\r\n // Byte 0: upper 3 bits = CallTypeId, lower 5 bits = HeaderCount\r\n const byte0 = data[pos++];\r\n const callTypeId = (byte0 >> 5) & 0x7;\r\n const headerCount = byte0 & 0x1f;\r\n\r\n // RelatedId as VarUint\r\n const relId = readVarUint(data, pos);\r\n pos += relId.bytesRead;\r\n\r\n // MethodRef as LVarSpan\r\n const methodLen = readVarUint(data, pos);\r\n pos += methodLen.bytesRead;\r\n const methodBytes = data.subarray(pos, pos + methodLen.value);\r\n const method = textDecoder.decode(methodBytes);\r\n pos += methodLen.value;\r\n\r\n // ArgData length as fixed 4-byte LE\r\n const argDataLen = view.getInt32(pos, true);\r\n pos += 4;\r\n\r\n // Skip headers (if any — TS client doesn't use them)\r\n if (headerCount > 0) {\r\n for (let h = 0; h < headerCount; h++) {\r\n // L1Memory: 1-byte length prefix + key bytes\r\n const keyLen = data[pos++];\r\n pos += keyLen;\r\n // LVarSpan: VarUint length + value bytes\r\n const valLen = readVarUint(data, pos);\r\n pos += valLen.bytesRead + valLen.value;\r\n }\r\n }\r\n\r\n // Deserialize arguments from argData — multiple concatenated MessagePack values\r\n const args: unknown[] = [];\r\n const argEnd = pos + argDataLen;\r\n if (argDataLen > 0) {\r\n const argSlice = data.subarray(pos, argEnd);\r\n // Reuse the provided decoder across calls; `decodeMulti` is a generator\r\n // so each yield completes before the next `decode` begins, which is\r\n // safe on a single-threaded event loop.\r\n for (const decoded of decoder.decodeMulti(argSlice)) {\r\n args.push(decoded);\r\n }\r\n pos = argEnd;\r\n }\r\n\r\n const message: RpcMessage = {\r\n Method: method,\r\n RelatedId: relId.value,\r\n CallType: callTypeId,\r\n };\r\n\r\n return { message, args, bytesRead: pos - offset };\r\n}\r\n\r\n/**\r\n * Splits a binary WebSocket frame into individual deserialized messages.\r\n * V5 envelopes are self-delimiting (header + method + argLen + argData), so\r\n * multiple envelopes concatenated in a single WebSocket frame can be decoded\r\n * by iterating with the bytesRead returned from deserializeBinaryMessage.\r\n *\r\n * This must stay symmetric with serializeBinaryFrame() (which concatenates\r\n * multiple envelopes). The .NET server batches outbound RPC messages into a\r\n * single WebSocket frame via WebSocketChannel/WriteDelayer, so any assumption\r\n * that a frame is a single envelope silently drops every trailing message.\r\n *\r\n * Accepts an optional `Decoder` for reuse across calls on the same\r\n * connection — forwarded to `deserializeBinaryMessage`.\r\n */\r\nexport function splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[] }[] {\r\n const results: { message: RpcMessage; args: unknown[] }[] = [];\r\n let offset = 0;\r\n while (offset < frame.length) {\r\n const { message, args, bytesRead } = deserializeBinaryMessage(\r\n frame,\r\n offset,\r\n decoder\r\n );\r\n if (bytesRead <= 0) break; // defensive — avoid infinite loop on malformed data\r\n results.push({ message, args });\r\n offset += bytesRead;\r\n }\r\n return results;\r\n}\r\n\r\n/**\r\n * Serializes multiple binary messages into a single WebSocket frame.\r\n * Simply concatenates the already size-prefixed messages.\r\n */\r\nexport function serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return concatUint8Arrays(messages);\r\n}\r\n\r\n// ============================================================\r\n// Compact binary format (V5Compact) — 4-byte method hash\r\n// ============================================================\r\n\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/**\r\n * Serializes an RpcMessage + args into V5Compact binary format.\r\n * Same as V5 except the method is encoded as a 4-byte LE hash\r\n * instead of an LVar-prefixed UTF-8 string.\r\n *\r\n * Layout:\r\n * [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]\r\n * [4-byte LE methodHash] [4-byte LE argLen]\r\n * [argData]\r\n */\r\nexport function serializeCompactBinaryMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n registry?: RpcMethodRegistry,\r\n encoder: Encoder = defaultBinaryEncoder\r\n): Uint8Array {\r\n // 1. Encode args\r\n let argsDataLen = 0;\r\n let argBufs: Uint8Array[] | null = null;\r\n if (args && args.length > 0) {\r\n argBufs = new Array<Uint8Array>(args.length);\r\n for (let i = 0; i < args.length; i++) {\r\n const buf = encoder.encode(args[i]);\r\n argBufs[i] = buf;\r\n argsDataLen += buf.length;\r\n }\r\n }\r\n\r\n // 2. Get method hash\r\n const methodName = message.Method ?? '';\r\n const methodHash = registry?.requireHash(methodName) ?? 0;\r\n\r\n // 3. Compute sizes\r\n const callType = message.CallType ?? 0;\r\n const relatedId = message.RelatedId ?? 0;\r\n const relatedIdLen = varUintByteLen(relatedId);\r\n // Compact: 4 bytes for hash (instead of LVar method name)\r\n const headerSize = 1 + relatedIdLen + 4;\r\n const totalSize = headerSize + 4 + argsDataLen;\r\n\r\n // 4. Build wire buffer\r\n const out = new Uint8Array(totalSize);\r\n let pos = 0;\r\n out[pos++] = (callType << 5) & 0xe0;\r\n pos = writeVarUintInto(out, pos, relatedId);\r\n // Method hash as 4-byte LE uint32\r\n const hashU32 = methodHash >>> 0;\r\n out[pos++] = hashU32 & 0xff;\r\n out[pos++] = (hashU32 >>> 8) & 0xff;\r\n out[pos++] = (hashU32 >>> 16) & 0xff;\r\n out[pos++] = (hashU32 >>> 24) & 0xff;\r\n // argLen as int32 LE\r\n out[pos++] = argsDataLen & 0xff;\r\n out[pos++] = (argsDataLen >>> 8) & 0xff;\r\n out[pos++] = (argsDataLen >>> 16) & 0xff;\r\n out[pos++] = (argsDataLen >>> 24) & 0xff;\r\n if (argBufs !== null) {\r\n for (const buf of argBufs) {\r\n out.set(buf, pos);\r\n pos += buf.length;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Deserializes a single V5Compact binary message starting at `offset`.\r\n * Reads a 4-byte LE method hash and resolves it via the registry.\r\n */\r\nexport function deserializeCompactBinaryMessage(\r\n data: Uint8Array,\r\n offset: number,\r\n registry?: RpcMethodRegistry,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[]; bytesRead: number } {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n let pos = offset;\r\n\r\n // Byte 0: upper 3 bits = CallTypeId, lower 5 bits = HeaderCount\r\n const byte0 = data[pos++];\r\n const callTypeId = (byte0 >> 5) & 0x7;\r\n const headerCount = byte0 & 0x1f;\r\n\r\n // RelatedId as VarUint\r\n const relId = readVarUint(data, pos);\r\n pos += relId.bytesRead;\r\n\r\n // Method hash as fixed 4-byte LE uint32\r\n const methodHash = view.getUint32(pos, true);\r\n pos += 4;\r\n const method =\r\n registry?.getName(methodHash | 0) ??\r\n `<hash:0x${methodHash.toString(16).padStart(8, '0')}>`;\r\n\r\n // ArgData length as fixed 4-byte LE\r\n const argDataLen = view.getInt32(pos, true);\r\n pos += 4;\r\n\r\n // Skip headers (if any)\r\n if (headerCount > 0) {\r\n for (let h = 0; h < headerCount; h++) {\r\n const keyLen = data[pos++];\r\n pos += keyLen;\r\n const valLen = readVarUint(data, pos);\r\n pos += valLen.bytesRead + valLen.value;\r\n }\r\n }\r\n\r\n // Deserialize arguments\r\n const args: unknown[] = [];\r\n const argEnd = pos + argDataLen;\r\n if (argDataLen > 0) {\r\n const argSlice = data.subarray(pos, argEnd);\r\n for (const decoded of decoder.decodeMulti(argSlice)) {\r\n args.push(decoded);\r\n }\r\n pos = argEnd;\r\n }\r\n\r\n const message: RpcMessage = {\r\n Method: method,\r\n RelatedId: relId.value,\r\n CallType: callTypeId,\r\n };\r\n\r\n return { message, args, bytesRead: pos - offset };\r\n}\r\n\r\n/**\r\n * Splits a compact binary frame into individual deserialized messages.\r\n */\r\nexport function splitCompactBinaryFrame(\r\n frame: Uint8Array,\r\n registry?: RpcMethodRegistry,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[] }[] {\r\n const results: { message: RpcMessage; args: unknown[] }[] = [];\r\n let offset = 0;\r\n while (offset < frame.length) {\r\n const { message, args, bytesRead } =\r\n deserializeCompactBinaryMessage(\r\n frame,\r\n offset,\r\n registry,\r\n decoder\r\n );\r\n if (bytesRead <= 0) break;\r\n results.push({ message, args });\r\n offset += bytesRead;\r\n }\r\n return results;\r\n}\r\n","// .NET counterparts:\r\n// RpcConnection — thin wrapper around RpcTransport + PropertyBag. RpcTransport\r\n// is an abstract IAsyncEnumerable<RpcInboundMessage> + Send() that can be\r\n// WebSocket-based or in-memory. The transport also handles frame batching and\r\n// back-pressure via a Channel<T> send queue.\r\n//\r\n// Omitted from .NET:\r\n// - PropertyBag on connection — used in .NET for per-connection metadata (e.g.\r\n// authentication info attached by middleware). TS has no middleware pipeline,\r\n// so no need for an extensible property bag.\r\n// - IsLocal flag — .NET distinguishes local loopback connections (same-process\r\n// server) from remote ones. TS is always a remote client.\r\n// - RpcTransport as IAsyncEnumerable — .NET reads inbound messages via\r\n// async iteration with cancellation. TS uses event-based delivery\r\n// (messageReceived handler) because browser WebSocket API is event-driven.\r\n// - Channel<RpcOutboundMessage> send queue with backpressure — .NET buffers\r\n// outbound messages in an async channel that the transport drains. TS sends\r\n// synchronously on the WebSocket; if the socket isn't ready, messages are\r\n// buffered in _sendBuffer (CONNECTING) or silently dropped (CLOSING/CLOSED).\r\n// JS is single-threaded so there's no contention, and WebSocket.send() itself\r\n// handles buffering at the OS level.\r\n// - IAsyncDisposable — .NET transports are disposable resources. TS connections\r\n// are closed via close() and garbage-collected.\r\n\r\nimport { Encoder, Decoder } from '@msgpack/msgpack';\r\nimport { PromiseSource, EventHandlerSet } from '@actuallab/core';\r\nimport {\r\n splitFrame,\r\n serializeFrame,\r\n splitBinaryFrame as splitBinaryFrameFn,\r\n serializeBinaryFrame,\r\n createBinaryEncoder,\r\n} from './rpc-serialization.js';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport type { RpcSerializationFormat } from './rpc-serialization-format.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/** Abstract WebSocket interface — works with both browser WebSocket and Node.js ws. */\r\nexport interface WebSocketLike {\r\n readonly readyState: number;\r\n binaryType?: string;\r\n send(data: string | ArrayBufferLike | Uint8Array | ArrayBufferView): void;\r\n close(code?: number, reason?: string): void;\r\n onopen: ((ev: unknown) => void) | null;\r\n onmessage: ((ev: { data: unknown }) => void) | null;\r\n onclose: ((ev: { code: number; reason: string }) => void) | null;\r\n onerror: ((ev: unknown) => void) | null;\r\n}\r\n\r\nexport const WebSocketState = {\r\n CONNECTING: 0,\r\n OPEN: 1,\r\n CLOSING: 2,\r\n CLOSED: 3,\r\n} as const;\r\n\r\n/** Received message — either text (string) or binary (already parsed). */\r\nexport type RpcReceivedMessage =\r\n | { kind: 'text'; raw: string }\r\n | { kind: 'binary'; message: RpcMessage; args: unknown[] };\r\n\r\n/** Abstract RPC connection — transport-agnostic interface for sending/receiving messages. */\r\nexport interface RpcConnection {\r\n readonly isOpen: boolean;\r\n readonly binaryMode: boolean;\r\n readonly whenConnected: Promise<void>;\r\n readonly messageReceived: EventHandlerSet<RpcReceivedMessage>;\r\n readonly closed: EventHandlerSet<{ code: number; reason: string }>;\r\n /** Optional reusable msgpack encoder for outbound binary messages.\r\n * Callers passing this to `serializeBinaryMessage` skip the per-call\r\n * Encoder construction + resizeBuffer growth. Implementations that\r\n * don't support binary serialization can leave it undefined. */\r\n readonly encoder?: Encoder;\r\n send(serializedMessage: string): void;\r\n sendBinary(data: Uint8Array): void;\r\n close(code?: number, reason?: string): void;\r\n}\r\n\r\n/** WebSocket-based RpcConnection — handles frame splitting, binary/text modes, and message queueing. */\r\nexport class RpcWebSocketConnection implements RpcConnection {\r\n private _ws: WebSocketLike;\r\n private _sendBuffer: (string | Uint8Array)[] = [];\r\n private _connected = new PromiseSource<void>();\r\n\r\n /** Per-connection msgpack encoder — reused across outbound messages to\r\n * amortise construction cost and to keep the internal write buffer at\r\n * its largest observed size (avoids repeated `resizeBuffer` growth on\r\n * large video frames). See serializeBinaryMessage() for details. */\r\n private _encoder: Encoder = createBinaryEncoder();\r\n\r\n /** Per-connection msgpack decoder — reused across inbound messages\r\n * rather than reconstructing one for every `decodeMulti` call. */\r\n private _decoder: Decoder = new Decoder();\r\n\r\n /** Exposed for callers who need to encode outbound binary messages\r\n * through this connection (e.g. `serializeBinaryMessage`). Safe to\r\n * pass to synchronous encode calls on the same event-loop turn. */\r\n get encoder(): Encoder {\r\n return this._encoder;\r\n }\r\n get decoder(): Decoder {\r\n return this._decoder;\r\n }\r\n\r\n private _format: RpcSerializationFormat | undefined;\r\n private _methodRegistry: RpcMethodRegistry | undefined;\r\n\r\n readonly binaryMode: boolean;\r\n readonly messageReceived = new EventHandlerSet<RpcReceivedMessage>();\r\n readonly closed = new EventHandlerSet<{ code: number; reason: string }>();\r\n readonly error = new EventHandlerSet<unknown>();\r\n\r\n constructor(\r\n ws: WebSocketLike,\r\n binaryMode = false,\r\n format?: RpcSerializationFormat,\r\n methodRegistry?: RpcMethodRegistry\r\n ) {\r\n this._ws = ws;\r\n this.binaryMode = binaryMode;\r\n this._format = format;\r\n this._methodRegistry = methodRegistry;\r\n\r\n if (binaryMode && ws.binaryType !== undefined)\r\n ws.binaryType = 'arraybuffer';\r\n\r\n if (ws.readyState === WebSocketState.OPEN) {\r\n this._connected.resolve();\r\n this._flush();\r\n }\r\n\r\n ws.onopen = () => {\r\n this._connected.resolve();\r\n this._flush();\r\n };\r\n\r\n ws.onmessage = ev => {\r\n // Binary frame — V5 self-delimiting envelopes (one or more per WS frame).\r\n //\r\n // Accept BOTH `ArrayBuffer` (browser WebSocket when `binaryType` is\r\n // 'arraybuffer') AND `Uint8Array`-shaped views (Node `ws` delivering a\r\n // `Buffer`, which is a `Uint8Array` subclass). The node-ws adapter\r\n // intentionally passes Buffer through without an ArrayBuffer copy —\r\n // at 300 concurrent video streams that copy was ~100 MB/s of pure\r\n // memcpy + allocation pressure. Matching `ArrayBuffer.isView` here\r\n // keeps the zero-copy path alive all the way to `splitBinaryFrame`.\r\n if (\r\n ev.data instanceof Uint8Array ||\r\n ev.data instanceof ArrayBuffer\r\n ) {\r\n // Node `Buffer` is a `Uint8Array` subclass, so we can hand it to\r\n // `splitBinaryFrame` directly with no view wrapping or copying.\r\n // Browsers deliver `ArrayBuffer`, which needs a single zero-copy\r\n // view wrap.\r\n const frame =\r\n ev.data instanceof Uint8Array\r\n ? ev.data\r\n : new Uint8Array(ev.data);\r\n try {\r\n const messages = this._splitBinary(frame);\r\n for (const { message, args } of messages) {\r\n this.messageReceived.trigger({\r\n kind: 'binary',\r\n message,\r\n args,\r\n });\r\n }\r\n } catch (e) {\r\n this.error.trigger(e);\r\n }\r\n } else if (\r\n typeof Blob !== 'undefined' &&\r\n ev.data instanceof Blob &&\r\n this.binaryMode\r\n ) {\r\n // Fallback: some Chromium builds deliver the first frames as Blob even\r\n // after setting binaryType='arraybuffer'. Convert and route through\r\n // the binary path so we don't silently drop them.\r\n void ev.data.arrayBuffer().then(ab => {\r\n const frame = new Uint8Array(ab);\r\n try {\r\n const messages = this._splitBinary(frame);\r\n for (const { message, args } of messages) {\r\n this.messageReceived.trigger({\r\n kind: 'binary',\r\n message,\r\n args,\r\n });\r\n }\r\n } catch (e) {\r\n this.error.trigger(e);\r\n }\r\n });\r\n } else {\r\n // Text frame — JSON delimited messages\r\n const data =\r\n typeof ev.data === 'string' ? ev.data : String(ev.data);\r\n const messages = splitFrame(data);\r\n for (const msg of messages) {\r\n if (msg.length > 0)\r\n this.messageReceived.trigger({\r\n kind: 'text',\r\n raw: msg,\r\n });\r\n }\r\n }\r\n };\r\n\r\n ws.onclose = ev => {\r\n this.closed.trigger({ code: ev.code, reason: ev.reason });\r\n };\r\n\r\n ws.onerror = ev => {\r\n this.error.trigger(ev);\r\n };\r\n }\r\n\r\n get isOpen(): boolean {\r\n return this._ws.readyState === WebSocketState.OPEN;\r\n }\r\n\r\n get whenConnected(): Promise<void> {\r\n return this._connected.promise;\r\n }\r\n\r\n send(serializedMessage: string): void {\r\n this._sendRaw(serializedMessage);\r\n }\r\n\r\n sendBinary(data: Uint8Array): void {\r\n this._sendRaw(data);\r\n }\r\n\r\n sendTextBatch(messages: string[]): void {\r\n this._sendRaw(serializeFrame(messages));\r\n }\r\n\r\n sendBinaryBatch(messages: Uint8Array[]): void {\r\n this._sendRaw(serializeBinaryFrame(messages));\r\n }\r\n\r\n /** Split a binary frame using the format (compact-aware) or default splitter. */\r\n private _splitBinary(\r\n frame: Uint8Array\r\n ): { message: RpcMessage; args: unknown[] }[] {\r\n if (this._format) {\r\n return this._format.splitBinaryFrame(\r\n frame,\r\n this._decoder,\r\n this._methodRegistry\r\n );\r\n }\r\n return splitBinaryFrameFn(frame, this._decoder);\r\n }\r\n\r\n close(code?: number, reason?: string): void {\r\n this._ws.close(code, reason);\r\n }\r\n\r\n private _sendRaw(data: string | Uint8Array): void {\r\n try {\r\n if (this._ws.readyState === WebSocketState.OPEN) {\r\n this._ws.send(data);\r\n } else if (this._ws.readyState === WebSocketState.CONNECTING)\r\n this._sendBuffer.push(data);\r\n // CLOSING/CLOSED: silently drop\r\n } catch {\r\n // Swallow — disconnect event handles cleanup\r\n }\r\n }\r\n\r\n private _flush(): void {\r\n if (this._sendBuffer.length === 0) return;\r\n const buffer = this._sendBuffer;\r\n this._sendBuffer = [];\r\n try {\r\n for (const item of buffer) this._ws.send(item);\r\n } catch {\r\n // Swallow — disconnect event handles cleanup\r\n }\r\n }\r\n}\r\n","// .NET counterpart: none — this is a TS-only test transport.\r\n//\r\n// .NET tests use a different mechanism: RpcTestClient creates an in-memory\r\n// Channel<RpcMessage> pair wrapped in an RpcTransport. We use the browser-\r\n// standard MessageChannel API instead, which gives us a synchronous in-process\r\n// transport without requiring WebSocket mocks.\r\n\r\nimport { EventHandlerSet } from '@actuallab/core';\r\nimport { splitFrame } from './rpc-serialization.js';\r\nimport type { RpcConnection, RpcReceivedMessage } from './rpc-connection.js';\r\n\r\n/** MessagePort-based RpcConnection — for in-process testing without WebSocket mocks. */\r\nexport class RpcMessageChannelConnection implements RpcConnection {\r\n private _port: MessagePort;\r\n private _open = true;\r\n\r\n readonly binaryMode = false;\r\n readonly messageReceived = new EventHandlerSet<RpcReceivedMessage>();\r\n readonly closed = new EventHandlerSet<{ code: number; reason: string }>();\r\n readonly whenConnected: Promise<void> = Promise.resolve(); // immediately connected\r\n\r\n constructor(port: MessagePort) {\r\n this._port = port;\r\n port.onmessage = (ev: MessageEvent) => {\r\n const data =\r\n typeof ev.data === 'string' ? ev.data : String(ev.data);\r\n for (const msg of splitFrame(data))\r\n if (msg.length > 0)\r\n this.messageReceived.trigger({ kind: 'text', raw: msg });\r\n };\r\n }\r\n\r\n get isOpen(): boolean {\r\n return this._open;\r\n }\r\n\r\n send(serializedMessage: string): void {\r\n if (!this._open) return;\r\n try {\r\n this._port.postMessage(serializedMessage);\r\n } catch {\r\n // never fail\r\n }\r\n }\r\n\r\n sendBinary(data: Uint8Array): void {\r\n if (!this._open) return;\r\n try {\r\n this._port.postMessage(data, [data.buffer]);\r\n } catch {\r\n // never fail\r\n }\r\n }\r\n\r\n close(code?: number, reason?: string): void {\r\n if (!this._open) return;\r\n this._open = false;\r\n this._port.close();\r\n this.closed.trigger({ code: code ?? 1000, reason: reason ?? '' });\r\n }\r\n}\r\n\r\n/** Creates a pair of connected RpcMessageChannelConnections for testing. */\r\nexport function createMessageChannelPair(): [\r\n RpcMessageChannelConnection,\r\n RpcMessageChannelConnection,\r\n ] {\r\n const channel = new MessageChannel();\r\n return [\r\n new RpcMessageChannelConnection(channel.port1),\r\n new RpcMessageChannelConnection(channel.port2),\r\n ];\r\n}\r\n","// .NET counterparts:\r\n// RpcServiceDef (Configuration/) — 162 lines. Describes a registered service\r\n// including its .NET Type, Mode (Local/Client/Server/Hybrid), ServerResolver\r\n// (DI-based lazy resolution), ClientType, IsSystem, IsBackend flags, Scope,\r\n// LegacyNames, PropertyBag, and a method dictionary built via reflection.\r\n// RpcMethodDef (Configuration/) — 189 lines. Describes a single method:\r\n// FullName (ServiceName.MethodName:ArgCount), CallType (Regular/Reliable),\r\n// NoWait, HasPolymorphicArguments/Result, RpcMethodKind (Query/Command/System),\r\n// RpcMethodAttribute, LegacyNames, Tracer, outbound/inbound call pipeline\r\n// (factories, invokers, middleware chains, routers, timeouts).\r\n//\r\n// Omitted from .NET:\r\n// - Reflection-based method discovery (BuildMethods) — .NET scans interface\r\n// methods via reflection, filters generics, builds call pipelines. TS uses\r\n// explicit defineRpcService() or decorator metadata — no runtime reflection.\r\n// - RpcMethodKind (Query/Command/System/Other) — .NET classifies methods to\r\n// route Commands through ICommander. TS has no command bus; the distinction\r\n// is unnecessary.\r\n// - IsBackend / IBackendService — .NET separates \"backend-only\" services that\r\n// require backend auth. TS client never exposes backend services.\r\n// - RpcMethodAttribute / LegacyNames — .NET supports custom wire names and\r\n// version-specific legacy name mappings for rolling upgrades. TS has a\r\n// single version; wire names = \"ServiceName.MethodName:wireArgCount\".\r\n// - Call pipeline (OutboundCallFactory, InboundCallFactory, InboundCallInvoker,\r\n// MiddlewareFilter, OutboundCallRouter, OutboundCallTimeouts) — .NET builds a\r\n// per-method middleware chain at startup via generic factory types. TS dispatches\r\n// directly from RpcServiceHost; no middleware or routing layer.\r\n// - CallType (Regular/Reliable) — Reliable calls track stages for reconnect\r\n// resumption. TS replays entire calls on reconnect.\r\n// - HasPolymorphicArguments/Result — governs serializer behavior for abstract\r\n// argument types. TS uses JSON (inherently polymorphic); not applicable.\r\n// - Tracer / RpcCallTracer — per-method distributed tracing. Not ported.\r\n// - PropertyBag — extensible metadata on service/method def. Not needed.\r\n// - Mode (ServiceMode) / Scope / ServerResolver / ClientType — DI wiring.\r\n\r\n/** Describes a single method on an RPC service. */\r\nexport interface RpcMethodDef {\r\n readonly name: string;\r\n readonly serviceName: string;\r\n readonly argCount: number;\r\n readonly wireArgCount: number;\r\n readonly callTypeId: number;\r\n readonly stream: boolean;\r\n readonly noWait: boolean;\r\n}\r\n\r\n/** Describes an RPC service — its name and method definitions. */\r\nexport interface RpcServiceDef {\r\n readonly name: string;\r\n readonly methods: ReadonlyMap<string, RpcMethodDef>;\r\n}\r\n\r\nexport interface RpcMethodDefInput {\r\n args: unknown[];\r\n returns?: symbol;\r\n callTypeId?: number;\r\n /** Override for wireArgCount. Default: args.length + 1 (assumes a CancellationToken slot). */\r\n wireArgCount?: number;\r\n}\r\n\r\nexport const RpcType = {\r\n object: Symbol('object'),\r\n stream: Symbol('stream'),\r\n noWait: Symbol('noWait'),\r\n void: Symbol('void'),\r\n} as const;\r\n\r\n/** Returns the full wire method name: \"ServiceName.MethodName:wireArgCount\". */\r\nexport function wireMethodName(def: RpcMethodDef): string {\r\n return `${def.serviceName}.${def.name}:${def.wireArgCount}`;\r\n}\r\n\r\nexport function defineRpcService(\r\n name: string,\r\n methods: Record<string, RpcMethodDefInput>\r\n): RpcServiceDef {\r\n const map = new Map<string, RpcMethodDef>();\r\n for (const [key, input] of Object.entries(methods)) {\r\n // If the key contains \":\", the part before \":\" is the clean name\r\n // (the suffix is for JS object key disambiguation of overloads).\r\n // Otherwise the key IS the clean name.\r\n const colonIndex = key.indexOf(':');\r\n const cleanName = colonIndex >= 0 ? key.substring(0, colonIndex) : key;\r\n const wireArgCount = input.wireArgCount ?? input.args.length + 1;\r\n const mapKey = `${cleanName}:${wireArgCount}`;\r\n map.set(mapKey, {\r\n name: cleanName,\r\n serviceName: name,\r\n argCount: input.args.length,\r\n wireArgCount,\r\n callTypeId: input.callTypeId ?? 0,\r\n stream: input.returns === RpcType.stream,\r\n noWait: input.returns === RpcType.noWait,\r\n });\r\n }\r\n return { name, methods: map };\r\n}\r\n","// .NET counterparts:\r\n// RpcCall (29 lines) — base class: MethodDef, Id, NoWait flag, Lock.\r\n// RpcOutboundCall (437 lines) — tracks an outbound call's full lifecycle:\r\n// result via AsyncTaskMethodBuilder, CacheInfoCapture, CancellationHandler,\r\n// CompletedStage (for Reliable reconnection), StartedAt (for timeouts),\r\n// hashing for Match, tracing, routing, and retry logic.\r\n// RpcInboundCall (298 lines) — tracks an inbound call: deserialization,\r\n// middleware-chain invocation, cancellation via linked CTS, stage-based\r\n// re-processing for reconnection, sending the result back.\r\n// RpcOutboundCallTracker (255 lines) — thread-safe ConcurrentDictionary of\r\n// outbound calls with: Maintain() loop (timeout monitoring + logging),\r\n// Reconnect() protocol (stage-based call resumption), Abort(), TryReroute().\r\n// RpcInboundCallTracker (64 lines) — ConcurrentDictionary, GetOrRegister,\r\n// Unregister, Clear.\r\n//\r\n// Omitted from .NET:\r\n// - AsyncTaskMethodBuilder / typed RpcOutboundCall<T> — .NET creates a typed\r\n// task builder for each call's return type. TS uses PromiseSource<unknown>\r\n// (untyped) because TypeScript erases generics at runtime.\r\n// - CancellationHandler (CancellationToken.Register → Cancel) — .NET registers\r\n// a callback per outbound call. TS implements equivalent via optional\r\n// AbortSignal on RpcPeer.call(); the cancel handler rejects the promise,\r\n// removes from tracker, and sends $sys.Cancel — same behavior as .NET's\r\n// Cancel() + NotifyCancelled().\r\n// - StartedAt / CpuTimestamp / Timeout monitoring — .NET's Maintain() loop\r\n// checks elapsed time against per-method timeouts every CallTimeoutCheckPeriod.\r\n// TS has no per-call timeout mechanism; the WebSocket-level disconnect +\r\n// rejectAll handles stuck calls.\r\n// - CompletedStage / RpcCallStage — supports Reliable call type's stage-based\r\n// reconnection protocol where the server tells the client which stage each\r\n// call reached, avoiding re-execution of completed stages. TS replays entire\r\n// calls on reconnect (simpler, adequate for browser client).\r\n// - Reconnect() protocol — outbound tracker sends $sys.Reconnect with compressed\r\n// call IDs grouped by stage; server responds with \"unknown\" IDs that need\r\n// re-sending. Not ported; TS uses full replay.\r\n// - Abort() with multi-pass retry — .NET iterates 3+ times with delays to\r\n// catch late-registered calls. TS does a single-pass rejectAll().\r\n// - TryReroute() — checks if the call's peer route has changed (load-balancer\r\n// rerouting) and sets RpcRerouteException. TS has no routing layer.\r\n// - IsLongLiving / _longLivingCalls — separate tracking for calls that outlive\r\n// normal timeouts (e.g. streaming). Not needed without RpcStream.\r\n// - RpcInboundCall: middleware-chain invocation, deserialization with polymorphic\r\n// argument handling, stage-based TryReprocess, CancellationTokenSource per\r\n// call. TS inbound calls are dispatched directly by RpcServiceHost; no\r\n// middleware, no per-call CTS, no stage tracking.\r\n// - RpcCall.Lock (monitor-based synchronisation) — .NET uses lock(this) for\r\n// thread-safe result setting. TS is single-threaded; no locking needed.\r\n\r\nimport { PromiseSource } from '@actuallab/core';\r\n\r\n/** Tracks a pending outbound RPC call. */\r\nexport class RpcOutboundCall {\r\n readonly callId: number;\r\n readonly method: string;\r\n readonly result = new PromiseSource<unknown>();\r\n\r\n /** Whether to remove this call from the tracker on $sys.Ok. Default: true.\r\n * Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */\r\n readonly removeOnOk: boolean = true;\r\n\r\n /** The serialized wire data — stored for re-sending on reconnect. */\r\n serializedWireData: string | Uint8Array = '';\r\n\r\n constructor(callId: number, method: string) {\r\n this.callId = callId;\r\n this.method = method;\r\n }\r\n\r\n /** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */\r\n onDisconnect(): void {\r\n // no-op by default\r\n }\r\n}\r\n\r\n/** Manages outbound calls by their RelatedId. */\r\nexport class RpcOutboundCallTracker {\r\n private _calls = new Map<number, RpcOutboundCall>();\r\n private _nextId = 1;\r\n\r\n get size(): number {\r\n return this._calls.size;\r\n }\r\n\r\n nextId(): number {\r\n return this._nextId++;\r\n }\r\n\r\n register(call: RpcOutboundCall): void {\r\n this._calls.set(call.callId, call);\r\n }\r\n\r\n get(callId: number): RpcOutboundCall | undefined {\r\n return this._calls.get(callId);\r\n }\r\n\r\n remove(callId: number): RpcOutboundCall | undefined {\r\n const call = this._calls.get(callId);\r\n if (call !== undefined) this._calls.delete(callId);\r\n return call;\r\n }\r\n\r\n values(): IterableIterator<RpcOutboundCall> {\r\n return this._calls.values();\r\n }\r\n\r\n activeCallIds(): number[] {\r\n return [...this._calls.keys()];\r\n }\r\n\r\n /** Reject all pending calls with the given error.\r\n * Stage-3 compute calls (result resolved, awaiting invalidation) are kept in the tracker. */\r\n rejectAll(error: Error): void {\r\n for (const [id, call] of this._calls) {\r\n if (!call.removeOnOk && call.result.isCompleted) {\r\n // Stage-3 compute call — keep it for later invalidation on reconnect/stop\r\n continue;\r\n }\r\n call.result.reject(error);\r\n call.onDisconnect();\r\n this._calls.delete(id);\r\n }\r\n }\r\n\r\n /** Invalidate all remaining stage-3 calls (on reconnect or peer stop). */\r\n invalidateAll(): void {\r\n for (const call of this._calls.values()) {\r\n call.onDisconnect();\r\n }\r\n this._calls.clear();\r\n }\r\n\r\n clear(): void {\r\n this._calls.clear();\r\n }\r\n}\r\n\r\n/** Tracks an incoming inbound RPC call. */\r\nexport class RpcInboundCall {\r\n readonly callId: number;\r\n readonly method: string;\r\n readonly args: unknown[];\r\n\r\n constructor(callId: number, method: string, args: unknown[]) {\r\n this.callId = callId;\r\n this.method = method;\r\n this.args = args;\r\n }\r\n}\r\n\r\n/** Manages inbound calls by their RelatedId. */\r\nexport class RpcInboundCallTracker {\r\n private _calls = new Map<number, RpcInboundCall>();\r\n\r\n get size(): number {\r\n return this._calls.size;\r\n }\r\n\r\n register(call: RpcInboundCall): void {\r\n this._calls.set(call.callId, call);\r\n }\r\n\r\n get(callId: number): RpcInboundCall | undefined {\r\n return this._calls.get(callId);\r\n }\r\n\r\n remove(callId: number): RpcInboundCall | undefined {\r\n const call = this._calls.get(callId);\r\n if (call !== undefined) this._calls.delete(callId);\r\n return call;\r\n }\r\n\r\n clear(): void {\r\n this._calls.clear();\r\n }\r\n}\r\n","import Denque from 'denque';\r\nimport { PromiseSource } from '@actuallab/core';\r\nimport type { RpcObjectId, IRpcObject } from './rpc-object.js';\r\nimport { RpcObjectKind } from './rpc-object.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport { RpcStreamSender } from './rpc-stream-sender.js';\r\n\r\n/** Default ack period (matches .NET RpcStream defaults). */\r\nconst DEFAULT_ACK_PERIOD = 30;\r\n/** Default ack advance (matches .NET RpcStream defaults). */\r\nconst DEFAULT_ACK_ADVANCE = 61;\r\n\r\n/** Parsed stream reference from the server's result payload. */\r\nexport interface RpcStreamRef {\r\n readonly hostId: string;\r\n readonly localId: number;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n}\r\n\r\n/** Configuration options for creating a local (origin-side) RpcStream. */\r\nexport interface RpcStreamOptions<T> {\r\n ackPeriod?: number;\r\n ackAdvance?: number;\r\n allowReconnect?: boolean;\r\n isRealTime?: boolean;\r\n canSkipTo?: (item: T) => boolean;\r\n}\r\n\r\n/**\r\n * Parses a stream reference string of the form \"{hostId},{localId},{ackPeriod},{ackAdvance}\".\r\n * Returns null if the value is not a valid stream reference.\r\n */\r\nexport function parseStreamRef(value: unknown): RpcStreamRef | null {\r\n // Text format: \"hostId,localId,ackPeriod,ackAdvance[,allowReconnect[,isRealTime]]\"\r\n if (typeof value === 'string') {\r\n const parts = value.split(',');\r\n if (parts.length < 4 || parts.length > 6) return null;\r\n const hostId = parts[0];\r\n const localId = parseInt(parts[1], 10);\r\n const ackPeriod = parseInt(parts[2], 10);\r\n const ackAdvance = parseInt(parts[3], 10);\r\n if (isNaN(localId) || isNaN(ackPeriod) || isNaN(ackAdvance))\r\n return null;\r\n const allowReconnect = parts.length < 5 || parts[4] !== '0';\r\n const isRealTime = parts.length >= 6 && parts[5] === '1';\r\n return { hostId, localId, ackPeriod, ackAdvance, allowReconnect, isRealTime };\r\n }\r\n // Binary (MessagePack) format: { SerializedId: [hostId, localId], AckPeriod, AckAdvance, AllowReconnect }\r\n if (typeof value === 'object' && value !== null) {\r\n const obj = value as Record<string, unknown>;\r\n const serializedId = obj.SerializedId as unknown[];\r\n if (!Array.isArray(serializedId) || serializedId.length < 2)\r\n return null;\r\n const rawHostId = serializedId[0];\r\n const hostId = String(rawHostId);\r\n const localId = Number(serializedId[1]);\r\n const ackPeriod = Number(obj.AckPeriod ?? 256);\r\n const ackAdvance = Number(obj.AckAdvance ?? 128);\r\n const allowReconnect = obj.AllowReconnect !== false;\r\n const isRealTime = obj.IsRealTime === true;\r\n return { hostId, localId, ackPeriod, ackAdvance, allowReconnect, isRealTime };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Dual-mode RPC stream — works as both local (origin-side) and remote (target-side).\r\n *\r\n * **Local mode**: wraps an AsyncIterable and carries streaming configuration\r\n * (IsRealTime, CanSkipTo, etc.). Created by service methods and sent to the\r\n * remote peer via RpcStreamSender.\r\n *\r\n * **Remote mode**: consumes items sent by the server via system calls\r\n * ($sys.I, $sys.B, $sys.End) and implements AsyncIterable for for-await-of consumption.\r\n *\r\n * This mirrors the .NET RpcStream<T> design where the same type serves both roles.\r\n */\r\nexport class RpcStream<T> implements AsyncIterable<T>, IRpcObject {\r\n readonly id: RpcObjectId;\r\n readonly kind: RpcObjectKind;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n readonly canSkipTo: (item: T) => boolean;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n\r\n // Local (origin) mode\r\n readonly localSource?: AsyncIterable<T>;\r\n\r\n // Remote (target) mode\r\n readonly peer!: RpcPeer;\r\n\r\n // Local-only state\r\n private _sender?: RpcStreamSender<T>;\r\n private _toRefValue?: unknown;\r\n private _whenSent?: Promise<void>;\r\n\r\n // Remote-only state\r\n private _buffer: Denque<T> = new Denque<T>();\r\n private _nextExpectedIndex = 0;\r\n private _consumerWaiting: PromiseSource<void> | null = null;\r\n private _completed = false;\r\n private _completionError: Error | null = null;\r\n private _disposed = false;\r\n private _started = false;\r\n private _iterating = false;\r\n private _ackSentUpTo = 0;\r\n\r\n /** Create a local (origin-side) stream wrapping an async iterable with optional configuration. */\r\n constructor(source: AsyncIterable<T>, options?: RpcStreamOptions<T>);\r\n /** Create a remote (target-side) stream from a parsed stream reference and peer. */\r\n constructor(ref: RpcStreamRef, peer: RpcPeer);\r\n constructor(\r\n sourceOrRef: AsyncIterable<T> | RpcStreamRef,\r\n optionsOrPeer?: RpcStreamOptions<T> | RpcPeer,\r\n ) {\r\n if (_isAsyncIterable(sourceOrRef)) {\r\n // Local (origin) mode\r\n const options = (optionsOrPeer as RpcStreamOptions<T> | undefined) ?? {};\r\n this.kind = RpcObjectKind.Local;\r\n this.localSource = sourceOrRef;\r\n this.id = { hostId: '', localId: 0 };\r\n this.allowReconnect = options.allowReconnect ?? true;\r\n this.isRealTime = options.isRealTime ?? false;\r\n this.canSkipTo = options.canSkipTo ?? (() => true);\r\n this.ackPeriod = options.ackPeriod ?? DEFAULT_ACK_PERIOD;\r\n this.ackAdvance = options.ackAdvance ?? DEFAULT_ACK_ADVANCE;\r\n } else {\r\n // Remote (target) mode\r\n const ref = sourceOrRef;\r\n const peer = optionsOrPeer as RpcPeer;\r\n this.kind = RpcObjectKind.Remote;\r\n this.id = { hostId: ref.hostId, localId: ref.localId };\r\n this.peer = peer;\r\n this.allowReconnect = ref.allowReconnect;\r\n this.isRealTime = ref.isRealTime;\r\n this.canSkipTo = () => true; // not serialized\r\n this.ackPeriod = ref.ackPeriod;\r\n this.ackAdvance = ref.ackAdvance;\r\n }\r\n }\r\n\r\n /**\r\n * For local streams: resolves when the sender finishes pumping (after `toRef()` was called).\r\n * Rejects if the source throws. Throws if `toRef()` hasn't been called yet.\r\n */\r\n get whenSent(): Promise<void> {\r\n if (!this._whenSent)\r\n throw new Error('toRef() must be called before awaiting whenSent.');\r\n return this._whenSent;\r\n }\r\n\r\n /**\r\n * For local streams: bind to a peer, create and register an `RpcStreamSender`,\r\n * start pumping items from the local source in the background, and return the\r\n * stream reference.\r\n *\r\n * For binary peers the ref is a MessagePack-compatible object\r\n * (`{ SerializedId, AckPeriod, AckAdvance, AllowReconnect }`);\r\n * for text peers it is a comma-separated string.\r\n *\r\n * Can only be called once per stream.\r\n */\r\n toRef(peer: RpcPeer): unknown {\r\n if (this.kind !== RpcObjectKind.Local)\r\n throw new Error('toRef() is only valid for local streams.');\r\n if (this._sender) {\r\n if (this._sender.peer !== peer)\r\n throw new Error('toRef() was already called with a different peer.');\r\n // Same peer — return the cached ref\r\n return this._toRefValue!;\r\n }\r\n\r\n const sender = new RpcStreamSender<T>(\r\n peer, this.ackPeriod, this.ackAdvance,\r\n this.allowReconnect, this.isRealTime, this.canSkipTo,\r\n );\r\n peer.sharedObjects.register(sender);\r\n this._sender = sender;\r\n\r\n // Start pumping in background (writeFrom awaits the initial Ack)\r\n this._whenSent = sender.writeFrom(this.localSource!);\r\n\r\n // Cache and return ref in the format appropriate for the peer's serialization\r\n this._toRefValue = peer.format.isBinary\r\n ? {\r\n SerializedId: [sender.id.hostId, sender.id.localId],\r\n AckPeriod: sender.ackPeriod,\r\n AckAdvance: sender.ackAdvance,\r\n AllowReconnect: sender.allowReconnect,\r\n }\r\n : sender.toRef();\r\n return this._toRefValue;\r\n }\r\n\r\n /** Called by system call handler when a single item arrives ($sys.I). */\r\n onItem(index: number, item: T): void {\r\n if (this._disposed || this._completed) return;\r\n\r\n if (index > this._nextExpectedIndex) {\r\n console.warn(\r\n `[RpcStream] item index gap: localId=${this.id.localId}, expected=${this._nextExpectedIndex}, received=${index}`\r\n );\r\n if (!this.allowReconnect) {\r\n this._completed = true;\r\n this._completionError = new Error(\r\n `Stream gap at index ${index} (expected ${this._nextExpectedIndex}); reconnect not allowed`\r\n );\r\n this._notifyConsumer();\r\n return;\r\n }\r\n this._sendAck(this._nextExpectedIndex, true);\r\n return;\r\n }\r\n if (index < this._nextExpectedIndex) {\r\n // Duplicate — ack and ignore\r\n this._maybeSendAck(index + 1);\r\n return;\r\n }\r\n\r\n this._buffer.push(item);\r\n this._nextExpectedIndex = index + 1;\r\n this._maybeSendAck(this._nextExpectedIndex);\r\n this._notifyConsumer();\r\n }\r\n\r\n /** Called by system call handler when a batch arrives ($sys.B). */\r\n onBatch(index: number, items: T[]): void {\r\n if (this._disposed || this._completed) return;\r\n\r\n if (index > this._nextExpectedIndex) {\r\n console.warn(\r\n `[RpcStream] batch index gap: localId=${this.id.localId}, expected=${this._nextExpectedIndex}, received=${index}`\r\n );\r\n if (!this.allowReconnect) {\r\n this._completed = true;\r\n this._completionError = new Error(\r\n `Stream gap at index ${index} (expected ${this._nextExpectedIndex}); reconnect not allowed`\r\n );\r\n this._notifyConsumer();\r\n return;\r\n }\r\n this._sendAck(this._nextExpectedIndex, true);\r\n return;\r\n }\r\n if (index < this._nextExpectedIndex) {\r\n this._maybeSendAck(index + items.length);\r\n return;\r\n }\r\n\r\n for (const item of items) this._buffer.push(item);\r\n this._nextExpectedIndex = index + items.length;\r\n this._maybeSendAck(this._nextExpectedIndex);\r\n this._notifyConsumer();\r\n }\r\n\r\n /** Called by system call handler when the stream ends ($sys.End). */\r\n onEnd(index: number, error: Error | null): void {\r\n if (this._disposed || this._completed) return;\r\n this._completed = true;\r\n this._completionError = error;\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- IRpcObject --\r\n\r\n reconnect(): void {\r\n if (this.kind === RpcObjectKind.Local) return; // no-op for local streams\r\n if (this.allowReconnect) {\r\n this._sendAck(this._nextExpectedIndex, true);\r\n } else {\r\n this.disconnect();\r\n }\r\n }\r\n\r\n disconnect(): void {\r\n if (this.kind === RpcObjectKind.Local) return; // no-op for local streams\r\n if (this._completed) return;\r\n this._completed = true;\r\n this._completionError = new Error('Peer disconnected.');\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- AsyncIterable --\r\n\r\n [Symbol.asyncIterator](): AsyncIterator<T> {\r\n // Local mode: delegate to the local source\r\n if (this.kind === RpcObjectKind.Local) {\r\n return this.localSource![Symbol.asyncIterator]();\r\n }\r\n\r\n // Remote mode: buffer-based consumption\r\n if (this._iterating)\r\n throw new Error('RpcStream can only be iterated once.');\r\n this._iterating = true;\r\n\r\n return {\r\n next: async (): Promise<IteratorResult<T>> => {\r\n // Lazy start: send initial ack on first next() call\r\n if (!this._started) {\r\n this._started = true;\r\n this._sendAck(0, true);\r\n }\r\n\r\n // Read from buffer or wait for new data\r\n for (;;) {\r\n if (!this._buffer.isEmpty()) {\r\n // shift() is O(1) on Denque and releases the slot so the\r\n // ring buffer can be reclaimed as the consumer drains.\r\n const value = this._buffer.shift()!;\r\n return { value, done: false };\r\n }\r\n\r\n if (this._completed) {\r\n if (this._completionError) throw this._completionError;\r\n return { value: undefined as T, done: true };\r\n }\r\n\r\n // Wait for more data\r\n this._consumerWaiting = new PromiseSource<void>();\r\n await this._consumerWaiting.promise;\r\n }\r\n },\r\n\r\n return: (): Promise<IteratorResult<T>> => {\r\n this._sendAckEnd();\r\n this.dispose();\r\n return Promise.resolve({ value: undefined as T, done: true });\r\n },\r\n };\r\n }\r\n\r\n dispose(): void {\r\n if (this._disposed) return;\r\n this._disposed = true;\r\n this._completed = true;\r\n if (this.kind === RpcObjectKind.Remote) {\r\n this.peer.remoteObjects.unregister(this);\r\n }\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- Private --\r\n\r\n private _notifyConsumer(): void {\r\n if (this._consumerWaiting !== null) {\r\n this._consumerWaiting.resolve();\r\n this._consumerWaiting = null;\r\n }\r\n }\r\n\r\n private _maybeSendAck(nextIndex: number): void {\r\n if (this.ackPeriod <= 0) return;\r\n const threshold = this._ackSentUpTo + this.ackPeriod;\r\n if (nextIndex >= threshold) {\r\n this._sendAck(nextIndex, false);\r\n }\r\n }\r\n\r\n private static readonly _emptyGuid = '00000000-0000-0000-0000-000000000000';\r\n\r\n private _sendAck(nextIndex: number, mustReset: boolean): void {\r\n this._ackSentUpTo = nextIndex;\r\n const conn = this.peer.connection;\r\n if (conn) {\r\n const hostId = mustReset ? this.id.hostId : RpcStream._emptyGuid;\r\n this.peer.hub.systemCallSender.ack(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n nextIndex,\r\n hostId\r\n );\r\n }\r\n }\r\n\r\n private _sendAckEnd(): void {\r\n const conn = this.peer.connection;\r\n if (conn) {\r\n this.peer.hub.systemCallSender.ackEnd(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this.id.hostId\r\n );\r\n }\r\n }\r\n}\r\n\r\n/** @internal Type guard for AsyncIterable (has Symbol.asyncIterator). */\r\nfunction _isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {\r\n return (\r\n value !== null &&\r\n typeof value === 'object' &&\r\n Symbol.asyncIterator in (value)\r\n );\r\n}\r\n\r\n/**\r\n * Recursively walks a deserialized value and replaces any stream ref strings\r\n * with live RpcStream<unknown> instances registered on the given peer.\r\n * This handles nested stream refs inside complex return types (e.g. Table<T>\r\n * containing RpcStream<Row<T>> fields serialized as \"{hostId},{localId},{ackPeriod},{ackAdvance}\").\r\n */\r\nexport function resolveStreamRefs(value: unknown, peer: RpcPeer): unknown {\r\n if (value === null || value === undefined) return value;\r\n\r\n if (typeof value === 'string') {\r\n const ref = parseStreamRef(value);\r\n if (ref !== null) {\r\n const stream = new RpcStream(ref, peer);\r\n peer.remoteObjects.register(stream);\r\n return stream;\r\n }\r\n return value;\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n for (let i = 0; i < value.length; i++) {\r\n value[i] = resolveStreamRefs(value[i], peer);\r\n }\r\n return value;\r\n }\r\n\r\n if (typeof value === 'object') {\r\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer)\r\n return value;\r\n\r\n for (const key of Object.keys(value as Record<string, unknown>)) {\r\n (value as Record<string, unknown>)[key] = resolveStreamRefs(\r\n (value as Record<string, unknown>)[key],\r\n peer\r\n );\r\n }\r\n return value;\r\n }\r\n\r\n return value;\r\n}\r\n","export interface RpcObjectId {\r\n readonly hostId: string;\r\n readonly localId: number;\r\n}\r\n\r\nexport const RpcObjectKind = { Local: 0, Remote: 1 } as const;\r\nexport type RpcObjectKind = (typeof RpcObjectKind)[keyof typeof RpcObjectKind];\r\n\r\nexport interface IRpcObject {\r\n readonly id: RpcObjectId;\r\n readonly kind: RpcObjectKind;\r\n readonly allowReconnect: boolean;\r\n reconnect(): void;\r\n disconnect(): void;\r\n}\r\n","import { PromiseSource } from '@actuallab/core';\r\nimport type { RpcObjectId, IRpcObject } from './rpc-object.js';\r\nimport { RpcObjectKind } from './rpc-object.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\n\r\n/** Default ack period for server-side streams. */\r\nconst DEFAULT_ACK_PERIOD = 256;\r\n/** Default ack advance for server-side streams. */\r\nconst DEFAULT_ACK_ADVANCE = 128;\r\n\r\n/**\r\n * Server-side RPC stream producer — sends items to a remote consumer via\r\n * $sys.I / $sys.B / $sys.End system calls.\r\n *\r\n * Wire protocol (server perspective):\r\n * - Server returns the stream reference string as $sys.Ok\r\n * - Client sends Ack(0, hostId) to start the stream\r\n * - Server sends I (single item) / B (batch) messages\r\n * - Client acks every ackPeriod items for flow control\r\n * - Server sends End to signal completion (with optional error)\r\n * - Client sends AckEnd to acknowledge completion\r\n */\r\nexport class RpcStreamSender<T> implements IRpcObject {\r\n private static readonly _emptyGuid = '00000000-0000-0000-0000-000000000000';\r\n\r\n readonly id: RpcObjectId;\r\n readonly kind = RpcObjectKind.Local;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n readonly canSkipTo: (item: T) => boolean;\r\n readonly peer: RpcPeer;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n\r\n private _nextIndex = 0;\r\n private _ended = false;\r\n private _started = new PromiseSource<void>();\r\n private _lastAckedIndex = 0;\r\n private _ackWaiting: PromiseSource<void> | null = null;\r\n private _resetRequested = false;\r\n\r\n constructor(\r\n peer: RpcPeer,\r\n ackPeriod = DEFAULT_ACK_PERIOD,\r\n ackAdvance = DEFAULT_ACK_ADVANCE,\r\n allowReconnect = true,\r\n isRealTime = false,\r\n canSkipTo: (item: T) => boolean = () => true,\r\n ) {\r\n const localId = peer.sharedObjects.nextId();\r\n this.id = { hostId: peer.hub.hubId, localId };\r\n this.allowReconnect = allowReconnect;\r\n this.isRealTime = isRealTime;\r\n this.canSkipTo = canSkipTo;\r\n this.peer = peer;\r\n this.ackPeriod = ackPeriod;\r\n this.ackAdvance = ackAdvance;\r\n }\r\n\r\n /** Returns the stream reference string for the $sys.Ok response. */\r\n toRef(): string {\r\n return `${this.id.hostId},${this.id.localId},${this.ackPeriod},${this.ackAdvance},${this.allowReconnect ? '1' : '0'},${this.isRealTime ? '1' : '0'}`;\r\n }\r\n\r\n /** Called by system call handler when $sys.Ack is received from the client. */\r\n onAck(nextIndex: number, hostId: string): void {\r\n const mustReset = hostId !== '' && hostId !== RpcStreamSender._emptyGuid;\r\n\r\n if (!this._started.isCompleted) {\r\n this._started.resolve();\r\n }\r\n\r\n if (mustReset && this.isRealTime) {\r\n // Real-time reconnect: reset position and request skip to next canSkipTo item\r\n this._nextIndex = nextIndex;\r\n this._lastAckedIndex = nextIndex;\r\n this._resetRequested = true;\r\n } else {\r\n if (mustReset || nextIndex > this._lastAckedIndex) {\r\n this._lastAckedIndex = nextIndex;\r\n }\r\n }\r\n\r\n if (this._ackWaiting) {\r\n this._ackWaiting.resolve();\r\n this._ackWaiting = null;\r\n }\r\n }\r\n\r\n /** Called by system call handler when $sys.AckEnd is received from the client. */\r\n onAckEnd(_hostId: string): void {\r\n this._ended = true;\r\n this.peer.sharedObjects.unregister(this);\r\n }\r\n\r\n /** Send a single item to the client. */\r\n sendItem(item: T): void {\r\n if (this._ended) return;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n this.peer.hub.systemCallSender.item(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n item\r\n );\r\n this._nextIndex++;\r\n }\r\n\r\n /** Send a batch of items to the client. */\r\n sendBatch(items: T[]): void {\r\n if (this._ended || items.length === 0) return;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n this.peer.hub.systemCallSender.batch(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n items\r\n );\r\n this._nextIndex += items.length;\r\n }\r\n\r\n /** Signal stream completion to the client. */\r\n sendEnd(error?: Error | null): void {\r\n if (this._ended) return;\r\n this._ended = true;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n // .NET ExceptionInfo is a non-nullable value type, so we must always\r\n // emit a valid map shape (empty TypeRef+Message for the \"no error\" case).\r\n const errorInfo = error\r\n ? { TypeRef: 'System.Exception', Message: error.message }\r\n : { TypeRef: '', Message: '' };\r\n this.peer.hub.systemCallSender.end(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n errorInfo\r\n );\r\n }\r\n\r\n /**\r\n * Consume an AsyncIterable and send all items to the client.\r\n * Waits for the client's initial Ack before starting to pump items.\r\n *\r\n * When `isRealTime` is true, applies flow control based on `ackAdvance`:\r\n * if the sender is `ackAdvance` items ahead of the last ACK, it enters\r\n * skip mode — draining the source and discarding items until it finds\r\n * one where `canSkipTo` returns true.\r\n */\r\n async writeFrom(source: AsyncIterable<T>): Promise<void> {\r\n await this._started.promise;\r\n\r\n const iterator = source[Symbol.asyncIterator]();\r\n try {\r\n for (;;) {\r\n const next = await iterator.next();\r\n \r\n if (next.done || this._ended) break;\r\n\r\n const item = next.value;\r\n\r\n // Real-time reconnect: drain source to next canSkipTo item\r\n if (this._resetRequested) {\r\n if (!this.canSkipTo(item)) continue;\r\n this._resetRequested = false;\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n // Flow control: check if we've hit the AckAdvance ceiling\r\n if (this._nextIndex < this._lastAckedIndex + this.ackAdvance) {\r\n // Under budget — send normally\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n if (!this.isRealTime) {\r\n // Normal mode: wait for ACK before sending\r\n await this._waitForAckBudget();\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n // Real-time mode: hit the ceiling. Drain the source,\r\n // discarding non-skip-targets, keeping the latest skip target.\r\n // Stop draining when budget becomes available or source exhausts.\r\n let latestSkipTarget: T | undefined = this.canSkipTo(item) ? item : undefined;\r\n let sourceExhausted = false;\r\n\r\n while (this._nextIndex >= this._lastAckedIndex + this.ackAdvance) {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n const n = await iterator.next();\r\n if (n.done) {\r\n sourceExhausted = true;\r\n break;\r\n }\r\n if (this.canSkipTo(n.value)) {\r\n latestSkipTarget = n.value;\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n\r\n if (latestSkipTarget !== undefined) {\r\n this.sendItem(latestSkipTarget);\r\n }\r\n\r\n if (sourceExhausted) {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (!this._ended) this.sendEnd();\r\n return;\r\n }\r\n }\r\n \r\n if (!this._ended) {\r\n this.sendEnd();\r\n }\r\n } catch (e) {\r\n if (!this._ended) {\r\n this.sendEnd(e instanceof Error ? e : new Error(String(e)));\r\n }\r\n }\r\n }\r\n\r\n /** Wait until _nextIndex < _lastAckedIndex + ackAdvance. */\r\n private async _waitForAckBudget(): Promise<void> {\r\n while (this._nextIndex >= this._lastAckedIndex + this.ackAdvance) {\r\n if (this._ended) return;\r\n this._ackWaiting = new PromiseSource<void>();\r\n await this._ackWaiting.promise;\r\n }\r\n }\r\n\r\n // -- IRpcObject --\r\n\r\n reconnect(): void {\r\n // Server-side streams don't support reconnection — the client\r\n // creates a new stream on reconnect.\r\n }\r\n\r\n disconnect(): void {\r\n this._ended = true;\r\n if (!this._started.isCompleted) {\r\n // Resolve (not reject) — writeFrom() will see _ended=true and exit cleanly.\r\n // Rejecting would cause unhandled rejections when writeFrom() is void-called.\r\n this._started.resolve();\r\n }\r\n this.peer.sharedObjects.unregister(this);\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcSystemCalls (239 lines) — implements IRpcSystemCalls interface; handles\r\n// all inbound system messages as regular RPC method calls dispatched through\r\n// the same inbound-call pipeline as user calls.\r\n//\r\n// Omitted from .NET:\r\n// - Reconnect() handler — receives compressed call-ID sets grouped by stage,\r\n// looks up each inbound call, calls TryReprocess(), and returns the IDs of\r\n// unknown calls. TS doesn't implement the Reliable reconnection protocol.\r\n// - Cancel() handler — .NET finds the inbound call and cancels its\r\n// CancellationTokenSource, aborting the running handler. TS removes the\r\n// inbound call from the tracker but does not yet propagate cancellation\r\n// to the service handler (no AbortSignal threading through dispatch).\r\n// - M() (Match) handler — tells an outbound call to use its cached result\r\n// instead of the response payload. TS has no response caching.\r\n// - NotFound() — throws an EndpointNotFound error. TS sends this as a regular\r\n// $sys.Error; no separate system call type.\r\n// - KeepAlive() / Disconnect() — manage RpcSharedObject lifetimes. TS has no\r\n// shared-object tracker.\r\n// - IRpcPolymorphicArgumentHandler.IsValidCall — resolves the concrete\r\n// deserialization type for polymorphic Ok/Item/Batch arguments by looking up\r\n// the related outbound call's return type. TS deserializes all args as\r\n// unknown via JSON.parse (inherently polymorphic).\r\n// - DI / IServiceProvider / RpcServiceBase — .NET system calls are resolved via\r\n// DI. TS uses a class with a handle() method.\r\n\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport type { RpcStream } from './rpc-stream.js';\r\nimport { resolveStreamRefs } from './rpc-stream.js';\r\nimport type { RpcStreamSender } from './rpc-stream-sender.js';\r\n\r\n/** Handles incoming system call messages — class-based equivalent of the former standalone function. */\r\nexport class RpcSystemCallHandler {\r\n handle(message: RpcMessage, args: unknown[], peer: RpcPeer): void {\r\n const method = message.Method;\r\n const relatedId = message.RelatedId ?? 0;\r\n\r\n switch (method) {\r\n case RpcSystemCalls.ok: {\r\n const call = peer.outbound.get(relatedId);\r\n if (call !== undefined) {\r\n if (call.removeOnOk) {\r\n peer.outbound.remove(relatedId);\r\n }\r\n call.result.resolve(args[0]);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.error: {\r\n const call = peer.outbound.remove(relatedId);\r\n if (call !== undefined) {\r\n const errorInfo = args[0] as\r\n | Record<string, unknown>\r\n | undefined;\r\n const msg = (errorInfo?.Message ??\r\n errorInfo?.message ??\r\n 'RPC error') as string;\r\n call.result.reject(new Error(msg));\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.cancel: {\r\n // Remote peer is cancelling a call it asked us to process — remove\r\n // from the inbound tracker. Full cancellation propagation (aborting\r\n // the running service handler) is not yet implemented; this just\r\n // unregisters the call so we don't send a response for it.\r\n peer.inbound.remove(relatedId);\r\n break;\r\n }\r\n case RpcSystemCalls.keepAlive: {\r\n // Remote keep-alive — nothing to do, just acknowledges the connection is alive\r\n break;\r\n }\r\n case RpcSystemCalls.item: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.I: no stream for relatedId=${relatedId}`\r\n );\r\n } else {\r\n stream.onItem(\r\n args[0] as number,\r\n resolveStreamRefs(args[1], peer)\r\n );\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.batch: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.B: no stream for relatedId=${relatedId}`\r\n );\r\n } else if (Array.isArray(args[1])) {\r\n const items = args[1] as unknown[];\r\n for (let i = 0; i < items.length; i++)\r\n items[i] = resolveStreamRefs(items[i], peer);\r\n stream.onBatch(args[0] as number, items);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.end: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.End: no stream for relatedId=${relatedId}`\r\n );\r\n } else {\r\n // .NET ExceptionInfo is a struct — even for normal completion, it serializes\r\n // as a non-null object with empty fields (e.g. { \"message\": \"\", \"typeRef\": {...} }).\r\n // Check both PascalCase and camelCase, and treat empty messages as no error.\r\n const errorInfo = args[1] as Record<string, unknown> | null;\r\n const msg = (errorInfo?.Message ?? errorInfo?.message) as\r\n | string\r\n | undefined;\r\n const error = msg ? new Error(msg) : null;\r\n stream.onEnd(args[0] as number, error);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.ack: {\r\n const sender = peer.sharedObjects.get(relatedId) as\r\n | RpcStreamSender<unknown>\r\n | undefined;\r\n sender?.onAck(args[0] as number, args[1] as string);\r\n break;\r\n }\r\n case RpcSystemCalls.ackEnd: {\r\n const sender = peer.sharedObjects.get(relatedId) as\r\n | RpcStreamSender<unknown>\r\n | undefined;\r\n sender?.onAckEnd(args[0] as string);\r\n break;\r\n }\r\n default: {\r\n if (\r\n method === '$sys.Disconnect' ||\r\n method?.startsWith('$sys.Disconnect')\r\n ) {\r\n // Server is telling us the listed remote object IDs have been torn down\r\n // on its side (e.g. shared stream closed). Propagate disconnect() to the\r\n // matching remote objects so any pending consumers (for-await loops) exit\r\n // cleanly instead of hanging.\r\n const ids = args[0] as number[] | undefined;\r\n if (Array.isArray(ids)) {\r\n for (const id of ids) {\r\n const remoteObj = peer.remoteObjects.get(id);\r\n if (\r\n remoteObj &&\r\n typeof remoteObj.disconnect === 'function'\r\n ) {\r\n remoteObj.disconnect();\r\n }\r\n // Also check shared objects — server may disconnect a client-to-server\r\n // stream sender (e.g. audio stream) after pod restart or timeout.\r\n const sharedObj = peer.sharedObjects.get(id);\r\n if (\r\n sharedObj &&\r\n typeof sharedObj.disconnect === 'function'\r\n ) {\r\n sharedObj.disconnect();\r\n }\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcSystemCallSender (202 lines) — a DI-registered service that sends system\r\n// calls by creating RpcOutboundContext + calling PrepareCallForSendNoWait +\r\n// serialising via the full outbound message pipeline.\r\n//\r\n// Omitted from .NET:\r\n// - Complete<TResult>() / typed Ok<TResult>() — .NET serialises the Ok result\r\n// using the method's unwrapped return type for proper polymorphic handling.\r\n// TS uses JSON.stringify(result) which handles any type uniformly.\r\n// - Match() — sends $sys.M when the response hash matches a cached entry,\r\n// avoiding re-sending the full payload. TS has no response caching.\r\n// - NotFound() — TS sends \"Service not found\" / \"Method not found\" as $sys.Error.\r\n// - Disconnect() — sends $sys.Disconnect with object IDs for shared-object\r\n// lifetime management. TS has no shared-object tracker.\r\n// - Ack() / AckEnd() / Item<T>() / Batch<T>() / End() — stream control\r\n// messages for RpcStream. TS has no streaming support yet.\r\n// - RpcOutboundContext / PrepareCallForSendNoWait pipeline — .NET creates a full\r\n// outbound context with MethodDef, ArgumentList, etc., then serialises via the\r\n// peer's MessageSerializer. TS directly calls serializeMessage() (JSON) since\r\n// there's only one serialization format.\r\n// - Tracing / CallLogger integration — .NET logs each system call through the\r\n// peer's CallLogger. TS has no tracing infrastructure.\r\n// - StopMode-aware Error() — .NET checks peer.StopMode to decide whether to\r\n// suppress error responses when the peer is shutting down. TS has no stop\r\n// mode concept.\r\n\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport type { RpcConnection } from './rpc-connection.js';\r\nimport type { RpcSerializationFormat } from './rpc-serialization-format.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/**\r\n * Sends system RPC messages — like .NET's RpcSystemCallSender.\r\n *\r\n * Hot-path allocation notes: `item`, `batch`, `ack`, and `end` are called\r\n * once per stream frame (or once per ack window). Naively building a fresh\r\n * `{ Method, RelatedId }` envelope object plus a fresh two-element arg array\r\n * on every call showed up as ~2-4% self time + non-trivial GC pressure in\r\n * the 300-pull video-load-test profile.\r\n *\r\n * The sender itself is a per-Hub singleton and `_send`/format.serializeMessage\r\n * are fully synchronous (no awaits, no re-entrancy on a single-threaded event\r\n * loop), so we reuse a small pool of preallocated envelope + arg-array slots\r\n * per hot method. Mutate fields just before the send call; the encoder reads\r\n * them synchronously and produces a detached copy, after which the slot is\r\n * free to be mutated again on the next call.\r\n */\r\nexport class RpcSystemCallSender {\r\n // Reusable envelopes — one per hot-path method.\r\n private readonly _itemEnv: RpcMessage = {\r\n Method: RpcSystemCalls.item,\r\n RelatedId: 0,\r\n };\r\n private readonly _batchEnv: RpcMessage = {\r\n Method: RpcSystemCalls.batch,\r\n RelatedId: 0,\r\n };\r\n private readonly _endEnv: RpcMessage = {\r\n Method: RpcSystemCalls.end,\r\n RelatedId: 0,\r\n };\r\n private readonly _ackEnv: RpcMessage = {\r\n Method: RpcSystemCalls.ack,\r\n RelatedId: 0,\r\n };\r\n private readonly _ackEndEnv: RpcMessage = {\r\n Method: RpcSystemCalls.ackEnd,\r\n RelatedId: 0,\r\n };\r\n\r\n // Reusable arg arrays.\r\n private readonly _itemArgs: [number, unknown] = [0, null];\r\n private readonly _batchArgs: [number, unknown] = [0, null];\r\n private readonly _endArgs: [number, { TypeRef: string; Message: string }] =\r\n [0, { TypeRef: '', Message: '' }];\r\n private readonly _ackArgs: [number, string] = [0, ''];\r\n private readonly _ackEndArgs: [string] = [''];\r\n\r\n private static readonly NO_ERROR: { TypeRef: string; Message: string } =\r\n Object.freeze({ TypeRef: '', Message: '' }) as unknown as {\r\n TypeRef: string;\r\n Message: string;\r\n };\r\n\r\n registry?: RpcMethodRegistry;\r\n\r\n private _send(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n envelope: RpcMessage,\r\n args?: unknown[]\r\n ): void {\r\n const wireData = format.serializeMessage(\r\n envelope,\r\n args,\r\n conn.encoder,\r\n this.registry\r\n );\r\n if (typeof wireData === 'string') {\r\n conn.send(wireData);\r\n } else {\r\n conn.sendBinary(wireData);\r\n }\r\n }\r\n\r\n handshake(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n peerId: string,\r\n hubId: string,\r\n index: number\r\n ): void {\r\n // RpcHandshake uses [MessagePackObject] array mode for binary.\r\n const handshakeArg = format.isBinary\r\n ? [peerId, null, hubId, 2, index]\r\n : {\r\n RemotePeerId: peerId,\r\n RemoteApiVersionSet: null,\r\n RemoteHubId: hubId,\r\n ProtocolVersion: 2,\r\n Index: index,\r\n };\r\n this._send(conn, format, { Method: RpcSystemCalls.handshake }, [\r\n handshakeArg,\r\n ]);\r\n }\r\n\r\n ok(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number,\r\n result: unknown\r\n ): void {\r\n this._send(\r\n conn,\r\n format,\r\n { Method: RpcSystemCalls.ok, RelatedId: relatedId },\r\n [result]\r\n );\r\n }\r\n\r\n error(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number,\r\n error: unknown\r\n ): void {\r\n const message = error instanceof Error ? error.message : String(error);\r\n this._send(\r\n conn,\r\n format,\r\n { Method: RpcSystemCalls.error, RelatedId: relatedId },\r\n [{ Message: message }]\r\n );\r\n }\r\n\r\n cancel(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number\r\n ): void {\r\n this._send(conn, format, {\r\n Method: RpcSystemCalls.cancel,\r\n RelatedId: relatedId,\r\n });\r\n }\r\n\r\n keepAlive(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n activeCallIds: number[]\r\n ): void {\r\n this._send(conn, format, { Method: RpcSystemCalls.keepAlive }, [\r\n activeCallIds,\r\n ]);\r\n }\r\n\r\n item(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n item: unknown\r\n ): void {\r\n this._itemEnv.RelatedId = localId;\r\n this._itemArgs[0] = index;\r\n this._itemArgs[1] = item;\r\n this._send(conn, format, this._itemEnv, this._itemArgs);\r\n this._itemArgs[1] = null;\r\n }\r\n\r\n batch(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n items: unknown[]\r\n ): void {\r\n this._batchEnv.RelatedId = localId;\r\n this._batchArgs[0] = index;\r\n this._batchArgs[1] = items;\r\n this._send(conn, format, this._batchEnv, this._batchArgs);\r\n this._batchArgs[1] = null;\r\n }\r\n\r\n end(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n error: {\r\n TypeRef: string;\r\n Message: string;\r\n } = RpcSystemCallSender.NO_ERROR\r\n ): void {\r\n this._endEnv.RelatedId = localId;\r\n this._endArgs[0] = index;\r\n this._endArgs[1] = error;\r\n this._send(conn, format, this._endEnv, this._endArgs);\r\n }\r\n\r\n ack(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n nextIndex: number,\r\n hostId: string\r\n ): void {\r\n this._ackEnv.RelatedId = localId;\r\n this._ackArgs[0] = nextIndex;\r\n this._ackArgs[1] = hostId;\r\n this._send(conn, format, this._ackEnv, this._ackArgs);\r\n }\r\n\r\n ackEnd(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n hostId: string\r\n ): void {\r\n this._ackEndEnv.RelatedId = localId;\r\n this._ackEndArgs[0] = hostId;\r\n this._send(conn, format, this._ackEndEnv, this._ackEndArgs);\r\n }\r\n}\r\n","import type { IRpcObject } from './rpc-object.js';\r\n\r\nexport class RpcRemoteObjectTracker {\r\n private _objects = new Map<number, IRpcObject>();\r\n\r\n register(obj: IRpcObject): void {\r\n this._objects.set(obj.id.localId, obj);\r\n }\r\n\r\n get(localId: number): IRpcObject | undefined {\r\n return this._objects.get(localId);\r\n }\r\n\r\n keys(): IterableIterator<number> {\r\n return this._objects.keys();\r\n }\r\n\r\n unregister(obj: IRpcObject): void {\r\n this._objects.delete(obj.id.localId);\r\n }\r\n\r\n disconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n obj.disconnect();\r\n }\r\n this._objects.clear();\r\n }\r\n\r\n reconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n if (obj.allowReconnect) obj.reconnect();\r\n else obj.disconnect();\r\n }\r\n }\r\n}\r\n","import type { IRpcObject } from './rpc-object.js';\r\n\r\nexport class RpcSharedObjectTracker {\r\n private _nextId = 1;\r\n private _objects = new Map<number, IRpcObject>();\r\n\r\n nextId(): number {\r\n return this._nextId++;\r\n }\r\n\r\n register(obj: IRpcObject): void {\r\n this._objects.set(obj.id.localId, obj);\r\n }\r\n\r\n get(localId: number): IRpcObject | undefined {\r\n return this._objects.get(localId);\r\n }\r\n\r\n keys(): IterableIterator<number> {\r\n return this._objects.keys();\r\n }\r\n\r\n unregister(obj: IRpcObject): void {\r\n this._objects.delete(obj.id.localId);\r\n }\r\n\r\n disconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n obj.disconnect();\r\n }\r\n this._objects.clear();\r\n }\r\n}\r\n","// .NET counterparts:\r\n// RpcPeer (529 lines) — abstract WorkerBase that runs a reconnection loop in\r\n// OnRun(). Manages AsyncState<RpcPeerConnectionState> (a linked list of\r\n// immutable connection snapshots), handshake exchange, peerChanged detection,\r\n// message processing loop, maintenance tasks, Reset(), and SetConnectionState()\r\n// with thread-safe locking.\r\n// RpcClientPeer (56 lines) — calls GetConnection → WebSocket transport.\r\n// RpcServerPeer (54 lines) — receives connection via RpcServerConnectionHandler.\r\n// RpcPeerConnectionKind (48 lines) — None/Remote/Loopback/Local enum.\r\n// RpcPeerConnectionState (42 lines) — immutable record: Connection, Transport,\r\n// Handshake, OwnHandshake, ReaderTokenSource, Error, TryIndex.\r\n// RpcPeerChangeKind (11 lines) — Unchanged/ChangedToVeryFirst/Changed enum.\r\n// RpcHandshake (28 lines) — PeerId, ApiVersionSet, HubId, ProtocolVersion,\r\n// Index. Has GetPeerChangeKind(lastHandshake) comparison method.\r\n// RpcClientPeerReconnectDelayer (35 lines) — exponential backoff profiles:\r\n// test (50ms), server (250ms), client (1s) with 1.5x growth, max 10s.\r\n//\r\n// Ported from .NET:\r\n// - Handshake exchange — run() sends $sys.Handshake on connect, waits for the\r\n// server's response. RpcServerPeer._onHandshakeReceived() auto-replies.\r\n// Like .NET's OnRun() handshake sequence.\r\n// - Peer change detection — run() compares RemoteHubId from successive\r\n// handshakes to detect server restarts, triggering peerChanged + inbound.clear().\r\n// Like .NET's RpcHandshake.GetPeerChangeKind().\r\n// - Outbound call cancellation via AbortSignal — call(signal) registers an\r\n// abort listener that rejects the call, removes it from the tracker, and sends\r\n// $sys.Cancel to the server. Like .NET's CancellationHandler + NotifyCancelled().\r\n//\r\n// Omitted from .NET:\r\n// - AsyncState<RpcPeerConnectionState> — immutable linked-list of connection\r\n// states that consumers can await via WhenConnected/WhenDisconnected. TS uses\r\n// simpler EventHandlerSet events (connected/disconnected). AsyncState enables\r\n// callers to block until a specific state transition, which is essential in\r\n// .NET's multi-threaded world but unnecessary in TS's single-threaded model.\r\n// - RpcPeerConnectionState record — snapshots Connection + Handshake + OwnHandshake\r\n// + ReaderTokenSource + Error + TryIndex. TS tracks these as mutable fields\r\n// on the peer directly.\r\n// - Maintenance tasks (SharedObjects.Maintain, RemoteObjects.Maintain,\r\n// OutboundCalls.Maintain) — background loops that run while connected,\r\n// checking timeouts and managing object lifetimes. TS has simpler keep-alive\r\n// timer; no shared/remote object tracking, no call timeout monitoring.\r\n// - Reconnect protocol (OutboundCalls.Reconnect) — stage-based call resumption\r\n// after reconnection. TS uses transparent reconnect: outbound calls survive\r\n// disconnect, are re-sent on reconnect (stage-3 compute calls self-invalidate\r\n// on peer change instead of being re-sent).\r\n// - peerChangedToken / CancellationTokenSource — .NET threads a cancellation\r\n// token through all inbound calls that gets cancelled when the remote peer\r\n// changes identity. TS clears the inbound tracker on peer change;\r\n// outbound calls survive disconnect and are re-sent on reconnect.\r\n// - Reset() — aborts RemoteObjects, SharedObjects, OutboundCalls, and clears\r\n// InboundCalls. TS clears inbound tracker on peer change; outbound calls\r\n// are never rejected on disconnect (only on close/stop).\r\n// - ServerMethodResolver / GetServerMethodResolver(handshake) — resolves method\r\n// defs using the remote peer's API version set + legacy names. TS has no\r\n// versioning.\r\n// - ProcessMessage() — creates RpcInboundContext per message, dispatches via\r\n// MethodDef.InboundCallInvoker. TS dispatches via _handleMessage →\r\n// handleSystemCall or RpcServiceHost.dispatch.\r\n// - RpcPeerRef / routing — .NET peers are keyed by RpcPeerRef (which encodes\r\n// client/server, route state, versions, serialization format). TS peers are\r\n// keyed by string ref (URL for clients, \"server://{uuid}\" for servers).\r\n// - StopMode / ComputeAutoStopMode — controls behavior of inbound calls when\r\n// peer stops (cancel vs keep-incomplete). TS has no stop mode.\r\n// - ConnectionKind detector (Remote/Loopback/Local/None) — .NET detects if peer\r\n// is in-process. TS is always remote.\r\n// - Versions / VersionSet / API version negotiation — .NET exchanges version\r\n// sets during handshake for backward compatibility. TS has no versioning.\r\n// - Diagnostics (CallLogger, CallLogLevel, DebugLog) — per-peer logging/tracing.\r\n// - Per-call timeout monitoring (OutboundCallTracker.Maintain) — .NET checks\r\n// elapsed time against per-method timeouts. TS relies on WebSocket-level\r\n// disconnect + rejectAll.\r\n// - Inbound call cancellation propagation — when $sys.Cancel is received, .NET\r\n// cancels the inbound call's CancellationTokenSource, aborting the running\r\n// service method. TS removes the call from the inbound tracker but does not\r\n// yet propagate cancellation to the service handler (would require AbortSignal\r\n// threading through RpcServiceHost.dispatch).\r\n\r\nimport { EventHandlerSet, PromiseSource } from '@actuallab/core';\r\nimport { RpcClientPeerReconnectDelayer } from './rpc-client-peer-reconnect-delayer.js';\r\nimport {\r\n RpcWebSocketConnection,\r\n type RpcConnection,\r\n type RpcReceivedMessage,\r\n type WebSocketLike,\r\n} from './rpc-connection.js';\r\nimport {\r\n RpcOutboundCall,\r\n RpcOutboundCallTracker,\r\n RpcInboundCall,\r\n RpcInboundCallTracker,\r\n} from './rpc-call-tracker.js';\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport { deserializeMessage } from './rpc-serialization.js';\r\nimport type { RpcHub } from './rpc-hub.js';\r\nimport { RpcRemoteObjectTracker } from './rpc-remote-object-tracker.js';\r\nimport { RpcSharedObjectTracker } from './rpc-shared-object-tracker.js';\r\nimport { RpcStream } from './rpc-stream.js';\r\nimport { RpcSerializationFormat, RpcSerializationFormatResolver } from './rpc-serialization-format.js';\r\n\r\n/** WebSocket close code sent by the server when the client's serialization format is unsupported. */\r\nexport const RPC_CLOSE_CODE_UNSUPPORTED_FORMAT = 4001;\r\n\r\n/** Builds the WebSocket connection URL for an RpcClientPeer. */\r\nexport type RpcConnectionUrlResolver = (peer: RpcClientPeer) => string;\r\n\r\n/** Default connection URL provider — appends `clientId` and `f` query parameters. */\r\nexport const defaultConnectionUrlResolver: RpcConnectionUrlResolver = peer => {\r\n const sep = peer.ref.includes('?') ? '&' : '?';\r\n return (\r\n peer.ref +\r\n sep +\r\n `clientId=${peer.clientId}&f=${peer.serializationFormat}`\r\n );\r\n};\r\n\r\n/** Options for RpcPeer.call() — allows custom call types and cancellation. */\r\nexport interface RpcCallOptions {\r\n /** Wire CallType field (0 = regular). */\r\n callTypeId?: number;\r\n /** Factory for creating custom outbound call instances (e.g. compute calls). */\r\n outboundCallFactory?: (id: number, method: string) => RpcOutboundCall;\r\n /** AbortSignal for caller-initiated cancellation. */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/** Data extracted from an inbound $sys.Handshake message. */\r\nexport interface RemoteHandshake {\r\n RemotePeerId?: string;\r\n RemoteHubId?: string;\r\n ProtocolVersion?: number;\r\n Index?: number;\r\n}\r\n\r\n/** Base class for RPC peers — handles bidirectional message dispatch. */\r\nexport abstract class RpcPeer {\r\n /** Routing/addressing key — used as key in hub.peers (URL for clients, \"server://{uuid}\" for servers). */\r\n readonly ref: string;\r\n /** Auto-generated GUID — used in handshakes only. */\r\n readonly id: string = crypto.randomUUID();\r\n protected _hub: RpcHub;\r\n protected _connection: RpcConnection | undefined;\r\n readonly outbound = new RpcOutboundCallTracker();\r\n readonly inbound = new RpcInboundCallTracker();\r\n readonly remoteObjects = new RpcRemoteObjectTracker();\r\n readonly sharedObjects = new RpcSharedObjectTracker();\r\n\r\n readonly connected = new EventHandlerSet<void>();\r\n readonly disconnected = new EventHandlerSet<{\r\n code: number;\r\n reason: string;\r\n }>();\r\n\r\n protected _pendingSends: RpcOutboundCall[] = [];\r\n private _keepAliveTimer: ReturnType<typeof setInterval> | undefined;\r\n\r\n constructor(ref: string, hub: RpcHub) {\r\n this.ref = ref;\r\n this._hub = hub;\r\n }\r\n\r\n get hub(): RpcHub {\r\n return this._hub;\r\n }\r\n\r\n get connection(): RpcConnection | undefined {\r\n return this._connection;\r\n }\r\n\r\n get isConnected(): boolean {\r\n return this._connection?.isOpen ?? false;\r\n }\r\n\r\n protected setupConnection(conn: RpcConnection): void {\r\n this._connection = conn;\r\n\r\n conn.messageReceived.add(raw => this._handleMessage(raw));\r\n conn.closed.add(ev => {\r\n this._connection = undefined;\r\n this._stopKeepAlive();\r\n this.disconnected.trigger(ev);\r\n });\r\n\r\n void conn.whenConnected.then(() => {\r\n this.connected.trigger();\r\n this._startKeepAlive();\r\n });\r\n }\r\n\r\n /** The serialization format used by this peer. Override in subclasses. */\r\n get format(): RpcSerializationFormat {\r\n return RpcSerializationFormatResolver.Default.defaultFormat;\r\n }\r\n\r\n call(\r\n method: string,\r\n args?: unknown[],\r\n options?: RpcCallOptions\r\n ): RpcOutboundCall {\r\n const callId = this.outbound.nextId();\r\n const outboundCall = options?.outboundCallFactory\r\n ? options.outboundCallFactory(callId, method)\r\n : new RpcOutboundCall(callId, method);\r\n\r\n const envelope: RpcMessage = {\r\n Method: method,\r\n RelatedId: callId,\r\n CallType: options?.callTypeId ?? 0,\r\n };\r\n outboundCall.serializedWireData = this.format.serializeMessage(\r\n envelope,\r\n args,\r\n this._connection?.encoder,\r\n this._hub.registry\r\n );\r\n if (this._connection !== undefined) {\r\n this.outbound.register(outboundCall);\r\n this._sendWireData(outboundCall.serializedWireData);\r\n } else {\r\n this._pendingSends.push(outboundCall);\r\n }\r\n\r\n // Wire up caller-initiated cancellation → sends $sys.Cancel to remote peer\r\n const signal = options?.signal;\r\n if (signal !== undefined) {\r\n const onAbort = () => {\r\n if (this.outbound.remove(callId) !== undefined) {\r\n outboundCall.result.reject(new Error('Call cancelled.'));\r\n outboundCall.onDisconnect();\r\n if (this._connection !== undefined)\r\n this._hub.systemCallSender.cancel(this._connection, this.format, callId);\r\n } else {\r\n const idx = this._pendingSends.findIndex(\r\n c => c.callId === callId\r\n );\r\n if (idx !== -1) {\r\n this._pendingSends.splice(idx, 1);\r\n outboundCall.result.reject(\r\n new Error('Call cancelled.')\r\n );\r\n outboundCall.onDisconnect();\r\n }\r\n }\r\n };\r\n signal.addEventListener('abort', onAbort, { once: true });\r\n // Clean up listener when the call completes normally\r\n outboundCall.result.promise\r\n .then(() => signal.removeEventListener('abort', onAbort))\r\n .catch(() => signal.removeEventListener('abort', onAbort));\r\n }\r\n\r\n return outboundCall;\r\n }\r\n\r\n callNoWait(method: string, args?: unknown[]): void {\r\n if (this._connection === undefined) return; // silently drop\r\n const envelope: RpcMessage = { Method: method, RelatedId: 0 };\r\n const wireData = this.format.serializeMessage(\r\n envelope,\r\n args,\r\n this._connection.encoder,\r\n this._hub.registry\r\n );\r\n this._sendWireData(wireData);\r\n }\r\n\r\n close(): void {\r\n this._stopKeepAlive();\r\n this.remoteObjects.disconnectAll();\r\n this.sharedObjects.disconnectAll();\r\n for (const call of this._pendingSends) {\r\n if (!call.result.isCompleted)\r\n call.result.reject(new Error('Peer closed.'));\r\n call.onDisconnect();\r\n }\r\n this._pendingSends.length = 0;\r\n this.outbound.rejectAll(new Error('Peer closed.'));\r\n this.outbound.invalidateAll();\r\n this._connection?.close();\r\n this._hub.peers.delete(this.ref);\r\n }\r\n\r\n /** Send any messages buffered while disconnected. Call after connection + handshake are ready. */\r\n protected _flushPendingSends(): void {\r\n if (this._pendingSends.length === 0 || this._connection === undefined)\r\n return;\r\n for (const call of this._pendingSends) {\r\n this.outbound.register(call);\r\n this._sendWireData(call.serializedWireData);\r\n }\r\n this._pendingSends.length = 0;\r\n }\r\n\r\n /** Send pre-serialized wire data through the current connection. */\r\n protected _sendWireData(data: string | Uint8Array): void {\r\n if (this._connection === undefined) return;\r\n if (typeof data === 'string') {\r\n this._connection.send(data);\r\n } else {\r\n this._connection.sendBinary(data);\r\n }\r\n }\r\n\r\n /** Override in subclasses to handle the remote peer's handshake response. */\r\n protected _onHandshakeReceived(_handshake: RemoteHandshake): void {\r\n // Default: no-op. RpcClientPeer resolves a pending promise;\r\n // RpcServerPeer sends its own handshake back.\r\n }\r\n\r\n private _handleMessage(received: RpcReceivedMessage): void {\r\n let message: RpcMessage;\r\n let args: unknown[];\r\n if (received.kind === 'binary') {\r\n message = received.message;\r\n args = received.args;\r\n } else {\r\n const parsed = deserializeMessage(received.raw);\r\n message = parsed.message;\r\n args = parsed.args;\r\n }\r\n const method = message.Method ?? '';\r\n\r\n // Handshake — dispatch to subclass handler\r\n if (method === RpcSystemCalls.handshake) {\r\n const handshake = args[0] as RemoteHandshake | undefined;\r\n if (handshake !== undefined) this._onHandshakeReceived(handshake);\r\n return;\r\n }\r\n\r\n // Other system calls — delegate to hub's system call handler\r\n if (method.startsWith('$sys')) {\r\n this._hub.systemCallHandler.handle(message, args, this);\r\n return;\r\n }\r\n\r\n // Regular inbound call — dispatch to service host\r\n this._handleInbound(message, args);\r\n }\r\n\r\n private _handleInbound(message: RpcMessage, args: unknown[]): void {\r\n const method = message.Method ?? '';\r\n const relatedId = message.RelatedId ?? 0;\r\n\r\n const call = new RpcInboundCall(relatedId, method, args);\r\n const methodDef = this._hub.serviceHost.getMethodDef(method);\r\n\r\n // For noWait calls: don't register in tracker, don't send response\r\n const isNoWait = methodDef?.noWait === true;\r\n if (!isNoWait) {\r\n this.inbound.register(call);\r\n }\r\n\r\n // Dispatch to the hub's service host\r\n const serviceHost = this._hub.serviceHost;\r\n void (async () => {\r\n try {\r\n const context =\r\n this._connection !== undefined\r\n ? {\r\n __rpcDispatch: true as const,\r\n callId: relatedId,\r\n connection: this._connection,\r\n }\r\n : undefined;\r\n const result = await serviceHost.dispatch(\r\n method,\r\n args,\r\n context\r\n );\r\n if (\r\n methodDef?.stream === true &&\r\n this._connection !== undefined\r\n ) {\r\n // Stream method — wrap result in RpcStream if needed,\r\n // then let toRef() create the sender, register it, and start pumping.\r\n const stream = result instanceof RpcStream\r\n ? result as RpcStream<unknown>\r\n : new RpcStream<unknown>(result as AsyncIterable<unknown>);\r\n this._hub.systemCallSender.ok(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n stream.toRef(this)\r\n );\r\n } else if (!isNoWait && this._connection !== undefined) {\r\n this._hub.systemCallSender.ok(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n result\r\n );\r\n }\r\n } catch (e) {\r\n if (!isNoWait && this._connection !== undefined) {\r\n this._hub.systemCallSender.error(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n e\r\n );\r\n }\r\n } finally {\r\n if (!isNoWait) {\r\n this.inbound.remove(relatedId);\r\n }\r\n }\r\n })();\r\n }\r\n\r\n private _startKeepAlive(): void {\r\n this._keepAliveTimer = setInterval(() => {\r\n if (this._connection !== undefined) {\r\n // Send remote object IDs so the server's SharedObjectTracker keeps them alive.\r\n // Must NOT send outbound call IDs — those are a different ID namespace and would\r\n // cause the server to send $sys.Disconnect for IDs it doesn't recognize, which\r\n // the client may misinterpret as a disconnect of its own shared objects (e.g.\r\n // RpcStreamSender) when the IDs collide numerically.\r\n this._hub.systemCallSender.keepAlive(this._connection, this.format, [\r\n ...this.remoteObjects.keys(),\r\n ]);\r\n }\r\n }, 15_000);\r\n }\r\n\r\n private _stopKeepAlive(): void {\r\n if (this._keepAliveTimer !== undefined) {\r\n clearInterval(this._keepAliveTimer);\r\n this._keepAliveTimer = undefined;\r\n }\r\n }\r\n}\r\n\r\n/** Connection state for RpcClientPeer. */\r\nexport const enum RpcPeerConnectionKind {\r\n Disconnected = 0,\r\n Connecting = 1,\r\n Connected = 2,\r\n}\r\n\r\n/** Client-side RPC peer — initiates WebSocket connection. ref = URL. */\r\nexport class RpcClientPeer extends RpcPeer {\r\n private _disposed = false;\r\n private _connectionKind = RpcPeerConnectionKind.Disconnected;\r\n private _tryIndex = 0;\r\n private _handshakeIndex = 0;\r\n private _lastRemoteHubId: string | undefined;\r\n private _pendingHandshake: PromiseSource<RemoteHandshake> | undefined;\r\n private _reconnectsAt = 0;\r\n\r\n /** Base64url-encoded peer ID — matches .NET's RpcClientPeer.ClientId (Guid.ToBase64Url). */\r\n readonly clientId: string;\r\n /**\r\n * Serialization format key sent to the server via `f=` query parameter.\r\n * TS uses plain JSON.stringify (no polymorphic type wrapping), so `json5np`\r\n * (no-polymorphism) is the correct default.\r\n */\r\n readonly serializationFormat: string;\r\n /** Builds the WebSocket URL for this peer. Replace to customize URL construction. */\r\n connectionUrlResolver: RpcConnectionUrlResolver =\r\n defaultConnectionUrlResolver;\r\n readonly peerChanged = new EventHandlerSet<void>();\r\n /** Fired when the server rejects the connection due to an unsupported serialization format (close code 4010). */\r\n readonly unsupportedFormat = new EventHandlerSet<{ reason: string }>();\r\n readonly reconnectDelayer = new RpcClientPeerReconnectDelayer();\r\n readonly reconnectsAtChanged = new EventHandlerSet<void>();\r\n\r\n get reconnectsAt(): number {\r\n return this._reconnectsAt;\r\n }\r\n\r\n private _setReconnectsAt(value: number): void {\r\n if (this._reconnectsAt === value) return;\r\n this._reconnectsAt = value;\r\n this.reconnectsAtChanged.trigger();\r\n }\r\n\r\n private _format: RpcSerializationFormat;\r\n\r\n constructor(hub: RpcHub, url: string, serializationFormat?: string) {\r\n super(url, hub);\r\n this.clientId = guidToBase64Url(this.id);\r\n const resolver = RpcSerializationFormatResolver.Default;\r\n this.serializationFormat =\r\n serializationFormat ?? resolver.defaultFormatKey;\r\n this._format = resolver.get(this.serializationFormat);\r\n }\r\n\r\n override get format(): RpcSerializationFormat {\r\n return this._format;\r\n }\r\n\r\n get connectionKind(): RpcPeerConnectionKind {\r\n return this._connectionKind;\r\n }\r\n\r\n /** One-shot connection for tests — no reconnection loop, no handshake. */\r\n connectWith(conn: RpcConnection): void {\r\n // Set up new connection and re-send outbound calls (treat as peer change —\r\n // no handshake exchange to determine same-peer, so stage-3 compute calls\r\n // are self-invalidated while regular in-flight calls are re-sent).\r\n this.setupConnection(conn);\r\n this._reconnect(true);\r\n }\r\n\r\n /** Start the reconnection loop — runs until disposed. */\r\n async run(wsFactory?: (url: string) => WebSocketLike): Promise<void> {\r\n const connUrl = this.connectionUrlResolver(this);\r\n while (!this._disposed) {\r\n let lastCloseCode = 0;\r\n let lastCloseReason = '';\r\n try {\r\n const ws =\r\n wsFactory?.(connUrl) ??\r\n (new WebSocket(connUrl) as unknown as WebSocketLike);\r\n const conn = new RpcWebSocketConnection(\r\n ws,\r\n this.format.isBinary,\r\n this.format,\r\n this._hub.registry\r\n );\r\n this._connectionKind = RpcPeerConnectionKind.Connecting;\r\n\r\n // Track close info for unsupported format detection\r\n conn.closed.add(ev => {\r\n lastCloseCode = ev.code;\r\n lastCloseReason = ev.reason;\r\n });\r\n\r\n // Create a fresh handshake promise before setupConnection (which registers\r\n // the message handler). The handler can only fire after the WS opens,\r\n // and we send our handshake below, so timing is safe.\r\n this._pendingHandshake = new PromiseSource<RemoteHandshake>();\r\n this.setupConnection(conn);\r\n // Keep _connection undefined until handshake completes — prevents\r\n // calls from being sent through the connection before the handshake\r\n // (which the .NET server cannot process). Calls made during this\r\n // window go to _pendingSends and are flushed after handshake.\r\n this._connection = undefined;\r\n\r\n // Race connection open against close — if WS fails to connect,\r\n // whenConnected stays pending forever, so we must also watch for close.\r\n const closedRejection = new Promise<never>((_, reject) =>\r\n conn.closed.add(() =>\r\n reject(new Error('Connection failed'))\r\n )\r\n );\r\n closedRejection.catch(() => { /* noop — prevent unhandled rejection when conn closes normally */ });\r\n await Promise.race([conn.whenConnected, closedRejection]);\r\n\r\n // Send our handshake, then wait for the server's response.\r\n this._hub.systemCallSender.handshake(\r\n conn,\r\n this.format,\r\n this.id,\r\n this._hub.hubId,\r\n ++this._handshakeIndex\r\n );\r\n const remoteHandshake = await Promise.race([\r\n this._pendingHandshake.promise,\r\n closedRejection,\r\n ]);\r\n this._pendingHandshake = undefined;\r\n\r\n // Peer change detection (like .NET's RpcHandshake.GetPeerChangeKind)\r\n const remoteHubId = remoteHandshake.RemoteHubId;\r\n let isPeerChanged = false;\r\n if (remoteHubId !== undefined) {\r\n isPeerChanged =\r\n this._lastRemoteHubId !== undefined &&\r\n this._lastRemoteHubId !== remoteHubId;\r\n if (isPeerChanged) {\r\n // Server identity changed — clear inbound state\r\n this.inbound.clear();\r\n this.peerChanged.trigger();\r\n }\r\n this._lastRemoteHubId = remoteHubId;\r\n }\r\n\r\n // Activate the connection and re-send outbound calls.\r\n // All of this happens AFTER the handshake, so the server is ready to process calls.\r\n this._connection = conn;\r\n this._connectionKind = RpcPeerConnectionKind.Connected;\r\n this._tryIndex = 0;\r\n this._reconnect(isPeerChanged);\r\n\r\n // Wait until disconnected\r\n await new Promise<void>(r => conn.closed.add(() => r()));\r\n } catch {\r\n // connection failed or handshake failed\r\n }\r\n\r\n this._connectionKind = RpcPeerConnectionKind.Disconnected;\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _disposed can change during await\r\n if (this._disposed) break;\r\n\r\n // Server rejected our serialization format — stop reconnecting and notify listeners\r\n if (lastCloseCode === RPC_CLOSE_CODE_UNSUPPORTED_FORMAT) {\r\n this.unsupportedFormat.trigger({ reason: lastCloseReason });\r\n this._disposed = true;\r\n break;\r\n }\r\n\r\n this._tryIndex++;\r\n const delay = this.reconnectDelayer.getDelay(this._tryIndex);\r\n if (delay.isLimitExceeded) {\r\n this._disposed = true;\r\n break;\r\n }\r\n this._setReconnectsAt(delay.endsAt);\r\n try {\r\n await delay.promise;\r\n } finally {\r\n this._setReconnectsAt(0);\r\n }\r\n }\r\n }\r\n\r\n /** Re-send outbound calls after reconnection + flush pending sends.\r\n * Stage-3 compute calls are always self-invalidated: without $sys.Reconnect\r\n * protocol, the server's invalidation tracking is lost on disconnect, and\r\n * re-sending would get a duplicate $sys.Ok that is ignored (PromiseSource\r\n * already resolved). Self-invalidation forces a fresh recompute that\r\n * establishes new invalidation tracking on the new connection.\r\n * Regular in-flight calls are re-sent transparently. */\r\n private _reconnect(_isPeerChanged: boolean): void {\r\n if (this._connection === undefined) return;\r\n\r\n // Handle remote objects on reconnect\r\n if (_isPeerChanged) {\r\n this.remoteObjects.disconnectAll();\r\n } else {\r\n this.remoteObjects.reconnectAll();\r\n }\r\n\r\n // Re-send existing tracker calls (self-invalidate stage-3 compute calls)\r\n const trackerCalls = [...this.outbound.values()];\r\n for (const call of trackerCalls) {\r\n if (!call.removeOnOk && call.result.isCompleted) {\r\n // Stage-3 compute call: self-invalidate, forcing fresh recompute\r\n call.onDisconnect();\r\n this.outbound.remove(call.callId);\r\n } else {\r\n // Regular call or in-flight compute call: re-send\r\n this._sendWireData(call.serializedWireData);\r\n }\r\n }\r\n\r\n // Flush calls buffered while disconnected\r\n this._flushPendingSends();\r\n }\r\n\r\n protected override _onHandshakeReceived(handshake: RemoteHandshake): void {\r\n this._pendingHandshake?.resolve(handshake);\r\n }\r\n\r\n override close(): void {\r\n this._disposed = true;\r\n super.close();\r\n }\r\n}\r\n\r\n/** Server-side RPC peer — wraps an accepted connection. ref = \"server://{uuid}\". */\r\nexport class RpcServerPeer extends RpcPeer {\r\n constructor(hub: RpcHub, ref: string) {\r\n super(ref, hub);\r\n }\r\n\r\n /** Accept an incoming connection — sets up message handling and handshake response. */\r\n accept(conn: RpcConnection): void {\r\n this.setupConnection(conn);\r\n }\r\n\r\n protected override _onHandshakeReceived(_handshake: RemoteHandshake): void {\r\n // Client sent its handshake → respond with our own\r\n if (this._connection !== undefined) {\r\n this._hub.systemCallSender.handshake(\r\n this._connection,\r\n this.format,\r\n this.id,\r\n this._hub.hubId,\r\n 0\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Convert a UUID string to base64url — matches .NET's Guid.ToBase64Url().\r\n * .NET Guid stores the first 3 groups in little-endian byte order.\r\n */\r\nfunction guidToBase64Url(uuid: string): string {\r\n const hex = uuid.replace(/-/g, '');\r\n const bytes = new Uint8Array(16);\r\n\r\n // Group 1 (bytes 0-3): little-endian\r\n bytes[0] = parseInt(hex.slice(6, 8), 16);\r\n bytes[1] = parseInt(hex.slice(4, 6), 16);\r\n bytes[2] = parseInt(hex.slice(2, 4), 16);\r\n bytes[3] = parseInt(hex.slice(0, 2), 16);\r\n // Group 2 (bytes 4-5): little-endian\r\n bytes[4] = parseInt(hex.slice(10, 12), 16);\r\n bytes[5] = parseInt(hex.slice(8, 10), 16);\r\n // Group 3 (bytes 6-7): little-endian\r\n bytes[6] = parseInt(hex.slice(14, 16), 16);\r\n bytes[7] = parseInt(hex.slice(12, 14), 16);\r\n // Groups 4-5 (bytes 8-15): big-endian\r\n for (let i = 8; i < 16; i++)\r\n bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\r\n\r\n const binary = String.fromCharCode(...bytes);\r\n return btoa(binary)\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=+$/, '');\r\n}\r\n","// .NET counterpart: ActualLab.Rpc.RpcClientPeerReconnectDelayer\r\n\r\nimport { RetryDelaySeq, RetryDelayer } from '@actuallab/core';\r\n\r\nexport class RpcClientPeerReconnectDelayer extends RetryDelayer {\r\n constructor() {\r\n super();\r\n this.delays = RetryDelaySeq.exp(1000, 60_000); // 1s min, 60s max\r\n }\r\n}\r\n","// RPC serialization format definitions — mirrors .NET RpcSerializationFormat.\r\n//\r\n// Each format knows how to serialize/deserialize RPC messages on the wire.\r\n// Format instances are immutable singletons — state like method registries\r\n// is passed in via parameters, not held by the format.\r\n\r\nimport { Encoder, Decoder } from '@msgpack/msgpack';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport {\r\n serializeMessage,\r\n deserializeMessage,\r\n serializeBinaryMessage,\r\n splitBinaryFrame,\r\n serializeBinaryFrame,\r\n createBinaryEncoder,\r\n serializeCompactBinaryMessage,\r\n splitCompactBinaryFrame,\r\n} from './rpc-serialization.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/** Parsed inbound message — result of deserialization. */\r\nexport interface RpcDeserializedMessage {\r\n message: RpcMessage;\r\n args: unknown[];\r\n}\r\n\r\n/** Wire data produced by serialization — either text or binary. */\r\nexport type RpcWireData = string | Uint8Array;\r\n\r\n/**\r\n * Base class for RPC serialization formats.\r\n * Instances are immutable singletons — one per format key.\r\n * State (like method registries) is passed via parameters.\r\n */\r\nexport abstract class RpcSerializationFormat {\r\n abstract readonly key: string;\r\n abstract readonly isBinary: boolean;\r\n /** Whether this format uses compact method hashes (needs RpcMethodRegistry). */\r\n abstract readonly isCompact: boolean;\r\n\r\n /** Serialize an outbound message. */\r\n abstract serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcWireData;\r\n\r\n /** Deserialize a single text message (only called for text formats). */\r\n abstract deserializeTextMessage(raw: string): RpcDeserializedMessage;\r\n\r\n /** Split + deserialize a binary frame (only called for binary formats). */\r\n abstract splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcDeserializedMessage[];\r\n\r\n /** Concatenate multiple serialized binary messages into one frame. */\r\n abstract serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;\r\n\r\n /** Create a reusable binary encoder for this format. Returns undefined for text formats. */\r\n createEncoder(): Encoder | undefined {\r\n return undefined;\r\n }\r\n\r\n /** Create a reusable binary decoder for this format. Returns undefined for text formats. */\r\n createDecoder(): Decoder | undefined {\r\n return undefined;\r\n }\r\n\r\n // Named format instances — initialized in initFormats() below (after subclasses are defined)\r\n static SystemJsonV5: RpcSerializationFormat;\r\n static SystemJsonV5NP: RpcSerializationFormat;\r\n static NewtonsoftJsonV5: RpcSerializationFormat;\r\n static NewtonsoftJsonV5NP: RpcSerializationFormat;\r\n static MessagePackV6: RpcSerializationFormat;\r\n static MemoryPackV6: RpcSerializationFormat;\r\n static MessagePackV6C: RpcSerializationFormat;\r\n static MemoryPackV6C: RpcSerializationFormat;\r\n static All: readonly RpcSerializationFormat[];\r\n\r\n /** Convenience shortcut for RpcSerializationFormatResolver.Default.get(key). */\r\n static get(key: string): RpcSerializationFormat {\r\n return RpcSerializationFormatResolver.Default.get(key);\r\n }\r\n\r\n /** Convenience shortcut for RpcSerializationFormatResolver.Default.tryGet(key). */\r\n static tryGet(key: string): RpcSerializationFormat | undefined {\r\n return RpcSerializationFormatResolver.Default.tryGet(key);\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Concrete formats (immutable singletons)\r\n// ============================================================\r\n\r\n/**\r\n * JSON text format — \"json5np\" (System.Text.Json, no polymorphism).\r\n */\r\nexport class RpcJsonSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = false;\r\n readonly isCompact = false;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(message: RpcMessage, args?: unknown[]): string {\r\n return serializeMessage(message, args);\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(): RpcDeserializedMessage[] {\r\n throw new Error('Text format does not support binary frames');\r\n }\r\n\r\n serializeBinaryFrame(): Uint8Array {\r\n throw new Error('Text format does not support binary frames');\r\n }\r\n}\r\n\r\n/**\r\n * MessagePack binary format — \"msgpack6\" / \"mempack6\" (V5 wire format).\r\n */\r\nexport class RpcMessagePackSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = true;\r\n readonly isCompact = false;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder\r\n ): Uint8Array {\r\n return serializeBinaryMessage(message, args, encoder);\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder\r\n ): RpcDeserializedMessage[] {\r\n return splitBinaryFrame(frame, decoder);\r\n }\r\n\r\n serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return serializeBinaryFrame(messages);\r\n }\r\n\r\n override createEncoder(): Encoder {\r\n return createBinaryEncoder();\r\n }\r\n\r\n override createDecoder(): Decoder {\r\n return new Decoder();\r\n }\r\n}\r\n\r\n/**\r\n * MessagePack compact binary format — \"msgpack6c\" / \"mempack6c\" (V5Compact).\r\n * Uses 4-byte method hash instead of full method name.\r\n * Registry is passed via parameters — format instance is immutable.\r\n */\r\nexport class RpcMessagePackCompactSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = true;\r\n readonly isCompact = true;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder,\r\n registry?: RpcMethodRegistry\r\n ): Uint8Array {\r\n return serializeCompactBinaryMessage(\r\n message,\r\n args,\r\n registry,\r\n encoder\r\n );\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcDeserializedMessage[] {\r\n return splitCompactBinaryFrame(frame, registry, decoder);\r\n }\r\n\r\n serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return serializeBinaryFrame(messages);\r\n }\r\n\r\n override createEncoder(): Encoder {\r\n return createBinaryEncoder();\r\n }\r\n\r\n override createDecoder(): Decoder {\r\n return new Decoder();\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Initialize named format instances (after subclasses are defined)\r\n// ============================================================\r\n\r\n// Text: System.Text.Json\r\nRpcSerializationFormat.SystemJsonV5 = new RpcJsonSerializationFormat('json5');\r\nRpcSerializationFormat.SystemJsonV5NP = new RpcJsonSerializationFormat('json5np');\r\n// Text: Newtonsoft.Json\r\nRpcSerializationFormat.NewtonsoftJsonV5 = new RpcJsonSerializationFormat('njson5');\r\nRpcSerializationFormat.NewtonsoftJsonV5NP = new RpcJsonSerializationFormat('njson5np');\r\n// Binary: MessagePack (non-compact)\r\nRpcSerializationFormat.MessagePackV6 = new RpcMessagePackSerializationFormat('msgpack6');\r\nRpcSerializationFormat.MemoryPackV6 = new RpcMessagePackSerializationFormat('mempack6');\r\n// Binary: MessagePack (compact)\r\nRpcSerializationFormat.MessagePackV6C = new RpcMessagePackCompactSerializationFormat('msgpack6c');\r\nRpcSerializationFormat.MemoryPackV6C = new RpcMessagePackCompactSerializationFormat('mempack6c');\r\n\r\nRpcSerializationFormat.All = [\r\n RpcSerializationFormat.SystemJsonV5,\r\n RpcSerializationFormat.SystemJsonV5NP,\r\n RpcSerializationFormat.NewtonsoftJsonV5,\r\n RpcSerializationFormat.NewtonsoftJsonV5NP,\r\n RpcSerializationFormat.MessagePackV6,\r\n RpcSerializationFormat.MemoryPackV6,\r\n RpcSerializationFormat.MessagePackV6C,\r\n RpcSerializationFormat.MemoryPackV6C,\r\n];\r\n\r\n// ============================================================\r\n// RpcSerializationFormatResolver — mirrors .NET RpcSerializationFormatResolver\r\n// ============================================================\r\n\r\n/**\r\n * Resolves RpcSerializationFormat instances by key, with a configurable default.\r\n * Mirrors .NET RpcSerializationFormatResolver.\r\n */\r\nexport class RpcSerializationFormatResolver {\r\n static DefaultFormats: readonly RpcSerializationFormat[] = RpcSerializationFormat.All;\r\n static Default = new RpcSerializationFormatResolver('json5np');\r\n\r\n readonly defaultFormatKey: string;\r\n readonly formats: ReadonlyMap<string, RpcSerializationFormat>;\r\n\r\n get defaultFormat(): RpcSerializationFormat {\r\n return this.get(this.defaultFormatKey);\r\n }\r\n\r\n constructor(defaultFormatKey: string, formats?: Iterable<RpcSerializationFormat>) {\r\n const map = new Map<string, RpcSerializationFormat>();\r\n for (const f of formats ?? RpcSerializationFormatResolver.DefaultFormats)\r\n map.set(f.key, f);\r\n\r\n if (!map.has(defaultFormatKey))\r\n throw new Error(`No format with key '${defaultFormatKey}'.`);\r\n\r\n this.defaultFormatKey = defaultFormatKey;\r\n this.formats = map;\r\n }\r\n\r\n get(key: string): RpcSerializationFormat {\r\n const format = this.tryGet(key);\r\n if (!format)\r\n throw new Error(`No format with key '${key}'.`);\r\n return format;\r\n }\r\n\r\n tryGet(key: string): RpcSerializationFormat | undefined {\r\n if (!key) key = this.defaultFormatKey;\r\n return this.formats.get(key);\r\n }\r\n}\r\n","// .NET counterparts:\r\n// RpcServiceBase (17 lines) — abstract base class providing DI access (Services,\r\n// Hub, Log). All RPC service implementations inherit from it.\r\n// RpcServiceRegistry — builds the full map of all services and their method defs\r\n// at startup; provides GetServerMethodResolver() for version-aware method\r\n// lookup. Inbound call dispatch is handled by RpcInboundCall.Process() which\r\n// invokes the method via a compiled delegate chain (MethodDef.InboundCallInvoker).\r\n//\r\n// Omitted from .NET:\r\n// - Compiled delegate pipeline — .NET pre-compiles per-method invoker delegates\r\n// (InboundCallServerInvokerFactory<T>, InboundCallMiddlewareInvokerFactory<T>)\r\n// using generic type instantiation. These invokers handle deserialization,\r\n// middleware chain, server method invocation, and result serialization — all\r\n// as a strongly-typed Task<TResult>. TS uses a simple async function dispatch\r\n// via fn(...args) because there's no middleware pipeline and JSON handles any\r\n// type.\r\n// - ServiceResolver (DI-based lazy service resolution) — .NET resolves the\r\n// service implementation from DI on first use. TS receives the impl object\r\n// directly in register().\r\n// - RpcServiceMode (Local/Client/Server/Hybrid) — .NET classifies each service\r\n// registration. TS has no mode; services are either registered (server) or\r\n// proxied (client).\r\n// - Version-aware method resolution (ServerMethodResolver with legacy names) —\r\n// .NET can resolve methods by legacy names for rolling-upgrade compatibility.\r\n// TS has no versioning.\r\n// - RpcInboundContext / AsyncLocal — .NET sets thread-local inbound context\r\n// so system call handlers can access the current peer/message. TS passes\r\n// context explicitly as a function argument (RpcDispatchContext).\r\n\r\nimport type { RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName } from './rpc-service-def.js';\r\nimport type { RpcServiceDef } from './rpc-service-def.js';\r\nimport type { RpcConnection } from './rpc-connection.js';\r\n\r\nexport type RpcServiceImpl = Record<string, ((...args: unknown[]) => unknown) | undefined>;\r\n\r\n/** Context passed to service dispatch — carries callId and connection for compute tracking. */\r\nexport interface RpcDispatchContext {\r\n __rpcDispatch: true;\r\n callId: number;\r\n connection: RpcConnection;\r\n}\r\n\r\n/** Dispatches inbound RPC calls to registered service implementations. */\r\nexport class RpcServiceHost {\r\n private _methods = new Map<\r\n string,\r\n { def: RpcMethodDef; fn: (...args: unknown[]) => unknown }\r\n >();\r\n\r\n register(def: RpcServiceDef, impl: RpcServiceImpl): void {\r\n for (const methodDef of def.methods.values()) {\r\n const fn = impl[methodDef.name];\r\n if (!fn) continue;\r\n this._methods.set(wireMethodName(methodDef), {\r\n def: methodDef,\r\n fn,\r\n });\r\n }\r\n }\r\n\r\n async dispatch(\r\n wireMethod: string,\r\n args: unknown[],\r\n context?: RpcDispatchContext\r\n ): Promise<unknown> {\r\n const entry = this._methods.get(wireMethod);\r\n if (entry === undefined)\r\n throw new Error(`Method not found: ${wireMethod}`);\r\n\r\n // Pass context as the last arg only for custom call types (e.g., compute) — their\r\n // wrapped functions use it; regular methods should not see it to avoid polluting ...args.\r\n if (context !== undefined && entry.def.callTypeId !== 0) {\r\n return await entry.fn(...args, context);\r\n }\r\n return await entry.fn(...args);\r\n }\r\n\r\n getMethodDef(wireMethod: string): RpcMethodDef | undefined {\r\n return this._methods.get(wireMethod)?.def;\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcMethodAttribute — optional attribute that can override a method's wire name.\r\n// Method metadata (arg count, return type, NoWait, stream, etc.) is discovered\r\n// automatically via reflection on the service interface.\r\n// Interface-based metadata — .NET discovers all methods by reflecting on the\r\n// service interface type. NoWait is determined by return type == Task<RpcNoWait>.\r\n// Stream is determined by return type being IAsyncEnumerable<T>.\r\n//\r\n// Omitted from .NET:\r\n// - Reflection-based auto-discovery — .NET scans interface methods, parameter\r\n// types, and return types at startup. TS uses explicit decorator metadata\r\n// because TypeScript erases type information at runtime.\r\n// - RpcMethodAttribute.Name — custom wire name override. TS decorators don't\r\n// support custom wire names (always \"ServiceName.methodName\").\r\n// - RpcServiceAttribute — .NET has no class-level decorator; the service name\r\n// is configured in RpcServiceBuilder via DI. TS uses @rpcService(\"name\")\r\n// class decorator as a convenient alternative to DI configuration.\r\n// - Automatic NoWait detection from return type — .NET checks if return type\r\n// is Task<RpcNoWait>. TS requires explicit { returns: RpcType.noWait }\r\n// because return types are erased.\r\n// - Automatic stream detection from return type — .NET checks for\r\n// IAsyncEnumerable<T>. TS requires explicit { returns: RpcType.stream }.\r\n// - compute flag in method metadata — stored here for FusionHub's\r\n// addServiceFromContract() which reads decorator metadata to build a\r\n// RpcServiceDef. .NET determines this via the service interface hierarchy\r\n// (IComputeService marker interface).\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\nconst SERVICE_META = Symbol.for('actuallab.service');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n returns?: symbol;\r\n [key: symbol]: unknown;\r\n}\r\n\r\nexport interface ServiceMeta {\r\n name: string;\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- constructor type requires any for maximum compatibility\r\nexport type AnyConstructor = abstract new (...args: any[]) => any;\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: AnyConstructor,\r\n): Record<string, MethodMeta> | undefined {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- Symbol.metadata is not in standard typings\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META] as Record<string, MethodMeta> | undefined;\r\n}\r\n\r\n/** Read service metadata from a decorated class. */\r\nexport function getServiceMeta(\r\n cls: AnyConstructor,\r\n): ServiceMeta | undefined {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- Symbol.metadata is not in standard typings\r\n return (cls as any)[Symbol.metadata]?.[SERVICE_META] as ServiceMeta | undefined;\r\n}\r\n\r\n/** Class decorator — stores the RPC service wire name. */\r\nexport function rpcService(serviceName: string) {\r\n return function <T extends AnyConstructor>(\r\n _target: T,\r\n context: ClassDecoratorContext<T>,\r\n ): void {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- decorator metadata requires untyped access\r\n const meta: ServiceMeta = ((context.metadata as any)[SERVICE_META] ??=\r\n {} as ServiceMeta);\r\n meta.name = serviceName;\r\n };\r\n}\r\n\r\n/** Method decorator — stores RPC method metadata (argCount, returns). Does NOT wrap the method. */\r\nexport function rpcMethod(options?: { returns?: symbol }) {\r\n return function <This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n ): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- decorator metadata requires untyped access */\r\n const methods: Record<string, MethodMeta> = ((context.metadata as any)[\r\n METHODS_META\r\n ] ??= {});\r\n /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n argCount: target.length,\r\n returns: options?.returns,\r\n };\r\n return target; // no wrapping — RPC proxy handles invocation\r\n };\r\n}\r\n","// Pure TypeScript XXH3-64 implementation using BigInt.\r\n// Sync, zero dependencies. Supports inputs of any length.\r\n//\r\n// Reference: https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h\r\n// Verified against .NET System.IO.Hashing.XxHash3.HashToUInt64.\r\n\r\n \r\n\r\nconst U64_MASK = 0xffff_ffff_ffff_ffffn;\r\nconst U32_MASK = 0xffff_ffffn;\r\n\r\nconst PRIME32_1 = 0x9e3779b1;\r\nconst PRIME32_2 = 0x85ebca77;\r\nconst PRIME32_3 = 0xc2b2ae3d;\r\n\r\nconst PRIME64_1 = 0x9e3779b185ebca87n;\r\nconst PRIME64_2 = 0xc2b2ae3d27d4eb4fn;\r\nconst PRIME64_3 = 0x165667b19e3779f9n;\r\nconst PRIME64_4 = 0x85ebca77c2b2ae63n;\r\nconst PRIME64_5 = 0x27d4eb2f165667c5n;\r\n\r\nconst XXH3_SECRET_SIZE_MIN = 136;\r\nconst XXH_SECRET_DEFAULT_SIZE = 192;\r\n\r\nconst STRIPE_LEN = 64;\r\nconst XXH_SECRET_CONSUME_RATE = 8;\r\nconst ACC_NB = STRIPE_LEN / 8;\r\n\r\nconst XXH3_MIDSIZE_MAX = 240;\r\nconst XXH3_MIDSIZE_STARTOFFSET = 3;\r\nconst XXH3_MIDSIZE_LASTOFFSET = 17;\r\nconst XXH_SECRET_LASTACC_START = 7;\r\nconst XXH_SECRET_MERGEACCS_START = 11;\r\n\r\nconst RRMXMX = 0x9fb21c651e98df25n;\r\n\r\n// prettier-ignore\r\nconst DEFAULT_SECRET = new Uint8Array([\r\n 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,\r\n 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,\r\n 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,\r\n 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,\r\n 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,\r\n 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,\r\n 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,\r\n 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,\r\n 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,\r\n 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,\r\n 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,\r\n 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,\r\n]);\r\n\r\nfunction u64(x: bigint): bigint {\r\n return x & U64_MASK;\r\n}\r\n\r\nfunction read32LE(buf: Uint8Array, off: number): number {\r\n return (\r\n (buf[off] |\r\n (buf[off + 1] << 8) |\r\n (buf[off + 2] << 16) |\r\n (buf[off + 3] << 24)) >>>\r\n 0\r\n );\r\n}\r\n\r\nfunction read64LE(buf: Uint8Array, off: number): bigint {\r\n return (\r\n BigInt(buf[off]) |\r\n (BigInt(buf[off + 1]) << 8n) |\r\n (BigInt(buf[off + 2]) << 16n) |\r\n (BigInt(buf[off + 3]) << 24n) |\r\n (BigInt(buf[off + 4]) << 32n) |\r\n (BigInt(buf[off + 5]) << 40n) |\r\n (BigInt(buf[off + 6]) << 48n) |\r\n (BigInt(buf[off + 7]) << 56n)\r\n );\r\n}\r\n\r\nfunction write64LE(buf: Uint8Array, off: number, value: bigint): void {\r\n let x = u64(value);\r\n for (let i = 0; i < 8; i++) {\r\n buf[off + i] = Number(x & 0xffn);\r\n x >>= 8n;\r\n }\r\n}\r\n\r\nfunction swap32(x: number): number {\r\n return (\r\n (((x << 24) & 0xff000000) |\r\n ((x << 8) & 0x00ff0000) |\r\n ((x >>> 8) & 0x0000ff00) |\r\n ((x >>> 24) & 0x000000ff)) >>>\r\n 0\r\n );\r\n}\r\n\r\nfunction swap64(x: bigint): bigint {\r\n x = u64(x);\r\n return (\r\n ((x << 56n) & 0xff00000000000000n) |\r\n ((x << 40n) & 0x00ff000000000000n) |\r\n ((x << 24n) & 0x0000ff0000000000n) |\r\n ((x << 8n) & 0x000000ff00000000n) |\r\n ((x >> 8n) & 0x00000000ff000000n) |\r\n ((x >> 24n) & 0x0000000000ff0000n) |\r\n ((x >> 40n) & 0x000000000000ff00n) |\r\n ((x >> 56n) & 0x00000000000000ffn)\r\n );\r\n}\r\n\r\nfunction rotl64(x: bigint, amount: number): bigint {\r\n const r = BigInt(amount & 63);\r\n return u64((x << r) | (x >> (64n - r)));\r\n}\r\n\r\nfunction mul128Fold64(lhs: bigint, rhs: bigint): bigint {\r\n const product = u64(lhs) * u64(rhs);\r\n return u64(product) ^ u64(product >> 64n);\r\n}\r\n\r\n// XXH64_avalanche — used by len_0 and len_1to3\r\nfunction xxh64Avalanche(hash: bigint): bigint {\r\n let h = u64(hash);\r\n h ^= h >> 33n;\r\n h = u64(h * PRIME64_2);\r\n h ^= h >> 29n;\r\n h = u64(h * PRIME64_3);\r\n h ^= h >> 32n;\r\n return u64(h);\r\n}\r\n\r\n// XXH3_avalanche — used by len_9to16, len_17to128, len_129to240\r\nfunction xxh3Avalanche(hash: bigint): bigint {\r\n let h = u64(hash);\r\n h ^= h >> 37n;\r\n h = u64(h * 0x165667919e3779f9n);\r\n h ^= h >> 32n;\r\n return u64(h);\r\n}\r\n\r\nfunction len0(secret: Uint8Array, seed: bigint): bigint {\r\n const acc = u64(seed ^ read64LE(secret, 56) ^ read64LE(secret, 64));\r\n return xxh64Avalanche(acc);\r\n}\r\n\r\nfunction len1to3(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n const byte1 = input[0];\r\n const byte2 = length > 1 ? input[1] : input[0];\r\n const byte3 = input[length - 1];\r\n const combined =\r\n ((byte1 << 16) | (byte2 << 24) | byte3 | (length << 8)) >>> 0;\r\n const bitflip = u64(\r\n BigInt((read32LE(secret, 0) ^ read32LE(secret, 4)) >>> 0) + seed\r\n );\r\n const value64 = u64(BigInt(combined) ^ bitflip);\r\n return xxh64Avalanche(value64);\r\n}\r\n\r\nfunction len4to8(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n const inputHi = read32LE(input, 0);\r\n const inputLo = read32LE(input, length - 4);\r\n const input64 = BigInt(inputLo) | (BigInt(inputHi) << 32n);\r\n let acc = read64LE(secret, 8) ^ read64LE(secret, 16);\r\n seed ^= BigInt(swap32(Number(seed & U32_MASK))) << 32n;\r\n acc = u64(acc - seed);\r\n acc ^= input64;\r\n acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);\r\n acc = u64(acc * RRMXMX);\r\n acc ^= (acc >> 35n) + BigInt(length);\r\n acc = u64(acc * RRMXMX);\r\n acc ^= acc >> 28n;\r\n return u64(acc);\r\n}\r\n\r\nfunction len9to16(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let inputLo = read64LE(secret, 24) ^ read64LE(secret, 32);\r\n let inputHi = read64LE(secret, 40) ^ read64LE(secret, 48);\r\n let acc = BigInt(length);\r\n inputLo = u64(inputLo + seed);\r\n inputHi = u64(inputHi - seed);\r\n inputLo ^= read64LE(input, 0);\r\n inputHi ^= read64LE(input, length - 8);\r\n acc = u64(acc + swap64(inputLo));\r\n acc = u64(acc + inputHi);\r\n acc = u64(acc + mul128Fold64(inputLo, inputHi));\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction mix16B(\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number,\r\n seed: bigint\r\n): bigint {\r\n let lhs = seed;\r\n let rhs = u64(0n - seed);\r\n lhs = u64(lhs + read64LE(secret, secretOff));\r\n rhs = u64(rhs + read64LE(secret, secretOff + 8));\r\n lhs ^= read64LE(input, inputOff);\r\n rhs ^= read64LE(input, inputOff + 8);\r\n return mul128Fold64(lhs, rhs);\r\n}\r\n\r\nfunction len17to128(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let i = Math.floor((length - 1) / 32);\r\n let acc = u64(BigInt(length) * PRIME64_1);\r\n for (; i >= 0; i--) {\r\n acc = u64(acc + mix16B(input, 16 * i, secret, 32 * i, seed));\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n length - 16 * (i + 1),\r\n secret,\r\n 32 * i + 16,\r\n seed\r\n )\r\n );\r\n }\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction len129to240(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let acc = u64(BigInt(length) * PRIME64_1);\r\n const nbRounds = Math.floor(length / 16);\r\n for (let i = 0; i < 8; i++) {\r\n acc = u64(acc + mix16B(input, 16 * i, secret, 16 * i, seed));\r\n }\r\n acc = xxh3Avalanche(acc);\r\n for (let i = 8; i < nbRounds; i++) {\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n 16 * i,\r\n secret,\r\n 16 * (i - 8) + XXH3_MIDSIZE_STARTOFFSET,\r\n seed\r\n )\r\n );\r\n }\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n length - 16,\r\n secret,\r\n XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET,\r\n seed\r\n )\r\n );\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction hashShort(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n if (length <= 16) {\r\n if (length > 8) return len9to16(input, length, secret, seed);\r\n if (length >= 4) return len4to8(input, length, secret, seed);\r\n if (length !== 0) return len1to3(input, length, secret, seed);\r\n return len0(secret, seed);\r\n }\r\n if (length <= 128) return len17to128(input, length, secret, seed);\r\n return len129to240(input, length, secret, seed);\r\n}\r\n\r\n// --- Long input (> 240 bytes) ---\r\n\r\nfunction accumulate512(\r\n acc: bigint[],\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number\r\n): void {\r\n for (let i = 0; i < ACC_NB; i++) {\r\n const dataVal = read64LE(input, inputOff + 8 * i);\r\n const dataKey = dataVal ^ read64LE(secret, secretOff + 8 * i);\r\n acc[i ^ 1] = u64(acc[i ^ 1] + dataVal);\r\n const low32 = dataKey & U32_MASK;\r\n const high32 = dataKey >> 32n;\r\n acc[i] = u64(acc[i] + low32 * high32);\r\n }\r\n}\r\n\r\nfunction scrambleAcc(\r\n acc: bigint[],\r\n secret: Uint8Array,\r\n secretOff: number\r\n): void {\r\n for (let i = 0; i < ACC_NB; i++) {\r\n let x = acc[i];\r\n x ^= x >> 47n;\r\n x ^= read64LE(secret, secretOff + 8 * i);\r\n x = u64(x * BigInt(PRIME32_1));\r\n acc[i] = x;\r\n }\r\n}\r\n\r\nfunction accumulateLoop(\r\n acc: bigint[],\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number,\r\n nbStripes: number\r\n): void {\r\n for (let n = 0; n < nbStripes; n++) {\r\n accumulate512(\r\n acc,\r\n input,\r\n inputOff + n * STRIPE_LEN,\r\n secret,\r\n secretOff + 8 * n\r\n );\r\n }\r\n}\r\n\r\nfunction mix2Accs(\r\n acc: bigint[],\r\n accOff: number,\r\n secret: Uint8Array,\r\n secretOff: number\r\n): bigint {\r\n return mul128Fold64(\r\n acc[accOff] ^ read64LE(secret, secretOff),\r\n acc[accOff + 1] ^ read64LE(secret, secretOff + 8)\r\n );\r\n}\r\n\r\nfunction mergeAccs(\r\n acc: bigint[],\r\n key: Uint8Array,\r\n keyOff: number,\r\n start: bigint\r\n): bigint {\r\n let result = start;\r\n for (let i = 0; i < 4; i++) {\r\n result = u64(result + mix2Accs(acc, 2 * i, key, keyOff + 16 * i));\r\n }\r\n return xxh3Avalanche(result);\r\n}\r\n\r\nfunction hashLong(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n secretSize: number\r\n): bigint {\r\n const nbRounds = Math.floor(\r\n (secretSize - STRIPE_LEN) / XXH_SECRET_CONSUME_RATE\r\n );\r\n const blockLen = STRIPE_LEN * nbRounds;\r\n const nbBlocks = Math.floor((length - 1) / blockLen);\r\n const nbStripes = Math.floor(\r\n ((length - 1) - blockLen * nbBlocks) / STRIPE_LEN\r\n );\r\n\r\n const acc: bigint[] = [\r\n BigInt(PRIME32_3),\r\n PRIME64_1,\r\n PRIME64_2,\r\n PRIME64_3,\r\n PRIME64_4,\r\n BigInt(PRIME32_2),\r\n PRIME64_5,\r\n BigInt(PRIME32_1),\r\n ];\r\n\r\n for (let n = 0; n < nbBlocks; n++) {\r\n accumulateLoop(acc, input, n * blockLen, secret, 0, nbRounds);\r\n scrambleAcc(acc, secret, secretSize - STRIPE_LEN);\r\n }\r\n\r\n accumulateLoop(acc, input, nbBlocks * blockLen, secret, 0, nbStripes);\r\n\r\n // Last stripe — always applied (C reference: unconditional)\r\n accumulate512(\r\n acc,\r\n input,\r\n length - STRIPE_LEN,\r\n secret,\r\n secretSize - STRIPE_LEN - XXH_SECRET_LASTACC_START\r\n );\r\n\r\n return mergeAccs(\r\n acc,\r\n secret,\r\n XXH_SECRET_MERGEACCS_START,\r\n u64(BigInt(length) * PRIME64_1)\r\n );\r\n}\r\n\r\nfunction hashLongWithSeed(\r\n input: Uint8Array,\r\n length: number,\r\n seed: bigint\r\n): bigint {\r\n const secret = new Uint8Array(XXH_SECRET_DEFAULT_SIZE);\r\n for (let i = 0; i < XXH_SECRET_DEFAULT_SIZE / 16; i++) {\r\n const off = 16 * i;\r\n write64LE(secret, off, u64(read64LE(DEFAULT_SECRET, off) + seed));\r\n write64LE(\r\n secret,\r\n off + 8,\r\n u64(read64LE(DEFAULT_SECRET, off + 8) - seed)\r\n );\r\n }\r\n return hashLong(input, length, secret, secret.length);\r\n}\r\n\r\n// --- Public API ---\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n/**\r\n * Compute XXH3-64 hash of a byte array. Returns a BigInt (unsigned 64-bit).\r\n * Pure TypeScript, synchronous, supports any input length.\r\n */\r\nexport function xxh3_64(input: Uint8Array, seed = 0n): bigint {\r\n const len = input.length;\r\n if (len <= XXH3_MIDSIZE_MAX) {\r\n return hashShort(input, len, DEFAULT_SECRET, u64(seed));\r\n }\r\n return hashLongWithSeed(input, len, u64(seed));\r\n}\r\n\r\n/**\r\n * Compute XXH3-64 hash of a UTF-8 string. Returns a BigInt (unsigned 64-bit).\r\n */\r\nexport function xxh3_64str(input: string, seed = 0n): bigint {\r\n return xxh3_64(textEncoder.encode(input), seed);\r\n}\r\n\r\n/**\r\n * Compute the RPC method hash matching .NET's RpcMethodRef.ComputeHashCode.\r\n * Returns a 32-bit signed integer (lower 32 bits of XXH3-64 of [prefix + utf8Name]).\r\n *\r\n * The prefix is uint32 LE of (67211 * utf8Name.length), which ensures methods\r\n * with different name lengths but similar text produce different hashes.\r\n *\r\n * Computed on demand — caller should cache the result per method name.\r\n */\r\nexport function computeMethodHash(methodName: string): number {\r\n const utf8 = textEncoder.encode(methodName);\r\n // Prefix: uint32 LE of (67211 * utf8.length)\r\n const prefixValue = Math.imul(67211, utf8.length) >>> 0;\r\n const prefixed = new Uint8Array(4 + utf8.length);\r\n prefixed[0] = prefixValue & 0xff;\r\n prefixed[1] = (prefixValue >>> 8) & 0xff;\r\n prefixed[2] = (prefixValue >>> 16) & 0xff;\r\n prefixed[3] = (prefixValue >>> 24) & 0xff;\r\n prefixed.set(utf8, 4);\r\n const hash64 = xxh3_64(prefixed);\r\n // Truncate to signed int32 (same as C#'s unchecked((int)hash64))\r\n return Number(hash64 & 0xffffffffn) | 0;\r\n}\r\n","// Method name ↔ hash registry for compact binary serialization.\r\n//\r\n// .NET counterpart: RpcMethodResolver — maintains MethodByHashCode dictionary\r\n// for resolving compact 4-byte method hashes back to full method names.\r\n//\r\n// Hashes are computed on demand (first use) and cached. The computeMethodHash\r\n// function uses BigInt-based XXH3-64, which is pure sync TypeScript.\r\n\r\nimport { computeMethodHash } from './rpc-xxhash3.js';\r\n\r\n/**\r\n * Registry mapping RPC method wire names to/from their 4-byte XXH3 hashes.\r\n * Hashes match .NET's RpcMethodRef.ComputeHashCode.\r\n * Hashes are computed lazily on first access and cached.\r\n */\r\nexport class RpcMethodRegistry {\r\n private _nameToHash = new Map<string, number>();\r\n private _hashToName = new Map<number, string>();\r\n\r\n /** Register a method name and compute its hash. */\r\n register(methodName: string): void {\r\n if (this._nameToHash.has(methodName)) return;\r\n const hash = computeMethodHash(methodName);\r\n\r\n // Check for hash collisions\r\n const existing = this._hashToName.get(hash);\r\n if (existing !== undefined && existing !== methodName) {\r\n console.warn(\r\n `[RpcMethodRegistry] hash collision: \"${methodName}\" and \"${existing}\" both hash to ${hash}`\r\n );\r\n return;\r\n }\r\n\r\n this._nameToHash.set(methodName, hash);\r\n this._hashToName.set(hash, methodName);\r\n }\r\n\r\n /** Register all wire method names from a service definition. */\r\n registerService(\r\n serviceName: string,\r\n methods: ReadonlyMap<string, { name: string; wireArgCount: number }>\r\n ): void {\r\n for (const [, def] of methods) {\r\n const wireName = `${serviceName}.${def.name}:${def.wireArgCount}`;\r\n this.register(wireName);\r\n }\r\n }\r\n\r\n /** Get the hash for a method name. Computes on demand if not registered. */\r\n getHash(methodName: string): number {\r\n let hash = this._nameToHash.get(methodName);\r\n if (hash === undefined) {\r\n this.register(methodName);\r\n hash = this._nameToHash.get(methodName)!;\r\n }\r\n return hash;\r\n }\r\n\r\n /** Get the method name for a hash. Returns undefined if not registered. */\r\n getName(hash: number): string | undefined {\r\n return this._hashToName.get(hash);\r\n }\r\n\r\n /** Get the hash for a method name, throwing if not registered. */\r\n requireHash(methodName: string): number {\r\n return this.getHash(methodName);\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcHub (141 lines) — a sealed ProcessorBase (IAsyncDisposable) that owns:\r\n// DI-resolved configuration (RpcRegistryOptions, PeerOptions, InboundCallOptions,\r\n// OutboundCallOptions, DiagnosticsOptions), SerializationFormats, Middlewares,\r\n// ClientPeerReconnectDelayer, Limits, SystemClock.\r\n// Manages peers via ConcurrentDictionary<RpcPeerRef, RpcPeer> with GetPeer()\r\n// that lazily creates + starts peers. Also has GetClient<T>() / GetServer<T>()\r\n// that look up services in ServiceRegistry.\r\n//\r\n// Omitted from .NET:\r\n// - DI / IServiceProvider integration — .NET resolves all options, serializers,\r\n// middleware, delayers, etc. from DI. TS constructs everything directly.\r\n// - RpcServiceRegistry — .NET builds a full registry of all RPC services at\r\n// startup via reflection + DI, mapping Type → RpcServiceDef. TS uses explicit\r\n// addService() / addClient() calls.\r\n// - GetClient<T>() / GetServer<T>() — .NET resolves typed client/server proxies\r\n// via the ServiceRegistry + DI. TS uses addClient<T>(peer, def).\r\n// - RpcPeerRef-keyed peer dictionary — .NET peers are keyed by RpcPeerRef (rich\r\n// value object encoding route, version, serialization format). TS uses string\r\n// refs (URL for clients, \"server://{uuid}\" for servers).\r\n// - Lazy peer creation + Start() — .NET's GetPeer auto-creates and starts a\r\n// peer's reconnection loop. TS requires explicit addPeer() + run().\r\n// - DisposeAsync — .NET disposes all peers on hub shutdown. TS has close().\r\n// - Route change detection (RouteState.WhenChanged → Dispose peer) — .NET\r\n// watches for load-balancer route changes and auto-disposes stale peers.\r\n// TS has no routing layer.\r\n// - Middlewares (IRpcMiddleware[]) — ordered middleware pipeline for inbound\r\n// calls. TS dispatches directly to service implementations.\r\n// - Limits (RpcLimits) — configurable limits for call timeout, handshake\r\n// timeout, max message size, etc. TS uses hardcoded values.\r\n// - RpcConfiguration / Configuration.Freeze() — frozen config snapshot.\r\n// - HostId / SystemClock — infrastructure services.\r\n// - DefaultPeer / LoopbackPeer / LocalPeer / NonePeer — cached well-known peers.\r\n\r\nimport {\r\n RpcClientPeer,\r\n RpcServerPeer,\r\n type RpcPeer,\r\n type RpcCallOptions,\r\n} from './rpc-peer.js';\r\nimport { RpcServiceHost, type RpcServiceImpl } from './rpc-service-host.js';\r\nimport type { RpcServiceDef, RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName, RpcType } from './rpc-service-def.js';\r\nimport { getServiceMeta, getMethodsMeta, type AnyConstructor } from './rpc-decorators.js';\r\nimport { RpcSystemCallSender } from './rpc-system-call-sender.js';\r\nimport { RpcSystemCallHandler } from './rpc-system-call-handler.js';\r\nimport { RpcStream, parseStreamRef, resolveStreamRefs } from './rpc-stream.js';\r\nimport { RpcMethodRegistry } from './rpc-method-registry.js';\r\nimport { RpcSystemCalls } from './rpc-message.js';\r\n\r\n/** Central RPC coordinator — manages peers, services, and configuration. */\r\nexport class RpcHub {\r\n readonly hubId: string;\r\n readonly peers = new Map<string, RpcPeer>();\r\n readonly serviceHost: RpcServiceHost;\r\n readonly systemCallSender = new RpcSystemCallSender();\r\n systemCallHandler: RpcSystemCallHandler = new RpcSystemCallHandler();\r\n\r\n /** Method registry for compact format hash ↔ name resolution.\r\n * Created lazily, populated by addService/addClient. */\r\n readonly registry = new RpcMethodRegistry();\r\n\r\n constructor(hubId?: string) {\r\n this.hubId = hubId ?? crypto.randomUUID();\r\n this.serviceHost = new RpcServiceHost();\r\n this.systemCallSender.registry = this.registry;\r\n // Pre-register system call method names for compact format hash resolution\r\n for (const methodName of Object.values(RpcSystemCalls)) {\r\n this.registry.register(methodName);\r\n }\r\n }\r\n\r\n addPeer(peer: RpcPeer): void {\r\n this.peers.set(peer.ref, peer);\r\n }\r\n\r\n removePeer(ref: string): void {\r\n const peer = this.peers.get(ref);\r\n if (peer !== undefined) {\r\n peer.close();\r\n this.peers.delete(ref);\r\n }\r\n }\r\n\r\n /** Get or create a peer by ref. Server peers have \"server://\" prefix, everything else is a client peer. */\r\n getPeer(ref: string): RpcPeer {\r\n let peer = this.peers.get(ref);\r\n if (peer) return peer;\r\n peer = ref.startsWith('server://')\r\n ? new RpcServerPeer(this, ref)\r\n : new RpcClientPeer(this, ref);\r\n this.addPeer(peer);\r\n return peer;\r\n }\r\n\r\n /** Get or create a client peer for the given URL. */\r\n getClientPeer(ref: string): RpcClientPeer {\r\n return this.getPeer(ref) as RpcClientPeer;\r\n }\r\n\r\n /** Get or create a server peer for the given ref. */\r\n getServerPeer(ref: string): RpcServerPeer {\r\n return this.getPeer(ref) as RpcServerPeer;\r\n }\r\n\r\n /** Register a service with optional server method wrapping for custom call types. */\r\n addService(\r\n defOrContract: RpcServiceDef | (AnyConstructor),\r\n impl: RpcServiceImpl\r\n ): void {\r\n const def = this._resolveServiceDef(defOrContract);\r\n const wrappedImpl: RpcServiceImpl = {};\r\n for (const methodDef of def.methods.values()) {\r\n const fn = impl[methodDef.name];\r\n if (!fn) continue;\r\n wrappedImpl[methodDef.name] =\r\n methodDef.callTypeId !== 0\r\n ? this._wrapServerMethod(methodDef, fn, impl as object)\r\n : fn;\r\n }\r\n this.serviceHost.register(def, wrappedImpl);\r\n this.registry.registerService(def.name, def.methods);\r\n }\r\n\r\n /** Create a typed client proxy for a service on a remote peer. */\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T is used for caller-specified proxy type\r\n addClient<T extends object>(\r\n peer: RpcPeer,\r\n defOrContract: RpcServiceDef | (AnyConstructor)\r\n ): T {\r\n const def = this._resolveServiceDef(defOrContract);\r\n this.registry.registerService(def.name, def.methods);\r\n\r\n type RpcClientFn = (...args: unknown[]) => unknown;\r\n\r\n // Group methods by clean name, indexed by argCount for overload resolution\r\n const overloads = new Map<string, Map<number, RpcClientFn>>();\r\n for (const methodDef of def.methods.values()) {\r\n let byArgCount = overloads.get(methodDef.name);\r\n if (!byArgCount) {\r\n byArgCount = new Map<number, RpcClientFn>();\r\n overloads.set(methodDef.name, byArgCount);\r\n }\r\n byArgCount.set(\r\n methodDef.argCount,\r\n this._createClientMethod(peer, methodDef)\r\n );\r\n }\r\n\r\n // Build final proxy methods — single overload: use directly; multiple: resolve by args.length\r\n const methods = new Map<string, RpcClientFn>();\r\n for (const [name, byArgCount] of overloads) {\r\n if (byArgCount.size === 1) {\r\n methods.set(name, byArgCount.values().next().value!);\r\n } else {\r\n methods.set(name, (...args: unknown[]) => {\r\n const fn = byArgCount.get(args.length);\r\n if (!fn)\r\n throw new Error(\r\n `No overload of ${name} accepts ${args.length} arguments`\r\n );\r\n return fn(...args);\r\n });\r\n }\r\n }\r\n\r\n return new Proxy({} as T, {\r\n get: (_target, prop) =>\r\n typeof prop === 'string' ? methods.get(prop) : undefined,\r\n });\r\n }\r\n\r\n close(): void {\r\n for (const peer of this.peers.values()) peer.close();\r\n this.peers.clear();\r\n }\r\n\r\n /** Build an RpcServiceDef from decorator metadata on a contract class. Override in FusionHub for compute support. */\r\n protected _buildServiceDef(\r\n cls: AnyConstructor\r\n ): RpcServiceDef {\r\n const svcMeta = getServiceMeta(cls);\r\n if (svcMeta === undefined)\r\n throw new Error('Contract class missing @rpcService metadata');\r\n\r\n const methodsMeta = getMethodsMeta(cls) ?? {};\r\n const methods = new Map<string, RpcMethodDef>();\r\n\r\n for (const [name, meta] of Object.entries(methodsMeta)) {\r\n const wireArgCount = meta.argCount + 1;\r\n const mapKey = `${name}:${wireArgCount}`;\r\n methods.set(mapKey, {\r\n name,\r\n serviceName: svcMeta.name,\r\n argCount: meta.argCount,\r\n wireArgCount,\r\n callTypeId: 0,\r\n stream: meta.returns === RpcType.stream,\r\n noWait: meta.returns === RpcType.noWait,\r\n });\r\n }\r\n\r\n return { name: svcMeta.name, methods };\r\n }\r\n\r\n /** Resolve a service def from either a plain RpcServiceDef or a contract class. */\r\n protected _resolveServiceDef(\r\n defOrContract: RpcServiceDef | (AnyConstructor)\r\n ): RpcServiceDef {\r\n if (typeof defOrContract === 'function')\r\n return this._buildServiceDef(defOrContract);\r\n return defOrContract;\r\n }\r\n\r\n /** Override in FusionHub — default is pass-through (for methods with callTypeId !== 0). */\r\n protected _wrapServerMethod(\r\n _methodDef: RpcMethodDef,\r\n fn: (...args: unknown[]) => unknown,\r\n _impl: object\r\n ): (...args: unknown[]) => unknown {\r\n return fn;\r\n }\r\n\r\n /** Create a client method for the given methodDef. Override in FusionHub for custom call types. */\r\n protected _createClientMethod(\r\n peer: RpcPeer,\r\n methodDef: RpcMethodDef\r\n ): (...args: unknown[]) => unknown {\r\n const wireName = wireMethodName(methodDef);\r\n\r\n // NoWait methods\r\n if (methodDef.noWait) {\r\n return (...args: unknown[]) => {\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n peer.callNoWait(wireName, callArgs);\r\n };\r\n }\r\n\r\n // Stream methods — call returns an RpcStream<T> (AsyncIterable)\r\n if (methodDef.stream) {\r\n return async (...args: unknown[]) => {\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const outboundCall = peer.call(wireName, callArgs);\r\n const result = await outboundCall.result.promise;\r\n const ref = parseStreamRef(result);\r\n if (!ref)\r\n throw new Error(\r\n `Expected stream reference, got: ${JSON.stringify(result)}`\r\n );\r\n const stream = new RpcStream(ref, peer);\r\n peer.remoteObjects.register(stream);\r\n return stream;\r\n };\r\n }\r\n\r\n // Regular methods (including non-zero callTypeId — subclass can override for custom behavior)\r\n const callOptions: RpcCallOptions | undefined =\r\n methodDef.callTypeId !== 0\r\n ? { callTypeId: methodDef.callTypeId }\r\n : undefined;\r\n\r\n return async (...args: unknown[]) => {\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const outboundCall = peer.call(wireName, callArgs, callOptions);\r\n const result = await outboundCall.result.promise;\r\n return resolveStreamRefs(result, peer);\r\n };\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcClient — a DI-registered service used by generated interceptor proxies.\r\n// The proxy classes (generated by Interceptor/ProxyGenerator) intercept method\r\n// calls on the service interface, create an RpcOutboundContext, resolve the\r\n// target peer via OutboundCallRouter, and invoke the outbound call pipeline.\r\n//\r\n// Omitted from .NET:\r\n// - Interceptor-based proxy generation — .NET generates proxy classes at startup\r\n// (via Castle DynamicProxy / source generators) that implement the service\r\n// interface. TS uses a runtime Proxy object instead, which achieves the same\r\n// result without code generation.\r\n// - RpcOutboundContext — .NET creates a rich context per call with CancellationToken,\r\n// Headers, CacheInfoCapture, Trace, RoutingMode. TS passes arguments directly.\r\n// - OutboundCallRouter — .NET routes each call to the appropriate peer based on\r\n// sharding/load-balancing rules. TS passes the peer explicitly.\r\n// - This standalone function is superseded by RpcHub.addClient() which adds\r\n// noWait and compute-aware dispatch. Kept for backward compatibility.\r\n\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport type { RpcServiceDef, RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName } from './rpc-service-def.js';\r\n\r\ntype RpcClientFn = (...args: unknown[]) => unknown;\r\n\r\n/** Creates a typed RPC client proxy — intercepts method calls and sends them over RPC. */\r\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T is used for caller-specified proxy type\r\nexport function createRpcClient<T extends object>(\r\n peer: RpcPeer,\r\n serviceDef: RpcServiceDef\r\n): T {\r\n // Group methods by clean name, indexed by argCount for overload resolution\r\n const overloads = new Map<string, Map<number, RpcMethodDef>>();\r\n for (const methodDef of serviceDef.methods.values()) {\r\n let byArgCount = overloads.get(methodDef.name);\r\n if (!byArgCount) {\r\n byArgCount = new Map<number, RpcMethodDef>();\r\n overloads.set(methodDef.name, byArgCount);\r\n }\r\n byArgCount.set(methodDef.argCount, methodDef);\r\n }\r\n\r\n // Build proxy methods\r\n const methods = new Map<string, RpcClientFn>();\r\n for (const [name, byArgCount] of overloads) {\r\n if (byArgCount.size === 1) {\r\n const methodDef = byArgCount.values().next().value!;\r\n methods.set(name, createMethod(peer, methodDef));\r\n } else {\r\n const fns = new Map<number, RpcClientFn>();\r\n for (const [argCount, methodDef] of byArgCount) {\r\n fns.set(argCount, createMethod(peer, methodDef));\r\n }\r\n methods.set(name, (...args: unknown[]) => {\r\n const fn = fns.get(args.length);\r\n if (!fn)\r\n throw new Error(\r\n `No overload of ${name} accepts ${args.length} arguments`\r\n );\r\n return fn(...args);\r\n });\r\n }\r\n }\r\n\r\n return new Proxy({} as T, {\r\n get(_target, prop) {\r\n if (typeof prop !== 'string') return undefined;\r\n return methods.get(prop);\r\n },\r\n });\r\n}\r\n\r\nfunction createMethod(peer: RpcPeer, methodDef: RpcMethodDef): RpcClientFn {\r\n return async (...args: unknown[]) => {\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const wireName = wireMethodName(methodDef);\r\n const options =\r\n methodDef.callTypeId !== 0\r\n ? { callTypeId: methodDef.callTypeId }\r\n : undefined;\r\n const outboundCall = peer.call(wireName, callArgs, options);\r\n return outboundCall.result.promise;\r\n };\r\n}\r\n","// .NET counterpart: ActualLab.Fusion.Extensions.RpcPeerState\r\n\r\nexport const enum RpcPeerStateKind {\r\n Connected = 0,\r\n JustDisconnected = 1,\r\n Disconnected = 2,\r\n JustConnected = 3,\r\n}\r\n\r\nexport interface RpcPeerState {\r\n readonly kind: RpcPeerStateKind;\r\n readonly lastError?: Error;\r\n readonly reconnectsIn: number; // ms, 0 = no countdown\r\n}\r\n\r\nexport function isConnected(state: RpcPeerState): boolean {\r\n return (\r\n state.kind === RpcPeerStateKind.Connected ||\r\n state.kind === RpcPeerStateKind.JustConnected\r\n );\r\n}\r\n\r\nexport function likelyConnected(state: RpcPeerState): boolean {\r\n return state.kind !== RpcPeerStateKind.Disconnected;\r\n}\r\n\r\nexport function getStateDescription(\r\n state: RpcPeerState,\r\n useLastError = false\r\n): string {\r\n switch (state.kind) {\r\n case RpcPeerStateKind.JustConnected:\r\n return 'Just connected.';\r\n case RpcPeerStateKind.Connected:\r\n return 'Connected.';\r\n case RpcPeerStateKind.JustDisconnected:\r\n return 'Just disconnected, reconnecting...';\r\n case RpcPeerStateKind.Disconnected:\r\n if (state.reconnectsIn > 0) break; // fall through to error message below\r\n return 'Reconnecting...';\r\n }\r\n if (state.lastError == null || !useLastError) return 'Disconnected.';\r\n\r\n let message = state.lastError.message.trim();\r\n if (\r\n !(\r\n message.endsWith('.') ||\r\n message.endsWith('!') ||\r\n message.endsWith('?')\r\n )\r\n )\r\n message += '.';\r\n return 'Disconnected: ' + message;\r\n}\r\n","// .NET counterpart: ActualLab.Fusion.Extensions.RpcPeerStateMonitor\r\n// Simplified TS version using EventHandlerSet + setTimeout (no Fusion computed state).\r\n\r\nimport { EventHandlerSet } from '@actuallab/core';\r\nimport type { RpcClientPeer } from './rpc-peer.js';\r\nimport { type RpcPeerState, RpcPeerStateKind } from './rpc-peer-state.js';\r\n\r\nconst JustConnectedPeriodMs = 1500;\r\nconst JustDisconnectedPeriodMs = 3000;\r\nconst MinReconnectsInMs = 1000;\r\n\r\nexport class RpcPeerStateMonitor {\r\n readonly peer: RpcClientPeer;\r\n readonly stateChanged = new EventHandlerSet<RpcPeerState>();\r\n\r\n private _rawConnected: boolean;\r\n private _connectedAt = 0;\r\n private _disconnectedAt = 0;\r\n private _lastError: Error | undefined;\r\n private _state: RpcPeerState;\r\n private _timer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n // Arrow functions to preserve `this` when used as event handlers\r\n private _onConnected = (): void => {\r\n this._rawConnected = true;\r\n this._connectedAt = Date.now();\r\n this._lastError = undefined;\r\n this._recompute();\r\n };\r\n\r\n private _onDisconnected = (ev: { code: number; reason: string }): void => {\r\n const wasConnected = this._rawConnected;\r\n this._rawConnected = false;\r\n this._lastError = new Error(\r\n `Connection closed: ${ev.reason} (code ${ev.code})`\r\n );\r\n if (wasConnected) {\r\n // True connected→disconnected transition — start JustDisconnected period\r\n this._disconnectedAt = Date.now();\r\n }\r\n // When wasConnected=false, this is a failed reconnect attempt —\r\n // keep the original _disconnectedAt so the countdown isn't reset.\r\n this._recompute();\r\n };\r\n\r\n private _onReconnectsAtChanged = (): void => {\r\n this._recompute();\r\n };\r\n\r\n private _onCancelDelaysChanged = (): void => {\r\n this._recompute();\r\n };\r\n\r\n constructor(peer: RpcClientPeer) {\r\n this.peer = peer;\r\n this._rawConnected = peer.isConnected;\r\n\r\n if (this._rawConnected) {\r\n this._connectedAt = Date.now();\r\n this._state = {\r\n kind: RpcPeerStateKind.JustConnected,\r\n reconnectsIn: 0,\r\n };\r\n } else {\r\n this._disconnectedAt = Date.now();\r\n this._state = {\r\n kind: RpcPeerStateKind.JustDisconnected,\r\n reconnectsIn: 0,\r\n };\r\n }\r\n\r\n peer.connected.add(this._onConnected);\r\n peer.disconnected.add(this._onDisconnected);\r\n peer.reconnectsAtChanged.add(this._onReconnectsAtChanged);\r\n peer.reconnectDelayer.cancelDelaysChanged.add(\r\n this._onCancelDelaysChanged\r\n );\r\n\r\n // Schedule initial transition from Just* states\r\n this._scheduleRecompute(\r\n this._rawConnected\r\n ? JustConnectedPeriodMs\r\n : JustDisconnectedPeriodMs\r\n );\r\n }\r\n\r\n get state(): RpcPeerState {\r\n return this._state;\r\n }\r\n\r\n dispose(): void {\r\n if (this._timer !== undefined) {\r\n clearTimeout(this._timer);\r\n this._timer = undefined;\r\n }\r\n this.peer.connected.remove(this._onConnected);\r\n this.peer.disconnected.remove(this._onDisconnected);\r\n this.peer.reconnectsAtChanged.remove(this._onReconnectsAtChanged);\r\n this.peer.reconnectDelayer.cancelDelaysChanged.remove(\r\n this._onCancelDelaysChanged\r\n );\r\n }\r\n\r\n private _recompute(): void {\r\n if (this._timer !== undefined) {\r\n clearTimeout(this._timer);\r\n this._timer = undefined;\r\n }\r\n\r\n const now = Date.now();\r\n let newState: RpcPeerState;\r\n\r\n if (this._rawConnected) {\r\n const connectedFor = now - this._connectedAt;\r\n if (connectedFor < JustConnectedPeriodMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.JustConnected,\r\n reconnectsIn: 0,\r\n };\r\n this._scheduleRecompute(JustConnectedPeriodMs - connectedFor);\r\n } else {\r\n newState = {\r\n kind: RpcPeerStateKind.Connected,\r\n reconnectsIn: 0,\r\n };\r\n }\r\n } else {\r\n const disconnectedFor = now - this._disconnectedAt;\r\n if (disconnectedFor < JustDisconnectedPeriodMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.JustDisconnected,\r\n lastError: this._lastError,\r\n reconnectsIn: 0,\r\n };\r\n this._scheduleRecompute(\r\n JustDisconnectedPeriodMs - disconnectedFor\r\n );\r\n } else {\r\n const reconnectsAt = this.peer.reconnectsAt;\r\n const reconnectsIn =\r\n reconnectsAt > 0 ? Math.max(0, reconnectsAt - now) : 0;\r\n if (reconnectsIn < MinReconnectsInMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.Disconnected,\r\n lastError: this._lastError,\r\n reconnectsIn: 0,\r\n };\r\n } else {\r\n newState = {\r\n kind: RpcPeerStateKind.Disconnected,\r\n lastError: this._lastError,\r\n reconnectsIn,\r\n };\r\n // Recompute periodically to update countdown\r\n this._scheduleRecompute(\r\n Math.min(1000, reconnectsIn - MinReconnectsInMs)\r\n );\r\n }\r\n }\r\n }\r\n\r\n this._setState(newState);\r\n }\r\n\r\n private _setState(newState: RpcPeerState): void {\r\n const old = this._state;\r\n if (\r\n old.kind === newState.kind &&\r\n old.lastError === newState.lastError &&\r\n old.reconnectsIn === newState.reconnectsIn\r\n )\r\n return;\r\n\r\n this._state = newState;\r\n this.stateChanged.trigger(newState);\r\n }\r\n\r\n private _scheduleRecompute(delayMs: number): void {\r\n if (this._timer !== undefined) clearTimeout(this._timer);\r\n this._timer = setTimeout(\r\n () => {\r\n this._timer = undefined;\r\n this._recompute();\r\n },\r\n Math.max(0, delayMs)\r\n );\r\n }\r\n}\r\n"],"mappings":"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AAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC1F;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM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","names":["RpcCallTypeId","Decoder","Decoder","EventHandlerSet","EventHandlerSet","PromiseSource","PromiseSource","PromiseSource","PromiseSource","DEFAULT_ACK_PERIOD","DEFAULT_ACK_ADVANCE","PromiseSource","EventHandlerSet","PromiseSource","Decoder","Decoder","EventHandlerSet","RpcPeerConnectionKind","PromiseSource","textEncoder","RpcPeerStateKind","EventHandlerSet","EventHandlerSet"]}
1
+ {"version":3,"sources":["../src/rpc-message.ts","../src/rpc-serialization.ts","../src/rpc-connection.ts","../src/rpc-message-channel-connection.ts","../src/rpc-service-def.ts","../src/rpc-call-tracker.ts","../src/rpc-stream.ts","../src/rpc-object.ts","../src/rpc-stream-sender.ts","../src/rpc-system-call-handler.ts","../src/rpc-system-call-sender.ts","../src/rpc-remote-object-tracker.ts","../src/rpc-shared-object-tracker.ts","../src/rpc-peer.ts","../src/rpc-client-peer-reconnect-delayer.ts","../src/rpc-serialization-format.ts","../src/rpc-service-host.ts","../src/rpc-decorators.ts","../src/rpc-xxhash3.ts","../src/rpc-method-registry.ts","../src/rpc-hub.ts","../src/rpc-client.ts","../src/rpc-peer-state.ts","../src/rpc-peer-state-monitor.ts"],"sourcesContent":["// .NET counterparts:\r\n// RpcMessage — .NET has no single \"message\" type; the wire format is built by\r\n// RpcMessageSerializer / RpcOutboundMessage / RpcInboundMessage. In .NET the\r\n// envelope carries MethodRef, RelatedId, Headers, CallTypeId, and serialized\r\n// argument data as binary or text segments. In TS we use a simpler JSON\r\n// envelope + delimiter-separated args.\r\n//\r\n// Omitted from .NET:\r\n// - RpcCallTypeId Reliable (stage-based reconnection protocol) — the TS client\r\n// is browser-only; reconnection replays entire calls rather than resuming at\r\n// a stage, so Reliable call type adds no value.\r\n// - RpcHeader / RpcHeaders — .NET passes typed header arrays on every message\r\n// (Hash, ActivityContext, etc.). TS has no RPC caching, OpenTelemetry\r\n// propagation, or middleware pipeline, so headers aren't needed yet. The\r\n// Headers field on RpcMessage is reserved for future use.\r\n// - $sys.M (Match) / $sys.NotFound / $sys.Disconnect / Stream calls\r\n// (Ack, AckEnd, I, B, End) — Match is for hash-based response caching\r\n// (bandwidth optimisation); NotFound is a server-side \"service not registered\"\r\n// response; Disconnect is for RpcSharedObject lifetime management; the stream\r\n// calls are for RpcStream (server→client IAsyncEnumerable). None of these\r\n// are needed in the TS client today because:\r\n// * No response caching → no Match.\r\n// * Service-not-found is sent as $sys.Error.\r\n// * No shared-object tracking (server-side concept) → no Disconnect.\r\n// * No RpcStream yet → no Ack/AckEnd/I/B/End.\r\n// They can be added when streaming or caching is ported.\r\n// - Binary serialization variants (RpcByteMessageSerializer) — TS uses\r\n// text (JSON) exclusively; binary MessagePack/MemoryPack require native\r\n// codecs that aren't available in browsers.\r\n\r\n/** Identifies the type of an RPC call on the wire. */\r\nexport const enum RpcCallTypeId {\r\n Regular = 0,\r\n Reliable = 1,\r\n}\r\n\r\n/** Identifies system call methods — names include :argCount suffix for .NET interop. */\r\nexport const RpcSystemCalls = {\r\n handshake: '$sys.Handshake:1',\r\n ok: '$sys.Ok:1',\r\n error: '$sys.Error:1',\r\n cancel: '$sys.Cancel:0',\r\n keepAlive: '$sys.KeepAlive:1',\r\n reconnect: '$sys.Reconnect:3',\r\n ack: '$sys.Ack:2',\r\n ackEnd: '$sys.AckEnd:1',\r\n item: '$sys.I:2',\r\n batch: '$sys.B:2',\r\n end: '$sys.End:2',\r\n} as const;\r\n\r\n/** Wire-format RPC message envelope. */\r\nexport interface RpcMessage {\r\n CallType?: number;\r\n RelatedId?: number;\r\n Method?: string;\r\n Headers?: unknown[];\r\n}\r\n\r\n// Delimiters used in the wire format\r\nexport const ENVELOPE_DELIMITER = '\\n'; // \\x0A between envelope and args\r\nexport const ARG_DELIMITER = '\\x1F'; // Unit Separator between args\r\nexport const FRAME_DELIMITER = '\\n\\x1E'; // \\x0A\\x1E between messages in a frame\r\n","// Serialization for the RPC wire format.\r\n//\r\n// Supports two formats:\r\n// - Text (json5np): JSON envelope + delimiter-separated JSON args (V3 wire format)\r\n// - Binary (msgpack6np): V5 binary envelope + MessagePack-encoded args\r\n//\r\n// The format is selected at connection time via the `f=` query parameter.\r\n\r\nimport {\r\n decode as _msgpackDecode,\r\n Encoder,\r\n Decoder,\r\n type DecodeOptions,\r\n} from '@msgpack/msgpack';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport {\r\n ENVELOPE_DELIMITER,\r\n ARG_DELIMITER,\r\n FRAME_DELIMITER,\r\n} from './rpc-message.js';\r\n\r\n// ============================================================\r\n// Text format (json5np) — V3 wire format\r\n// ============================================================\r\n\r\n/** Serializes an RpcMessage + args into the json5 wire format. */\r\nexport function serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[]\r\n): string {\r\n const envelope = JSON.stringify(message);\r\n if (args === undefined || args.length === 0) {\r\n return envelope + ENVELOPE_DELIMITER;\r\n }\r\n const argsStr = args.map(a => JSON.stringify(a)).join(ARG_DELIMITER);\r\n return envelope + ENVELOPE_DELIMITER + argsStr;\r\n}\r\n\r\n/** Serializes multiple messages into a single WebSocket frame. */\r\nexport function serializeFrame(messages: string[]): string {\r\n return messages.join(FRAME_DELIMITER);\r\n}\r\n\r\n/** Splits a WebSocket text frame into individual message strings. */\r\nexport function splitFrame(frame: string): string[] {\r\n return frame.split(FRAME_DELIMITER);\r\n}\r\n\r\n/** Deserializes a single message string into envelope + args. */\r\nexport function deserializeMessage(raw: string): {\r\n message: RpcMessage;\r\n args: unknown[];\r\n} {\r\n const nlIndex = raw.indexOf(ENVELOPE_DELIMITER);\r\n if (nlIndex === -1) {\r\n return { message: JSON.parse(raw) as RpcMessage, args: [] };\r\n }\r\n\r\n const envelopeStr = raw.substring(0, nlIndex);\r\n const argsStr = raw.substring(nlIndex + 1);\r\n const message = JSON.parse(envelopeStr) as RpcMessage;\r\n\r\n if (argsStr.length === 0) {\r\n return { message, args: [] };\r\n }\r\n\r\n const args = argsStr.split(ARG_DELIMITER).map(s => {\r\n try {\r\n return JSON.parse(s) as unknown;\r\n } catch {\r\n console.warn(\r\n `[RpcSerialization] failed to parse arg as JSON: ${s.substring(0, 100)}`\r\n );\r\n return s; // Return raw string if not valid JSON\r\n }\r\n });\r\n\r\n return { message, args };\r\n}\r\n\r\n// ============================================================\r\n// Binary format (msgpack6np) — V5 wire format\r\n// ============================================================\r\n\r\n// MessagePack decode options\r\nconst _msgpackDecodeOptions: DecodeOptions = {};\r\n\r\nconst textEncoder = new TextEncoder();\r\nconst textDecoder = new TextDecoder();\r\n\r\n/**\r\n * Default module-level encoder/decoder. RpcWebSocketConnection passes its own\r\n * per-connection instances for the hot path; these defaults cover callers\r\n * that don't bother (tests, one-shot uses).\r\n *\r\n * Reusing an Encoder across calls is critical at high message rates because\r\n * - construction cost (internal resolvers, buffer allocation) is nontrivial;\r\n * - the internal write buffer stays at its largest observed size after the\r\n * first few encodes, eliminating `resizeBuffer` growth churn (which was\r\n * ~5% self time in the 300-pull profile).\r\n *\r\n * NOT thread-safe and NOT re-entrant. Safe under Node's single-threaded event\r\n * loop as long as `serializeBinaryMessage` is called synchronously (which it\r\n * always is — no awaits inside).\r\n *\r\n * The `@msgpack/msgpack` Encoder constructor takes positional args:\r\n * (extensionCodec, context, maxDepth, initialBufferSize, sortKeys, ...)\r\n * We only need initialBufferSize here — set large enough to fit a typical\r\n * video frame (~11 KB) + envelope overhead without any resizeBuffer growth.\r\n */\r\nconst INITIAL_ENCODER_BUFFER_SIZE = 32 * 1024;\r\nexport const defaultBinaryEncoder = new Encoder(\r\n undefined,\r\n undefined,\r\n undefined,\r\n INITIAL_ENCODER_BUFFER_SIZE\r\n);\r\nexport const defaultBinaryDecoder = new Decoder();\r\n/** Exposed so connection code can instantiate a matching Encoder\r\n * with the same initial buffer size without needing to reach into\r\n * this module's private constants. */\r\nexport function createBinaryEncoder(): Encoder {\r\n return new Encoder(\r\n undefined,\r\n undefined,\r\n undefined,\r\n INITIAL_ENCODER_BUFFER_SIZE\r\n );\r\n}\r\n\r\n// --- LEB128 VarUInt helpers ---\r\n\r\n/** Number of bytes a VarUint encoding of `value` will occupy. */\r\nfunction varUintByteLen(value: number): number {\r\n if (value < 0) value = 0;\r\n let n = 0;\r\n do {\r\n n++;\r\n value >>>= 7;\r\n } while (value > 0);\r\n return n;\r\n}\r\n\r\n/** Write VarUint directly into a `Uint8Array` at `pos`. Returns new pos. */\r\nfunction writeVarUintInto(out: Uint8Array, pos: number, value: number): number {\r\n if (value < 0) value = 0;\r\n do {\r\n let byte = value & 0x7f;\r\n value >>>= 7;\r\n if (value > 0) byte |= 0x80;\r\n out[pos++] = byte;\r\n } while (value > 0);\r\n return pos;\r\n}\r\n\r\nfunction readVarUint(\r\n data: Uint8Array,\r\n offset: number\r\n): { value: number; bytesRead: number } {\r\n let value = 0,\r\n shift = 0,\r\n bytesRead = 0;\r\n do {\r\n if (offset + bytesRead >= data.length) break;\r\n const byte = data[offset + bytesRead];\r\n value |= (byte & 0x7f) << shift;\r\n bytesRead++;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n } while (shift < 35); // Max 5 bytes for uint32\r\n return { value: value >>> 0, bytesRead };\r\n}\r\n\r\n// --- Binary helpers ---\r\n\r\nfunction concatUint8Arrays(arrays: Uint8Array[]): Uint8Array {\r\n let totalLength = 0;\r\n for (const arr of arrays) totalLength += arr.length;\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const arr of arrays) {\r\n result.set(arr, offset);\r\n offset += arr.length;\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Serializes an RpcMessage + args into V5 binary format (msgpack6np).\r\n *\r\n * Layout (NO frame-level size prefix; V5 with PersistsMessageSize=false):\r\n * envelope + argData\r\n * Envelope:\r\n * [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]\r\n * [LVarSpan methodRef] [4-byte LE argLen]\r\n * ArgData: concatenated MessagePack-encoded arguments\r\n *\r\n * Single-allocation build: pre-encodes args with the supplied reusable\r\n * `Encoder`, computes the total envelope size, then writes everything\r\n * into one `Uint8Array`. Eliminates the previous build's intermediate\r\n * `headerParts` number array + four `Uint8Array` concats per call,\r\n * which showed up as ~2% self time in the 300-pull profile and\r\n * pulled the msgpack `resizeBuffer` + `Encoder` constructor along\r\n * with it for another ~6%.\r\n *\r\n * NOTE: `@msgpack/msgpack` `Encoder.encode()` already returns a fresh\r\n * copy of the internal buffer (there's a separate `encodeSharedRef()`\r\n * for zero-copy access), so we can push the results straight into\r\n * `argBufs` without an extra slice. The benefit of reusing the Encoder\r\n * is that its internal write buffer stays at its high-water mark —\r\n * once the first ~11 KB frame has grown it to the full size, no\r\n * subsequent `resizeBuffer` calls are needed.\r\n */\r\nexport function serializeBinaryMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder: Encoder = defaultBinaryEncoder\r\n): Uint8Array {\r\n // 1. Encode each arg. encode() returns a fresh Uint8Array copy per\r\n // call, so the results are safe to retain across subsequent encodes.\r\n let argsDataLen = 0;\r\n let argBufs: Uint8Array[] | null = null;\r\n if (args && args.length > 0) {\r\n argBufs = new Array<Uint8Array>(args.length);\r\n for (let i = 0; i < args.length; i++) {\r\n const buf = encoder.encode(args[i]);\r\n argBufs[i] = buf;\r\n argsDataLen += buf.length;\r\n }\r\n }\r\n\r\n // 2. Compute header sizes without intermediate allocations.\r\n const callType = message.CallType ?? 0;\r\n const relatedId = message.RelatedId ?? 0;\r\n const methodBytes = textEncoder.encode(message.Method ?? '');\r\n const relatedIdLen = varUintByteLen(relatedId);\r\n const methodLenVarintLen = varUintByteLen(methodBytes.length);\r\n const headerSize =\r\n 1 + relatedIdLen + methodLenVarintLen + methodBytes.length;\r\n const totalSize = headerSize + 4 + argsDataLen;\r\n\r\n // 3. Allocate the final wire buffer once and fill it in place.\r\n const out = new Uint8Array(totalSize);\r\n let pos = 0;\r\n out[pos++] = (callType << 5) & 0xe0;\r\n pos = writeVarUintInto(out, pos, relatedId);\r\n pos = writeVarUintInto(out, pos, methodBytes.length);\r\n out.set(methodBytes, pos);\r\n pos += methodBytes.length;\r\n // argLen as int32 LE\r\n out[pos++] = argsDataLen & 0xff;\r\n out[pos++] = (argsDataLen >>> 8) & 0xff;\r\n out[pos++] = (argsDataLen >>> 16) & 0xff;\r\n out[pos++] = (argsDataLen >>> 24) & 0xff;\r\n if (argBufs !== null) {\r\n for (const buf of argBufs) {\r\n out.set(buf, pos);\r\n pos += buf.length;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Deserializes a single V5 binary message starting at `offset`.\r\n * Returns parsed message, args, and number of bytes consumed.\r\n *\r\n * Accepts an optional `Decoder` for reuse across calls on the same\r\n * connection — avoids constructing a new `@msgpack/msgpack.Decoder`\r\n * (and its internal resolver/table state) on every inbound message.\r\n */\r\nexport function deserializeBinaryMessage(\r\n data: Uint8Array,\r\n offset: number,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[]; bytesRead: number } {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n\r\n // V5: no frame-level size prefix. Parse envelope directly.\r\n let pos = offset;\r\n\r\n // Byte 0: upper 3 bits = CallTypeId, lower 5 bits = HeaderCount\r\n const byte0 = data[pos++];\r\n const callTypeId = (byte0 >> 5) & 0x7;\r\n const headerCount = byte0 & 0x1f;\r\n\r\n // RelatedId as VarUint\r\n const relId = readVarUint(data, pos);\r\n pos += relId.bytesRead;\r\n\r\n // MethodRef as LVarSpan\r\n const methodLen = readVarUint(data, pos);\r\n pos += methodLen.bytesRead;\r\n const methodBytes = data.subarray(pos, pos + methodLen.value);\r\n const method = textDecoder.decode(methodBytes);\r\n pos += methodLen.value;\r\n\r\n // ArgData length as fixed 4-byte LE\r\n const argDataLen = view.getInt32(pos, true);\r\n pos += 4;\r\n\r\n // Skip headers (if any — TS client doesn't use them)\r\n if (headerCount > 0) {\r\n for (let h = 0; h < headerCount; h++) {\r\n // L1Memory: 1-byte length prefix + key bytes\r\n const keyLen = data[pos++];\r\n pos += keyLen;\r\n // LVarSpan: VarUint length + value bytes\r\n const valLen = readVarUint(data, pos);\r\n pos += valLen.bytesRead + valLen.value;\r\n }\r\n }\r\n\r\n // Deserialize arguments from argData — multiple concatenated MessagePack values\r\n const args: unknown[] = [];\r\n const argEnd = pos + argDataLen;\r\n if (argDataLen > 0) {\r\n const argSlice = data.subarray(pos, argEnd);\r\n // Reuse the provided decoder across calls; `decodeMulti` is a generator\r\n // so each yield completes before the next `decode` begins, which is\r\n // safe on a single-threaded event loop.\r\n for (const decoded of decoder.decodeMulti(argSlice)) {\r\n args.push(decoded);\r\n }\r\n pos = argEnd;\r\n }\r\n\r\n const message: RpcMessage = {\r\n Method: method,\r\n RelatedId: relId.value,\r\n CallType: callTypeId,\r\n };\r\n\r\n return { message, args, bytesRead: pos - offset };\r\n}\r\n\r\n/**\r\n * Splits a binary WebSocket frame into individual deserialized messages.\r\n * V5 envelopes are self-delimiting (header + method + argLen + argData), so\r\n * multiple envelopes concatenated in a single WebSocket frame can be decoded\r\n * by iterating with the bytesRead returned from deserializeBinaryMessage.\r\n *\r\n * This must stay symmetric with serializeBinaryFrame() (which concatenates\r\n * multiple envelopes). The .NET server batches outbound RPC messages into a\r\n * single WebSocket frame via WebSocketChannel/WriteDelayer, so any assumption\r\n * that a frame is a single envelope silently drops every trailing message.\r\n *\r\n * Accepts an optional `Decoder` for reuse across calls on the same\r\n * connection — forwarded to `deserializeBinaryMessage`.\r\n */\r\nexport function splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[] }[] {\r\n const results: { message: RpcMessage; args: unknown[] }[] = [];\r\n let offset = 0;\r\n while (offset < frame.length) {\r\n const { message, args, bytesRead } = deserializeBinaryMessage(\r\n frame,\r\n offset,\r\n decoder\r\n );\r\n if (bytesRead <= 0) break; // defensive — avoid infinite loop on malformed data\r\n results.push({ message, args });\r\n offset += bytesRead;\r\n }\r\n return results;\r\n}\r\n\r\n/**\r\n * Serializes multiple binary messages into a single WebSocket frame.\r\n * Simply concatenates the already size-prefixed messages.\r\n */\r\nexport function serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return concatUint8Arrays(messages);\r\n}\r\n\r\n// ============================================================\r\n// Compact binary format (V5Compact) — 4-byte method hash\r\n// ============================================================\r\n\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/**\r\n * Serializes an RpcMessage + args into V5Compact binary format.\r\n * Same as V5 except the method is encoded as a 4-byte LE hash\r\n * instead of an LVar-prefixed UTF-8 string.\r\n *\r\n * Layout:\r\n * [byte 0: (CallTypeId<<5) | HeaderCount] [VarUint relatedId]\r\n * [4-byte LE methodHash] [4-byte LE argLen]\r\n * [argData]\r\n */\r\nexport function serializeCompactBinaryMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n registry?: RpcMethodRegistry,\r\n encoder: Encoder = defaultBinaryEncoder\r\n): Uint8Array {\r\n // 1. Encode args\r\n let argsDataLen = 0;\r\n let argBufs: Uint8Array[] | null = null;\r\n if (args && args.length > 0) {\r\n argBufs = new Array<Uint8Array>(args.length);\r\n for (let i = 0; i < args.length; i++) {\r\n const buf = encoder.encode(args[i]);\r\n argBufs[i] = buf;\r\n argsDataLen += buf.length;\r\n }\r\n }\r\n\r\n // 2. Get method hash\r\n const methodName = message.Method ?? '';\r\n const methodHash = registry?.requireHash(methodName) ?? 0;\r\n\r\n // 3. Compute sizes\r\n const callType = message.CallType ?? 0;\r\n const relatedId = message.RelatedId ?? 0;\r\n const relatedIdLen = varUintByteLen(relatedId);\r\n // Compact: 4 bytes for hash (instead of LVar method name)\r\n const headerSize = 1 + relatedIdLen + 4;\r\n const totalSize = headerSize + 4 + argsDataLen;\r\n\r\n // 4. Build wire buffer\r\n const out = new Uint8Array(totalSize);\r\n let pos = 0;\r\n out[pos++] = (callType << 5) & 0xe0;\r\n pos = writeVarUintInto(out, pos, relatedId);\r\n // Method hash as 4-byte LE uint32\r\n const hashU32 = methodHash >>> 0;\r\n out[pos++] = hashU32 & 0xff;\r\n out[pos++] = (hashU32 >>> 8) & 0xff;\r\n out[pos++] = (hashU32 >>> 16) & 0xff;\r\n out[pos++] = (hashU32 >>> 24) & 0xff;\r\n // argLen as int32 LE\r\n out[pos++] = argsDataLen & 0xff;\r\n out[pos++] = (argsDataLen >>> 8) & 0xff;\r\n out[pos++] = (argsDataLen >>> 16) & 0xff;\r\n out[pos++] = (argsDataLen >>> 24) & 0xff;\r\n if (argBufs !== null) {\r\n for (const buf of argBufs) {\r\n out.set(buf, pos);\r\n pos += buf.length;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Deserializes a single V5Compact binary message starting at `offset`.\r\n * Reads a 4-byte LE method hash and resolves it via the registry.\r\n */\r\nexport function deserializeCompactBinaryMessage(\r\n data: Uint8Array,\r\n offset: number,\r\n registry?: RpcMethodRegistry,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[]; bytesRead: number } {\r\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\r\n let pos = offset;\r\n\r\n // Byte 0: upper 3 bits = CallTypeId, lower 5 bits = HeaderCount\r\n const byte0 = data[pos++];\r\n const callTypeId = (byte0 >> 5) & 0x7;\r\n const headerCount = byte0 & 0x1f;\r\n\r\n // RelatedId as VarUint\r\n const relId = readVarUint(data, pos);\r\n pos += relId.bytesRead;\r\n\r\n // Method hash as fixed 4-byte LE uint32\r\n const methodHash = view.getUint32(pos, true);\r\n pos += 4;\r\n const method =\r\n registry?.getName(methodHash | 0) ??\r\n `<hash:0x${methodHash.toString(16).padStart(8, '0')}>`;\r\n\r\n // ArgData length as fixed 4-byte LE\r\n const argDataLen = view.getInt32(pos, true);\r\n pos += 4;\r\n\r\n // Skip headers (if any)\r\n if (headerCount > 0) {\r\n for (let h = 0; h < headerCount; h++) {\r\n const keyLen = data[pos++];\r\n pos += keyLen;\r\n const valLen = readVarUint(data, pos);\r\n pos += valLen.bytesRead + valLen.value;\r\n }\r\n }\r\n\r\n // Deserialize arguments\r\n const args: unknown[] = [];\r\n const argEnd = pos + argDataLen;\r\n if (argDataLen > 0) {\r\n const argSlice = data.subarray(pos, argEnd);\r\n for (const decoded of decoder.decodeMulti(argSlice)) {\r\n args.push(decoded);\r\n }\r\n pos = argEnd;\r\n }\r\n\r\n const message: RpcMessage = {\r\n Method: method,\r\n RelatedId: relId.value,\r\n CallType: callTypeId,\r\n };\r\n\r\n return { message, args, bytesRead: pos - offset };\r\n}\r\n\r\n/**\r\n * Splits a compact binary frame into individual deserialized messages.\r\n */\r\nexport function splitCompactBinaryFrame(\r\n frame: Uint8Array,\r\n registry?: RpcMethodRegistry,\r\n decoder: Decoder = defaultBinaryDecoder\r\n): { message: RpcMessage; args: unknown[] }[] {\r\n const results: { message: RpcMessage; args: unknown[] }[] = [];\r\n let offset = 0;\r\n while (offset < frame.length) {\r\n const { message, args, bytesRead } =\r\n deserializeCompactBinaryMessage(\r\n frame,\r\n offset,\r\n registry,\r\n decoder\r\n );\r\n if (bytesRead <= 0) break;\r\n results.push({ message, args });\r\n offset += bytesRead;\r\n }\r\n return results;\r\n}\r\n","// .NET counterparts:\r\n// RpcConnection — thin wrapper around RpcTransport + PropertyBag. RpcTransport\r\n// is an abstract IAsyncEnumerable<RpcInboundMessage> + Send() that can be\r\n// WebSocket-based or in-memory. The transport also handles frame batching and\r\n// back-pressure via a Channel<T> send queue.\r\n//\r\n// Omitted from .NET:\r\n// - PropertyBag on connection — used in .NET for per-connection metadata (e.g.\r\n// authentication info attached by middleware). TS has no middleware pipeline,\r\n// so no need for an extensible property bag.\r\n// - IsLocal flag — .NET distinguishes local loopback connections (same-process\r\n// server) from remote ones. TS is always a remote client.\r\n// - RpcTransport as IAsyncEnumerable — .NET reads inbound messages via\r\n// async iteration with cancellation. TS uses event-based delivery\r\n// (messageReceived handler) because browser WebSocket API is event-driven.\r\n// - Channel<RpcOutboundMessage> send queue with backpressure — .NET buffers\r\n// outbound messages in an async channel that the transport drains. TS sends\r\n// synchronously on the WebSocket; if the socket isn't ready, messages are\r\n// buffered in _sendBuffer (CONNECTING) or silently dropped (CLOSING/CLOSED).\r\n// JS is single-threaded so there's no contention, and WebSocket.send() itself\r\n// handles buffering at the OS level.\r\n// - IAsyncDisposable — .NET transports are disposable resources. TS connections\r\n// are closed via close() and garbage-collected.\r\n\r\nimport { Encoder, Decoder } from '@msgpack/msgpack';\r\nimport { PromiseSource, EventHandlerSet } from '@actuallab/core';\r\nimport {\r\n splitFrame,\r\n serializeFrame,\r\n splitBinaryFrame as splitBinaryFrameFn,\r\n serializeBinaryFrame,\r\n createBinaryEncoder,\r\n} from './rpc-serialization.js';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport type { RpcSerializationFormat } from './rpc-serialization-format.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/** Abstract WebSocket interface — works with both browser WebSocket and Node.js ws. */\r\nexport interface WebSocketLike {\r\n readonly readyState: number;\r\n binaryType?: string;\r\n send(data: string | ArrayBufferLike | Uint8Array | ArrayBufferView): void;\r\n close(code?: number, reason?: string): void;\r\n onopen: ((ev: unknown) => void) | null;\r\n onmessage: ((ev: { data: unknown }) => void) | null;\r\n onclose: ((ev: { code: number; reason: string }) => void) | null;\r\n onerror: ((ev: unknown) => void) | null;\r\n}\r\n\r\nexport const WebSocketState = {\r\n CONNECTING: 0,\r\n OPEN: 1,\r\n CLOSING: 2,\r\n CLOSED: 3,\r\n} as const;\r\n\r\n/** Received message — either text (string) or binary (already parsed). */\r\nexport type RpcReceivedMessage =\r\n | { kind: 'text'; raw: string }\r\n | { kind: 'binary'; message: RpcMessage; args: unknown[] };\r\n\r\n/** Abstract RPC connection — transport-agnostic interface for sending/receiving messages. */\r\nexport interface RpcConnection {\r\n readonly isOpen: boolean;\r\n readonly binaryMode: boolean;\r\n readonly whenConnected: Promise<void>;\r\n readonly messageReceived: EventHandlerSet<RpcReceivedMessage>;\r\n readonly closed: EventHandlerSet<{ code: number; reason: string }>;\r\n /** Optional reusable msgpack encoder for outbound binary messages.\r\n * Callers passing this to `serializeBinaryMessage` skip the per-call\r\n * Encoder construction + resizeBuffer growth. Implementations that\r\n * don't support binary serialization can leave it undefined. */\r\n readonly encoder?: Encoder;\r\n send(serializedMessage: string): void;\r\n sendBinary(data: Uint8Array): void;\r\n close(code?: number, reason?: string): void;\r\n}\r\n\r\n/** WebSocket-based RpcConnection — handles frame splitting, binary/text modes, and message queueing. */\r\nexport class RpcWebSocketConnection implements RpcConnection {\r\n private _ws: WebSocketLike;\r\n private _sendBuffer: (string | Uint8Array)[] = [];\r\n private _connected = new PromiseSource<void>();\r\n\r\n /** Per-connection msgpack encoder — reused across outbound messages to\r\n * amortise construction cost and to keep the internal write buffer at\r\n * its largest observed size (avoids repeated `resizeBuffer` growth on\r\n * large video frames). See serializeBinaryMessage() for details. */\r\n private _encoder: Encoder = createBinaryEncoder();\r\n\r\n /** Per-connection msgpack decoder — reused across inbound messages\r\n * rather than reconstructing one for every `decodeMulti` call. */\r\n private _decoder: Decoder = new Decoder();\r\n\r\n /** Exposed for callers who need to encode outbound binary messages\r\n * through this connection (e.g. `serializeBinaryMessage`). Safe to\r\n * pass to synchronous encode calls on the same event-loop turn. */\r\n get encoder(): Encoder {\r\n return this._encoder;\r\n }\r\n get decoder(): Decoder {\r\n return this._decoder;\r\n }\r\n\r\n private _format: RpcSerializationFormat | undefined;\r\n private _methodRegistry: RpcMethodRegistry | undefined;\r\n\r\n readonly binaryMode: boolean;\r\n readonly messageReceived = new EventHandlerSet<RpcReceivedMessage>();\r\n readonly closed = new EventHandlerSet<{ code: number; reason: string }>();\r\n readonly error = new EventHandlerSet<unknown>();\r\n\r\n constructor(\r\n ws: WebSocketLike,\r\n binaryMode = false,\r\n format?: RpcSerializationFormat,\r\n methodRegistry?: RpcMethodRegistry\r\n ) {\r\n this._ws = ws;\r\n this.binaryMode = binaryMode;\r\n this._format = format;\r\n this._methodRegistry = methodRegistry;\r\n\r\n if (binaryMode && ws.binaryType !== undefined)\r\n ws.binaryType = 'arraybuffer';\r\n\r\n if (ws.readyState === WebSocketState.OPEN) {\r\n this._connected.resolve();\r\n this._flush();\r\n }\r\n\r\n ws.onopen = () => {\r\n this._connected.resolve();\r\n this._flush();\r\n };\r\n\r\n ws.onmessage = ev => {\r\n // Binary frame — V5 self-delimiting envelopes (one or more per WS frame).\r\n //\r\n // Accept BOTH `ArrayBuffer` (browser WebSocket when `binaryType` is\r\n // 'arraybuffer') AND `Uint8Array`-shaped views (Node `ws` delivering a\r\n // `Buffer`, which is a `Uint8Array` subclass). The node-ws adapter\r\n // intentionally passes Buffer through without an ArrayBuffer copy —\r\n // at 300 concurrent video streams that copy was ~100 MB/s of pure\r\n // memcpy + allocation pressure. Matching `ArrayBuffer.isView` here\r\n // keeps the zero-copy path alive all the way to `splitBinaryFrame`.\r\n if (\r\n ev.data instanceof Uint8Array ||\r\n ev.data instanceof ArrayBuffer\r\n ) {\r\n // Node `Buffer` is a `Uint8Array` subclass, so we can hand it to\r\n // `splitBinaryFrame` directly with no view wrapping or copying.\r\n // Browsers deliver `ArrayBuffer`, which needs a single zero-copy\r\n // view wrap.\r\n const frame =\r\n ev.data instanceof Uint8Array\r\n ? ev.data\r\n : new Uint8Array(ev.data);\r\n try {\r\n const messages = this._splitBinary(frame);\r\n for (const { message, args } of messages) {\r\n this.messageReceived.trigger({\r\n kind: 'binary',\r\n message,\r\n args,\r\n });\r\n }\r\n } catch (e) {\r\n this.error.trigger(e);\r\n }\r\n } else if (\r\n typeof Blob !== 'undefined' &&\r\n ev.data instanceof Blob &&\r\n this.binaryMode\r\n ) {\r\n // Fallback: some Chromium builds deliver the first frames as Blob even\r\n // after setting binaryType='arraybuffer'. Convert and route through\r\n // the binary path so we don't silently drop them.\r\n void ev.data.arrayBuffer().then(ab => {\r\n const frame = new Uint8Array(ab);\r\n try {\r\n const messages = this._splitBinary(frame);\r\n for (const { message, args } of messages) {\r\n this.messageReceived.trigger({\r\n kind: 'binary',\r\n message,\r\n args,\r\n });\r\n }\r\n } catch (e) {\r\n this.error.trigger(e);\r\n }\r\n });\r\n } else {\r\n // Text frame — JSON delimited messages\r\n const data =\r\n typeof ev.data === 'string' ? ev.data : String(ev.data);\r\n const messages = splitFrame(data);\r\n for (const msg of messages) {\r\n if (msg.length > 0)\r\n this.messageReceived.trigger({\r\n kind: 'text',\r\n raw: msg,\r\n });\r\n }\r\n }\r\n };\r\n\r\n ws.onclose = ev => {\r\n this.closed.trigger({ code: ev.code, reason: ev.reason });\r\n };\r\n\r\n ws.onerror = ev => {\r\n this.error.trigger(ev);\r\n };\r\n }\r\n\r\n get isOpen(): boolean {\r\n return this._ws.readyState === WebSocketState.OPEN;\r\n }\r\n\r\n get whenConnected(): Promise<void> {\r\n return this._connected.promise;\r\n }\r\n\r\n send(serializedMessage: string): void {\r\n this._sendRaw(serializedMessage);\r\n }\r\n\r\n sendBinary(data: Uint8Array): void {\r\n this._sendRaw(data);\r\n }\r\n\r\n sendTextBatch(messages: string[]): void {\r\n this._sendRaw(serializeFrame(messages));\r\n }\r\n\r\n sendBinaryBatch(messages: Uint8Array[]): void {\r\n this._sendRaw(serializeBinaryFrame(messages));\r\n }\r\n\r\n /** Split a binary frame using the format (compact-aware) or default splitter. */\r\n private _splitBinary(\r\n frame: Uint8Array\r\n ): { message: RpcMessage; args: unknown[] }[] {\r\n if (this._format) {\r\n return this._format.splitBinaryFrame(\r\n frame,\r\n this._decoder,\r\n this._methodRegistry\r\n );\r\n }\r\n return splitBinaryFrameFn(frame, this._decoder);\r\n }\r\n\r\n close(code?: number, reason?: string): void {\r\n this._ws.close(code, reason);\r\n }\r\n\r\n private _sendRaw(data: string | Uint8Array): void {\r\n try {\r\n if (this._ws.readyState === WebSocketState.OPEN) {\r\n this._ws.send(data);\r\n } else if (this._ws.readyState === WebSocketState.CONNECTING)\r\n this._sendBuffer.push(data);\r\n // CLOSING/CLOSED: silently drop\r\n } catch {\r\n // Swallow — disconnect event handles cleanup\r\n }\r\n }\r\n\r\n private _flush(): void {\r\n if (this._sendBuffer.length === 0) return;\r\n const buffer = this._sendBuffer;\r\n this._sendBuffer = [];\r\n try {\r\n for (const item of buffer) this._ws.send(item);\r\n } catch {\r\n // Swallow — disconnect event handles cleanup\r\n }\r\n }\r\n}\r\n","// .NET counterpart: none — this is a TS-only test transport.\r\n//\r\n// .NET tests use a different mechanism: RpcTestClient creates an in-memory\r\n// Channel<RpcMessage> pair wrapped in an RpcTransport. We use the browser-\r\n// standard MessageChannel API instead, which gives us a synchronous in-process\r\n// transport without requiring WebSocket mocks.\r\n\r\nimport { EventHandlerSet } from '@actuallab/core';\r\nimport { splitFrame } from './rpc-serialization.js';\r\nimport type { RpcConnection, RpcReceivedMessage } from './rpc-connection.js';\r\n\r\n/** MessagePort-based RpcConnection — for in-process testing without WebSocket mocks. */\r\nexport class RpcMessageChannelConnection implements RpcConnection {\r\n private _port: MessagePort;\r\n private _open = true;\r\n\r\n readonly binaryMode = false;\r\n readonly messageReceived = new EventHandlerSet<RpcReceivedMessage>();\r\n readonly closed = new EventHandlerSet<{ code: number; reason: string }>();\r\n readonly whenConnected: Promise<void> = Promise.resolve(); // immediately connected\r\n\r\n constructor(port: MessagePort) {\r\n this._port = port;\r\n port.onmessage = (ev: MessageEvent) => {\r\n const data =\r\n typeof ev.data === 'string' ? ev.data : String(ev.data);\r\n for (const msg of splitFrame(data))\r\n if (msg.length > 0)\r\n this.messageReceived.trigger({ kind: 'text', raw: msg });\r\n };\r\n }\r\n\r\n get isOpen(): boolean {\r\n return this._open;\r\n }\r\n\r\n send(serializedMessage: string): void {\r\n if (!this._open) return;\r\n try {\r\n this._port.postMessage(serializedMessage);\r\n } catch {\r\n // never fail\r\n }\r\n }\r\n\r\n sendBinary(data: Uint8Array): void {\r\n if (!this._open) return;\r\n try {\r\n this._port.postMessage(data, [data.buffer]);\r\n } catch {\r\n // never fail\r\n }\r\n }\r\n\r\n close(code?: number, reason?: string): void {\r\n if (!this._open) return;\r\n this._open = false;\r\n this._port.close();\r\n this.closed.trigger({ code: code ?? 1000, reason: reason ?? '' });\r\n }\r\n}\r\n\r\n/** Creates a pair of connected RpcMessageChannelConnections for testing. */\r\nexport function createMessageChannelPair(): [\r\n RpcMessageChannelConnection,\r\n RpcMessageChannelConnection,\r\n ] {\r\n const channel = new MessageChannel();\r\n return [\r\n new RpcMessageChannelConnection(channel.port1),\r\n new RpcMessageChannelConnection(channel.port2),\r\n ];\r\n}\r\n","// .NET counterparts:\r\n// RpcServiceDef (Configuration/) — 162 lines. Describes a registered service\r\n// including its .NET Type, Mode (Local/Client/Server/Hybrid), ServerResolver\r\n// (DI-based lazy resolution), ClientType, IsSystem, IsBackend flags, Scope,\r\n// LegacyNames, PropertyBag, and a method dictionary built via reflection.\r\n// RpcMethodDef (Configuration/) — 189 lines. Describes a single method:\r\n// FullName (ServiceName.MethodName:ArgCount), CallType (Regular/Reliable),\r\n// NoWait, HasPolymorphicArguments/Result, RpcMethodKind (Query/Command/System),\r\n// RpcMethodAttribute, LegacyNames, Tracer, outbound/inbound call pipeline\r\n// (factories, invokers, middleware chains, routers, timeouts).\r\n//\r\n// Omitted from .NET:\r\n// - Reflection-based method discovery (BuildMethods) — .NET scans interface\r\n// methods via reflection, filters generics, builds call pipelines. TS uses\r\n// explicit defineRpcService() or decorator metadata — no runtime reflection.\r\n// - RpcMethodKind (Query/Command/System/Other) — .NET classifies methods to\r\n// route Commands through ICommander. TS has no command bus; the distinction\r\n// is unnecessary.\r\n// - IsBackend / IBackendService — .NET separates \"backend-only\" services that\r\n// require backend auth. TS client never exposes backend services.\r\n// - RpcMethodAttribute / LegacyNames — .NET supports custom wire names and\r\n// version-specific legacy name mappings for rolling upgrades. TS has a\r\n// single version; wire names = \"ServiceName.MethodName:wireArgCount\".\r\n// - Call pipeline (OutboundCallFactory, InboundCallFactory, InboundCallInvoker,\r\n// MiddlewareFilter, OutboundCallRouter, OutboundCallTimeouts) — .NET builds a\r\n// per-method middleware chain at startup via generic factory types. TS dispatches\r\n// directly from RpcServiceHost; no middleware or routing layer.\r\n// - CallType (Regular/Reliable) — Reliable calls track stages for reconnect\r\n// resumption. TS replays entire calls on reconnect.\r\n// - HasPolymorphicArguments/Result — governs serializer behavior for abstract\r\n// argument types. TS uses JSON (inherently polymorphic); not applicable.\r\n// - Tracer / RpcCallTracer — per-method distributed tracing. Not ported.\r\n// - PropertyBag — extensible metadata on service/method def. Not needed.\r\n// - Mode (ServiceMode) / Scope / ServerResolver / ClientType — DI wiring.\r\n\r\n/** Controls outbound RPC call behavior regarding connection waiting, reconnection, and resending. */\r\nexport const RpcRemoteExecutionMode = {\r\n /** Wait for connection if disconnected when the call is made. */\r\n AwaitForConnection: 1,\r\n /** Resend on reconnection to the same peer. */\r\n AllowReconnect: 2,\r\n /** Resend on reconnection to a different peer (implies AllowReconnect). */\r\n AllowResend: 6, // 4 | AllowReconnect\r\n /** Default: wait + reconnect + resend. */\r\n Default: 7, // AwaitForConnection | AllowResend\r\n} as const;\r\n/** Bitfield combination of RpcRemoteExecutionMode flags. */\r\nexport type RpcRemoteExecutionMode = number;\r\n\r\n/** Describes a single method on an RPC service. */\r\nexport interface RpcMethodDef {\r\n readonly name: string;\r\n readonly serviceName: string;\r\n readonly argCount: number;\r\n readonly wireArgCount: number;\r\n readonly callTypeId: number;\r\n readonly stream: boolean;\r\n readonly noWait: boolean;\r\n readonly remoteExecutionMode: RpcRemoteExecutionMode;\r\n}\r\n\r\n/** Describes an RPC service — its name and method definitions. */\r\nexport interface RpcServiceDef {\r\n readonly name: string;\r\n readonly methods: ReadonlyMap<string, RpcMethodDef>;\r\n}\r\n\r\nexport interface RpcMethodDefInput {\r\n args: unknown[];\r\n returns?: symbol;\r\n callTypeId?: number;\r\n /** Override for wireArgCount. Default: args.length + 1 (assumes a CancellationToken slot). */\r\n wireArgCount?: number;\r\n /** Override for remoteExecutionMode. Default: RpcRemoteExecutionMode.Default (7). NoWait methods always use 0. */\r\n remoteExecutionMode?: RpcRemoteExecutionMode;\r\n}\r\n\r\nexport const RpcType = {\r\n object: Symbol('object'),\r\n stream: Symbol('stream'),\r\n noWait: Symbol('noWait'),\r\n void: Symbol('void'),\r\n} as const;\r\n\r\n/** Returns the full wire method name: \"ServiceName.MethodName:wireArgCount\". */\r\nexport function wireMethodName(def: RpcMethodDef): string {\r\n return `${def.serviceName}.${def.name}:${def.wireArgCount}`;\r\n}\r\n\r\nexport function defineRpcService(\r\n name: string,\r\n methods: Record<string, RpcMethodDefInput>\r\n): RpcServiceDef {\r\n const map = new Map<string, RpcMethodDef>();\r\n for (const [key, input] of Object.entries(methods)) {\r\n // If the key contains \":\", the part before \":\" is the clean name\r\n // (the suffix is for JS object key disambiguation of overloads).\r\n // Otherwise the key IS the clean name.\r\n const colonIndex = key.indexOf(':');\r\n const cleanName = colonIndex >= 0 ? key.substring(0, colonIndex) : key;\r\n const wireArgCount = input.wireArgCount ?? input.args.length + 1;\r\n const mapKey = `${cleanName}:${wireArgCount}`;\r\n const isNoWait = input.returns === RpcType.noWait;\r\n map.set(mapKey, {\r\n name: cleanName,\r\n serviceName: name,\r\n argCount: input.args.length,\r\n wireArgCount,\r\n callTypeId: input.callTypeId ?? 0,\r\n stream: input.returns === RpcType.stream,\r\n noWait: isNoWait,\r\n remoteExecutionMode: isNoWait\r\n ? 0\r\n : (input.remoteExecutionMode ?? RpcRemoteExecutionMode.Default),\r\n });\r\n }\r\n return { name, methods: map };\r\n}\r\n","// .NET counterparts:\r\n// RpcCall (29 lines) — base class: MethodDef, Id, NoWait flag, Lock.\r\n// RpcOutboundCall (437 lines) — tracks an outbound call's full lifecycle:\r\n// result via AsyncTaskMethodBuilder, CacheInfoCapture, CancellationHandler,\r\n// CompletedStage (for Reliable reconnection), StartedAt (for timeouts),\r\n// hashing for Match, tracing, routing, and retry logic.\r\n// RpcInboundCall (298 lines) — tracks an inbound call: deserialization,\r\n// middleware-chain invocation, cancellation via linked CTS, stage-based\r\n// re-processing for reconnection, sending the result back.\r\n// RpcOutboundCallTracker (255 lines) — thread-safe ConcurrentDictionary of\r\n// outbound calls with: Maintain() loop (timeout monitoring + logging),\r\n// Reconnect() protocol (stage-based call resumption), Abort(), TryReroute().\r\n// RpcInboundCallTracker (64 lines) — ConcurrentDictionary, GetOrRegister,\r\n// Unregister, Clear.\r\n//\r\n// Omitted from .NET:\r\n// - AsyncTaskMethodBuilder / typed RpcOutboundCall<T> — .NET creates a typed\r\n// task builder for each call's return type. TS uses PromiseSource<unknown>\r\n// (untyped) because TypeScript erases generics at runtime.\r\n// - CancellationHandler (CancellationToken.Register → Cancel) — .NET registers\r\n// a callback per outbound call. TS implements equivalent via optional\r\n// AbortSignal on RpcPeer.call(); the cancel handler rejects the promise,\r\n// removes from tracker, and sends $sys.Cancel — same behavior as .NET's\r\n// Cancel() + NotifyCancelled().\r\n// - StartedAt / CpuTimestamp / Timeout monitoring — .NET's Maintain() loop\r\n// checks elapsed time against per-method timeouts every CallTimeoutCheckPeriod.\r\n// TS has no per-call timeout mechanism; the WebSocket-level disconnect +\r\n// rejectAll handles stuck calls.\r\n// - CompletedStage / RpcCallStage — supports Reliable call type's stage-based\r\n// reconnection protocol where the server tells the client which stage each\r\n// call reached, avoiding re-execution of completed stages. TS replays entire\r\n// calls on reconnect (simpler, adequate for browser client).\r\n// - Reconnect() protocol — outbound tracker sends $sys.Reconnect with compressed\r\n// call IDs grouped by stage; server responds with \"unknown\" IDs that need\r\n// re-sending. Not ported; TS uses full replay.\r\n// - Abort() with multi-pass retry — .NET iterates 3+ times with delays to\r\n// catch late-registered calls. TS does a single-pass rejectAll().\r\n// - TryReroute() — checks if the call's peer route has changed (load-balancer\r\n// rerouting) and sets RpcRerouteException. TS has no routing layer.\r\n// - IsLongLiving / _longLivingCalls — separate tracking for calls that outlive\r\n// normal timeouts (e.g. streaming). Not needed without RpcStream.\r\n// - RpcInboundCall: middleware-chain invocation, deserialization with polymorphic\r\n// argument handling, stage-based TryReprocess, CancellationTokenSource per\r\n// call. TS inbound calls are dispatched directly by RpcServiceHost; no\r\n// middleware, no per-call CTS, no stage tracking.\r\n// - RpcCall.Lock (monitor-based synchronisation) — .NET uses lock(this) for\r\n// thread-safe result setting. TS is single-threaded; no locking needed.\r\n\r\nimport { PromiseSource } from '@actuallab/core';\r\n\r\n/** Tracks a pending outbound RPC call. */\r\nexport class RpcOutboundCall {\r\n readonly callId: number;\r\n readonly method: string;\r\n readonly result = new PromiseSource<unknown>();\r\n /** Bitfield of RpcRemoteExecutionMode flags controlling reconnect/resend behavior. */\r\n readonly remoteExecutionMode: number;\r\n\r\n /** Whether to remove this call from the tracker on $sys.Ok. Default: true.\r\n * Subclasses (e.g. compute calls) override to false to stay in tracker for invalidation. */\r\n readonly removeOnOk: boolean = true;\r\n\r\n /** The serialized wire data — stored for re-sending on reconnect. */\r\n serializedWireData: string | Uint8Array = '';\r\n\r\n constructor(callId: number, method: string, remoteExecutionMode = 7) {\r\n this.callId = callId;\r\n this.method = method;\r\n this.remoteExecutionMode = remoteExecutionMode;\r\n }\r\n\r\n /** Called when the connection is lost. Subclasses can override to resolve invalidation promises. */\r\n onDisconnect(): void {\r\n // no-op by default\r\n }\r\n}\r\n\r\n/** Manages outbound calls by their RelatedId. */\r\nexport class RpcOutboundCallTracker {\r\n private _calls = new Map<number, RpcOutboundCall>();\r\n private _nextId = 1;\r\n\r\n get size(): number {\r\n return this._calls.size;\r\n }\r\n\r\n nextId(): number {\r\n return this._nextId++;\r\n }\r\n\r\n register(call: RpcOutboundCall): void {\r\n this._calls.set(call.callId, call);\r\n }\r\n\r\n get(callId: number): RpcOutboundCall | undefined {\r\n return this._calls.get(callId);\r\n }\r\n\r\n remove(callId: number): RpcOutboundCall | undefined {\r\n const call = this._calls.get(callId);\r\n if (call !== undefined) this._calls.delete(callId);\r\n return call;\r\n }\r\n\r\n values(): IterableIterator<RpcOutboundCall> {\r\n return this._calls.values();\r\n }\r\n\r\n activeCallIds(): number[] {\r\n return [...this._calls.keys()];\r\n }\r\n\r\n /** Reject all pending calls with the given error.\r\n * Stage-3 compute calls (result resolved, awaiting invalidation) are kept in the tracker. */\r\n rejectAll(error: Error): void {\r\n for (const [id, call] of this._calls) {\r\n if (!call.removeOnOk && call.result.isCompleted) {\r\n // Stage-3 compute call — keep it for later invalidation on reconnect/stop\r\n continue;\r\n }\r\n call.result.reject(error);\r\n call.onDisconnect();\r\n this._calls.delete(id);\r\n }\r\n }\r\n\r\n /** Invalidate all remaining stage-3 calls (on reconnect or peer stop). */\r\n invalidateAll(): void {\r\n for (const call of this._calls.values()) {\r\n call.onDisconnect();\r\n }\r\n this._calls.clear();\r\n }\r\n\r\n clear(): void {\r\n this._calls.clear();\r\n }\r\n}\r\n\r\n/** Tracks an incoming inbound RPC call. */\r\nexport class RpcInboundCall {\r\n readonly callId: number;\r\n readonly method: string;\r\n readonly args: unknown[];\r\n\r\n constructor(callId: number, method: string, args: unknown[]) {\r\n this.callId = callId;\r\n this.method = method;\r\n this.args = args;\r\n }\r\n}\r\n\r\n/** Manages inbound calls by their RelatedId. */\r\nexport class RpcInboundCallTracker {\r\n private _calls = new Map<number, RpcInboundCall>();\r\n\r\n get size(): number {\r\n return this._calls.size;\r\n }\r\n\r\n register(call: RpcInboundCall): void {\r\n this._calls.set(call.callId, call);\r\n }\r\n\r\n get(callId: number): RpcInboundCall | undefined {\r\n return this._calls.get(callId);\r\n }\r\n\r\n remove(callId: number): RpcInboundCall | undefined {\r\n const call = this._calls.get(callId);\r\n if (call !== undefined) this._calls.delete(callId);\r\n return call;\r\n }\r\n\r\n clear(): void {\r\n this._calls.clear();\r\n }\r\n}\r\n","import Denque from 'denque';\r\nimport { PromiseSource } from '@actuallab/core';\r\nimport type { RpcObjectId, IRpcObject } from './rpc-object.js';\r\nimport { RpcObjectKind } from './rpc-object.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport { RpcStreamSender } from './rpc-stream-sender.js';\r\n\r\n/** Default ack period (matches .NET RpcStream defaults). */\r\nconst DEFAULT_ACK_PERIOD = 30;\r\n/** Default ack advance (matches .NET RpcStream defaults). */\r\nconst DEFAULT_ACK_ADVANCE = 61;\r\n\r\n/** Parsed stream reference from the server's result payload. */\r\nexport interface RpcStreamRef {\r\n readonly hostId: string;\r\n readonly localId: number;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n}\r\n\r\n/**\r\n * A stream source is either a plain async iterable or a factory function\r\n * that receives an AbortSignal and returns an async iterable.\r\n * The AbortSignal is aborted when the sender is disconnected, allowing\r\n * the source to release resources (e.g., camera, microphone) promptly.\r\n */\r\nexport type RpcStreamSource<T> = AsyncIterable<T> | ((abortSignal: AbortSignal) => AsyncIterable<T>);\r\n\r\n/** Configuration options for creating a local (origin-side) RpcStream. */\r\nexport interface RpcStreamOptions<T> {\r\n ackPeriod?: number;\r\n ackAdvance?: number;\r\n allowReconnect?: boolean;\r\n isRealTime?: boolean;\r\n canSkipTo?: (item: T) => boolean;\r\n}\r\n\r\n/**\r\n * Parses a stream reference string of the form \"{hostId},{localId},{ackPeriod},{ackAdvance}\".\r\n * Returns null if the value is not a valid stream reference.\r\n */\r\nexport function parseStreamRef(value: unknown): RpcStreamRef | null {\r\n // Text format: \"hostId,localId,ackPeriod,ackAdvance[,allowReconnect[,isRealTime]]\"\r\n if (typeof value === 'string') {\r\n const parts = value.split(',');\r\n if (parts.length < 4 || parts.length > 6) return null;\r\n const hostId = parts[0];\r\n const localId = parseInt(parts[1], 10);\r\n const ackPeriod = parseInt(parts[2], 10);\r\n const ackAdvance = parseInt(parts[3], 10);\r\n if (isNaN(localId) || isNaN(ackPeriod) || isNaN(ackAdvance))\r\n return null;\r\n const allowReconnect = parts.length < 5 || parts[4] !== '0';\r\n const isRealTime = parts.length >= 6 && parts[5] === '1';\r\n return { hostId, localId, ackPeriod, ackAdvance, allowReconnect, isRealTime };\r\n }\r\n // Binary (MessagePack) format: { SerializedId: [hostId, localId], AckPeriod, AckAdvance, AllowReconnect }\r\n if (typeof value === 'object' && value !== null) {\r\n const obj = value as Record<string, unknown>;\r\n const serializedId = obj.SerializedId as unknown[];\r\n if (!Array.isArray(serializedId) || serializedId.length < 2)\r\n return null;\r\n const rawHostId = serializedId[0];\r\n const hostId = String(rawHostId);\r\n const localId = Number(serializedId[1]);\r\n const ackPeriod = Number(obj.AckPeriod ?? 256);\r\n const ackAdvance = Number(obj.AckAdvance ?? 128);\r\n const allowReconnect = obj.AllowReconnect !== false;\r\n const isRealTime = obj.IsRealTime === true;\r\n return { hostId, localId, ackPeriod, ackAdvance, allowReconnect, isRealTime };\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * Dual-mode RPC stream — works as both local (origin-side) and remote (target-side).\r\n *\r\n * **Local mode**: wraps an AsyncIterable and carries streaming configuration\r\n * (IsRealTime, CanSkipTo, etc.). Created by service methods and sent to the\r\n * remote peer via RpcStreamSender.\r\n *\r\n * **Remote mode**: consumes items sent by the server via system calls\r\n * ($sys.I, $sys.B, $sys.End) and implements AsyncIterable for for-await-of consumption.\r\n *\r\n * This mirrors the .NET RpcStream<T> design where the same type serves both roles.\r\n */\r\nexport class RpcStream<T> implements AsyncIterable<T>, IRpcObject {\r\n readonly id: RpcObjectId;\r\n readonly kind: RpcObjectKind;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n readonly canSkipTo: (item: T) => boolean;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n\r\n // Local (origin) mode\r\n readonly localSource?: RpcStreamSource<T>;\r\n\r\n // Remote (target) mode\r\n readonly peer!: RpcPeer;\r\n\r\n // Local-only state\r\n private _sender?: RpcStreamSender<T>;\r\n private _toRefValue?: unknown;\r\n private _whenSent?: Promise<void>;\r\n\r\n // Remote-only state\r\n private _buffer: Denque<T> = new Denque<T>();\r\n private _nextExpectedIndex = 0;\r\n private _consumerWaiting: PromiseSource<void> | null = null;\r\n private _completed = false;\r\n private _completionError: Error | null = null;\r\n private _disposed = false;\r\n private _started = false;\r\n private _iterating = false;\r\n private _ackSentUpTo = 0;\r\n\r\n /** Create a local (origin-side) stream wrapping an async iterable or source factory with optional configuration. */\r\n constructor(source: RpcStreamSource<T>, options?: RpcStreamOptions<T>);\r\n /** Create a remote (target-side) stream from a parsed stream reference and peer. */\r\n constructor(ref: RpcStreamRef, peer: RpcPeer);\r\n constructor(\r\n sourceOrRef: RpcStreamSource<T> | RpcStreamRef,\r\n optionsOrPeer?: RpcStreamOptions<T> | RpcPeer,\r\n ) {\r\n if (_isStreamSource(sourceOrRef)) {\r\n // Local (origin) mode\r\n const options = (optionsOrPeer as RpcStreamOptions<T> | undefined) ?? {};\r\n this.kind = RpcObjectKind.Local;\r\n this.localSource = sourceOrRef;\r\n this.id = { hostId: '', localId: 0 };\r\n this.allowReconnect = options.allowReconnect ?? true;\r\n this.isRealTime = options.isRealTime ?? false;\r\n this.canSkipTo = options.canSkipTo ?? (() => true);\r\n this.ackPeriod = options.ackPeriod ?? DEFAULT_ACK_PERIOD;\r\n this.ackAdvance = options.ackAdvance ?? DEFAULT_ACK_ADVANCE;\r\n } else {\r\n // Remote (target) mode\r\n const ref = sourceOrRef;\r\n const peer = optionsOrPeer as RpcPeer;\r\n this.kind = RpcObjectKind.Remote;\r\n this.id = { hostId: ref.hostId, localId: ref.localId };\r\n this.peer = peer;\r\n this.allowReconnect = ref.allowReconnect;\r\n this.isRealTime = ref.isRealTime;\r\n this.canSkipTo = () => true; // not serialized\r\n this.ackPeriod = ref.ackPeriod;\r\n this.ackAdvance = ref.ackAdvance;\r\n }\r\n }\r\n\r\n /**\r\n * For local streams: resolves when the sender finishes pumping (after `toRef()` was called).\r\n * Rejects if the source throws. Throws if `toRef()` hasn't been called yet.\r\n */\r\n get whenSent(): Promise<void> {\r\n if (!this._whenSent)\r\n throw new Error('toRef() must be called before awaiting whenSent.');\r\n return this._whenSent;\r\n }\r\n\r\n /**\r\n * For local streams: bind to a peer, create and register an `RpcStreamSender`,\r\n * start pumping items from the local source in the background, and return the\r\n * stream reference.\r\n *\r\n * For binary peers the ref is a MessagePack-compatible object\r\n * (`{ SerializedId, AckPeriod, AckAdvance, AllowReconnect }`);\r\n * for text peers it is a comma-separated string.\r\n *\r\n * Can only be called once per stream.\r\n */\r\n toRef(peer: RpcPeer): unknown {\r\n if (this.kind !== RpcObjectKind.Local)\r\n throw new Error('toRef() is only valid for local streams.');\r\n if (this._sender) {\r\n if (this._sender.peer !== peer)\r\n throw new Error('toRef() was already called with a different peer.');\r\n // Same peer — return the cached ref\r\n return this._toRefValue!;\r\n }\r\n\r\n const sender = new RpcStreamSender<T>(\r\n peer, this.ackPeriod, this.ackAdvance,\r\n this.allowReconnect, this.isRealTime, this.canSkipTo,\r\n );\r\n peer.sharedObjects.register(sender);\r\n this._sender = sender;\r\n\r\n // Resolve source: if it's a factory, call it with the sender's AbortSignal\r\n const source = typeof this.localSource === 'function'\r\n ? this.localSource(sender.abortSignal)\r\n : this.localSource!;\r\n\r\n // Start pumping in background (writeFrom awaits the initial Ack)\r\n this._whenSent = sender.writeFrom(source);\r\n\r\n // Cache and return ref in the format appropriate for the peer's serialization\r\n this._toRefValue = peer.format.isBinary\r\n ? {\r\n SerializedId: [sender.id.hostId, sender.id.localId],\r\n AckPeriod: sender.ackPeriod,\r\n AckAdvance: sender.ackAdvance,\r\n AllowReconnect: sender.allowReconnect,\r\n }\r\n : sender.toRef();\r\n return this._toRefValue;\r\n }\r\n\r\n /** Called by system call handler when a single item arrives ($sys.I). */\r\n onItem(index: number, item: T): void {\r\n if (this._disposed || this._completed) return;\r\n\r\n if (index > this._nextExpectedIndex) {\r\n console.warn(\r\n `[RpcStream] item index gap: localId=${this.id.localId}, expected=${this._nextExpectedIndex}, received=${index}`\r\n );\r\n if (!this.allowReconnect) {\r\n this._completed = true;\r\n this._completionError = new Error(\r\n `Stream gap at index ${index} (expected ${this._nextExpectedIndex}); reconnect not allowed`\r\n );\r\n this._notifyConsumer();\r\n return;\r\n }\r\n this._sendAck(this._nextExpectedIndex, true);\r\n return;\r\n }\r\n if (index < this._nextExpectedIndex) {\r\n // Duplicate — ack and ignore\r\n this._maybeSendAck(index + 1);\r\n return;\r\n }\r\n\r\n this._buffer.push(item);\r\n this._nextExpectedIndex = index + 1;\r\n this._maybeSendAck(this._nextExpectedIndex);\r\n this._notifyConsumer();\r\n }\r\n\r\n /** Called by system call handler when a batch arrives ($sys.B). */\r\n onBatch(index: number, items: T[]): void {\r\n if (this._disposed || this._completed) return;\r\n\r\n if (index > this._nextExpectedIndex) {\r\n console.warn(\r\n `[RpcStream] batch index gap: localId=${this.id.localId}, expected=${this._nextExpectedIndex}, received=${index}`\r\n );\r\n if (!this.allowReconnect) {\r\n this._completed = true;\r\n this._completionError = new Error(\r\n `Stream gap at index ${index} (expected ${this._nextExpectedIndex}); reconnect not allowed`\r\n );\r\n this._notifyConsumer();\r\n return;\r\n }\r\n this._sendAck(this._nextExpectedIndex, true);\r\n return;\r\n }\r\n if (index < this._nextExpectedIndex) {\r\n this._maybeSendAck(index + items.length);\r\n return;\r\n }\r\n\r\n for (const item of items) this._buffer.push(item);\r\n this._nextExpectedIndex = index + items.length;\r\n this._maybeSendAck(this._nextExpectedIndex);\r\n this._notifyConsumer();\r\n }\r\n\r\n /** Called by system call handler when the stream ends ($sys.End). */\r\n onEnd(index: number, error: Error | null): void {\r\n if (this._disposed || this._completed) return;\r\n this._completed = true;\r\n this._completionError = error;\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- IRpcObject --\r\n\r\n reconnect(): void {\r\n if (this.kind === RpcObjectKind.Local) return; // no-op for local streams\r\n if (this.allowReconnect) {\r\n this._sendAck(this._nextExpectedIndex, true);\r\n } else {\r\n this.disconnect();\r\n }\r\n }\r\n\r\n disconnect(): void {\r\n if (this.kind === RpcObjectKind.Local) {\r\n // Propagate to sender — aborts the AbortSignal and terminates the iterator\r\n this._sender?.disconnect();\r\n return;\r\n }\r\n if (this._completed) return;\r\n this._completed = true;\r\n this._completionError = new Error('Peer disconnected.');\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- AsyncIterable --\r\n\r\n [Symbol.asyncIterator](): AsyncIterator<T> {\r\n // Local mode: delegate to the local source\r\n if (this.kind === RpcObjectKind.Local) {\r\n const source = typeof this.localSource === 'function'\r\n ? this.localSource(new AbortController().signal)\r\n : this.localSource!;\r\n return source[Symbol.asyncIterator]();\r\n }\r\n\r\n // Remote mode: buffer-based consumption\r\n if (this._iterating)\r\n throw new Error('RpcStream can only be iterated once.');\r\n this._iterating = true;\r\n\r\n return {\r\n next: async (): Promise<IteratorResult<T>> => {\r\n // Lazy start: send initial ack on first next() call\r\n if (!this._started) {\r\n this._started = true;\r\n this._sendAck(0, true);\r\n }\r\n\r\n // Read from buffer or wait for new data\r\n for (;;) {\r\n if (!this._buffer.isEmpty()) {\r\n // shift() is O(1) on Denque and releases the slot so the\r\n // ring buffer can be reclaimed as the consumer drains.\r\n const value = this._buffer.shift()!;\r\n return { value, done: false };\r\n }\r\n\r\n if (this._completed) {\r\n if (this._completionError) throw this._completionError;\r\n return { value: undefined as T, done: true };\r\n }\r\n\r\n // Wait for more data\r\n this._consumerWaiting = new PromiseSource<void>();\r\n await this._consumerWaiting.promise;\r\n }\r\n },\r\n\r\n return: (): Promise<IteratorResult<T>> => {\r\n this._sendAckEnd();\r\n this.dispose();\r\n return Promise.resolve({ value: undefined as T, done: true });\r\n },\r\n };\r\n }\r\n\r\n dispose(): void {\r\n if (this._disposed) return;\r\n this._disposed = true;\r\n this._completed = true;\r\n if (this.kind === RpcObjectKind.Remote) {\r\n this.peer.remoteObjects.unregister(this);\r\n }\r\n this._notifyConsumer();\r\n }\r\n\r\n // -- Private --\r\n\r\n private _notifyConsumer(): void {\r\n if (this._consumerWaiting !== null) {\r\n this._consumerWaiting.resolve();\r\n this._consumerWaiting = null;\r\n }\r\n }\r\n\r\n private _maybeSendAck(nextIndex: number): void {\r\n if (this.ackPeriod <= 0) return;\r\n const threshold = this._ackSentUpTo + this.ackPeriod;\r\n if (nextIndex >= threshold) {\r\n this._sendAck(nextIndex, false);\r\n }\r\n }\r\n\r\n private static readonly _emptyGuid = '00000000-0000-0000-0000-000000000000';\r\n\r\n private _sendAck(nextIndex: number, mustReset: boolean): void {\r\n this._ackSentUpTo = nextIndex;\r\n const conn = this.peer.connection;\r\n if (conn) {\r\n const hostId = mustReset ? this.id.hostId : RpcStream._emptyGuid;\r\n this.peer.hub.systemCallSender.ack(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n nextIndex,\r\n hostId\r\n );\r\n }\r\n }\r\n\r\n private _sendAckEnd(): void {\r\n const conn = this.peer.connection;\r\n if (conn) {\r\n this.peer.hub.systemCallSender.ackEnd(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this.id.hostId\r\n );\r\n }\r\n }\r\n}\r\n\r\n/** @internal Type guard for RpcStreamSource (AsyncIterable or factory function). */\r\nfunction _isStreamSource<T>(value: unknown): value is RpcStreamSource<T> {\r\n if (typeof value === 'function') return true;\r\n return (\r\n value !== null &&\r\n typeof value === 'object' &&\r\n Symbol.asyncIterator in (value)\r\n );\r\n}\r\n\r\n/**\r\n * Recursively walks a deserialized value and replaces any stream ref strings\r\n * with live RpcStream<unknown> instances registered on the given peer.\r\n * This handles nested stream refs inside complex return types (e.g. Table<T>\r\n * containing RpcStream<Row<T>> fields serialized as \"{hostId},{localId},{ackPeriod},{ackAdvance}\").\r\n */\r\nexport function resolveStreamRefs(value: unknown, peer: RpcPeer): unknown {\r\n if (value === null || value === undefined) return value;\r\n\r\n if (typeof value === 'string') {\r\n const ref = parseStreamRef(value);\r\n if (ref !== null) {\r\n const stream = new RpcStream(ref, peer);\r\n peer.remoteObjects.register(stream);\r\n return stream;\r\n }\r\n return value;\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n for (let i = 0; i < value.length; i++) {\r\n value[i] = resolveStreamRefs(value[i], peer);\r\n }\r\n return value;\r\n }\r\n\r\n if (typeof value === 'object') {\r\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer)\r\n return value;\r\n\r\n for (const key of Object.keys(value as Record<string, unknown>)) {\r\n (value as Record<string, unknown>)[key] = resolveStreamRefs(\r\n (value as Record<string, unknown>)[key],\r\n peer\r\n );\r\n }\r\n return value;\r\n }\r\n\r\n return value;\r\n}\r\n","export interface RpcObjectId {\r\n readonly hostId: string;\r\n readonly localId: number;\r\n}\r\n\r\nexport const RpcObjectKind = { Local: 0, Remote: 1 } as const;\r\nexport type RpcObjectKind = (typeof RpcObjectKind)[keyof typeof RpcObjectKind];\r\n\r\nexport interface IRpcObject {\r\n readonly id: RpcObjectId;\r\n readonly kind: RpcObjectKind;\r\n readonly allowReconnect: boolean;\r\n reconnect(): void;\r\n disconnect(): void;\r\n}\r\n","import { PromiseSource } from '@actuallab/core';\r\nimport type { RpcObjectId, IRpcObject } from './rpc-object.js';\r\nimport { RpcObjectKind } from './rpc-object.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\n\r\n/** Default ack period for server-side streams. */\r\nconst DEFAULT_ACK_PERIOD = 256;\r\n/** Default ack advance for server-side streams. */\r\nconst DEFAULT_ACK_ADVANCE = 128;\r\n\r\n/**\r\n * Server-side RPC stream producer — sends items to a remote consumer via\r\n * $sys.I / $sys.B / $sys.End system calls.\r\n *\r\n * Wire protocol (server perspective):\r\n * - Server returns the stream reference string as $sys.Ok\r\n * - Client sends Ack(0, hostId) to start the stream\r\n * - Server sends I (single item) / B (batch) messages\r\n * - Client acks every ackPeriod items for flow control\r\n * - Server sends End to signal completion (with optional error)\r\n * - Client sends AckEnd to acknowledge completion\r\n */\r\nexport class RpcStreamSender<T> implements IRpcObject {\r\n private static readonly _emptyGuid = '00000000-0000-0000-0000-000000000000';\r\n\r\n readonly id: RpcObjectId;\r\n readonly kind = RpcObjectKind.Local;\r\n readonly allowReconnect: boolean;\r\n readonly isRealTime: boolean;\r\n readonly canSkipTo: (item: T) => boolean;\r\n readonly peer: RpcPeer;\r\n readonly ackPeriod: number;\r\n readonly ackAdvance: number;\r\n\r\n private _nextIndex = 0;\r\n private _ended = false;\r\n private _started = new PromiseSource<void>();\r\n private _lastAckedIndex = 0;\r\n private _ackWaiting: PromiseSource<void> | null = null;\r\n private _resetRequested = false;\r\n private _abortController = new AbortController();\r\n private _iterator: AsyncIterator<T> | null = null;\r\n\r\n constructor(\r\n peer: RpcPeer,\r\n ackPeriod = DEFAULT_ACK_PERIOD,\r\n ackAdvance = DEFAULT_ACK_ADVANCE,\r\n allowReconnect = true,\r\n isRealTime = false,\r\n canSkipTo: (item: T) => boolean = () => true,\r\n ) {\r\n const localId = peer.sharedObjects.nextId();\r\n this.id = { hostId: peer.hub.hubId, localId };\r\n this.allowReconnect = allowReconnect;\r\n this.isRealTime = isRealTime;\r\n this.canSkipTo = canSkipTo;\r\n this.peer = peer;\r\n this.ackPeriod = ackPeriod;\r\n this.ackAdvance = ackAdvance;\r\n }\r\n\r\n /** AbortSignal that is aborted when the sender is disconnected. */\r\n get abortSignal(): AbortSignal {\r\n return this._abortController.signal;\r\n }\r\n\r\n /** Returns the stream reference string for the $sys.Ok response. */\r\n toRef(): string {\r\n return `${this.id.hostId},${this.id.localId},${this.ackPeriod},${this.ackAdvance},${this.allowReconnect ? '1' : '0'},${this.isRealTime ? '1' : '0'}`;\r\n }\r\n\r\n /** Called by system call handler when $sys.Ack is received from the client. */\r\n onAck(nextIndex: number, hostId: string): void {\r\n const mustReset = hostId !== '' && hostId !== RpcStreamSender._emptyGuid;\r\n\r\n if (!this._started.isCompleted) {\r\n this._started.resolve();\r\n }\r\n\r\n if (mustReset && this.isRealTime) {\r\n // Real-time reconnect: reset position and request skip to next canSkipTo item\r\n this._nextIndex = nextIndex;\r\n this._lastAckedIndex = nextIndex;\r\n this._resetRequested = true;\r\n } else {\r\n if (mustReset || nextIndex > this._lastAckedIndex) {\r\n this._lastAckedIndex = nextIndex;\r\n }\r\n }\r\n\r\n if (this._ackWaiting) {\r\n this._ackWaiting.resolve();\r\n this._ackWaiting = null;\r\n }\r\n }\r\n\r\n /** Called by system call handler when $sys.AckEnd is received from the client. */\r\n onAckEnd(_hostId: string): void {\r\n this.disconnect();\r\n }\r\n\r\n /** Send a single item to the client. */\r\n sendItem(item: T): void {\r\n if (this._ended) return;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n this.peer.hub.systemCallSender.item(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n item\r\n );\r\n this._nextIndex++;\r\n }\r\n\r\n /** Send a batch of items to the client. */\r\n sendBatch(items: T[]): void {\r\n if (this._ended || items.length === 0) return;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n this.peer.hub.systemCallSender.batch(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n items\r\n );\r\n this._nextIndex += items.length;\r\n }\r\n\r\n /** Signal stream completion to the client. */\r\n sendEnd(error?: Error | null): void {\r\n if (this._ended) return;\r\n this._ended = true;\r\n const conn = this.peer.connection;\r\n if (!conn) return;\r\n // .NET ExceptionInfo is a non-nullable value type, so we must always\r\n // emit a valid map shape (empty TypeRef+Message for the \"no error\" case).\r\n const errorInfo = error\r\n ? { TypeRef: 'System.Exception', Message: error.message }\r\n : { TypeRef: '', Message: '' };\r\n this.peer.hub.systemCallSender.end(\r\n conn,\r\n this.peer.format,\r\n this.id.localId,\r\n this._nextIndex,\r\n errorInfo\r\n );\r\n }\r\n\r\n /**\r\n * Consume an AsyncIterable and send all items to the client.\r\n * Waits for the client's initial Ack before starting to pump items.\r\n *\r\n * When `isRealTime` is true, applies flow control based on `ackAdvance`:\r\n * if the sender is `ackAdvance` items ahead of the last ACK, it enters\r\n * skip mode — draining the source and discarding items until it finds\r\n * one where `canSkipTo` returns true.\r\n */\r\n async writeFrom(source: AsyncIterable<T>): Promise<void> {\r\n await this._started.promise;\r\n\r\n const iterator = source[Symbol.asyncIterator]();\r\n this._iterator = iterator;\r\n try {\r\n for (;;) {\r\n const next = await iterator.next();\r\n \r\n if (next.done || this._ended) break;\r\n\r\n const item = next.value;\r\n\r\n // Real-time reconnect: drain source to next canSkipTo item\r\n if (this._resetRequested) {\r\n if (!this.canSkipTo(item)) continue;\r\n this._resetRequested = false;\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n // Flow control: check if we've hit the AckAdvance ceiling\r\n if (this._nextIndex < this._lastAckedIndex + this.ackAdvance) {\r\n // Under budget — send normally\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n if (!this.isRealTime) {\r\n // Normal mode: wait for ACK before sending\r\n await this._waitForAckBudget();\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n this.sendItem(item);\r\n continue;\r\n }\r\n\r\n // Real-time mode: hit the ceiling. Drain the source,\r\n // discarding non-skip-targets, keeping the latest skip target.\r\n // Stop draining when budget becomes available or source exhausts.\r\n let latestSkipTarget: T | undefined = this.canSkipTo(item) ? item : undefined;\r\n let sourceExhausted = false;\r\n\r\n while (this._nextIndex >= this._lastAckedIndex + this.ackAdvance) {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n const n = await iterator.next();\r\n if (n.done) {\r\n sourceExhausted = true;\r\n break;\r\n }\r\n if (this.canSkipTo(n.value)) {\r\n latestSkipTarget = n.value;\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (this._ended) return;\r\n\r\n if (latestSkipTarget !== undefined) {\r\n this.sendItem(latestSkipTarget);\r\n }\r\n\r\n if (sourceExhausted) {\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _ended can change during await\r\n if (!this._ended) this.sendEnd();\r\n return;\r\n }\r\n }\r\n \r\n if (!this._ended) {\r\n this.sendEnd();\r\n }\r\n } catch (e) {\r\n if (!this._ended) {\r\n this.sendEnd(e instanceof Error ? e : new Error(String(e)));\r\n }\r\n }\r\n }\r\n\r\n /** Wait until _nextIndex < _lastAckedIndex + ackAdvance. */\r\n private async _waitForAckBudget(): Promise<void> {\r\n while (this._nextIndex >= this._lastAckedIndex + this.ackAdvance) {\r\n if (this._ended) return;\r\n this._ackWaiting = new PromiseSource<void>();\r\n await this._ackWaiting.promise;\r\n }\r\n }\r\n\r\n // -- IRpcObject --\r\n\r\n reconnect(): void {\r\n // Server-side streams don't support reconnection — the client\r\n // creates a new stream on reconnect.\r\n }\r\n\r\n disconnect(): void {\r\n if (this._ended) return;\r\n this._ended = true;\r\n this._abortController.abort();\r\n if (!this._started.isCompleted) {\r\n // Resolve (not reject) — writeFrom() will see _ended=true and exit cleanly.\r\n // Rejecting would cause unhandled rejections when writeFrom() is void-called.\r\n this._started.resolve();\r\n }\r\n // Unblock _waitForAckBudget if it's waiting\r\n if (this._ackWaiting) {\r\n this._ackWaiting.resolve();\r\n this._ackWaiting = null;\r\n }\r\n // Force-terminate the iterator to interrupt blocking next() calls\r\n // and trigger finally blocks in async generators\r\n if (this._iterator) {\r\n void this._iterator.return?.(undefined);\r\n this._iterator = null;\r\n }\r\n this.peer.sharedObjects.unregister(this);\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcSystemCalls (239 lines) — implements IRpcSystemCalls interface; handles\r\n// all inbound system messages as regular RPC method calls dispatched through\r\n// the same inbound-call pipeline as user calls.\r\n//\r\n// Omitted from .NET:\r\n// - Reconnect() handler — receives compressed call-ID sets grouped by stage,\r\n// looks up each inbound call, calls TryReprocess(), and returns the IDs of\r\n// unknown calls. TS doesn't implement the Reliable reconnection protocol.\r\n// - Cancel() handler — .NET finds the inbound call and cancels its\r\n// CancellationTokenSource, aborting the running handler. TS removes the\r\n// inbound call from the tracker but does not yet propagate cancellation\r\n// to the service handler (no AbortSignal threading through dispatch).\r\n// - M() (Match) handler — tells an outbound call to use its cached result\r\n// instead of the response payload. TS has no response caching.\r\n// - NotFound() — throws an EndpointNotFound error. TS sends this as a regular\r\n// $sys.Error; no separate system call type.\r\n// - KeepAlive() / Disconnect() — manage RpcSharedObject lifetimes. TS has no\r\n// shared-object tracker.\r\n// - IRpcPolymorphicArgumentHandler.IsValidCall — resolves the concrete\r\n// deserialization type for polymorphic Ok/Item/Batch arguments by looking up\r\n// the related outbound call's return type. TS deserializes all args as\r\n// unknown via JSON.parse (inherently polymorphic).\r\n// - DI / IServiceProvider / RpcServiceBase — .NET system calls are resolved via\r\n// DI. TS uses a class with a handle() method.\r\n\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport type { RpcStream } from './rpc-stream.js';\r\nimport { resolveStreamRefs } from './rpc-stream.js';\r\nimport type { RpcStreamSender } from './rpc-stream-sender.js';\r\n\r\n/** Handles incoming system call messages — class-based equivalent of the former standalone function. */\r\nexport class RpcSystemCallHandler {\r\n handle(message: RpcMessage, args: unknown[], peer: RpcPeer): void {\r\n const method = message.Method;\r\n const relatedId = message.RelatedId ?? 0;\r\n\r\n switch (method) {\r\n case RpcSystemCalls.ok: {\r\n const call = peer.outbound.get(relatedId);\r\n if (call !== undefined) {\r\n if (call.removeOnOk) {\r\n peer.outbound.remove(relatedId);\r\n }\r\n call.result.resolve(args[0]);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.error: {\r\n const call = peer.outbound.remove(relatedId);\r\n if (call !== undefined) {\r\n const errorInfo = args[0] as\r\n | Record<string, unknown>\r\n | undefined;\r\n const msg = (errorInfo?.Message ??\r\n errorInfo?.message ??\r\n 'RPC error') as string;\r\n call.result.reject(new Error(msg));\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.cancel: {\r\n // Remote peer is cancelling a call it asked us to process — remove\r\n // from the inbound tracker. Full cancellation propagation (aborting\r\n // the running service handler) is not yet implemented; this just\r\n // unregisters the call so we don't send a response for it.\r\n peer.inbound.remove(relatedId);\r\n break;\r\n }\r\n case RpcSystemCalls.keepAlive: {\r\n // Remote keep-alive — nothing to do, just acknowledges the connection is alive\r\n break;\r\n }\r\n case RpcSystemCalls.item: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.I: no stream for relatedId=${relatedId}`\r\n );\r\n } else {\r\n stream.onItem(\r\n args[0] as number,\r\n resolveStreamRefs(args[1], peer)\r\n );\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.batch: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.B: no stream for relatedId=${relatedId}`\r\n );\r\n } else if (Array.isArray(args[1])) {\r\n const items = args[1] as unknown[];\r\n for (let i = 0; i < items.length; i++)\r\n items[i] = resolveStreamRefs(items[i], peer);\r\n stream.onBatch(args[0] as number, items);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.end: {\r\n const stream = peer.remoteObjects.get(relatedId) as\r\n | RpcStream<unknown>\r\n | undefined;\r\n if (!stream) {\r\n console.warn(\r\n `[RpcSysHandler] $sys.End: no stream for relatedId=${relatedId}`\r\n );\r\n } else {\r\n // .NET ExceptionInfo is a struct — even for normal completion, it serializes\r\n // as a non-null object with empty fields (e.g. { \"message\": \"\", \"typeRef\": {...} }).\r\n // Check both PascalCase and camelCase, and treat empty messages as no error.\r\n const errorInfo = args[1] as Record<string, unknown> | null;\r\n const msg = (errorInfo?.Message ?? errorInfo?.message) as\r\n | string\r\n | undefined;\r\n const error = msg ? new Error(msg) : null;\r\n stream.onEnd(args[0] as number, error);\r\n }\r\n break;\r\n }\r\n case RpcSystemCalls.ack: {\r\n const sender = peer.sharedObjects.get(relatedId) as\r\n | RpcStreamSender<unknown>\r\n | undefined;\r\n sender?.onAck(args[0] as number, args[1] as string);\r\n break;\r\n }\r\n case RpcSystemCalls.ackEnd: {\r\n const sender = peer.sharedObjects.get(relatedId) as\r\n | RpcStreamSender<unknown>\r\n | undefined;\r\n sender?.onAckEnd(args[0] as string);\r\n break;\r\n }\r\n default: {\r\n if (\r\n method === '$sys.Disconnect' ||\r\n method?.startsWith('$sys.Disconnect')\r\n ) {\r\n // Server is telling us the listed remote object IDs have been torn down\r\n // on its side (e.g. shared stream closed). Propagate disconnect() to the\r\n // matching remote objects so any pending consumers (for-await loops) exit\r\n // cleanly instead of hanging.\r\n const ids = args[0] as number[] | undefined;\r\n if (Array.isArray(ids)) {\r\n for (const id of ids) {\r\n const remoteObj = peer.remoteObjects.get(id);\r\n if (\r\n remoteObj &&\r\n typeof remoteObj.disconnect === 'function'\r\n ) {\r\n remoteObj.disconnect();\r\n }\r\n // Also check shared objects — server may disconnect a client-to-server\r\n // stream sender (e.g. audio stream) after pod restart or timeout.\r\n const sharedObj = peer.sharedObjects.get(id);\r\n if (\r\n sharedObj &&\r\n typeof sharedObj.disconnect === 'function'\r\n ) {\r\n sharedObj.disconnect();\r\n }\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcSystemCallSender (202 lines) — a DI-registered service that sends system\r\n// calls by creating RpcOutboundContext + calling PrepareCallForSendNoWait +\r\n// serialising via the full outbound message pipeline.\r\n//\r\n// Omitted from .NET:\r\n// - Complete<TResult>() / typed Ok<TResult>() — .NET serialises the Ok result\r\n// using the method's unwrapped return type for proper polymorphic handling.\r\n// TS uses JSON.stringify(result) which handles any type uniformly.\r\n// - Match() — sends $sys.M when the response hash matches a cached entry,\r\n// avoiding re-sending the full payload. TS has no response caching.\r\n// - NotFound() — TS sends \"Service not found\" / \"Method not found\" as $sys.Error.\r\n// - Disconnect() — sends $sys.Disconnect with object IDs for shared-object\r\n// lifetime management. TS has no shared-object tracker.\r\n// - Ack() / AckEnd() / Item<T>() / Batch<T>() / End() — stream control\r\n// messages for RpcStream. TS has no streaming support yet.\r\n// - RpcOutboundContext / PrepareCallForSendNoWait pipeline — .NET creates a full\r\n// outbound context with MethodDef, ArgumentList, etc., then serialises via the\r\n// peer's MessageSerializer. TS directly calls serializeMessage() (JSON) since\r\n// there's only one serialization format.\r\n// - Tracing / CallLogger integration — .NET logs each system call through the\r\n// peer's CallLogger. TS has no tracing infrastructure.\r\n// - StopMode-aware Error() — .NET checks peer.StopMode to decide whether to\r\n// suppress error responses when the peer is shutting down. TS has no stop\r\n// mode concept.\r\n\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport type { RpcConnection } from './rpc-connection.js';\r\nimport type { RpcSerializationFormat } from './rpc-serialization-format.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/**\r\n * Sends system RPC messages — like .NET's RpcSystemCallSender.\r\n *\r\n * Hot-path allocation notes: `item`, `batch`, `ack`, and `end` are called\r\n * once per stream frame (or once per ack window). Naively building a fresh\r\n * `{ Method, RelatedId }` envelope object plus a fresh two-element arg array\r\n * on every call showed up as ~2-4% self time + non-trivial GC pressure in\r\n * the 300-pull video-load-test profile.\r\n *\r\n * The sender itself is a per-Hub singleton and `_send`/format.serializeMessage\r\n * are fully synchronous (no awaits, no re-entrancy on a single-threaded event\r\n * loop), so we reuse a small pool of preallocated envelope + arg-array slots\r\n * per hot method. Mutate fields just before the send call; the encoder reads\r\n * them synchronously and produces a detached copy, after which the slot is\r\n * free to be mutated again on the next call.\r\n */\r\nexport class RpcSystemCallSender {\r\n // Reusable envelopes — one per hot-path method.\r\n private readonly _itemEnv: RpcMessage = {\r\n Method: RpcSystemCalls.item,\r\n RelatedId: 0,\r\n };\r\n private readonly _batchEnv: RpcMessage = {\r\n Method: RpcSystemCalls.batch,\r\n RelatedId: 0,\r\n };\r\n private readonly _endEnv: RpcMessage = {\r\n Method: RpcSystemCalls.end,\r\n RelatedId: 0,\r\n };\r\n private readonly _ackEnv: RpcMessage = {\r\n Method: RpcSystemCalls.ack,\r\n RelatedId: 0,\r\n };\r\n private readonly _ackEndEnv: RpcMessage = {\r\n Method: RpcSystemCalls.ackEnd,\r\n RelatedId: 0,\r\n };\r\n\r\n // Reusable arg arrays.\r\n private readonly _itemArgs: [number, unknown] = [0, null];\r\n private readonly _batchArgs: [number, unknown] = [0, null];\r\n private readonly _endArgs: [number, { TypeRef: string; Message: string }] =\r\n [0, { TypeRef: '', Message: '' }];\r\n private readonly _ackArgs: [number, string] = [0, ''];\r\n private readonly _ackEndArgs: [string] = [''];\r\n\r\n private static readonly NO_ERROR: { TypeRef: string; Message: string } =\r\n Object.freeze({ TypeRef: '', Message: '' }) as unknown as {\r\n TypeRef: string;\r\n Message: string;\r\n };\r\n\r\n registry?: RpcMethodRegistry;\r\n\r\n private _send(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n envelope: RpcMessage,\r\n args?: unknown[]\r\n ): void {\r\n const wireData = format.serializeMessage(\r\n envelope,\r\n args,\r\n conn.encoder,\r\n this.registry\r\n );\r\n if (typeof wireData === 'string') {\r\n conn.send(wireData);\r\n } else {\r\n conn.sendBinary(wireData);\r\n }\r\n }\r\n\r\n handshake(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n peerId: string,\r\n hubId: string,\r\n index: number\r\n ): void {\r\n // RpcHandshake uses [MessagePackObject] array mode for binary.\r\n const handshakeArg = format.isBinary\r\n ? [peerId, null, hubId, 2, index]\r\n : {\r\n RemotePeerId: peerId,\r\n RemoteApiVersionSet: null,\r\n RemoteHubId: hubId,\r\n ProtocolVersion: 2,\r\n Index: index,\r\n };\r\n this._send(conn, format, { Method: RpcSystemCalls.handshake }, [\r\n handshakeArg,\r\n ]);\r\n }\r\n\r\n ok(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number,\r\n result: unknown\r\n ): void {\r\n this._send(\r\n conn,\r\n format,\r\n { Method: RpcSystemCalls.ok, RelatedId: relatedId },\r\n [result]\r\n );\r\n }\r\n\r\n error(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number,\r\n error: unknown\r\n ): void {\r\n const message = error instanceof Error ? error.message : String(error);\r\n this._send(\r\n conn,\r\n format,\r\n { Method: RpcSystemCalls.error, RelatedId: relatedId },\r\n [{ Message: message }]\r\n );\r\n }\r\n\r\n cancel(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n relatedId: number\r\n ): void {\r\n this._send(conn, format, {\r\n Method: RpcSystemCalls.cancel,\r\n RelatedId: relatedId,\r\n });\r\n }\r\n\r\n keepAlive(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n activeCallIds: number[]\r\n ): void {\r\n this._send(conn, format, { Method: RpcSystemCalls.keepAlive }, [\r\n activeCallIds,\r\n ]);\r\n }\r\n\r\n item(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n item: unknown\r\n ): void {\r\n this._itemEnv.RelatedId = localId;\r\n this._itemArgs[0] = index;\r\n this._itemArgs[1] = item;\r\n this._send(conn, format, this._itemEnv, this._itemArgs);\r\n this._itemArgs[1] = null;\r\n }\r\n\r\n batch(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n items: unknown[]\r\n ): void {\r\n this._batchEnv.RelatedId = localId;\r\n this._batchArgs[0] = index;\r\n this._batchArgs[1] = items;\r\n this._send(conn, format, this._batchEnv, this._batchArgs);\r\n this._batchArgs[1] = null;\r\n }\r\n\r\n end(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n index: number,\r\n error: {\r\n TypeRef: string;\r\n Message: string;\r\n } = RpcSystemCallSender.NO_ERROR\r\n ): void {\r\n this._endEnv.RelatedId = localId;\r\n this._endArgs[0] = index;\r\n this._endArgs[1] = error;\r\n this._send(conn, format, this._endEnv, this._endArgs);\r\n }\r\n\r\n ack(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n nextIndex: number,\r\n hostId: string\r\n ): void {\r\n this._ackEnv.RelatedId = localId;\r\n this._ackArgs[0] = nextIndex;\r\n this._ackArgs[1] = hostId;\r\n this._send(conn, format, this._ackEnv, this._ackArgs);\r\n }\r\n\r\n ackEnd(\r\n conn: RpcConnection,\r\n format: RpcSerializationFormat,\r\n localId: number,\r\n hostId: string\r\n ): void {\r\n this._ackEndEnv.RelatedId = localId;\r\n this._ackEndArgs[0] = hostId;\r\n this._send(conn, format, this._ackEndEnv, this._ackEndArgs);\r\n }\r\n}\r\n","import type { IRpcObject } from './rpc-object.js';\r\n\r\nexport class RpcRemoteObjectTracker {\r\n private _objects = new Map<number, IRpcObject>();\r\n\r\n register(obj: IRpcObject): void {\r\n this._objects.set(obj.id.localId, obj);\r\n }\r\n\r\n get(localId: number): IRpcObject | undefined {\r\n return this._objects.get(localId);\r\n }\r\n\r\n keys(): IterableIterator<number> {\r\n return this._objects.keys();\r\n }\r\n\r\n unregister(obj: IRpcObject): void {\r\n this._objects.delete(obj.id.localId);\r\n }\r\n\r\n disconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n obj.disconnect();\r\n }\r\n this._objects.clear();\r\n }\r\n\r\n reconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n if (obj.allowReconnect) obj.reconnect();\r\n else obj.disconnect();\r\n }\r\n }\r\n}\r\n","import type { IRpcObject } from './rpc-object.js';\r\n\r\nexport class RpcSharedObjectTracker {\r\n private _nextId = 1;\r\n private _objects = new Map<number, IRpcObject>();\r\n\r\n nextId(): number {\r\n return this._nextId++;\r\n }\r\n\r\n register(obj: IRpcObject): void {\r\n this._objects.set(obj.id.localId, obj);\r\n }\r\n\r\n get(localId: number): IRpcObject | undefined {\r\n return this._objects.get(localId);\r\n }\r\n\r\n keys(): IterableIterator<number> {\r\n return this._objects.keys();\r\n }\r\n\r\n unregister(obj: IRpcObject): void {\r\n this._objects.delete(obj.id.localId);\r\n }\r\n\r\n disconnectAll(): void {\r\n for (const obj of this._objects.values()) {\r\n obj.disconnect();\r\n }\r\n this._objects.clear();\r\n }\r\n}\r\n","// .NET counterparts:\r\n// RpcPeer (529 lines) — abstract WorkerBase that runs a reconnection loop in\r\n// OnRun(). Manages AsyncState<RpcPeerConnectionState> (a linked list of\r\n// immutable connection snapshots), handshake exchange, peerChanged detection,\r\n// message processing loop, maintenance tasks, Reset(), and SetConnectionState()\r\n// with thread-safe locking.\r\n// RpcClientPeer (56 lines) — calls GetConnection → WebSocket transport.\r\n// RpcServerPeer (54 lines) — receives connection via RpcServerConnectionHandler.\r\n// RpcPeerConnectionKind (48 lines) — None/Remote/Loopback/Local enum.\r\n// RpcPeerConnectionState (42 lines) — immutable record: Connection, Transport,\r\n// Handshake, OwnHandshake, ReaderTokenSource, Error, TryIndex.\r\n// RpcPeerChangeKind (11 lines) — Unchanged/ChangedToVeryFirst/Changed enum.\r\n// RpcHandshake (28 lines) — PeerId, ApiVersionSet, HubId, ProtocolVersion,\r\n// Index. Has GetPeerChangeKind(lastHandshake) comparison method.\r\n// RpcClientPeerReconnectDelayer (35 lines) — exponential backoff profiles:\r\n// test (50ms), server (250ms), client (1s) with 1.5x growth, max 10s.\r\n//\r\n// Ported from .NET:\r\n// - Handshake exchange — run() sends $sys.Handshake on connect, waits for the\r\n// server's response. RpcServerPeer._onHandshakeReceived() auto-replies.\r\n// Like .NET's OnRun() handshake sequence.\r\n// - Peer change detection — run() compares RemoteHubId from successive\r\n// handshakes to detect server restarts, triggering peerChanged + inbound.clear().\r\n// Like .NET's RpcHandshake.GetPeerChangeKind().\r\n// - Outbound call cancellation via AbortSignal — call(signal) registers an\r\n// abort listener that rejects the call, removes it from the tracker, and sends\r\n// $sys.Cancel to the server. Like .NET's CancellationHandler + NotifyCancelled().\r\n//\r\n// Omitted from .NET:\r\n// - AsyncState<RpcPeerConnectionState> — immutable linked-list of connection\r\n// states that consumers can await via WhenConnected/WhenDisconnected. TS uses\r\n// simpler EventHandlerSet events (connected/disconnected). AsyncState enables\r\n// callers to block until a specific state transition, which is essential in\r\n// .NET's multi-threaded world but unnecessary in TS's single-threaded model.\r\n// - RpcPeerConnectionState record — snapshots Connection + Handshake + OwnHandshake\r\n// + ReaderTokenSource + Error + TryIndex. TS tracks these as mutable fields\r\n// on the peer directly.\r\n// - Maintenance tasks (SharedObjects.Maintain, RemoteObjects.Maintain,\r\n// OutboundCalls.Maintain) — background loops that run while connected,\r\n// checking timeouts and managing object lifetimes. TS has simpler keep-alive\r\n// timer; no shared/remote object tracking, no call timeout monitoring.\r\n// - Reconnect protocol (OutboundCalls.Reconnect) — stage-based call resumption\r\n// after reconnection. TS uses transparent reconnect: outbound calls survive\r\n// disconnect, are re-sent on reconnect (stage-3 compute calls self-invalidate\r\n// on peer change instead of being re-sent).\r\n// - peerChangedToken / CancellationTokenSource — .NET threads a cancellation\r\n// token through all inbound calls that gets cancelled when the remote peer\r\n// changes identity. TS clears the inbound tracker on peer change;\r\n// outbound calls survive disconnect and are re-sent on reconnect.\r\n// - Reset() — aborts RemoteObjects, SharedObjects, OutboundCalls, and clears\r\n// InboundCalls. TS clears inbound tracker on peer change; outbound calls\r\n// are never rejected on disconnect (only on close/stop).\r\n// - ServerMethodResolver / GetServerMethodResolver(handshake) — resolves method\r\n// defs using the remote peer's API version set + legacy names. TS has no\r\n// versioning.\r\n// - ProcessMessage() — creates RpcInboundContext per message, dispatches via\r\n// MethodDef.InboundCallInvoker. TS dispatches via _handleMessage →\r\n// handleSystemCall or RpcServiceHost.dispatch.\r\n// - RpcPeerRef / routing — .NET peers are keyed by RpcPeerRef (which encodes\r\n// client/server, route state, versions, serialization format). TS peers are\r\n// keyed by string ref (URL for clients, \"server://{uuid}\" for servers).\r\n// - StopMode / ComputeAutoStopMode — controls behavior of inbound calls when\r\n// peer stops (cancel vs keep-incomplete). TS has no stop mode.\r\n// - ConnectionKind detector (Remote/Loopback/Local/None) — .NET detects if peer\r\n// is in-process. TS is always remote.\r\n// - Versions / VersionSet / API version negotiation — .NET exchanges version\r\n// sets during handshake for backward compatibility. TS has no versioning.\r\n// - Diagnostics (CallLogger, CallLogLevel, DebugLog) — per-peer logging/tracing.\r\n// - Per-call timeout monitoring (OutboundCallTracker.Maintain) — .NET checks\r\n// elapsed time against per-method timeouts. TS relies on WebSocket-level\r\n// disconnect + rejectAll.\r\n// - Inbound call cancellation propagation — when $sys.Cancel is received, .NET\r\n// cancels the inbound call's CancellationTokenSource, aborting the running\r\n// service method. TS removes the call from the inbound tracker but does not\r\n// yet propagate cancellation to the service handler (would require AbortSignal\r\n// threading through RpcServiceHost.dispatch).\r\n\r\nimport { EventHandlerSet, PromiseSource } from '@actuallab/core';\r\nimport { RpcClientPeerReconnectDelayer } from './rpc-client-peer-reconnect-delayer.js';\r\nimport {\r\n RpcWebSocketConnection,\r\n type RpcConnection,\r\n type RpcReceivedMessage,\r\n type WebSocketLike,\r\n} from './rpc-connection.js';\r\nimport {\r\n RpcOutboundCall,\r\n RpcOutboundCallTracker,\r\n RpcInboundCall,\r\n RpcInboundCallTracker,\r\n} from './rpc-call-tracker.js';\r\nimport { RpcSystemCalls, type RpcMessage } from './rpc-message.js';\r\nimport { deserializeMessage } from './rpc-serialization.js';\r\nimport type { RpcHub } from './rpc-hub.js';\r\nimport { RpcRemoteObjectTracker } from './rpc-remote-object-tracker.js';\r\nimport { RpcSharedObjectTracker } from './rpc-shared-object-tracker.js';\r\nimport { RpcStream } from './rpc-stream.js';\r\nimport { RpcSerializationFormat, RpcSerializationFormatResolver } from './rpc-serialization-format.js';\r\n\r\n/** WebSocket close code sent by the server when the client's serialization format is unsupported. */\r\nexport const RPC_CLOSE_CODE_UNSUPPORTED_FORMAT = 4001;\r\n\r\n/** Builds the WebSocket connection URL for an RpcClientPeer. */\r\nexport type RpcConnectionUrlResolver = (peer: RpcClientPeer) => string;\r\n\r\n/** Default connection URL provider — appends `clientId` and `f` query parameters. */\r\nexport const defaultConnectionUrlResolver: RpcConnectionUrlResolver = peer => {\r\n const sep = peer.ref.includes('?') ? '&' : '?';\r\n return (\r\n peer.ref +\r\n sep +\r\n `clientId=${peer.clientId}&f=${peer.serializationFormat}`\r\n );\r\n};\r\n\r\n/** Options for RpcPeer.call() — allows custom call types and cancellation. */\r\nexport interface RpcCallOptions {\r\n /** Wire CallType field (0 = regular). */\r\n callTypeId?: number;\r\n /** Factory for creating custom outbound call instances (e.g. compute calls). */\r\n outboundCallFactory?: (id: number, method: string) => RpcOutboundCall;\r\n /** AbortSignal for caller-initiated cancellation. */\r\n signal?: AbortSignal;\r\n /** Bitfield of RpcRemoteExecutionMode flags (default: 7 = Default). */\r\n remoteExecutionMode?: number;\r\n}\r\n\r\n/** Data extracted from an inbound $sys.Handshake message. */\r\nexport interface RemoteHandshake {\r\n RemotePeerId?: string;\r\n RemoteHubId?: string;\r\n ProtocolVersion?: number;\r\n Index?: number;\r\n}\r\n\r\n/** Base class for RPC peers — handles bidirectional message dispatch. */\r\nexport abstract class RpcPeer {\r\n /** Routing/addressing key — used as key in hub.peers (URL for clients, \"server://{uuid}\" for servers). */\r\n readonly ref: string;\r\n /** Auto-generated GUID — used in handshakes only. */\r\n readonly id: string = crypto.randomUUID();\r\n protected _hub: RpcHub;\r\n protected _connection: RpcConnection | undefined;\r\n readonly outbound = new RpcOutboundCallTracker();\r\n readonly inbound = new RpcInboundCallTracker();\r\n readonly remoteObjects = new RpcRemoteObjectTracker();\r\n readonly sharedObjects = new RpcSharedObjectTracker();\r\n\r\n readonly connected = new EventHandlerSet<void>();\r\n readonly disconnected = new EventHandlerSet<{\r\n code: number;\r\n reason: string;\r\n }>();\r\n\r\n protected _pendingSends: RpcOutboundCall[] = [];\r\n private _keepAliveTimer: ReturnType<typeof setInterval> | undefined;\r\n\r\n constructor(ref: string, hub: RpcHub) {\r\n this.ref = ref;\r\n this._hub = hub;\r\n }\r\n\r\n get hub(): RpcHub {\r\n return this._hub;\r\n }\r\n\r\n get connection(): RpcConnection | undefined {\r\n return this._connection;\r\n }\r\n\r\n get isConnected(): boolean {\r\n return this._connection?.isOpen ?? false;\r\n }\r\n\r\n protected setupConnection(conn: RpcConnection): void {\r\n this._connection = conn;\r\n\r\n conn.messageReceived.add(raw => this._handleMessage(raw));\r\n conn.closed.add(ev => {\r\n this._connection = undefined;\r\n this._stopKeepAlive();\r\n this.disconnected.trigger(ev);\r\n });\r\n\r\n void conn.whenConnected.then(() => {\r\n this.connected.trigger();\r\n this._startKeepAlive();\r\n });\r\n }\r\n\r\n /** The serialization format used by this peer. Override in subclasses. */\r\n get format(): RpcSerializationFormat {\r\n return RpcSerializationFormatResolver.Default.defaultFormat;\r\n }\r\n\r\n call(\r\n method: string,\r\n args?: unknown[],\r\n options?: RpcCallOptions\r\n ): RpcOutboundCall {\r\n const callId = this.outbound.nextId();\r\n const outboundCall = options?.outboundCallFactory\r\n ? options.outboundCallFactory(callId, method)\r\n : new RpcOutboundCall(callId, method, options?.remoteExecutionMode ?? 7);\r\n\r\n const envelope: RpcMessage = {\r\n Method: method,\r\n RelatedId: callId,\r\n CallType: options?.callTypeId ?? 0,\r\n };\r\n outboundCall.serializedWireData = this.format.serializeMessage(\r\n envelope,\r\n args,\r\n this._connection?.encoder,\r\n this._hub.registry\r\n );\r\n if (this._connection !== undefined) {\r\n this.outbound.register(outboundCall);\r\n this._sendWireData(outboundCall.serializedWireData);\r\n } else {\r\n this._pendingSends.push(outboundCall);\r\n }\r\n\r\n // Wire up caller-initiated cancellation → sends $sys.Cancel to remote peer\r\n const signal = options?.signal;\r\n if (signal !== undefined) {\r\n const onAbort = () => {\r\n if (this.outbound.remove(callId) !== undefined) {\r\n outboundCall.result.reject(new Error('Call cancelled.'));\r\n outboundCall.onDisconnect();\r\n if (this._connection !== undefined)\r\n this._hub.systemCallSender.cancel(this._connection, this.format, callId);\r\n } else {\r\n const idx = this._pendingSends.findIndex(\r\n c => c.callId === callId\r\n );\r\n if (idx !== -1) {\r\n this._pendingSends.splice(idx, 1);\r\n outboundCall.result.reject(\r\n new Error('Call cancelled.')\r\n );\r\n outboundCall.onDisconnect();\r\n }\r\n }\r\n };\r\n signal.addEventListener('abort', onAbort, { once: true });\r\n // Clean up listener when the call completes normally\r\n outboundCall.result.promise\r\n .then(() => signal.removeEventListener('abort', onAbort))\r\n .catch(() => signal.removeEventListener('abort', onAbort));\r\n }\r\n\r\n return outboundCall;\r\n }\r\n\r\n callNoWait(method: string, args?: unknown[]): void {\r\n if (this._connection === undefined) return; // silently drop\r\n const envelope: RpcMessage = { Method: method, RelatedId: 0 };\r\n const wireData = this.format.serializeMessage(\r\n envelope,\r\n args,\r\n this._connection.encoder,\r\n this._hub.registry\r\n );\r\n this._sendWireData(wireData);\r\n }\r\n\r\n close(): void {\r\n this._stopKeepAlive();\r\n this.remoteObjects.disconnectAll();\r\n this.sharedObjects.disconnectAll();\r\n for (const call of this._pendingSends) {\r\n if (!call.result.isCompleted)\r\n call.result.reject(new Error('Peer closed.'));\r\n call.onDisconnect();\r\n }\r\n this._pendingSends.length = 0;\r\n this.outbound.rejectAll(new Error('Peer closed.'));\r\n this.outbound.invalidateAll();\r\n this._connection?.close();\r\n this._hub.peers.delete(this.ref);\r\n }\r\n\r\n /** Send any messages buffered while disconnected. Call after connection + handshake are ready. */\r\n protected _flushPendingSends(): void {\r\n if (this._pendingSends.length === 0 || this._connection === undefined)\r\n return;\r\n for (const call of this._pendingSends) {\r\n this.outbound.register(call);\r\n this._sendWireData(call.serializedWireData);\r\n }\r\n this._pendingSends.length = 0;\r\n }\r\n\r\n /** Send pre-serialized wire data through the current connection. */\r\n protected _sendWireData(data: string | Uint8Array): void {\r\n if (this._connection === undefined) return;\r\n if (typeof data === 'string') {\r\n this._connection.send(data);\r\n } else {\r\n this._connection.sendBinary(data);\r\n }\r\n }\r\n\r\n /** Override in subclasses to handle the remote peer's handshake response. */\r\n protected _onHandshakeReceived(_handshake: RemoteHandshake): void {\r\n // Default: no-op. RpcClientPeer resolves a pending promise;\r\n // RpcServerPeer sends its own handshake back.\r\n }\r\n\r\n private _handleMessage(received: RpcReceivedMessage): void {\r\n let message: RpcMessage;\r\n let args: unknown[];\r\n if (received.kind === 'binary') {\r\n message = received.message;\r\n args = received.args;\r\n } else {\r\n const parsed = deserializeMessage(received.raw);\r\n message = parsed.message;\r\n args = parsed.args;\r\n }\r\n const method = message.Method ?? '';\r\n\r\n // Handshake — dispatch to subclass handler\r\n if (method === RpcSystemCalls.handshake) {\r\n const handshake = args[0] as RemoteHandshake | undefined;\r\n if (handshake !== undefined) this._onHandshakeReceived(handshake);\r\n return;\r\n }\r\n\r\n // Other system calls — delegate to hub's system call handler\r\n if (method.startsWith('$sys')) {\r\n this._hub.systemCallHandler.handle(message, args, this);\r\n return;\r\n }\r\n\r\n // Regular inbound call — dispatch to service host\r\n this._handleInbound(message, args);\r\n }\r\n\r\n private _handleInbound(message: RpcMessage, args: unknown[]): void {\r\n const method = message.Method ?? '';\r\n const relatedId = message.RelatedId ?? 0;\r\n\r\n const call = new RpcInboundCall(relatedId, method, args);\r\n const methodDef = this._hub.serviceHost.getMethodDef(method);\r\n\r\n // For noWait calls: don't register in tracker, don't send response\r\n const isNoWait = methodDef?.noWait === true;\r\n if (!isNoWait) {\r\n this.inbound.register(call);\r\n }\r\n\r\n // Dispatch to the hub's service host\r\n const serviceHost = this._hub.serviceHost;\r\n void (async () => {\r\n try {\r\n const context =\r\n this._connection !== undefined\r\n ? {\r\n __rpcDispatch: true as const,\r\n callId: relatedId,\r\n connection: this._connection,\r\n }\r\n : undefined;\r\n const result = await serviceHost.dispatch(\r\n method,\r\n args,\r\n context\r\n );\r\n if (\r\n methodDef?.stream === true &&\r\n this._connection !== undefined\r\n ) {\r\n // Stream method — wrap result in RpcStream if needed,\r\n // then let toRef() create the sender, register it, and start pumping.\r\n const stream = result instanceof RpcStream\r\n ? result as RpcStream<unknown>\r\n : new RpcStream<unknown>(result as AsyncIterable<unknown>);\r\n this._hub.systemCallSender.ok(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n stream.toRef(this)\r\n );\r\n } else if (!isNoWait && this._connection !== undefined) {\r\n this._hub.systemCallSender.ok(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n result\r\n );\r\n }\r\n } catch (e) {\r\n if (!isNoWait && this._connection !== undefined) {\r\n this._hub.systemCallSender.error(\r\n this._connection,\r\n this.format,\r\n relatedId,\r\n e\r\n );\r\n }\r\n } finally {\r\n if (!isNoWait) {\r\n this.inbound.remove(relatedId);\r\n }\r\n }\r\n })();\r\n }\r\n\r\n private _startKeepAlive(): void {\r\n this._keepAliveTimer = setInterval(() => {\r\n if (this._connection !== undefined) {\r\n // Send remote object IDs so the server's SharedObjectTracker keeps them alive.\r\n // Must NOT send outbound call IDs — those are a different ID namespace and would\r\n // cause the server to send $sys.Disconnect for IDs it doesn't recognize, which\r\n // the client may misinterpret as a disconnect of its own shared objects (e.g.\r\n // RpcStreamSender) when the IDs collide numerically.\r\n this._hub.systemCallSender.keepAlive(this._connection, this.format, [\r\n ...this.remoteObjects.keys(),\r\n ]);\r\n }\r\n }, 15_000);\r\n }\r\n\r\n private _stopKeepAlive(): void {\r\n if (this._keepAliveTimer !== undefined) {\r\n clearInterval(this._keepAliveTimer);\r\n this._keepAliveTimer = undefined;\r\n }\r\n }\r\n}\r\n\r\n/** Connection state for RpcClientPeer. */\r\nexport const enum RpcPeerConnectionKind {\r\n Disconnected = 0,\r\n Connecting = 1,\r\n Connected = 2,\r\n}\r\n\r\n/** Client-side RPC peer — initiates WebSocket connection. ref = URL. */\r\nexport class RpcClientPeer extends RpcPeer {\r\n private _disposed = false;\r\n private _connectionKind = RpcPeerConnectionKind.Disconnected;\r\n private _tryIndex = 0;\r\n private _handshakeIndex = 0;\r\n private _lastRemoteHubId: string | undefined;\r\n private _pendingHandshake: PromiseSource<RemoteHandshake> | undefined;\r\n private _reconnectsAt = 0;\r\n\r\n /** Base64url-encoded peer ID — matches .NET's RpcClientPeer.ClientId (Guid.ToBase64Url). */\r\n readonly clientId: string;\r\n /**\r\n * Serialization format key sent to the server via `f=` query parameter.\r\n * TS uses plain JSON.stringify (no polymorphic type wrapping), so `json5np`\r\n * (no-polymorphism) is the correct default.\r\n */\r\n readonly serializationFormat: string;\r\n /** Builds the WebSocket URL for this peer. Replace to customize URL construction. */\r\n connectionUrlResolver: RpcConnectionUrlResolver =\r\n defaultConnectionUrlResolver;\r\n readonly peerChanged = new EventHandlerSet<void>();\r\n /** Fired when the server rejects the connection due to an unsupported serialization format (close code 4010). */\r\n readonly unsupportedFormat = new EventHandlerSet<{ reason: string }>();\r\n readonly reconnectDelayer = new RpcClientPeerReconnectDelayer();\r\n readonly reconnectsAtChanged = new EventHandlerSet<void>();\r\n\r\n get reconnectsAt(): number {\r\n return this._reconnectsAt;\r\n }\r\n\r\n private _setReconnectsAt(value: number): void {\r\n if (this._reconnectsAt === value) return;\r\n this._reconnectsAt = value;\r\n this.reconnectsAtChanged.trigger();\r\n }\r\n\r\n private _format: RpcSerializationFormat;\r\n\r\n constructor(hub: RpcHub, url: string, serializationFormat?: string) {\r\n super(url, hub);\r\n this.clientId = guidToBase64Url(this.id);\r\n const resolver = RpcSerializationFormatResolver.Default;\r\n this.serializationFormat =\r\n serializationFormat ?? resolver.defaultFormatKey;\r\n this._format = resolver.get(this.serializationFormat);\r\n }\r\n\r\n override get format(): RpcSerializationFormat {\r\n return this._format;\r\n }\r\n\r\n get connectionKind(): RpcPeerConnectionKind {\r\n return this._connectionKind;\r\n }\r\n\r\n /** One-shot connection for tests — no reconnection loop, no handshake. */\r\n connectWith(conn: RpcConnection): void {\r\n // Set up new connection and re-send outbound calls (treat as peer change —\r\n // no handshake exchange to determine same-peer, so stage-3 compute calls\r\n // are self-invalidated while regular in-flight calls are re-sent).\r\n this.setupConnection(conn);\r\n this._reconnect(true);\r\n }\r\n\r\n /** Start the reconnection loop — runs until disposed. */\r\n async run(wsFactory?: (url: string) => WebSocketLike): Promise<void> {\r\n const connUrl = this.connectionUrlResolver(this);\r\n while (!this._disposed) {\r\n let lastCloseCode = 0;\r\n let lastCloseReason = '';\r\n try {\r\n const ws =\r\n wsFactory?.(connUrl) ??\r\n (new WebSocket(connUrl) as unknown as WebSocketLike);\r\n const conn = new RpcWebSocketConnection(\r\n ws,\r\n this.format.isBinary,\r\n this.format,\r\n this._hub.registry\r\n );\r\n this._connectionKind = RpcPeerConnectionKind.Connecting;\r\n\r\n // Track close info for unsupported format detection\r\n conn.closed.add(ev => {\r\n lastCloseCode = ev.code;\r\n lastCloseReason = ev.reason;\r\n });\r\n\r\n // Create a fresh handshake promise before setupConnection (which registers\r\n // the message handler). The handler can only fire after the WS opens,\r\n // and we send our handshake below, so timing is safe.\r\n this._pendingHandshake = new PromiseSource<RemoteHandshake>();\r\n this.setupConnection(conn);\r\n // Keep _connection undefined until handshake completes — prevents\r\n // calls from being sent through the connection before the handshake\r\n // (which the .NET server cannot process). Calls made during this\r\n // window go to _pendingSends and are flushed after handshake.\r\n this._connection = undefined;\r\n\r\n // Race connection open against close — if WS fails to connect,\r\n // whenConnected stays pending forever, so we must also watch for close.\r\n const closedRejection = new Promise<never>((_, reject) =>\r\n conn.closed.add(() =>\r\n reject(new Error('Connection failed'))\r\n )\r\n );\r\n closedRejection.catch(() => { /* noop — prevent unhandled rejection when conn closes normally */ });\r\n await Promise.race([conn.whenConnected, closedRejection]);\r\n\r\n // Send our handshake, then wait for the server's response.\r\n this._hub.systemCallSender.handshake(\r\n conn,\r\n this.format,\r\n this.id,\r\n this._hub.hubId,\r\n ++this._handshakeIndex\r\n );\r\n const remoteHandshake = await Promise.race([\r\n this._pendingHandshake.promise,\r\n closedRejection,\r\n ]);\r\n this._pendingHandshake = undefined;\r\n\r\n // Peer change detection (like .NET's RpcHandshake.GetPeerChangeKind)\r\n const remoteHubId = remoteHandshake.RemoteHubId;\r\n let isPeerChanged = false;\r\n if (remoteHubId !== undefined) {\r\n isPeerChanged =\r\n this._lastRemoteHubId !== undefined &&\r\n this._lastRemoteHubId !== remoteHubId;\r\n if (isPeerChanged) {\r\n // Server identity changed — clear inbound state\r\n this.inbound.clear();\r\n this.peerChanged.trigger();\r\n }\r\n this._lastRemoteHubId = remoteHubId;\r\n }\r\n\r\n // Activate the connection and re-send outbound calls.\r\n // All of this happens AFTER the handshake, so the server is ready to process calls.\r\n this._connection = conn;\r\n this._connectionKind = RpcPeerConnectionKind.Connected;\r\n this._tryIndex = 0;\r\n this._reconnect(isPeerChanged);\r\n\r\n // Wait until disconnected\r\n await new Promise<void>(r => conn.closed.add(() => r()));\r\n } catch {\r\n // connection failed or handshake failed\r\n }\r\n\r\n this._connectionKind = RpcPeerConnectionKind.Disconnected;\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- _disposed can change during await\r\n if (this._disposed) break;\r\n\r\n // Server rejected our serialization format — stop reconnecting and notify listeners\r\n if (lastCloseCode === RPC_CLOSE_CODE_UNSUPPORTED_FORMAT) {\r\n this.unsupportedFormat.trigger({ reason: lastCloseReason });\r\n this._disposed = true;\r\n break;\r\n }\r\n\r\n this._tryIndex++;\r\n const delay = this.reconnectDelayer.getDelay(this._tryIndex);\r\n if (delay.isLimitExceeded) {\r\n this._disposed = true;\r\n break;\r\n }\r\n this._setReconnectsAt(delay.endsAt);\r\n try {\r\n await delay.promise;\r\n } finally {\r\n this._setReconnectsAt(0);\r\n }\r\n }\r\n }\r\n\r\n /** Re-send outbound calls after reconnection + flush pending sends.\r\n * Stage-3 compute calls are always self-invalidated: without $sys.Reconnect\r\n * protocol, the server's invalidation tracking is lost on disconnect, and\r\n * re-sending would get a duplicate $sys.Ok that is ignored (PromiseSource\r\n * already resolved). Self-invalidation forces a fresh recompute that\r\n * establishes new invalidation tracking on the new connection.\r\n * Regular in-flight calls are re-sent transparently. */\r\n private _reconnect(_isPeerChanged: boolean): void {\r\n if (this._connection === undefined) return;\r\n\r\n // Handle remote objects on reconnect\r\n if (_isPeerChanged) {\r\n this.remoteObjects.disconnectAll();\r\n } else {\r\n this.remoteObjects.reconnectAll();\r\n }\r\n\r\n // Re-send existing tracker calls, abort those whose RemoteExecutionMode disallows it\r\n const trackerCalls = [...this.outbound.values()];\r\n for (const call of trackerCalls) {\r\n const mode = call.remoteExecutionMode;\r\n if (!(mode & 2)) {\r\n // AllowReconnect not set — abort\r\n if (!call.result.isCompleted)\r\n call.result.reject(new Error('Outbound call failed: disconnected and AllowReconnect is not set.'));\r\n call.onDisconnect();\r\n this.outbound.remove(call.callId);\r\n } else if (_isPeerChanged && !(mode & 4)) {\r\n // AllowResend not set, peer changed — abort\r\n if (!call.result.isCompleted)\r\n call.result.reject(new Error('Outbound call failed: reconnected to a different peer and AllowResend is not set.'));\r\n call.onDisconnect();\r\n this.outbound.remove(call.callId);\r\n } else if (!call.removeOnOk && call.result.isCompleted) {\r\n // Stage-3 compute call: self-invalidate, forcing fresh recompute\r\n call.onDisconnect();\r\n this.outbound.remove(call.callId);\r\n } else {\r\n // Regular call or in-flight compute call: re-send\r\n this._sendWireData(call.serializedWireData);\r\n }\r\n }\r\n\r\n // Flush calls buffered while disconnected\r\n this._flushPendingSends();\r\n }\r\n\r\n protected override _onHandshakeReceived(handshake: RemoteHandshake): void {\r\n this._pendingHandshake?.resolve(handshake);\r\n }\r\n\r\n override close(): void {\r\n this._disposed = true;\r\n super.close();\r\n }\r\n}\r\n\r\n/** Server-side RPC peer — wraps an accepted connection. ref = \"server://{uuid}\". */\r\nexport class RpcServerPeer extends RpcPeer {\r\n constructor(hub: RpcHub, ref: string) {\r\n super(ref, hub);\r\n }\r\n\r\n /** Accept an incoming connection — sets up message handling and handshake response. */\r\n accept(conn: RpcConnection): void {\r\n this.setupConnection(conn);\r\n // When the client connection drops, clean up shared objects (stream senders).\r\n // Server peers don't reconnect — once the connection is gone, senders must be\r\n // terminated so their source iterators release resources promptly.\r\n conn.closed.add(() => {\r\n this.sharedObjects.disconnectAll();\r\n });\r\n }\r\n\r\n protected override _onHandshakeReceived(_handshake: RemoteHandshake): void {\r\n // Client sent its handshake → respond with our own\r\n if (this._connection !== undefined) {\r\n this._hub.systemCallSender.handshake(\r\n this._connection,\r\n this.format,\r\n this.id,\r\n this._hub.hubId,\r\n 0\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Convert a UUID string to base64url — matches .NET's Guid.ToBase64Url().\r\n * .NET Guid stores the first 3 groups in little-endian byte order.\r\n */\r\nfunction guidToBase64Url(uuid: string): string {\r\n const hex = uuid.replace(/-/g, '');\r\n const bytes = new Uint8Array(16);\r\n\r\n // Group 1 (bytes 0-3): little-endian\r\n bytes[0] = parseInt(hex.slice(6, 8), 16);\r\n bytes[1] = parseInt(hex.slice(4, 6), 16);\r\n bytes[2] = parseInt(hex.slice(2, 4), 16);\r\n bytes[3] = parseInt(hex.slice(0, 2), 16);\r\n // Group 2 (bytes 4-5): little-endian\r\n bytes[4] = parseInt(hex.slice(10, 12), 16);\r\n bytes[5] = parseInt(hex.slice(8, 10), 16);\r\n // Group 3 (bytes 6-7): little-endian\r\n bytes[6] = parseInt(hex.slice(14, 16), 16);\r\n bytes[7] = parseInt(hex.slice(12, 14), 16);\r\n // Groups 4-5 (bytes 8-15): big-endian\r\n for (let i = 8; i < 16; i++)\r\n bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\r\n\r\n const binary = String.fromCharCode(...bytes);\r\n return btoa(binary)\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=+$/, '');\r\n}\r\n","// .NET counterpart: ActualLab.Rpc.RpcClientPeerReconnectDelayer\r\n\r\nimport { RetryDelaySeq, RetryDelayer } from '@actuallab/core';\r\n\r\nexport class RpcClientPeerReconnectDelayer extends RetryDelayer {\r\n constructor() {\r\n super();\r\n this.delays = RetryDelaySeq.exp(1000, 60_000); // 1s min, 60s max\r\n }\r\n}\r\n","// RPC serialization format definitions — mirrors .NET RpcSerializationFormat.\r\n//\r\n// Each format knows how to serialize/deserialize RPC messages on the wire.\r\n// Format instances are immutable singletons — state like method registries\r\n// is passed in via parameters, not held by the format.\r\n\r\nimport { Encoder, Decoder } from '@msgpack/msgpack';\r\nimport type { RpcMessage } from './rpc-message.js';\r\nimport {\r\n serializeMessage,\r\n deserializeMessage,\r\n serializeBinaryMessage,\r\n splitBinaryFrame,\r\n serializeBinaryFrame,\r\n createBinaryEncoder,\r\n serializeCompactBinaryMessage,\r\n splitCompactBinaryFrame,\r\n} from './rpc-serialization.js';\r\nimport type { RpcMethodRegistry } from './rpc-method-registry.js';\r\n\r\n/** Parsed inbound message — result of deserialization. */\r\nexport interface RpcDeserializedMessage {\r\n message: RpcMessage;\r\n args: unknown[];\r\n}\r\n\r\n/** Wire data produced by serialization — either text or binary. */\r\nexport type RpcWireData = string | Uint8Array;\r\n\r\n/**\r\n * Base class for RPC serialization formats.\r\n * Instances are immutable singletons — one per format key.\r\n * State (like method registries) is passed via parameters.\r\n */\r\nexport abstract class RpcSerializationFormat {\r\n abstract readonly key: string;\r\n abstract readonly isBinary: boolean;\r\n /** Whether this format uses compact method hashes (needs RpcMethodRegistry). */\r\n abstract readonly isCompact: boolean;\r\n\r\n /** Serialize an outbound message. */\r\n abstract serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcWireData;\r\n\r\n /** Deserialize a single text message (only called for text formats). */\r\n abstract deserializeTextMessage(raw: string): RpcDeserializedMessage;\r\n\r\n /** Split + deserialize a binary frame (only called for binary formats). */\r\n abstract splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcDeserializedMessage[];\r\n\r\n /** Concatenate multiple serialized binary messages into one frame. */\r\n abstract serializeBinaryFrame(messages: Uint8Array[]): Uint8Array;\r\n\r\n /** Create a reusable binary encoder for this format. Returns undefined for text formats. */\r\n createEncoder(): Encoder | undefined {\r\n return undefined;\r\n }\r\n\r\n /** Create a reusable binary decoder for this format. Returns undefined for text formats. */\r\n createDecoder(): Decoder | undefined {\r\n return undefined;\r\n }\r\n\r\n // Named format instances — initialized in initFormats() below (after subclasses are defined)\r\n static SystemJsonV5: RpcSerializationFormat;\r\n static SystemJsonV5NP: RpcSerializationFormat;\r\n static NewtonsoftJsonV5: RpcSerializationFormat;\r\n static NewtonsoftJsonV5NP: RpcSerializationFormat;\r\n static MessagePackV6: RpcSerializationFormat;\r\n static MemoryPackV6: RpcSerializationFormat;\r\n static MessagePackV6C: RpcSerializationFormat;\r\n static MemoryPackV6C: RpcSerializationFormat;\r\n static All: readonly RpcSerializationFormat[];\r\n\r\n /** Convenience shortcut for RpcSerializationFormatResolver.Default.get(key). */\r\n static get(key: string): RpcSerializationFormat {\r\n return RpcSerializationFormatResolver.Default.get(key);\r\n }\r\n\r\n /** Convenience shortcut for RpcSerializationFormatResolver.Default.tryGet(key). */\r\n static tryGet(key: string): RpcSerializationFormat | undefined {\r\n return RpcSerializationFormatResolver.Default.tryGet(key);\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Concrete formats (immutable singletons)\r\n// ============================================================\r\n\r\n/**\r\n * JSON text format — \"json5np\" (System.Text.Json, no polymorphism).\r\n */\r\nexport class RpcJsonSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = false;\r\n readonly isCompact = false;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(message: RpcMessage, args?: unknown[]): string {\r\n return serializeMessage(message, args);\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(): RpcDeserializedMessage[] {\r\n throw new Error('Text format does not support binary frames');\r\n }\r\n\r\n serializeBinaryFrame(): Uint8Array {\r\n throw new Error('Text format does not support binary frames');\r\n }\r\n}\r\n\r\n/**\r\n * MessagePack binary format — \"msgpack6\" / \"mempack6\" (V5 wire format).\r\n */\r\nexport class RpcMessagePackSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = true;\r\n readonly isCompact = false;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder\r\n ): Uint8Array {\r\n return serializeBinaryMessage(message, args, encoder);\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder\r\n ): RpcDeserializedMessage[] {\r\n return splitBinaryFrame(frame, decoder);\r\n }\r\n\r\n serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return serializeBinaryFrame(messages);\r\n }\r\n\r\n override createEncoder(): Encoder {\r\n return createBinaryEncoder();\r\n }\r\n\r\n override createDecoder(): Decoder {\r\n return new Decoder();\r\n }\r\n}\r\n\r\n/**\r\n * MessagePack compact binary format — \"msgpack6c\" / \"mempack6c\" (V5Compact).\r\n * Uses 4-byte method hash instead of full method name.\r\n * Registry is passed via parameters — format instance is immutable.\r\n */\r\nexport class RpcMessagePackCompactSerializationFormat extends RpcSerializationFormat {\r\n readonly key: string;\r\n readonly isBinary = true;\r\n readonly isCompact = true;\r\n\r\n constructor(key: string) {\r\n super();\r\n this.key = key;\r\n }\r\n\r\n serializeMessage(\r\n message: RpcMessage,\r\n args?: unknown[],\r\n encoder?: Encoder,\r\n registry?: RpcMethodRegistry\r\n ): Uint8Array {\r\n return serializeCompactBinaryMessage(\r\n message,\r\n args,\r\n registry,\r\n encoder\r\n );\r\n }\r\n\r\n deserializeTextMessage(raw: string): RpcDeserializedMessage {\r\n return deserializeMessage(raw);\r\n }\r\n\r\n splitBinaryFrame(\r\n frame: Uint8Array,\r\n decoder?: Decoder,\r\n registry?: RpcMethodRegistry\r\n ): RpcDeserializedMessage[] {\r\n return splitCompactBinaryFrame(frame, registry, decoder);\r\n }\r\n\r\n serializeBinaryFrame(messages: Uint8Array[]): Uint8Array {\r\n return serializeBinaryFrame(messages);\r\n }\r\n\r\n override createEncoder(): Encoder {\r\n return createBinaryEncoder();\r\n }\r\n\r\n override createDecoder(): Decoder {\r\n return new Decoder();\r\n }\r\n}\r\n\r\n// ============================================================\r\n// Initialize named format instances (after subclasses are defined)\r\n// ============================================================\r\n\r\n// Text: System.Text.Json\r\nRpcSerializationFormat.SystemJsonV5 = new RpcJsonSerializationFormat('json5');\r\nRpcSerializationFormat.SystemJsonV5NP = new RpcJsonSerializationFormat('json5np');\r\n// Text: Newtonsoft.Json\r\nRpcSerializationFormat.NewtonsoftJsonV5 = new RpcJsonSerializationFormat('njson5');\r\nRpcSerializationFormat.NewtonsoftJsonV5NP = new RpcJsonSerializationFormat('njson5np');\r\n// Binary: MessagePack (non-compact)\r\nRpcSerializationFormat.MessagePackV6 = new RpcMessagePackSerializationFormat('msgpack6');\r\nRpcSerializationFormat.MemoryPackV6 = new RpcMessagePackSerializationFormat('mempack6');\r\n// Binary: MessagePack (compact)\r\nRpcSerializationFormat.MessagePackV6C = new RpcMessagePackCompactSerializationFormat('msgpack6c');\r\nRpcSerializationFormat.MemoryPackV6C = new RpcMessagePackCompactSerializationFormat('mempack6c');\r\n\r\nRpcSerializationFormat.All = [\r\n RpcSerializationFormat.SystemJsonV5,\r\n RpcSerializationFormat.SystemJsonV5NP,\r\n RpcSerializationFormat.NewtonsoftJsonV5,\r\n RpcSerializationFormat.NewtonsoftJsonV5NP,\r\n RpcSerializationFormat.MessagePackV6,\r\n RpcSerializationFormat.MemoryPackV6,\r\n RpcSerializationFormat.MessagePackV6C,\r\n RpcSerializationFormat.MemoryPackV6C,\r\n];\r\n\r\n// ============================================================\r\n// RpcSerializationFormatResolver — mirrors .NET RpcSerializationFormatResolver\r\n// ============================================================\r\n\r\n/**\r\n * Resolves RpcSerializationFormat instances by key, with a configurable default.\r\n * Mirrors .NET RpcSerializationFormatResolver.\r\n */\r\nexport class RpcSerializationFormatResolver {\r\n static DefaultFormats: readonly RpcSerializationFormat[] = RpcSerializationFormat.All;\r\n static Default = new RpcSerializationFormatResolver('json5np');\r\n\r\n readonly defaultFormatKey: string;\r\n readonly formats: ReadonlyMap<string, RpcSerializationFormat>;\r\n\r\n get defaultFormat(): RpcSerializationFormat {\r\n return this.get(this.defaultFormatKey);\r\n }\r\n\r\n constructor(defaultFormatKey: string, formats?: Iterable<RpcSerializationFormat>) {\r\n const map = new Map<string, RpcSerializationFormat>();\r\n for (const f of formats ?? RpcSerializationFormatResolver.DefaultFormats)\r\n map.set(f.key, f);\r\n\r\n if (!map.has(defaultFormatKey))\r\n throw new Error(`No format with key '${defaultFormatKey}'.`);\r\n\r\n this.defaultFormatKey = defaultFormatKey;\r\n this.formats = map;\r\n }\r\n\r\n get(key: string): RpcSerializationFormat {\r\n const format = this.tryGet(key);\r\n if (!format)\r\n throw new Error(`No format with key '${key}'.`);\r\n return format;\r\n }\r\n\r\n tryGet(key: string): RpcSerializationFormat | undefined {\r\n if (!key) key = this.defaultFormatKey;\r\n return this.formats.get(key);\r\n }\r\n}\r\n","// .NET counterparts:\r\n// RpcServiceBase (17 lines) — abstract base class providing DI access (Services,\r\n// Hub, Log). All RPC service implementations inherit from it.\r\n// RpcServiceRegistry — builds the full map of all services and their method defs\r\n// at startup; provides GetServerMethodResolver() for version-aware method\r\n// lookup. Inbound call dispatch is handled by RpcInboundCall.Process() which\r\n// invokes the method via a compiled delegate chain (MethodDef.InboundCallInvoker).\r\n//\r\n// Omitted from .NET:\r\n// - Compiled delegate pipeline — .NET pre-compiles per-method invoker delegates\r\n// (InboundCallServerInvokerFactory<T>, InboundCallMiddlewareInvokerFactory<T>)\r\n// using generic type instantiation. These invokers handle deserialization,\r\n// middleware chain, server method invocation, and result serialization — all\r\n// as a strongly-typed Task<TResult>. TS uses a simple async function dispatch\r\n// via fn(...args) because there's no middleware pipeline and JSON handles any\r\n// type.\r\n// - ServiceResolver (DI-based lazy service resolution) — .NET resolves the\r\n// service implementation from DI on first use. TS receives the impl object\r\n// directly in register().\r\n// - RpcServiceMode (Local/Client/Server/Hybrid) — .NET classifies each service\r\n// registration. TS has no mode; services are either registered (server) or\r\n// proxied (client).\r\n// - Version-aware method resolution (ServerMethodResolver with legacy names) —\r\n// .NET can resolve methods by legacy names for rolling-upgrade compatibility.\r\n// TS has no versioning.\r\n// - RpcInboundContext / AsyncLocal — .NET sets thread-local inbound context\r\n// so system call handlers can access the current peer/message. TS passes\r\n// context explicitly as a function argument (RpcDispatchContext).\r\n\r\nimport type { RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName } from './rpc-service-def.js';\r\nimport type { RpcServiceDef } from './rpc-service-def.js';\r\nimport type { RpcConnection } from './rpc-connection.js';\r\n\r\nexport type RpcServiceImpl = Record<string, ((...args: unknown[]) => unknown) | undefined>;\r\n\r\n/** Context passed to service dispatch — carries callId and connection for compute tracking. */\r\nexport interface RpcDispatchContext {\r\n __rpcDispatch: true;\r\n callId: number;\r\n connection: RpcConnection;\r\n}\r\n\r\n/** Dispatches inbound RPC calls to registered service implementations. */\r\nexport class RpcServiceHost {\r\n private _methods = new Map<\r\n string,\r\n { def: RpcMethodDef; fn: (...args: unknown[]) => unknown }\r\n >();\r\n\r\n register(def: RpcServiceDef, impl: RpcServiceImpl): void {\r\n for (const methodDef of def.methods.values()) {\r\n const fn = impl[methodDef.name];\r\n if (!fn) continue;\r\n this._methods.set(wireMethodName(methodDef), {\r\n def: methodDef,\r\n fn,\r\n });\r\n }\r\n }\r\n\r\n async dispatch(\r\n wireMethod: string,\r\n args: unknown[],\r\n context?: RpcDispatchContext\r\n ): Promise<unknown> {\r\n const entry = this._methods.get(wireMethod);\r\n if (entry === undefined)\r\n throw new Error(`Method not found: ${wireMethod}`);\r\n\r\n // Pass context as the last arg only for custom call types (e.g., compute) — their\r\n // wrapped functions use it; regular methods should not see it to avoid polluting ...args.\r\n if (context !== undefined && entry.def.callTypeId !== 0) {\r\n return await entry.fn(...args, context);\r\n }\r\n return await entry.fn(...args);\r\n }\r\n\r\n getMethodDef(wireMethod: string): RpcMethodDef | undefined {\r\n return this._methods.get(wireMethod)?.def;\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcMethodAttribute — optional attribute that can override a method's wire name.\r\n// Method metadata (arg count, return type, NoWait, stream, etc.) is discovered\r\n// automatically via reflection on the service interface.\r\n// Interface-based metadata — .NET discovers all methods by reflecting on the\r\n// service interface type. NoWait is determined by return type == Task<RpcNoWait>.\r\n// Stream is determined by return type being IAsyncEnumerable<T>.\r\n//\r\n// Omitted from .NET:\r\n// - Reflection-based auto-discovery — .NET scans interface methods, parameter\r\n// types, and return types at startup. TS uses explicit decorator metadata\r\n// because TypeScript erases type information at runtime.\r\n// - RpcMethodAttribute.Name — custom wire name override. TS decorators don't\r\n// support custom wire names (always \"ServiceName.methodName\").\r\n// - RpcServiceAttribute — .NET has no class-level decorator; the service name\r\n// is configured in RpcServiceBuilder via DI. TS uses @rpcService(\"name\")\r\n// class decorator as a convenient alternative to DI configuration.\r\n// - Automatic NoWait detection from return type — .NET checks if return type\r\n// is Task<RpcNoWait>. TS requires explicit { returns: RpcType.noWait }\r\n// because return types are erased.\r\n// - Automatic stream detection from return type — .NET checks for\r\n// IAsyncEnumerable<T>. TS requires explicit { returns: RpcType.stream }.\r\n// - compute flag in method metadata — stored here for FusionHub's\r\n// addServiceFromContract() which reads decorator metadata to build a\r\n// RpcServiceDef. .NET determines this via the service interface hierarchy\r\n// (IComputeService marker interface).\r\n\r\nconst METHODS_META = Symbol.for('actuallab.methods');\r\nconst SERVICE_META = Symbol.for('actuallab.service');\r\n\r\nexport interface MethodMeta {\r\n argCount: number;\r\n returns?: symbol;\r\n /** Bitfield of RpcRemoteExecutionMode flags. */\r\n remoteExecutionMode?: number;\r\n [key: symbol]: unknown;\r\n}\r\n\r\nexport interface ServiceMeta {\r\n name: string;\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- constructor type requires any for maximum compatibility\r\nexport type AnyConstructor = abstract new (...args: any[]) => any;\r\n\r\n/** Read method metadata from a decorated class. */\r\nexport function getMethodsMeta(\r\n cls: AnyConstructor,\r\n): Record<string, MethodMeta> | undefined {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- Symbol.metadata is not in standard typings\r\n return (cls as any)[Symbol.metadata]?.[METHODS_META] as Record<string, MethodMeta> | undefined;\r\n}\r\n\r\n/** Read service metadata from a decorated class. */\r\nexport function getServiceMeta(\r\n cls: AnyConstructor,\r\n): ServiceMeta | undefined {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- Symbol.metadata is not in standard typings\r\n return (cls as any)[Symbol.metadata]?.[SERVICE_META] as ServiceMeta | undefined;\r\n}\r\n\r\n/** Class decorator — stores the RPC service wire name. */\r\nexport function rpcService(serviceName: string) {\r\n return function <T extends AnyConstructor>(\r\n _target: T,\r\n context: ClassDecoratorContext<T>,\r\n ): void {\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- decorator metadata requires untyped access\r\n const meta: ServiceMeta = ((context.metadata as any)[SERVICE_META] ??=\r\n {} as ServiceMeta);\r\n meta.name = serviceName;\r\n };\r\n}\r\n\r\n/** Method decorator — stores RPC method metadata (argCount, returns, remoteExecutionMode). Does NOT wrap the method. */\r\nexport function rpcMethod(options?: { returns?: symbol; remoteExecutionMode?: number }) {\r\n return function <This, Args extends unknown[], Return>(\r\n target: (this: This, ...args: Args) => Return,\r\n context: ClassMethodDecoratorContext<\r\n This,\r\n (this: This, ...args: Args) => Return\r\n >,\r\n ): (this: This, ...args: Args) => Return {\r\n const methodName = String(context.name);\r\n /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any -- decorator metadata requires untyped access */\r\n const methods: Record<string, MethodMeta> = ((context.metadata as any)[\r\n METHODS_META\r\n ] ??= {});\r\n /* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */\r\n methods[methodName] = {\r\n ...methods[methodName],\r\n argCount: target.length,\r\n returns: options?.returns,\r\n remoteExecutionMode: options?.remoteExecutionMode,\r\n };\r\n return target; // no wrapping — RPC proxy handles invocation\r\n };\r\n}\r\n","// Pure TypeScript XXH3-64 implementation using BigInt.\r\n// Sync, zero dependencies. Supports inputs of any length.\r\n//\r\n// Reference: https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h\r\n// Verified against .NET System.IO.Hashing.XxHash3.HashToUInt64.\r\n\r\n \r\n\r\nconst U64_MASK = 0xffff_ffff_ffff_ffffn;\r\nconst U32_MASK = 0xffff_ffffn;\r\n\r\nconst PRIME32_1 = 0x9e3779b1;\r\nconst PRIME32_2 = 0x85ebca77;\r\nconst PRIME32_3 = 0xc2b2ae3d;\r\n\r\nconst PRIME64_1 = 0x9e3779b185ebca87n;\r\nconst PRIME64_2 = 0xc2b2ae3d27d4eb4fn;\r\nconst PRIME64_3 = 0x165667b19e3779f9n;\r\nconst PRIME64_4 = 0x85ebca77c2b2ae63n;\r\nconst PRIME64_5 = 0x27d4eb2f165667c5n;\r\n\r\nconst XXH3_SECRET_SIZE_MIN = 136;\r\nconst XXH_SECRET_DEFAULT_SIZE = 192;\r\n\r\nconst STRIPE_LEN = 64;\r\nconst XXH_SECRET_CONSUME_RATE = 8;\r\nconst ACC_NB = STRIPE_LEN / 8;\r\n\r\nconst XXH3_MIDSIZE_MAX = 240;\r\nconst XXH3_MIDSIZE_STARTOFFSET = 3;\r\nconst XXH3_MIDSIZE_LASTOFFSET = 17;\r\nconst XXH_SECRET_LASTACC_START = 7;\r\nconst XXH_SECRET_MERGEACCS_START = 11;\r\n\r\nconst RRMXMX = 0x9fb21c651e98df25n;\r\n\r\n// prettier-ignore\r\nconst DEFAULT_SECRET = new Uint8Array([\r\n 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,\r\n 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,\r\n 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21,\r\n 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c,\r\n 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3,\r\n 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8,\r\n 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d,\r\n 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64,\r\n 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,\r\n 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,\r\n 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,\r\n 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,\r\n]);\r\n\r\nfunction u64(x: bigint): bigint {\r\n return x & U64_MASK;\r\n}\r\n\r\nfunction read32LE(buf: Uint8Array, off: number): number {\r\n return (\r\n (buf[off] |\r\n (buf[off + 1] << 8) |\r\n (buf[off + 2] << 16) |\r\n (buf[off + 3] << 24)) >>>\r\n 0\r\n );\r\n}\r\n\r\nfunction read64LE(buf: Uint8Array, off: number): bigint {\r\n return (\r\n BigInt(buf[off]) |\r\n (BigInt(buf[off + 1]) << 8n) |\r\n (BigInt(buf[off + 2]) << 16n) |\r\n (BigInt(buf[off + 3]) << 24n) |\r\n (BigInt(buf[off + 4]) << 32n) |\r\n (BigInt(buf[off + 5]) << 40n) |\r\n (BigInt(buf[off + 6]) << 48n) |\r\n (BigInt(buf[off + 7]) << 56n)\r\n );\r\n}\r\n\r\nfunction write64LE(buf: Uint8Array, off: number, value: bigint): void {\r\n let x = u64(value);\r\n for (let i = 0; i < 8; i++) {\r\n buf[off + i] = Number(x & 0xffn);\r\n x >>= 8n;\r\n }\r\n}\r\n\r\nfunction swap32(x: number): number {\r\n return (\r\n (((x << 24) & 0xff000000) |\r\n ((x << 8) & 0x00ff0000) |\r\n ((x >>> 8) & 0x0000ff00) |\r\n ((x >>> 24) & 0x000000ff)) >>>\r\n 0\r\n );\r\n}\r\n\r\nfunction swap64(x: bigint): bigint {\r\n x = u64(x);\r\n return (\r\n ((x << 56n) & 0xff00000000000000n) |\r\n ((x << 40n) & 0x00ff000000000000n) |\r\n ((x << 24n) & 0x0000ff0000000000n) |\r\n ((x << 8n) & 0x000000ff00000000n) |\r\n ((x >> 8n) & 0x00000000ff000000n) |\r\n ((x >> 24n) & 0x0000000000ff0000n) |\r\n ((x >> 40n) & 0x000000000000ff00n) |\r\n ((x >> 56n) & 0x00000000000000ffn)\r\n );\r\n}\r\n\r\nfunction rotl64(x: bigint, amount: number): bigint {\r\n const r = BigInt(amount & 63);\r\n return u64((x << r) | (x >> (64n - r)));\r\n}\r\n\r\nfunction mul128Fold64(lhs: bigint, rhs: bigint): bigint {\r\n const product = u64(lhs) * u64(rhs);\r\n return u64(product) ^ u64(product >> 64n);\r\n}\r\n\r\n// XXH64_avalanche — used by len_0 and len_1to3\r\nfunction xxh64Avalanche(hash: bigint): bigint {\r\n let h = u64(hash);\r\n h ^= h >> 33n;\r\n h = u64(h * PRIME64_2);\r\n h ^= h >> 29n;\r\n h = u64(h * PRIME64_3);\r\n h ^= h >> 32n;\r\n return u64(h);\r\n}\r\n\r\n// XXH3_avalanche — used by len_9to16, len_17to128, len_129to240\r\nfunction xxh3Avalanche(hash: bigint): bigint {\r\n let h = u64(hash);\r\n h ^= h >> 37n;\r\n h = u64(h * 0x165667919e3779f9n);\r\n h ^= h >> 32n;\r\n return u64(h);\r\n}\r\n\r\nfunction len0(secret: Uint8Array, seed: bigint): bigint {\r\n const acc = u64(seed ^ read64LE(secret, 56) ^ read64LE(secret, 64));\r\n return xxh64Avalanche(acc);\r\n}\r\n\r\nfunction len1to3(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n const byte1 = input[0];\r\n const byte2 = length > 1 ? input[1] : input[0];\r\n const byte3 = input[length - 1];\r\n const combined =\r\n ((byte1 << 16) | (byte2 << 24) | byte3 | (length << 8)) >>> 0;\r\n const bitflip = u64(\r\n BigInt((read32LE(secret, 0) ^ read32LE(secret, 4)) >>> 0) + seed\r\n );\r\n const value64 = u64(BigInt(combined) ^ bitflip);\r\n return xxh64Avalanche(value64);\r\n}\r\n\r\nfunction len4to8(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n const inputHi = read32LE(input, 0);\r\n const inputLo = read32LE(input, length - 4);\r\n const input64 = BigInt(inputLo) | (BigInt(inputHi) << 32n);\r\n let acc = read64LE(secret, 8) ^ read64LE(secret, 16);\r\n seed ^= BigInt(swap32(Number(seed & U32_MASK))) << 32n;\r\n acc = u64(acc - seed);\r\n acc ^= input64;\r\n acc ^= rotl64(acc, 49) ^ rotl64(acc, 24);\r\n acc = u64(acc * RRMXMX);\r\n acc ^= (acc >> 35n) + BigInt(length);\r\n acc = u64(acc * RRMXMX);\r\n acc ^= acc >> 28n;\r\n return u64(acc);\r\n}\r\n\r\nfunction len9to16(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let inputLo = read64LE(secret, 24) ^ read64LE(secret, 32);\r\n let inputHi = read64LE(secret, 40) ^ read64LE(secret, 48);\r\n let acc = BigInt(length);\r\n inputLo = u64(inputLo + seed);\r\n inputHi = u64(inputHi - seed);\r\n inputLo ^= read64LE(input, 0);\r\n inputHi ^= read64LE(input, length - 8);\r\n acc = u64(acc + swap64(inputLo));\r\n acc = u64(acc + inputHi);\r\n acc = u64(acc + mul128Fold64(inputLo, inputHi));\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction mix16B(\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number,\r\n seed: bigint\r\n): bigint {\r\n let lhs = seed;\r\n let rhs = u64(0n - seed);\r\n lhs = u64(lhs + read64LE(secret, secretOff));\r\n rhs = u64(rhs + read64LE(secret, secretOff + 8));\r\n lhs ^= read64LE(input, inputOff);\r\n rhs ^= read64LE(input, inputOff + 8);\r\n return mul128Fold64(lhs, rhs);\r\n}\r\n\r\nfunction len17to128(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let i = Math.floor((length - 1) / 32);\r\n let acc = u64(BigInt(length) * PRIME64_1);\r\n for (; i >= 0; i--) {\r\n acc = u64(acc + mix16B(input, 16 * i, secret, 32 * i, seed));\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n length - 16 * (i + 1),\r\n secret,\r\n 32 * i + 16,\r\n seed\r\n )\r\n );\r\n }\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction len129to240(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n let acc = u64(BigInt(length) * PRIME64_1);\r\n const nbRounds = Math.floor(length / 16);\r\n for (let i = 0; i < 8; i++) {\r\n acc = u64(acc + mix16B(input, 16 * i, secret, 16 * i, seed));\r\n }\r\n acc = xxh3Avalanche(acc);\r\n for (let i = 8; i < nbRounds; i++) {\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n 16 * i,\r\n secret,\r\n 16 * (i - 8) + XXH3_MIDSIZE_STARTOFFSET,\r\n seed\r\n )\r\n );\r\n }\r\n acc = u64(\r\n acc +\r\n mix16B(\r\n input,\r\n length - 16,\r\n secret,\r\n XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET,\r\n seed\r\n )\r\n );\r\n return xxh3Avalanche(acc);\r\n}\r\n\r\nfunction hashShort(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n seed: bigint\r\n): bigint {\r\n if (length <= 16) {\r\n if (length > 8) return len9to16(input, length, secret, seed);\r\n if (length >= 4) return len4to8(input, length, secret, seed);\r\n if (length !== 0) return len1to3(input, length, secret, seed);\r\n return len0(secret, seed);\r\n }\r\n if (length <= 128) return len17to128(input, length, secret, seed);\r\n return len129to240(input, length, secret, seed);\r\n}\r\n\r\n// --- Long input (> 240 bytes) ---\r\n\r\nfunction accumulate512(\r\n acc: bigint[],\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number\r\n): void {\r\n for (let i = 0; i < ACC_NB; i++) {\r\n const dataVal = read64LE(input, inputOff + 8 * i);\r\n const dataKey = dataVal ^ read64LE(secret, secretOff + 8 * i);\r\n acc[i ^ 1] = u64(acc[i ^ 1] + dataVal);\r\n const low32 = dataKey & U32_MASK;\r\n const high32 = dataKey >> 32n;\r\n acc[i] = u64(acc[i] + low32 * high32);\r\n }\r\n}\r\n\r\nfunction scrambleAcc(\r\n acc: bigint[],\r\n secret: Uint8Array,\r\n secretOff: number\r\n): void {\r\n for (let i = 0; i < ACC_NB; i++) {\r\n let x = acc[i];\r\n x ^= x >> 47n;\r\n x ^= read64LE(secret, secretOff + 8 * i);\r\n x = u64(x * BigInt(PRIME32_1));\r\n acc[i] = x;\r\n }\r\n}\r\n\r\nfunction accumulateLoop(\r\n acc: bigint[],\r\n input: Uint8Array,\r\n inputOff: number,\r\n secret: Uint8Array,\r\n secretOff: number,\r\n nbStripes: number\r\n): void {\r\n for (let n = 0; n < nbStripes; n++) {\r\n accumulate512(\r\n acc,\r\n input,\r\n inputOff + n * STRIPE_LEN,\r\n secret,\r\n secretOff + 8 * n\r\n );\r\n }\r\n}\r\n\r\nfunction mix2Accs(\r\n acc: bigint[],\r\n accOff: number,\r\n secret: Uint8Array,\r\n secretOff: number\r\n): bigint {\r\n return mul128Fold64(\r\n acc[accOff] ^ read64LE(secret, secretOff),\r\n acc[accOff + 1] ^ read64LE(secret, secretOff + 8)\r\n );\r\n}\r\n\r\nfunction mergeAccs(\r\n acc: bigint[],\r\n key: Uint8Array,\r\n keyOff: number,\r\n start: bigint\r\n): bigint {\r\n let result = start;\r\n for (let i = 0; i < 4; i++) {\r\n result = u64(result + mix2Accs(acc, 2 * i, key, keyOff + 16 * i));\r\n }\r\n return xxh3Avalanche(result);\r\n}\r\n\r\nfunction hashLong(\r\n input: Uint8Array,\r\n length: number,\r\n secret: Uint8Array,\r\n secretSize: number\r\n): bigint {\r\n const nbRounds = Math.floor(\r\n (secretSize - STRIPE_LEN) / XXH_SECRET_CONSUME_RATE\r\n );\r\n const blockLen = STRIPE_LEN * nbRounds;\r\n const nbBlocks = Math.floor((length - 1) / blockLen);\r\n const nbStripes = Math.floor(\r\n ((length - 1) - blockLen * nbBlocks) / STRIPE_LEN\r\n );\r\n\r\n const acc: bigint[] = [\r\n BigInt(PRIME32_3),\r\n PRIME64_1,\r\n PRIME64_2,\r\n PRIME64_3,\r\n PRIME64_4,\r\n BigInt(PRIME32_2),\r\n PRIME64_5,\r\n BigInt(PRIME32_1),\r\n ];\r\n\r\n for (let n = 0; n < nbBlocks; n++) {\r\n accumulateLoop(acc, input, n * blockLen, secret, 0, nbRounds);\r\n scrambleAcc(acc, secret, secretSize - STRIPE_LEN);\r\n }\r\n\r\n accumulateLoop(acc, input, nbBlocks * blockLen, secret, 0, nbStripes);\r\n\r\n // Last stripe — always applied (C reference: unconditional)\r\n accumulate512(\r\n acc,\r\n input,\r\n length - STRIPE_LEN,\r\n secret,\r\n secretSize - STRIPE_LEN - XXH_SECRET_LASTACC_START\r\n );\r\n\r\n return mergeAccs(\r\n acc,\r\n secret,\r\n XXH_SECRET_MERGEACCS_START,\r\n u64(BigInt(length) * PRIME64_1)\r\n );\r\n}\r\n\r\nfunction hashLongWithSeed(\r\n input: Uint8Array,\r\n length: number,\r\n seed: bigint\r\n): bigint {\r\n const secret = new Uint8Array(XXH_SECRET_DEFAULT_SIZE);\r\n for (let i = 0; i < XXH_SECRET_DEFAULT_SIZE / 16; i++) {\r\n const off = 16 * i;\r\n write64LE(secret, off, u64(read64LE(DEFAULT_SECRET, off) + seed));\r\n write64LE(\r\n secret,\r\n off + 8,\r\n u64(read64LE(DEFAULT_SECRET, off + 8) - seed)\r\n );\r\n }\r\n return hashLong(input, length, secret, secret.length);\r\n}\r\n\r\n// --- Public API ---\r\n\r\nconst textEncoder = new TextEncoder();\r\n\r\n/**\r\n * Compute XXH3-64 hash of a byte array. Returns a BigInt (unsigned 64-bit).\r\n * Pure TypeScript, synchronous, supports any input length.\r\n */\r\nexport function xxh3_64(input: Uint8Array, seed = 0n): bigint {\r\n const len = input.length;\r\n if (len <= XXH3_MIDSIZE_MAX) {\r\n return hashShort(input, len, DEFAULT_SECRET, u64(seed));\r\n }\r\n return hashLongWithSeed(input, len, u64(seed));\r\n}\r\n\r\n/**\r\n * Compute XXH3-64 hash of a UTF-8 string. Returns a BigInt (unsigned 64-bit).\r\n */\r\nexport function xxh3_64str(input: string, seed = 0n): bigint {\r\n return xxh3_64(textEncoder.encode(input), seed);\r\n}\r\n\r\n/**\r\n * Compute the RPC method hash matching .NET's RpcMethodRef.ComputeHashCode.\r\n * Returns a 32-bit signed integer (lower 32 bits of XXH3-64 of [prefix + utf8Name]).\r\n *\r\n * The prefix is uint32 LE of (67211 * utf8Name.length), which ensures methods\r\n * with different name lengths but similar text produce different hashes.\r\n *\r\n * Computed on demand — caller should cache the result per method name.\r\n */\r\nexport function computeMethodHash(methodName: string): number {\r\n const utf8 = textEncoder.encode(methodName);\r\n // Prefix: uint32 LE of (67211 * utf8.length)\r\n const prefixValue = Math.imul(67211, utf8.length) >>> 0;\r\n const prefixed = new Uint8Array(4 + utf8.length);\r\n prefixed[0] = prefixValue & 0xff;\r\n prefixed[1] = (prefixValue >>> 8) & 0xff;\r\n prefixed[2] = (prefixValue >>> 16) & 0xff;\r\n prefixed[3] = (prefixValue >>> 24) & 0xff;\r\n prefixed.set(utf8, 4);\r\n const hash64 = xxh3_64(prefixed);\r\n // Truncate to signed int32 (same as C#'s unchecked((int)hash64))\r\n return Number(hash64 & 0xffffffffn) | 0;\r\n}\r\n","// Method name ↔ hash registry for compact binary serialization.\r\n//\r\n// .NET counterpart: RpcMethodResolver — maintains MethodByHashCode dictionary\r\n// for resolving compact 4-byte method hashes back to full method names.\r\n//\r\n// Hashes are computed on demand (first use) and cached. The computeMethodHash\r\n// function uses BigInt-based XXH3-64, which is pure sync TypeScript.\r\n\r\nimport { computeMethodHash } from './rpc-xxhash3.js';\r\n\r\n/**\r\n * Registry mapping RPC method wire names to/from their 4-byte XXH3 hashes.\r\n * Hashes match .NET's RpcMethodRef.ComputeHashCode.\r\n * Hashes are computed lazily on first access and cached.\r\n */\r\nexport class RpcMethodRegistry {\r\n private _nameToHash = new Map<string, number>();\r\n private _hashToName = new Map<number, string>();\r\n\r\n /** Register a method name and compute its hash. */\r\n register(methodName: string): void {\r\n if (this._nameToHash.has(methodName)) return;\r\n const hash = computeMethodHash(methodName);\r\n\r\n // Check for hash collisions\r\n const existing = this._hashToName.get(hash);\r\n if (existing !== undefined && existing !== methodName) {\r\n console.warn(\r\n `[RpcMethodRegistry] hash collision: \"${methodName}\" and \"${existing}\" both hash to ${hash}`\r\n );\r\n return;\r\n }\r\n\r\n this._nameToHash.set(methodName, hash);\r\n this._hashToName.set(hash, methodName);\r\n }\r\n\r\n /** Register all wire method names from a service definition. */\r\n registerService(\r\n serviceName: string,\r\n methods: ReadonlyMap<string, { name: string; wireArgCount: number }>\r\n ): void {\r\n for (const [, def] of methods) {\r\n const wireName = `${serviceName}.${def.name}:${def.wireArgCount}`;\r\n this.register(wireName);\r\n }\r\n }\r\n\r\n /** Get the hash for a method name. Computes on demand if not registered. */\r\n getHash(methodName: string): number {\r\n let hash = this._nameToHash.get(methodName);\r\n if (hash === undefined) {\r\n this.register(methodName);\r\n hash = this._nameToHash.get(methodName)!;\r\n }\r\n return hash;\r\n }\r\n\r\n /** Get the method name for a hash. Returns undefined if not registered. */\r\n getName(hash: number): string | undefined {\r\n return this._hashToName.get(hash);\r\n }\r\n\r\n /** Get the hash for a method name, throwing if not registered. */\r\n requireHash(methodName: string): number {\r\n return this.getHash(methodName);\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcHub (141 lines) — a sealed ProcessorBase (IAsyncDisposable) that owns:\r\n// DI-resolved configuration (RpcRegistryOptions, PeerOptions, InboundCallOptions,\r\n// OutboundCallOptions, DiagnosticsOptions), SerializationFormats, Middlewares,\r\n// ClientPeerReconnectDelayer, Limits, SystemClock.\r\n// Manages peers via ConcurrentDictionary<RpcPeerRef, RpcPeer> with GetPeer()\r\n// that lazily creates + starts peers. Also has GetClient<T>() / GetServer<T>()\r\n// that look up services in ServiceRegistry.\r\n//\r\n// Omitted from .NET:\r\n// - DI / IServiceProvider integration — .NET resolves all options, serializers,\r\n// middleware, delayers, etc. from DI. TS constructs everything directly.\r\n// - RpcServiceRegistry — .NET builds a full registry of all RPC services at\r\n// startup via reflection + DI, mapping Type → RpcServiceDef. TS uses explicit\r\n// addService() / addClient() calls.\r\n// - GetClient<T>() / GetServer<T>() — .NET resolves typed client/server proxies\r\n// via the ServiceRegistry + DI. TS uses addClient<T>(peer, def).\r\n// - RpcPeerRef-keyed peer dictionary — .NET peers are keyed by RpcPeerRef (rich\r\n// value object encoding route, version, serialization format). TS uses string\r\n// refs (URL for clients, \"server://{uuid}\" for servers).\r\n// - Lazy peer creation + Start() — .NET's GetPeer auto-creates and starts a\r\n// peer's reconnection loop. TS requires explicit addPeer() + run().\r\n// - DisposeAsync — .NET disposes all peers on hub shutdown. TS has close().\r\n// - Route change detection (RouteState.WhenChanged → Dispose peer) — .NET\r\n// watches for load-balancer route changes and auto-disposes stale peers.\r\n// TS has no routing layer.\r\n// - Middlewares (IRpcMiddleware[]) — ordered middleware pipeline for inbound\r\n// calls. TS dispatches directly to service implementations.\r\n// - Limits (RpcLimits) — configurable limits for call timeout, handshake\r\n// timeout, max message size, etc. TS uses hardcoded values.\r\n// - RpcConfiguration / Configuration.Freeze() — frozen config snapshot.\r\n// - HostId / SystemClock — infrastructure services.\r\n// - DefaultPeer / LoopbackPeer / LocalPeer / NonePeer — cached well-known peers.\r\n\r\nimport {\r\n RpcClientPeer,\r\n RpcServerPeer,\r\n type RpcPeer,\r\n type RpcCallOptions,\r\n} from './rpc-peer.js';\r\nimport { RpcServiceHost, type RpcServiceImpl } from './rpc-service-host.js';\r\nimport type { RpcServiceDef, RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName, RpcType, RpcRemoteExecutionMode } from './rpc-service-def.js';\r\nimport { getServiceMeta, getMethodsMeta, type AnyConstructor } from './rpc-decorators.js';\r\nimport { RpcSystemCallSender } from './rpc-system-call-sender.js';\r\nimport { RpcSystemCallHandler } from './rpc-system-call-handler.js';\r\nimport { RpcStream, parseStreamRef, resolveStreamRefs } from './rpc-stream.js';\r\nimport { RpcMethodRegistry } from './rpc-method-registry.js';\r\nimport { RpcSystemCalls } from './rpc-message.js';\r\n\r\n/** Central RPC coordinator — manages peers, services, and configuration. */\r\nexport class RpcHub {\r\n readonly hubId: string;\r\n readonly peers = new Map<string, RpcPeer>();\r\n readonly serviceHost: RpcServiceHost;\r\n readonly systemCallSender = new RpcSystemCallSender();\r\n systemCallHandler: RpcSystemCallHandler = new RpcSystemCallHandler();\r\n\r\n /** Method registry for compact format hash ↔ name resolution.\r\n * Created lazily, populated by addService/addClient. */\r\n readonly registry = new RpcMethodRegistry();\r\n\r\n constructor(hubId?: string) {\r\n this.hubId = hubId ?? crypto.randomUUID();\r\n this.serviceHost = new RpcServiceHost();\r\n this.systemCallSender.registry = this.registry;\r\n // Pre-register system call method names for compact format hash resolution\r\n for (const methodName of Object.values(RpcSystemCalls)) {\r\n this.registry.register(methodName);\r\n }\r\n }\r\n\r\n addPeer(peer: RpcPeer): void {\r\n this.peers.set(peer.ref, peer);\r\n }\r\n\r\n removePeer(ref: string): void {\r\n const peer = this.peers.get(ref);\r\n if (peer !== undefined) {\r\n peer.close();\r\n this.peers.delete(ref);\r\n }\r\n }\r\n\r\n /** Get or create a peer by ref. Server peers have \"server://\" prefix, everything else is a client peer. */\r\n getPeer(ref: string): RpcPeer {\r\n let peer = this.peers.get(ref);\r\n if (peer) return peer;\r\n peer = ref.startsWith('server://')\r\n ? new RpcServerPeer(this, ref)\r\n : new RpcClientPeer(this, ref);\r\n this.addPeer(peer);\r\n return peer;\r\n }\r\n\r\n /** Get or create a client peer for the given URL. */\r\n getClientPeer(ref: string): RpcClientPeer {\r\n return this.getPeer(ref) as RpcClientPeer;\r\n }\r\n\r\n /** Get or create a server peer for the given ref. */\r\n getServerPeer(ref: string): RpcServerPeer {\r\n return this.getPeer(ref) as RpcServerPeer;\r\n }\r\n\r\n /** Register a service with optional server method wrapping for custom call types. */\r\n addService(\r\n defOrContract: RpcServiceDef | (AnyConstructor),\r\n impl: RpcServiceImpl\r\n ): void {\r\n const def = this._resolveServiceDef(defOrContract);\r\n const wrappedImpl: RpcServiceImpl = {};\r\n for (const methodDef of def.methods.values()) {\r\n const fn = impl[methodDef.name];\r\n if (!fn) continue;\r\n wrappedImpl[methodDef.name] =\r\n methodDef.callTypeId !== 0\r\n ? this._wrapServerMethod(methodDef, fn, impl as object)\r\n : fn;\r\n }\r\n this.serviceHost.register(def, wrappedImpl);\r\n this.registry.registerService(def.name, def.methods);\r\n }\r\n\r\n /** Create a typed client proxy for a service on a remote peer. */\r\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T is used for caller-specified proxy type\r\n addClient<T extends object>(\r\n peer: RpcPeer,\r\n defOrContract: RpcServiceDef | (AnyConstructor)\r\n ): T {\r\n const def = this._resolveServiceDef(defOrContract);\r\n this.registry.registerService(def.name, def.methods);\r\n\r\n type RpcClientFn = (...args: unknown[]) => unknown;\r\n\r\n // Group methods by clean name, indexed by argCount for overload resolution\r\n const overloads = new Map<string, Map<number, RpcClientFn>>();\r\n for (const methodDef of def.methods.values()) {\r\n let byArgCount = overloads.get(methodDef.name);\r\n if (!byArgCount) {\r\n byArgCount = new Map<number, RpcClientFn>();\r\n overloads.set(methodDef.name, byArgCount);\r\n }\r\n byArgCount.set(\r\n methodDef.argCount,\r\n this._createClientMethod(peer, methodDef)\r\n );\r\n }\r\n\r\n // Build final proxy methods — single overload: use directly; multiple: resolve by args.length\r\n const methods = new Map<string, RpcClientFn>();\r\n for (const [name, byArgCount] of overloads) {\r\n if (byArgCount.size === 1) {\r\n const [[, singleFn]] = byArgCount;\r\n methods.set(name, singleFn);\r\n } else {\r\n methods.set(name, (...args: unknown[]) => {\r\n const fn = byArgCount.get(args.length);\r\n if (!fn)\r\n throw new Error(\r\n `No overload of ${name} accepts ${args.length} arguments`\r\n );\r\n return fn(...args);\r\n });\r\n }\r\n }\r\n\r\n return new Proxy({} as T, {\r\n get: (_target, prop) =>\r\n typeof prop === 'string' ? methods.get(prop) : undefined,\r\n });\r\n }\r\n\r\n close(): void {\r\n for (const peer of this.peers.values()) peer.close();\r\n this.peers.clear();\r\n }\r\n\r\n /** Build an RpcServiceDef from decorator metadata on a contract class. Override in FusionHub for compute support. */\r\n protected _buildServiceDef(\r\n cls: AnyConstructor\r\n ): RpcServiceDef {\r\n const svcMeta = getServiceMeta(cls);\r\n if (svcMeta === undefined)\r\n throw new Error('Contract class missing @rpcService metadata');\r\n\r\n const methodsMeta = getMethodsMeta(cls) ?? {};\r\n const methods = new Map<string, RpcMethodDef>();\r\n\r\n for (const [name, meta] of Object.entries(methodsMeta)) {\r\n const wireArgCount = meta.argCount + 1;\r\n const mapKey = `${name}:${wireArgCount}`;\r\n const isNoWait = meta.returns === RpcType.noWait;\r\n methods.set(mapKey, {\r\n name,\r\n serviceName: svcMeta.name,\r\n argCount: meta.argCount,\r\n wireArgCount,\r\n callTypeId: 0,\r\n stream: meta.returns === RpcType.stream,\r\n noWait: isNoWait,\r\n remoteExecutionMode: isNoWait\r\n ? 0\r\n : (meta.remoteExecutionMode ?? RpcRemoteExecutionMode.Default),\r\n });\r\n }\r\n\r\n return { name: svcMeta.name, methods };\r\n }\r\n\r\n /** Resolve a service def from either a plain RpcServiceDef or a contract class. */\r\n protected _resolveServiceDef(\r\n defOrContract: RpcServiceDef | (AnyConstructor)\r\n ): RpcServiceDef {\r\n if (typeof defOrContract === 'function')\r\n return this._buildServiceDef(defOrContract);\r\n return defOrContract;\r\n }\r\n\r\n /** Override in FusionHub — default is pass-through (for methods with callTypeId !== 0). */\r\n protected _wrapServerMethod(\r\n _methodDef: RpcMethodDef,\r\n fn: (...args: unknown[]) => unknown,\r\n _impl: object\r\n ): (...args: unknown[]) => unknown {\r\n return fn;\r\n }\r\n\r\n /** Create a client method for the given methodDef. Override in FusionHub for custom call types. */\r\n protected _createClientMethod(\r\n peer: RpcPeer,\r\n methodDef: RpcMethodDef\r\n ): (...args: unknown[]) => unknown {\r\n const wireName = wireMethodName(methodDef);\r\n const mode = methodDef.remoteExecutionMode;\r\n const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);\r\n\r\n // NoWait methods — remoteExecutionMode is always 0, silently drop if disconnected\r\n if (methodDef.noWait) {\r\n return (...args: unknown[]) => {\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n peer.callNoWait(wireName, callArgs);\r\n };\r\n }\r\n\r\n // Stream methods — call returns an RpcStream<T> (AsyncIterable)\r\n if (methodDef.stream) {\r\n return async (...args: unknown[]) => {\r\n if (mustCheckConnection && !peer.isConnected)\r\n throw new Error('Outbound call failed: not connected and AwaitForConnection is not set.');\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const outboundCall = peer.call(wireName, callArgs);\r\n const result = await outboundCall.result.promise;\r\n const ref = parseStreamRef(result);\r\n if (!ref)\r\n throw new Error(\r\n `Expected stream reference, got: ${JSON.stringify(result)}`\r\n );\r\n const stream = new RpcStream(ref, peer);\r\n peer.remoteObjects.register(stream);\r\n return stream;\r\n };\r\n }\r\n\r\n // Regular methods (including non-zero callTypeId — subclass can override for custom behavior)\r\n const callOptions: RpcCallOptions | undefined =\r\n (methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default)\r\n ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode }\r\n : undefined;\r\n\r\n return async (...args: unknown[]) => {\r\n if (mustCheckConnection && !peer.isConnected)\r\n throw new Error('Outbound call failed: not connected and AwaitForConnection is not set.');\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const outboundCall = peer.call(wireName, callArgs, callOptions);\r\n const result = await outboundCall.result.promise;\r\n return resolveStreamRefs(result, peer);\r\n };\r\n }\r\n}\r\n","// .NET counterpart:\r\n// RpcClient — a DI-registered service used by generated interceptor proxies.\r\n// The proxy classes (generated by Interceptor/ProxyGenerator) intercept method\r\n// calls on the service interface, create an RpcOutboundContext, resolve the\r\n// target peer via OutboundCallRouter, and invoke the outbound call pipeline.\r\n//\r\n// Omitted from .NET:\r\n// - Interceptor-based proxy generation — .NET generates proxy classes at startup\r\n// (via Castle DynamicProxy / source generators) that implement the service\r\n// interface. TS uses a runtime Proxy object instead, which achieves the same\r\n// result without code generation.\r\n// - RpcOutboundContext — .NET creates a rich context per call with CancellationToken,\r\n// Headers, CacheInfoCapture, Trace, RoutingMode. TS passes arguments directly.\r\n// - OutboundCallRouter — .NET routes each call to the appropriate peer based on\r\n// sharding/load-balancing rules. TS passes the peer explicitly.\r\n// - This standalone function is superseded by RpcHub.addClient() which adds\r\n// noWait and compute-aware dispatch. Kept for backward compatibility.\r\n\r\nimport type { RpcPeer } from './rpc-peer.js';\r\nimport type { RpcServiceDef, RpcMethodDef } from './rpc-service-def.js';\r\nimport { wireMethodName, RpcRemoteExecutionMode } from './rpc-service-def.js';\r\n\r\ntype RpcClientFn = (...args: unknown[]) => unknown;\r\n\r\n/** Creates a typed RPC client proxy — intercepts method calls and sends them over RPC. */\r\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters -- T is used for caller-specified proxy type\r\nexport function createRpcClient<T extends object>(\r\n peer: RpcPeer,\r\n serviceDef: RpcServiceDef\r\n): T {\r\n // Group methods by clean name, indexed by argCount for overload resolution\r\n const overloads = new Map<string, Map<number, RpcMethodDef>>();\r\n for (const methodDef of serviceDef.methods.values()) {\r\n let byArgCount = overloads.get(methodDef.name);\r\n if (!byArgCount) {\r\n byArgCount = new Map<number, RpcMethodDef>();\r\n overloads.set(methodDef.name, byArgCount);\r\n }\r\n byArgCount.set(methodDef.argCount, methodDef);\r\n }\r\n\r\n // Build proxy methods\r\n const methods = new Map<string, RpcClientFn>();\r\n for (const [name, byArgCount] of overloads) {\r\n if (byArgCount.size === 1) {\r\n const [[, methodDef]] = byArgCount;\r\n methods.set(name, createMethod(peer, methodDef));\r\n } else {\r\n const fns = new Map<number, RpcClientFn>();\r\n for (const [argCount, methodDef] of byArgCount) {\r\n fns.set(argCount, createMethod(peer, methodDef));\r\n }\r\n methods.set(name, (...args: unknown[]) => {\r\n const fn = fns.get(args.length);\r\n if (!fn)\r\n throw new Error(\r\n `No overload of ${name} accepts ${args.length} arguments`\r\n );\r\n return fn(...args);\r\n });\r\n }\r\n }\r\n\r\n return new Proxy({} as T, {\r\n get(_target, prop) {\r\n if (typeof prop !== 'string') return undefined;\r\n return methods.get(prop);\r\n },\r\n });\r\n}\r\n\r\nfunction createMethod(peer: RpcPeer, methodDef: RpcMethodDef): RpcClientFn {\r\n const mode = methodDef.remoteExecutionMode;\r\n const mustCheckConnection = !(mode & RpcRemoteExecutionMode.AwaitForConnection);\r\n return async (...args: unknown[]) => {\r\n if (mustCheckConnection && !peer.isConnected)\r\n throw new Error('Outbound call failed: not connected and AwaitForConnection is not set.');\r\n const callArgs = args.slice(0, methodDef.argCount);\r\n const wireName = wireMethodName(methodDef);\r\n const options =\r\n (methodDef.callTypeId !== 0 || mode !== RpcRemoteExecutionMode.Default)\r\n ? { callTypeId: methodDef.callTypeId, remoteExecutionMode: mode }\r\n : undefined;\r\n const outboundCall = peer.call(wireName, callArgs, options);\r\n return outboundCall.result.promise;\r\n };\r\n}\r\n","// .NET counterpart: ActualLab.Fusion.Extensions.RpcPeerState\r\n\r\nexport const enum RpcPeerStateKind {\r\n Connected = 0,\r\n JustDisconnected = 1,\r\n Disconnected = 2,\r\n JustConnected = 3,\r\n}\r\n\r\nexport interface RpcPeerState {\r\n readonly kind: RpcPeerStateKind;\r\n readonly lastError?: Error;\r\n readonly reconnectsIn: number; // ms, 0 = no countdown\r\n}\r\n\r\nexport function isConnected(state: RpcPeerState): boolean {\r\n return (\r\n state.kind === RpcPeerStateKind.Connected ||\r\n state.kind === RpcPeerStateKind.JustConnected\r\n );\r\n}\r\n\r\nexport function likelyConnected(state: RpcPeerState): boolean {\r\n return state.kind !== RpcPeerStateKind.Disconnected;\r\n}\r\n\r\nexport function getStateDescription(\r\n state: RpcPeerState,\r\n useLastError = false\r\n): string {\r\n switch (state.kind) {\r\n case RpcPeerStateKind.JustConnected:\r\n return 'Just connected.';\r\n case RpcPeerStateKind.Connected:\r\n return 'Connected.';\r\n case RpcPeerStateKind.JustDisconnected:\r\n return 'Just disconnected, reconnecting...';\r\n case RpcPeerStateKind.Disconnected:\r\n if (state.reconnectsIn > 0) break; // fall through to error message below\r\n return 'Reconnecting...';\r\n }\r\n if (state.lastError == null || !useLastError) return 'Disconnected.';\r\n\r\n let message = state.lastError.message.trim();\r\n if (\r\n !(\r\n message.endsWith('.') ||\r\n message.endsWith('!') ||\r\n message.endsWith('?')\r\n )\r\n )\r\n message += '.';\r\n return 'Disconnected: ' + message;\r\n}\r\n","// .NET counterpart: ActualLab.Fusion.Extensions.RpcPeerStateMonitor\r\n// Simplified TS version using EventHandlerSet + setTimeout (no Fusion computed state).\r\n\r\nimport { EventHandlerSet } from '@actuallab/core';\r\nimport type { RpcClientPeer } from './rpc-peer.js';\r\nimport { type RpcPeerState, RpcPeerStateKind } from './rpc-peer-state.js';\r\n\r\nconst JustConnectedPeriodMs = 1500;\r\nconst JustDisconnectedPeriodMs = 3000;\r\nconst MinReconnectsInMs = 1000;\r\n\r\nexport class RpcPeerStateMonitor {\r\n readonly peer: RpcClientPeer;\r\n readonly stateChanged = new EventHandlerSet<RpcPeerState>();\r\n\r\n private _rawConnected: boolean;\r\n private _connectedAt = 0;\r\n private _disconnectedAt = 0;\r\n private _lastError: Error | undefined;\r\n private _state: RpcPeerState;\r\n private _timer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n // Arrow functions to preserve `this` when used as event handlers\r\n private _onConnected = (): void => {\r\n this._rawConnected = true;\r\n this._connectedAt = Date.now();\r\n this._lastError = undefined;\r\n this._recompute();\r\n };\r\n\r\n private _onDisconnected = (ev: { code: number; reason: string }): void => {\r\n const wasConnected = this._rawConnected;\r\n this._rawConnected = false;\r\n this._lastError = new Error(\r\n `Connection closed: ${ev.reason} (code ${ev.code})`\r\n );\r\n if (wasConnected) {\r\n // True connected→disconnected transition — start JustDisconnected period\r\n this._disconnectedAt = Date.now();\r\n }\r\n // When wasConnected=false, this is a failed reconnect attempt —\r\n // keep the original _disconnectedAt so the countdown isn't reset.\r\n this._recompute();\r\n };\r\n\r\n private _onReconnectsAtChanged = (): void => {\r\n this._recompute();\r\n };\r\n\r\n private _onCancelDelaysChanged = (): void => {\r\n this._recompute();\r\n };\r\n\r\n constructor(peer: RpcClientPeer) {\r\n this.peer = peer;\r\n this._rawConnected = peer.isConnected;\r\n\r\n if (this._rawConnected) {\r\n this._connectedAt = Date.now();\r\n this._state = {\r\n kind: RpcPeerStateKind.JustConnected,\r\n reconnectsIn: 0,\r\n };\r\n } else {\r\n this._disconnectedAt = Date.now();\r\n this._state = {\r\n kind: RpcPeerStateKind.JustDisconnected,\r\n reconnectsIn: 0,\r\n };\r\n }\r\n\r\n peer.connected.add(this._onConnected);\r\n peer.disconnected.add(this._onDisconnected);\r\n peer.reconnectsAtChanged.add(this._onReconnectsAtChanged);\r\n peer.reconnectDelayer.cancelDelaysChanged.add(\r\n this._onCancelDelaysChanged\r\n );\r\n\r\n // Schedule initial transition from Just* states\r\n this._scheduleRecompute(\r\n this._rawConnected\r\n ? JustConnectedPeriodMs\r\n : JustDisconnectedPeriodMs\r\n );\r\n }\r\n\r\n get state(): RpcPeerState {\r\n return this._state;\r\n }\r\n\r\n dispose(): void {\r\n if (this._timer !== undefined) {\r\n clearTimeout(this._timer);\r\n this._timer = undefined;\r\n }\r\n this.peer.connected.remove(this._onConnected);\r\n this.peer.disconnected.remove(this._onDisconnected);\r\n this.peer.reconnectsAtChanged.remove(this._onReconnectsAtChanged);\r\n this.peer.reconnectDelayer.cancelDelaysChanged.remove(\r\n this._onCancelDelaysChanged\r\n );\r\n }\r\n\r\n private _recompute(): void {\r\n if (this._timer !== undefined) {\r\n clearTimeout(this._timer);\r\n this._timer = undefined;\r\n }\r\n\r\n const now = Date.now();\r\n let newState: RpcPeerState;\r\n\r\n if (this._rawConnected) {\r\n const connectedFor = now - this._connectedAt;\r\n if (connectedFor < JustConnectedPeriodMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.JustConnected,\r\n reconnectsIn: 0,\r\n };\r\n this._scheduleRecompute(JustConnectedPeriodMs - connectedFor);\r\n } else {\r\n newState = {\r\n kind: RpcPeerStateKind.Connected,\r\n reconnectsIn: 0,\r\n };\r\n }\r\n } else {\r\n const disconnectedFor = now - this._disconnectedAt;\r\n if (disconnectedFor < JustDisconnectedPeriodMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.JustDisconnected,\r\n lastError: this._lastError,\r\n reconnectsIn: 0,\r\n };\r\n this._scheduleRecompute(\r\n JustDisconnectedPeriodMs - disconnectedFor\r\n );\r\n } else {\r\n const reconnectsAt = this.peer.reconnectsAt;\r\n const reconnectsIn =\r\n reconnectsAt > 0 ? Math.max(0, reconnectsAt - now) : 0;\r\n if (reconnectsIn < MinReconnectsInMs) {\r\n newState = {\r\n kind: RpcPeerStateKind.Disconnected,\r\n lastError: this._lastError,\r\n reconnectsIn: 0,\r\n };\r\n } else {\r\n newState = {\r\n kind: RpcPeerStateKind.Disconnected,\r\n lastError: this._lastError,\r\n reconnectsIn,\r\n };\r\n // Recompute periodically to update countdown\r\n this._scheduleRecompute(\r\n Math.min(1000, reconnectsIn - MinReconnectsInMs)\r\n );\r\n }\r\n }\r\n }\r\n\r\n this._setState(newState);\r\n }\r\n\r\n private _setState(newState: RpcPeerState): void {\r\n const old = this._state;\r\n if (\r\n old.kind === newState.kind &&\r\n old.lastError === newState.lastError &&\r\n old.reconnectsIn === newState.reconnectsIn\r\n )\r\n return;\r\n\r\n this._state = newState;\r\n this.stateChanged.trigger(newState);\r\n }\r\n\r\n private _scheduleRecompute(delayMs: number): void {\r\n if (this._timer !== undefined) clearTimeout(this._timer);\r\n this._timer = setTimeout(\r\n () => {\r\n this._timer = undefined;\r\n this._recompute();\r\n },\r\n Math.max(0, delayMs)\r\n );\r\n }\r\n}\r\n"],"mappings":"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","names":["RpcCallTypeId","Decoder","Decoder","EventHandlerSet","EventHandlerSet","PromiseSource","PromiseSource","PromiseSource","PromiseSource","DEFAULT_ACK_PERIOD","DEFAULT_ACK_ADVANCE","PromiseSource","EventHandlerSet","PromiseSource","Decoder","Decoder","EventHandlerSet","RpcPeerConnectionKind","PromiseSource","textEncoder","RpcPeerStateKind","EventHandlerSet","EventHandlerSet"]}