@streamr/trackerless-network 103.6.0-rc.0 → 103.8.0-rc.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/dist/exports.d.ts CHANGED
@@ -1167,6 +1167,7 @@ interface StrictContentDeliveryLayerNodeOptions {
1167
1167
  proxyConnectionRpcLocal?: ProxyConnectionRpcLocal;
1168
1168
  rpcRequestTimeout?: number;
1169
1169
  plumtreeManager?: PlumtreeManager;
1170
+ suppressOwnMessageLoopback?: boolean;
1170
1171
  }
1171
1172
  declare class ContentDeliveryLayerNode extends EventEmitter<Events$2> {
1172
1173
  private started;
@@ -1297,6 +1298,7 @@ interface ContentDeliveryManagerOptions {
1297
1298
  rpcRequestTimeout?: number;
1298
1299
  neighborUpdateInterval?: number;
1299
1300
  bufferWhileConnecting?: boolean;
1301
+ suppressOwnMessageLoopback?: boolean;
1300
1302
  }
1301
1303
  type PlumtreeOptions = {
1302
1304
  enabled: true;
@@ -1409,5 +1411,11 @@ declare class NetworkNode {
1409
1411
  createExternalRpcClient<T extends ExternalRpcClient>(clientClass: ExternalRpcClientClass<T>): ProtoRpcClient<T>;
1410
1412
  }
1411
1413
 
1412
- export { AsymmetricEncryptionType, ContentType, ControlLayerInfo, EncryptedGroupKey, EncryptionType, GroupKeyRequest, GroupKeyResponse, MessageID, MessageRef, NetworkNode, NetworkStack, ProxyDirection, SignatureType, StreamMessage, createNetworkNode, streamPartIdToDataKey };
1414
+ declare function setGapDiagnosticsEnabled(val: boolean): void;
1415
+ declare function logGapDiagnosticSampled(layer: string, opts?: {
1416
+ detail?: Record<string, unknown>;
1417
+ outlierThresholdMs?: number;
1418
+ }): void;
1419
+
1420
+ export { AsymmetricEncryptionType, ContentType, ControlLayerInfo, EncryptedGroupKey, EncryptionType, GroupKeyRequest, GroupKeyResponse, MessageID, MessageRef, NetworkNode, NetworkStack, ProxyDirection, SignatureType, StreamMessage, createNetworkNode, logGapDiagnosticSampled, setGapDiagnosticsEnabled as setTrackerlessGapDiagnosticsEnabled, streamPartIdToDataKey };
1413
1421
  export type { ContentDeliveryLayerNeighborInfo, ContentDeliveryManagerOptions, ExternalRpcClient, ExternalRpcClientClass, NetworkOptions, NodeInfo, StreamPartDeliveryOptions, StreamPartitionInfo };
package/dist/exports.js CHANGED
@@ -27,7 +27,7 @@ class ExternalNetworkRpc {
27
27
  }
28
28
  }
29
29
 
30
- var version = "103.6.0-rc.0";
30
+ var version = "103.8.0-rc.3";
31
31
 
32
32
  // @generated message type with reflection information, may provide speed optimized methods
33
33
  class Any$Type extends MessageType {
@@ -2402,12 +2402,72 @@ class NeighborUpdateManager {
2402
2402
  }
2403
2403
  }
2404
2404
 
2405
+ let enabled = false;
2406
+ function setGapDiagnosticsEnabled(val) {
2407
+ enabled = val;
2408
+ globalThis.__trackerlessGapDiagEnabled = val;
2409
+ }
2410
+ const SUMMARY_INTERVAL_MS = 2000;
2411
+ const accumulators = new Map();
2412
+ function logGapDiagnosticSampled(layer, opts = {}) {
2413
+ if (!enabled)
2414
+ return;
2415
+ const now = performance.now();
2416
+ const threshold = opts.outlierThresholdMs ?? 30;
2417
+ let acc = accumulators.get(layer);
2418
+ if (acc === undefined) {
2419
+ acc = { count: 0, sumDeltaMs: 0, maxDeltaMs: 0, outlierCount: 0, lastReportMs: now, lastEventMs: now };
2420
+ accumulators.set(layer, acc);
2421
+ return;
2422
+ }
2423
+ const deltaMs = now - acc.lastEventMs;
2424
+ acc.lastEventMs = now;
2425
+ acc.count++;
2426
+ if (deltaMs > acc.maxDeltaMs)
2427
+ acc.maxDeltaMs = deltaMs;
2428
+ acc.sumDeltaMs += deltaMs;
2429
+ if (deltaMs > threshold)
2430
+ acc.outlierCount++;
2431
+ if (deltaMs > threshold) {
2432
+ const payload = {
2433
+ layer,
2434
+ timestampMs: now,
2435
+ deltaMs: +deltaMs.toFixed(2),
2436
+ detail: opts.detail,
2437
+ };
2438
+ // eslint-disable-next-line no-console
2439
+ console.log('[gap-diagnostics]', JSON.stringify(payload));
2440
+ }
2441
+ if (now - acc.lastReportMs >= SUMMARY_INTERVAL_MS) {
2442
+ const summaryDetail = {
2443
+ count: acc.count,
2444
+ meanDeltaMs: acc.count > 0 ? +(acc.sumDeltaMs / acc.count).toFixed(2) : 0,
2445
+ maxDeltaMs: +acc.maxDeltaMs.toFixed(2),
2446
+ outlierCount: acc.outlierCount,
2447
+ periodMs: +(now - acc.lastReportMs).toFixed(1),
2448
+ };
2449
+ const summary = {
2450
+ layer: `${layer}.summary`,
2451
+ timestampMs: now,
2452
+ detail: summaryDetail,
2453
+ };
2454
+ // eslint-disable-next-line no-console
2455
+ console.log('[gap-diagnostics]', JSON.stringify(summary));
2456
+ acc.count = 0;
2457
+ acc.sumDeltaMs = 0;
2458
+ acc.maxDeltaMs = 0;
2459
+ acc.outlierCount = 0;
2460
+ acc.lastReportMs = now;
2461
+ }
2462
+ }
2463
+
2405
2464
  class ContentDeliveryRpcLocal {
2406
2465
  options;
2407
2466
  constructor(options) {
2408
2467
  this.options = options;
2409
2468
  }
2410
2469
  async sendStreamMessage(message, context) {
2470
+ logGapDiagnosticSampled('trackerless.rpcLocal.sendStreamMessage');
2411
2471
  const previousNode = context.incomingSourceDescriptor;
2412
2472
  const previousNodeId = toNodeId(previousNode);
2413
2473
  this.options.markForInspection(previousNodeId, message.messageId);
@@ -2768,12 +2828,23 @@ class ContentDeliveryLayerNode extends EventEmitter {
2768
2828
  this.options.neighborFinder.stop();
2769
2829
  this.options.neighborUpdateManager.stop();
2770
2830
  this.options.inspector.stop();
2831
+ this.duplicateDetectors.clear();
2771
2832
  }
2772
2833
  broadcast(msg, previousNode) {
2773
2834
  if (!previousNode) {
2835
+ logGapDiagnosticSampled('trackerless.cdNode.broadcastOut');
2774
2836
  markAndCheckDuplicate(this.duplicateDetectors, msg.messageId, msg.previousMessageRef);
2775
2837
  }
2776
- this.emit('message', msg);
2838
+ else {
2839
+ logGapDiagnosticSampled('trackerless.cdNode.broadcastIn');
2840
+ }
2841
+ // Deliver to local listeners — except own publishes (no previousNode)
2842
+ // when loopback is suppressed: nothing local consumes them and they
2843
+ // would otherwise be re-serialized across a worker boundary just to be
2844
+ // discarded. Propagation + duplicate detection below are unaffected.
2845
+ if (previousNode !== undefined || !this.options.suppressOwnMessageLoopback) {
2846
+ this.emit('message', msg);
2847
+ }
2777
2848
  const skipBackPropagation = previousNode !== undefined && !this.options.temporaryConnectionRpcLocal.hasNode(previousNode);
2778
2849
  this.options.propagation.feedUnseenMessage(msg, this.getPropagationTargets(msg), skipBackPropagation ? previousNode : null);
2779
2850
  this.messagesPropagated += 1;
@@ -3070,6 +3141,7 @@ class Propagation {
3070
3141
  }
3071
3142
  sendAndAwaitThenMark({ message, source, handledNeighbors }, neighborId) {
3072
3143
  if (!handledNeighbors.has(neighborId) && neighborId !== source) {
3144
+ logGapDiagnosticSampled('trackerless.propagation.sendToNeighbor');
3073
3145
  (async () => {
3074
3146
  try {
3075
3147
  await this.sendToNeighbor(neighborId, message);
@@ -3627,6 +3699,9 @@ class PlumtreeManager extends EventEmitter {
3627
3699
  stop() {
3628
3700
  this.abortController.abort();
3629
3701
  this.neighbors.off('nodeRemoved', this.onNeighborRemoved);
3702
+ this.latestMessages.clear();
3703
+ this.recoveryState.clear();
3704
+ this.recoveryCooldownUntil.clear();
3630
3705
  }
3631
3706
  }
3632
3707
 
@@ -4149,6 +4224,7 @@ class ContentDeliveryManager extends EventEmitter {
4149
4224
  neighborUpdateInterval: this.options.neighborUpdateInterval,
4150
4225
  isLocalNodeEntryPoint,
4151
4226
  bufferWhileConnecting: this.options.bufferWhileConnecting,
4227
+ suppressOwnMessageLoopback: this.options.suppressOwnMessageLoopback,
4152
4228
  plumtreeOptimization: streamPartDeliveryOptions?.plumtreeOptimization?.enabled,
4153
4229
  plumtreeMaxPausedNeighbors: streamPartDeliveryOptions?.plumtreeOptimization?.enabled === true ?
4154
4230
  streamPartDeliveryOptions?.plumtreeOptimization?.maxPausedNeighbors : undefined
@@ -4568,5 +4644,5 @@ class NetworkNode {
4568
4644
  }
4569
4645
  }
4570
4646
 
4571
- export { AsymmetricEncryptionType, ContentType, ControlLayerInfo, EncryptedGroupKey, EncryptionType, GroupKeyRequest, GroupKeyResponse, MessageID, MessageRef, NetworkNode, NetworkStack, ProxyDirection, SignatureType, StreamMessage, createNetworkNode, streamPartIdToDataKey };
4647
+ export { AsymmetricEncryptionType, ContentType, ControlLayerInfo, EncryptedGroupKey, EncryptionType, GroupKeyRequest, GroupKeyResponse, MessageID, MessageRef, NetworkNode, NetworkStack, ProxyDirection, SignatureType, StreamMessage, createNetworkNode, logGapDiagnosticSampled, setGapDiagnosticsEnabled as setTrackerlessGapDiagnosticsEnabled, streamPartIdToDataKey };
4572
4648
  //# sourceMappingURL=exports.js.map