@streamr/sdk 103.3.1 → 103.6.0-rc.0

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.
@@ -41288,6 +41288,22 @@
41288
41288
  cb();
41289
41289
  }, ms);
41290
41290
  };
41291
+ /**
41292
+ * setInterval with AbortSignal support. Aborting will simply clear
41293
+ * the interval silently.
41294
+ */
41295
+ const setAbortableInterval = (cb, ms, abortSignal) => {
41296
+ if (abortSignal.aborted) {
41297
+ return;
41298
+ }
41299
+ const abortListener = () => {
41300
+ clearInterval(timeoutRef);
41301
+ };
41302
+ abortSignal.addEventListener('abort', abortListener, { once: true });
41303
+ const timeoutRef = setInterval(() => {
41304
+ cb();
41305
+ }, ms);
41306
+ };
41291
41307
 
41292
41308
  const noopExecutor = () => { };
41293
41309
  /**
@@ -73321,7 +73337,7 @@
73321
73337
  }
73322
73338
  }
73323
73339
 
73324
- const logger$D = new Logger('LoggingJsonRpcProvider');
73340
+ const logger$E = new Logger('LoggingJsonRpcProvider');
73325
73341
  class LoggingJsonRpcProvider extends JsonRpcProvider {
73326
73342
  urlConfig;
73327
73343
  constructor(urlConfig, network, options) {
@@ -73340,20 +73356,20 @@
73340
73356
  timeout: this.urlConfig.timeout
73341
73357
  }
73342
73358
  };
73343
- logger$D.debug('Send request', logContext);
73359
+ logger$E.debug('Send request', logContext);
73344
73360
  let result;
73345
73361
  try {
73346
73362
  result = await super.send(method, params);
73347
73363
  }
73348
73364
  catch (err) {
73349
- logger$D.debug('Encountered error while requesting', {
73365
+ logger$E.debug('Encountered error while requesting', {
73350
73366
  ...logContext,
73351
73367
  err,
73352
73368
  elapsedTime: Date.now() - startTime
73353
73369
  });
73354
73370
  throw err;
73355
73371
  }
73356
- logger$D.debug('Received response', {
73372
+ logger$E.debug('Received response', {
73357
73373
  ...logContext,
73358
73374
  elapsedTime: Date.now() - startTime
73359
73375
  });
@@ -80246,7 +80262,7 @@
80246
80262
  this.deferredPromises.trailer.resolve({});
80247
80263
  }
80248
80264
  catch (err) {
80249
- logger$y.debug(`Could not parse response, received message is likely `);
80265
+ logger$z.debug(`Could not parse response, received message is likely `);
80250
80266
  const error = new FailedToParse(`Failed to parse received response, network protocol version likely is likely incompatible`, err);
80251
80267
  this.rejectDeferredPromises(error, StatusCode.SERVER_ERROR);
80252
80268
  }
@@ -80267,7 +80283,7 @@
80267
80283
  return this.callContext;
80268
80284
  }
80269
80285
  }
80270
- const logger$y = new Logger('RpcCommunicator');
80286
+ const logger$z = new Logger('RpcCommunicator');
80271
80287
  class RpcCommunicator {
80272
80288
  stopped = false;
80273
80289
  rpcClientTransport;
@@ -80321,7 +80337,7 @@
80321
80337
  if (deferredPromises && (!callContext || !callContext.notification)) {
80322
80338
  this.registerRequest(rpcMessage.requestId, deferredPromises, callContext, requestOptions.timeout);
80323
80339
  }
80324
- logger$y.trace(`onOutGoingMessage, messageId: ${rpcMessage.requestId}`);
80340
+ logger$z.trace(`onOutGoingMessage, messageId: ${rpcMessage.requestId}`);
80325
80341
  if (this.outgoingMessageListener) {
80326
80342
  this.outgoingMessageListener(rpcMessage, rpcMessage.requestId, callContext)
80327
80343
  .catch((clientSideException) => {
@@ -80352,7 +80368,7 @@
80352
80368
  }
80353
80369
  }
80354
80370
  async onIncomingMessage(rpcMessage, callContext) {
80355
- logger$y.trace(`onIncomingMessage, requestId: ${rpcMessage.requestId}`);
80371
+ logger$z.trace(`onIncomingMessage, requestId: ${rpcMessage.requestId}`);
80356
80372
  if (rpcMessage.header.response && this.ongoingRequests.has(rpcMessage.requestId)) {
80357
80373
  if (rpcMessage.errorType !== undefined) {
80358
80374
  this.rejectOngoingRequest(rpcMessage);
@@ -80414,7 +80430,7 @@
80414
80430
  await this.rpcServerRegistry.handleNotification(rpcMessage, callContext);
80415
80431
  }
80416
80432
  catch (err) {
80417
- logger$y.debug('error', { err });
80433
+ logger$z.debug('error', { err });
80418
80434
  }
80419
80435
  }
80420
80436
  registerRequest(requestId, deferredPromises, callContext, timeout = this.rpcRequestTimeout) {
@@ -81601,6 +81617,355 @@
81601
81617
  var ipaddrExports = requireIpaddr();
81602
81618
  var ipaddr = /*@__PURE__*/getDefaultExportFromCjs$1(ipaddrExports);
81603
81619
 
