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