@naeemo/capnp 0.4.0 → 0.5.2
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/cli.js +2187 -305
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1362 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1311 -25
- package/dist/index.js.map +1 -1
- package/dist/rpc-connection-C3-uEtpd.js +2158 -0
- package/dist/rpc-connection-C3-uEtpd.js.map +1 -0
- package/dist/rpc-connection-CDzawjwJ.js +3 -0
- package/dist/rpc-connection-_eHtWsk2.js +2296 -0
- package/dist/rpc-connection-_eHtWsk2.js.map +1 -0
- package/dist/rpc-connection-jIPnPyT6.js +3 -0
- package/package.json +39 -27
- package/dist/codegen/cli-v3.js +0 -1857
- package/dist/codegen/cli-v3.js.map +0 -1
- package/dist/rpc-connection-BKWQQ7f9.js +0 -960
- package/dist/rpc-connection-BKWQQ7f9.js.map +0 -1
- package/dist/rpc-connection-C2C1wyga.js +0 -3
- package/dist/rpc-connection-Dz3rYT1P.js +0 -870
- package/dist/rpc-connection-Dz3rYT1P.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
const require_rpc_connection = require('./rpc-connection-_eHtWsk2.js');
|
|
30
|
+
let node_net = require("node:net");
|
|
31
|
+
node_net = __toESM(node_net);
|
|
3
32
|
|
|
4
33
|
//#region src/core/pointer.ts
|
|
5
34
|
/**
|
|
@@ -128,6 +157,7 @@ var Segment = class Segment {
|
|
|
128
157
|
*/
|
|
129
158
|
getWord(wordOffset) {
|
|
130
159
|
const byteOffset = wordOffset * WORD_SIZE;
|
|
160
|
+
if (byteOffset + 8 > this._size) throw new Error(`Offset ${wordOffset} is outside the bounds of the segment (${this.wordCount} words)`);
|
|
131
161
|
const low = BigInt(this.view.getUint32(byteOffset, true));
|
|
132
162
|
return BigInt(this.view.getUint32(byteOffset + 4, true)) << BigInt(32) | low;
|
|
133
163
|
}
|
|
@@ -136,6 +166,7 @@ var Segment = class Segment {
|
|
|
136
166
|
*/
|
|
137
167
|
setWord(wordOffset, value) {
|
|
138
168
|
const byteOffset = wordOffset * WORD_SIZE;
|
|
169
|
+
if (byteOffset + 8 > this.buffer.byteLength) throw new Error(`Offset ${wordOffset} is outside the bounds of the segment`);
|
|
139
170
|
this.view.setUint32(byteOffset, Number(value & BigInt(4294967295)), true);
|
|
140
171
|
this.view.setUint32(byteOffset + 4, Number(value >> BigInt(32)), true);
|
|
141
172
|
}
|
|
@@ -637,73 +668,113 @@ var StructReader = class StructReader {
|
|
|
637
668
|
getBool(bitOffset) {
|
|
638
669
|
const byteOffset = Math.floor(bitOffset / 8);
|
|
639
670
|
const bitInByte = bitOffset % 8;
|
|
640
|
-
|
|
671
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
672
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
673
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
674
|
+
if (dataOffset < 0 || dataOffset >= dataSectionEnd) return false;
|
|
675
|
+
return (segment.dataView.getUint8(dataOffset) & 1 << bitInByte) !== 0;
|
|
641
676
|
}
|
|
642
677
|
/**
|
|
643
678
|
* 获取 int8 字段
|
|
644
679
|
*/
|
|
645
680
|
getInt8(byteOffset) {
|
|
646
|
-
|
|
681
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
682
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
683
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
684
|
+
if (dataOffset < 0 || dataOffset >= dataSectionEnd) return 0;
|
|
685
|
+
return segment.dataView.getInt8(dataOffset);
|
|
647
686
|
}
|
|
648
687
|
/**
|
|
649
688
|
* 获取 int16 字段
|
|
650
689
|
*/
|
|
651
690
|
getInt16(byteOffset) {
|
|
652
|
-
|
|
691
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
692
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
693
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
694
|
+
if (dataOffset < 0 || dataOffset + 2 > dataSectionEnd) return 0;
|
|
695
|
+
return segment.dataView.getInt16(dataOffset, true);
|
|
653
696
|
}
|
|
654
697
|
/**
|
|
655
698
|
* 获取 int32 字段
|
|
656
699
|
*/
|
|
657
700
|
getInt32(byteOffset) {
|
|
658
|
-
|
|
701
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
702
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
703
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
704
|
+
if (dataOffset < 0 || dataOffset + 4 > dataSectionEnd) return 0;
|
|
705
|
+
return segment.dataView.getInt32(dataOffset, true);
|
|
659
706
|
}
|
|
660
707
|
/**
|
|
661
708
|
* 获取 int64 字段
|
|
662
709
|
*/
|
|
663
710
|
getInt64(byteOffset) {
|
|
664
711
|
const segment = this.message.getSegment(this.segmentIndex);
|
|
665
|
-
const
|
|
666
|
-
const
|
|
667
|
-
|
|
712
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
713
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
714
|
+
if (dataOffset < 0 || dataOffset + 8 > dataSectionEnd) return BigInt(0);
|
|
715
|
+
const low = BigInt(segment.dataView.getUint32(dataOffset, true));
|
|
716
|
+
return BigInt(segment.dataView.getInt32(dataOffset + 4, true)) << BigInt(32) | low;
|
|
668
717
|
}
|
|
669
718
|
/**
|
|
670
719
|
* 获取 uint8 字段
|
|
671
720
|
*/
|
|
672
721
|
getUint8(byteOffset) {
|
|
673
|
-
|
|
722
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
723
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
724
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
725
|
+
if (dataOffset < 0 || dataOffset >= dataSectionEnd) return 0;
|
|
726
|
+
return segment.dataView.getUint8(dataOffset);
|
|
674
727
|
}
|
|
675
728
|
/**
|
|
676
729
|
* 获取 uint16 字段
|
|
677
730
|
*/
|
|
678
731
|
getUint16(byteOffset) {
|
|
679
|
-
|
|
732
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
733
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
734
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
735
|
+
if (dataOffset < 0 || dataOffset + 2 > dataSectionEnd) return 0;
|
|
736
|
+
return segment.dataView.getUint16(dataOffset, true);
|
|
680
737
|
}
|
|
681
738
|
/**
|
|
682
739
|
* 获取 uint32 字段
|
|
683
740
|
*/
|
|
684
741
|
getUint32(byteOffset) {
|
|
685
|
-
|
|
742
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
743
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
744
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
745
|
+
if (dataOffset < 0 || dataOffset + 4 > dataSectionEnd) return 0;
|
|
746
|
+
return segment.dataView.getUint32(dataOffset, true);
|
|
686
747
|
}
|
|
687
748
|
/**
|
|
688
749
|
* 获取 uint64 字段
|
|
689
750
|
*/
|
|
690
751
|
getUint64(byteOffset) {
|
|
691
752
|
const segment = this.message.getSegment(this.segmentIndex);
|
|
692
|
-
const
|
|
693
|
-
const
|
|
694
|
-
|
|
753
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
754
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
755
|
+
if (dataOffset < 0 || dataOffset + 8 > dataSectionEnd) return BigInt(0);
|
|
756
|
+
const low = BigInt(segment.dataView.getUint32(dataOffset, true));
|
|
757
|
+
return BigInt(segment.dataView.getUint32(dataOffset + 4, true)) << BigInt(32) | low;
|
|
695
758
|
}
|
|
696
759
|
/**
|
|
697
760
|
* 获取 float32 字段
|
|
698
761
|
*/
|
|
699
762
|
getFloat32(byteOffset) {
|
|
700
|
-
|
|
763
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
764
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
765
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
766
|
+
if (dataOffset < 0 || dataOffset + 4 > dataSectionEnd) return 0;
|
|
767
|
+
return segment.dataView.getFloat32(dataOffset, true);
|
|
701
768
|
}
|
|
702
769
|
/**
|
|
703
770
|
* 获取 float64 字段
|
|
704
771
|
*/
|
|
705
772
|
getFloat64(byteOffset) {
|
|
706
|
-
|
|
773
|
+
const segment = this.message.getSegment(this.segmentIndex);
|
|
774
|
+
const dataOffset = this.wordOffset * WORD_SIZE + byteOffset;
|
|
775
|
+
const dataSectionEnd = this.wordOffset * WORD_SIZE + this.dataWords * WORD_SIZE;
|
|
776
|
+
if (dataOffset < 0 || dataOffset + 8 > dataSectionEnd) return 0;
|
|
777
|
+
return segment.dataView.getFloat64(dataOffset, true);
|
|
707
778
|
}
|
|
708
779
|
/**
|
|
709
780
|
* 获取文本字段
|
|
@@ -748,13 +819,18 @@ var StructReader = class StructReader {
|
|
|
748
819
|
let actualStructSize = structSize;
|
|
749
820
|
const segment = this.message.getSegment(segmentIndex);
|
|
750
821
|
if (listPtr.elementSize === ElementSize.COMPOSITE) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
822
|
+
if (targetOffset < 0 || targetOffset >= segment.wordCount) return;
|
|
823
|
+
try {
|
|
824
|
+
const tagWord = segment.getWord(targetOffset);
|
|
825
|
+
elementCount = Number(tagWord & BigInt(4294967295));
|
|
826
|
+
actualStructSize = {
|
|
827
|
+
dataWords: Number(tagWord >> BigInt(32) & BigInt(65535)),
|
|
828
|
+
pointerCount: Number(tagWord >> BigInt(48) & BigInt(65535))
|
|
829
|
+
};
|
|
830
|
+
targetOffset += 1;
|
|
831
|
+
} catch {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
758
834
|
}
|
|
759
835
|
return new ListReader(this.message, segmentIndex, listPtr.elementSize, elementCount, actualStructSize, targetOffset);
|
|
760
836
|
}
|
|
@@ -1694,6 +1770,316 @@ var WebSocketTransport = class WebSocketTransport {
|
|
|
1694
1770
|
}
|
|
1695
1771
|
};
|
|
1696
1772
|
|
|
1773
|
+
//#endregion
|
|
1774
|
+
//#region src/rpc/tcp-transport.ts
|
|
1775
|
+
/**
|
|
1776
|
+
* TCP Transport Implementation for Node.js
|
|
1777
|
+
*
|
|
1778
|
+
* Implements RpcTransport over raw TCP socket for C++ interop testing.
|
|
1779
|
+
* This allows direct communication with the official Cap'n Proto C++ implementation.
|
|
1780
|
+
*/
|
|
1781
|
+
/**
|
|
1782
|
+
* TCP Transport for Cap'n Proto RPC
|
|
1783
|
+
*
|
|
1784
|
+
* Uses length-prefixed binary message framing compatible with Cap'n Proto C++ implementation.
|
|
1785
|
+
* Format: [4 bytes: message length (little-endian)] [N bytes: message data]
|
|
1786
|
+
*/
|
|
1787
|
+
var TcpTransport = class TcpTransport {
|
|
1788
|
+
socket = null;
|
|
1789
|
+
messageQueue = [];
|
|
1790
|
+
receiveQueue = [];
|
|
1791
|
+
_connected = false;
|
|
1792
|
+
pendingBuffer = Buffer.alloc(0);
|
|
1793
|
+
pendingLength = 0;
|
|
1794
|
+
hasPendingLength = false;
|
|
1795
|
+
onClose;
|
|
1796
|
+
onError;
|
|
1797
|
+
constructor(host, port, options = {}) {
|
|
1798
|
+
this.host = host;
|
|
1799
|
+
this.port = port;
|
|
1800
|
+
this.options = options;
|
|
1801
|
+
}
|
|
1802
|
+
static async connect(host, port, options) {
|
|
1803
|
+
const transport = new TcpTransport(host, port, options);
|
|
1804
|
+
await transport.connect();
|
|
1805
|
+
return transport;
|
|
1806
|
+
}
|
|
1807
|
+
static fromSocket(socket, options) {
|
|
1808
|
+
const transport = new TcpTransport("", 0, options);
|
|
1809
|
+
transport.attachSocket(socket);
|
|
1810
|
+
return transport;
|
|
1811
|
+
}
|
|
1812
|
+
get connected() {
|
|
1813
|
+
return this._connected && this.socket?.readyState === "open";
|
|
1814
|
+
}
|
|
1815
|
+
connect() {
|
|
1816
|
+
return new Promise((resolve, reject) => {
|
|
1817
|
+
const timeout = setTimeout(() => {
|
|
1818
|
+
this.socket?.destroy();
|
|
1819
|
+
reject(/* @__PURE__ */ new Error("Connection timeout"));
|
|
1820
|
+
}, this.options.connectTimeoutMs ?? 1e4);
|
|
1821
|
+
this.socket = new node_net.Socket();
|
|
1822
|
+
this.socket.on("connect", () => {
|
|
1823
|
+
clearTimeout(timeout);
|
|
1824
|
+
this._connected = true;
|
|
1825
|
+
resolve();
|
|
1826
|
+
});
|
|
1827
|
+
this.socket.on("data", (data) => {
|
|
1828
|
+
this.handleData(data);
|
|
1829
|
+
});
|
|
1830
|
+
this.socket.on("close", (hadError) => {
|
|
1831
|
+
this._connected = false;
|
|
1832
|
+
this.flushReceiveQueue(null);
|
|
1833
|
+
if (hadError) this.onClose?.(/* @__PURE__ */ new Error("Connection closed with error"));
|
|
1834
|
+
else this.onClose?.();
|
|
1835
|
+
});
|
|
1836
|
+
this.socket.on("error", (err) => {
|
|
1837
|
+
clearTimeout(timeout);
|
|
1838
|
+
this._connected = false;
|
|
1839
|
+
this.onError?.(err);
|
|
1840
|
+
reject(err);
|
|
1841
|
+
});
|
|
1842
|
+
this.socket.on("end", () => {
|
|
1843
|
+
this._connected = false;
|
|
1844
|
+
});
|
|
1845
|
+
this.socket.connect(this.port, this.host);
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
attachSocket(socket) {
|
|
1849
|
+
this.socket = socket;
|
|
1850
|
+
this._connected = socket.readyState === "open";
|
|
1851
|
+
socket.on("data", (data) => {
|
|
1852
|
+
this.handleData(data);
|
|
1853
|
+
});
|
|
1854
|
+
socket.on("close", (hadError) => {
|
|
1855
|
+
this._connected = false;
|
|
1856
|
+
this.flushReceiveQueue(null);
|
|
1857
|
+
if (hadError) this.onClose?.(/* @__PURE__ */ new Error("Connection closed with error"));
|
|
1858
|
+
else this.onClose?.();
|
|
1859
|
+
});
|
|
1860
|
+
socket.on("error", (err) => {
|
|
1861
|
+
this._connected = false;
|
|
1862
|
+
this.onError?.(err);
|
|
1863
|
+
});
|
|
1864
|
+
socket.on("end", () => {
|
|
1865
|
+
this._connected = false;
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
handleData(data) {
|
|
1869
|
+
this.pendingBuffer = Buffer.concat([this.pendingBuffer, data]);
|
|
1870
|
+
while (this.pendingBuffer.length >= 4) {
|
|
1871
|
+
if (!this.hasPendingLength) {
|
|
1872
|
+
this.pendingLength = this.pendingBuffer.readUInt32LE(0);
|
|
1873
|
+
this.hasPendingLength = true;
|
|
1874
|
+
if (this.pendingLength > 64 * 1024 * 1024) {
|
|
1875
|
+
this.onError?.(/* @__PURE__ */ new Error(`Message too large: ${this.pendingLength} bytes`));
|
|
1876
|
+
this.close(/* @__PURE__ */ new Error("Message too large"));
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const totalLength = 4 + this.pendingLength;
|
|
1881
|
+
if (this.pendingBuffer.length < totalLength) break;
|
|
1882
|
+
const messageData = this.pendingBuffer.subarray(4, totalLength);
|
|
1883
|
+
this.pendingBuffer = this.pendingBuffer.subarray(totalLength);
|
|
1884
|
+
this.hasPendingLength = false;
|
|
1885
|
+
try {
|
|
1886
|
+
const message = deserializeRpcMessage(new Uint8Array(messageData));
|
|
1887
|
+
this.handleRpcMessage(message);
|
|
1888
|
+
} catch (err) {
|
|
1889
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
handleRpcMessage(message) {
|
|
1894
|
+
if (this.receiveQueue.length > 0) {
|
|
1895
|
+
const { resolve } = this.receiveQueue.shift();
|
|
1896
|
+
resolve(message);
|
|
1897
|
+
} else this.messageQueue.push(message);
|
|
1898
|
+
}
|
|
1899
|
+
async send(message) {
|
|
1900
|
+
if (!this.socket || this.socket.readyState !== "open") throw new Error("Socket not connected");
|
|
1901
|
+
const data = serializeRpcMessage(message);
|
|
1902
|
+
const frame = Buffer.allocUnsafe(4 + data.length);
|
|
1903
|
+
frame.writeUInt32LE(data.length, 0);
|
|
1904
|
+
frame.set(data, 4);
|
|
1905
|
+
return new Promise((resolve, reject) => {
|
|
1906
|
+
this.socket.write(frame, (err) => {
|
|
1907
|
+
if (err) reject(err);
|
|
1908
|
+
else resolve();
|
|
1909
|
+
});
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
async receive() {
|
|
1913
|
+
if (this.messageQueue.length > 0) return this.messageQueue.shift();
|
|
1914
|
+
if (!this._connected) return null;
|
|
1915
|
+
return new Promise((resolve, reject) => {
|
|
1916
|
+
this.receiveQueue.push({
|
|
1917
|
+
resolve,
|
|
1918
|
+
reject
|
|
1919
|
+
});
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
close(reason) {
|
|
1923
|
+
this._connected = false;
|
|
1924
|
+
this.socket?.end();
|
|
1925
|
+
this.socket?.destroy();
|
|
1926
|
+
this.flushReceiveQueue(null);
|
|
1927
|
+
this.onClose?.(reason);
|
|
1928
|
+
}
|
|
1929
|
+
flushReceiveQueue(value) {
|
|
1930
|
+
while (this.receiveQueue.length > 0) {
|
|
1931
|
+
const { resolve } = this.receiveQueue.shift();
|
|
1932
|
+
resolve(value);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1937
|
+
//#endregion
|
|
1938
|
+
//#region src/rpc/ezrpc-transport.ts
|
|
1939
|
+
/**
|
|
1940
|
+
* EzRpc TCP Transport
|
|
1941
|
+
*
|
|
1942
|
+
* Implements RpcTransport over raw TCP socket for C++ EzRpc compatibility.
|
|
1943
|
+
* Does NOT use length-prefixed framing - sends raw Cap'n Proto messages.
|
|
1944
|
+
*/
|
|
1945
|
+
/**
|
|
1946
|
+
* EzRpc TCP Transport
|
|
1947
|
+
*
|
|
1948
|
+
* Compatible with Cap'n Proto C++ EzRpcServer/EzRpcClient.
|
|
1949
|
+
* Sends raw Cap'n Proto messages without length prefix.
|
|
1950
|
+
*/
|
|
1951
|
+
var EzRpcTransport = class EzRpcTransport {
|
|
1952
|
+
socket = null;
|
|
1953
|
+
messageQueue = [];
|
|
1954
|
+
receiveQueue = [];
|
|
1955
|
+
_connected = false;
|
|
1956
|
+
pendingBuffer = Buffer.alloc(0);
|
|
1957
|
+
onClose;
|
|
1958
|
+
onError;
|
|
1959
|
+
constructor(host, port, options = {}) {
|
|
1960
|
+
this.host = host;
|
|
1961
|
+
this.port = port;
|
|
1962
|
+
this.options = options;
|
|
1963
|
+
}
|
|
1964
|
+
static async connect(host, port, options) {
|
|
1965
|
+
const transport = new EzRpcTransport(host, port, options);
|
|
1966
|
+
await transport.doConnect();
|
|
1967
|
+
return transport;
|
|
1968
|
+
}
|
|
1969
|
+
get connected() {
|
|
1970
|
+
return this._connected && this.socket !== null && !this.socket.destroyed;
|
|
1971
|
+
}
|
|
1972
|
+
doConnect() {
|
|
1973
|
+
return new Promise((resolve, reject) => {
|
|
1974
|
+
const timeout = setTimeout(() => {
|
|
1975
|
+
this.socket?.destroy();
|
|
1976
|
+
reject(/* @__PURE__ */ new Error(`Connection timeout: failed to connect to ${this.host}:${this.port}`));
|
|
1977
|
+
}, this.options.connectTimeoutMs ?? 1e4);
|
|
1978
|
+
this.socket = new node_net.Socket();
|
|
1979
|
+
this.socket.on("connect", () => {
|
|
1980
|
+
clearTimeout(timeout);
|
|
1981
|
+
this._connected = true;
|
|
1982
|
+
resolve();
|
|
1983
|
+
});
|
|
1984
|
+
this.socket.on("data", (data) => {
|
|
1985
|
+
try {
|
|
1986
|
+
this.handleData(data);
|
|
1987
|
+
} catch (err) {
|
|
1988
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
this.socket.on("close", (hadError) => {
|
|
1992
|
+
const wasConnected = this._connected;
|
|
1993
|
+
this._connected = false;
|
|
1994
|
+
const error = hadError ? /* @__PURE__ */ new Error("Connection closed with error") : /* @__PURE__ */ new Error("Connection closed");
|
|
1995
|
+
this.flushReceiveQueueWithError(error);
|
|
1996
|
+
if (wasConnected) this.onClose?.(hadError ? error : void 0);
|
|
1997
|
+
});
|
|
1998
|
+
this.socket.on("error", (err) => {
|
|
1999
|
+
clearTimeout(timeout);
|
|
2000
|
+
this._connected = false;
|
|
2001
|
+
this.flushReceiveQueueWithError(err);
|
|
2002
|
+
this.onError?.(err);
|
|
2003
|
+
reject(err);
|
|
2004
|
+
});
|
|
2005
|
+
this.socket.connect(this.port, this.host);
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
handleData(data) {
|
|
2009
|
+
if (this.pendingBuffer.length > 0) this.pendingBuffer = Buffer.concat([this.pendingBuffer, data]);
|
|
2010
|
+
else this.pendingBuffer = Buffer.from(data);
|
|
2011
|
+
while (this.pendingBuffer.length >= 8) {
|
|
2012
|
+
const segmentCount = this.pendingBuffer.readUInt32LE(0) + 1;
|
|
2013
|
+
const firstSegmentSize = this.pendingBuffer.readUInt32LE(4);
|
|
2014
|
+
let headerSize = 8;
|
|
2015
|
+
if (segmentCount > 1) headerSize += (segmentCount - 1) * 4;
|
|
2016
|
+
const messageSize = headerSize + firstSegmentSize * 8;
|
|
2017
|
+
if (this.pendingBuffer.length < messageSize) break;
|
|
2018
|
+
const messageData = this.pendingBuffer.subarray(0, messageSize);
|
|
2019
|
+
this.pendingBuffer = this.pendingBuffer.subarray(messageSize);
|
|
2020
|
+
try {
|
|
2021
|
+
const message = deserializeRpcMessage(new Uint8Array(messageData));
|
|
2022
|
+
if (this.receiveQueue.length > 0) {
|
|
2023
|
+
const { resolve } = this.receiveQueue.shift();
|
|
2024
|
+
resolve(message);
|
|
2025
|
+
} else this.messageQueue.push(message);
|
|
2026
|
+
} catch (err) {
|
|
2027
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
async send(message) {
|
|
2032
|
+
if (!this.connected) throw new Error(`Cannot send: socket not connected to ${this.host}:${this.port}`);
|
|
2033
|
+
const data = serializeRpcMessage(message);
|
|
2034
|
+
return new Promise((resolve, reject) => {
|
|
2035
|
+
this.socket.write(Buffer.from(data), (err) => {
|
|
2036
|
+
if (err) reject(/* @__PURE__ */ new Error(`Failed to send message: ${err.message}`));
|
|
2037
|
+
else resolve();
|
|
2038
|
+
});
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
async receive() {
|
|
2042
|
+
if (this.messageQueue.length > 0) return this.messageQueue.shift();
|
|
2043
|
+
if (!this.connected) return null;
|
|
2044
|
+
return new Promise((resolve, reject) => {
|
|
2045
|
+
const timeoutId = setTimeout(() => {
|
|
2046
|
+
const index = this.receiveQueue.findIndex((item) => item.resolve === resolve);
|
|
2047
|
+
if (index !== -1) this.receiveQueue.splice(index, 1);
|
|
2048
|
+
reject(/* @__PURE__ */ new Error("Receive timeout"));
|
|
2049
|
+
}, 3e4);
|
|
2050
|
+
this.receiveQueue.push({
|
|
2051
|
+
resolve: (msg) => {
|
|
2052
|
+
clearTimeout(timeoutId);
|
|
2053
|
+
resolve(msg);
|
|
2054
|
+
},
|
|
2055
|
+
reject: (err) => {
|
|
2056
|
+
clearTimeout(timeoutId);
|
|
2057
|
+
reject(err);
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
});
|
|
2061
|
+
}
|
|
2062
|
+
close(reason) {
|
|
2063
|
+
this._connected = false;
|
|
2064
|
+
this.socket?.end();
|
|
2065
|
+
this.socket?.destroy();
|
|
2066
|
+
this.flushReceiveQueue(null);
|
|
2067
|
+
this.onClose?.(reason);
|
|
2068
|
+
}
|
|
2069
|
+
flushReceiveQueueWithError(error) {
|
|
2070
|
+
while (this.receiveQueue.length > 0) {
|
|
2071
|
+
const { reject } = this.receiveQueue.shift();
|
|
2072
|
+
reject(error);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
flushReceiveQueue(value) {
|
|
2076
|
+
while (this.receiveQueue.length > 0) {
|
|
2077
|
+
const { resolve } = this.receiveQueue.shift();
|
|
2078
|
+
resolve(value);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
|
|
1697
2083
|
//#endregion
|
|
1698
2084
|
//#region src/rpc/capability-client.ts
|
|
1699
2085
|
/** Base class for capability client implementations */
|
|
@@ -2306,7 +2692,7 @@ var ConnectionManager = class {
|
|
|
2306
2692
|
}
|
|
2307
2693
|
}
|
|
2308
2694
|
async doEstablishConnection(vatId, address) {
|
|
2309
|
-
const { RpcConnection } = await Promise.resolve().then(() => require("./rpc-connection-
|
|
2695
|
+
const { RpcConnection } = await Promise.resolve().then(() => require("./rpc-connection-CDzawjwJ.js"));
|
|
2310
2696
|
const connection = new RpcConnection(await this.options.connectionFactory(vatId, address), this.options.connectionOptions);
|
|
2311
2697
|
await connection.start();
|
|
2312
2698
|
this.registerConnection(vatId, connection);
|
|
@@ -4901,6 +5287,934 @@ function supportsStreaming(connection) {
|
|
|
4901
5287
|
return connection instanceof StreamingRpcConnection;
|
|
4902
5288
|
}
|
|
4903
5289
|
|
|
5290
|
+
//#endregion
|
|
5291
|
+
//#region src/rpc/dynamic-reader.ts
|
|
5292
|
+
/**
|
|
5293
|
+
* Create a dynamic reader from schema and buffer
|
|
5294
|
+
*
|
|
5295
|
+
* @param schema - The schema node describing the struct type
|
|
5296
|
+
* @param buffer - The Cap'n Proto message buffer
|
|
5297
|
+
* @returns A DynamicReader for accessing the message fields
|
|
5298
|
+
*/
|
|
5299
|
+
function createDynamicReader(schema, buffer) {
|
|
5300
|
+
const messageReader = new MessageReader(buffer);
|
|
5301
|
+
if (!schema.structInfo) throw new Error(`Schema node ${schema.displayName} is not a struct`);
|
|
5302
|
+
const { dataWordCount, pointerCount } = schema.structInfo;
|
|
5303
|
+
return new DynamicReaderImpl(schema, messageReader.getRoot(dataWordCount, pointerCount), messageReader);
|
|
5304
|
+
}
|
|
5305
|
+
/**
|
|
5306
|
+
* Create a dynamic reader from an existing StructReader
|
|
5307
|
+
*
|
|
5308
|
+
* @param schema - The schema node describing the struct type
|
|
5309
|
+
* @param structReader - The StructReader to wrap
|
|
5310
|
+
* @param messageReader - The underlying MessageReader
|
|
5311
|
+
* @returns A DynamicReader for accessing the message fields
|
|
5312
|
+
*/
|
|
5313
|
+
function createDynamicReaderFromStruct(schema, structReader, messageReader) {
|
|
5314
|
+
return new DynamicReaderImpl(schema, structReader, messageReader);
|
|
5315
|
+
}
|
|
5316
|
+
/**
|
|
5317
|
+
* Implementation of DynamicReader
|
|
5318
|
+
*/
|
|
5319
|
+
var DynamicReaderImpl = class {
|
|
5320
|
+
fieldCache;
|
|
5321
|
+
pointerOffset;
|
|
5322
|
+
constructor(schema, structReader, messageReader) {
|
|
5323
|
+
this.schema = schema;
|
|
5324
|
+
this.structReader = structReader;
|
|
5325
|
+
this.messageReader = messageReader;
|
|
5326
|
+
this.fieldCache = /* @__PURE__ */ new Map();
|
|
5327
|
+
this.pointerOffset = schema.structInfo?.dataWordCount ?? 0;
|
|
5328
|
+
if (schema.structInfo?.fields) for (const field of schema.structInfo.fields) this.fieldCache.set(field.name, field);
|
|
5329
|
+
}
|
|
5330
|
+
get(fieldName) {
|
|
5331
|
+
const field = this.fieldCache.get(fieldName);
|
|
5332
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5333
|
+
return this.readFieldValue(field);
|
|
5334
|
+
}
|
|
5335
|
+
has(fieldName) {
|
|
5336
|
+
return this.fieldCache.has(fieldName);
|
|
5337
|
+
}
|
|
5338
|
+
getFieldNames() {
|
|
5339
|
+
return Array.from(this.fieldCache.keys());
|
|
5340
|
+
}
|
|
5341
|
+
getSchema() {
|
|
5342
|
+
return this.schema;
|
|
5343
|
+
}
|
|
5344
|
+
getStruct(fieldName) {
|
|
5345
|
+
const field = this.fieldCache.get(fieldName);
|
|
5346
|
+
if (!field) return;
|
|
5347
|
+
if (field.type.kind.type !== "struct") return;
|
|
5348
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5349
|
+
const nestedStruct = this.structReader.getStruct(pointerIndex, 0, 0);
|
|
5350
|
+
if (!nestedStruct) return;
|
|
5351
|
+
return new DynamicStructReaderWithoutSchema(nestedStruct, this.messageReader);
|
|
5352
|
+
}
|
|
5353
|
+
getList(fieldName) {
|
|
5354
|
+
const field = this.fieldCache.get(fieldName);
|
|
5355
|
+
if (!field) return;
|
|
5356
|
+
if (field.type.kind.type !== "list") return;
|
|
5357
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5358
|
+
const elementType = field.type.kind.elementType;
|
|
5359
|
+
return this.readListField(pointerIndex, elementType);
|
|
5360
|
+
}
|
|
5361
|
+
getRawReader() {
|
|
5362
|
+
return this.structReader;
|
|
5363
|
+
}
|
|
5364
|
+
/**
|
|
5365
|
+
* Read a field value based on its type
|
|
5366
|
+
*/
|
|
5367
|
+
readFieldValue(field) {
|
|
5368
|
+
const kind = field.type.kind;
|
|
5369
|
+
switch (kind.type) {
|
|
5370
|
+
case "void": return;
|
|
5371
|
+
case "bool": return this.structReader.getBool(field.offset);
|
|
5372
|
+
case "int8": return this.structReader.getInt8(field.offset);
|
|
5373
|
+
case "int16": return this.structReader.getInt16(field.offset);
|
|
5374
|
+
case "int32": return this.structReader.getInt32(field.offset);
|
|
5375
|
+
case "int64": return this.structReader.getInt64(field.offset);
|
|
5376
|
+
case "uint8": return this.structReader.getUint8(field.offset);
|
|
5377
|
+
case "uint16": return this.structReader.getUint16(field.offset);
|
|
5378
|
+
case "uint32": return this.structReader.getUint32(field.offset);
|
|
5379
|
+
case "uint64": return this.structReader.getUint64(field.offset);
|
|
5380
|
+
case "float32": return this.structReader.getFloat32(field.offset);
|
|
5381
|
+
case "float64": return this.structReader.getFloat64(field.offset);
|
|
5382
|
+
case "text": return this.readTextField(field);
|
|
5383
|
+
case "data": return this.readDataField(field);
|
|
5384
|
+
case "list": return this.readListFieldBySchema(field);
|
|
5385
|
+
case "enum": return this.readEnumField(field);
|
|
5386
|
+
case "struct": return this.readStructField(field);
|
|
5387
|
+
case "interface": return this.readInterfaceField(field);
|
|
5388
|
+
case "anyPointer": return this.readAnyPointerField(field);
|
|
5389
|
+
default: throw new Error(`Unsupported field type: ${kind.type}`);
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
/**
|
|
5393
|
+
* Get the pointer index for a field
|
|
5394
|
+
* In Cap'n Proto, pointer fields have offsets that start from 0 for the first pointer
|
|
5395
|
+
* The offset is measured in bits from the start of the data section
|
|
5396
|
+
* For pointer fields, offset = dataWordCount * 64 + pointerIndex * 64
|
|
5397
|
+
* So pointerIndex = (offset - dataWordCount * 64) / 64
|
|
5398
|
+
*/
|
|
5399
|
+
getPointerIndex(field) {
|
|
5400
|
+
const dataSectionBits = (this.schema.structInfo?.dataWordCount ?? 0) * 64;
|
|
5401
|
+
return (field.offset - dataSectionBits) / 64;
|
|
5402
|
+
}
|
|
5403
|
+
/**
|
|
5404
|
+
* Read a text field
|
|
5405
|
+
*/
|
|
5406
|
+
readTextField(field) {
|
|
5407
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5408
|
+
return this.structReader.getText(pointerIndex);
|
|
5409
|
+
}
|
|
5410
|
+
/**
|
|
5411
|
+
* Read a data field
|
|
5412
|
+
*/
|
|
5413
|
+
readDataField(field) {
|
|
5414
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5415
|
+
const text = this.structReader.getText(pointerIndex);
|
|
5416
|
+
return new TextEncoder().encode(text);
|
|
5417
|
+
}
|
|
5418
|
+
/**
|
|
5419
|
+
* Read a list field using schema information
|
|
5420
|
+
*/
|
|
5421
|
+
readListFieldBySchema(field) {
|
|
5422
|
+
if (field.type.kind.type !== "list") throw new Error(`Field '${field.name}' is not a list type`);
|
|
5423
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5424
|
+
const elementType = field.type.kind.elementType;
|
|
5425
|
+
return this.readListField(pointerIndex, elementType);
|
|
5426
|
+
}
|
|
5427
|
+
/**
|
|
5428
|
+
* Read a list field
|
|
5429
|
+
*/
|
|
5430
|
+
readListField(pointerIndex, elementType) {
|
|
5431
|
+
const elementSize = this.mapTypeToElementSize(elementType);
|
|
5432
|
+
const listReader = this.structReader.getList(pointerIndex, elementSize);
|
|
5433
|
+
if (!listReader) return [];
|
|
5434
|
+
const result = [];
|
|
5435
|
+
const length = listReader.length;
|
|
5436
|
+
for (let i = 0; i < length; i++) result.push(this.readListElement(listReader, i, elementType));
|
|
5437
|
+
return result;
|
|
5438
|
+
}
|
|
5439
|
+
/**
|
|
5440
|
+
* Map schema type to ElementSize
|
|
5441
|
+
*/
|
|
5442
|
+
mapTypeToElementSize(type) {
|
|
5443
|
+
switch (type.kind.type) {
|
|
5444
|
+
case "void": return ElementSize.VOID;
|
|
5445
|
+
case "bool": return ElementSize.BIT;
|
|
5446
|
+
case "int8":
|
|
5447
|
+
case "uint8": return ElementSize.BYTE;
|
|
5448
|
+
case "int16":
|
|
5449
|
+
case "uint16": return ElementSize.TWO_BYTES;
|
|
5450
|
+
case "int32":
|
|
5451
|
+
case "uint32":
|
|
5452
|
+
case "float32": return ElementSize.FOUR_BYTES;
|
|
5453
|
+
case "int64":
|
|
5454
|
+
case "uint64":
|
|
5455
|
+
case "float64": return ElementSize.EIGHT_BYTES;
|
|
5456
|
+
case "struct": return ElementSize.COMPOSITE;
|
|
5457
|
+
default: return ElementSize.POINTER;
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
/**
|
|
5461
|
+
* Read a single list element
|
|
5462
|
+
*/
|
|
5463
|
+
readListElement(listReader, index, elementType) {
|
|
5464
|
+
switch (elementType.kind.type) {
|
|
5465
|
+
case "void": return;
|
|
5466
|
+
case "bool": return listReader.getPrimitive(index) !== 0;
|
|
5467
|
+
case "int8": return listReader.getPrimitive(index);
|
|
5468
|
+
case "int16": return listReader.getPrimitive(index);
|
|
5469
|
+
case "int32": return listReader.getPrimitive(index);
|
|
5470
|
+
case "int64": return listReader.getPrimitive(index);
|
|
5471
|
+
case "uint8": return listReader.getPrimitive(index);
|
|
5472
|
+
case "uint16": return listReader.getPrimitive(index);
|
|
5473
|
+
case "uint32": return listReader.getPrimitive(index);
|
|
5474
|
+
case "uint64": return listReader.getPrimitive(index);
|
|
5475
|
+
case "float32": return listReader.getPrimitive(index);
|
|
5476
|
+
case "float64": return listReader.getPrimitive(index);
|
|
5477
|
+
case "struct": {
|
|
5478
|
+
const structReader = listReader.getStruct(index);
|
|
5479
|
+
if (!structReader) return void 0;
|
|
5480
|
+
return new DynamicStructReaderWithoutSchema(structReader, this.messageReader);
|
|
5481
|
+
}
|
|
5482
|
+
default: return;
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
/**
|
|
5486
|
+
* Read an enum field
|
|
5487
|
+
*/
|
|
5488
|
+
readEnumField(field) {
|
|
5489
|
+
return this.structReader.getUint16(field.offset);
|
|
5490
|
+
}
|
|
5491
|
+
/**
|
|
5492
|
+
* Read a struct field
|
|
5493
|
+
*/
|
|
5494
|
+
readStructField(field) {
|
|
5495
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5496
|
+
const nestedStruct = this.structReader.getStruct(pointerIndex, 0, 0);
|
|
5497
|
+
if (!nestedStruct) return;
|
|
5498
|
+
return new DynamicStructReaderWithoutSchema(nestedStruct, this.messageReader);
|
|
5499
|
+
}
|
|
5500
|
+
/**
|
|
5501
|
+
* Read an interface field (capability)
|
|
5502
|
+
*/
|
|
5503
|
+
readInterfaceField(_field) {
|
|
5504
|
+
throw new Error("Interface fields not yet supported in dynamic reader");
|
|
5505
|
+
}
|
|
5506
|
+
/**
|
|
5507
|
+
* Read an anyPointer field
|
|
5508
|
+
*/
|
|
5509
|
+
readAnyPointerField(_field) {
|
|
5510
|
+
throw new Error("anyPointer fields not yet supported in dynamic reader");
|
|
5511
|
+
}
|
|
5512
|
+
};
|
|
5513
|
+
/**
|
|
5514
|
+
* A limited dynamic reader for structs without schema information
|
|
5515
|
+
* Provides basic field access but no type information
|
|
5516
|
+
*/
|
|
5517
|
+
var DynamicStructReaderWithoutSchema = class {
|
|
5518
|
+
constructor(structReader, messageReader) {
|
|
5519
|
+
this.structReader = structReader;
|
|
5520
|
+
this.messageReader = messageReader;
|
|
5521
|
+
}
|
|
5522
|
+
get(_fieldName) {
|
|
5523
|
+
throw new Error("Cannot access fields without schema information");
|
|
5524
|
+
}
|
|
5525
|
+
has(_fieldName) {
|
|
5526
|
+
return false;
|
|
5527
|
+
}
|
|
5528
|
+
getFieldNames() {
|
|
5529
|
+
return [];
|
|
5530
|
+
}
|
|
5531
|
+
getSchema() {
|
|
5532
|
+
throw new Error("No schema information available");
|
|
5533
|
+
}
|
|
5534
|
+
getStruct(_fieldName) {}
|
|
5535
|
+
getList(_fieldName) {}
|
|
5536
|
+
getRawReader() {
|
|
5537
|
+
return this.structReader;
|
|
5538
|
+
}
|
|
5539
|
+
};
|
|
5540
|
+
/**
|
|
5541
|
+
* Create a dynamic reader for a specific type ID
|
|
5542
|
+
* This looks up the schema in a registry and creates the appropriate reader
|
|
5543
|
+
*
|
|
5544
|
+
* @param typeId - The type ID of the struct
|
|
5545
|
+
* @param buffer - The Cap'n Proto message buffer
|
|
5546
|
+
* @param schemaRegistry - A map of type IDs to schema nodes
|
|
5547
|
+
* @returns A DynamicReader for the message
|
|
5548
|
+
*/
|
|
5549
|
+
function createDynamicReaderByTypeId(typeId, buffer, schemaRegistry) {
|
|
5550
|
+
const schema = schemaRegistry.get(typeId);
|
|
5551
|
+
if (!schema) throw new Error(`Schema not found for type ID: ${typeId}`);
|
|
5552
|
+
if (schema.type !== require_rpc_connection.SchemaNodeType.STRUCT) throw new Error(`Type ${typeId} is not a struct`);
|
|
5553
|
+
return createDynamicReader(schema, buffer);
|
|
5554
|
+
}
|
|
5555
|
+
/**
|
|
5556
|
+
* Utility function to dump all fields from a dynamic reader
|
|
5557
|
+
* Useful for debugging and exploration
|
|
5558
|
+
*
|
|
5559
|
+
* @param reader - The DynamicReader to dump
|
|
5560
|
+
* @returns An object with all field names and values
|
|
5561
|
+
*/
|
|
5562
|
+
function dumpDynamicReader(reader) {
|
|
5563
|
+
const result = {};
|
|
5564
|
+
for (const fieldName of reader.getFieldNames()) try {
|
|
5565
|
+
result[fieldName] = reader.get(fieldName);
|
|
5566
|
+
} catch (error) {
|
|
5567
|
+
result[fieldName] = `<error: ${error}>`;
|
|
5568
|
+
}
|
|
5569
|
+
return result;
|
|
5570
|
+
}
|
|
5571
|
+
|
|
5572
|
+
//#endregion
|
|
5573
|
+
//#region src/rpc/dynamic-writer.ts
|
|
5574
|
+
/**
|
|
5575
|
+
* Create a dynamic writer from schema
|
|
5576
|
+
*
|
|
5577
|
+
* @param schema - The schema node describing the struct type
|
|
5578
|
+
* @returns A DynamicWriter for setting message fields
|
|
5579
|
+
*/
|
|
5580
|
+
function createDynamicWriter(schema) {
|
|
5581
|
+
if (!schema.structInfo) throw new Error(`Schema node ${schema.displayName} is not a struct`);
|
|
5582
|
+
const { dataWordCount, pointerCount } = schema.structInfo;
|
|
5583
|
+
const messageBuilder = new MessageBuilder();
|
|
5584
|
+
return new DynamicWriterImpl(schema, messageBuilder.initRoot(dataWordCount, pointerCount), messageBuilder);
|
|
5585
|
+
}
|
|
5586
|
+
/**
|
|
5587
|
+
* Create a dynamic writer for a nested struct
|
|
5588
|
+
*
|
|
5589
|
+
* @param schema - The schema node describing the struct type
|
|
5590
|
+
* @param structBuilder - The StructBuilder to wrap
|
|
5591
|
+
* @param messageBuilder - The underlying MessageBuilder
|
|
5592
|
+
* @returns A DynamicWriter for setting message fields
|
|
5593
|
+
*/
|
|
5594
|
+
function createNestedDynamicWriter(schema, structBuilder, messageBuilder) {
|
|
5595
|
+
return new DynamicWriterImpl(schema, structBuilder, messageBuilder);
|
|
5596
|
+
}
|
|
5597
|
+
/**
|
|
5598
|
+
* Implementation of DynamicWriter
|
|
5599
|
+
*/
|
|
5600
|
+
var DynamicWriterImpl = class {
|
|
5601
|
+
fieldCache;
|
|
5602
|
+
pointerOffset;
|
|
5603
|
+
constructor(schema, structBuilder, messageBuilder) {
|
|
5604
|
+
this.schema = schema;
|
|
5605
|
+
this.structBuilder = structBuilder;
|
|
5606
|
+
this.messageBuilder = messageBuilder;
|
|
5607
|
+
this.fieldCache = /* @__PURE__ */ new Map();
|
|
5608
|
+
this.pointerOffset = schema.structInfo?.dataWordCount ?? 0;
|
|
5609
|
+
if (schema.structInfo?.fields) for (const field of schema.structInfo.fields) this.fieldCache.set(field.name, field);
|
|
5610
|
+
}
|
|
5611
|
+
set(fieldName, value) {
|
|
5612
|
+
const field = this.fieldCache.get(fieldName);
|
|
5613
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5614
|
+
this.writeFieldValue(field, value);
|
|
5615
|
+
}
|
|
5616
|
+
setFields(fields) {
|
|
5617
|
+
for (const [name, value] of Object.entries(fields)) this.set(name, value);
|
|
5618
|
+
}
|
|
5619
|
+
initStruct(fieldName) {
|
|
5620
|
+
const field = this.fieldCache.get(fieldName);
|
|
5621
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5622
|
+
if (field.type.kind.type !== "struct") throw new Error(`Field '${fieldName}' is not a struct type`);
|
|
5623
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5624
|
+
return new DynamicWriterWithoutSchema(this.structBuilder.initStruct(pointerIndex, 0, 0), this.messageBuilder);
|
|
5625
|
+
}
|
|
5626
|
+
initList(fieldName, size) {
|
|
5627
|
+
const field = this.fieldCache.get(fieldName);
|
|
5628
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5629
|
+
if (field.type.kind.type !== "list") throw new Error(`Field '${fieldName}' is not a list type`);
|
|
5630
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5631
|
+
const elementType = field.type.kind.elementType;
|
|
5632
|
+
return this.createListWriter(pointerIndex, size, elementType);
|
|
5633
|
+
}
|
|
5634
|
+
setText(fieldName, value) {
|
|
5635
|
+
const field = this.fieldCache.get(fieldName);
|
|
5636
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5637
|
+
if (field.type.kind.type !== "text") throw new Error(`Field '${fieldName}' is not a text type`);
|
|
5638
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5639
|
+
this.structBuilder.setText(pointerIndex, value);
|
|
5640
|
+
}
|
|
5641
|
+
setData(fieldName, value) {
|
|
5642
|
+
const field = this.fieldCache.get(fieldName);
|
|
5643
|
+
if (!field) throw new Error(`Field '${fieldName}' not found in schema ${this.schema.displayName}`);
|
|
5644
|
+
if (field.type.kind.type !== "data") throw new Error(`Field '${fieldName}' is not a data type`);
|
|
5645
|
+
const pointerIndex = this.getPointerIndex(field);
|
|
5646
|
+
const textValue = new TextDecoder().decode(value);
|
|
5647
|
+
this.structBuilder.setText(pointerIndex, `${textValue}\0`);
|
|
5648
|
+
}
|
|
5649
|
+
getSchema() {
|
|
5650
|
+
return this.schema;
|
|
5651
|
+
}
|
|
5652
|
+
getRawBuilder() {
|
|
5653
|
+
return this.structBuilder;
|
|
5654
|
+
}
|
|
5655
|
+
toBuffer() {
|
|
5656
|
+
return this.messageBuilder.toArrayBuffer();
|
|
5657
|
+
}
|
|
5658
|
+
/**
|
|
5659
|
+
* Write a field value based on its type
|
|
5660
|
+
*/
|
|
5661
|
+
writeFieldValue(field, value) {
|
|
5662
|
+
const kind = field.type.kind;
|
|
5663
|
+
switch (kind.type) {
|
|
5664
|
+
case "void": break;
|
|
5665
|
+
case "bool":
|
|
5666
|
+
this.structBuilder.setBool(field.offset, Boolean(value));
|
|
5667
|
+
break;
|
|
5668
|
+
case "int8":
|
|
5669
|
+
this.structBuilder.setInt8(field.offset, Number(value));
|
|
5670
|
+
break;
|
|
5671
|
+
case "int16":
|
|
5672
|
+
this.structBuilder.setInt16(field.offset, Number(value));
|
|
5673
|
+
break;
|
|
5674
|
+
case "int32":
|
|
5675
|
+
this.structBuilder.setInt32(field.offset, Number(value));
|
|
5676
|
+
break;
|
|
5677
|
+
case "int64":
|
|
5678
|
+
this.structBuilder.setInt64(field.offset, BigInt(value));
|
|
5679
|
+
break;
|
|
5680
|
+
case "uint8":
|
|
5681
|
+
this.structBuilder.setUint8(field.offset, Number(value));
|
|
5682
|
+
break;
|
|
5683
|
+
case "uint16":
|
|
5684
|
+
this.structBuilder.setUint16(field.offset, Number(value));
|
|
5685
|
+
break;
|
|
5686
|
+
case "uint32":
|
|
5687
|
+
this.structBuilder.setUint32(field.offset, Number(value));
|
|
5688
|
+
break;
|
|
5689
|
+
case "uint64":
|
|
5690
|
+
this.structBuilder.setUint64(field.offset, BigInt(value));
|
|
5691
|
+
break;
|
|
5692
|
+
case "float32":
|
|
5693
|
+
this.structBuilder.setFloat32(field.offset, Number(value));
|
|
5694
|
+
break;
|
|
5695
|
+
case "float64":
|
|
5696
|
+
this.structBuilder.setFloat64(field.offset, Number(value));
|
|
5697
|
+
break;
|
|
5698
|
+
case "text":
|
|
5699
|
+
this.setText(field.name, String(value));
|
|
5700
|
+
break;
|
|
5701
|
+
case "data":
|
|
5702
|
+
if (value instanceof Uint8Array) this.setData(field.name, value);
|
|
5703
|
+
else throw new Error(`Field '${field.name}' expects Uint8Array`);
|
|
5704
|
+
break;
|
|
5705
|
+
case "list":
|
|
5706
|
+
if (Array.isArray(value)) this.initList(field.name, value.length).setAll(value);
|
|
5707
|
+
else throw new Error(`Field '${field.name}' expects an array`);
|
|
5708
|
+
break;
|
|
5709
|
+
case "enum":
|
|
5710
|
+
this.structBuilder.setUint16(field.offset, Number(value));
|
|
5711
|
+
break;
|
|
5712
|
+
case "struct":
|
|
5713
|
+
if (typeof value === "object" && value !== null) {
|
|
5714
|
+
const structWriter = this.initStruct(field.name);
|
|
5715
|
+
if (!(value instanceof Uint8Array) && !Array.isArray(value)) structWriter.setFields(value);
|
|
5716
|
+
} else throw new Error(`Field '${field.name}' expects an object`);
|
|
5717
|
+
break;
|
|
5718
|
+
case "interface": throw new Error("Interface fields not yet supported in dynamic writer");
|
|
5719
|
+
case "anyPointer": throw new Error("anyPointer fields not yet supported in dynamic writer");
|
|
5720
|
+
default: throw new Error(`Unsupported field type: ${kind.type}`);
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
/**
|
|
5724
|
+
* Get the pointer index for a field
|
|
5725
|
+
* In Cap'n Proto, pointer fields have offsets that start from 0 for the first pointer
|
|
5726
|
+
* The offset is measured in bits from the start of the data section
|
|
5727
|
+
* For pointer fields, offset = dataWordCount * 64 + pointerIndex * 64
|
|
5728
|
+
* So pointerIndex = (offset - dataWordCount * 64) / 64
|
|
5729
|
+
*/
|
|
5730
|
+
getPointerIndex(field) {
|
|
5731
|
+
const dataSectionBits = (this.schema.structInfo?.dataWordCount ?? 0) * 64;
|
|
5732
|
+
return (field.offset - dataSectionBits) / 64;
|
|
5733
|
+
}
|
|
5734
|
+
/**
|
|
5735
|
+
* Create a list writer for a field
|
|
5736
|
+
*/
|
|
5737
|
+
createListWriter(pointerIndex, size, elementType) {
|
|
5738
|
+
const elementSize = this.mapTypeToElementSize(elementType);
|
|
5739
|
+
let structSize;
|
|
5740
|
+
if (elementSize === ElementSize.COMPOSITE) structSize = {
|
|
5741
|
+
dataWords: 0,
|
|
5742
|
+
pointerCount: 0
|
|
5743
|
+
};
|
|
5744
|
+
return new DynamicListWriterImpl(this.structBuilder.initList(pointerIndex, elementSize, size, structSize), elementType, this.messageBuilder);
|
|
5745
|
+
}
|
|
5746
|
+
/**
|
|
5747
|
+
* Map schema type to ElementSize
|
|
5748
|
+
*/
|
|
5749
|
+
mapTypeToElementSize(type) {
|
|
5750
|
+
switch (type.kind.type) {
|
|
5751
|
+
case "void": return ElementSize.VOID;
|
|
5752
|
+
case "bool": return ElementSize.BIT;
|
|
5753
|
+
case "int8":
|
|
5754
|
+
case "uint8": return ElementSize.BYTE;
|
|
5755
|
+
case "int16":
|
|
5756
|
+
case "uint16": return ElementSize.TWO_BYTES;
|
|
5757
|
+
case "int32":
|
|
5758
|
+
case "uint32":
|
|
5759
|
+
case "float32": return ElementSize.FOUR_BYTES;
|
|
5760
|
+
case "int64":
|
|
5761
|
+
case "uint64":
|
|
5762
|
+
case "float64": return ElementSize.EIGHT_BYTES;
|
|
5763
|
+
case "struct": return ElementSize.COMPOSITE;
|
|
5764
|
+
default: return ElementSize.POINTER;
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
};
|
|
5768
|
+
/**
|
|
5769
|
+
* Implementation of DynamicListWriter
|
|
5770
|
+
*/
|
|
5771
|
+
var DynamicListWriterImpl = class {
|
|
5772
|
+
constructor(listBuilder, elementType, messageBuilder) {
|
|
5773
|
+
this.listBuilder = listBuilder;
|
|
5774
|
+
this.elementType = elementType;
|
|
5775
|
+
this.messageBuilder = messageBuilder;
|
|
5776
|
+
}
|
|
5777
|
+
set(index, value) {
|
|
5778
|
+
if (index < 0 || index >= this.listBuilder.length) throw new Error(`Index ${index} out of bounds`);
|
|
5779
|
+
const kind = this.elementType.kind;
|
|
5780
|
+
switch (kind.type) {
|
|
5781
|
+
case "void": break;
|
|
5782
|
+
case "bool":
|
|
5783
|
+
this.listBuilder.setPrimitive(index, value ? 1 : 0);
|
|
5784
|
+
break;
|
|
5785
|
+
case "int8":
|
|
5786
|
+
case "uint8":
|
|
5787
|
+
case "int16":
|
|
5788
|
+
case "uint16":
|
|
5789
|
+
case "int32":
|
|
5790
|
+
case "uint32":
|
|
5791
|
+
case "float32":
|
|
5792
|
+
this.listBuilder.setPrimitive(index, Number(value));
|
|
5793
|
+
break;
|
|
5794
|
+
case "int64":
|
|
5795
|
+
case "uint64":
|
|
5796
|
+
case "float64":
|
|
5797
|
+
this.listBuilder.setPrimitive(index, BigInt(value));
|
|
5798
|
+
break;
|
|
5799
|
+
case "struct":
|
|
5800
|
+
if (typeof value === "object" && value !== null && !(value instanceof Uint8Array)) this.initStruct(index).setFields(value);
|
|
5801
|
+
break;
|
|
5802
|
+
default: throw new Error(`Unsupported list element type: ${kind.type}`);
|
|
5803
|
+
}
|
|
5804
|
+
}
|
|
5805
|
+
getSize() {
|
|
5806
|
+
return this.listBuilder.length;
|
|
5807
|
+
}
|
|
5808
|
+
getLength() {
|
|
5809
|
+
return this.listBuilder.length;
|
|
5810
|
+
}
|
|
5811
|
+
initStruct(index) {
|
|
5812
|
+
return new DynamicWriterWithoutSchema(this.listBuilder.getStruct(index), this.messageBuilder);
|
|
5813
|
+
}
|
|
5814
|
+
setAll(values) {
|
|
5815
|
+
if (values.length > this.getSize()) throw new Error(`Cannot set ${values.length} values in list of size ${this.getSize()}`);
|
|
5816
|
+
for (let i = 0; i < values.length; i++) this.set(i, values[i]);
|
|
5817
|
+
}
|
|
5818
|
+
};
|
|
5819
|
+
/**
|
|
5820
|
+
* A limited dynamic writer for structs without full schema information
|
|
5821
|
+
* Provides basic field setting but no type validation
|
|
5822
|
+
*/
|
|
5823
|
+
var DynamicWriterWithoutSchema = class {
|
|
5824
|
+
constructor(structBuilder, messageBuilder) {
|
|
5825
|
+
this.structBuilder = structBuilder;
|
|
5826
|
+
this.messageBuilder = messageBuilder;
|
|
5827
|
+
}
|
|
5828
|
+
set(fieldName, _value) {
|
|
5829
|
+
throw new Error(`Cannot set field '${fieldName}' without schema information`);
|
|
5830
|
+
}
|
|
5831
|
+
setFields(_fields) {
|
|
5832
|
+
throw new Error("Cannot set fields without schema information");
|
|
5833
|
+
}
|
|
5834
|
+
initStruct(_fieldName) {
|
|
5835
|
+
throw new Error("Cannot init struct without schema information");
|
|
5836
|
+
}
|
|
5837
|
+
initList(_fieldName, _size) {
|
|
5838
|
+
throw new Error("Cannot init list without schema information");
|
|
5839
|
+
}
|
|
5840
|
+
setText(_fieldName, _value) {
|
|
5841
|
+
throw new Error("Cannot set text without schema information");
|
|
5842
|
+
}
|
|
5843
|
+
setData(_fieldName, _value) {
|
|
5844
|
+
throw new Error("Cannot set data without schema information");
|
|
5845
|
+
}
|
|
5846
|
+
getSchema() {
|
|
5847
|
+
throw new Error("No schema information available");
|
|
5848
|
+
}
|
|
5849
|
+
getRawBuilder() {
|
|
5850
|
+
return this.structBuilder;
|
|
5851
|
+
}
|
|
5852
|
+
toBuffer() {
|
|
5853
|
+
return this.messageBuilder.toArrayBuffer();
|
|
5854
|
+
}
|
|
5855
|
+
};
|
|
5856
|
+
/**
|
|
5857
|
+
* Create a dynamic writer for a specific type ID
|
|
5858
|
+
* This looks up the schema in a registry and creates the appropriate writer
|
|
5859
|
+
*
|
|
5860
|
+
* @param typeId - The type ID of the struct
|
|
5861
|
+
* @param schemaRegistry - A map of type IDs to schema nodes
|
|
5862
|
+
* @returns A DynamicWriter for the message
|
|
5863
|
+
*/
|
|
5864
|
+
function createDynamicWriterByTypeId(typeId, schemaRegistry) {
|
|
5865
|
+
const schema = schemaRegistry.get(typeId);
|
|
5866
|
+
if (!schema) throw new Error(`Schema not found for type ID: ${typeId}`);
|
|
5867
|
+
if (schema.type !== require_rpc_connection.SchemaNodeType.STRUCT) throw new Error(`Type ${typeId} is not a struct`);
|
|
5868
|
+
return createDynamicWriter(schema);
|
|
5869
|
+
}
|
|
5870
|
+
/**
|
|
5871
|
+
* Utility function to create a message from a plain object
|
|
5872
|
+
* Uses schema information to properly serialize the data
|
|
5873
|
+
*
|
|
5874
|
+
* @param schema - The schema node describing the struct type
|
|
5875
|
+
* @param data - The data object to serialize
|
|
5876
|
+
* @returns The serialized message buffer
|
|
5877
|
+
*/
|
|
5878
|
+
function serializeDynamic(schema, data) {
|
|
5879
|
+
const writer = createDynamicWriter(schema);
|
|
5880
|
+
writer.setFields(data);
|
|
5881
|
+
return writer.toBuffer();
|
|
5882
|
+
}
|
|
5883
|
+
/**
|
|
5884
|
+
* Utility function to create a message from a plain object using type ID
|
|
5885
|
+
*
|
|
5886
|
+
* @param typeId - The type ID of the struct
|
|
5887
|
+
* @param data - The data object to serialize
|
|
5888
|
+
* @param schemaRegistry - A map of type IDs to schema nodes
|
|
5889
|
+
* @returns The serialized message buffer
|
|
5890
|
+
*/
|
|
5891
|
+
function serializeDynamicByTypeId(typeId, data, schemaRegistry) {
|
|
5892
|
+
const writer = createDynamicWriterByTypeId(typeId, schemaRegistry);
|
|
5893
|
+
writer.setFields(data);
|
|
5894
|
+
return writer.toBuffer();
|
|
5895
|
+
}
|
|
5896
|
+
|
|
5897
|
+
//#endregion
|
|
5898
|
+
//#region src/rpc/schema-capability.ts
|
|
5899
|
+
/**
|
|
5900
|
+
* Server-side implementation of the SchemaCapability interface.
|
|
5901
|
+
* Provides schema information to remote clients.
|
|
5902
|
+
*/
|
|
5903
|
+
var SchemaCapabilityServer = class {
|
|
5904
|
+
registry;
|
|
5905
|
+
schemasByName;
|
|
5906
|
+
/**
|
|
5907
|
+
* Create a new SchemaCapabilityServer
|
|
5908
|
+
* @param initialSchemas - Optional map of schemas to register initially
|
|
5909
|
+
*/
|
|
5910
|
+
constructor(initialSchemas) {
|
|
5911
|
+
this.registry = new Map(initialSchemas);
|
|
5912
|
+
this.schemasByName = /* @__PURE__ */ new Map();
|
|
5913
|
+
for (const schema of this.registry.values()) this.schemasByName.set(schema.displayName, schema);
|
|
5914
|
+
}
|
|
5915
|
+
/**
|
|
5916
|
+
* Register a schema node
|
|
5917
|
+
* @param node - The schema node to register
|
|
5918
|
+
*/
|
|
5919
|
+
registerSchema(node) {
|
|
5920
|
+
this.registry.set(node.id, node);
|
|
5921
|
+
this.schemasByName.set(node.displayName, node);
|
|
5922
|
+
}
|
|
5923
|
+
/**
|
|
5924
|
+
* Unregister a schema by ID
|
|
5925
|
+
* @param typeId - The type ID to unregister
|
|
5926
|
+
*/
|
|
5927
|
+
unregisterSchema(typeId) {
|
|
5928
|
+
const node = this.registry.get(typeId);
|
|
5929
|
+
if (node) {
|
|
5930
|
+
this.registry.delete(typeId);
|
|
5931
|
+
this.schemasByName.delete(node.displayName);
|
|
5932
|
+
}
|
|
5933
|
+
}
|
|
5934
|
+
/**
|
|
5935
|
+
* Get schema information based on target specification
|
|
5936
|
+
* @param params - GetSchemaParams containing target and format
|
|
5937
|
+
* @returns GetSchemaResults with the schema payload
|
|
5938
|
+
*/
|
|
5939
|
+
async getSchema(params) {
|
|
5940
|
+
const { target, format = require_rpc_connection.SchemaFormat.BINARY } = params;
|
|
5941
|
+
let schemaData;
|
|
5942
|
+
let dependencies = [];
|
|
5943
|
+
switch (target.type) {
|
|
5944
|
+
case "byTypeId": {
|
|
5945
|
+
const node = this.registry.get(target.typeId);
|
|
5946
|
+
if (!node) throw new Error(`Schema not found for type ID: ${target.typeId.toString(16)}`);
|
|
5947
|
+
schemaData = this.serializeSchemaNode(node, format);
|
|
5948
|
+
dependencies = this.collectDependencies(node);
|
|
5949
|
+
break;
|
|
5950
|
+
}
|
|
5951
|
+
case "byTypeName": {
|
|
5952
|
+
const node = this.schemasByName.get(target.typeName);
|
|
5953
|
+
if (!node) throw new Error(`Schema not found for type name: ${target.typeName}`);
|
|
5954
|
+
schemaData = this.serializeSchemaNode(node, format);
|
|
5955
|
+
dependencies = this.collectDependencies(node);
|
|
5956
|
+
break;
|
|
5957
|
+
}
|
|
5958
|
+
case "byFileId": {
|
|
5959
|
+
const nodes = this.getSchemasByFileId(target.fileId);
|
|
5960
|
+
schemaData = this.serializeSchemaNodes(nodes, format);
|
|
5961
|
+
break;
|
|
5962
|
+
}
|
|
5963
|
+
case "byFileName": {
|
|
5964
|
+
const nodes = this.getSchemasByFileName(target.fileName);
|
|
5965
|
+
schemaData = this.serializeSchemaNodes(nodes, format);
|
|
5966
|
+
break;
|
|
5967
|
+
}
|
|
5968
|
+
case "allSchemas": {
|
|
5969
|
+
const nodes = Array.from(this.registry.values());
|
|
5970
|
+
schemaData = this.serializeSchemaNodes(nodes, format);
|
|
5971
|
+
break;
|
|
5972
|
+
}
|
|
5973
|
+
case "bootstrapInterface": {
|
|
5974
|
+
const bootstrapSchema = this.findBootstrapSchema();
|
|
5975
|
+
if (!bootstrapSchema) throw new Error("Bootstrap interface schema not available");
|
|
5976
|
+
schemaData = this.serializeSchemaNode(bootstrapSchema, format);
|
|
5977
|
+
dependencies = this.collectDependencies(bootstrapSchema);
|
|
5978
|
+
break;
|
|
5979
|
+
}
|
|
5980
|
+
default: throw new Error(`Unsupported schema target type: ${target.type}`);
|
|
5981
|
+
}
|
|
5982
|
+
return { payload: {
|
|
5983
|
+
schemaData,
|
|
5984
|
+
format,
|
|
5985
|
+
dependencies
|
|
5986
|
+
} };
|
|
5987
|
+
}
|
|
5988
|
+
/**
|
|
5989
|
+
* List all available schemas
|
|
5990
|
+
* @returns ListSchemasResults with available schema information
|
|
5991
|
+
*/
|
|
5992
|
+
async listAvailableSchemas() {
|
|
5993
|
+
const schemas = [];
|
|
5994
|
+
for (const node of this.registry.values()) schemas.push({
|
|
5995
|
+
typeId: node.id,
|
|
5996
|
+
displayName: node.displayName,
|
|
5997
|
+
fileId: node.scopeId,
|
|
5998
|
+
fileName: this.inferFileName(node),
|
|
5999
|
+
isInterface: node.type === require_rpc_connection.SchemaNodeType.INTERFACE,
|
|
6000
|
+
isStruct: node.type === require_rpc_connection.SchemaNodeType.STRUCT,
|
|
6001
|
+
isEnum: node.type === require_rpc_connection.SchemaNodeType.ENUM
|
|
6002
|
+
});
|
|
6003
|
+
return { schemas };
|
|
6004
|
+
}
|
|
6005
|
+
/**
|
|
6006
|
+
* Handle a raw schema request (for RPC integration)
|
|
6007
|
+
* @param requestData - The serialized SchemaRequest
|
|
6008
|
+
* @returns The serialized SchemaResponse
|
|
6009
|
+
*/
|
|
6010
|
+
handleRequest(requestData) {
|
|
6011
|
+
try {
|
|
6012
|
+
const request = require_rpc_connection.deserializeSchemaRequest(requestData);
|
|
6013
|
+
this.getSchema({ target: request.targetSchema });
|
|
6014
|
+
throw new Error("Async handling not implemented in handleRequest");
|
|
6015
|
+
} catch (error) {
|
|
6016
|
+
return require_rpc_connection.serializeSchemaResponse({
|
|
6017
|
+
answerId: 0,
|
|
6018
|
+
result: {
|
|
6019
|
+
type: "exception",
|
|
6020
|
+
exception: {
|
|
6021
|
+
reason: error instanceof Error ? error.message : "Unknown error",
|
|
6022
|
+
type: "failed",
|
|
6023
|
+
obsoleteIsCallersFault: false,
|
|
6024
|
+
obsoleteDurability: 0
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
});
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
/**
|
|
6031
|
+
* Get the number of registered schemas
|
|
6032
|
+
*/
|
|
6033
|
+
getSchemaCount() {
|
|
6034
|
+
return this.registry.size;
|
|
6035
|
+
}
|
|
6036
|
+
/**
|
|
6037
|
+
* Check if a schema is registered
|
|
6038
|
+
*/
|
|
6039
|
+
hasSchema(typeId) {
|
|
6040
|
+
return this.registry.has(typeId);
|
|
6041
|
+
}
|
|
6042
|
+
serializeSchemaNode(node, format) {
|
|
6043
|
+
switch (format) {
|
|
6044
|
+
case require_rpc_connection.SchemaFormat.BINARY: return this.serializeToBinary([node]);
|
|
6045
|
+
case require_rpc_connection.SchemaFormat.JSON: return this.serializeToJson([node]);
|
|
6046
|
+
case require_rpc_connection.SchemaFormat.CAPNP: return this.serializeToCapnp([node]);
|
|
6047
|
+
default: throw new Error(`Unsupported schema format: ${format}`);
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
serializeSchemaNodes(nodes, format) {
|
|
6051
|
+
switch (format) {
|
|
6052
|
+
case require_rpc_connection.SchemaFormat.BINARY: return this.serializeToBinary(nodes);
|
|
6053
|
+
case require_rpc_connection.SchemaFormat.JSON: return this.serializeToJson(nodes);
|
|
6054
|
+
case require_rpc_connection.SchemaFormat.CAPNP: return this.serializeToCapnp(nodes);
|
|
6055
|
+
default: throw new Error(`Unsupported schema format: ${format}`);
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
serializeToBinary(nodes) {
|
|
6059
|
+
const encoder = new TextEncoder();
|
|
6060
|
+
const json = JSON.stringify(nodes, (_key, value) => {
|
|
6061
|
+
if (typeof value === "bigint") return value.toString();
|
|
6062
|
+
return value;
|
|
6063
|
+
});
|
|
6064
|
+
return encoder.encode(json);
|
|
6065
|
+
}
|
|
6066
|
+
serializeToJson(nodes) {
|
|
6067
|
+
const encoder = new TextEncoder();
|
|
6068
|
+
const json = JSON.stringify({ nodes: nodes.map((node) => ({
|
|
6069
|
+
id: node.id.toString(),
|
|
6070
|
+
displayName: node.displayName,
|
|
6071
|
+
displayNamePrefixLength: node.displayNamePrefixLength,
|
|
6072
|
+
scopeId: node.scopeId.toString(),
|
|
6073
|
+
type: node.type,
|
|
6074
|
+
structInfo: node.structInfo,
|
|
6075
|
+
enumInfo: node.enumInfo,
|
|
6076
|
+
interfaceInfo: node.interfaceInfo
|
|
6077
|
+
})) });
|
|
6078
|
+
return encoder.encode(json);
|
|
6079
|
+
}
|
|
6080
|
+
serializeToCapnp(nodes) {
|
|
6081
|
+
const lines = [];
|
|
6082
|
+
for (const node of nodes) if (node.structInfo) {
|
|
6083
|
+
lines.push(`struct ${node.displayName} {`);
|
|
6084
|
+
for (const field of node.structInfo.fields) lines.push(` ${field.name} @${field.codeOrder} :${this.typeToCapnp(field.type)};`);
|
|
6085
|
+
lines.push("}");
|
|
6086
|
+
}
|
|
6087
|
+
return new TextEncoder().encode(lines.join("\n"));
|
|
6088
|
+
}
|
|
6089
|
+
typeToCapnp(type) {
|
|
6090
|
+
switch (type.kind.type) {
|
|
6091
|
+
case "void": return "Void";
|
|
6092
|
+
case "bool": return "Bool";
|
|
6093
|
+
case "int8": return "Int8";
|
|
6094
|
+
case "int16": return "Int16";
|
|
6095
|
+
case "int32": return "Int32";
|
|
6096
|
+
case "int64": return "Int64";
|
|
6097
|
+
case "uint8": return "UInt8";
|
|
6098
|
+
case "uint16": return "UInt16";
|
|
6099
|
+
case "uint32": return "UInt32";
|
|
6100
|
+
case "uint64": return "UInt64";
|
|
6101
|
+
case "float32": return "Float32";
|
|
6102
|
+
case "float64": return "Float64";
|
|
6103
|
+
case "text": return "Text";
|
|
6104
|
+
case "data": return "Data";
|
|
6105
|
+
case "list": return "List";
|
|
6106
|
+
case "enum": return "UInt16";
|
|
6107
|
+
case "struct": return "AnyPointer";
|
|
6108
|
+
case "interface": return "Capability";
|
|
6109
|
+
default: return "AnyPointer";
|
|
6110
|
+
}
|
|
6111
|
+
}
|
|
6112
|
+
collectDependencies(_node) {
|
|
6113
|
+
return [];
|
|
6114
|
+
}
|
|
6115
|
+
getSchemasByFileId(fileId) {
|
|
6116
|
+
return Array.from(this.registry.values()).filter((node) => node.scopeId === fileId);
|
|
6117
|
+
}
|
|
6118
|
+
getSchemasByFileName(fileName) {
|
|
6119
|
+
return Array.from(this.registry.values()).filter((node) => {
|
|
6120
|
+
return this.inferFileName(node) === fileName || node.displayName.startsWith(fileName);
|
|
6121
|
+
});
|
|
6122
|
+
}
|
|
6123
|
+
inferFileName(node) {
|
|
6124
|
+
const parts = node.displayName.split(".");
|
|
6125
|
+
if (parts.length > 1) return `${parts.slice(0, -1).join("/")}.capnp`;
|
|
6126
|
+
return "unknown.capnp";
|
|
6127
|
+
}
|
|
6128
|
+
findBootstrapSchema() {
|
|
6129
|
+
for (const node of this.registry.values()) if (node.type === require_rpc_connection.SchemaNodeType.INTERFACE) return node;
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
/**
|
|
6133
|
+
* Client-side implementation for accessing remote SchemaCapability
|
|
6134
|
+
*/
|
|
6135
|
+
var SchemaCapabilityClient = class {
|
|
6136
|
+
connection;
|
|
6137
|
+
/**
|
|
6138
|
+
* Create a new SchemaCapabilityClient
|
|
6139
|
+
* @param connection - The RPC connection to use
|
|
6140
|
+
*/
|
|
6141
|
+
constructor(connection) {
|
|
6142
|
+
this.connection = connection;
|
|
6143
|
+
}
|
|
6144
|
+
/**
|
|
6145
|
+
* Fetch schema information from the remote server
|
|
6146
|
+
* @param target - The schema target specification
|
|
6147
|
+
* @param format - The desired format (defaults to BINARY)
|
|
6148
|
+
* @returns The schema node
|
|
6149
|
+
*/
|
|
6150
|
+
async getSchema(target, format = require_rpc_connection.SchemaFormat.BINARY) {
|
|
6151
|
+
if (target.type === "byTypeId") return this.connection.getDynamicSchema(target.typeId);
|
|
6152
|
+
if (target.type === "byTypeName") return this.connection.getDynamicSchemaByName(target.typeName);
|
|
6153
|
+
throw new Error(`Schema target type not implemented: ${target.type}`);
|
|
6154
|
+
}
|
|
6155
|
+
/**
|
|
6156
|
+
* Fetch schema by type ID
|
|
6157
|
+
* @param typeId - The type ID
|
|
6158
|
+
* @returns The schema node
|
|
6159
|
+
*/
|
|
6160
|
+
async getSchemaById(typeId) {
|
|
6161
|
+
return this.connection.getDynamicSchema(typeId);
|
|
6162
|
+
}
|
|
6163
|
+
/**
|
|
6164
|
+
* Fetch schema by type name
|
|
6165
|
+
* @param typeName - The fully qualified type name
|
|
6166
|
+
* @returns The schema node
|
|
6167
|
+
*/
|
|
6168
|
+
async getSchemaByName(typeName) {
|
|
6169
|
+
return this.connection.getDynamicSchemaByName(typeName);
|
|
6170
|
+
}
|
|
6171
|
+
/**
|
|
6172
|
+
* List all available schemas from the remote server
|
|
6173
|
+
* @returns Array of available schema information
|
|
6174
|
+
*/
|
|
6175
|
+
async listAvailableSchemas() {
|
|
6176
|
+
return (await this.connection.listAvailableSchemas()).map((s) => ({
|
|
6177
|
+
typeId: s.typeId,
|
|
6178
|
+
displayName: s.displayName,
|
|
6179
|
+
fileId: BigInt(0),
|
|
6180
|
+
fileName: "",
|
|
6181
|
+
isInterface: false,
|
|
6182
|
+
isStruct: true,
|
|
6183
|
+
isEnum: false
|
|
6184
|
+
}));
|
|
6185
|
+
}
|
|
6186
|
+
/**
|
|
6187
|
+
* Fetch multiple schemas at once
|
|
6188
|
+
* @param typeIds - Array of type IDs to fetch
|
|
6189
|
+
* @returns Map of type ID to schema node
|
|
6190
|
+
*/
|
|
6191
|
+
async getSchemas(typeIds) {
|
|
6192
|
+
const results = /* @__PURE__ */ new Map();
|
|
6193
|
+
await Promise.all(typeIds.map(async (typeId) => {
|
|
6194
|
+
try {
|
|
6195
|
+
const schema = await this.getSchemaById(typeId);
|
|
6196
|
+
results.set(typeId, schema);
|
|
6197
|
+
} catch (error) {
|
|
6198
|
+
console.warn(`Failed to fetch schema ${typeId.toString(16)}:`, error);
|
|
6199
|
+
}
|
|
6200
|
+
}));
|
|
6201
|
+
return results;
|
|
6202
|
+
}
|
|
6203
|
+
/**
|
|
6204
|
+
* Check if a schema is available on the remote server
|
|
6205
|
+
* @param typeId - The type ID to check
|
|
6206
|
+
* @returns True if the schema is available
|
|
6207
|
+
*/
|
|
6208
|
+
async hasSchema(typeId) {
|
|
6209
|
+
try {
|
|
6210
|
+
await this.getSchemaById(typeId);
|
|
6211
|
+
return true;
|
|
6212
|
+
} catch {
|
|
6213
|
+
return false;
|
|
6214
|
+
}
|
|
6215
|
+
}
|
|
6216
|
+
};
|
|
6217
|
+
|
|
4904
6218
|
//#endregion
|
|
4905
6219
|
exports.AnswerTable = require_rpc_connection.AnswerTable;
|
|
4906
6220
|
exports.BaseCapabilityClient = BaseCapabilityClient;
|
|
@@ -4917,6 +6231,7 @@ exports.DEFAULT_STREAMING_CAPABILITIES = DEFAULT_STREAMING_CAPABILITIES;
|
|
|
4917
6231
|
exports.DropPolicy = DropPolicy;
|
|
4918
6232
|
exports.ElementSize = ElementSize;
|
|
4919
6233
|
exports.ExportTable = require_rpc_connection.ExportTable;
|
|
6234
|
+
exports.EzRpcTransport = EzRpcTransport;
|
|
4920
6235
|
exports.ImportTable = require_rpc_connection.ImportTable;
|
|
4921
6236
|
exports.Level3Handlers = Level3Handlers;
|
|
4922
6237
|
exports.Level4Handlers = Level4Handlers;
|
|
@@ -4937,6 +6252,10 @@ exports.RealtimeStream = RealtimeStream;
|
|
|
4937
6252
|
exports.RealtimeStreamManager = RealtimeStreamManager;
|
|
4938
6253
|
exports.RestoreHandler = RestoreHandler;
|
|
4939
6254
|
exports.RpcConnection = require_rpc_connection.RpcConnection;
|
|
6255
|
+
exports.SCHEMA_MESSAGE_TYPES = require_rpc_connection.SCHEMA_MESSAGE_TYPES;
|
|
6256
|
+
exports.SchemaCapabilityClient = SchemaCapabilityClient;
|
|
6257
|
+
exports.SchemaCapabilityServer = SchemaCapabilityServer;
|
|
6258
|
+
exports.SchemaFormat = require_rpc_connection.SchemaFormat;
|
|
4940
6259
|
exports.Segment = Segment;
|
|
4941
6260
|
exports.Stream = Stream;
|
|
4942
6261
|
exports.StreamManager = StreamManager;
|
|
@@ -4946,16 +6265,24 @@ exports.StreamingRpcConnection = StreamingRpcConnection;
|
|
|
4946
6265
|
exports.StructBuilder = StructBuilder;
|
|
4947
6266
|
exports.StructReader = StructReader;
|
|
4948
6267
|
exports.SturdyRefManager = SturdyRefManager;
|
|
6268
|
+
exports.TcpTransport = TcpTransport;
|
|
4949
6269
|
exports.UnionBuilder = UnionBuilder;
|
|
4950
6270
|
exports.UnionReader = UnionReader;
|
|
4951
6271
|
exports.WORD_SIZE = WORD_SIZE;
|
|
4952
6272
|
exports.WebSocketTransport = WebSocketTransport;
|
|
4953
6273
|
exports.configureGlobalMemoryPool = configureGlobalMemoryPool;
|
|
4954
6274
|
exports.createBulkTransferManager = createBulkTransferManager;
|
|
6275
|
+
exports.createDynamicReader = createDynamicReader;
|
|
6276
|
+
exports.createDynamicReaderByTypeId = createDynamicReaderByTypeId;
|
|
6277
|
+
exports.createDynamicReaderFromStruct = createDynamicReaderFromStruct;
|
|
6278
|
+
exports.createDynamicWriter = createDynamicWriter;
|
|
6279
|
+
exports.createDynamicWriterByTypeId = createDynamicWriterByTypeId;
|
|
6280
|
+
exports.createNestedDynamicWriter = createNestedDynamicWriter;
|
|
4955
6281
|
exports.createPipelineClient = require_rpc_connection.createPipelineClient;
|
|
4956
6282
|
exports.createProvisionId = createProvisionId;
|
|
4957
6283
|
exports.createRealtimeStreamManager = createRealtimeStreamManager;
|
|
4958
6284
|
exports.createRecipientId = createRecipientId;
|
|
6285
|
+
exports.createSchemaRegistry = require_rpc_connection.createSchemaRegistry;
|
|
4959
6286
|
exports.createStream = createStream;
|
|
4960
6287
|
exports.createStreamManager = createStreamManager;
|
|
4961
6288
|
exports.createStreamingConnection = createStreamingConnection;
|
|
@@ -4966,7 +6293,10 @@ exports.createUnionReader = createUnionReader;
|
|
|
4966
6293
|
exports.createZeroCopyView = createZeroCopyView;
|
|
4967
6294
|
exports.decodePointer = decodePointer;
|
|
4968
6295
|
exports.deserializeRpcMessage = deserializeRpcMessage;
|
|
6296
|
+
exports.deserializeSchemaRequest = require_rpc_connection.deserializeSchemaRequest;
|
|
6297
|
+
exports.deserializeSchemaResponse = require_rpc_connection.deserializeSchemaResponse;
|
|
4969
6298
|
exports.deserializeSturdyRef = deserializeSturdyRef;
|
|
6299
|
+
exports.dumpDynamicReader = dumpDynamicReader;
|
|
4970
6300
|
exports.encodeListPointer = encodeListPointer;
|
|
4971
6301
|
exports.encodeStructPointer = encodeStructPointer;
|
|
4972
6302
|
exports.fastCopy = fastCopy;
|
|
@@ -4977,7 +6307,15 @@ exports.isPipelineClient = require_rpc_connection.isPipelineClient;
|
|
|
4977
6307
|
exports.isSameBuffer = isSameBuffer;
|
|
4978
6308
|
exports.isStream = isStream;
|
|
4979
6309
|
exports.isSturdyRefValid = isSturdyRefValid;
|
|
6310
|
+
exports.parseSchemaNodes = require_rpc_connection.parseSchemaNodes;
|
|
6311
|
+
exports.serializeDynamic = serializeDynamic;
|
|
6312
|
+
exports.serializeDynamicByTypeId = serializeDynamicByTypeId;
|
|
6313
|
+
exports.serializeGetSchemaParams = require_rpc_connection.serializeGetSchemaParams;
|
|
6314
|
+
exports.serializeGetSchemaResults = require_rpc_connection.serializeGetSchemaResults;
|
|
6315
|
+
exports.serializeListSchemasResults = require_rpc_connection.serializeListSchemasResults;
|
|
4980
6316
|
exports.serializeRpcMessage = serializeRpcMessage;
|
|
6317
|
+
exports.serializeSchemaRequest = require_rpc_connection.serializeSchemaRequest;
|
|
6318
|
+
exports.serializeSchemaResponse = require_rpc_connection.serializeSchemaResponse;
|
|
4981
6319
|
exports.serializeSturdyRef = serializeSturdyRef;
|
|
4982
6320
|
exports.supportsStreaming = supportsStreaming;
|
|
4983
6321
|
//# sourceMappingURL=index.cjs.map
|