81620
+ /**
81621
+ * @license
81622
+ * Copyright 2019 Google LLC
81623
+ * SPDX-License-Identifier: Apache-2.0
81624
+ */
81625
+ const proxyMarker = Symbol("Comlink.proxy");
81626
+ const createEndpoint = Symbol("Comlink.endpoint");
81627
+ const releaseProxy = Symbol("Comlink.releaseProxy");
81628
+ const finalizer = Symbol("Comlink.finalizer");
81629
+ const throwMarker = Symbol("Comlink.thrown");
81630
+ const isObject$1 = (val) => (typeof val === "object" && val !== null) || typeof val === "function";
81631
+ /**
81632
+ * Internal transfer handle to handle objects marked to proxy.
81633
+ */
81634
+ const proxyTransferHandler = {
81635
+ canHandle: (val) => isObject$1(val) && val[proxyMarker],
81636
+ serialize(obj) {
81637
+ const { port1, port2 } = new MessageChannel();
81638
+ expose(obj, port1);
81639
+ return [port2, [port2]];
81640
+ },
81641
+ deserialize(port) {
81642
+ port.start();
81643
+ return wrap$1(port);
81644
+ },
81645
+ };
81646
+ /**
81647
+ * Internal transfer handler to handle thrown exceptions.
81648
+ */
81649
+ const throwTransferHandler = {
81650
+ canHandle: (value) => isObject$1(value) && throwMarker in value,
81651
+ serialize({ value }) {
81652
+ let serialized;
81653
+ if (value instanceof Error) {
81654
+ serialized = {
81655
+ isError: true,
81656
+ value: {
81657
+ message: value.message,
81658
+ name: value.name,
81659
+ stack: value.stack,
81660
+ },
81661
+ };
81662
+ }
81663
+ else {
81664
+ serialized = { isError: false, value };
81665
+ }
81666
+ return [serialized, []];
81667
+ },
81668
+ deserialize(serialized) {
81669
+ if (serialized.isError) {
81670
+ throw Object.assign(new Error(serialized.value.message), serialized.value);
81671
+ }
81672
+ throw serialized.value;
81673
+ },
81674
+ };
81675
+ /**
81676
+ * Allows customizing the serialization of certain values.
81677
+ */
81678
+ const transferHandlers = new Map([
81679
+ ["proxy", proxyTransferHandler],
81680
+ ["throw", throwTransferHandler],
81681
+ ]);
81682
+ function isAllowedOrigin(allowedOrigins, origin) {
81683
+ for (const allowedOrigin of allowedOrigins) {
81684
+ if (origin === allowedOrigin || allowedOrigin === "*") {
81685
+ return true;
81686
+ }
81687
+ if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {
81688
+ return true;
81689
+ }
81690
+ }
81691
+ return false;
81692
+ }
81693
+ function expose(obj, ep = globalThis, allowedOrigins = ["*"]) {
81694
+ ep.addEventListener("message", function callback(ev) {
81695
+ if (!ev || !ev.data) {
81696
+ return;
81697
+ }
81698
+ if (!isAllowedOrigin(allowedOrigins, ev.origin)) {
81699
+ console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
81700
+ return;
81701
+ }
81702
+ const { id, type, path } = Object.assign({ path: [] }, ev.data);
81703
+ const argumentList = (ev.data.argumentList || []).map(fromWireValue);
81704
+ let returnValue;
81705
+ try {
81706
+ const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);
81707
+ const rawValue = path.reduce((obj, prop) => obj[prop], obj);
81708
+ switch (type) {
81709
+ case "GET" /* MessageType.GET */:
81710
+ {
81711
+ returnValue = rawValue;
81712
+ }
81713
+ break;
81714
+ case "SET" /* MessageType.SET */:
81715
+ {
81716
+ parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);
81717
+ returnValue = true;
81718
+ }
81719
+ break;
81720
+ case "APPLY" /* MessageType.APPLY */:
81721
+ {
81722
+ returnValue = rawValue.apply(parent, argumentList);
81723
+ }
81724
+ break;
81725
+ case "CONSTRUCT" /* MessageType.CONSTRUCT */:
81726
+ {
81727
+ const value = new rawValue(...argumentList);
81728
+ returnValue = proxy(value);
81729
+ }
81730
+ break;
81731
+ case "ENDPOINT" /* MessageType.ENDPOINT */:
81732
+ {
81733
+ const { port1, port2 } = new MessageChannel();
81734
+ expose(obj, port2);
81735
+ returnValue = transfer(port1, [port1]);
81736
+ }
81737
+ break;
81738
+ case "RELEASE" /* MessageType.RELEASE */:
81739
+ {
81740
+ returnValue = undefined;
81741
+ }
81742
+ break;
81743
+ default:
81744
+ return;
81745
+ }
81746
+ }
81747
+ catch (value) {
81748
+ returnValue = { value, [throwMarker]: 0 };
81749
+ }
81750
+ Promise.resolve(returnValue)
81751
+ .catch((value) => {
81752
+ return { value, [throwMarker]: 0 };
81753
+ })
81754
+ .then((returnValue) => {
81755
+ const [wireValue, transferables] = toWireValue(returnValue);
81756
+ ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
81757
+ if (type === "RELEASE" /* MessageType.RELEASE */) {
81758
+ // detach and deactive after sending release response above.
81759
+ ep.removeEventListener("message", callback);
81760
+ closeEndPoint(ep);
81761
+ if (finalizer in obj && typeof obj[finalizer] === "function") {
81762
+ obj[finalizer]();
81763
+ }
81764
+ }
81765
+ })
81766
+ .catch((error) => {
81767
+ // Send Serialization Error To Caller
81768
+ const [wireValue, transferables] = toWireValue({
81769
+ value: new TypeError("Unserializable return value"),
81770
+ [throwMarker]: 0,
81771
+ });
81772
+ ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
81773
+ });
81774
+ });
81775
+ if (ep.start) {
81776
+ ep.start();
81777
+ }
81778
+ }
81779
+ function isMessagePort(endpoint) {
81780
+ return endpoint.constructor.name === "MessagePort";
81781
+ }
81782
+ function closeEndPoint(endpoint) {
81783
+ if (isMessagePort(endpoint))
81784
+ endpoint.close();
81785
+ }
81786
+ function wrap$1(ep, target) {
81787
+ const pendingListeners = new Map();
81788
+ ep.addEventListener("message", function handleMessage(ev) {
81789
+ const { data } = ev;
81790
+ if (!data || !data.id) {
81791
+ return;
81792
+ }
81793
+ const resolver = pendingListeners.get(data.id);
81794
+ if (!resolver) {
81795
+ return;
81796
+ }
81797
+ try {
81798
+ resolver(data);
81799
+ }
81800
+ finally {
81801
+ pendingListeners.delete(data.id);
81802
+ }
81803
+ });
81804
+ return createProxy(ep, pendingListeners, [], target);
81805
+ }
81806
+ function throwIfProxyReleased(isReleased) {
81807
+ if (isReleased) {
81808
+ throw new Error("Proxy has been released and is not useable");
81809
+ }
81810
+ }
81811
+ function releaseEndpoint(ep) {
81812
+ return requestResponseMessage(ep, new Map(), {
81813
+ type: "RELEASE" /* MessageType.RELEASE */,
81814
+ }).then(() => {
81815
+ closeEndPoint(ep);
81816
+ });
81817
+ }
81818
+ const proxyCounter = new WeakMap();
81819
+ const proxyFinalizers = "FinalizationRegistry" in globalThis &&
81820
+ new FinalizationRegistry((ep) => {
81821
+ const newCount = (proxyCounter.get(ep) || 0) - 1;
81822
+ proxyCounter.set(ep, newCount);
81823
+ if (newCount === 0) {
81824
+ releaseEndpoint(ep);
81825
+ }
81826
+ });
81827
+ function registerProxy(proxy, ep) {
81828
+ const newCount = (proxyCounter.get(ep) || 0) + 1;
81829
+ proxyCounter.set(ep, newCount);
81830
+ if (proxyFinalizers) {
81831
+ proxyFinalizers.register(proxy, ep, proxy);
81832
+ }
81833
+ }
81834
+ function unregisterProxy(proxy) {
81835
+ if (proxyFinalizers) {
81836
+ proxyFinalizers.unregister(proxy);
81837
+ }
81838
+ }
81839
+ function createProxy(ep, pendingListeners, path = [], target = function () { }) {
81840
+ let isProxyReleased = false;
81841
+ const proxy = new Proxy(target, {
81842
+ get(_target, prop) {
81843
+ throwIfProxyReleased(isProxyReleased);
81844
+ if (prop === releaseProxy) {
81845
+ return () => {
81846
+ unregisterProxy(proxy);
81847
+ releaseEndpoint(ep);
81848
+ pendingListeners.clear();
81849
+ isProxyReleased = true;
81850
+ };
81851
+ }
81852
+ if (prop === "then") {
81853
+ if (path.length === 0) {
81854
+ return { then: () => proxy };
81855
+ }
81856
+ const r = requestResponseMessage(ep, pendingListeners, {
81857
+ type: "GET" /* MessageType.GET */,
81858
+ path: path.map((p) => p.toString()),
81859
+ }).then(fromWireValue);
81860
+ return r.then.bind(r);
81861
+ }
81862
+ return createProxy(ep, pendingListeners, [...path, prop]);
81863
+ },
81864
+ set(_target, prop, rawValue) {
81865
+ throwIfProxyReleased(isProxyReleased);
81866
+ // FIXME: ES6 Proxy Handler `set` methods are supposed to return a
81867
+ // boolean. To show good will, we return true asynchronously ¯\_(ツ)_/¯
81868
+ const [value, transferables] = toWireValue(rawValue);
81869
+ return requestResponseMessage(ep, pendingListeners, {
81870
+ type: "SET" /* MessageType.SET */,
81871
+ path: [...path, prop].map((p) => p.toString()),
81872
+ value,
81873
+ }, transferables).then(fromWireValue);
81874
+ },
81875
+ apply(_target, _thisArg, rawArgumentList) {
81876
+ throwIfProxyReleased(isProxyReleased);
81877
+ const last = path[path.length - 1];
81878
+ if (last === createEndpoint) {
81879
+ return requestResponseMessage(ep, pendingListeners, {
81880
+ type: "ENDPOINT" /* MessageType.ENDPOINT */,
81881
+ }).then(fromWireValue);
81882
+ }
81883
+ // We just pretend that `bind()` didn’t happen.
81884
+ if (last === "bind") {
81885
+ return createProxy(ep, pendingListeners, path.slice(0, -1));
81886
+ }
81887
+ const [argumentList, transferables] = processArguments(rawArgumentList);
81888
+ return requestResponseMessage(ep, pendingListeners, {
81889
+ type: "APPLY" /* MessageType.APPLY */,
81890
+ path: path.map((p) => p.toString()),
81891
+ argumentList,
81892
+ }, transferables).then(fromWireValue);
81893
+ },
81894
+ construct(_target, rawArgumentList) {
81895
+ throwIfProxyReleased(isProxyReleased);
81896
+ const [argumentList, transferables] = processArguments(rawArgumentList);
81897
+ return requestResponseMessage(ep, pendingListeners, {
81898
+ type: "CONSTRUCT" /* MessageType.CONSTRUCT */,
81899
+ path: path.map((p) => p.toString()),
81900
+ argumentList,
81901
+ }, transferables).then(fromWireValue);
81902
+ },
81903
+ });
81904
+ registerProxy(proxy, ep);
81905
+ return proxy;
81906
+ }
81907
+ function myFlat(arr) {
81908
+ return Array.prototype.concat.apply([], arr);
81909
+ }
81910
+ function processArguments(argumentList) {
81911
+ const processed = argumentList.map(toWireValue);
81912
+ return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
81913
+ }
81914
+ const transferCache = new WeakMap();
81915
+ function transfer(obj, transfers) {
81916
+ transferCache.set(obj, transfers);
81917
+ return obj;
81918
+ }
81919
+ function proxy(obj) {
81920
+ return Object.assign(obj, { [proxyMarker]: true });
81921
+ }
81922
+ function toWireValue(value) {
81923
+ for (const [name, handler] of transferHandlers) {
81924
+ if (handler.canHandle(value)) {
81925
+ const [serializedValue, transferables] = handler.serialize(value);
81926
+ return [
81927
+ {
81928
+ type: "HANDLER" /* WireValueType.HANDLER */,
81929
+ name,
81930
+ value: serializedValue,
81931
+ },
81932
+ transferables,
81933
+ ];
81934
+ }
81935
+ }
81936
+ return [
81937
+ {
81938
+ type: "RAW" /* WireValueType.RAW */,
81939
+ value,
81940
+ },
81941
+ transferCache.get(value) || [],
81942
+ ];
81943
+ }
81944
+ function fromWireValue(value) {
81945
+ switch (value.type) {
81946
+ case "HANDLER" /* WireValueType.HANDLER */:
81947
+ return transferHandlers.get(value.name).deserialize(value.value);
81948
+ case "RAW" /* WireValueType.RAW */:
81949
+ return value.value;
81950
+ }
81951
+ }
81952
+ function requestResponseMessage(ep, pendingListeners, msg, transfers) {
81953
+ return new Promise((resolve) => {
81954
+ const id = generateUUID();
81955
+ pendingListeners.set(id, resolve);
81956
+ if (ep.start) {
81957
+ ep.start();
81958
+ }
81959
+ ep.postMessage(Object.assign({ id }, msg), transfers);
81960
+ });
81961
+ }
81962
+ function generateUUID() {
81963
+ return new Array(4)
81964
+ .fill(0)
81965
+ .map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))
81966
+ .join("-");
81967
+ }
81968
+
81604
81969
  var global$1;
81605
81970
  var hasRequiredGlobal;
81606
81971
 
@@ -85073,7 +85438,7 @@
85073
85438
  };
85074
85439
 
85075
85440
  const DEFAULT_MAX_CACHE_AGE = 1000 * 60 * 60; // 1 hour
85076
- const logger$v = new Logger('getLocalRegion');
85441
+ const logger$w = new Logger('getLocalRegion');
85077
85442
  let cachedLocalRegion = undefined;
85078
85443
  let cachedLocalRegionFetchTime = undefined;
85079
85444
  const getLocalAirportCode = async () => {
@@ -85093,7 +85458,7 @@
85093
85458
  // indicate that the region is random by adding 99, the convention is
85094
85459
  // that random region numbers end with 99
85095
85460
  const randomRegion = airportCodeToRegion[randomAirportCode][0] + 99;
85096
- logger$v.warn(`Could not get airport code, using random region: ${randomRegion}`);
85461
+ logger$w.warn(`Could not get airport code, using random region: ${randomRegion}`);
85097
85462
  return randomRegion;
85098
85463
  };
85099
85464
  const getLocalRegionWithCache = async (maxCacheAge = DEFAULT_MAX_CACHE_AGE) => {
@@ -87288,7 +87653,7 @@
87288
87653
  return v4();
87289
87654
  };
87290
87655
 
87291
- const logger$C = new Logger('ManagedConnection');
87656
+ const logger$D = new Logger('ManagedConnection');
87292
87657
  // ManagedConnection is a component used as a wrapper for IConnection after they have been successfully handshaked.
87293
87658
  // Should only be used in the ConnectionManager.
