grpc-libp2p-client 0.0.37 → 0.0.39

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/index.cjs.js CHANGED
@@ -357,7 +357,7 @@ class HPACK {
357
357
  }
358
358
  // Huffman编码实现
359
359
  huffmanEncode(bytes) {
360
- let result = [];
360
+ const result = [];
361
361
  let current = 0;
362
362
  let bits = 0;
363
363
  for (let i = 0; i < bytes.length; i++) {
@@ -450,7 +450,7 @@ class HPACK {
450
450
  try {
451
451
  result = this.decode(bytes);
452
452
  }
453
- catch (e) {
453
+ catch {
454
454
  result = '';
455
455
  }
456
456
  }
@@ -458,7 +458,7 @@ class HPACK {
458
458
  try {
459
459
  result = new TextDecoder().decode(bytes);
460
460
  }
461
- catch (e) {
461
+ catch {
462
462
  result = '';
463
463
  }
464
464
  }
@@ -504,7 +504,8 @@ class FrameEncoder {
504
504
  // 编码SETTINGS帧
505
505
  static encodeSettingsFrame(frame) {
506
506
  // 计算payload总长度:每个设置项占6字节
507
- const payloadLength = frame.payload.length * 6;
507
+ const settingsPayload = frame.payload;
508
+ const payloadLength = settingsPayload.length * 6;
508
509
  // 分配缓冲区:9字节头部 + payload长度
509
510
  const buffer = new Uint8Array(9 + payloadLength);
510
511
  // 编码帧头部(前9个字节)
@@ -515,7 +516,7 @@ class FrameEncoder {
515
516
  streamId: frame.streamId
516
517
  });
517
518
  // 编码payload
518
- _encodeSettingsPayload(buffer, frame.payload);
519
+ _encodeSettingsPayload(buffer, settingsPayload);
519
520
  return buffer;
520
521
  }
521
522
  // 编码SETTINGS ACK帧
@@ -585,11 +586,11 @@ const defaultSettings = {
585
586
  [SETTINGS_PARAMETERS.MAX_FRAME_SIZE]: 16 << 10, // 16k
586
587
  [SETTINGS_PARAMETERS.MAX_HEADER_LIST_SIZE]: 8192
587
588
  };
588
- const HTTP2_PREFACE = 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n';
589
+ const HTTP2_PREFACE$1 = 'PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n';
589
590
  class Http2Frame {
590
591
  // 创建并编码PREFACE帧
591
592
  static createPreface() {
592
- return new TextEncoder().encode(HTTP2_PREFACE);
593
+ return new TextEncoder().encode(HTTP2_PREFACE$1);
593
594
  }
594
595
  static createPongFrame(payload) {
595
596
  return Http2Frame.createFrame(0x6, 0x1, 0, payload);
@@ -806,6 +807,7 @@ function _createPayload(settings) {
806
807
  return payload;
807
808
  }
808
809
 
810
+ const HTTP2_PREFACE = new TextEncoder().encode("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
809
811
  class HTTP2Parser {
810
812
  constructor(writer, options) {
811
813
  this.buffer = new Uint8Array(0);
@@ -853,44 +855,49 @@ class HTTP2Parser {
853
855
  // 处理单个数据块
854
856
  _processChunk(chunk) {
855
857
  // chunk 是 Uint8ArrayList 或 Uint8Array
856
- const newData = chunk.subarray ? chunk.subarray() : new Uint8Array(chunk);
857
- // 累积数据到buffer
858
+ const newData = 'subarray' in chunk && typeof chunk.subarray === 'function'
859
+ ? chunk.subarray()
860
+ : chunk;
861
+ // 原作者之前的 O(N) 内存拷贝优化被保留,去掉了存在 onEnd 竞态的 setTimeout
858
862
  const newBuffer = new Uint8Array(this.buffer.length + newData.length);
859
863
  newBuffer.set(this.buffer);
860
864
  newBuffer.set(newData, this.buffer.length);
861
865
  this.buffer = newBuffer;
862
866
  // 持续处理所有完整的帧
863
- while (this.buffer.length >= 9) {
867
+ let readOffset = 0;
868
+ while (this.buffer.length - readOffset >= 9) {
864
869
  // 判断是否有HTTP/2前导
865
- if (this.buffer.length >= 24 && this.isHttp2Preface(this.buffer)) {
866
- this.buffer = this.buffer.slice(24);
870
+ if (this.buffer.length - readOffset >= 24 && this.isHttp2Preface(this.buffer.subarray(readOffset))) {
871
+ readOffset += 24;
867
872
  // 发送SETTINGS帧
868
873
  const settingFrame = Http2Frame.createSettingsFrame();
869
874
  this.writer.write(settingFrame);
870
- break;
875
+ continue;
871
876
  }
872
- const frameHeader = this._parseFrameHeader(this.buffer);
877
+ const frameHeader = this._parseFrameHeader(this.buffer.subarray(readOffset));
873
878
  const totalFrameLength = 9 + frameHeader.length;
874
879
  // 检查是否有完整的帧
875
- if (this.buffer.length < totalFrameLength) {
880
+ if (this.buffer.length - readOffset < totalFrameLength) {
876
881
  break;
877
882
  }
878
883
  // 获取完整帧数据
879
- const frameData = this.buffer.slice(0, totalFrameLength);
884
+ const frameData = this.buffer.subarray(readOffset, readOffset + totalFrameLength);
880
885
  // 处理不同类型的帧
881
886
  this._handleFrame(frameHeader, frameData).catch((err) => {
882
887
  console.error("Error handling frame:", err);
883
888
  });
884
- // 移除已处理的帧
885
- this.buffer = this.buffer.slice(totalFrameLength);
889
+ // 移动偏移量
890
+ readOffset += totalFrameLength;
891
+ }
892
+ if (readOffset > 0) {
893
+ this.buffer = this.buffer.slice(readOffset);
886
894
  }
887
895
  }
888
896
  isHttp2Preface(buffer) {
889
- const PREFACE = new TextEncoder().encode("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n");
890
- if (buffer.length < PREFACE.length)
897
+ if (buffer.length < HTTP2_PREFACE.length)
891
898
  return false;
892
- for (let i = 0; i < PREFACE.length; i++) {
893
- if (buffer[i] !== PREFACE[i])
899
+ for (let i = 0; i < HTTP2_PREFACE.length; i++) {
900
+ if (buffer[i] !== HTTP2_PREFACE[i])
894
901
  return false;
895
902
  }
896
903
  return true;
@@ -1077,7 +1084,9 @@ class HTTP2Parser {
1077
1084
  waiters.forEach(fn => { try {
1078
1085
  fn();
1079
1086
  }
1080
- catch { } });
1087
+ catch (e) {
1088
+ console.debug('waiter error', e);
1089
+ } });
1081
1090
  }
1082
1091
  break;
1083
1092
  case FRAME_TYPES.DATA:
@@ -1126,7 +1135,7 @@ class HTTP2Parser {
1126
1135
  break;
1127
1136
  case FRAME_TYPES.WINDOW_UPDATE:
1128
1137
  // 处理窗口更新帧
1129
- this.handleWindowUpdateFrame(frameHeader, frameData, frameHeader.streamId);
1138
+ this.handleWindowUpdateFrame(frameHeader, frameData);
1130
1139
  // 更新发送窗口(对端接收窗口)
1131
1140
  try {
1132
1141
  const inc = this.parseWindowUpdateFrame(frameData, frameHeader).windowSizeIncrement;
@@ -1141,9 +1150,11 @@ class HTTP2Parser {
1141
1150
  waiters.forEach(fn => { try {
1142
1151
  fn();
1143
1152
  }
1144
- catch { } });
1153
+ catch (e) {
1154
+ console.debug('waiter error', e);
1155
+ } });
1145
1156
  }
1146
- catch (e) { }
1157
+ catch { /* ignore WINDOW_UPDATE parse errors */ }
1147
1158
  break;
1148
1159
  case FRAME_TYPES.PING:
1149
1160
  // 处理PING帧
@@ -1165,7 +1176,7 @@ class HTTP2Parser {
1165
1176
  info = {};
1166
1177
  }
1167
1178
  }
1168
- catch { }
1179
+ catch { /* ignore GOAWAY parse errors */ }
1169
1180
  try {
1170
1181
  this.onGoaway?.(info ?? {});
1171
1182
  }
@@ -1298,7 +1309,7 @@ class HTTP2Parser {
1298
1309
  };
1299
1310
  }
1300
1311
  // 处理 WINDOW_UPDATE 帧
1301
- handleWindowUpdateFrame(frameHeader, payload, streamId) {
1312
+ handleWindowUpdateFrame(frameHeader, payload) {
1302
1313
  try {
1303
1314
  const windowUpdate = this.parseWindowUpdateFrame(payload, frameHeader);
1304
1315
  this.connectionWindowSize += windowUpdate.windowSizeIncrement;
@@ -1439,8 +1450,8 @@ class StreamWriter {
1439
1450
  }
1440
1451
  catch (err) {
1441
1452
  // Gracefully handle stream closing errors - 不要传递到 handleError
1442
- const errMsg = err.message?.toLowerCase() || '';
1443
- if (err.name === 'StreamStateError' ||
1453
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase();
1454
+ if ((err instanceof Error && err.name === 'StreamStateError') ||
1444
1455
  errMsg.includes('closing') ||
1445
1456
  errMsg.includes('closed') ||
1446
1457
  errMsg.includes('write to a stream that is closed')) {
@@ -1452,6 +1463,7 @@ class StreamWriter {
1452
1463
  }
1453
1464
  }
1454
1465
  createTransform() {
1466
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1455
1467
  const self = this;
1456
1468
  return async function* (source) {
1457
1469
  for await (const chunk of source) {
@@ -1461,7 +1473,7 @@ class StreamWriter {
1461
1473
  // 因此这里统计的 bytesDrained 更接近实际被 sink 消费的字节数
1462
1474
  try {
1463
1475
  // 在下游消费后再扣减待消费队列,避免误判“next 没取”
1464
- if (self.p?._queueSize != null) {
1476
+ if (self.p._queueSize != null) {
1465
1477
  self.p._queueSize = Math.max(0, self.p._queueSize - chunk.byteLength);
1466
1478
  }
1467
1479
  self.bytesDrained += chunk.byteLength;
@@ -1481,10 +1493,11 @@ class StreamWriter {
1481
1493
  };
1482
1494
  }
1483
1495
  // 简单的卡顿看门狗:当队列长期高位且 bytesDrained 无进展时发出 stalled 事件
1496
+ // 使用递归 setTimeout 而非 setInterval,避免标签页后台恢复时回调堆积导致 Violation
1484
1497
  startWatchdog(intervalMs = 500, stallMs = 1500) {
1485
1498
  if (this.watchdogTimer)
1486
1499
  return;
1487
- this.watchdogTimer = setInterval(() => {
1500
+ const tick = () => {
1488
1501
  if (this.abortController.signal.aborted)
1489
1502
  return;
1490
1503
  const baseThreshold = this.options.bufferSize * 0.7;
@@ -1495,7 +1508,13 @@ class StreamWriter {
1495
1508
  if (!this.stallStartAt)
1496
1509
  this.stallStartAt = now;
1497
1510
  if (now - this.stallStartAt >= stallMs) {
1498
- this.dispatchEvent(new CustomEvent('stalled', { detail: { queueSize: q, drained: this.bytesDrained, sinceMs: now - this.stallStartAt } }));
1511
+ // 异步触发事件,让当前 tick 立即返回,避免同步事件处理器阻塞主线程
1512
+ const detail = { queueSize: q, drained: this.bytesDrained, sinceMs: now - this.stallStartAt };
1513
+ setTimeout(() => {
1514
+ if (!this.abortController.signal.aborted) {
1515
+ this.dispatchEvent(new CustomEvent('stalled', { detail }));
1516
+ }
1517
+ }, 0);
1499
1518
  // 避免持续触发,推进起点
1500
1519
  this.stallStartAt = now;
1501
1520
  }
@@ -1510,7 +1529,10 @@ class StreamWriter {
1510
1529
  // 队列回落,重置
1511
1530
  this.stallStartAt = 0;
1512
1531
  }
1513
- }, intervalMs);
1532
+ // 本次 tick 完成后再安排下一次,不会因主线程繁忙而堆积
1533
+ this.watchdogTimer = setTimeout(tick, intervalMs);
1534
+ };
1535
+ this.watchdogTimer = setTimeout(tick, intervalMs);
1514
1536
  }
1515
1537
  async write(data) {
1516
1538
  // 静默处理 aborted 状态,避免在正常的流关闭场景下抛出错误
@@ -1542,6 +1564,8 @@ class StreamWriter {
1542
1564
  return data.arrayBuffer();
1543
1565
  if (typeof data === 'string')
1544
1566
  return new TextEncoder().encode(data).buffer;
1567
+ if (data instanceof Uint8Array)
1568
+ return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
1545
1569
  return data;
1546
1570
  }
1547
1571
  async writeChunks(buffer) {
@@ -1684,7 +1708,7 @@ class StreamWriter {
1684
1708
  }
1685
1709
  catch (err) {
1686
1710
  // 忽略关闭已关闭流的错误
1687
- const errMsg = err.message?.toLowerCase() || '';
1711
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase();
1688
1712
  if (!errMsg.includes('closed') && !errMsg.includes('closing')) {
1689
1713
  this.log?.trace?.('Stream close error:', err);
1690
1714
  }
@@ -1702,7 +1726,8 @@ class StreamWriter {
1702
1726
  // 先检查流状态,避免在已关闭的流上调用 abort
1703
1727
  if (this.stream && typeof this.stream.abort === 'function') {
1704
1728
  // 检查流的状态,避免操作已关闭的流
1705
- const streamState = this.stream.status || this.stream.state;
1729
+ const streamState = this.stream.status ||
1730
+ this.stream.state;
1706
1731
  if (streamState !== 'closed' && streamState !== 'closing') {
1707
1732
  this.stream.abort(new Error(reason));
1708
1733
  }
@@ -1711,7 +1736,7 @@ class StreamWriter {
1711
1736
  catch (err) {
1712
1737
  // Stream may already be closed, ignore all stream-related errors
1713
1738
  // 完全忽略流操作错误,避免在错误处理中再次抛出错误
1714
- const errMsg = err.message?.toLowerCase() || '';
1739
+ const errMsg = (err instanceof Error ? err.message : '').toLowerCase();
1715
1740
  if (!errMsg.includes('closed') && !errMsg.includes('closing') && !errMsg.includes('write')) {
1716
1741
  this.log?.trace?.('Stream abort error:', err);
1717
1742
  }
@@ -1733,17 +1758,17 @@ class StreamWriter {
1733
1758
  }
1734
1759
  // 立即拒绝所有待处理的写入任务,避免它们继续执行
1735
1760
  const pendingTasks = this.writeQueue.splice(0);
1736
- pendingTasks.forEach(task => {
1761
+ pendingTasks.forEach(() => {
1737
1762
  // 这些任务的 Promise 会在执行时因为检查到 aborted 而被拒绝
1738
1763
  });
1739
1764
  try {
1740
1765
  this.p.end();
1741
1766
  }
1742
- catch (err) {
1767
+ catch {
1743
1768
  // Ignore errors when ending pushable
1744
1769
  }
1745
1770
  if (this.watchdogTimer) {
1746
- clearInterval(this.watchdogTimer);
1771
+ clearTimeout(this.watchdogTimer);
1747
1772
  this.watchdogTimer = undefined;
1748
1773
  }
1749
1774
  }
@@ -1879,6 +1904,7 @@ class Libp2pGrpcClient {
1879
1904
  }
1880
1905
  await new Promise((resolve, reject) => {
1881
1906
  let settled = false;
1907
+ // eslint-disable-next-line prefer-const
1882
1908
  let timeoutId;
1883
1909
  const cleanup = () => {
1884
1910
  const idx = state.waiters.indexOf(waiter);
@@ -1961,7 +1987,7 @@ class Libp2pGrpcClient {
1961
1987
  if (pooled) {
1962
1988
  const conn = pooled.connection;
1963
1989
  if (conn) {
1964
- const status = conn?.stat?.status?.toLowerCase?.();
1990
+ const status = conn.status;
1965
1991
  if (!status || status === "open") {
1966
1992
  return conn;
1967
1993
  }
@@ -1988,17 +2014,9 @@ class Libp2pGrpcClient {
1988
2014
  }
1989
2015
  };
1990
2016
  try {
1991
- const anyConn = conn;
1992
- if (typeof anyConn.addEventListener === "function") {
1993
- anyConn.addEventListener("close", removeFromPool, {
1994
- once: true,
1995
- });
1996
- }
1997
- else if (typeof anyConn.once === "function") {
1998
- anyConn.once("close", removeFromPool);
1999
- }
2017
+ conn.addEventListener("close", removeFromPool, { once: true });
2000
2018
  }
2001
- catch { }
2019
+ catch { /* ignore event listener registration errors */ }
2002
2020
  }
2003
2021
  }
2004
2022
  return conn;
@@ -2068,14 +2086,14 @@ class Libp2pGrpcClient {
2068
2086
  });
2069
2087
  try {
2070
2088
  writer.addEventListener("backpressure", (e) => {
2071
- const d = e?.detail || {};
2089
+ const d = e.detail || {};
2072
2090
  console.warn(`[unary stream ${streamId}] backpressure current=${d.currentSize} avg=${d.averageSize} threshold=${d.threshold}`);
2073
2091
  });
2074
- writer.addEventListener("drain", (e) => {
2075
- const d = e?.detail || {};
2092
+ writer.addEventListener("drain", () => {
2093
+ // drain event - no action needed
2076
2094
  });
2077
2095
  writer.addEventListener("stalled", (e) => {
2078
- const d = e?.detail || {};
2096
+ const d = e.detail || {};
2079
2097
  console.warn(`[unary stream ${streamId}] stalled queue=${d.queueSize} drained=${d.drained} since=${d.sinceMs}ms — sending PING`);
2080
2098
  try {
2081
2099
  const payload = new Uint8Array(8);
@@ -2083,10 +2101,10 @@ class Libp2pGrpcClient {
2083
2101
  const ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
2084
2102
  writer.write(ping);
2085
2103
  }
2086
- catch { }
2104
+ catch { /* ignore ping write errors */ }
2087
2105
  });
2088
2106
  }
2089
- catch { }
2107
+ catch { /* ignore addEventListener errors */ }
2090
2108
  const parser = new HTTP2Parser(writer);
2091
2109
  parser.onGoaway = (info) => {
2092
2110
  console.warn("[unaryCall] GOAWAY received from server", info);
@@ -2097,7 +2115,7 @@ class Libp2pGrpcClient {
2097
2115
  exitFlag = true;
2098
2116
  errMsg = `GOAWAY received: code=${info.errorCode}`;
2099
2117
  try {
2100
- connection?.close?.();
2118
+ connection?.close();
2101
2119
  }
2102
2120
  catch (err) {
2103
2121
  console.warn("Error closing connection after GOAWAY:", err);
@@ -2122,7 +2140,6 @@ class Libp2pGrpcClient {
2122
2140
  if (payload.length < 5) {
2123
2141
  return;
2124
2142
  }
2125
- const compressionFlag = payload[0]; // 压缩标志
2126
2143
  const lengthBytes = payload.slice(1, 5); // 消息长度的4字节
2127
2144
  responseDataExpectedLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
2128
2145
  if (responseDataExpectedLength < 0) {
@@ -2199,7 +2216,7 @@ class Libp2pGrpcClient {
2199
2216
  const ackSettingFrame = Http2Frame.createSettingsAckFrame();
2200
2217
  writer.write(ackSettingFrame);
2201
2218
  };
2202
- parser.onHeaders = (headers, header) => {
2219
+ parser.onHeaders = (headers) => {
2203
2220
  const plainHeaders = hpack.decodeHeaderFields(headers);
2204
2221
  if (plainHeaders.get("grpc-status") === "0") {
2205
2222
  // 成功状态
@@ -2224,21 +2241,12 @@ class Libp2pGrpcClient {
2224
2241
  const settingFrme = Http2Frame.createSettingsFrame();
2225
2242
  await writer.write(settingFrme);
2226
2243
  // 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
2227
- {
2228
- let progressed = false;
2229
- await Promise.race([
2230
- (async () => {
2231
- await parser.waitForPeerSettings(1000);
2232
- progressed = true;
2233
- })(),
2234
- (async () => {
2235
- await parser.waitForSettingsAck();
2236
- progressed = true;
2237
- })(),
2238
- new Promise((res) => setTimeout(res, 300)),
2239
- ]);
2240
- // 即使未等到,也继续;多数实现会随后发送
2241
- }
2244
+ await Promise.race([
2245
+ parser.waitForPeerSettings(1000),
2246
+ parser.waitForSettingsAck(),
2247
+ new Promise((res) => setTimeout(res, 300)),
2248
+ ]);
2249
+ // 即使未等到,也继续;多数实现会随后发送
2242
2250
  // 创建头部帧
2243
2251
  const headerFrame = Http2Frame.createHeadersFrame(streamId, method, true, this.token);
2244
2252
  await writer.write(headerFrame);
@@ -2266,9 +2274,9 @@ class Libp2pGrpcClient {
2266
2274
  checkResponse();
2267
2275
  });
2268
2276
  try {
2269
- await writer.flush?.(timeout);
2277
+ await writer.flush(timeout);
2270
2278
  }
2271
- catch { }
2279
+ catch { /* ignore flush errors */ }
2272
2280
  await writer.end();
2273
2281
  }
2274
2282
  catch (err) {
@@ -2368,7 +2376,7 @@ class Libp2pGrpcClient {
2368
2376
  if (options?.freshConnection) {
2369
2377
  try {
2370
2378
  this.connectionPool.delete(this.peerAddr.toString());
2371
- await this.node?.hangUp?.(this.peerAddr);
2379
+ await this.node.hangUp(this.peerAddr);
2372
2380
  console.warn("[Call] hangUp existing connection before dialing due to freshConnection=true");
2373
2381
  }
2374
2382
  catch (err) {
@@ -2401,14 +2409,14 @@ class Libp2pGrpcClient {
2401
2409
  });
2402
2410
  try {
2403
2411
  writer.addEventListener("backpressure", (e) => {
2404
- const d = e?.detail || {};
2412
+ const d = e.detail || {};
2405
2413
  console.warn(`[stream ${streamId}] backpressure current=${d.currentSize} avg=${d.averageSize} threshold=${d.threshold}`);
2406
2414
  });
2407
- writer.addEventListener("drain", (e) => {
2408
- const d = e?.detail || {};
2415
+ writer.addEventListener("drain", () => {
2416
+ // drain event - no action needed
2409
2417
  });
2410
2418
  writer.addEventListener("stalled", (e) => {
2411
- const d = e?.detail || {};
2419
+ const d = e.detail || {};
2412
2420
  console.warn(`[stream ${streamId}] stalled queue=${d.queueSize} drained=${d.drained} since=${d.sinceMs}ms — sending PING`);
2413
2421
  try {
2414
2422
  const payload = new Uint8Array(8);
@@ -2416,10 +2424,10 @@ class Libp2pGrpcClient {
2416
2424
  const ping = Http2Frame.createFrame(0x6, 0x0, 0, payload);
2417
2425
  writer.write(ping);
2418
2426
  }
2419
- catch { /* empty */ }
2427
+ catch { /* ignore ping write errors */ }
2420
2428
  });
2421
2429
  }
2422
- catch { /* empty */ }
2430
+ catch { /* ignore addEventListener errors */ }
2423
2431
  const parser = new HTTP2Parser(writer, {
2424
2432
  compatibilityMode: !useFlowControl,
2425
2433
  });
@@ -2436,7 +2444,7 @@ class Libp2pGrpcClient {
2436
2444
  }
2437
2445
  internalController.abort();
2438
2446
  try {
2439
- connection?.close?.();
2447
+ connection?.close();
2440
2448
  }
2441
2449
  catch (err) {
2442
2450
  console.warn("Error closing connection after GOAWAY:", err);
@@ -2471,7 +2479,7 @@ class Libp2pGrpcClient {
2471
2479
  }
2472
2480
  };
2473
2481
  // 在各个回调中检查是否已中止
2474
- parser.onData = async (payload, frameHeader) => {
2482
+ parser.onData = async (payload) => {
2475
2483
  // 检查是否已中止
2476
2484
  if (internalController.signal.aborted) {
2477
2485
  return;
@@ -2491,7 +2499,6 @@ class Libp2pGrpcClient {
2491
2499
  // 如果还没有读取消息长度,且缓冲区有足够数据
2492
2500
  if (expectedMessageLength === -1 && messageBuffer.length >= 5) {
2493
2501
  // 读取 gRPC 消息头:1字节压缩标志 + 4字节长度
2494
- const compressionFlag = messageBuffer[0];
2495
2502
  const lengthBytes = messageBuffer.slice(1, 5);
2496
2503
  expectedMessageLength = new DataView(lengthBytes.buffer, lengthBytes.byteOffset).getUint32(0, false); // big-endian
2497
2504
  }
@@ -2528,7 +2535,7 @@ class Libp2pGrpcClient {
2528
2535
  const ackSettingFrame = Http2Frame.createSettingsAckFrame();
2529
2536
  writer.write(ackSettingFrame);
2530
2537
  };
2531
- parser.onHeaders = (headers, header) => {
2538
+ parser.onHeaders = (headers) => {
2532
2539
  // 检查是否已中止
2533
2540
  if (internalController.signal.aborted)
2534
2541
  return;
@@ -2574,16 +2581,9 @@ class Libp2pGrpcClient {
2574
2581
  }
2575
2582
  // 等待对端 SETTINGS 或 ACK,择一即可,避免偶发握手竞态
2576
2583
  {
2577
- let progressed = false;
2578
2584
  await Promise.race([
2579
- (async () => {
2580
- await parser.waitForPeerSettings(1000);
2581
- progressed = true;
2582
- })(),
2583
- (async () => {
2584
- await parser.waitForSettingsAck();
2585
- progressed = true;
2586
- })(),
2585
+ parser.waitForPeerSettings(1000),
2586
+ parser.waitForSettingsAck(),
2587
2587
  new Promise((res) => setTimeout(res, 300)),
2588
2588
  ]);
2589
2589
  // 即使未等到,也继续;多数实现会随后发送
@@ -2620,7 +2620,6 @@ class Libp2pGrpcClient {
2620
2620
  }
2621
2621
  // 动态批量处理逻辑 - 在处理过程中动态补充新数据
2622
2622
  const batchSize = options?.batchSize || 10;
2623
- const maxBatchWaitMs = options?.maxBatchWaitMs || 50;
2624
2623
  // 动态批处理器
2625
2624
  const processingQueue = [];
2626
2625
  let isProcessing = false;
@@ -2751,9 +2750,9 @@ class Libp2pGrpcClient {
2751
2750
  await writeFrame(finalFrame);
2752
2751
  // 在结束前尽量冲刷内部队列,避免服务器看到部分数据 + context canceled
2753
2752
  try {
2754
- await writer.flush?.(timeout);
2753
+ await writer.flush(timeout);
2755
2754
  }
2756
- catch { }
2755
+ catch { /* ignore flush errors */ }
2757
2756
  await writer.end();
2758
2757
  }
2759
2758
  // 检查是否已中止
@@ -2800,15 +2799,16 @@ class Libp2pGrpcClient {
2800
2799
  if (options?.freshConnection) {
2801
2800
  try {
2802
2801
  // 通过 libp2p 连接管理器关闭到该 peer 的连接
2803
- const conns = this.node?.getConnections?.(this.peerAddr) || [];
2802
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2803
+ const conns = this.node.getConnections?.(this.peerAddr) || [];
2804
2804
  for (const c of conns) {
2805
2805
  try {
2806
2806
  await c.close?.();
2807
2807
  }
2808
- catch { }
2808
+ catch { /* ignore close errors */ }
2809
2809
  }
2810
2810
  }
2811
- catch { }
2811
+ catch { /* ignore connection cleanup errors */ }
2812
2812
  }
2813
2813
  if (streamSlotAcquired && state) {
2814
2814
  state.activeStreams = Math.max(0, state.activeStreams - 1);