@waku/core 0.0.28 → 0.0.29-3ec2344.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.
Files changed (35) hide show
  1. package/bundle/{base_protocol-D0Zdzb-v.js → base_protocol-3fdjkRTX.js} +60 -18
  2. package/bundle/{browser-DoQRY-an.js → browser-H8Jgqifo.js} +5 -0
  3. package/bundle/{index-BJwgMx4y.js → index-BQ8SG1DC.js} +11 -20
  4. package/bundle/index.js +106 -362
  5. package/bundle/lib/base_protocol.js +3 -3
  6. package/bundle/lib/message/version_0.js +3 -3
  7. package/bundle/lib/predefined_bootstrap_nodes.js +1 -1
  8. package/bundle/{version_0-C6o0DvNW.js → version_0-D_Nwtppu.js} +5 -1
  9. package/dist/.tsbuildinfo +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/lib/filter/index.d.ts +13 -2
  13. package/dist/lib/filter/index.js +74 -259
  14. package/dist/lib/filter/index.js.map +1 -1
  15. package/dist/lib/keep_alive_manager.js +1 -1
  16. package/dist/lib/light_push/index.js +3 -3
  17. package/dist/lib/light_push/index.js.map +1 -1
  18. package/dist/lib/metadata/index.js +11 -1
  19. package/dist/lib/metadata/index.js.map +1 -1
  20. package/dist/lib/store/index.js +8 -1
  21. package/dist/lib/store/index.js.map +1 -1
  22. package/dist/lib/stream_manager.d.ts +4 -2
  23. package/dist/lib/stream_manager.js +58 -16
  24. package/dist/lib/stream_manager.js.map +1 -1
  25. package/dist/lib/wait_for_remote_peer.js +1 -1
  26. package/dist/lib/wait_for_remote_peer.js.map +1 -1
  27. package/package.json +1 -136
  28. package/src/index.ts +1 -1
  29. package/src/lib/filter/index.ts +138 -455
  30. package/src/lib/keep_alive_manager.ts +1 -1
  31. package/src/lib/light_push/index.ts +4 -7
  32. package/src/lib/metadata/index.ts +10 -1
  33. package/src/lib/store/index.ts +7 -1
  34. package/src/lib/stream_manager.ts +73 -23
  35. package/src/lib/wait_for_remote_peer.ts +1 -1
@@ -1,5 +1,5 @@
1
- import { b as bytesToUtf8, L as Logger, j as ensureShardingConfigured } from './index-BJwgMx4y.js';
2
- import { T as Tags } from './browser-DoQRY-an.js';
1
+ import { c as bytesToUtf8, L as Logger, e as ensureShardingConfigured } from './index-BQ8SG1DC.js';
2
+ import { T as Tags } from './browser-H8Jgqifo.js';
3
3
 