87294
87659
  class ManagedConnection extends EventEmitter {
@@ -87318,7 +87683,7 @@
87318
87683
  this.remotePeerDescriptor = peerDescriptor;
87319
87684
  }
87320
87685
  onDisconnected(gracefulLeave) {
87321
- logger$C.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' onDisconnected() ' + gracefulLeave);
87686
+ logger$D.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' onDisconnected() ' + gracefulLeave);
87322
87687
  if (!this.replacedAsDuplicate) {
87323
87688
  this.emit('disconnected', gracefulLeave);
87324
87689
  }
@@ -87327,7 +87692,7 @@
87327
87692
  // TODO: Can this be removed if ManagedConnections can never be duplicates?
87328
87693
  // Handle duplicates in the ConncetorFacade and no longer have PendingConnections in ConnectionManager
87329
87694
  replaceAsDuplicate() {
87330
- logger$C.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
87695
+ logger$D.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
87331
87696
  this.replacedAsDuplicate = true;
87332
87697
  }
87333
87698
  send(data) {
@@ -87474,10 +87839,10 @@
87474
87839
  }
87475
87840
  }
87476
87841
 
87477
- const logger$B = new Logger('ConnectionLockRpcRemote');
87842
+ const logger$C = new Logger('ConnectionLockRpcRemote');
87478
87843
  class ConnectionLockRpcRemote extends RpcRemote {
87479
87844
  async lockRequest(lockId) {
87480
- logger$B.trace(`Requesting locked connection to ${toNodeId(this.getPeerDescriptor())}`);
87845
+ logger$C.trace(`Requesting locked connection to ${toNodeId(this.getPeerDescriptor())}`);
87481
87846
  const request = {
87482
87847
  lockId
87483
87848
  };
@@ -87487,12 +87852,12 @@
87487
87852
  return res.accepted;
87488
87853
  }
87489
87854
  catch (err) {
87490
- logger$B.debug('Connection lock rejected', { err });
87855
+ logger$C.debug('Connection lock rejected', { err });
87491
87856
  return false;
87492
87857
  }
87493
87858
  }
87494
87859
  unlockRequest(lockId) {
87495
- logger$B.trace(`Requesting connection to be unlocked from ${toNodeId(this.getPeerDescriptor())}`);
87860
+ logger$C.trace(`Requesting connection to be unlocked from ${toNodeId(this.getPeerDescriptor())}`);
87496
87861
  const request = {
87497
87862
  lockId
87498
87863
  };
@@ -87500,11 +87865,11 @@
87500
87865
  notification: true
87501
87866
  });
87502
87867
  this.getClient().unlockRequest(request, options).catch((_e) => {
87503
- logger$B.trace('failed to send unlockRequest');
87868
+ logger$C.trace('failed to send unlockRequest');
87504
87869
  });
87505
87870
  }
87506
87871
  async gracefulDisconnect(disconnectMode) {
87507
- logger$B.trace(`Notifying a graceful disconnect to ${toNodeId(this.getPeerDescriptor())}`);
87872
+ logger$C.trace(`Notifying a graceful disconnect to ${toNodeId(this.getPeerDescriptor())}`);
87508
87873
  const request = {
87509
87874
  disconnectMode
87510
87875
  };
@@ -87516,7 +87881,7 @@
87516
87881
  await this.getClient().gracefulDisconnect(request, options);
87517
87882
  }
87518
87883
  async setPrivate(isPrivate) {
87519
- logger$B.trace(`Setting isPrivate: ${isPrivate} for ${toNodeId(this.getPeerDescriptor())}`);
87884
+ logger$C.trace(`Setting isPrivate: ${isPrivate} for ${toNodeId(this.getPeerDescriptor())}`);
87520
87885
  const request = {
87521
87886
  isPrivate
87522
87887
  };
@@ -87528,7 +87893,7 @@
87528
87893
  }
87529
87894
  }
87530
87895
 
87531
- const logger$A = new Logger('ConnectionLockRpcLocal');
87896
+ const logger$B = new Logger('ConnectionLockRpcLocal');
87532
87897
  class ConnectionLockRpcLocal {
87533
87898
  options;
87534
87899
  constructor(options) {
@@ -87557,7 +87922,7 @@
87557
87922
  }
87558
87923
  async gracefulDisconnect(disconnectNotice, context) {
87559
87924
  const senderPeerDescriptor = context.incomingSourceDescriptor;
87560
- logger$A.trace(getNodeIdOrUnknownFromPeerDescriptor(senderPeerDescriptor) + ' received gracefulDisconnect notice');
87925
+ logger$B.trace(getNodeIdOrUnknownFromPeerDescriptor(senderPeerDescriptor) + ' received gracefulDisconnect notice');
87561
87926
  if (disconnectNotice.disconnectMode === DisconnectMode$2.LEAVING) {
87562
87927
  await this.options.closeConnection(senderPeerDescriptor, true, 'graceful leave notified');
87563
87928
  }
@@ -87608,7 +87973,7 @@
87608
87973
  NatType["OPEN_INTERNET"] = "open_internet";
87609
87974
  NatType["UNKNOWN"] = "unknown";
87610
87975
  })(NatType || (NatType = {}));
87611
- const logger$z = new Logger('ConnectionManager');
87976
+ const logger$A = new Logger('ConnectionManager');
87612
87977
  var ConnectionManagerState;
87613
87978
  (function (ConnectionManagerState) {
87614
87979
  ConnectionManagerState["IDLE"] = "idle";
@@ -87658,7 +88023,7 @@
87658
88023
  getLocalPeerDescriptor: () => this.getLocalPeerDescriptor(),
87659
88024
  setPrivate: (id, isPrivate) => {
87660
88025
  if (!this.options.allowIncomingPrivateConnections) {
87661
- logger$z.debug(`node ${id} attemted to set a connection as private, but it is not allowed`);
88026
+ logger$A.debug(`node ${id} attemted to set a connection as private, but it is not allowed`);
87662
88027
  return;
87663
88028
  }
87664
88029
  if (isPrivate) {
@@ -87692,7 +88057,7 @@
87692
88057
  const connection = endpoint.connection;
87693
88058
  const nodeId = connection.getNodeId();
87694
88059
  if (!this.locks.isLocked(nodeId) && !this.locks.isPrivate(nodeId) && Date.now() - connection.getLastUsedTimestamp() > maxIdleTime) {
87695
- logger$z.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()));
88060
+ logger$A.trace('disconnecting in timeout interval: ' + getNodeIdOrUnknownFromPeerDescriptor(connection.getPeerDescriptor()));
87696
88061
  disconnectionCandidates.addContact(connection);
87697
88062
  }
87698
88063
  }
@@ -87700,7 +88065,7 @@
87700
88065
  const disconnectables = disconnectionCandidates.getFurthestContacts(this.endpoints.size - maxConnections);
87701
88066
  for (const disconnectable of disconnectables) {
87702
88067
  const peerDescriptor = disconnectable.getPeerDescriptor();
87703
- logger$z.trace('garbageCollecting ' + toNodeId(peerDescriptor));
88068
+ logger$A.trace('garbageCollecting ' + toNodeId(peerDescriptor));
87704
88069
  this.gracefullyDisconnectAsync(peerDescriptor, DisconnectMode$2.NORMAL).catch((_e) => { });
87705
88070
  }
87706
88071
  }
@@ -87709,11 +88074,11 @@
87709
88074
  throw new CouldNotStart(`Cannot start already ${this.state} module`);
87710
88075
  }
87711
88076
  this.state = ConnectionManagerState.RUNNING;
87712
- logger$z.trace(`Starting ConnectionManager...`);
88077
+ logger$A.trace(`Starting ConnectionManager...`);
87713
88078
  await this.connectorFacade.start((connection) => this.onNewConnection(connection), (nodeId) => this.hasConnection(nodeId), this);
87714
88079
  // Garbage collection of connections
87715
88080
  this.disconnectorIntervalRef = setInterval(() => {
87716
- logger$z.trace('disconnectorInterval');
88081
+ logger$A.trace('disconnectorInterval');
87717
88082
  const LAST_USED_LIMIT = 20000;
87718
88083
  this.garbageCollectConnections(this.options.maxConnections ?? 80, LAST_USED_LIMIT);
87719
88084
  }, 5000); // TODO use options option or named constant?
@@ -87723,7 +88088,7 @@
87723
88088
  return;
87724
88089
  }
87725
88090
  this.state = ConnectionManagerState.STOPPING;
87726
- logger$z.trace(`Stopping ConnectionManager`);
88091
+ logger$A.trace(`Stopping ConnectionManager`);
87727
88092
  if (this.disconnectorIntervalRef) {
87728
88093
  clearInterval(this.disconnectorIntervalRef);
87729
88094
  }
@@ -87733,23 +88098,23 @@
87733
88098
  await this.gracefullyDisconnectAsync(endpoint.connection.getPeerDescriptor(), DisconnectMode$2.LEAVING);
87734
88099
  }
87735
88100
  catch (e) {
87736
- logger$z.error(e);
88101
+ logger$A.error(e);
87737
88102
  }
87738
88103
  }
87739
88104
  else {
87740
88105
  const connection = endpoint.connection;
87741
- logger$z.trace('handshake of connection not completed, force-closing');
88106
+ logger$A.trace('handshake of connection not completed, force-closing');
87742
88107
  // TODO use options option or named constant?
87743
88108
  const eventReceived = waitForEvent(connection, 'disconnected', 2000);
87744
88109
  // TODO should we have some handling for this floating promise?
87745
88110
  connection.close(true);
87746
88111
  try {
87747
88112
  await eventReceived;
87748
- logger$z.trace('resolving after receiving disconnected event from non-handshaked connection');
88113
+ logger$A.trace('resolving after receiving disconnected event from non-handshaked connection');
87749
88114
  }
87750
88115
  catch (e) {
87751
88116
  endpoint.buffer.reject();
87752
- logger$z.trace('force-closing non-handshaked connection timed out ' + e);
88117
+ logger$A.trace('force-closing non-handshaked connection timed out ' + e);
87753
88118
  }
87754
88119
  }
87755
88120
  }));
@@ -87778,7 +88143,7 @@
87778
88143
  throw new CannotConnectToSelf('Cannot send to self');
87779
88144
  }
