connectbase-client 3.7.1 → 3.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +156 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1456,6 +1456,129 @@ function createWsBinaryFrame(payload) {
|
|
|
1456
1456
|
}
|
|
1457
1457
|
return Buffer.concat([header, maskKey, masked]);
|
|
1458
1458
|
}
|
|
1459
|
+
var UpstreamWsFrameParser = class {
|
|
1460
|
+
constructor(handlers) {
|
|
1461
|
+
this.buffer = Buffer.alloc(0);
|
|
1462
|
+
this.fragmentBuffer = null;
|
|
1463
|
+
this.h = handlers;
|
|
1464
|
+
}
|
|
1465
|
+
feed(chunk) {
|
|
1466
|
+
this.buffer = Buffer.concat([this.buffer, chunk]);
|
|
1467
|
+
try {
|
|
1468
|
+
this.parse();
|
|
1469
|
+
} catch (e) {
|
|
1470
|
+
this.h.onError(e instanceof Error ? e : new Error(String(e)));
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
parse() {
|
|
1474
|
+
while (this.buffer.length >= 2) {
|
|
1475
|
+
const firstByte = this.buffer[0];
|
|
1476
|
+
const secondByte = this.buffer[1];
|
|
1477
|
+
const fin = (firstByte & 128) !== 0;
|
|
1478
|
+
const rsv1 = (firstByte & 64) !== 0;
|
|
1479
|
+
const opcode = firstByte & 15;
|
|
1480
|
+
const isMasked = (secondByte & 128) !== 0;
|
|
1481
|
+
let payloadLen = secondByte & 127;
|
|
1482
|
+
let offset = 2;
|
|
1483
|
+
if (payloadLen === 126) {
|
|
1484
|
+
if (this.buffer.length < 4) return;
|
|
1485
|
+
payloadLen = this.buffer.readUInt16BE(2);
|
|
1486
|
+
offset = 4;
|
|
1487
|
+
} else if (payloadLen === 127) {
|
|
1488
|
+
if (this.buffer.length < 10) return;
|
|
1489
|
+
const big = this.buffer.readBigUInt64BE(2);
|
|
1490
|
+
if (big > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
1491
|
+
throw new Error(`payload too large: ${big}`);
|
|
1492
|
+
}
|
|
1493
|
+
payloadLen = Number(big);
|
|
1494
|
+
offset = 10;
|
|
1495
|
+
}
|
|
1496
|
+
let maskKey = null;
|
|
1497
|
+
if (isMasked) {
|
|
1498
|
+
if (this.buffer.length < offset + 4) return;
|
|
1499
|
+
maskKey = this.buffer.subarray(offset, offset + 4);
|
|
1500
|
+
offset += 4;
|
|
1501
|
+
}
|
|
1502
|
+
if (this.buffer.length < offset + payloadLen) return;
|
|
1503
|
+
if (rsv1 && (opcode === 1 || opcode === 2 || opcode === 0)) {
|
|
1504
|
+
throw new Error("upstream sent compressed (RSV1) frame without negotiation");
|
|
1505
|
+
}
|
|
1506
|
+
let payload = this.buffer.subarray(offset, offset + payloadLen);
|
|
1507
|
+
if (maskKey) {
|
|
1508
|
+
const unmasked = Buffer.alloc(payloadLen);
|
|
1509
|
+
for (let i = 0; i < payloadLen; i++) {
|
|
1510
|
+
unmasked[i] = payload[i] ^ maskKey[i % 4];
|
|
1511
|
+
}
|
|
1512
|
+
payload = unmasked;
|
|
1513
|
+
}
|
|
1514
|
+
this.buffer = this.buffer.subarray(offset + payloadLen);
|
|
1515
|
+
const payloadCopy = Buffer.from(payload);
|
|
1516
|
+
switch (opcode) {
|
|
1517
|
+
case 0:
|
|
1518
|
+
if (this.fragmentBuffer == null) {
|
|
1519
|
+
throw new Error("continuation frame without preceding non-final data frame");
|
|
1520
|
+
}
|
|
1521
|
+
this.fragmentBuffer = Buffer.concat([this.fragmentBuffer, payloadCopy]);
|
|
1522
|
+
if (fin) {
|
|
1523
|
+
const out = this.fragmentBuffer;
|
|
1524
|
+
this.fragmentBuffer = null;
|
|
1525
|
+
this.h.onPayload(out);
|
|
1526
|
+
}
|
|
1527
|
+
break;
|
|
1528
|
+
case 1:
|
|
1529
|
+
// TEXT
|
|
1530
|
+
case 2:
|
|
1531
|
+
if (fin) {
|
|
1532
|
+
this.h.onPayload(payloadCopy);
|
|
1533
|
+
} else {
|
|
1534
|
+
this.fragmentBuffer = payloadCopy;
|
|
1535
|
+
}
|
|
1536
|
+
break;
|
|
1537
|
+
case 8:
|
|
1538
|
+
this.h.onClose();
|
|
1539
|
+
break;
|
|
1540
|
+
case 9:
|
|
1541
|
+
this.h.onPing(payloadCopy);
|
|
1542
|
+
break;
|
|
1543
|
+
case 10:
|
|
1544
|
+
break;
|
|
1545
|
+
default:
|
|
1546
|
+
throw new Error(`unknown WS opcode 0x${opcode.toString(16)}`);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
function createUpstreamTextFrame(payload) {
|
|
1552
|
+
return buildClientFrame(129, payload);
|
|
1553
|
+
}
|
|
1554
|
+
function createUpstreamPongFrame(payload) {
|
|
1555
|
+
return buildClientFrame(138, payload);
|
|
1556
|
+
}
|
|
1557
|
+
function buildClientFrame(firstByte, payload) {
|
|
1558
|
+
const len = payload.length;
|
|
1559
|
+
const maskKey = crypto.randomBytes(4);
|
|
1560
|
+
let header;
|
|
1561
|
+
if (len < 126) {
|
|
1562
|
+
header = Buffer.alloc(2);
|
|
1563
|
+
header[0] = firstByte;
|
|
1564
|
+
header[1] = 128 | len;
|
|
1565
|
+
} else if (len < 65536) {
|
|
1566
|
+
header = Buffer.alloc(4);
|
|
1567
|
+
header[0] = firstByte;
|
|
1568
|
+
header[1] = 128 | 126;
|
|
1569
|
+
header.writeUInt16BE(len, 2);
|
|
1570
|
+
} else {
|
|
1571
|
+
header = Buffer.alloc(10);
|
|
1572
|
+
header[0] = firstByte;
|
|
1573
|
+
header[1] = 128 | 127;
|
|
1574
|
+
header.writeBigUInt64BE(BigInt(len), 2);
|
|
1575
|
+
}
|
|
1576
|
+
const masked = Buffer.alloc(len);
|
|
1577
|
+
for (let i = 0; i < len; i++) {
|
|
1578
|
+
masked[i] = payload[i] ^ maskKey[i % 4];
|
|
1579
|
+
}
|
|
1580
|
+
return Buffer.concat([header, maskKey, masked]);
|
|
1581
|
+
}
|
|
1459
1582
|
var WsFrameParser = class {
|
|
1460
1583
|
constructor(handlers) {
|
|
1461
1584
|
this.buffer = Buffer.alloc(0);
|
|
@@ -1951,7 +2074,10 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1951
2074
|
const fullPath = query ? `${reqPath}?${query}` : reqPath;
|
|
1952
2075
|
const localHeaders = {};
|
|
1953
2076
|
for (const [k, v] of Object.entries(headers)) {
|
|
1954
|
-
|
|
2077
|
+
const lk = k.toLowerCase();
|
|
2078
|
+
if (lk === "host") continue;
|
|
2079
|
+
if (lk === "sec-websocket-extensions") continue;
|
|
2080
|
+
localHeaders[k] = v;
|
|
1955
2081
|
}
|
|
1956
2082
|
localHeaders["host"] = `localhost:${localPort}`;
|
|
1957
2083
|
localHeaders["connection"] = "Upgrade";
|
|
@@ -1980,9 +2106,28 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1980
2106
|
websocket: true
|
|
1981
2107
|
});
|
|
1982
2108
|
log(`${colors.dim}${(/* @__PURE__ */ new Date()).toLocaleTimeString()}${colors.reset} ${colors.cyan}WS${colors.reset} ${reqPath} \u2192 101`);
|
|
2109
|
+
const upstreamParser = new UpstreamWsFrameParser({
|
|
2110
|
+
onPayload: (payload) => {
|
|
2111
|
+
if (cancelled) return;
|
|
2112
|
+
sendBinary(sock, streamId, payload);
|
|
2113
|
+
},
|
|
2114
|
+
onPing: (payload) => {
|
|
2115
|
+
if (cancelled || !upstream) return;
|
|
2116
|
+
upstream.write(createUpstreamPongFrame(payload));
|
|
2117
|
+
},
|
|
2118
|
+
onClose: () => {
|
|
2119
|
+
if (cancelled) return;
|
|
2120
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId });
|
|
2121
|
+
streams.delete(streamId);
|
|
2122
|
+
},
|
|
2123
|
+
onError: (err) => {
|
|
2124
|
+
sendControl(sock, { type: "stream_close", stream_id: streamId, error: `upstream_frame_error: ${err.message}` });
|
|
2125
|
+
streams.delete(streamId);
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
1983
2128
|
sk.on("data", (chunk) => {
|
|
1984
2129
|
if (cancelled) return;
|
|
1985
|
-
|
|
2130
|
+
upstreamParser.feed(chunk);
|
|
1986
2131
|
});
|
|
1987
2132
|
sk.on("close", () => {
|
|
1988
2133
|
if (cancelled) return;
|
|
@@ -2017,8 +2162,16 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
2017
2162
|
req.end();
|
|
2018
2163
|
const forwarder = {
|
|
2019
2164
|
kind: "ws",
|
|
2165
|
+
// Encode the v2 payload as an upstream WS frame BEFORE writing to
|
|
2166
|
+
// the socket. The prior implementation wrote raw payload to the
|
|
2167
|
+
// socket which is not a valid WS frame; upstream WS servers (e.g.
|
|
2168
|
+
// ComfyUI) would error out. Default to TEXT opcode — the v2
|
|
2169
|
+
// protocol does not propagate the original opcode from the client,
|
|
2170
|
+
// and most WS APIs (JSON-based) use text. Binary client→upstream
|
|
2171
|
+
// is a known limitation pending opcode propagation in v2.
|
|
2020
2172
|
feedBody: (chunk) => {
|
|
2021
|
-
if (
|
|
2173
|
+
if (cancelled || !upstream) return;
|
|
2174
|
+
upstream.write(createUpstreamTextFrame(chunk));
|
|
2022
2175
|
},
|
|
2023
2176
|
endBody: () => {
|
|
2024
2177
|
},
|