4
4
  const decodeRelayShard = (bytes) => {
5
5
  // explicitly converting to Uint8Array to avoid Buffer
@@ -175,6 +175,9 @@ function filterPeersByDiscovery(peers, numPeers, maxBootstrapPeers) {
175
175
  return selectedPeers;
176
176
  }
177
177
 
178
+ const CONNECTION_TIMEOUT = 5_000;
179
+ const RETRY_BACKOFF_BASE = 1_000;
180
+ const MAX_RETRIES = 3;
178
181
  class StreamManager {
179
182
  multicodec;
180
183
  getConnections;
@@ -186,47 +189,86 @@ class StreamManager {
186
189
  this.getConnections = getConnections;
187
190
  this.addEventListener = addEventListener;
188
191
  this.log = new Logger(`stream-manager:${multicodec}`);
189
- this.addEventListener("peer:update", this.handlePeerUpdateStreamPool.bind(this));
190
- this.getStream = this.getStream.bind(this);
191
192
  this.streamPool = new Map();
193
+ this.addEventListener("peer:update", this.handlePeerUpdateStreamPool);
194
+ this.getStream = this.getStream.bind(this);
192
195
  }
193
196
  async getStream(peer) {
194
197
  const peerIdStr = peer.id.toString();
195
198
  const streamPromise = this.streamPool.get(peerIdStr);
196
199
  if (!streamPromise) {
197
- return this.newStream(peer); // fallback by creating a new stream on the spot
200
+ return this.createStream(peer);
198
201
  }
199
- // We have the stream, let's remove it from the map
200
202
  this.streamPool.delete(peerIdStr);
201
203
  this.prepareNewStream(peer);
202
- const stream = await streamPromise;
203
- if (!stream || stream.status === "closed") {
204
- return this.newStream(peer); // fallback by creating a new stream on the spot
204
+ try {
205
+ const stream = await streamPromise;
206
+ if (stream && stream.status !== "closed") {
207
+ return stream;
208
+ }
209
+ }
210
+ catch (error) {
211
+ this.log.error(`Failed to get stream for ${peerIdStr} -- `, error);
212
+ }
213
+ return this.createStream(peer);
214
+ }
215
+ async createStream(peer) {
216
+ try {
217
+ return await this.newStream(peer);
218
+ }
219
+ catch (error) {
220
+ throw new Error(`Failed to create a new stream for ${peer.id.toString()} -- ` + error);
205
221
  }
206
- return stream;
207
222
  }
208
- async newStream(peer) {
223
+ async newStream(peer, retries = 0) {
209
224
  const connections = this.getConnections(peer.id);
210
225
  const connection = selectConnection(connections);
211
226
  if (!connection) {
212
227
  throw new Error("Failed to get a connection to the peer");
213
228
  }
214
- return connection.newStream(this.multicodec);
229
+ try {
230
+ return await connection.newStream(this.multicodec);
231
+ }
232
+ catch (error) {
233
+ if (retries < MAX_RETRIES) {
234
+ const backoff = RETRY_BACKOFF_BASE * Math.pow(2, retries);
235
+ await new Promise((resolve) => setTimeout(resolve, backoff));
236
+ return this.newStream(peer, retries + 1);
237
+ }
238
+ throw error;
239
+ }
215
240
  }
216
241
  prepareNewStream(peer) {
217
- const streamPromise = this.newStream(peer).catch(() => {
218
- // No error thrown as this call is not triggered by the user
219
- this.log.error(`Failed to prepare a new stream for ${peer.id.toString()}`);
242
+ const timeoutPromise = new Promise((resolve) => setTimeout(resolve, CONNECTION_TIMEOUT));
243
+ const streamPromise = Promise.race([
244
+ this.newStream(peer),
245
+ timeoutPromise.then(() => {
246
+ throw new Error("Connection timeout");
247
+ })
248
+ ]).catch((error) => {
249
+ this.log.error(`Failed to prepare a new stream for ${peer.id.toString()} -- `, error);
220
250
  });
221
251
  this.streamPool.set(peer.id.toString(), streamPromise);
222
252
  }
223
253
  handlePeerUpdateStreamPool = (evt) => {
224
- const peer = evt.detail.peer;
254
+ const { peer } = evt.detail;
225
255
  if (peer.protocols.includes(this.multicodec)) {
226
- this.log.info(`Preemptively opening a stream to ${peer.id.toString()}`);
227
- this.prepareNewStream(peer);
256
+ const isConnected = this.isConnectedTo(peer.id);
257
+ if (isConnected) {
258
+ this.log.info(`Preemptively opening a stream to ${peer.id.toString()}`);
259
+ this.prepareNewStream(peer);
260
+ }
261
+ else {
262
+ const peerIdStr = peer.id.toString();
263
+ this.streamPool.delete(peerIdStr);
264
+ this.log.info(`Removed pending stream for disconnected peer ${peerIdStr}`);
265
+ }
228
266
  }
229
267
  };
268
+ isConnectedTo(peerId) {
269
+ const connections = this.getConnections(peerId);
270
+ return connections.some((connection) => connection.status === "open");
271
+ }
230
272
  }
231
273
 
232
274
  /**
@@ -663,6 +663,11 @@ var ProtocolError;
663
663
  * on the connection manager before retrying.
664
664
  */
665
665
  ProtocolError["NO_PEER_AVAILABLE"] = "No peer available";
666
+ /**
667
+ * Failure to find a stream to the peer. This may be because the connection with the peer is not still alive.
668
+ * Mitigation can be: retrying after a given time period, or mitigation for `NO_PEER_AVAILABLE` can be used.
669
+ */
670
+ ProtocolError["NO_STREAM_AVAILABLE"] = "No stream available";
666
671
  /**
667
672
  * The remote peer did not behave as expected. Mitigation for `NO_PEER_AVAILABLE`
668
673
  * or `DECODE_FAILED` can be used.
@@ -1,4 +1,4 @@
1
- import { i as identityBase, c as base2, d as base8, e as base10, f as base16, h as base32, j as base36, k as base58, l as base64, m as base256emoji, n as debug } from './browser-DoQRY-an.js';
1
+ import { i as identityBase, c as base2, d as base8, e as base10, f as base16, h as base32, j as base36, k as base58, l as base64, m as base256emoji, n as debug } from './browser-H8Jgqifo.js';
2
2
 
3
3
  /**
4
4
  * Returns a `Uint8Array` of the requested size. Referenced memory will
@@ -379,7 +379,6 @@ const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
379
379
  /**
380
380
  * DefaultPubsubTopic is the default gossipsub topic to use for Waku.
381
381
  */
382
- const DefaultPubsubTopic = "/waku/2/default-waku/proto";
383
382
  /**
384
383
  * The default cluster ID for The Waku Network
385
384
  */
@@ -424,9 +423,9 @@ function concat(byteArrays, totalLength) {
424
423
  }
425
424
 
426
425
  const singleShardInfoToPubsubTopic = (shardInfo) => {
427
- if (shardInfo.clusterId === undefined || shardInfo.shard === undefined)
426
+ if (shardInfo.shard === undefined)
428
427
  throw new Error("Invalid shard");
429
- return `/waku/2/rs/${shardInfo.clusterId}/${shardInfo.shard}`;
428
+ return `/waku/2/rs/${shardInfo.clusterId ?? DEFAULT_CLUSTER_ID}/${shardInfo.shard}`;
430
429
  };
431
430
  const shardInfoToPubsubTopics = (shardInfo) => {
432
431
  if ("contentTopics" in shardInfo && shardInfo.contentTopics) {
@@ -465,13 +464,6 @@ const pubsubTopicToSingleShardInfo = (pubsubTopics) => {
465
464
  shard
466
465
  };
467
466
  };
468
- //TODO: move part of BaseProtocol instead of utils
469
- // return `ProtocolError.TOPIC_NOT_CONFIGURED` instead of throwing
470
- function ensurePubsubTopicIsConfigured(pubsubTopic, configuredTopics) {
471
- if (!configuredTopics.includes(pubsubTopic)) {
472
- throw new Error(`Pubsub topic ${pubsubTopic} has not been configured on this instance. Configured topics are: ${configuredTopics}. Please update your configuration by passing in the topic during Waku node instantiation.`);
473
- }
474
- }
475
467
  /**
476
468
  * Given a string, will throw an error if it is not formatted as a valid content topic for autosharding based on https://rfc.vac.dev/spec/51/
477
469
  * @param contentTopic String to validate
@@ -530,23 +522,22 @@ function contentTopicToShardIndex(contentTopic, networkShards = 8) {
530
522
  return Number(dataview.getBigUint64(0, false) % BigInt(networkShards));
531
523
  }
532
524
  function contentTopicToPubsubTopic(contentTopic, clusterId = DEFAULT_CLUSTER_ID, networkShards = 8) {
525
+ if (!contentTopic) {
526
+ throw Error("Content topic must be specified");
527
+ }
533
528
  const shardIndex = contentTopicToShardIndex(contentTopic, networkShards);
534
529
  return `/waku/2/rs/${clusterId}/${shardIndex}`;
535
530
  }
536
531
  /**
537
532
  * Used when creating encoders/decoders to determine which pubsub topic to use
538
533
  */
539
- function determinePubsubTopic(contentTopic, pubsubTopicShardInfo = DefaultPubsubTopic) {
534
+ function determinePubsubTopic(contentTopic, pubsubTopicShardInfo) {
540
535
  if (typeof pubsubTopicShardInfo == "string") {
541
536
  return pubsubTopicShardInfo;
542
537
  }
543
- else {
544
- return pubsubTopicShardInfo
545
- ? pubsubTopicShardInfo.shard
546
- ? singleShardInfoToPubsubTopic(pubsubTopicShardInfo)
547
- : contentTopicToPubsubTopic(contentTopic, pubsubTopicShardInfo.clusterId)
548
- : DefaultPubsubTopic;
549
- }
538
+ return pubsubTopicShardInfo?.shard !== undefined
539
+ ? singleShardInfoToPubsubTopic(pubsubTopicShardInfo)
540
+ : contentTopicToPubsubTopic(contentTopic, pubsubTopicShardInfo?.clusterId ?? DEFAULT_CLUSTER_ID);
550
541
  }
551
542
  /**
552
543
  * Validates sharding configuration and sets defaults where possible.
@@ -620,4 +611,4 @@ class Logger {
620
611
  }
621
612
  }
622
613
 
623
- export { DefaultPubsubTopic as D, Logger as L, allocUnsafe as a, bytesToUtf8 as b, concat as c, alloc as d, singleShardInfoToPubsubTopic as e, ensurePubsubTopicIsConfigured as f, shardInfoToPubsubTopics as g, fromString as h, determinePubsubTopic as i, ensureShardingConfigured as j, pubsubTopicToSingleShardInfo as p, sha256 as s, utf8ToBytes as u };
614
+ export { Logger as L, allocUnsafe as a, alloc as b, bytesToUtf8 as c, determinePubsubTopic as d, ensureShardingConfigured as e, fromString as f, pubsubTopicToSingleShardInfo as p, shardInfoToPubsubTopics as s, utf8ToBytes as u };