87780
88145
  const nodeId = toNodeId(peerDescriptor);
87781
- logger$z.trace(`Sending message to: ${nodeId}`);
88146
+ logger$A.trace(`Sending message to: ${nodeId}`);
87782
88147
  message = {
87783
88148
  ...message,
87784
88149
  sourceDescriptor: this.getLocalPeerDescriptor()
@@ -87833,13 +88198,13 @@
87833
88198
  }
87834
88199
  handleMessage(message) {
87835
88200
  const messageType = message.body.oneofKind;
87836
- logger$z.trace('Received message of type ' + messageType);
88201
+ logger$A.trace('Received message of type ' + messageType);
87837
88202
  if (messageType !== 'rpcMessage') {
87838
- logger$z.trace('Filtered out non-RPC message of type ' + messageType);
88203
+ logger$A.trace('Filtered out non-RPC message of type ' + messageType);
87839
88204
  return;
87840
88205
  }
87841
88206
  if (this.duplicateMessageDetector.isMostLikelyDuplicate(message.messageId)) {
87842
- logger$z.trace('handleMessage filtered duplicate ' + toNodeId(message.sourceDescriptor)
88207
+ logger$A.trace('handleMessage filtered duplicate ' + toNodeId(message.sourceDescriptor)
87843
88208
  + ' ' + message.serviceId + ' ' + message.messageId);
87844
88209
  return;
87845
88210
  }
@@ -87848,7 +88213,7 @@
87848
88213
  this.rpcCommunicator?.handleMessageFromPeer(message);
87849
88214
  }
87850
88215
  else {
87851
- logger$z.trace('emit "message" ' + toNodeId(message.sourceDescriptor)
88216
+ logger$A.trace('emit "message" ' + toNodeId(message.sourceDescriptor)
87852
88217
  + ' ' + message.serviceId + ' ' + message.messageId);
87853
88218
  this.emit('message', message);
87854
88219
  }
@@ -87865,7 +88230,7 @@
87865
88230
  }
87866
88231
  catch (e) {
87867
88232
  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
87868
- logger$z.debug(`Parsing incoming data into Message failed: ${e}`);
88233
+ logger$A.debug(`Parsing incoming data into Message failed: ${e}`);
87869
88234
  return;
87870
88235
  }
87871
88236
  message.sourceDescriptor = peerDescriptor;
@@ -87874,7 +88239,7 @@
87874
88239
  }
87875
88240
  catch (e) {
87876
88241
  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
87877
- logger$z.debug(`Handling incoming data failed: ${e}`);
88242
+ logger$A.debug(`Handling incoming data failed: ${e}`);
87878
88243
  }
87879
88244
  }
87880
88245
  onConnected(peerDescriptor, connection) {
@@ -87887,7 +88252,7 @@
87887
88252
  const pendingConnection = endpoint.connection;
87888
88253
  const buffer = outputBuffer.getBuffer();
87889
88254
  while (buffer.length > 0) {
87890
- logger$z.trace('emptying buffer');
88255
+ logger$A.trace('emptying buffer');
87891
88256
  managedConnection.send(buffer.shift());
87892
88257
  }
87893
88258
  outputBuffer.resolve();
@@ -87904,7 +88269,7 @@
87904
88269
  }
87905
88270
  onDisconnected(peerDescriptor, gracefulLeave) {
87906
88271
  const nodeId = toNodeId(peerDescriptor);
87907
- logger$z.trace(nodeId + ' onDisconnected() gracefulLeave: ' + gracefulLeave);
88272
+ logger$A.trace(nodeId + ' onDisconnected() gracefulLeave: ' + gracefulLeave);
87908
88273
  const endpoint = this.endpoints.get(nodeId);
87909
88274
  if (endpoint) {
87910
88275
  this.locks.clearAllLocks(nodeId);
@@ -87912,7 +88277,7 @@
87912
88277
  endpoint.buffer.reject();
87913
88278
  }
87914
88279
  this.endpoints.delete(nodeId);
87915
- logger$z.trace(nodeId + ' deleted connection in onDisconnected() gracefulLeave: ' + gracefulLeave);
88280
+ logger$A.trace(nodeId + ' deleted connection in onDisconnected() gracefulLeave: ' + gracefulLeave);
87916
88281
  this.emit('disconnected', peerDescriptor, gracefulLeave);
87917
88282
  this.onConnectionCountChange();
87918
88283
  }
@@ -87921,7 +88286,7 @@
87921
88286
  if (this.state === ConnectionManagerState.STOPPED) {
87922
88287
  return false;
87923
88288
  }
87924
- logger$z.trace('onNewConnection()');
88289
+ logger$A.trace('onNewConnection()');
87925
88290
  if (!this.acceptNewConnection(connection)) {
87926
88291
  return false;
87927
88292
  }
@@ -87931,7 +88296,7 @@
87931
88296
  }
87932
88297
  acceptNewConnection(newConnection) {
87933
88298
  const nodeId = toNodeId(newConnection.getPeerDescriptor());
87934
- logger$z.trace(nodeId + ' acceptNewConnection()');
88299
+ logger$A.trace(nodeId + ' acceptNewConnection()');
87935
88300
  if (this.endpoints.has(nodeId)) {
87936
88301
  if (getOfferer(toNodeId(this.getLocalPeerDescriptor()), nodeId) === 'remote') {
87937
88302
  let buffer;
@@ -87940,14 +88305,14 @@
87940
88305
  // Could be related to WS client connections not realizing that they have been disconnected.
87941
88306
  // Makes refactoring duplicate connection handling to the connectors very difficult.
87942
88307
  if (this.endpoints.get(nodeId).connected) {
87943
- logger$z.debug('replacing connected connection', { nodeId });
88308
+ logger$A.debug('replacing connected connection', { nodeId });
87944
88309
  buffer = new OutputBuffer();
87945
88310
  }
87946
88311
  else {
87947
88312
  buffer = endpoint.buffer;
87948
88313
  }
87949
88314
  const oldConnection = endpoint.connection;
87950
- logger$z.trace('replaced: ' + nodeId);
88315
+ logger$A.trace('replaced: ' + nodeId);
87951
88316
  oldConnection.replaceAsDuplicate();
87952
88317
  this.endpoints.set(nodeId, { connected: false, connection: newConnection, buffer: buffer });
87953
88318
  return true;
@@ -87956,7 +88321,7 @@
87956
88321
  return false;
87957
88322
  }
87958
88323
  }
87959
- logger$z.trace(nodeId + ' added to connections at acceptNewConnection');
88324
+ logger$A.trace(nodeId + ' added to connections at acceptNewConnection');
87960
88325
  this.endpoints.set(nodeId, {
87961
88326
  connected: false,
87962
88327
  buffer: new OutputBuffer(),
@@ -87966,14 +88331,14 @@
87966
88331
  }
87967
88332
  async closeConnection(peerDescriptor, gracefulLeave, reason) {
87968
88333
  const nodeId = toNodeId(peerDescriptor);
87969
- logger$z.trace(nodeId + ' ' + 'closeConnection() ' + reason);
88334
+ logger$A.trace(nodeId + ' ' + 'closeConnection() ' + reason);
87970
88335
  this.locks.clearAllLocks(nodeId);
87971
88336
  if (this.endpoints.has(nodeId)) {
87972
88337
  const connectionToClose = this.endpoints.get(nodeId).connection;
87973
88338
  await connectionToClose.close(gracefulLeave);
87974
88339
  }
87975
88340
  else {
87976
- logger$z.trace(nodeId + ' ' + 'closeConnection() this.endpoints did not have the id');
88341
+ logger$A.trace(nodeId + ' ' + 'closeConnection() this.endpoints did not have the id');
87977
88342
  this.emit('disconnected', peerDescriptor, false);
87978
88343
  }
87979
88344
  }
@@ -87985,8 +88350,8 @@
87985
88350
  const rpcRemote = new ConnectionLockRpcRemote(this.getLocalPeerDescriptor(), targetDescriptor, this.rpcCommunicator, ConnectionLockRpcClient);
87986
88351
  this.locks.addLocalLocked(nodeId, lockId);
87987
88352
  rpcRemote.lockRequest(lockId)
87988
- .then((_accepted) => logger$z.trace('LockRequest successful'))
87989
- .catch((err) => { logger$z.debug(err); });
88353
+ .then((_accepted) => logger$A.trace('LockRequest successful'))
88354
+ .catch((err) => { logger$A.debug(err); });
87990
88355
  }
87991
88356
  unlockConnection(targetDescriptor, lockId) {
87992
88357
  if (this.state === ConnectionManagerState.STOPPED || areEqualPeerDescriptors(targetDescriptor, this.getLocalPeerDescriptor())) {
@@ -88038,7 +88403,7 @@
88038
88403
  async gracefullyDisconnectAsync(targetDescriptor, disconnectMode) {
88039
88404
  const endpoint = this.endpoints.get(toNodeId(targetDescriptor));
88040
88405
  if (!endpoint) {
88041
- logger$z.debug('gracefullyDisconnectedAsync() tried on a non-existing connection');
88406
+ logger$A.debug('gracefullyDisconnectedAsync() tried on a non-existing connection');
88042
88407
  return;
88043
88408
  }
88044
88409
  if (endpoint.connected) {
@@ -88047,15 +88412,15 @@
88047
88412
  // TODO use options option or named constant?
88048
88413
  // eslint-disable-next-line promise/catch-or-return
88049
88414
  waitForEvent(connection, 'disconnected', 2000).then(() => {
88050
- logger$z.trace('disconnected event received in gracefullyDisconnectAsync()');
88415
+ logger$A.trace('disconnected event received in gracefullyDisconnectAsync()');
88051
88416
  })
88052
88417
  .catch((e) => {
88053
- logger$z.trace('force-closing connection after timeout ' + e);
88418
+ logger$A.trace('force-closing connection after timeout ' + e);
88054
88419
  // TODO should we have some handling for this floating promise?
88055
88420
  connection.close(true);
88056
88421
  })
88057
88422
  .finally(() => {
88058
- logger$z.trace('resolving after receiving disconnected event');
88423
+ logger$A.trace('resolving after receiving disconnected event');
88059
88424
  resolve();
88060
88425
  });
88061
88426
  });
@@ -88070,13 +88435,13 @@
88070
88435
  }
88071
88436
  async doGracefullyDisconnectAsync(targetDescriptor, disconnectMode) {
88072
88437
  const nodeId = toNodeId(targetDescriptor);
88073
- logger$z.trace(nodeId + ' gracefullyDisconnectAsync()');
88438
+ logger$A.trace(nodeId + ' gracefullyDisconnectAsync()');
88074
88439
  const rpcRemote = new ConnectionLockRpcRemote(this.getLocalPeerDescriptor(), targetDescriptor, this.rpcCommunicator, ConnectionLockRpcClient);
88075
88440
  try {
88076
88441
  await rpcRemote.gracefulDisconnect(disconnectMode);
88077
88442
  }
88078
88443
  catch (ex) {
88079
- logger$z.trace(nodeId + ' remote.gracefulDisconnect() failed' + ex);
88444
+ logger$A.trace(nodeId + ' remote.gracefulDisconnect() failed' + ex);
88080
88445
  }
88081
88446
  }
88082
88447
  getConnections() {
@@ -88136,9 +88501,9 @@
88136
88501
  }
88137
88502
  };
88138
88503
 
88139
- var version$2 = "103.3.1";
88504
+ var version$2 = "103.6.0-rc.0";
88140
88505
 
88141
- const logger$x = new Logger('Handshaker');
88506
+ const logger$y = new Logger('Handshaker');
88142
88507
  // Optimally the Outgoing and Incoming Handshakers could be their own separate classes
88143
88508
  // However, in cases where the PeerDescriptor of the other end of the connection can be known
88144
88509
  // only after a HandshakeRequest a base Handshaker class is needed as the IncomingHandshaker currently
@@ -88160,7 +88525,7 @@
88160
88525
  }
