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