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