88161
88526
  };
88162
88527
  const handshakeCompletedListener = (peerDescriptor) => {
88163
- logger$x.trace('handshake completed for outgoing connection, ' + toNodeId(peerDescriptor));
88528
+ logger$y.trace('handshake completed for outgoing connection, ' + toNodeId(peerDescriptor));
88164
88529
  pendingConnection.onHandshakeCompleted(connection);
88165
88530
  stopHandshaker();
88166
88531
  };
@@ -88260,12 +88625,12 @@
88260
88625
  try {
88261
88626
  const message = Message$2.fromBinary(data);
88262
88627
  if (message.body.oneofKind === 'handshakeRequest') {
88263
- logger$x.trace('handshake request received');
88628
+ logger$y.trace('handshake request received');
88264
88629
  const handshake = message.body.handshakeRequest;
88265
88630
  this.emit('handshakeRequest', handshake.sourcePeerDescriptor, handshake.protocolVersion, handshake.targetPeerDescriptor);
88266
88631
  }
88267
88632
  if (message.body.oneofKind === 'handshakeResponse') {
88268
- logger$x.trace('handshake response received');
88633
+ logger$y.trace('handshake response received');
88269
88634
  const handshake = message.body.handshakeResponse;
88270
88635
  const error = !isMaybeSupportedProtocolVersion(handshake.protocolVersion)
88271
88636
  ? HandshakeError$2.UNSUPPORTED_PROTOCOL_VERSION : handshake.error;
@@ -88278,18 +88643,18 @@
88278
88643
  }
88279
88644
  }
88280
88645
  catch (err) {
88281
- logger$x.debug('error while parsing handshake message', err);
88646
+ logger$y.debug('error while parsing handshake message', err);
88282
88647
  }
88283
88648
  }
88284
88649
  sendHandshakeRequest(remotePeerDescriptor) {
88285
88650
  const msg = createHandshakeRequest(this.localPeerDescriptor, remotePeerDescriptor);
88286
88651
  this.connection.send(Message$2.toBinary(msg));
88287
- logger$x.trace('handshake request sent');
88652
+ logger$y.trace('handshake request sent');
88288
88653
  }
88289
88654
  sendHandshakeResponse(error) {
88290
88655
  const msg = createHandshakeResponse(this.localPeerDescriptor, error);
88291
88656
  this.connection.send(Message$2.toBinary(msg));
88292
- logger$x.trace('handshake response sent');
88657
+ logger$y.trace('handshake response sent');
88293
88658
  }
88294
88659
  stop() {
88295
88660
  this.connection.off('data', this.onDataListener);
@@ -88297,7 +88662,7 @@
88297
88662
  }
88298
88663
  };
88299
88664
 
88300
- const logger$w = new Logger('PendingConnection');
88665
+ const logger$x = new Logger('PendingConnection');
88301
88666
  // PendingConnection is used as a reference to a connection that should be opened and handshaked to a given PeerDescriptor
88302
88667
  // It does not hold a connection internally. The public method onHandshakedCompleted should be called once a connection for the
88303
88668
  // remotePeerDescriptor is opened and handshaked successfully.
@@ -88315,7 +88680,7 @@
88315
88680
  }, timeout, this.connectingAbortController.signal);
88316
88681
  }
88317
88682
  replaceAsDuplicate() {
88318
- logger$w.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
88683
+ logger$x.trace(getNodeIdOrUnknownFromPeerDescriptor(this.remotePeerDescriptor) + ' replaceAsDuplicate');
88319
88684
  this.replacedAsDuplicate = true;
88320
88685
  }
88321
88686
  onHandshakeCompleted(connection) {
@@ -88372,6 +88737,8 @@
88372
88737
  }
88373
88738
  }
88374
88739
 
88740
+ const isWorkerEnvironment = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
88741
+
88375
88742
  var RtcDescription;
88376
88743
  (function (RtcDescription) {
88377
88744
  RtcDescription["OFFER"] = "offer";
@@ -88386,8 +88753,8 @@
88386
88753
  DisconnectedRtcPeerConnectionStateEnum["FAILED"] = "failed";
88387
88754
  DisconnectedRtcPeerConnectionStateEnum["CLOSED"] = "closed";
88388
88755
  })(DisconnectedRtcPeerConnectionStateEnum || (DisconnectedRtcPeerConnectionStateEnum = {}));
88389
- const logger$u = new Logger('WebrtcConnection (browser)');
88390
- class WebrtcConnection extends EventEmitter {
88756
+ const logger$v = new Logger('DirectWebrtcConnection (browser)');
88757
+ class DirectWebrtcConnection extends EventEmitter {
88391
88758
  connectionId;
88392
88759
  connectionType = ConnectionType.WEBRTC;
88393
88760
  // We need to keep track of connection state ourselves because
@@ -88425,7 +88792,7 @@
88425
88792
  }
88426
88793
  };
88427
88794
  this.peerConnection.onicegatheringstatechange = () => {
88428
- logger$u.trace(`conn.onGatheringStateChange: ${this.peerConnection?.iceGatheringState}`);
88795
+ logger$v.trace(`conn.onGatheringStateChange: ${this.peerConnection?.iceGatheringState}`);
88429
88796
  };
88430
88797
  this.peerConnection.onconnectionstatechange = () => this.onStateChange();
88431
88798
  if (isOffering) {
@@ -88436,7 +88803,7 @@
88436
88803
  await this.peerConnection.setLocalDescription();
88437
88804
  }
88438
88805
  catch (err) {
88439
- logger$u.warn('Failed to set local description', { err });
88806
+ logger$v.warn('Failed to set local description', { err });
88440
88807
  }
88441
88808
  if (this.peerConnection.localDescription !== null) {
88442
88809
  this.emit('localDescription', this.peerConnection.localDescription?.sdp, this.peerConnection.localDescription?.type);
@@ -88464,14 +88831,14 @@
88464
88831
  clearTimeout(this.earlyTimeout);
88465
88832
  }
88466
88833
  catch (err) {
88467
- logger$u.warn('Failed to set remote description', { err });
88834
+ logger$v.warn('Failed to set remote description', { err });
88468
88835
  }
88469
88836
  if ((type.toLowerCase() === RtcDescription.OFFER) && (this.peerConnection !== undefined)) {
88470
88837
  try {
88471
88838
  await this.peerConnection.setLocalDescription();
88472
88839
  }
88473
88840
  catch (err) {
88474
- logger$u.warn('Failed to set local description', { err });
88841
+ logger$v.warn('Failed to set local description', { err });
88475
88842
  }
88476
88843
  if (this.peerConnection.localDescription !== null) {
88477
88844
  this.emit('localDescription', this.peerConnection.localDescription.sdp, this.peerConnection.localDescription.type);
@@ -88481,7 +88848,7 @@
88481
88848
  addRemoteCandidate(candidate, mid) {
88482
88849
  this.peerConnection?.addIceCandidate({ candidate: candidate, sdpMid: mid })
88483
88850
  .catch((err) => {
88484
- logger$u.warn('Failed to add ICE candidate', { err });
88851
+ logger$v.warn('Failed to add ICE candidate', { err });
88485
88852
  });
88486
88853
  }
88487
88854
  isOpen() {
@@ -88504,7 +88871,7 @@
88504
88871
  this.dataChannel.close();
88505
88872
  }
88506
88873
  catch (err) {
88507
- logger$u.warn('Failed to close data channel', { err });
88874
+ logger$v.warn('Failed to close data channel', { err });
88508
88875
  }
88509
88876
  }
88510
88877
  this.dataChannel = undefined;
@@ -88513,7 +88880,7 @@
88513
88880
  this.peerConnection.close();
88514
88881
  }
88515
88882
  catch (err) {
88516
- logger$u.warn('Failed to close connection', { err });
88883
+ logger$v.warn('Failed to close connection', { err });
88517
88884
  }
88518
88885
  }
88519
88886
  this.peerConnection = undefined;
@@ -88533,7 +88900,7 @@
88533
88900
  }
88534
88901
  }
88535
88902
  else {
88536
- logger$u.warn('Tried to send on a connection with last state ' + this.lastState);
88903
+ logger$v.warn('Tried to send on a connection with last state ' + this.lastState);
88537
88904
  }
88538
88905
  }
