@naeemo/capnp 0.9.0 → 0.9.3
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/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/{cli-DwbiXeKw.js → cli-DGBgLdGK.js} +5 -3
- package/dist/{cli-DwbiXeKw.js.map → cli-DGBgLdGK.js.map} +1 -1
- package/dist/{cli-DHKzE1UX.js → cli-DlZBZozW.js} +2 -2
- package/dist/{cli-DHKzE1UX.js.map → cli-DlZBZozW.js.map} +1 -1
- package/dist/cli-audit-j58Eyd5d.js +380 -0
- package/dist/cli-audit-j58Eyd5d.js.map +1 -0
- package/dist/cli-bench-BRKmxDEn.js +5185 -0
- package/dist/cli-bench-BRKmxDEn.js.map +1 -0
- package/dist/{cli-gen-BF0So0Ig.js → cli-gen-aCkffW1Z.js} +5 -3
- package/dist/{cli-gen-BF0So0Ig.js.map → cli-gen-aCkffW1Z.js.map} +1 -1
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/core-DstLMMvA.js +2 -0
- package/dist/index.cjs +954 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +945 -30
- package/dist/index.js.map +1 -1
- package/dist/{message-reader-fw2PY8sU.js → message-reader-_TCBf61G.js} +40 -176
- package/dist/message-reader-_TCBf61G.js.map +1 -0
- package/dist/{schema-types-B6M2jsM7.js → schema-types-GVRD1pwE.js} +1 -1
- package/dist/{schema-types-B6M2jsM7.js.map → schema-types-GVRD1pwE.js.map} +1 -1
- package/dist/segment-yid_PYS5.js +176 -0
- package/dist/segment-yid_PYS5.js.map +1 -0
- package/package.json +5 -1
- package/dist/message-reader-fw2PY8sU.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -105,6 +105,13 @@ function encodeStructPointer(offset, dataWords, pointerCount) {
|
|
|
105
105
|
function encodeListPointer(offset, elementSize, elementCount) {
|
|
106
106
|
return (BigInt(offset < 0 ? offset + 1073741824 : offset) & BigInt(1073741823)) << BigInt(2) | BigInt(1) | BigInt(elementSize) << BigInt(32) | BigInt(elementCount) << BigInt(35);
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* 编码 Far 指针
|
|
110
|
+
*/
|
|
111
|
+
function encodeFarPointer(segment, offset, doubleFar = false) {
|
|
112
|
+
const offsetBits = BigInt(offset) & BigInt(536870911);
|
|
113
|
+
return (BigInt(segment) & BigInt(4294967295)) << BigInt(32) | offsetBits << BigInt(3) | (doubleFar ? BigInt(1) << BigInt(2) : BigInt(0)) | BigInt(2);
|
|
114
|
+
}
|
|
108
115
|
|
|
109
116
|
//#endregion
|
|
110
117
|
//#region src/core/segment.ts
|
|
@@ -549,21 +556,38 @@ var ListBuilder = class {
|
|
|
549
556
|
* Cap'n Proto MessageReader
|
|
550
557
|
* 纯 TypeScript 实现
|
|
551
558
|
*/
|
|
559
|
+
/** 默认安全选项 */
|
|
560
|
+
const DEFAULT_SECURITY_OPTIONS = {
|
|
561
|
+
maxSegments: 64,
|
|
562
|
+
maxTotalSize: 64 * 1024 * 1024,
|
|
563
|
+
strictMode: false
|
|
564
|
+
};
|
|
552
565
|
var MessageReader = class {
|
|
553
566
|
segments;
|
|
554
|
-
|
|
567
|
+
securityOptions;
|
|
568
|
+
constructor(buffer, securityOptions) {
|
|
569
|
+
this.securityOptions = {
|
|
570
|
+
...DEFAULT_SECURITY_OPTIONS,
|
|
571
|
+
...securityOptions
|
|
572
|
+
};
|
|
555
573
|
const uint8Array = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer;
|
|
556
574
|
this.segments = [];
|
|
575
|
+
if (this.securityOptions.strictMode && uint8Array.byteLength > this.securityOptions.maxTotalSize) throw new Error(`Message size (${uint8Array.byteLength} bytes) exceeds maximum allowed size (${this.securityOptions.maxTotalSize} bytes)`);
|
|
557
576
|
if (uint8Array.byteLength < 8) return;
|
|
558
577
|
const view = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
|
|
559
578
|
const firstWordLow = view.getUint32(0, true);
|
|
560
579
|
const firstWordHigh = view.getUint32(4, true);
|
|
561
580
|
const segmentCount = (firstWordLow & 4294967295) + 1;
|
|
562
581
|
const firstSegmentSize = firstWordHigh;
|
|
582
|
+
if (segmentCount > this.securityOptions.maxSegments) {
|
|
583
|
+
if (this.securityOptions.strictMode) throw new Error(`Segment count (${segmentCount}) exceeds maximum allowed (${this.securityOptions.maxSegments})`);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
563
586
|
let offset = 8;
|
|
564
587
|
const segmentSizes = [firstSegmentSize];
|
|
565
588
|
for (let i = 1; i < segmentCount; i++) {
|
|
566
589
|
if (offset + 4 > uint8Array.byteLength) {
|
|
590
|
+
if (this.securityOptions.strictMode) throw new Error(`Message ended prematurely while reading segment ${i} size (offset: ${offset}, length: ${uint8Array.byteLength})`);
|
|
567
591
|
this.segments = [];
|
|
568
592
|
return;
|
|
569
593
|
}
|
|
@@ -572,12 +596,24 @@ var MessageReader = class {
|
|
|
572
596
|
}
|
|
573
597
|
offset = offset + 7 & -8;
|
|
574
598
|
if (offset > uint8Array.byteLength) {
|
|
599
|
+
if (this.securityOptions.strictMode) throw new Error(`Insufficient data for segment table (offset: ${offset}, length: ${uint8Array.byteLength})`);
|
|
575
600
|
this.segments = [];
|
|
576
601
|
return;
|
|
577
602
|
}
|
|
603
|
+
const headerSize = offset;
|
|
604
|
+
let totalBodySize = 0;
|
|
605
|
+
for (const size of segmentSizes) totalBodySize += size * WORD_SIZE;
|
|
606
|
+
const expectedTotalSize = headerSize + totalBodySize;
|
|
607
|
+
if (expectedTotalSize > this.securityOptions.maxTotalSize) {
|
|
608
|
+
if (this.securityOptions.strictMode) throw new Error(`Total message size (${expectedTotalSize} bytes) exceeds maximum allowed size (${this.securityOptions.maxTotalSize} bytes)`);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
578
611
|
this.segments = [];
|
|
579
612
|
for (const size of segmentSizes) {
|
|
580
|
-
if (offset + size * WORD_SIZE > uint8Array.byteLength)
|
|
613
|
+
if (offset + size * WORD_SIZE > uint8Array.byteLength) {
|
|
614
|
+
if (this.securityOptions.strictMode) throw new Error(`Insufficient data for segment (expected ${size * WORD_SIZE} bytes at offset ${offset}, but message is ${uint8Array.byteLength} bytes)`);
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
581
617
|
const segmentBuffer = uint8Array.slice(offset, offset + size * WORD_SIZE);
|
|
582
618
|
this.segments.push(Segment.fromBuffer(segmentBuffer.buffer));
|
|
583
619
|
offset += size * WORD_SIZE;
|
|
@@ -671,6 +707,12 @@ var MessageReader = class {
|
|
|
671
707
|
get segmentCount() {
|
|
672
708
|
return this.segments.length;
|
|
673
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* 获取当前安全选项配置
|
|
712
|
+
*/
|
|
713
|
+
getSecurityOptions() {
|
|
714
|
+
return { ...this.securityOptions };
|
|
715
|
+
}
|
|
674
716
|
};
|
|
675
717
|
/**
|
|
676
718
|
* 结构读取器
|
|
@@ -1654,6 +1696,18 @@ var WebSocketTransport = class WebSocketTransport {
|
|
|
1654
1696
|
get connected() {
|
|
1655
1697
|
return this._connected;
|
|
1656
1698
|
}
|
|
1699
|
+
getCompressionState() {
|
|
1700
|
+
return {
|
|
1701
|
+
enabled: false,
|
|
1702
|
+
algorithm: "none",
|
|
1703
|
+
bytesSent: 0,
|
|
1704
|
+
bytesReceived: 0,
|
|
1705
|
+
uncompressedBytesSent: 0,
|
|
1706
|
+
uncompressedBytesReceived: 0,
|
|
1707
|
+
messagesCompressed: 0,
|
|
1708
|
+
messagesDecompressed: 0
|
|
1709
|
+
};
|
|
1710
|
+
}
|
|
1657
1711
|
connect(url) {
|
|
1658
1712
|
this.ws = new WebSocket(url);
|
|
1659
1713
|
this.ws.binaryType = this.options.binaryType ?? "arraybuffer";
|
|
@@ -1810,6 +1864,432 @@ var WebSocketTransport = class WebSocketTransport {
|
|
|
1810
1864
|
}
|
|
1811
1865
|
};
|
|
1812
1866
|
|
|
1867
|
+
//#endregion
|
|
1868
|
+
//#region node_modules/.pnpm/lz4js@0.2.0/node_modules/lz4js/util.js
|
|
1869
|
+
var require_util = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
1870
|
+
exports.hashU32 = function hashU32(a) {
|
|
1871
|
+
a = a | 0;
|
|
1872
|
+
a = a + 2127912214 + (a << 12) | 0;
|
|
1873
|
+
a = a ^ -949894596 ^ a >>> 19;
|
|
1874
|
+
a = a + 374761393 + (a << 5) | 0;
|
|
1875
|
+
a = a + -744332180 ^ a << 9;
|
|
1876
|
+
a = a + -42973499 + (a << 3) | 0;
|
|
1877
|
+
return a ^ -1252372727 ^ a >>> 16 | 0;
|
|
1878
|
+
};
|
|
1879
|
+
exports.readU64 = function readU64(b, n) {
|
|
1880
|
+
var x = 0;
|
|
1881
|
+
x |= b[n++] << 0;
|
|
1882
|
+
x |= b[n++] << 8;
|
|
1883
|
+
x |= b[n++] << 16;
|
|
1884
|
+
x |= b[n++] << 24;
|
|
1885
|
+
x |= b[n++] << 32;
|
|
1886
|
+
x |= b[n++] << 40;
|
|
1887
|
+
x |= b[n++] << 48;
|
|
1888
|
+
x |= b[n++] << 56;
|
|
1889
|
+
return x;
|
|
1890
|
+
};
|
|
1891
|
+
exports.readU32 = function readU32(b, n) {
|
|
1892
|
+
var x = 0;
|
|
1893
|
+
x |= b[n++] << 0;
|
|
1894
|
+
x |= b[n++] << 8;
|
|
1895
|
+
x |= b[n++] << 16;
|
|
1896
|
+
x |= b[n++] << 24;
|
|
1897
|
+
return x;
|
|
1898
|
+
};
|
|
1899
|
+
exports.writeU32 = function writeU32(b, n, x) {
|
|
1900
|
+
b[n++] = x >> 0 & 255;
|
|
1901
|
+
b[n++] = x >> 8 & 255;
|
|
1902
|
+
b[n++] = x >> 16 & 255;
|
|
1903
|
+
b[n++] = x >> 24 & 255;
|
|
1904
|
+
};
|
|
1905
|
+
exports.imul = function imul(a, b) {
|
|
1906
|
+
var ah = a >>> 16;
|
|
1907
|
+
var al = a & 65535;
|
|
1908
|
+
var bh = b >>> 16;
|
|
1909
|
+
var bl = b & 65535;
|
|
1910
|
+
return al * bl + (ah * bl + al * bh << 16) | 0;
|
|
1911
|
+
};
|
|
1912
|
+
}));
|
|
1913
|
+
|
|
1914
|
+
//#endregion
|
|
1915
|
+
//#region node_modules/.pnpm/lz4js@0.2.0/node_modules/lz4js/xxh32.js
|
|
1916
|
+
var require_xxh32 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
1917
|
+
var util = require_util();
|
|
1918
|
+
var prime1 = 2654435761;
|
|
1919
|
+
var prime2 = 2246822519;
|
|
1920
|
+
var prime3 = 3266489917;
|
|
1921
|
+
var prime4 = 668265263;
|
|
1922
|
+
var prime5 = 374761393;
|
|
1923
|
+
function rotl32(x, r) {
|
|
1924
|
+
x = x | 0;
|
|
1925
|
+
r = r | 0;
|
|
1926
|
+
return x >>> (32 - r | 0) | x << r | 0;
|
|
1927
|
+
}
|
|
1928
|
+
function rotmul32(h, r, m) {
|
|
1929
|
+
h = h | 0;
|
|
1930
|
+
r = r | 0;
|
|
1931
|
+
m = m | 0;
|
|
1932
|
+
return util.imul(h >>> (32 - r | 0) | h << r, m) | 0;
|
|
1933
|
+
}
|
|
1934
|
+
function shiftxor32(h, s) {
|
|
1935
|
+
h = h | 0;
|
|
1936
|
+
s = s | 0;
|
|
1937
|
+
return h >>> s ^ h | 0;
|
|
1938
|
+
}
|
|
1939
|
+
function xxhapply(h, src, m0, s, m1) {
|
|
1940
|
+
return rotmul32(util.imul(src, m0) + h, s, m1);
|
|
1941
|
+
}
|
|
1942
|
+
function xxh1(h, src, index) {
|
|
1943
|
+
return rotmul32(h + util.imul(src[index], prime5), 11, prime1);
|
|
1944
|
+
}
|
|
1945
|
+
function xxh4(h, src, index) {
|
|
1946
|
+
return xxhapply(h, util.readU32(src, index), prime3, 17, prime4);
|
|
1947
|
+
}
|
|
1948
|
+
function xxh16(h, src, index) {
|
|
1949
|
+
return [
|
|
1950
|
+
xxhapply(h[0], util.readU32(src, index + 0), prime2, 13, prime1),
|
|
1951
|
+
xxhapply(h[1], util.readU32(src, index + 4), prime2, 13, prime1),
|
|
1952
|
+
xxhapply(h[2], util.readU32(src, index + 8), prime2, 13, prime1),
|
|
1953
|
+
xxhapply(h[3], util.readU32(src, index + 12), prime2, 13, prime1)
|
|
1954
|
+
];
|
|
1955
|
+
}
|
|
1956
|
+
function xxh32(seed, src, index, len) {
|
|
1957
|
+
var h, l = len;
|
|
1958
|
+
if (len >= 16) {
|
|
1959
|
+
h = [
|
|
1960
|
+
seed + prime1 + prime2,
|
|
1961
|
+
seed + prime2,
|
|
1962
|
+
seed,
|
|
1963
|
+
seed - prime1
|
|
1964
|
+
];
|
|
1965
|
+
while (len >= 16) {
|
|
1966
|
+
h = xxh16(h, src, index);
|
|
1967
|
+
index += 16;
|
|
1968
|
+
len -= 16;
|
|
1969
|
+
}
|
|
1970
|
+
h = rotl32(h[0], 1) + rotl32(h[1], 7) + rotl32(h[2], 12) + rotl32(h[3], 18) + l;
|
|
1971
|
+
} else h = seed + prime5 + len >>> 0;
|
|
1972
|
+
while (len >= 4) {
|
|
1973
|
+
h = xxh4(h, src, index);
|
|
1974
|
+
index += 4;
|
|
1975
|
+
len -= 4;
|
|
1976
|
+
}
|
|
1977
|
+
while (len > 0) {
|
|
1978
|
+
h = xxh1(h, src, index);
|
|
1979
|
+
index++;
|
|
1980
|
+
len--;
|
|
1981
|
+
}
|
|
1982
|
+
h = shiftxor32(util.imul(shiftxor32(util.imul(shiftxor32(h, 15), prime2), 13), prime3), 16);
|
|
1983
|
+
return h >>> 0;
|
|
1984
|
+
}
|
|
1985
|
+
exports.hash = xxh32;
|
|
1986
|
+
}));
|
|
1987
|
+
|
|
1988
|
+
//#endregion
|
|
1989
|
+
//#region node_modules/.pnpm/lz4js@0.2.0/node_modules/lz4js/lz4.js
|
|
1990
|
+
var require_lz4 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
1991
|
+
var xxhash = require_xxh32();
|
|
1992
|
+
var util = require_util();
|
|
1993
|
+
var minMatch = 4;
|
|
1994
|
+
var minLength = 13;
|
|
1995
|
+
var searchLimit = 5;
|
|
1996
|
+
var skipTrigger = 6;
|
|
1997
|
+
var hashSize = 65536;
|
|
1998
|
+
var mlBits = 4;
|
|
1999
|
+
var mlMask = (1 << mlBits) - 1;
|
|
2000
|
+
var runMask = 15;
|
|
2001
|
+
var blockBuf = makeBuffer(5 << 20);
|
|
2002
|
+
var hashTable = makeHashTable();
|
|
2003
|
+
var magicNum = 407708164;
|
|
2004
|
+
var fdContentChksum = 4;
|
|
2005
|
+
var fdContentSize = 8;
|
|
2006
|
+
var fdBlockChksum = 16;
|
|
2007
|
+
var fdVersion = 64;
|
|
2008
|
+
var fdVersionMask = 192;
|
|
2009
|
+
var bsUncompressed = 2147483648;
|
|
2010
|
+
var bsDefault = 7;
|
|
2011
|
+
var bsShift = 4;
|
|
2012
|
+
var bsMask = 7;
|
|
2013
|
+
var bsMap = {
|
|
2014
|
+
4: 65536,
|
|
2015
|
+
5: 262144,
|
|
2016
|
+
6: 1048576,
|
|
2017
|
+
7: 4194304
|
|
2018
|
+
};
|
|
2019
|
+
function makeHashTable() {
|
|
2020
|
+
try {
|
|
2021
|
+
return new Uint32Array(hashSize);
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
var hashTable = new Array(hashSize);
|
|
2024
|
+
for (var i = 0; i < hashSize; i++) hashTable[i] = 0;
|
|
2025
|
+
return hashTable;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
function clearHashTable(table) {
|
|
2029
|
+
for (var i = 0; i < hashSize; i++) hashTable[i] = 0;
|
|
2030
|
+
}
|
|
2031
|
+
function makeBuffer(size) {
|
|
2032
|
+
try {
|
|
2033
|
+
return new Uint8Array(size);
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
var buf = new Array(size);
|
|
2036
|
+
for (var i = 0; i < size; i++) buf[i] = 0;
|
|
2037
|
+
return buf;
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
function sliceArray(array, start, end) {
|
|
2041
|
+
if (Uint8Array.prototype.slice) return array.slice(start, end);
|
|
2042
|
+
else {
|
|
2043
|
+
var len = array.length;
|
|
2044
|
+
start = start | 0;
|
|
2045
|
+
start = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
|
|
2046
|
+
end = end === void 0 ? len : end | 0;
|
|
2047
|
+
end = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
|
|
2048
|
+
var arraySlice = new Uint8Array(end - start);
|
|
2049
|
+
for (var i = start, n = 0; i < end;) arraySlice[n++] = array[i++];
|
|
2050
|
+
return arraySlice;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
exports.compressBound = function compressBound(n) {
|
|
2054
|
+
return n + n / 255 + 16 | 0;
|
|
2055
|
+
};
|
|
2056
|
+
exports.decompressBound = function decompressBound(src) {
|
|
2057
|
+
var sIndex = 0;
|
|
2058
|
+
if (util.readU32(src, sIndex) !== magicNum) throw new Error("invalid magic number");
|
|
2059
|
+
sIndex += 4;
|
|
2060
|
+
var descriptor = src[sIndex++];
|
|
2061
|
+
if ((descriptor & fdVersionMask) !== fdVersion) throw new Error("incompatible descriptor version " + (descriptor & fdVersionMask));
|
|
2062
|
+
var useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
|
2063
|
+
var useContentSize = (descriptor & fdContentSize) !== 0;
|
|
2064
|
+
var bsIdx = src[sIndex++] >> bsShift & bsMask;
|
|
2065
|
+
if (bsMap[bsIdx] === void 0) throw new Error("invalid block size " + bsIdx);
|
|
2066
|
+
var maxBlockSize = bsMap[bsIdx];
|
|
2067
|
+
if (useContentSize) return util.readU64(src, sIndex);
|
|
2068
|
+
sIndex++;
|
|
2069
|
+
var maxSize = 0;
|
|
2070
|
+
while (true) {
|
|
2071
|
+
var blockSize = util.readU32(src, sIndex);
|
|
2072
|
+
sIndex += 4;
|
|
2073
|
+
if (blockSize & bsUncompressed) {
|
|
2074
|
+
blockSize &= ~bsUncompressed;
|
|
2075
|
+
maxSize += blockSize;
|
|
2076
|
+
} else maxSize += maxBlockSize;
|
|
2077
|
+
if (blockSize === 0) return maxSize;
|
|
2078
|
+
if (useBlockSum) sIndex += 4;
|
|
2079
|
+
sIndex += blockSize;
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
exports.makeBuffer = makeBuffer;
|
|
2083
|
+
exports.decompressBlock = function decompressBlock(src, dst, sIndex, sLength, dIndex) {
|
|
2084
|
+
var mLength, mOffset, sEnd = sIndex + sLength, n, i;
|
|
2085
|
+
while (sIndex < sEnd) {
|
|
2086
|
+
var token = src[sIndex++];
|
|
2087
|
+
var literalCount = token >> 4;
|
|
2088
|
+
if (literalCount > 0) {
|
|
2089
|
+
if (literalCount === 15) while (true) {
|
|
2090
|
+
literalCount += src[sIndex];
|
|
2091
|
+
if (src[sIndex++] !== 255) break;
|
|
2092
|
+
}
|
|
2093
|
+
for (n = sIndex + literalCount; sIndex < n;) dst[dIndex++] = src[sIndex++];
|
|
2094
|
+
}
|
|
2095
|
+
if (sIndex >= sEnd) break;
|
|
2096
|
+
mLength = token & 15;
|
|
2097
|
+
mOffset = src[sIndex++] | src[sIndex++] << 8;
|
|
2098
|
+
if (mLength === 15) while (true) {
|
|
2099
|
+
mLength += src[sIndex];
|
|
2100
|
+
if (src[sIndex++] !== 255) break;
|
|
2101
|
+
}
|
|
2102
|
+
mLength += minMatch;
|
|
2103
|
+
for (i = dIndex - mOffset, n = i + mLength; i < n;) dst[dIndex++] = dst[i++] | 0;
|
|
2104
|
+
}
|
|
2105
|
+
return dIndex;
|
|
2106
|
+
};
|
|
2107
|
+
exports.compressBlock = function compressBlock(src, dst, sIndex, sLength, hashTable) {
|
|
2108
|
+
var mIndex, mAnchor, mLength, mOffset, mStep;
|
|
2109
|
+
var literalCount, dIndex = 0, sEnd = sLength + sIndex, n;
|
|
2110
|
+
mAnchor = sIndex;
|
|
2111
|
+
if (sLength >= minLength) {
|
|
2112
|
+
var searchMatchCount = (1 << skipTrigger) + 3;
|
|
2113
|
+
while (sIndex + minMatch < sEnd - searchLimit) {
|
|
2114
|
+
var seq = util.readU32(src, sIndex);
|
|
2115
|
+
var hash = util.hashU32(seq) >>> 0;
|
|
2116
|
+
hash = (hash >> 16 ^ hash) >>> 0 & 65535;
|
|
2117
|
+
mIndex = hashTable[hash] - 1;
|
|
2118
|
+
hashTable[hash] = sIndex + 1;
|
|
2119
|
+
if (mIndex < 0 || sIndex - mIndex >>> 16 > 0 || util.readU32(src, mIndex) !== seq) {
|
|
2120
|
+
mStep = searchMatchCount++ >> skipTrigger;
|
|
2121
|
+
sIndex += mStep;
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2124
|
+
searchMatchCount = (1 << skipTrigger) + 3;
|
|
2125
|
+
literalCount = sIndex - mAnchor;
|
|
2126
|
+
mOffset = sIndex - mIndex;
|
|
2127
|
+
sIndex += minMatch;
|
|
2128
|
+
mIndex += minMatch;
|
|
2129
|
+
mLength = sIndex;
|
|
2130
|
+
while (sIndex < sEnd - searchLimit && src[sIndex] === src[mIndex]) {
|
|
2131
|
+
sIndex++;
|
|
2132
|
+
mIndex++;
|
|
2133
|
+
}
|
|
2134
|
+
mLength = sIndex - mLength;
|
|
2135
|
+
var token = mLength < mlMask ? mLength : mlMask;
|
|
2136
|
+
if (literalCount >= runMask) {
|
|
2137
|
+
dst[dIndex++] = (runMask << mlBits) + token;
|
|
2138
|
+
for (n = literalCount - runMask; n >= 255; n -= 255) dst[dIndex++] = 255;
|
|
2139
|
+
dst[dIndex++] = n;
|
|
2140
|
+
} else dst[dIndex++] = (literalCount << mlBits) + token;
|
|
2141
|
+
for (var i = 0; i < literalCount; i++) dst[dIndex++] = src[mAnchor + i];
|
|
2142
|
+
dst[dIndex++] = mOffset;
|
|
2143
|
+
dst[dIndex++] = mOffset >> 8;
|
|
2144
|
+
if (mLength >= mlMask) {
|
|
2145
|
+
for (n = mLength - mlMask; n >= 255; n -= 255) dst[dIndex++] = 255;
|
|
2146
|
+
dst[dIndex++] = n;
|
|
2147
|
+
}
|
|
2148
|
+
mAnchor = sIndex;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
if (mAnchor === 0) return 0;
|
|
2152
|
+
literalCount = sEnd - mAnchor;
|
|
2153
|
+
if (literalCount >= runMask) {
|
|
2154
|
+
dst[dIndex++] = runMask << mlBits;
|
|
2155
|
+
for (n = literalCount - runMask; n >= 255; n -= 255) dst[dIndex++] = 255;
|
|
2156
|
+
dst[dIndex++] = n;
|
|
2157
|
+
} else dst[dIndex++] = literalCount << mlBits;
|
|
2158
|
+
sIndex = mAnchor;
|
|
2159
|
+
while (sIndex < sEnd) dst[dIndex++] = src[sIndex++];
|
|
2160
|
+
return dIndex;
|
|
2161
|
+
};
|
|
2162
|
+
exports.decompressFrame = function decompressFrame(src, dst) {
|
|
2163
|
+
var useBlockSum, useContentSum, useContentSize, descriptor;
|
|
2164
|
+
var sIndex = 0;
|
|
2165
|
+
var dIndex = 0;
|
|
2166
|
+
if (util.readU32(src, sIndex) !== magicNum) throw new Error("invalid magic number");
|
|
2167
|
+
sIndex += 4;
|
|
2168
|
+
descriptor = src[sIndex++];
|
|
2169
|
+
if ((descriptor & fdVersionMask) !== fdVersion) throw new Error("incompatible descriptor version");
|
|
2170
|
+
useBlockSum = (descriptor & fdBlockChksum) !== 0;
|
|
2171
|
+
useContentSum = (descriptor & fdContentChksum) !== 0;
|
|
2172
|
+
useContentSize = (descriptor & fdContentSize) !== 0;
|
|
2173
|
+
if (bsMap[src[sIndex++] >> bsShift & bsMask] === void 0) throw new Error("invalid block size");
|
|
2174
|
+
if (useContentSize) sIndex += 8;
|
|
2175
|
+
sIndex++;
|
|
2176
|
+
while (true) {
|
|
2177
|
+
var compSize = util.readU32(src, sIndex);
|
|
2178
|
+
sIndex += 4;
|
|
2179
|
+
if (compSize === 0) break;
|
|
2180
|
+
if (useBlockSum) sIndex += 4;
|
|
2181
|
+
if ((compSize & bsUncompressed) !== 0) {
|
|
2182
|
+
compSize &= ~bsUncompressed;
|
|
2183
|
+
for (var j = 0; j < compSize; j++) dst[dIndex++] = src[sIndex++];
|
|
2184
|
+
} else {
|
|
2185
|
+
dIndex = exports.decompressBlock(src, dst, sIndex, compSize, dIndex);
|
|
2186
|
+
sIndex += compSize;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
if (useContentSum) sIndex += 4;
|
|
2190
|
+
return dIndex;
|
|
2191
|
+
};
|
|
2192
|
+
exports.compressFrame = function compressFrame(src, dst) {
|
|
2193
|
+
var dIndex = 0;
|
|
2194
|
+
util.writeU32(dst, dIndex, magicNum);
|
|
2195
|
+
dIndex += 4;
|
|
2196
|
+
dst[dIndex++] = fdVersion;
|
|
2197
|
+
dst[dIndex++] = bsDefault << bsShift;
|
|
2198
|
+
dst[dIndex] = xxhash.hash(0, dst, 4, dIndex - 4) >> 8;
|
|
2199
|
+
dIndex++;
|
|
2200
|
+
var maxBlockSize = bsMap[bsDefault];
|
|
2201
|
+
var remaining = src.length;
|
|
2202
|
+
var sIndex = 0;
|
|
2203
|
+
clearHashTable(hashTable);
|
|
2204
|
+
while (remaining > 0) {
|
|
2205
|
+
var compSize = 0;
|
|
2206
|
+
var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining;
|
|
2207
|
+
compSize = exports.compressBlock(src, blockBuf, sIndex, blockSize, hashTable);
|
|
2208
|
+
if (compSize > blockSize || compSize === 0) {
|
|
2209
|
+
util.writeU32(dst, dIndex, 2147483648 | blockSize);
|
|
2210
|
+
dIndex += 4;
|
|
2211
|
+
for (var z = sIndex + blockSize; sIndex < z;) dst[dIndex++] = src[sIndex++];
|
|
2212
|
+
remaining -= blockSize;
|
|
2213
|
+
} else {
|
|
2214
|
+
util.writeU32(dst, dIndex, compSize);
|
|
2215
|
+
dIndex += 4;
|
|
2216
|
+
for (var j = 0; j < compSize;) dst[dIndex++] = blockBuf[j++];
|
|
2217
|
+
sIndex += blockSize;
|
|
2218
|
+
remaining -= blockSize;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
util.writeU32(dst, dIndex, 0);
|
|
2222
|
+
dIndex += 4;
|
|
2223
|
+
return dIndex;
|
|
2224
|
+
};
|
|
2225
|
+
exports.decompress = function decompress(src, maxSize) {
|
|
2226
|
+
var dst, size;
|
|
2227
|
+
if (maxSize === void 0) maxSize = exports.decompressBound(src);
|
|
2228
|
+
dst = exports.makeBuffer(maxSize);
|
|
2229
|
+
size = exports.decompressFrame(src, dst);
|
|
2230
|
+
if (size !== maxSize) dst = sliceArray(dst, 0, size);
|
|
2231
|
+
return dst;
|
|
2232
|
+
};
|
|
2233
|
+
exports.compress = function compress(src, maxSize) {
|
|
2234
|
+
var dst, size;
|
|
2235
|
+
if (maxSize === void 0) maxSize = exports.compressBound(src.length);
|
|
2236
|
+
dst = exports.makeBuffer(maxSize);
|
|
2237
|
+
size = exports.compressFrame(src, dst);
|
|
2238
|
+
if (size !== maxSize) dst = sliceArray(dst, 0, size);
|
|
2239
|
+
return dst;
|
|
2240
|
+
};
|
|
2241
|
+
}));
|
|
2242
|
+
|
|
2243
|
+
//#endregion
|
|
2244
|
+
//#region src/compression/lz4.ts
|
|
2245
|
+
var import_lz4 = require_lz4();
|
|
2246
|
+
/**
|
|
2247
|
+
* Default compression options
|
|
2248
|
+
*/
|
|
2249
|
+
const DEFAULT_COMPRESSION_OPTIONS = {
|
|
2250
|
+
threshold: 1024,
|
|
2251
|
+
acceleration: 1,
|
|
2252
|
+
level: 0
|
|
2253
|
+
};
|
|
2254
|
+
/**
|
|
2255
|
+
* Compress data using LZ4
|
|
2256
|
+
* @param data - Data to compress
|
|
2257
|
+
* @param options - Compression options
|
|
2258
|
+
* @returns Compressed data, or null if compression failed or not beneficial
|
|
2259
|
+
*/
|
|
2260
|
+
function compress(data, options = {}) {
|
|
2261
|
+
const opts = {
|
|
2262
|
+
...DEFAULT_COMPRESSION_OPTIONS,
|
|
2263
|
+
...options
|
|
2264
|
+
};
|
|
2265
|
+
if (data.length < opts.threshold) return null;
|
|
2266
|
+
try {
|
|
2267
|
+
const compressed = (0, import_lz4.compress)(Array.from(data));
|
|
2268
|
+
if (compressed.length >= data.length) return null;
|
|
2269
|
+
return new Uint8Array(compressed);
|
|
2270
|
+
} catch (_error) {
|
|
2271
|
+
return null;
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Decompress LZ4 compressed data
|
|
2276
|
+
* @param data - Compressed data
|
|
2277
|
+
* @param originalSize - Original uncompressed size
|
|
2278
|
+
* @returns Decompressed data, or null if decompression failed
|
|
2279
|
+
*/
|
|
2280
|
+
function decompress(data, originalSize) {
|
|
2281
|
+
try {
|
|
2282
|
+
const decompressed = (0, import_lz4.decompress)(Array.from(data), originalSize);
|
|
2283
|
+
return new Uint8Array(decompressed);
|
|
2284
|
+
} catch (_error) {
|
|
2285
|
+
return null;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Alias for decompress - same function, different name for API compatibility
|
|
2290
|
+
*/
|
|
2291
|
+
const uncompress = decompress;
|
|
2292
|
+
|
|
1813
2293
|
//#endregion
|
|
1814
2294
|
//#region src/rpc/tcp-transport.ts
|
|
1815
2295
|
/**
|
|
@@ -1818,11 +2298,20 @@ var WebSocketTransport = class WebSocketTransport {
|
|
|
1818
2298
|
* Implements RpcTransport over raw TCP socket for C++ interop testing.
|
|
1819
2299
|
* This allows direct communication with the official Cap'n Proto C++ implementation.
|
|
1820
2300
|
*/
|
|
2301
|
+
const FRAME_MAGIC = 1280980035;
|
|
2302
|
+
const ALGORITHM_LZ4 = 1;
|
|
2303
|
+
const CAPABILITY_VERSION = 1;
|
|
2304
|
+
const DEFAULT_COMPRESSION_THRESHOLD = 256;
|
|
1821
2305
|
/**
|
|
1822
2306
|
* TCP Transport for Cap'n Proto RPC
|
|
1823
2307
|
*
|
|
1824
2308
|
* Uses length-prefixed binary message framing compatible with Cap'n Proto C++ implementation.
|
|
1825
2309
|
* Format: [4 bytes: message length (little-endian)] [N bytes: message data]
|
|
2310
|
+
*
|
|
2311
|
+
* With compression support:
|
|
2312
|
+
* - Connection establishment includes capability negotiation
|
|
2313
|
+
* - Messages larger than threshold are automatically compressed
|
|
2314
|
+
* - Frame header indicates compression algorithm used
|
|
1826
2315
|
*/
|
|
1827
2316
|
var TcpTransport = class TcpTransport {
|
|
1828
2317
|
socket = null;
|
|
@@ -1832,12 +2321,35 @@ var TcpTransport = class TcpTransport {
|
|
|
1832
2321
|
pendingBuffer = Buffer.alloc(0);
|
|
1833
2322
|
pendingLength = 0;
|
|
1834
2323
|
hasPendingLength = false;
|
|
2324
|
+
compressionConfig;
|
|
2325
|
+
localSupportsLz4 = false;
|
|
2326
|
+
remoteSupportsLz4 = false;
|
|
2327
|
+
compressionEnabled = false;
|
|
2328
|
+
compressionState;
|
|
2329
|
+
negotiationComplete = false;
|
|
1835
2330
|
onClose;
|
|
1836
2331
|
onError;
|
|
1837
2332
|
constructor(host, port, options = {}) {
|
|
1838
2333
|
this.host = host;
|
|
1839
2334
|
this.port = port;
|
|
1840
2335
|
this.options = options;
|
|
2336
|
+
this.compressionConfig = {
|
|
2337
|
+
enabled: options.compression?.enabled ?? true,
|
|
2338
|
+
algorithm: options.compression?.algorithm ?? "lz4",
|
|
2339
|
+
thresholdBytes: options.compression?.thresholdBytes ?? DEFAULT_COMPRESSION_THRESHOLD,
|
|
2340
|
+
level: options.compression?.level ?? 1
|
|
2341
|
+
};
|
|
2342
|
+
this.localSupportsLz4 = this.compressionConfig.enabled && this.compressionConfig.algorithm === "lz4";
|
|
2343
|
+
this.compressionState = {
|
|
2344
|
+
enabled: false,
|
|
2345
|
+
algorithm: "none",
|
|
2346
|
+
bytesSent: 0,
|
|
2347
|
+
bytesReceived: 0,
|
|
2348
|
+
uncompressedBytesSent: 0,
|
|
2349
|
+
uncompressedBytesReceived: 0,
|
|
2350
|
+
messagesCompressed: 0,
|
|
2351
|
+
messagesDecompressed: 0
|
|
2352
|
+
};
|
|
1841
2353
|
}
|
|
1842
2354
|
static async connect(host, port, options) {
|
|
1843
2355
|
const transport = new TcpTransport(host, port, options);
|
|
@@ -1852,6 +2364,9 @@ var TcpTransport = class TcpTransport {
|
|
|
1852
2364
|
get connected() {
|
|
1853
2365
|
return this._connected && this.socket?.readyState === "open";
|
|
1854
2366
|
}
|
|
2367
|
+
getCompressionState() {
|
|
2368
|
+
return { ...this.compressionState };
|
|
2369
|
+
}
|
|
1855
2370
|
connect() {
|
|
1856
2371
|
return new Promise((resolve, reject) => {
|
|
1857
2372
|
const timeout = setTimeout(() => {
|
|
@@ -1859,10 +2374,15 @@ var TcpTransport = class TcpTransport {
|
|
|
1859
2374
|
reject(/* @__PURE__ */ new Error("Connection timeout"));
|
|
1860
2375
|
}, this.options.connectTimeoutMs ?? 1e4);
|
|
1861
2376
|
this.socket = new node_net.Socket();
|
|
1862
|
-
this.socket.on("connect", () => {
|
|
2377
|
+
this.socket.on("connect", async () => {
|
|
1863
2378
|
clearTimeout(timeout);
|
|
1864
2379
|
this._connected = true;
|
|
1865
|
-
|
|
2380
|
+
try {
|
|
2381
|
+
await this.performCapabilityNegotiation();
|
|
2382
|
+
resolve();
|
|
2383
|
+
} catch (err) {
|
|
2384
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
2385
|
+
}
|
|
1866
2386
|
});
|
|
1867
2387
|
this.socket.on("data", (data) => {
|
|
1868
2388
|
this.handleData(data);
|
|
@@ -1904,6 +2424,85 @@ var TcpTransport = class TcpTransport {
|
|
|
1904
2424
|
socket.on("end", () => {
|
|
1905
2425
|
this._connected = false;
|
|
1906
2426
|
});
|
|
2427
|
+
if (this._connected) this.performCapabilityNegotiation().catch((err) => {
|
|
2428
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* Perform capability negotiation with the remote peer
|
|
2433
|
+
*/
|
|
2434
|
+
async performCapabilityNegotiation() {
|
|
2435
|
+
if (!this.socket) throw new Error("Socket not connected");
|
|
2436
|
+
if (this.host === "" && this.port === 0) {
|
|
2437
|
+
this.remoteSupportsLz4 = (await this.readCapabilityNegotiation()).supportsLz4;
|
|
2438
|
+
await this.sendCapabilityNegotiation();
|
|
2439
|
+
} else {
|
|
2440
|
+
await this.sendCapabilityNegotiation();
|
|
2441
|
+
this.remoteSupportsLz4 = (await this.readCapabilityNegotiation()).supportsLz4;
|
|
2442
|
+
}
|
|
2443
|
+
this.compressionEnabled = this.localSupportsLz4 && this.remoteSupportsLz4;
|
|
2444
|
+
this.compressionState.enabled = this.compressionEnabled;
|
|
2445
|
+
this.compressionState.algorithm = this.compressionEnabled ? "lz4" : "none";
|
|
2446
|
+
this.negotiationComplete = true;
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* Send capability negotiation message
|
|
2450
|
+
*/
|
|
2451
|
+
async sendCapabilityNegotiation() {
|
|
2452
|
+
const caps = {
|
|
2453
|
+
type: "capabilities",
|
|
2454
|
+
supportsLz4: this.localSupportsLz4,
|
|
2455
|
+
version: CAPABILITY_VERSION
|
|
2456
|
+
};
|
|
2457
|
+
const data = Buffer.from(JSON.stringify(caps), "utf-8");
|
|
2458
|
+
const frame = Buffer.allocUnsafe(4 + data.length);
|
|
2459
|
+
frame.writeUInt32LE(data.length, 0);
|
|
2460
|
+
frame.set(data, 4);
|
|
2461
|
+
return new Promise((resolve, reject) => {
|
|
2462
|
+
this.socket.write(frame, (err) => {
|
|
2463
|
+
if (err) reject(err);
|
|
2464
|
+
else resolve();
|
|
2465
|
+
});
|
|
2466
|
+
});
|
|
2467
|
+
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Read capability negotiation message
|
|
2470
|
+
*/
|
|
2471
|
+
async readCapabilityNegotiation() {
|
|
2472
|
+
return new Promise((resolve, reject) => {
|
|
2473
|
+
const timeout = setTimeout(() => {
|
|
2474
|
+
reject(/* @__PURE__ */ new Error("Capability negotiation timeout"));
|
|
2475
|
+
}, 5e3);
|
|
2476
|
+
const checkBuffer = () => {
|
|
2477
|
+
if (this.pendingBuffer.length < 4) {
|
|
2478
|
+
this.socket.listenerCount("data");
|
|
2479
|
+
const dataHandler = () => {
|
|
2480
|
+
this.socket.off("data", dataHandler);
|
|
2481
|
+
checkBuffer();
|
|
2482
|
+
};
|
|
2483
|
+
this.socket.once("data", dataHandler);
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
const length = this.pendingBuffer.readUInt32LE(0);
|
|
2487
|
+
if (this.pendingBuffer.length < 4 + length) {
|
|
2488
|
+
const dataHandler = () => {
|
|
2489
|
+
this.socket.off("data", dataHandler);
|
|
2490
|
+
checkBuffer();
|
|
2491
|
+
};
|
|
2492
|
+
this.socket.once("data", dataHandler);
|
|
2493
|
+
return;
|
|
2494
|
+
}
|
|
2495
|
+
clearTimeout(timeout);
|
|
2496
|
+
const capsData = this.pendingBuffer.subarray(4, 4 + length);
|
|
2497
|
+
this.pendingBuffer = this.pendingBuffer.subarray(4 + length);
|
|
2498
|
+
try {
|
|
2499
|
+
resolve(JSON.parse(capsData.toString("utf-8")));
|
|
2500
|
+
} catch (err) {
|
|
2501
|
+
reject(/* @__PURE__ */ new Error(`Failed to parse capability negotiation: ${err}`));
|
|
2502
|
+
}
|
|
2503
|
+
};
|
|
2504
|
+
checkBuffer();
|
|
2505
|
+
});
|
|
1907
2506
|
}
|
|
1908
2507
|
handleData(data) {
|
|
1909
2508
|
this.pendingBuffer = Buffer.concat([this.pendingBuffer, data]);
|
|
@@ -1919,14 +2518,50 @@ var TcpTransport = class TcpTransport {
|
|
|
1919
2518
|
}
|
|
1920
2519
|
const totalLength = 4 + this.pendingLength;
|
|
1921
2520
|
if (this.pendingBuffer.length < totalLength) break;
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
this.
|
|
2521
|
+
if (this.pendingBuffer.readUInt32LE(4) === FRAME_MAGIC && this.negotiationComplete) {
|
|
2522
|
+
if (this.pendingLength < 16) {
|
|
2523
|
+
this.onError?.(/* @__PURE__ */ new Error("Invalid compressed frame"));
|
|
2524
|
+
this.close(/* @__PURE__ */ new Error("Invalid compressed frame"));
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2527
|
+
const headerOffset = 4;
|
|
2528
|
+
const originalSize = this.pendingBuffer.readUInt32LE(headerOffset + 4);
|
|
2529
|
+
const compressedSize = this.pendingBuffer.readUInt32LE(headerOffset + 8);
|
|
2530
|
+
const algorithm = this.pendingBuffer.readUInt32LE(headerOffset + 12);
|
|
2531
|
+
const frameTotalLength = 20 + compressedSize;
|
|
2532
|
+
if (this.pendingBuffer.length < frameTotalLength) break;
|
|
2533
|
+
const compressedData = this.pendingBuffer.subarray(headerOffset + 16, frameTotalLength);
|
|
2534
|
+
this.pendingBuffer = this.pendingBuffer.subarray(frameTotalLength);
|
|
2535
|
+
this.hasPendingLength = false;
|
|
2536
|
+
try {
|
|
2537
|
+
let messageData;
|
|
2538
|
+
if (algorithm === ALGORITHM_LZ4) {
|
|
2539
|
+
const decompressed = decompress(compressedData, originalSize);
|
|
2540
|
+
if (!decompressed) throw new Error("LZ4 decompression failed");
|
|
2541
|
+
messageData = decompressed;
|
|
2542
|
+
this.compressionState.messagesDecompressed++;
|
|
2543
|
+
this.compressionState.bytesReceived += compressedData.length;
|
|
2544
|
+
this.compressionState.uncompressedBytesReceived += messageData.length;
|
|
2545
|
+
} else {
|
|
2546
|
+
messageData = new Uint8Array(compressedData);
|
|
2547
|
+
this.compressionState.bytesReceived += compressedData.length;
|
|
2548
|
+
this.compressionState.uncompressedBytesReceived += compressedData.length;
|
|
2549
|
+
}
|
|
2550
|
+
const message = deserializeRpcMessage(messageData);
|
|
2551
|
+
this.handleRpcMessage(message);
|
|
2552
|
+
} catch (err) {
|
|
2553
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
2554
|
+
}
|
|
2555
|
+
} else {
|
|
2556
|
+
const messageData = this.pendingBuffer.subarray(4, totalLength);
|
|
2557
|
+
this.pendingBuffer = this.pendingBuffer.subarray(totalLength);
|
|
2558
|
+
this.hasPendingLength = false;
|
|
2559
|
+
try {
|
|
2560
|
+
const message = deserializeRpcMessage(new Uint8Array(messageData));
|
|
2561
|
+
this.handleRpcMessage(message);
|
|
2562
|
+
} catch (err) {
|
|
2563
|
+
this.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
2564
|
+
}
|
|
1930
2565
|
}
|
|
1931
2566
|
}
|
|
1932
2567
|
}
|
|
@@ -1938,10 +2573,31 @@ var TcpTransport = class TcpTransport {
|
|
|
1938
2573
|
}
|
|
1939
2574
|
async send(message) {
|
|
1940
2575
|
if (!this.socket || this.socket.readyState !== "open") throw new Error("Socket not connected");
|
|
2576
|
+
if (!this.negotiationComplete) throw new Error("Capability negotiation not complete");
|
|
1941
2577
|
const data = serializeRpcMessage(message);
|
|
1942
|
-
const
|
|
1943
|
-
frame
|
|
1944
|
-
|
|
2578
|
+
const shouldCompress = this.compressionEnabled && data.length >= this.compressionConfig.thresholdBytes;
|
|
2579
|
+
let frame;
|
|
2580
|
+
if (shouldCompress) {
|
|
2581
|
+
const compressed = compress(data, { threshold: 0 });
|
|
2582
|
+
if (!compressed) throw new Error("Compression failed");
|
|
2583
|
+
const frameLength = 16 + compressed.length;
|
|
2584
|
+
frame = Buffer.allocUnsafe(4 + frameLength);
|
|
2585
|
+
frame.writeUInt32LE(frameLength, 0);
|
|
2586
|
+
frame.writeUInt32LE(FRAME_MAGIC, 4);
|
|
2587
|
+
frame.writeUInt32LE(data.length, 8);
|
|
2588
|
+
frame.writeUInt32LE(compressed.length, 12);
|
|
2589
|
+
frame.writeUInt32LE(ALGORITHM_LZ4, 16);
|
|
2590
|
+
frame.set(compressed, 20);
|
|
2591
|
+
this.compressionState.bytesSent += compressed.length;
|
|
2592
|
+
this.compressionState.uncompressedBytesSent += data.length;
|
|
2593
|
+
this.compressionState.messagesCompressed++;
|
|
2594
|
+
} else {
|
|
2595
|
+
frame = Buffer.allocUnsafe(4 + data.length);
|
|
2596
|
+
frame.writeUInt32LE(data.length, 0);
|
|
2597
|
+
frame.set(data, 4);
|
|
2598
|
+
this.compressionState.bytesSent += data.length;
|
|
2599
|
+
this.compressionState.uncompressedBytesSent += data.length;
|
|
2600
|
+
}
|
|
1945
2601
|
return new Promise((resolve, reject) => {
|
|
1946
2602
|
this.socket.write(frame, (err) => {
|
|
1947
2603
|
if (err) reject(err);
|
|
@@ -2009,6 +2665,18 @@ var EzRpcTransport = class EzRpcTransport {
|
|
|
2009
2665
|
get connected() {
|
|
2010
2666
|
return this._connected && this.socket !== null && !this.socket.destroyed;
|
|
2011
2667
|
}
|
|
2668
|
+
getCompressionState() {
|
|
2669
|
+
return {
|
|
2670
|
+
enabled: false,
|
|
2671
|
+
algorithm: "none",
|
|
2672
|
+
bytesSent: 0,
|
|
2673
|
+
bytesReceived: 0,
|
|
2674
|
+
uncompressedBytesSent: 0,
|
|
2675
|
+
uncompressedBytesReceived: 0,
|
|
2676
|
+
messagesCompressed: 0,
|
|
2677
|
+
messagesDecompressed: 0
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2012
2680
|
doConnect() {
|
|
2013
2681
|
return new Promise((resolve, reject) => {
|
|
2014
2682
|
const timeout = setTimeout(() => {
|
|
@@ -9783,6 +10451,131 @@ var import_sender = /* @__PURE__ */ __toESM(require_sender(), 1);
|
|
|
9783
10451
|
var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
|
|
9784
10452
|
var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server(), 1);
|
|
9785
10453
|
|
|
10454
|
+
//#endregion
|
|
10455
|
+
//#region src/compression/frame.ts
|
|
10456
|
+
/**
|
|
10457
|
+
* LZ4 Frame Format Module
|
|
10458
|
+
*
|
|
10459
|
+
* Frame format: Magic(4) + Flags(1) + Length(4) + Payload
|
|
10460
|
+
* - Magic: 0x4C5A3401 (LZ4\0\x01)
|
|
10461
|
+
* - Flags: compression options and metadata
|
|
10462
|
+
* - Length: uncompressed data length (4 bytes, little-endian)
|
|
10463
|
+
* - Payload: compressed or uncompressed data
|
|
10464
|
+
*/
|
|
10465
|
+
/**
|
|
10466
|
+
* Frame format constants
|
|
10467
|
+
*/
|
|
10468
|
+
const LZ4_FRAME_MAGIC = 1280979969;
|
|
10469
|
+
const LZ4_FRAME_HEADER_SIZE = 9;
|
|
10470
|
+
/**
|
|
10471
|
+
* Frame flags
|
|
10472
|
+
*/
|
|
10473
|
+
let FrameFlags = /* @__PURE__ */ function(FrameFlags) {
|
|
10474
|
+
/** Data is compressed */
|
|
10475
|
+
FrameFlags[FrameFlags["COMPRESSED"] = 1] = "COMPRESSED";
|
|
10476
|
+
/** Reserved for future use */
|
|
10477
|
+
FrameFlags[FrameFlags["RESERVED_1"] = 2] = "RESERVED_1";
|
|
10478
|
+
/** Reserved for future use */
|
|
10479
|
+
FrameFlags[FrameFlags["RESERVED_2"] = 4] = "RESERVED_2";
|
|
10480
|
+
/** Reserved for future use */
|
|
10481
|
+
FrameFlags[FrameFlags["RESERVED_3"] = 8] = "RESERVED_3";
|
|
10482
|
+
/** Reserved for future use */
|
|
10483
|
+
FrameFlags[FrameFlags["RESERVED_4"] = 16] = "RESERVED_4";
|
|
10484
|
+
/** Reserved for future use */
|
|
10485
|
+
FrameFlags[FrameFlags["RESERVED_5"] = 32] = "RESERVED_5";
|
|
10486
|
+
/** Reserved for future use */
|
|
10487
|
+
FrameFlags[FrameFlags["RESERVED_6"] = 64] = "RESERVED_6";
|
|
10488
|
+
/** Reserved for future use */
|
|
10489
|
+
FrameFlags[FrameFlags["RESERVED_7"] = 128] = "RESERVED_7";
|
|
10490
|
+
return FrameFlags;
|
|
10491
|
+
}({});
|
|
10492
|
+
/**
|
|
10493
|
+
* Check if data has LZ4 frame magic header
|
|
10494
|
+
*/
|
|
10495
|
+
function hasFrameMagic(data) {
|
|
10496
|
+
if (data.length < 4) return false;
|
|
10497
|
+
return new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(0, true) === LZ4_FRAME_MAGIC;
|
|
10498
|
+
}
|
|
10499
|
+
/**
|
|
10500
|
+
* Parse frame header from data
|
|
10501
|
+
* @returns FrameHeader if valid, null otherwise
|
|
10502
|
+
*/
|
|
10503
|
+
function parseFrameHeader(data) {
|
|
10504
|
+
if (data.length < LZ4_FRAME_HEADER_SIZE) return null;
|
|
10505
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
10506
|
+
const magic = view.getUint32(0, true);
|
|
10507
|
+
if (magic !== LZ4_FRAME_MAGIC) return null;
|
|
10508
|
+
return {
|
|
10509
|
+
magic,
|
|
10510
|
+
flags: view.getUint8(4),
|
|
10511
|
+
length: view.getUint32(5, true)
|
|
10512
|
+
};
|
|
10513
|
+
}
|
|
10514
|
+
/**
|
|
10515
|
+
* Decompress framed data
|
|
10516
|
+
* @param data - Framed data (with or without frame header)
|
|
10517
|
+
* @param decompressFn - Decompression function for compressed payloads
|
|
10518
|
+
* @returns Decompressed data, or null if invalid
|
|
10519
|
+
*/
|
|
10520
|
+
function decompressFrame(data, decompressFn) {
|
|
10521
|
+
const header = parseFrameHeader(data);
|
|
10522
|
+
if (!header) return data;
|
|
10523
|
+
const payloadOffset = LZ4_FRAME_HEADER_SIZE;
|
|
10524
|
+
if (data.length - payloadOffset < 0) return null;
|
|
10525
|
+
const payload = data.subarray(payloadOffset);
|
|
10526
|
+
if (header.flags & FrameFlags.COMPRESSED) return decompressFn(payload, header.length);
|
|
10527
|
+
return payload;
|
|
10528
|
+
}
|
|
10529
|
+
|
|
10530
|
+
//#endregion
|
|
10531
|
+
//#region src/compression/index.ts
|
|
10532
|
+
/**
|
|
10533
|
+
* Create default compression config
|
|
10534
|
+
*/
|
|
10535
|
+
function createCompressionConfig(config) {
|
|
10536
|
+
return {
|
|
10537
|
+
enabled: false,
|
|
10538
|
+
algorithm: "lz4",
|
|
10539
|
+
threshold: 1024,
|
|
10540
|
+
level: 0,
|
|
10541
|
+
highCompression: false,
|
|
10542
|
+
...config
|
|
10543
|
+
};
|
|
10544
|
+
}
|
|
10545
|
+
/**
|
|
10546
|
+
* Create empty compression stats
|
|
10547
|
+
*/
|
|
10548
|
+
function createCompressionStats() {
|
|
10549
|
+
return {
|
|
10550
|
+
messagesCompressed: 0,
|
|
10551
|
+
messagesDecompressed: 0,
|
|
10552
|
+
bytesOriginal: 0,
|
|
10553
|
+
bytesCompressed: 0,
|
|
10554
|
+
compressionRatio: 1,
|
|
10555
|
+
savingsPercent: 0
|
|
10556
|
+
};
|
|
10557
|
+
}
|
|
10558
|
+
/**
|
|
10559
|
+
* Check if data is a compression frame (has LZ4 magic)
|
|
10560
|
+
* Works with both Buffer and Uint8Array
|
|
10561
|
+
*/
|
|
10562
|
+
function isCompressionFrame(data) {
|
|
10563
|
+
return hasFrameMagic(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
10564
|
+
}
|
|
10565
|
+
/**
|
|
10566
|
+
* Try to decompress, return original if not compressed or decompression fails
|
|
10567
|
+
* Works with both Buffer and Uint8Array
|
|
10568
|
+
* Assumes data has LZ4 frame header (created by compressFrame)
|
|
10569
|
+
*/
|
|
10570
|
+
function tryDecompress(data) {
|
|
10571
|
+
const uint8Data = data instanceof Buffer ? new Uint8Array(data.buffer, data.byteOffset, data.byteLength) : data;
|
|
10572
|
+
return decompressFrame(uint8Data, uncompress) ?? uint8Data;
|
|
10573
|
+
}
|
|
10574
|
+
/**
|
|
10575
|
+
* Default compression configuration
|
|
10576
|
+
*/
|
|
10577
|
+
const DEFAULT_COMPRESSION_CONFIG = createCompressionConfig();
|
|
10578
|
+
|
|
9786
10579
|
//#endregion
|
|
9787
10580
|
//#region src/proxy/websocket-proxy.ts
|
|
9788
10581
|
/**
|
|
@@ -9791,6 +10584,27 @@ var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server()
|
|
|
9791
10584
|
* Allows browsers to connect to native Cap'n Proto services (C++, etc.)
|
|
9792
10585
|
* via WebSocket. Handles the protocol bridging between WebSocket (browser)
|
|
9793
10586
|
* and raw TCP (Cap'n Proto services).
|
|
10587
|
+
*
|
|
10588
|
+
* Features:
|
|
10589
|
+
* - Independent compression configuration for WebSocket and TCP sides
|
|
10590
|
+
* - Automatic compression/decompression bridging
|
|
10591
|
+
* - Support for different compression settings on each side
|
|
10592
|
+
* - Backward compatibility with non-compressed peers
|
|
10593
|
+
*/
|
|
10594
|
+
/**
|
|
10595
|
+
* Convert Buffer to Uint8Array without copying if possible
|
|
10596
|
+
*/
|
|
10597
|
+
function bufferToUint8Array(buffer) {
|
|
10598
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
10599
|
+
}
|
|
10600
|
+
/**
|
|
10601
|
+
* Convert Uint8Array to Buffer without copying if possible
|
|
10602
|
+
*/
|
|
10603
|
+
function uint8ArrayToBuffer(arr) {
|
|
10604
|
+
return Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
10605
|
+
}
|
|
10606
|
+
/**
|
|
10607
|
+
* Represents a single proxy connection between WebSocket client and TCP server
|
|
9794
10608
|
*/
|
|
9795
10609
|
var ProxyConnection = class extends node_events.EventEmitter {
|
|
9796
10610
|
ws;
|
|
@@ -9798,16 +10612,22 @@ var ProxyConnection = class extends node_events.EventEmitter {
|
|
|
9798
10612
|
stats;
|
|
9799
10613
|
options;
|
|
9800
10614
|
closed = false;
|
|
10615
|
+
wsCompressionConfig;
|
|
10616
|
+
tcpCompressionConfig;
|
|
9801
10617
|
constructor(ws, options) {
|
|
9802
10618
|
super();
|
|
9803
10619
|
this.ws = ws;
|
|
9804
10620
|
this.options = options;
|
|
10621
|
+
this.wsCompressionConfig = createCompressionConfig(options.compression?.ws);
|
|
10622
|
+
this.tcpCompressionConfig = createCompressionConfig(options.compression?.tcp);
|
|
9805
10623
|
this.stats = {
|
|
9806
10624
|
wsMessagesIn: 0,
|
|
9807
10625
|
wsMessagesOut: 0,
|
|
9808
10626
|
tcpBytesIn: 0,
|
|
9809
10627
|
tcpBytesOut: 0,
|
|
9810
|
-
connectedAt: /* @__PURE__ */ new Date()
|
|
10628
|
+
connectedAt: /* @__PURE__ */ new Date(),
|
|
10629
|
+
wsCompression: createCompressionStats(),
|
|
10630
|
+
tcpCompression: createCompressionStats()
|
|
9811
10631
|
};
|
|
9812
10632
|
this.setupWebSocket();
|
|
9813
10633
|
}
|
|
@@ -9835,6 +10655,7 @@ var ProxyConnection = class extends node_events.EventEmitter {
|
|
|
9835
10655
|
});
|
|
9836
10656
|
this.tcpSocket.on("connect", () => {
|
|
9837
10657
|
this.log("Connected to target TCP service");
|
|
10658
|
+
this.log(`Compression - WS: ${this.wsCompressionConfig.enabled ? "enabled" : "disabled"}, TCP: ${this.tcpCompressionConfig.enabled ? "enabled" : "disabled"}`);
|
|
9838
10659
|
this.emit("connected");
|
|
9839
10660
|
});
|
|
9840
10661
|
this.tcpSocket.on("data", (data) => {
|
|
@@ -9854,29 +10675,78 @@ var ProxyConnection = class extends node_events.EventEmitter {
|
|
|
9854
10675
|
this.close();
|
|
9855
10676
|
});
|
|
9856
10677
|
}
|
|
10678
|
+
/**
|
|
10679
|
+
* Handle incoming message from WebSocket client
|
|
10680
|
+
* - Decompress if compressed (from browser)
|
|
10681
|
+
* - Re-compress for TCP side if TCP compression is enabled
|
|
10682
|
+
* - Forward to TCP server
|
|
10683
|
+
*/
|
|
9857
10684
|
handleWebSocketMessage(data) {
|
|
9858
10685
|
if (this.closed) return;
|
|
9859
10686
|
const buffer = Buffer.isBuffer(data) ? data : Array.isArray(data) ? Buffer.concat(data) : Buffer.from(data);
|
|
9860
10687
|
const maxSize = this.options.maxMessageSize ?? 16 * 1024 * 1024;
|
|
9861
|
-
|
|
9862
|
-
|
|
10688
|
+
const uint8Data = bufferToUint8Array(buffer);
|
|
10689
|
+
const frameInfo = parseFrameHeader(uint8Data);
|
|
10690
|
+
const uncompressedSize = frameInfo ? frameInfo.length : buffer.length;
|
|
10691
|
+
if (uncompressedSize > maxSize) {
|
|
10692
|
+
this.log(`Message too large: ${uncompressedSize} bytes (max: ${maxSize})`);
|
|
9863
10693
|
this.close();
|
|
9864
10694
|
return;
|
|
9865
10695
|
}
|
|
9866
10696
|
this.stats.wsMessagesIn++;
|
|
9867
|
-
|
|
10697
|
+
let decompressedData;
|
|
10698
|
+
if (hasFrameMagic(uint8Data)) {
|
|
10699
|
+
const decompressed = decompressFrame(uint8Data, uncompress);
|
|
10700
|
+
if (decompressed !== null) {
|
|
10701
|
+
decompressedData = decompressed;
|
|
10702
|
+
this.log(`Decompressed WS message: ${buffer.length} -> ${decompressedData.length} bytes`);
|
|
10703
|
+
} else decompressedData = uint8Data;
|
|
10704
|
+
} else decompressedData = uint8Data;
|
|
10705
|
+
let dataToSend = decompressedData;
|
|
10706
|
+
if (this.tcpCompressionConfig.enabled) {
|
|
10707
|
+
const compressed = compress(decompressedData, { threshold: this.tcpCompressionConfig.threshold });
|
|
10708
|
+
if (compressed !== null) {
|
|
10709
|
+
dataToSend = compressed;
|
|
10710
|
+
this.log(`Compressed for TCP: ${decompressedData.length} -> ${dataToSend.length} bytes`);
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10713
|
+
this.stats.tcpBytesOut += uint8ArrayToBuffer(dataToSend).length;
|
|
9868
10714
|
if (this.tcpSocket?.writable) {
|
|
9869
|
-
|
|
9870
|
-
this.
|
|
10715
|
+
const bufferToSend = uint8ArrayToBuffer(dataToSend);
|
|
10716
|
+
this.tcpSocket.write(bufferToSend);
|
|
10717
|
+
this.log(`Forwarded ${dataToSend.length} bytes to TCP (original: ${decompressedData.length})`);
|
|
9871
10718
|
}
|
|
9872
10719
|
}
|
|
10720
|
+
/**
|
|
10721
|
+
* Handle incoming data from TCP server
|
|
10722
|
+
* - Decompress if compressed (from native Cap'n Proto service)
|
|
10723
|
+
* - Re-compress for WebSocket side if WS compression is enabled
|
|
10724
|
+
* - Forward to WebSocket client
|
|
10725
|
+
*/
|
|
9873
10726
|
handleTcpData(data) {
|
|
9874
10727
|
if (this.closed) return;
|
|
9875
10728
|
this.stats.tcpBytesIn += data.length;
|
|
10729
|
+
const uint8Data = bufferToUint8Array(data);
|
|
10730
|
+
let decompressedData;
|
|
10731
|
+
if (hasFrameMagic(uint8Data)) {
|
|
10732
|
+
const decompressed = decompressFrame(uint8Data, uncompress);
|
|
10733
|
+
if (decompressed !== null) {
|
|
10734
|
+
decompressedData = decompressed;
|
|
10735
|
+
this.log(`Decompressed TCP message: ${data.length} -> ${decompressedData.length} bytes`);
|
|
10736
|
+
} else decompressedData = uint8Data;
|
|
10737
|
+
} else decompressedData = uint8Data;
|
|
10738
|
+
let dataToSend = decompressedData;
|
|
10739
|
+
if (this.wsCompressionConfig.enabled) {
|
|
10740
|
+
const compressed = compress(decompressedData, { threshold: this.wsCompressionConfig.threshold });
|
|
10741
|
+
if (compressed !== null) {
|
|
10742
|
+
dataToSend = compressed;
|
|
10743
|
+
this.log(`Compressed for WS: ${decompressedData.length} -> ${dataToSend.length} bytes`);
|
|
10744
|
+
}
|
|
10745
|
+
}
|
|
9876
10746
|
this.stats.wsMessagesOut++;
|
|
9877
10747
|
if (this.ws.readyState === import_websocket.default.OPEN) {
|
|
9878
|
-
this.ws.send(
|
|
9879
|
-
this.log(`Forwarded ${
|
|
10748
|
+
this.ws.send(dataToSend);
|
|
10749
|
+
this.log(`Forwarded ${dataToSend.length} bytes to WebSocket (original: ${decompressedData.length})`);
|
|
9880
10750
|
}
|
|
9881
10751
|
}
|
|
9882
10752
|
log(...args) {
|
|
@@ -9893,6 +10763,10 @@ var ProxyConnection = class extends node_events.EventEmitter {
|
|
|
9893
10763
|
this.emit("closed");
|
|
9894
10764
|
}
|
|
9895
10765
|
};
|
|
10766
|
+
/**
|
|
10767
|
+
* WebSocket-to-TCP Proxy server
|
|
10768
|
+
* Manages multiple proxy connections
|
|
10769
|
+
*/
|
|
9896
10770
|
var CapnpWebSocketProxy = class extends node_events.EventEmitter {
|
|
9897
10771
|
wss;
|
|
9898
10772
|
connections = /* @__PURE__ */ new Map();
|
|
@@ -9950,6 +10824,9 @@ if (require("url").pathToFileURL(__filename).href === `file://${process.argv[1]}
|
|
|
9950
10824
|
let targetHost = "localhost";
|
|
9951
10825
|
let targetPort = 8081;
|
|
9952
10826
|
let debug = false;
|
|
10827
|
+
let wsCompression = false;
|
|
10828
|
+
let tcpCompression = false;
|
|
10829
|
+
let compressionThreshold = 1024;
|
|
9953
10830
|
for (let i = 0; i < args.length; i++) switch (args[i]) {
|
|
9954
10831
|
case "--ws-port":
|
|
9955
10832
|
case "-p":
|
|
@@ -9966,6 +10843,17 @@ if (require("url").pathToFileURL(__filename).href === `file://${process.argv[1]}
|
|
|
9966
10843
|
case "-d":
|
|
9967
10844
|
debug = true;
|
|
9968
10845
|
break;
|
|
10846
|
+
case "--ws-compression":
|
|
10847
|
+
case "-w":
|
|
10848
|
+
wsCompression = true;
|
|
10849
|
+
break;
|
|
10850
|
+
case "--tcp-compression":
|
|
10851
|
+
case "-c":
|
|
10852
|
+
tcpCompression = true;
|
|
10853
|
+
break;
|
|
10854
|
+
case "--compression-threshold":
|
|
10855
|
+
compressionThreshold = Number.parseInt(args[++i], 10);
|
|
10856
|
+
break;
|
|
9969
10857
|
case "--help":
|
|
9970
10858
|
case "-h":
|
|
9971
10859
|
console.log(`
|
|
@@ -9974,13 +10862,25 @@ Cap'n Proto WebSocket-to-TCP Proxy
|
|
|
9974
10862
|
Usage: npx @naeemo/capnp proxy [options]
|
|
9975
10863
|
|
|
9976
10864
|
Options:
|
|
9977
|
-
-p, --ws-port <port>
|
|
9978
|
-
-t, --target <host:port>
|
|
9979
|
-
-d, --debug
|
|
9980
|
-
-
|
|
10865
|
+
-p, --ws-port <port> WebSocket server port (default: 8080)
|
|
10866
|
+
-t, --target <host:port> Target TCP service (default: localhost:8081)
|
|
10867
|
+
-d, --debug Enable debug logging
|
|
10868
|
+
-w, --ws-compression Enable WebSocket side compression
|
|
10869
|
+
-c, --tcp-compression Enable TCP side compression
|
|
10870
|
+
--compression-threshold <n> Minimum size to compress (default: 1024)
|
|
10871
|
+
-h, --help Show this help
|
|
9981
10872
|
|
|
9982
|
-
|
|
10873
|
+
Examples:
|
|
9983
10874
|
npx @naeemo/capnp proxy -p 9000 -t 192.168.1.100:7000
|
|
10875
|
+
|
|
10876
|
+
# Enable compression on WebSocket side only (for browser clients)
|
|
10877
|
+
npx @naeemo/capnp proxy -p 9000 -t localhost:7000 -w
|
|
10878
|
+
|
|
10879
|
+
# Enable compression on both sides
|
|
10880
|
+
npx @naeemo/capnp proxy -p 9000 -t localhost:7000 -w -c
|
|
10881
|
+
|
|
10882
|
+
# Enable compression with lower threshold
|
|
10883
|
+
npx @naeemo/capnp proxy -p 9000 -t localhost:7000 -w --compression-threshold 512
|
|
9984
10884
|
`);
|
|
9985
10885
|
process.exit(0);
|
|
9986
10886
|
}
|
|
@@ -9988,11 +10888,26 @@ Example:
|
|
|
9988
10888
|
wsPort,
|
|
9989
10889
|
targetHost,
|
|
9990
10890
|
targetPort,
|
|
9991
|
-
debug
|
|
10891
|
+
debug,
|
|
10892
|
+
compression: {
|
|
10893
|
+
ws: {
|
|
10894
|
+
enabled: wsCompression,
|
|
10895
|
+
threshold: compressionThreshold
|
|
10896
|
+
},
|
|
10897
|
+
tcp: {
|
|
10898
|
+
enabled: tcpCompression,
|
|
10899
|
+
threshold: compressionThreshold
|
|
10900
|
+
}
|
|
10901
|
+
}
|
|
9992
10902
|
});
|
|
9993
10903
|
console.log("WebSocket-to-TCP Proxy started");
|
|
9994
10904
|
console.log(` WebSocket: ws://localhost:${wsPort}`);
|
|
9995
10905
|
console.log(` Target: ${targetHost}:${targetPort}`);
|
|
10906
|
+
if (wsCompression || tcpCompression) {
|
|
10907
|
+
console.log(" Compression:");
|
|
10908
|
+
console.log(` WebSocket: ${wsCompression ? "enabled" : "disabled"} (threshold: ${compressionThreshold})`);
|
|
10909
|
+
console.log(` TCP: ${tcpCompression ? "enabled" : "disabled"} (threshold: ${compressionThreshold})`);
|
|
10910
|
+
}
|
|
9996
10911
|
proxy.on("connection", () => {
|
|
9997
10912
|
console.log(`Active connections: ${proxy.getConnectionCount()}`);
|
|
9998
10913
|
});
|
|
@@ -10014,6 +10929,7 @@ exports.BulkTransferManager = BulkTransferManager;
|
|
|
10014
10929
|
exports.CapnpWebSocketProxy = CapnpWebSocketProxy;
|
|
10015
10930
|
exports.ConnectionManager = ConnectionManager;
|
|
10016
10931
|
exports.DEFAULT_BULK_CONFIG = DEFAULT_BULK_CONFIG;
|
|
10932
|
+
exports.DEFAULT_COMPRESSION_CONFIG = DEFAULT_COMPRESSION_CONFIG;
|
|
10017
10933
|
exports.DEFAULT_ESCROW_CONFIG = DEFAULT_ESCROW_CONFIG;
|
|
10018
10934
|
exports.DEFAULT_FLOW_CONTROL = DEFAULT_FLOW_CONTROL;
|
|
10019
10935
|
exports.DEFAULT_JOIN_OPTIONS = DEFAULT_JOIN_OPTIONS;
|
|
@@ -10024,6 +10940,7 @@ exports.DropPolicy = DropPolicy;
|
|
|
10024
10940
|
exports.ElementSize = ElementSize;
|
|
10025
10941
|
exports.ExportTable = require_rpc_connection.ExportTable;
|
|
10026
10942
|
exports.EzRpcTransport = EzRpcTransport;
|
|
10943
|
+
exports.FrameFlags = FrameFlags;
|
|
10027
10944
|
exports.ImportTable = require_rpc_connection.ImportTable;
|
|
10028
10945
|
exports.Level3Handlers = Level3Handlers;
|
|
10029
10946
|
exports.Level4Handlers = Level4Handlers;
|
|
@@ -10062,8 +10979,11 @@ exports.UnionBuilder = UnionBuilder;
|
|
|
10062
10979
|
exports.UnionReader = UnionReader;
|
|
10063
10980
|
exports.WORD_SIZE = WORD_SIZE;
|
|
10064
10981
|
exports.WebSocketTransport = WebSocketTransport;
|
|
10982
|
+
exports.compress = compress;
|
|
10065
10983
|
exports.configureGlobalMemoryPool = configureGlobalMemoryPool;
|
|
10066
10984
|
exports.createBulkTransferManager = createBulkTransferManager;
|
|
10985
|
+
exports.createCompressionConfig = createCompressionConfig;
|
|
10986
|
+
exports.createCompressionStats = createCompressionStats;
|
|
10067
10987
|
exports.createDynamicReader = createDynamicReader;
|
|
10068
10988
|
exports.createDynamicReaderByTypeId = createDynamicReaderByTypeId;
|
|
10069
10989
|
exports.createDynamicReaderFromStruct = createDynamicReaderFromStruct;
|
|
@@ -10091,17 +11011,20 @@ exports.deserializeSturdyRef = deserializeSturdyRef;
|
|
|
10091
11011
|
exports.disableDebug = require_rpc_connection.disableDebug;
|
|
10092
11012
|
exports.dumpDynamicReader = dumpDynamicReader;
|
|
10093
11013
|
exports.enableDebug = require_rpc_connection.enableDebug;
|
|
11014
|
+
exports.encodeFarPointer = encodeFarPointer;
|
|
10094
11015
|
exports.encodeListPointer = encodeListPointer;
|
|
10095
11016
|
exports.encodeStructPointer = encodeStructPointer;
|
|
10096
11017
|
exports.fastCopy = fastCopy;
|
|
10097
11018
|
exports.generateProvisionId = generateProvisionId;
|
|
10098
11019
|
exports.generateVatId = generateVatId;
|
|
10099
11020
|
exports.getGlobalMemoryPool = getGlobalMemoryPool;
|
|
11021
|
+
exports.isCompressionFrame = isCompressionFrame;
|
|
10100
11022
|
exports.isDebugEnabled = require_rpc_connection.isDebugEnabled;
|
|
10101
11023
|
exports.isPipelineClient = require_rpc_connection.isPipelineClient;
|
|
10102
11024
|
exports.isSameBuffer = isSameBuffer;
|
|
10103
11025
|
exports.isStream = isStream;
|
|
10104
11026
|
exports.isSturdyRefValid = isSturdyRefValid;
|
|
11027
|
+
exports.parseFrameHeader = parseFrameHeader;
|
|
10105
11028
|
exports.parseSchemaNodes = require_rpc_connection.parseSchemaNodes;
|
|
10106
11029
|
exports.serializeDynamic = serializeDynamic;
|
|
10107
11030
|
exports.serializeDynamicByTypeId = serializeDynamicByTypeId;
|
|
@@ -10113,4 +11036,6 @@ exports.serializeSchemaRequest = require_rpc_connection.serializeSchemaRequest;
|
|
|
10113
11036
|
exports.serializeSchemaResponse = require_rpc_connection.serializeSchemaResponse;
|
|
10114
11037
|
exports.serializeSturdyRef = serializeSturdyRef;
|
|
10115
11038
|
exports.supportsStreaming = supportsStreaming;
|
|
11039
|
+
exports.tryDecompress = tryDecompress;
|
|
11040
|
+
exports.uncompress = uncompress;
|
|
10116
11041
|
//# sourceMappingURL=index.cjs.map
|