88539
88906
  setupDataChannel(dataChannel) {
@@ -88541,22 +88908,22 @@
88541
88908
  this.dataChannel.binaryType = 'arraybuffer';
88542
88909
  this.dataChannel.bufferedAmountLowThreshold = this.bufferThresholdLow;
88543
88910
  dataChannel.onopen = () => {
88544
- logger$u.trace('dc.onOpen');
88911
+ logger$v.trace('dc.onOpen');
88545
88912
  this.onDataChannelOpen();
88546
88913
  };
88547
88914
  dataChannel.onclose = () => {
88548
- logger$u.trace('dc.onClosed');
88915
+ logger$v.trace('dc.onClosed');
88549
88916
  this.doClose(false);
88550
88917
  };
88551
88918
  dataChannel.onerror = (err) => {
88552
- logger$u.warn('Data channel error', { err });
88919
+ logger$v.warn('Data channel error', { err });
88553
88920
  };
88554
88921
  dataChannel.onmessage = (msg) => {
88555
- logger$u.trace('dc.onmessage');
88922
+ logger$v.trace('dc.onmessage');
88556
88923
  this.emit('data', new Uint8Array(msg.data));
88557
88924
  };
88558
88925
  dataChannel.onbufferedamountlow = () => {
88559
- logger$u.trace('dc.onBufferedAmountLow');
88926
+ logger$v.trace('dc.onBufferedAmountLow');
88560
88927
  while (this.messageQueue.length > 0 && this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
88561
88928
  const data = this.messageQueue.shift();
88562
88929
  this.dataChannel.send(data);
@@ -88595,6 +88962,289 @@
88595
88962
  }
88596
88963
  }
88597
88964
 
88965
+ /**
88966
+ * Call this function on the **main thread** before the worker starts using
88967
+ * WebRTC connections. It creates a dedicated `MessageChannel`, exposes a
88968
+ * {@link WebrtcBridge} instance on one port, and sends the other port to
88969
+ * the worker so that `WorkerWebrtcConnection` can reach the bridge.
88970
+ *
88971
+ * @example
88972
+ * ```ts
88973
+ * import { installWebrtcBridge } from '@streamr/dht'
88974
+ *
88975
+ * const worker = new Worker('./my-worker.ts', { type: 'module' })
88976
+ * installWebrtcBridge(worker)
88977
+ * ```
88978
+ */
88979
+ const WEBRTC_BRIDGE_PORT_MESSAGE_TYPE = 'streamr-webrtc-bridge-port';
88980
+
88981
+ /**
88982
+ * WorkerWebrtcConnection — runs inside a **Web Worker**.
88983
+ *
88984
+ * Implements the same IWebrtcConnection + IConnection interfaces as
88985
+ * DirectWebrtcConnection, but delegates RTCPeerConnection management to
88986
+ * the main-thread {@link WebrtcBridge} via Comlink.
88987
+ *
88988
+ * The RTCDataChannel is **transferred** from the main thread and lives
88989
+ * entirely in the worker — all data events (onmessage, onopen, onclose,
88990
+ * onbufferedamountlow) fire in the worker's event loop. The main thread
88991
+ * is never involved in the data path.
88992
+ */
88993
+ // ── Module-level bridge client (initialized once per worker) ────────
88994
+ let resolveBridgeProxy;
88995
+ const bridgeProxyPromise = new Promise((resolve) => {
88996
+ resolveBridgeProxy = resolve;
88997
+ });
88998
+ // Listen for the bridge port message from the main thread.
88999
+ // This is guarded so it only runs inside a worker context.
89000
+ if (isWorkerEnvironment) {
89001
+ const handler = (e) => {
89002
+ if (e.data?.type === WEBRTC_BRIDGE_PORT_MESSAGE_TYPE && e.data.port) {
89003
+ const proxy = wrap$1(e.data.port);
89004
+ resolveBridgeProxy(proxy);
89005
+ self.removeEventListener('message', handler);
89006
+ }
89007
+ };
89008
+ self.addEventListener('message', handler);
89009
+ }
89010
+ function getBridgeProxy() {
89011
+ return bridgeProxyPromise;
89012
+ }
89013
+ // ── Disconnection states ────────────────────────────────────────────
89014
+ var DisconnectedState;
89015
+ (function (DisconnectedState) {
89016
+ DisconnectedState["DISCONNECTED"] = "disconnected";
89017
+ DisconnectedState["FAILED"] = "failed";
89018
+ DisconnectedState["CLOSED"] = "closed";
89019
+ })(DisconnectedState || (DisconnectedState = {}));
89020
+ const logger$u = new Logger('WorkerWebrtcConnection');
89021
+ // ── WorkerWebrtcConnection ──────────────────────────────────────────
89022
+ class WorkerWebrtcConnection extends EventEmitter {
89023
+ connectionId;
89024
+ connectionType = ConnectionType.WEBRTC;
89025
+ iceServers;
89026
+ bufferThresholdHigh;
89027
+ bufferThresholdLow;
89028
+ dataChannel;
89029
+ bridge;
89030
+ closed = false;
89031
+ connected = false;
89032
+ earlyTimeout;
89033
+ messageQueue = [];
89034
+ startPromise;
89035
+ constructor(params) {
89036
+ super();
89037
+ this.connectionId = createRandomConnectionId();
89038
+ this.iceServers = params.iceServers ?? [];
89039
+ this.bufferThresholdHigh = params.bufferThresholdHigh ?? 2 ** 17;
89040
+ this.bufferThresholdLow = params.bufferThresholdLow ?? 2 ** 15;
89041
+ this.earlyTimeout = setTimeout(() => {
89042
+ this.doClose(false, 'timed out due to remote descriptor not being set');
89043
+ }, EARLY_TIMEOUT);
89044
+ }
89045
+ // ── IWebrtcConnection ───────────────────────────────────────
89046
+ start(isOffering) {
89047
+ this.startPromise = this.doStart(isOffering);
89048
+ this.startPromise.catch((err) => {
89049
+ logger$u.warn('Failed to start worker WebRTC connection', { err });
89050
+ this.doClose(false, 'Failed to start');
89051
+ });
89052
+ }
89053
+ async doStart(isOffering) {
89054
+ this.bridge = await getBridgeProxy();
89055
+ const iceServers = this.iceServers.map(({ url, port, username, password }) => ({
89056
+ urls: `${url}:${port}`,
89057
+ username,
89058
+ credential: password,
89059
+ }));
89060
+ await this.bridge.start(this.connectionId, iceServers, isOffering, proxy({
89061
+ onLocalCandidate: (candidate, mid) => {
89062
+ if (!this.closed) {
89063
+ this.emit('localCandidate', candidate, mid);
89064
+ }
89065
+ },
89066
+ onLocalDescription: (description, type) => {
89067
+ if (!this.closed) {
89068
+ this.emit('localDescription', description, type);
89069
+ }
89070
+ },
89071
+ onConnectionStateChange: (state) => {
89072
+ if (state === DisconnectedState.CLOSED ||
89073
+ state === DisconnectedState.DISCONNECTED ||
89074
+ state === DisconnectedState.FAILED) {
89075
+ this.doClose(false);
89076
+ }
89077
+ },
89078
+ onDataChannel: (channel) => {
89079
+ if (!this.closed) {
89080
+ this.setupDataChannel(channel);
89081
+ // If the channel was already open at transfer time
89082
+ if (channel.readyState === 'open') {
89083
+ this.onDataChannelOpen();
89084
+ }
89085
+ }
89086
+ },
89087
+ }));
89088
+ }
89089
+ async setRemoteDescription(description, type) {
89090
+ if (this.startPromise) {
89091
+ await this.startPromise;
89092
+ }
89093
+ if (!this.bridge || this.closed) {
89094
+ return;
89095
+ }
89096
+ const wasSet = await this.bridge.setRemoteDescription(this.connectionId, description, type);
89097
+ if (wasSet) {
89098
+ clearTimeout(this.earlyTimeout);
89099
+ }
89100
+ }
89101
+ addRemoteCandidate(candidate, mid) {
89102
+ this.doAddRemoteCandidate(candidate, mid).catch((err) => {
89103
+ logger$u.warn('Failed to add remote candidate via bridge', { err });
89104
+ });
89105
+ }
89106
+ async doAddRemoteCandidate(candidate, mid) {
89107
+ if (this.startPromise) {
89108
+ await this.startPromise;
89109
+ }
89110
+ if (!this.bridge || this.closed) {
89111
+ return;
89112
+ }
89113
+ await this.bridge.addRemoteCandidate(this.connectionId, candidate, mid);
89114
+ }
89115
+ isOpen() {
89116
+ return this.connected;
89117
+ }
89118
+ // ── IConnection ─────────────────────────────────────────────
89119
+ async close(gracefulLeave, reason) {
89120
+ this.doClose(gracefulLeave, reason);
89121
+ }
89122
+ destroy() {
89123
+ this.removeAllListeners();
89124
+ this.doClose(false);
89125
+ }
89126
+ send(data) {
89127
+ if (this.connected && this.dataChannel) {
89128
+ if (this.dataChannel.bufferedAmount > this.bufferThresholdHigh) {
89129
+ this.messageQueue.push(data);
89130
+ }
89131
+ else {
89132
+ this.dataChannel.send(data);
89133
+ }
89134
+ }
89135
+ else if (!this.closed) {
89136
+ this.messageQueue.push(data);
89137
+ }
89138
+ }
89139
+ setConnectionId(connectionId) {
89140
+ const oldId = this.connectionId;
89141
+ this.connectionId = connectionId;
89142
+ if (this.bridge && oldId !== connectionId) {
89143
+ this.bridge.renameConnection(oldId, connectionId).catch(() => { });
89144
+ }
89145
+ }
89146
+ // ── DataChannel handling (runs entirely in the worker) ──────
89147
+ setupDataChannel(dataChannel) {
89148
+ this.dataChannel = dataChannel;
89149
+ this.dataChannel.binaryType = 'arraybuffer';
89150
+ this.dataChannel.bufferedAmountLowThreshold = this.bufferThresholdLow;
89151
+ dataChannel.onopen = () => {
89152
+ logger$u.trace('dc.onOpen (worker)');
89153
+ this.onDataChannelOpen();
89154
+ };
89155
+ dataChannel.onclose = () => {
89156
+ logger$u.trace('dc.onClosed (worker)');
89157
+ this.doClose(false);
89158
+ };
89159
+ dataChannel.onerror = (err) => {
89160
+ logger$u.warn('Data channel error (worker)', { err });
89161
+ };
89162
+ dataChannel.onmessage = (msg) => {
89163
+ logger$u.trace('dc.onmessage (worker)');
89164
+ this.emit('data', new Uint8Array(msg.data));
89165
+ };
89166
+ dataChannel.onbufferedamountlow = () => {
89167
+ logger$u.trace('dc.onBufferedAmountLow (worker)');
89168
+ while (this.messageQueue.length > 0 &&
89169
+ this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
89170
+ const data = this.messageQueue.shift();
89171
+ this.dataChannel.send(data);
89172
+ }
89173
+ };
89174
+ }
89175
+ onDataChannelOpen() {
89176
+ this.connected = true;
89177
+ this.flushMessageQueue();
89178
+ this.emit('connected');
89179
+ }
89180
+ flushMessageQueue() {
89181
+ while (this.messageQueue.length > 0 &&
89182
+ this.dataChannel &&
89183
+ this.dataChannel.bufferedAmount < this.bufferThresholdHigh) {
89184
+ const data = this.messageQueue.shift();
89185
+ this.dataChannel.send(data);
89186
+ }
89187
+ }
89188
+ // ── Teardown ────────────────────────────────────────────────
89189
+ doClose(gracefulLeave, reason) {
89190
+ if (!this.closed) {
89191
+ this.closed = true;
89192
+ this.connected = false;
89193
+ this.messageQueue.length = 0;
89194
+ clearTimeout(this.earlyTimeout);
89195
+ this.stopListening();
89196
+ this.emit('disconnected', gracefulLeave, undefined, reason);
89197
+ this.removeAllListeners();
89198
+ if (this.dataChannel !== undefined) {
89199
+ try {
89200
+ this.dataChannel.close();
89201
+ }
89202
+ catch (err) {
89203
+ logger$u.warn('Failed to close data channel (worker)', { err });
89204
+ }
89205
+ }
89206
+ this.dataChannel = undefined;
89207
+ // Tell the main-thread bridge to tear down the RTCPeerConnection.
89208
+ // Fire-and-forget — we don't block on this.
89209
+ this.bridge
89210
+ ?.close(this.connectionId)
89211
+ .catch(() => {
89212
+ // intentionally swallowed
89213
+ });
89214
+ }
89215
+ }
89216
+ stopListening() {
89217
+ if (this.dataChannel !== undefined) {
89218
+ this.dataChannel.onopen = null;
89219
+ this.dataChannel.onclose = null;
89220
+ this.dataChannel.onerror = null;
89221
+ this.dataChannel.onbufferedamountlow = null;
89222
+ this.dataChannel.onmessage = null;
89223
+ }
89224
+ }
89225
+ }
89226
+
89227
+ /**
89228
+ * Conditional re-export of the browser WebrtcConnection.
89229
+ *
89230
+ * At module-load time we detect whether we are running inside a Web Worker.
89231
+ * - **Main thread** → use {@link DirectWebrtcConnection} which owns the
89232
+ * `RTCPeerConnection` and `RTCDataChannel` directly.
89233
+ * - **Worker thread** → use {@link WorkerWebrtcConnection} which delegates
89234
+ * `RTCPeerConnection` signaling to the main thread via a Comlink bridge
89235
+ * and receives a transferred `RTCDataChannel` that lives entirely in the
89236
+ * worker.
89237
+ *
89238
+ * Both classes implement `IWebrtcConnection & IConnection` and expose the
89239
+ * same public API, so upstream code (WebrtcConnector, etc.) is unaffected.
89240
+ */
89241
+ // The constructor — points to the right class based on the runtime
89242
+ // environment. The type assertion is safe because both implementations
89243
+ // share the same public interface surface.
89244
+ const WebrtcConnection = (isWorkerEnvironment
89245
+ ? WorkerWebrtcConnection
89246
+ : DirectWebrtcConnection);
89247
+
88598
89248
  const logger$t = new Logger('WebrtcConnectorRpcRemote');
88599
89249
  class WebrtcConnectorRpcRemote extends RpcRemote {
88600
89250
  requestConnection() {
@@ -93073,7 +93723,7 @@
93073
93723
  }
93074
93724
  }
93075
93725
 
93076
- var version$1 = "103.3.1";
93726
+ var version$1 = "103.6.0-rc.0";
93077
93727
 
93078
93728
  // @generated message type with reflection information, may provide speed optimized methods
93079
93729
  let Any$Type$1 = class Any$Type extends MessageType {
@@ -94720,6 +95370,18 @@
94720
95370
  */
94721
95371
  const PauseNeighborRequest = new PauseNeighborRequest$Type();
94722
95372
  // @generated message type with reflection information, may provide speed optimized methods
95373
+ class PauseNeighborResponse$Type extends MessageType {
95374
+ constructor() {
95375
+ super("PauseNeighborResponse", [
95376
+ { no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
95377
+ ]);
95378
+ }
95379
+ }
95380
+ /**
95381
+ * @generated MessageType for protobuf message PauseNeighborResponse
95382
+ */
95383
+ const PauseNeighborResponse = new PauseNeighborResponse$Type();
95384
+ // @generated message type with reflection information, may provide speed optimized methods
94723
95385
  class ResumeNeighborRequest$Type extends MessageType {
94724
95386
  constructor() {
94725
95387
  super("ResumeNeighborRequest", [
@@ -94775,7 +95437,7 @@
94775
95437
  * @generated ServiceType for protobuf service PlumtreeRpc
94776
95438
  */
94777
95439
  const PlumtreeRpc = new ServiceType("PlumtreeRpc", [
94778
- { name: "pauseNeighbor", options: {}, I: PauseNeighborRequest, O: Empty$1 },
95440
+ { name: "pauseNeighbor", options: {}, I: PauseNeighborRequest, O: PauseNeighborResponse },
94779
95441
  { name: "resumeNeighbor", options: {}, I: ResumeNeighborRequest, O: Empty$1 },
94780
95442
  { name: "sendMetadata", options: {}, I: MessageID$1, O: Empty$1 }
94781
95443
  ]);
@@ -96377,14 +97039,17 @@
96377
97039
  async pauseNeighbor(request, context) {
96378
97040
  const sender = toNodeId(context.incomingSourceDescriptor);
96379
97041
  if (this.neighbors.has(sender)) {
96380
- this.pausedNodes.add(sender, request.messageChainId);
97042
+ const accepted = this.pausedNodes.add(sender, request.messageChainId);
97043
+ return { accepted };
96381
97044
  }
96382
- return Empty$1;
97045
+ return { accepted: false };
96383
97046
  }
96384
97047
  async resumeNeighbor(request, context) {
96385
97048
  const sender = context.incomingSourceDescriptor;
96386
- this.pausedNodes.delete(toNodeId(sender), request.messageChainId);
96387
- await this.sendBuffer(request.fromTimestamp, request.messageChainId, sender);
97049
+ if (this.neighbors.has(toNodeId(sender))) {
97050
+ this.pausedNodes.delete(toNodeId(sender), request.messageChainId);
97051
+ await this.sendBuffer(request.fromTimestamp, request.messageChainId, sender);
97052
+ }
96388
97053
  return Empty$1;
96389
97054
  }
96390
97055
  }
@@ -96397,10 +97062,9 @@
96397
97062
  await this.getClient().sendMetadata(msg, options);
96398
97063
  }
96399
97064
  async pauseNeighbor(messageChainId) {
96400
- const options = this.formDhtRpcOptions({
96401
- notification: true
96402
- });
96403
- await this.getClient().pauseNeighbor({ messageChainId }, options);
97065
+ const options = this.formDhtRpcOptions();
97066
+ const response = await this.getClient().pauseNeighbor({ messageChainId }, options);
97067
+ return response.accepted;
96404
97068
  }
96405
97069
  async resumeNeighbor(fromTimestamp, messageChainId) {
96406
97070
  const options = this.formDhtRpcOptions({
@@ -96422,9 +97086,10 @@
96422
97086
  this.pausedNeighbors.set(msgChainId, new Set());
96423
97087
  }
96424
97088
  if (this.pausedNeighbors.get(msgChainId).size >= this.limit) {
96425
- return;
97089
+ return false;
96426
97090
  }
96427
97091
  this.pausedNeighbors.get(msgChainId).add(node);
97092
+ return true;
96428
97093
  }
96429
97094
  delete(node, msgChainId) {
96430
97095
  this.pausedNeighbors.get(msgChainId)?.delete(node);
@@ -96457,19 +97122,24 @@
96457
97122
  }
96458
97123
 
96459
97124
  const MAX_PAUSED_NEIGHBORS_DEFAULT = 3;
97125
+ const DEFAULT_RECOVERY_TIMEOUT = 500;
97126
+ const DEFAULT_RECOVERY_CHECK_INTERVAL = 200;
97127
+ const DEFAULT_RECOVERY_COOLDOWN = 2500;
96460
97128
  const logger$4$1 = new Logger('PlumtreeManager');
96461
97129
  class PlumtreeManager extends EventEmitter {
96462
97130
  neighbors;
96463
97131
  localPeerDescriptor;
96464
- // We have paused sending real data to these neighbrs and only send metadata
96465
97132
  localPausedNeighbors;
96466
- // We have asked these nodes to pause sending real data to us, used to limit sending of pausing and resuming requests
96467
97133
  remotePausedNeighbors;
96468
97134
  rpcLocal;
96469
97135
  latestMessages = new Map();
96470
97136
  rpcCommunicator;
96471
- metadataTimestampsAheadOfRealData = new Map();
96472
97137
  maxPausedNeighbors;
97138
+ recoveryState = new Map();
97139
+ recoveryCooldownUntil = new Map();
97140
+ recoveryTimeout;
97141
+ recoveryCooldown;
97142
+ abortController = new AbortController();
96473
97143
  constructor(options) {
96474
97144
  super();
96475
97145
  this.neighbors = options.neighbors;
@@ -96477,12 +97147,22 @@
96477
97147
  this.localPeerDescriptor = options.localPeerDescriptor;
96478
97148
  this.localPausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
96479
97149
  this.remotePausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
97150
+ this.recoveryTimeout = options.recoveryTimeout ?? DEFAULT_RECOVERY_TIMEOUT;
97151
+ this.recoveryCooldown = options.recoveryCooldown ?? DEFAULT_RECOVERY_COOLDOWN;
96480
97152
  this.rpcLocal = new PlumtreeRpcLocal(this.neighbors, this.localPausedNeighbors, (metadata, previousNode) => this.onMetadata(metadata, previousNode), (fromTimestamp, msgChainId, remotePeerDescriptor) => this.sendBuffer(fromTimestamp, msgChainId, remotePeerDescriptor));
96481
- this.neighbors.on('nodeRemoved', (nodeId) => this.onNeighborRemoved(nodeId));
97153
+ this.neighbors.on('nodeRemoved', this.onNeighborRemoved);
96482
97154
  this.rpcCommunicator = options.rpcCommunicator;
96483
97155
  this.rpcCommunicator.registerRpcNotification(MessageID$1, 'sendMetadata', (msg, context) => this.rpcLocal.sendMetadata(msg, context));
96484
- this.rpcCommunicator.registerRpcNotification(PauseNeighborRequest, 'pauseNeighbor', (msg, context) => this.rpcLocal.pauseNeighbor(msg, context));
97156
+ this.rpcCommunicator.registerRpcMethod(PauseNeighborRequest, PauseNeighborResponse, 'pauseNeighbor', (msg, context) => this.rpcLocal.pauseNeighbor(msg, context));
96485
97157
  this.rpcCommunicator.registerRpcNotification(ResumeNeighborRequest, 'resumeNeighbor', (msg, context) => this.rpcLocal.resumeNeighbor(msg, context));
97158
+ setAbortableInterval(() => {
97159
+ const now = performance.now();
97160
+ for (const [chainId, state] of this.recoveryState) {
97161
+ if (now - state.metadataAheadSince >= this.recoveryTimeout && !state.resumeInProgress) {
97162
+ this.attemptRecovery(chainId, state, this.getLatestMessageTimestamp(chainId));
97163
+ }
97164
+ }
97165
+ }, options.recoveryCheckInterval ?? DEFAULT_RECOVERY_CHECK_INTERVAL, this.abortController.signal);
96486
97166
  }
96487
97167
  async pauseNeighbor(node, msgChainId) {
96488
97168
  if (this.neighbors.has(toNodeId(node))
@@ -96490,8 +97170,16 @@
96490
97170
  && this.remotePausedNeighbors.size(msgChainId) < this.maxPausedNeighbors) {
96491
97171
  logger$4$1.debug(`Pausing neighbor ${toNodeId(node)}`);
96492
97172
  this.remotePausedNeighbors.add(toNodeId(node), msgChainId);
96493
- const remote = this.createRemote(node);
96494
- await remote.pauseNeighbor(msgChainId);
97173
+ try {
97174
+ const remote = this.createRemote(node);
97175
+ const accepted = await remote.pauseNeighbor(msgChainId);
97176
+ if (!accepted) {
97177
+ this.remotePausedNeighbors.delete(toNodeId(node), msgChainId);
97178
+ }
97179
+ }
97180
+ catch (_e) {
97181
+ this.remotePausedNeighbors.delete(toNodeId(node), msgChainId);
97182
+ }
96495
97183
  }
96496
97184
  }
96497
97185
  async resumeNeighbor(node, msgChainId, fromTimestamp) {
@@ -96502,9 +97190,15 @@
96502
97190
  await remote.resumeNeighbor(fromTimestamp, msgChainId);
96503
97191
  }
96504
97192
  }
96505
- onNeighborRemoved(nodeId) {
97193
+ onNeighborRemoved = (nodeId) => {
96506
97194
  this.localPausedNeighbors.deleteAll(nodeId);
96507
97195
  this.remotePausedNeighbors.deleteAll(nodeId);
97196
+ for (const [_chainId, state] of this.recoveryState) {
97197
+ state.candidates = state.candidates.filter((c) => toNodeId(c) !== nodeId);
97198
+ if (state.lastAttemptedNode !== null && toNodeId(state.lastAttemptedNode) === nodeId) {
97199
+ state.lastAttemptedNode = null;
97200
+ }
97201
+ }
96508
97202
  if (this.neighbors.size() > 0) {
96509
97203
  this.remotePausedNeighbors.forEach((pausedNeighbors, msgChainId) => {
96510
97204
  if (pausedNeighbors.size >= this.neighbors.size()) {
@@ -96514,7 +97208,7 @@
96514
97208
  }
96515
97209
  });
96516
97210
  }
96517
- }
97211
+ };
96518
97212
  getLatestMessageTimestamp(msgChainId) {
96519
97213
  if (!this.latestMessages.has(msgChainId) || this.latestMessages.get(msgChainId).length === 0) {
96520
97214
  return 0;
@@ -96524,22 +97218,61 @@
96524
97218
  async sendBuffer(fromTimestamp, msgChainId, neighbor) {
96525
97219
  const remote = new ContentDeliveryRpcRemote(this.localPeerDescriptor, neighbor, this.rpcCommunicator, ContentDeliveryRpcClient);
96526
97220
  const messages = this.latestMessages.get(msgChainId)?.filter((msg) => msg.messageId.timestamp > fromTimestamp) ?? [];
96527
- await Promise.all(messages.map((msg) => remote.sendStreamMessage(msg)));
97221
+ for (const msg of messages) {
97222
+ await remote.sendStreamMessage(msg);
97223
+ }
96528
97224
  }
96529
97225
  async onMetadata(msg, previousNode) {
96530
- // If we receive newer metadata than messages in the buffer, resume the sending neighbor
96531
- const latestMessageTimestamp = this.getLatestMessageTimestamp(msg.messageChainId);
96532
- if (latestMessageTimestamp < msg.timestamp) {
96533
- if (!this.metadataTimestampsAheadOfRealData.has(msg.messageChainId)) {
96534
- this.metadataTimestampsAheadOfRealData.set(msg.messageChainId, new Set());
96535
- }
96536
- this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).add(msg.timestamp);
96537
- if (this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).size > 1) {
96538
- await this.resumeNeighbor(previousNode, msg.messageChainId, this.getLatestMessageTimestamp(msg.messageChainId));
96539
- this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).forEach((timestamp) => {
96540
- this.metadataTimestampsAheadOfRealData.get(msg.messageChainId).delete(timestamp);
96541
- });
96542
- }
97226
+ const latestTs = this.getLatestMessageTimestamp(msg.messageChainId);
97227
+ if (latestTs >= msg.timestamp) {
97228
+ return;
97229
+ }
97230
+ const chainId = msg.messageChainId;
97231
+ const cooldownUntil = this.recoveryCooldownUntil.get(chainId);
97232
+ if (cooldownUntil !== undefined && performance.now() < cooldownUntil) {
97233
+ return;
97234
+ }
97235
+ let state = this.recoveryState.get(chainId);
97236
+ if (!state) {
97237
+ state = {
97238
+ timestampsAhead: new Set(),
97239
+ metadataAheadSince: performance.now(),
97240
+ candidates: [],
97241
+ lastAttemptedNode: null,
97242
+ resumeInProgress: false
97243
+ };
97244
+ this.recoveryState.set(chainId, state);
97245
+ }
97246
+ state.timestampsAhead.add(msg.timestamp);
97247
+ const nodeId = toNodeId(previousNode);
97248
+ const isLastAttempted = state.lastAttemptedNode !== null && toNodeId(state.lastAttemptedNode) === nodeId;
97249
+ if (!isLastAttempted && !state.candidates.some((c) => toNodeId(c) === nodeId)) {
97250
+ state.candidates.push(previousNode);
97251
+ }
97252
+ if (state.timestampsAhead.size > 1 && !state.resumeInProgress) {
97253
+ await this.attemptRecovery(chainId, state, latestTs);
97254
+ }
97255
+ }
97256
+ async attemptRecovery(chainId, state, latestTs) {
97257
+ const candidate = state.candidates.shift();
97258
+ if (!candidate) {
97259
+ state.metadataAheadSince = performance.now();
97260
+ return;
97261
+ }
97262
+ state.resumeInProgress = true;
97263
+ state.lastAttemptedNode = candidate;
97264
+ state.candidates = [];
97265
+ state.timestampsAhead.clear();
97266
+ state.metadataAheadSince = performance.now();
97267
+ try {
97268
+ const remote = this.createRemote(candidate);
97269
+ await remote.resumeNeighbor(latestTs, chainId);
97270
+ }
97271
+ catch (_e) {
97272
+ logger$4$1.debug('Recovery resume failed, will retry with next candidate');
97273
+ }
97274
+ finally {
97275
+ state.resumeInProgress = false;
96543
97276
  }
96544
97277
  }
96545
97278
  createRemote(neighbor) {
@@ -96557,8 +97290,13 @@
96557
97290
  this.latestMessages.get(messageChainId).shift();
96558
97291
  this.latestMessages.get(messageChainId).push(msg);
96559
97292
  }
96560
- if (this.metadataTimestampsAheadOfRealData.has(msg.messageId.messageChainId)) {
96561
- this.metadataTimestampsAheadOfRealData.get(msg.messageId.messageChainId).delete(msg.messageId.timestamp);
97293
+ const state = this.recoveryState.get(messageChainId);
97294
+ if (state) {
97295
+ if (state.lastAttemptedNode) {
97296
+ this.remotePausedNeighbors.delete(toNodeId(state.lastAttemptedNode), messageChainId);
97297
+ }
97298
+ this.recoveryState.delete(messageChainId);
97299
+ this.recoveryCooldownUntil.set(messageChainId, performance.now() + this.recoveryCooldown);
96562
97300
  }
96563
97301
  this.emit('message', msg);
96564
97302
  const neighbors = this.neighbors.getAll().filter((neighbor) => toNodeId(neighbor.getPeerDescriptor()) !== previousNode);
@@ -96576,7 +97314,14 @@
96576
97314
  return this.localPausedNeighbors.isPaused(toNodeId(node), msgChainId)
96577
97315
  || this.remotePausedNeighbors.isPaused(toNodeId(node), msgChainId);
96578
97316
  }
97317
+ getLocalPausedNeighbors() {
97318
+ return this.localPausedNeighbors;
97319
+ }
97320
+ getRemotePausedNeighbors() {
97321
+ return this.remotePausedNeighbors;
97322
+ }
96579
97323
  stop() {
97324
+ this.abortController.abort();
96580
97325
  this.neighbors.off('nodeRemoved', this.onNeighborRemoved);
96581
97326
  }
96582
97327
  }