@waku/sds 0.0.4-006cd41.0 → 0.0.4-01af155.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.
package/bundle/index.js CHANGED
@@ -5614,11 +5614,17 @@ class TypedEventEmitter extends EventTarget {
5614
5614
  }
5615
5615
 
5616
5616
  /**
5617
- * Internal assertion helpers.
5617
+ * Utilities for hex, bytes, CSPRNG.
5618
5618
  * @module
5619
5619
  */
5620
- /** Asserts something is positive integer. */
5621
- /** Is number an Uint8Array? Copied from utils for perf. */
5620
+ /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5621
+ // We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
5622
+ // node.js versions earlier than v19 don't declare it in global scope.
5623
+ // For node.js, package.json#exports field mapping rewrites import
5624
+ // from `crypto` to `cryptoNode`, which imports native module.
5625
+ // Makes the utils un-importable in browsers without a bundler.
5626
+ // Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
5627
+ /** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
5622
5628
  function isBytes(a) {
5623
5629
  return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
5624
5630
  }
@@ -5644,19 +5650,13 @@ function aoutput(out, instance) {
5644
5650
  throw new Error('digestInto() expects output buffer of length at least ' + min);
5645
5651
  }
5646
5652
  }
5647
-
5648
- /**
5649
- * Utilities for hex, bytes, CSPRNG.
5650
- * @module
5651
- */
5652
- /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5653
- // We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
5654
- // node.js versions earlier than v19 don't declare it in global scope.
5655
- // For node.js, package.json#exports field mapping rewrites import
5656
- // from `crypto` to `cryptoNode`, which imports native module.
5657
- // Makes the utils un-importable in browsers without a bundler.
5658
- // Once node.js 18 is deprecated (2025-04-30), we can just drop the import.
5659
- // Cast array to view
5653
+ /** Zeroize a byte array. Warning: JS provides no guarantees. */
5654
+ function clean(...arrays) {
5655
+ for (let i = 0; i < arrays.length; i++) {
5656
+ arrays[i].fill(0);
5657
+ }
5658
+ }
5659
+ /** Create DataView of an array for easy byte-level manipulation. */
5660
5660
  function createView(arr) {
5661
5661
  return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
5662
5662
  }
@@ -5664,14 +5664,21 @@ function createView(arr) {
5664
5664
  function rotr(word, shift) {
5665
5665
  return (word << (32 - shift)) | (word >>> shift);
5666
5666
  }
5667
+ // Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex
5668
+ const hasHexBuiltin = /* @__PURE__ */ (() =>
5669
+ // @ts-ignore
5670
+ typeof Uint8Array.from([]).toHex === 'function' && typeof Uint8Array.fromHex === 'function')();
5667
5671
  // Array where index 0xf0 (240) is mapped to string 'f0'
5668
5672
  const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
5669
5673
  /**
5670
- * Convert byte array to hex string.
5674
+ * Convert byte array to hex string. Uses built-in function, when available.
5671
5675
  * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
5672
5676
  */
5673
5677
  function bytesToHex(bytes) {
5674
5678
  abytes(bytes);
5679
+ // @ts-ignore
5680
+ if (hasHexBuiltin)
5681
+ return bytes.toHex();
5675
5682
  // pre-caching improves the speed 6x
5676
5683
  let hex = '';
5677
5684
  for (let i = 0; i < bytes.length; i++) {
@@ -5680,12 +5687,12 @@ function bytesToHex(bytes) {
5680
5687
  return hex;
5681
5688
  }
5682
5689
  /**
5683
- * Convert JS string to byte array.
5684
- * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
5690
+ * Converts string to bytes using UTF8 encoding.
5691
+ * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])
5685
5692
  */
5686
5693
  function utf8ToBytes(str) {
5687
5694
  if (typeof str !== 'string')
5688
- throw new Error('utf8ToBytes expected string, got ' + typeof str);
5695
+ throw new Error('string expected');
5689
5696
  return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
5690
5697
  }
5691
5698
  /**
@@ -5701,13 +5708,9 @@ function toBytes(data) {
5701
5708
  }
5702
5709
  /** For runtime check if class implements interface */
5703
5710
  class Hash {
5704
- // Safe version that clones internal state
5705
- clone() {
5706
- return this._cloneInto();
5707
- }
5708
5711
  }
5709
5712
  /** Wraps hash function, creating an interface on top of it */
5710
- function wrapConstructor(hashCons) {
5713
+ function createHasher(hashCons) {
5711
5714
  const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
5712
5715
  const tmp = hashCons();
5713
5716
  hashC.outputLen = tmp.outputLen;
@@ -5748,21 +5751,22 @@ function Maj(a, b, c) {
5748
5751
  class HashMD extends Hash {
5749
5752
  constructor(blockLen, outputLen, padOffset, isLE) {
5750
5753
  super();
5751
- this.blockLen = blockLen;
5752
- this.outputLen = outputLen;
5753
- this.padOffset = padOffset;
5754
- this.isLE = isLE;
5755
5754
  this.finished = false;
5756
5755
  this.length = 0;
5757
5756
  this.pos = 0;
5758
5757
  this.destroyed = false;
5758
+ this.blockLen = blockLen;
5759
+ this.outputLen = outputLen;
5760
+ this.padOffset = padOffset;
5761
+ this.isLE = isLE;
5759
5762
  this.buffer = new Uint8Array(blockLen);
5760
5763
  this.view = createView(this.buffer);
5761
5764
  }
5762
5765
  update(data) {
5763
5766
  aexists(this);
5764
- const { view, buffer, blockLen } = this;
5765
5767
  data = toBytes(data);
5768
+ abytes(data);
5769
+ const { view, buffer, blockLen } = this;
5766
5770
  const len = data.length;
5767
5771
  for (let pos = 0; pos < len;) {
5768
5772
  const take = Math.min(blockLen - this.pos, len - pos);
@@ -5796,7 +5800,7 @@ class HashMD extends Hash {
5796
5800
  let { pos } = this;
5797
5801
  // append the bit '1' to the message
5798
5802
  buffer[pos++] = 0b10000000;
5799
- this.buffer.subarray(pos).fill(0);
5803
+ clean(this.buffer.subarray(pos));
5800
5804
  // we have less than padOffset left in buffer, so we cannot put length in
5801
5805
  // current block, need process it and pad again
5802
5806
  if (this.padOffset > blockLen - pos) {
@@ -5834,28 +5838,40 @@ class HashMD extends Hash {
5834
5838
  to || (to = new this.constructor());
5835
5839
  to.set(...this.get());
5836
5840
  const { blockLen, buffer, length, finished, destroyed, pos } = this;
5841
+ to.destroyed = destroyed;
5842
+ to.finished = finished;
5837
5843
  to.length = length;
5838
5844
  to.pos = pos;
5839
- to.finished = finished;
5840
- to.destroyed = destroyed;
5841
5845
  if (length % blockLen)
5842
5846
  to.buffer.set(buffer);
5843
5847
  return to;
5844
5848
  }
5849
+ clone() {
5850
+ return this._cloneInto();
5851
+ }
5845
5852
  }
5853
+ /**
5854
+ * Initial SHA-2 state: fractional parts of square roots of first 16 primes 2..53.
5855
+ * Check out `test/misc/sha2-gen-iv.js` for recomputation guide.
5856
+ */
5857
+ /** Initial SHA256 state. Bits 0..32 of frac part of sqrt of primes 2..19 */
5858
+ const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
5859
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
5860
+ ]);
5846
5861
 
5847
5862
  /**
5848
- * SHA2-256 a.k.a. sha256. In JS, it is the fastest hash, even faster than Blake3.
5849
- *
5850
- * To break sha256 using birthday attack, attackers need to try 2^128 hashes.
5851
- * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
5852
- *
5853
- * Check out [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
5863
+ * SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
5864
+ * SHA256 is the fastest hash implementable in JS, even faster than Blake3.
5865
+ * Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and
5866
+ * [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
5854
5867
  * @module
5855
5868
  */
5856
- /** Round constants: first 32 bits of fractional parts of the cube roots of the first 64 primes 2..311). */
5869
+ /**
5870
+ * Round constants:
5871
+ * First 32 bits of fractional parts of the cube roots of the first 64 primes 2..311)
5872
+ */
5857
5873
  // prettier-ignore
5858
- const SHA256_K = /* @__PURE__ */ new Uint32Array([
5874
+ const SHA256_K = /* @__PURE__ */ Uint32Array.from([
5859
5875
  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
5860
5876
  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
5861
5877
  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
@@ -5865,19 +5881,11 @@ const SHA256_K = /* @__PURE__ */ new Uint32Array([
5865
5881
  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
5866
5882
  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
5867
5883
  ]);
5868
- /** Initial state: first 32 bits of fractional parts of the square roots of the first 8 primes 2..19. */
5869
- // prettier-ignore
5870
- const SHA256_IV = /* @__PURE__ */ new Uint32Array([
5871
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
5872
- ]);
5873
- /**
5874
- * Temporary buffer, not used to store anything between runs.
5875
- * Named this way because it matches specification.
5876
- */
5884
+ /** Reusable temporary buffer. "W" comes straight from spec. */
5877
5885
  const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
5878
5886
  class SHA256 extends HashMD {
5879
- constructor() {
5880
- super(64, 32, 8, false);
5887
+ constructor(outputLen = 32) {
5888
+ super(64, outputLen, 8, false);
5881
5889
  // We cannot use array here since array allows indexing by variable
5882
5890
  // which means optimizer/compiler cannot use registers.
5883
5891
  this.A = SHA256_IV[0] | 0;
@@ -5943,15 +5951,929 @@ class SHA256 extends HashMD {
5943
5951
  this.set(A, B, C, D, E, F, G, H);
5944
5952
  }
5945
5953
  roundClean() {
5946
- SHA256_W.fill(0);
5954
+ clean(SHA256_W);
5947
5955
  }
5948
5956
  destroy() {
5949
5957
  this.set(0, 0, 0, 0, 0, 0, 0, 0);
5950
- this.buffer.fill(0);
5958
+ clean(this.buffer);
5959
+ }
5960
+ }
5961
+ /**
5962
+ * SHA2-256 hash function from RFC 4634.
5963
+ *
5964
+ * It is the fastest JS hash, even faster than Blake3.
5965
+ * To break sha256 using birthday attack, attackers need to try 2^128 hashes.
5966
+ * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
5967
+ */
5968
+ const sha256$1 = /* @__PURE__ */ createHasher(() => new SHA256());
5969
+
5970
+ /**
5971
+ * SHA2-256 a.k.a. sha256. In JS, it is the fastest hash, even faster than Blake3.
5972
+ *
5973
+ * To break sha256 using birthday attack, attackers need to try 2^128 hashes.
5974
+ * BTC network is doing 2^70 hashes/sec (2^95 hashes/year) as per 2025.
5975
+ *
5976
+ * Check out [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
5977
+ * @module
5978
+ * @deprecated
5979
+ */
5980
+ /** @deprecated Use import from `noble/hashes/sha2` module */
5981
+ const sha256 = sha256$1;
5982
+
5983
+ var Protocols;
5984
+ (function (Protocols) {
5985
+ Protocols["Relay"] = "relay";
5986
+ Protocols["Store"] = "store";
5987
+ Protocols["LightPush"] = "lightpush";
5988
+ Protocols["Filter"] = "filter";
5989
+ })(Protocols || (Protocols = {}));
5990
+ var ProtocolError;
5991
+ (function (ProtocolError) {
5992
+ //
5993
+ // GENERAL ERRORS SECTION
5994
+ //
5995
+ /**
5996
+ * Could not determine the origin of the fault. Best to check connectivity and try again
5997
+ * */
5998
+ ProtocolError["GENERIC_FAIL"] = "Generic error";
5999
+ /**
6000
+ * The remote peer rejected the message. Information provided by the remote peer
6001
+ * is logged. Review message validity, or mitigation for `NO_PEER_AVAILABLE`
6002
+ * or `DECODE_FAILED` can be used.
6003
+ */
6004
+ ProtocolError["REMOTE_PEER_REJECTED"] = "Remote peer rejected";
6005
+ /**
6006
+ * Failure to protobuf decode the message. May be due to a remote peer issue,
6007
+ * ensuring that messages are sent via several peer enable mitigation of this error.
6008
+ */
6009
+ ProtocolError["DECODE_FAILED"] = "Failed to decode";
6010
+ /**
6011
+ * Failure to find a peer with suitable protocols. This may due to a connection issue.
6012
+ * Mitigation can be: retrying after a given time period, display connectivity issue
6013
+ * to user or listening for `peer:connected:bootstrap` or `peer:connected:peer-exchange`
6014
+ * on the connection manager before retrying.
6015
+ */
6016
+ ProtocolError["NO_PEER_AVAILABLE"] = "No peer available";
6017
+ /**
6018
+ * Failure to find a stream to the peer. This may be because the connection with the peer is not still alive.
6019
+ * Mitigation can be: retrying after a given time period, or mitigation for `NO_PEER_AVAILABLE` can be used.
6020
+ */
6021
+ ProtocolError["NO_STREAM_AVAILABLE"] = "No stream available";
6022
+ /**
6023
+ * The remote peer did not behave as expected. Mitigation for `NO_PEER_AVAILABLE`
6024
+ * or `DECODE_FAILED` can be used.
6025
+ */
6026
+ ProtocolError["NO_RESPONSE"] = "No response received";
6027
+ //
6028
+ // SEND ERRORS SECTION
6029
+ //
6030
+ /**
6031
+ * Failure to protobuf encode the message. This is not recoverable and needs
6032
+ * further investigation.
6033
+ */
6034
+ ProtocolError["ENCODE_FAILED"] = "Failed to encode";
6035
+ /**
6036
+ * The message payload is empty, making the message invalid. Ensure that a non-empty
6037
+ * payload is set on the outgoing message.
6038
+ */
6039
+ ProtocolError["EMPTY_PAYLOAD"] = "Payload is empty";
6040
+ /**
6041
+ * The message size is above the maximum message size allowed on the Waku Network.
6042
+ * Compressing the message or using an alternative strategy for large messages is recommended.
6043
+ */
6044
+ ProtocolError["SIZE_TOO_BIG"] = "Size is too big";
6045
+ /**
6046
+ * The PubsubTopic passed to the send function is not configured on the Waku node.
6047
+ * Please ensure that the PubsubTopic is used when initializing the Waku node.
6048
+ */
6049
+ ProtocolError["TOPIC_NOT_CONFIGURED"] = "Topic not configured";
6050
+ /**
6051
+ * Fails when
6052
+ */
6053
+ ProtocolError["STREAM_ABORTED"] = "Stream aborted";
6054
+ /**
6055
+ * General proof generation error message.
6056
+ * nwaku: https://github.com/waku-org/nwaku/blob/c3cb06ac6c03f0f382d3941ea53b330f6a8dd127/waku/waku_rln_relay/group_manager/group_manager_base.nim#L201C19-L201C42
6057
+ */
6058
+ ProtocolError["RLN_PROOF_GENERATION"] = "Proof generation failed";
6059
+ //
6060
+ // RECEIVE ERRORS SECTION
6061
+ //
6062
+ /**
6063
+ * The pubsub topic configured on the decoder does not match the pubsub topic setup on the protocol.
6064
+ * Ensure that the pubsub topic used for decoder creation is the same as the one used for protocol.
6065
+ */
6066
+ ProtocolError["TOPIC_DECODER_MISMATCH"] = "Topic decoder mismatch";
6067
+ /**
6068
+ * The topics passed in the decoders do not match each other, or don't exist at all.
6069
+ * Ensure that all the pubsub topics used in the decoders are valid and match each other.
6070
+ */
6071
+ ProtocolError["INVALID_DECODER_TOPICS"] = "Invalid decoder topics";
6072
+ })(ProtocolError || (ProtocolError = {}));
6073
+
6074
+ var Tags;
6075
+ (function (Tags) {
6076
+ Tags["BOOTSTRAP"] = "bootstrap";
6077
+ Tags["PEER_EXCHANGE"] = "peer-exchange";
6078
+ Tags["LOCAL"] = "local-peer-cache";
6079
+ })(Tags || (Tags = {}));
6080
+ var EPeersByDiscoveryEvents;
6081
+ (function (EPeersByDiscoveryEvents) {
6082
+ EPeersByDiscoveryEvents["PEER_DISCOVERY_BOOTSTRAP"] = "peer:discovery:bootstrap";
6083
+ EPeersByDiscoveryEvents["PEER_DISCOVERY_PEER_EXCHANGE"] = "peer:discovery:peer-exchange";
6084
+ EPeersByDiscoveryEvents["PEER_CONNECT_BOOTSTRAP"] = "peer:connected:bootstrap";
6085
+ EPeersByDiscoveryEvents["PEER_CONNECT_PEER_EXCHANGE"] = "peer:connected:peer-exchange";
6086
+ })(EPeersByDiscoveryEvents || (EPeersByDiscoveryEvents = {}));
6087
+ var EConnectionStateEvents;
6088
+ (function (EConnectionStateEvents) {
6089
+ EConnectionStateEvents["CONNECTION_STATUS"] = "waku:connection";
6090
+ })(EConnectionStateEvents || (EConnectionStateEvents = {}));
6091
+
6092
+ var HealthStatusChangeEvents;
6093
+ (function (HealthStatusChangeEvents) {
6094
+ HealthStatusChangeEvents["StatusChange"] = "health:change";
6095
+ })(HealthStatusChangeEvents || (HealthStatusChangeEvents = {}));
6096
+ var HealthStatus;
6097
+ (function (HealthStatus) {
6098
+ HealthStatus["Unhealthy"] = "Unhealthy";
6099
+ HealthStatus["MinimallyHealthy"] = "MinimallyHealthy";
6100
+ HealthStatus["SufficientlyHealthy"] = "SufficientlyHealthy";
6101
+ })(HealthStatus || (HealthStatus = {}));
6102
+
6103
+ function getDefaultExportFromCjs (x) {
6104
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
6105
+ }
6106
+
6107
+ var browser = {exports: {}};
6108
+
6109
+ /**
6110
+ * Helpers.
6111
+ */
6112
+
6113
+ var ms;
6114
+ var hasRequiredMs;
6115
+
6116
+ function requireMs () {
6117
+ if (hasRequiredMs) return ms;
6118
+ hasRequiredMs = 1;
6119
+ var s = 1000;
6120
+ var m = s * 60;
6121
+ var h = m * 60;
6122
+ var d = h * 24;
6123
+ var w = d * 7;
6124
+ var y = d * 365.25;
6125
+
6126
+ /**
6127
+ * Parse or format the given `val`.
6128
+ *
6129
+ * Options:
6130
+ *
6131
+ * - `long` verbose formatting [false]
6132
+ *
6133
+ * @param {String|Number} val
6134
+ * @param {Object} [options]
6135
+ * @throws {Error} throw an error if val is not a non-empty string or a number
6136
+ * @return {String|Number}
6137
+ * @api public
6138
+ */
6139
+
6140
+ ms = function (val, options) {
6141
+ options = options || {};
6142
+ var type = typeof val;
6143
+ if (type === 'string' && val.length > 0) {
6144
+ return parse(val);
6145
+ } else if (type === 'number' && isFinite(val)) {
6146
+ return options.long ? fmtLong(val) : fmtShort(val);
6147
+ }
6148
+ throw new Error(
6149
+ 'val is not a non-empty string or a valid number. val=' +
6150
+ JSON.stringify(val)
6151
+ );
6152
+ };
6153
+
6154
+ /**
6155
+ * Parse the given `str` and return milliseconds.
6156
+ *
6157
+ * @param {String} str
6158
+ * @return {Number}
6159
+ * @api private
6160
+ */
6161
+
6162
+ function parse(str) {
6163
+ str = String(str);
6164
+ if (str.length > 100) {
6165
+ return;
6166
+ }
6167
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
6168
+ str
6169
+ );
6170
+ if (!match) {
6171
+ return;
6172
+ }
6173
+ var n = parseFloat(match[1]);
6174
+ var type = (match[2] || 'ms').toLowerCase();
6175
+ switch (type) {
6176
+ case 'years':
6177
+ case 'year':
6178
+ case 'yrs':
6179
+ case 'yr':
6180
+ case 'y':
6181
+ return n * y;
6182
+ case 'weeks':
6183
+ case 'week':
6184
+ case 'w':
6185
+ return n * w;
6186
+ case 'days':
6187
+ case 'day':
6188
+ case 'd':
6189
+ return n * d;
6190
+ case 'hours':
6191
+ case 'hour':
6192
+ case 'hrs':
6193
+ case 'hr':
6194
+ case 'h':
6195
+ return n * h;
6196
+ case 'minutes':
6197
+ case 'minute':
6198
+ case 'mins':
6199
+ case 'min':
6200
+ case 'm':
6201
+ return n * m;
6202
+ case 'seconds':
6203
+ case 'second':
6204
+ case 'secs':
6205
+ case 'sec':
6206
+ case 's':
6207
+ return n * s;
6208
+ case 'milliseconds':
6209
+ case 'millisecond':
6210
+ case 'msecs':
6211
+ case 'msec':
6212
+ case 'ms':
6213
+ return n;
6214
+ default:
6215
+ return undefined;
6216
+ }
6217
+ }
6218
+
6219
+ /**
6220
+ * Short format for `ms`.
6221
+ *
6222
+ * @param {Number} ms
6223
+ * @return {String}
6224
+ * @api private
6225
+ */
6226
+
6227
+ function fmtShort(ms) {
6228
+ var msAbs = Math.abs(ms);
6229
+ if (msAbs >= d) {
6230
+ return Math.round(ms / d) + 'd';
6231
+ }
6232
+ if (msAbs >= h) {
6233
+ return Math.round(ms / h) + 'h';
6234
+ }
6235
+ if (msAbs >= m) {
6236
+ return Math.round(ms / m) + 'm';
6237
+ }
6238
+ if (msAbs >= s) {
6239
+ return Math.round(ms / s) + 's';
6240
+ }
6241
+ return ms + 'ms';
6242
+ }
6243
+
6244
+ /**
6245
+ * Long format for `ms`.
6246
+ *
6247
+ * @param {Number} ms
6248
+ * @return {String}
6249
+ * @api private
6250
+ */
6251
+
6252
+ function fmtLong(ms) {
6253
+ var msAbs = Math.abs(ms);
6254
+ if (msAbs >= d) {
6255
+ return plural(ms, msAbs, d, 'day');
6256
+ }
6257
+ if (msAbs >= h) {
6258
+ return plural(ms, msAbs, h, 'hour');
6259
+ }
6260
+ if (msAbs >= m) {
6261
+ return plural(ms, msAbs, m, 'minute');
6262
+ }
6263
+ if (msAbs >= s) {
6264
+ return plural(ms, msAbs, s, 'second');
6265
+ }
6266
+ return ms + ' ms';
6267
+ }
6268
+
6269
+ /**
6270
+ * Pluralization helper.
6271
+ */
6272
+
6273
+ function plural(ms, msAbs, n, name) {
6274
+ var isPlural = msAbs >= n * 1.5;
6275
+ return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
6276
+ }
6277
+ return ms;
6278
+ }
6279
+
6280
+ /**
6281
+ * This is the common logic for both the Node.js and web browser
6282
+ * implementations of `debug()`.
6283
+ */
6284
+
6285
+ function setup(env) {
6286
+ createDebug.debug = createDebug;
6287
+ createDebug.default = createDebug;
6288
+ createDebug.coerce = coerce;
6289
+ createDebug.disable = disable;
6290
+ createDebug.enable = enable;
6291
+ createDebug.enabled = enabled;
6292
+ createDebug.humanize = requireMs();
6293
+ createDebug.destroy = destroy;
6294
+
6295
+ Object.keys(env).forEach(key => {
6296
+ createDebug[key] = env[key];
6297
+ });
6298
+
6299
+ /**
6300
+ * The currently active debug mode names, and names to skip.
6301
+ */
6302
+
6303
+ createDebug.names = [];
6304
+ createDebug.skips = [];
6305
+
6306
+ /**
6307
+ * Map of special "%n" handling functions, for the debug "format" argument.
6308
+ *
6309
+ * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
6310
+ */
6311
+ createDebug.formatters = {};
6312
+
6313
+ /**
6314
+ * Selects a color for a debug namespace
6315
+ * @param {String} namespace The namespace string for the debug instance to be colored
6316
+ * @return {Number|String} An ANSI color code for the given namespace
6317
+ * @api private
6318
+ */
6319
+ function selectColor(namespace) {
6320
+ let hash = 0;
6321
+
6322
+ for (let i = 0; i < namespace.length; i++) {
6323
+ hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
6324
+ hash |= 0; // Convert to 32bit integer
6325
+ }
6326
+
6327
+ return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
6328
+ }
6329
+ createDebug.selectColor = selectColor;
6330
+
6331
+ /**
6332
+ * Create a debugger with the given `namespace`.
6333
+ *
6334
+ * @param {String} namespace
6335
+ * @return {Function}
6336
+ * @api public
6337
+ */
6338
+ function createDebug(namespace) {
6339
+ let prevTime;
6340
+ let enableOverride = null;
6341
+ let namespacesCache;
6342
+ let enabledCache;
6343
+
6344
+ function debug(...args) {
6345
+ // Disabled?
6346
+ if (!debug.enabled) {
6347
+ return;
6348
+ }
6349
+
6350
+ const self = debug;
6351
+
6352
+ // Set `diff` timestamp
6353
+ const curr = Number(new Date());
6354
+ const ms = curr - (prevTime || curr);
6355
+ self.diff = ms;
6356
+ self.prev = prevTime;
6357
+ self.curr = curr;
6358
+ prevTime = curr;
6359
+
6360
+ args[0] = createDebug.coerce(args[0]);
6361
+
6362
+ if (typeof args[0] !== 'string') {
6363
+ // Anything else let's inspect with %O
6364
+ args.unshift('%O');
6365
+ }
6366
+
6367
+ // Apply any `formatters` transformations
6368
+ let index = 0;
6369
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
6370
+ // If we encounter an escaped % then don't increase the array index
6371
+ if (match === '%%') {
6372
+ return '%';
6373
+ }
6374
+ index++;
6375
+ const formatter = createDebug.formatters[format];
6376
+ if (typeof formatter === 'function') {
6377
+ const val = args[index];
6378
+ match = formatter.call(self, val);
6379
+
6380
+ // Now we need to remove `args[index]` since it's inlined in the `format`
6381
+ args.splice(index, 1);
6382
+ index--;
6383
+ }
6384
+ return match;
6385
+ });
6386
+
6387
+ // Apply env-specific formatting (colors, etc.)
6388
+ createDebug.formatArgs.call(self, args);
6389
+
6390
+ const logFn = self.log || createDebug.log;
6391
+ logFn.apply(self, args);
6392
+ }
6393
+
6394
+ debug.namespace = namespace;
6395
+ debug.useColors = createDebug.useColors();
6396
+ debug.color = createDebug.selectColor(namespace);
6397
+ debug.extend = extend;
6398
+ debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
6399
+
6400
+ Object.defineProperty(debug, 'enabled', {
6401
+ enumerable: true,
6402
+ configurable: false,
6403
+ get: () => {
6404
+ if (enableOverride !== null) {
6405
+ return enableOverride;
6406
+ }
6407
+ if (namespacesCache !== createDebug.namespaces) {
6408
+ namespacesCache = createDebug.namespaces;
6409
+ enabledCache = createDebug.enabled(namespace);
6410
+ }
6411
+
6412
+ return enabledCache;
6413
+ },
6414
+ set: v => {
6415
+ enableOverride = v;
6416
+ }
6417
+ });
6418
+
6419
+ // Env-specific initialization logic for debug instances
6420
+ if (typeof createDebug.init === 'function') {
6421
+ createDebug.init(debug);
6422
+ }
6423
+
6424
+ return debug;
6425
+ }
6426
+
6427
+ function extend(namespace, delimiter) {
6428
+ const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
6429
+ newDebug.log = this.log;
6430
+ return newDebug;
6431
+ }
6432
+
6433
+ /**
6434
+ * Enables a debug mode by namespaces. This can include modes
6435
+ * separated by a colon and wildcards.
6436
+ *
6437
+ * @param {String} namespaces
6438
+ * @api public
6439
+ */
6440
+ function enable(namespaces) {
6441
+ createDebug.save(namespaces);
6442
+ createDebug.namespaces = namespaces;
6443
+
6444
+ createDebug.names = [];
6445
+ createDebug.skips = [];
6446
+
6447
+ const split = (typeof namespaces === 'string' ? namespaces : '')
6448
+ .trim()
6449
+ .replace(' ', ',')
6450
+ .split(',')
6451
+ .filter(Boolean);
6452
+
6453
+ for (const ns of split) {
6454
+ if (ns[0] === '-') {
6455
+ createDebug.skips.push(ns.slice(1));
6456
+ } else {
6457
+ createDebug.names.push(ns);
6458
+ }
6459
+ }
6460
+ }
6461
+
6462
+ /**
6463
+ * Checks if the given string matches a namespace template, honoring
6464
+ * asterisks as wildcards.
6465
+ *
6466
+ * @param {String} search
6467
+ * @param {String} template
6468
+ * @return {Boolean}
6469
+ */
6470
+ function matchesTemplate(search, template) {
6471
+ let searchIndex = 0;
6472
+ let templateIndex = 0;
6473
+ let starIndex = -1;
6474
+ let matchIndex = 0;
6475
+
6476
+ while (searchIndex < search.length) {
6477
+ if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
6478
+ // Match character or proceed with wildcard
6479
+ if (template[templateIndex] === '*') {
6480
+ starIndex = templateIndex;
6481
+ matchIndex = searchIndex;
6482
+ templateIndex++; // Skip the '*'
6483
+ } else {
6484
+ searchIndex++;
6485
+ templateIndex++;
6486
+ }
6487
+ } else if (starIndex !== -1) { // eslint-disable-line no-negated-condition
6488
+ // Backtrack to the last '*' and try to match more characters
6489
+ templateIndex = starIndex + 1;
6490
+ matchIndex++;
6491
+ searchIndex = matchIndex;
6492
+ } else {
6493
+ return false; // No match
6494
+ }
6495
+ }
6496
+
6497
+ // Handle trailing '*' in template
6498
+ while (templateIndex < template.length && template[templateIndex] === '*') {
6499
+ templateIndex++;
6500
+ }
6501
+
6502
+ return templateIndex === template.length;
6503
+ }
6504
+
6505
+ /**
6506
+ * Disable debug output.
6507
+ *
6508
+ * @return {String} namespaces
6509
+ * @api public
6510
+ */
6511
+ function disable() {
6512
+ const namespaces = [
6513
+ ...createDebug.names,
6514
+ ...createDebug.skips.map(namespace => '-' + namespace)
6515
+ ].join(',');
6516
+ createDebug.enable('');
6517
+ return namespaces;
6518
+ }
6519
+
6520
+ /**
6521
+ * Returns true if the given mode name is enabled, false otherwise.
6522
+ *
6523
+ * @param {String} name
6524
+ * @return {Boolean}
6525
+ * @api public
6526
+ */
6527
+ function enabled(name) {
6528
+ for (const skip of createDebug.skips) {
6529
+ if (matchesTemplate(name, skip)) {
6530
+ return false;
6531
+ }
6532
+ }
6533
+
6534
+ for (const ns of createDebug.names) {
6535
+ if (matchesTemplate(name, ns)) {
6536
+ return true;
6537
+ }
6538
+ }
6539
+
6540
+ return false;
6541
+ }
6542
+
6543
+ /**
6544
+ * Coerce `val`.
6545
+ *
6546
+ * @param {Mixed} val
6547
+ * @return {Mixed}
6548
+ * @api private
6549
+ */
6550
+ function coerce(val) {
6551
+ if (val instanceof Error) {
6552
+ return val.stack || val.message;
6553
+ }
6554
+ return val;
6555
+ }
6556
+
6557
+ /**
6558
+ * XXX DO NOT USE. This is a temporary stub function.
6559
+ * XXX It WILL be removed in the next major release.
6560
+ */
6561
+ function destroy() {
6562
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
6563
+ }
6564
+
6565
+ createDebug.enable(createDebug.load());
6566
+
6567
+ return createDebug;
6568
+ }
6569
+
6570
+ var common = setup;
6571
+
6572
+ /* eslint-env browser */
6573
+
6574
+ (function (module, exports) {
6575
+ /**
6576
+ * This is the web browser implementation of `debug()`.
6577
+ */
6578
+
6579
+ exports.formatArgs = formatArgs;
6580
+ exports.save = save;
6581
+ exports.load = load;
6582
+ exports.useColors = useColors;
6583
+ exports.storage = localstorage();
6584
+ exports.destroy = (() => {
6585
+ let warned = false;
6586
+
6587
+ return () => {
6588
+ if (!warned) {
6589
+ warned = true;
6590
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
6591
+ }
6592
+ };
6593
+ })();
6594
+
6595
+ /**
6596
+ * Colors.
6597
+ */
6598
+
6599
+ exports.colors = [
6600
+ '#0000CC',
6601
+ '#0000FF',
6602
+ '#0033CC',
6603
+ '#0033FF',
6604
+ '#0066CC',
6605
+ '#0066FF',
6606
+ '#0099CC',
6607
+ '#0099FF',
6608
+ '#00CC00',
6609
+ '#00CC33',
6610
+ '#00CC66',
6611
+ '#00CC99',
6612
+ '#00CCCC',
6613
+ '#00CCFF',
6614
+ '#3300CC',
6615
+ '#3300FF',
6616
+ '#3333CC',
6617
+ '#3333FF',
6618
+ '#3366CC',
6619
+ '#3366FF',
6620
+ '#3399CC',
6621
+ '#3399FF',
6622
+ '#33CC00',
6623
+ '#33CC33',
6624
+ '#33CC66',
6625
+ '#33CC99',
6626
+ '#33CCCC',
6627
+ '#33CCFF',
6628
+ '#6600CC',
6629
+ '#6600FF',
6630
+ '#6633CC',
6631
+ '#6633FF',
6632
+ '#66CC00',
6633
+ '#66CC33',
6634
+ '#9900CC',
6635
+ '#9900FF',
6636
+ '#9933CC',
6637
+ '#9933FF',
6638
+ '#99CC00',
6639
+ '#99CC33',
6640
+ '#CC0000',
6641
+ '#CC0033',
6642
+ '#CC0066',
6643
+ '#CC0099',
6644
+ '#CC00CC',
6645
+ '#CC00FF',
6646
+ '#CC3300',
6647
+ '#CC3333',
6648
+ '#CC3366',
6649
+ '#CC3399',
6650
+ '#CC33CC',
6651
+ '#CC33FF',
6652
+ '#CC6600',
6653
+ '#CC6633',
6654
+ '#CC9900',
6655
+ '#CC9933',
6656
+ '#CCCC00',
6657
+ '#CCCC33',
6658
+ '#FF0000',
6659
+ '#FF0033',
6660
+ '#FF0066',
6661
+ '#FF0099',
6662
+ '#FF00CC',
6663
+ '#FF00FF',
6664
+ '#FF3300',
6665
+ '#FF3333',
6666
+ '#FF3366',
6667
+ '#FF3399',
6668
+ '#FF33CC',
6669
+ '#FF33FF',
6670
+ '#FF6600',
6671
+ '#FF6633',
6672
+ '#FF9900',
6673
+ '#FF9933',
6674
+ '#FFCC00',
6675
+ '#FFCC33'
6676
+ ];
6677
+
6678
+ /**
6679
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
6680
+ * and the Firebug extension (any Firefox version) are known
6681
+ * to support "%c" CSS customizations.
6682
+ *
6683
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
6684
+ */
6685
+
6686
+ // eslint-disable-next-line complexity
6687
+ function useColors() {
6688
+ // NB: In an Electron preload script, document will be defined but not fully
6689
+ // initialized. Since we know we're in Chrome, we'll just detect this case
6690
+ // explicitly
6691
+ if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
6692
+ return true;
6693
+ }
6694
+
6695
+ // Internet Explorer and Edge do not support colors.
6696
+ if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
6697
+ return false;
6698
+ }
6699
+
6700
+ let m;
6701
+
6702
+ // Is webkit? http://stackoverflow.com/a/16459606/376773
6703
+ // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
6704
+ // eslint-disable-next-line no-return-assign
6705
+ return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
6706
+ // Is firebug? http://stackoverflow.com/a/398120/376773
6707
+ (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
6708
+ // Is firefox >= v31?
6709
+ // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
6710
+ (typeof navigator !== 'undefined' && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31) ||
6711
+ // Double check webkit in userAgent just in case we are in a worker
6712
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
6713
+ }
6714
+
6715
+ /**
6716
+ * Colorize log arguments if enabled.
6717
+ *
6718
+ * @api public
6719
+ */
6720
+
6721
+ function formatArgs(args) {
6722
+ args[0] = (this.useColors ? '%c' : '') +
6723
+ this.namespace +
6724
+ (this.useColors ? ' %c' : ' ') +
6725
+ args[0] +
6726
+ (this.useColors ? '%c ' : ' ') +
6727
+ '+' + module.exports.humanize(this.diff);
6728
+
6729
+ if (!this.useColors) {
6730
+ return;
6731
+ }
6732
+
6733
+ const c = 'color: ' + this.color;
6734
+ args.splice(1, 0, c, 'color: inherit');
6735
+
6736
+ // The final "%c" is somewhat tricky, because there could be other
6737
+ // arguments passed either before or after the %c, so we need to
6738
+ // figure out the correct index to insert the CSS into
6739
+ let index = 0;
6740
+ let lastC = 0;
6741
+ args[0].replace(/%[a-zA-Z%]/g, match => {
6742
+ if (match === '%%') {
6743
+ return;
6744
+ }
6745
+ index++;
6746
+ if (match === '%c') {
6747
+ // We only are interested in the *last* %c
6748
+ // (the user may have provided their own)
6749
+ lastC = index;
6750
+ }
6751
+ });
6752
+
6753
+ args.splice(lastC, 0, c);
6754
+ }
6755
+
6756
+ /**
6757
+ * Invokes `console.debug()` when available.
6758
+ * No-op when `console.debug` is not a "function".
6759
+ * If `console.debug` is not available, falls back
6760
+ * to `console.log`.
6761
+ *
6762
+ * @api public
6763
+ */
6764
+ exports.log = console.debug || console.log || (() => {});
6765
+
6766
+ /**
6767
+ * Save `namespaces`.
6768
+ *
6769
+ * @param {String} namespaces
6770
+ * @api private
6771
+ */
6772
+ function save(namespaces) {
6773
+ try {
6774
+ if (namespaces) {
6775
+ exports.storage.setItem('debug', namespaces);
6776
+ } else {
6777
+ exports.storage.removeItem('debug');
6778
+ }
6779
+ } catch (error) {
6780
+ // Swallow
6781
+ // XXX (@Qix-) should we be logging these?
6782
+ }
6783
+ }
6784
+
6785
+ /**
6786
+ * Load `namespaces`.
6787
+ *
6788
+ * @return {String} returns the previously persisted debug modes
6789
+ * @api private
6790
+ */
6791
+ function load() {
6792
+ let r;
6793
+ try {
6794
+ r = exports.storage.getItem('debug');
6795
+ } catch (error) {
6796
+ // Swallow
6797
+ // XXX (@Qix-) should we be logging these?
6798
+ }
6799
+
6800
+ // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
6801
+ if (!r && typeof process !== 'undefined' && 'env' in process) {
6802
+ r = process.env.DEBUG;
6803
+ }
6804
+
6805
+ return r;
6806
+ }
6807
+
6808
+ /**
6809
+ * Localstorage attempts to return the localstorage.
6810
+ *
6811
+ * This is necessary because safari throws
6812
+ * when a user disables cookies/localstorage
6813
+ * and you attempt to access it.
6814
+ *
6815
+ * @return {LocalStorage}
6816
+ * @api private
6817
+ */
6818
+
6819
+ function localstorage() {
6820
+ try {
6821
+ // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
6822
+ // The Browser also has localStorage in the global context.
6823
+ return localStorage;
6824
+ } catch (error) {
6825
+ // Swallow
6826
+ // XXX (@Qix-) should we be logging these?
6827
+ }
6828
+ }
6829
+
6830
+ module.exports = common(exports);
6831
+
6832
+ const {formatters} = module.exports;
6833
+
6834
+ /**
6835
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
6836
+ */
6837
+
6838
+ formatters.j = function (v) {
6839
+ try {
6840
+ return JSON.stringify(v);
6841
+ } catch (error) {
6842
+ return '[UnexpectedJSONParseError]: ' + error.message;
6843
+ }
6844
+ };
6845
+ } (browser, browser.exports));
6846
+
6847
+ var browserExports = browser.exports;
6848
+ var debug = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
6849
+
6850
+ const APP_NAME = "waku";
6851
+ class Logger {
6852
+ _info;
6853
+ _warn;
6854
+ _error;
6855
+ static createDebugNamespace(level, prefix) {
6856
+ return prefix ? `${APP_NAME}:${level}:${prefix}` : `${APP_NAME}:${level}`;
6857
+ }
6858
+ constructor(prefix) {
6859
+ this._info = debug(Logger.createDebugNamespace("info", prefix));
6860
+ this._warn = debug(Logger.createDebugNamespace("warn", prefix));
6861
+ this._error = debug(Logger.createDebugNamespace("error", prefix));
6862
+ }
6863
+ get info() {
6864
+ return this._info;
6865
+ }
6866
+ get warn() {
6867
+ return this._warn;
6868
+ }
6869
+ get error() {
6870
+ return this._error;
6871
+ }
6872
+ log(level, ...args) {
6873
+ const logger = this[level];
6874
+ logger(...args);
5951
6875
  }
5952
6876
  }
5953
- /** SHA2-256 hash function */
5954
- const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
5955
6877
 
5956
6878
  const DEFAULT_BLOOM_FILTER_OPTIONS = {
5957
6879
  capacity: 10000,
@@ -5959,14 +6881,15 @@ const DEFAULT_BLOOM_FILTER_OPTIONS = {
5959
6881
  };
5960
6882
  const DEFAULT_CAUSAL_HISTORY_SIZE = 2;
5961
6883
  const DEFAULT_RECEIVED_MESSAGE_TIMEOUT = 1000 * 60 * 5; // 5 minutes
6884
+ const log = new Logger("sds:message-channel");
5962
6885
  class MessageChannel extends TypedEventEmitter {
6886
+ channelId;
5963
6887
  lamportTimestamp;
5964
6888
  filter;
5965
6889
  outgoingBuffer;
5966
6890
  acknowledgements;
5967
6891
  incomingBuffer;
5968
6892
  localHistory;
5969
- channelId;
5970
6893
  causalHistorySize;
5971
6894
  acknowledgementCount;
5972
6895
  timeReceived;
@@ -6002,40 +6925,61 @@ class MessageChannel extends TypedEventEmitter {
6002
6925
  this.receivedMessageTimeout =
6003
6926
  options.receivedMessageTimeout ?? DEFAULT_RECEIVED_MESSAGE_TIMEOUT;
6004
6927
  }
6005
- // Periodically called by the library consumer to process async operations
6006
- // in a sequential manner.
6928
+ static getMessageId(payload) {
6929
+ return bytesToHex(sha256(payload));
6930
+ }
6931
+ /**
6932
+ * Processes all queued tasks sequentially to ensure proper message ordering.
6933
+ *
6934
+ * This method should be called periodically by the library consumer to execute
6935
+ * queued send/receive operations in the correct sequence.
6936
+ *
6937
+ * @example
6938
+ * ```typescript
6939
+ * const channel = new MessageChannel("my-channel");
6940
+ *
6941
+ * // Queue some operations
6942
+ * await channel.sendMessage(payload, callback);
6943
+ * channel.receiveMessage(incomingMessage);
6944
+ *
6945
+ * // Process all queued operations
6946
+ * await channel.processTasks();
6947
+ * ```
6948
+ *
6949
+ * @throws Will emit a 'taskError' event if any task fails, but continues processing remaining tasks
6950
+ */
6007
6951
  async processTasks() {
6008
6952
  while (this.tasks.length > 0) {
6009
6953
  const item = this.tasks.shift();
6010
6954
  if (!item) {
6011
6955
  continue;
6012
6956
  }
6013
- // Use a generic helper function to ensure type safety
6014
6957
  await this.executeTask(item);
6015
6958
  }
6016
6959
  }
6017
- async executeTask(item) {
6018
- const handler = this.handlers[item.command];
6019
- await handler(item.params);
6020
- }
6021
- static getMessageId(payload) {
6022
- return bytesToHex(sha256(payload));
6023
- }
6024
6960
  /**
6025
- * Send a message to the SDS channel.
6961
+ * Queues a message to be sent on this channel.
6026
6962
  *
6027
- * Increments the lamport timestamp, constructs a `Message` object
6028
- * with the given payload, and adds it to the outgoing buffer.
6963
+ * The message will be processed sequentially when processTasks() is called.
6964
+ * This ensures proper lamport timestamp ordering and causal history tracking.
6029
6965
  *
6030
- * If the callback is successful, the message is also added to
6031
- * the bloom filter and message history. In the context of
6032
- * Waku, this likely means the message was published via
6033
- * light push or relay.
6966
+ * @param payload - The message content as a byte array
6967
+ * @param callback - Optional callback function called after the message is processed
6968
+ * @returns Promise that resolves when the message is queued (not sent)
6034
6969
  *
6035
- * See https://rfc.vac.dev/vac/raw/sds/#send-message
6970
+ * @example
6971
+ * ```typescript
6972
+ * const channel = new MessageChannel("chat-room");
6973
+ * const message = new TextEncoder().encode("Hello, world!");
6036
6974
  *
6037
- * @param payload - The payload to send.
6038
- * @param callback - A callback function that returns a boolean indicating whether the message was sent successfully.
6975
+ * await channel.sendMessage(message, async (processedMessage) => {
6976
+ * console.log("Message processed:", processedMessage.messageId);
6977
+ * return { success: true };
6978
+ * });
6979
+ *
6980
+ * // Actually send the message
6981
+ * await channel.processTasks();
6982
+ * ```
6039
6983
  */
6040
6984
  async sendMessage(payload, callback) {
6041
6985
  this.tasks.push({
@@ -6046,38 +6990,6 @@ class MessageChannel extends TypedEventEmitter {
6046
6990
  }
6047
6991
  });
6048
6992
  }
6049
- async _sendMessage(payload, callback) {
6050
- this.lamportTimestamp++;
6051
- const messageId = MessageChannel.getMessageId(payload);
6052
- const message = {
6053
- messageId,
6054
- channelId: this.channelId,
6055
- lamportTimestamp: this.lamportTimestamp,
6056
- causalHistory: this.localHistory
6057
- .slice(-this.causalHistorySize)
6058
- .map(({ historyEntry }) => historyEntry),
6059
- bloomFilter: this.filter.toBytes(),
6060
- content: payload
6061
- };
6062
- this.outgoingBuffer.push(message);
6063
- if (callback) {
6064
- const { success, retrievalHint } = await callback(message);
6065
- if (success) {
6066
- this.filter.insert(messageId);
6067
- this.localHistory.push({
6068
- timestamp: this.lamportTimestamp,
6069
- historyEntry: {
6070
- messageId,
6071
- retrievalHint
6072
- }
6073
- });
6074
- this.timeReceived.set(messageId, Date.now());
6075
- this.safeDispatchEvent(MessageChannelEvent.MessageSent, {
6076
- detail: message
6077
- });
6078
- }
6079
- }
6080
- }
6081
6993
  /**
6082
6994
  * Sends a short-lived message without synchronization or reliability requirements.
6083
6995
  *
@@ -6100,32 +7012,24 @@ class MessageChannel extends TypedEventEmitter {
6100
7012
  }
6101
7013
  });
6102
7014
  }
6103
- async _sendEphemeralMessage(payload, callback) {
6104
- const message = {
6105
- messageId: MessageChannel.getMessageId(payload),
6106
- channelId: this.channelId,
6107
- content: payload,
6108
- lamportTimestamp: undefined,
6109
- causalHistory: [],
6110
- bloomFilter: undefined
6111
- };
6112
- if (callback) {
6113
- await callback(message);
6114
- }
6115
- }
6116
7015
  /**
6117
- * Process a received SDS message for this channel.
7016
+ * Queues a received message for processing.
7017
+ *
7018
+ * The message will be processed when processTasks() is called, ensuring
7019
+ * proper dependency resolution and causal ordering.
7020
+ *
7021
+ * @param message - The message to receive and process
6118
7022
  *
6119
- * Review the acknowledgement status of messages in the outgoing buffer
6120
- * by inspecting the received message's bloom filter and causal history.
6121
- * Add the received message to the bloom filter.
6122
- * If the local history contains every message in the received message's
6123
- * causal history, deliver the message. Otherwise, add the message to the
6124
- * incoming buffer.
7023
+ * @example
7024
+ * ```typescript
7025
+ * const channel = new MessageChannel("chat-room");
6125
7026
  *
6126
- * See https://rfc.vac.dev/vac/raw/sds/#receive-message
7027
+ * // Receive a message from the network
7028
+ * channel.receiveMessage(incomingMessage);
6127
7029
  *
6128
- * @param message - The received SDS message.
7030
+ * // Process the received message
7031
+ * await channel.processTasks();
7032
+ * ```
6129
7033
  */
6130
7034
  receiveMessage(message) {
6131
7035
  this.tasks.push({
@@ -6135,62 +7039,17 @@ class MessageChannel extends TypedEventEmitter {
6135
7039
  }
6136
7040
  });
6137
7041
  }
6138
- _receiveMessage(message) {
6139
- if (message.content &&
6140
- message.content.length > 0 &&
6141
- this.timeReceived.has(message.messageId)) {
6142
- // Received a duplicate message
6143
- return;
6144
- }
6145
- if (!message.lamportTimestamp) {
6146
- // Messages with no timestamp are ephemeral messages and should be delivered immediately
6147
- this.deliverMessage(message);
6148
- return;
6149
- }
6150
- if (message.content?.length === 0) {
6151
- this.safeDispatchEvent(MessageChannelEvent.SyncReceived, {
6152
- detail: message
6153
- });
6154
- }
6155
- else {
6156
- this.safeDispatchEvent(MessageChannelEvent.MessageReceived, {
6157
- detail: message
6158
- });
6159
- }
6160
- // review ack status
6161
- this.reviewAckStatus(message);
6162
- // add to bloom filter (skip for messages with empty content)
6163
- if (message.content?.length && message.content.length > 0) {
6164
- this.filter.insert(message.messageId);
6165
- }
6166
- // verify causal history
6167
- const dependenciesMet = message.causalHistory.every((historyEntry) => this.localHistory.some(({ historyEntry: { messageId } }) => messageId === historyEntry.messageId));
6168
- if (!dependenciesMet) {
6169
- this.incomingBuffer.push(message);
6170
- this.timeReceived.set(message.messageId, Date.now());
6171
- }
6172
- else {
6173
- this.deliverMessage(message);
6174
- this.safeDispatchEvent(MessageChannelEvent.MessageDelivered, {
6175
- detail: {
6176
- messageId: message.messageId,
6177
- sentOrReceived: "received"
6178
- }
6179
- });
6180
- }
6181
- }
6182
- // https://rfc.vac.dev/vac/raw/sds/#periodic-incoming-buffer-sweep
6183
- // Note that even though this function has side effects, it is not async
6184
- // and does not need to be called through the queue.
7042
+ /**
7043
+ * Processes messages in the incoming buffer, delivering those with satisfied dependencies.
7044
+ *
7045
+ * @returns Array of history entries for messages still missing dependencies
7046
+ */
6185
7047
  sweepIncomingBuffer() {
6186
7048
  const { buffer, missing } = this.incomingBuffer.reduce(({ buffer, missing }, message) => {
6187
- // Check each message for missing dependencies
6188
7049
  const missingDependencies = message.causalHistory.filter((messageHistoryEntry) => !this.localHistory.some(({ historyEntry: { messageId } }) => messageId === messageHistoryEntry.messageId));
6189
7050
  if (missingDependencies.length === 0) {
6190
- // Any message with no missing dependencies is delivered
6191
- // and removed from the buffer (implicitly by not adding it to the new incoming buffer)
6192
7051
  this.deliverMessage(message);
6193
- this.safeDispatchEvent(MessageChannelEvent.MessageDelivered, {
7052
+ this.safeSendEvent(MessageChannelEvent.MessageDelivered, {
6194
7053
  detail: {
6195
7054
  messageId: message.messageId,
6196
7055
  sentOrReceived: "received"
@@ -6207,8 +7066,6 @@ class MessageChannel extends TypedEventEmitter {
6207
7066
  return { buffer, missing };
6208
7067
  }
6209
7068
  }
6210
- // Any message with missing dependencies stays in the buffer
6211
- // and the missing message IDs are returned for processing.
6212
7069
  missingDependencies.forEach((dependency) => {
6213
7070
  missing.add(dependency);
6214
7071
  });
@@ -6217,16 +7074,14 @@ class MessageChannel extends TypedEventEmitter {
6217
7074
  missing
6218
7075
  };
6219
7076
  }, { buffer: new Array(), missing: new Set() });
6220
- // Update the incoming buffer to only include messages with no missing dependencies
6221
7077
  this.incomingBuffer = buffer;
6222
- this.safeDispatchEvent(MessageChannelEvent.MissedMessages, {
7078
+ this.safeSendEvent(MessageChannelEvent.MissedMessages, {
6223
7079
  detail: Array.from(missing)
6224
7080
  });
6225
7081
  return Array.from(missing);
6226
7082
  }
6227
7083
  // https://rfc.vac.dev/vac/raw/sds/#periodic-outgoing-buffer-sweep
6228
7084
  sweepOutgoingBuffer() {
6229
- // Partition all messages in the outgoing buffer into unacknowledged and possibly acknowledged messages
6230
7085
  return this.outgoingBuffer.reduce(({ unacknowledged, possiblyAcknowledged }, message) => {
6231
7086
  if (this.acknowledgements.has(message.messageId)) {
6232
7087
  return {
@@ -6267,13 +7122,136 @@ class MessageChannel extends TypedEventEmitter {
6267
7122
  content: emptyMessage
6268
7123
  };
6269
7124
  if (callback) {
6270
- await callback(message);
6271
- this.safeDispatchEvent(MessageChannelEvent.SyncSent, {
7125
+ try {
7126
+ await callback(message);
7127
+ this.safeSendEvent(MessageChannelEvent.SyncSent, {
7128
+ detail: message
7129
+ });
7130
+ return true;
7131
+ }
7132
+ catch (error) {
7133
+ log.error("Callback execution failed in sendSyncMessage:", error);
7134
+ throw error;
7135
+ }
7136
+ }
7137
+ return false;
7138
+ }
7139
+ _receiveMessage(message) {
7140
+ const isDuplicate = message.content &&
7141
+ message.content.length > 0 &&
7142
+ this.timeReceived.has(message.messageId);
7143
+ if (isDuplicate) {
7144
+ return;
7145
+ }
7146
+ if (!message.lamportTimestamp) {
7147
+ this.deliverMessage(message);
7148
+ return;
7149
+ }
7150
+ if (message.content?.length === 0) {
7151
+ this.safeSendEvent(MessageChannelEvent.SyncReceived, {
6272
7152
  detail: message
6273
7153
  });
6274
- return true;
6275
7154
  }
6276
- return false;
7155
+ else {
7156
+ this.safeSendEvent(MessageChannelEvent.MessageReceived, {
7157
+ detail: message
7158
+ });
7159
+ }
7160
+ this.reviewAckStatus(message);
7161
+ if (message.content?.length && message.content.length > 0) {
7162
+ this.filter.insert(message.messageId);
7163
+ }
7164
+ const dependenciesMet = message.causalHistory.every((historyEntry) => this.localHistory.some(({ historyEntry: { messageId } }) => messageId === historyEntry.messageId));
7165
+ if (!dependenciesMet) {
7166
+ this.incomingBuffer.push(message);
7167
+ this.timeReceived.set(message.messageId, Date.now());
7168
+ }
7169
+ else {
7170
+ this.deliverMessage(message);
7171
+ this.safeSendEvent(MessageChannelEvent.MessageDelivered, {
7172
+ detail: {
7173
+ messageId: message.messageId,
7174
+ sentOrReceived: "received"
7175
+ }
7176
+ });
7177
+ }
7178
+ }
7179
+ async executeTask(item) {
7180
+ try {
7181
+ const handler = this.handlers[item.command];
7182
+ await handler(item.params);
7183
+ }
7184
+ catch (error) {
7185
+ log.error(`Task execution failed for command ${item.command}:`, error);
7186
+ this.dispatchEvent(new CustomEvent("taskError", {
7187
+ detail: { command: item.command, error, params: item.params }
7188
+ }));
7189
+ }
7190
+ }
7191
+ safeSendEvent(event, eventInit) {
7192
+ try {
7193
+ this.dispatchEvent(new CustomEvent(event, eventInit));
7194
+ }
7195
+ catch (error) {
7196
+ log.error(`Failed to dispatch event ${event}:`, error);
7197
+ }
7198
+ }
7199
+ async _sendMessage(payload, callback) {
7200
+ this.lamportTimestamp++;
7201
+ const messageId = MessageChannel.getMessageId(payload);
7202
+ const message = {
7203
+ messageId,
7204
+ channelId: this.channelId,
7205
+ lamportTimestamp: this.lamportTimestamp,
7206
+ causalHistory: this.localHistory
7207
+ .slice(-this.causalHistorySize)
7208
+ .map(({ historyEntry }) => historyEntry),
7209
+ bloomFilter: this.filter.toBytes(),
7210
+ content: payload
7211
+ };
7212
+ this.outgoingBuffer.push(message);
7213
+ if (callback) {
7214
+ try {
7215
+ const { success, retrievalHint } = await callback(message);
7216
+ if (success) {
7217
+ this.filter.insert(messageId);
7218
+ this.localHistory.push({
7219
+ timestamp: this.lamportTimestamp,
7220
+ historyEntry: {
7221
+ messageId,
7222
+ retrievalHint
7223
+ }
7224
+ });
7225
+ this.timeReceived.set(messageId, Date.now());
7226
+ this.safeSendEvent(MessageChannelEvent.MessageSent, {
7227
+ detail: message
7228
+ });
7229
+ }
7230
+ }
7231
+ catch (error) {
7232
+ log.error("Callback execution failed in _sendMessage:", error);
7233
+ throw error;
7234
+ }
7235
+ }
7236
+ }
7237
+ async _sendEphemeralMessage(payload, callback) {
7238
+ const message = {
7239
+ messageId: MessageChannel.getMessageId(payload),
7240
+ channelId: this.channelId,
7241
+ content: payload,
7242
+ lamportTimestamp: undefined,
7243
+ causalHistory: [],
7244
+ bloomFilter: undefined
7245
+ };
7246
+ if (callback) {
7247
+ try {
7248
+ await callback(message);
7249
+ }
7250
+ catch (error) {
7251
+ log.error("Callback execution failed in _sendEphemeralMessage:", error);
7252
+ throw error;
7253
+ }
7254
+ }
6277
7255
  }
6278
7256
  // See https://rfc.vac.dev/vac/raw/sds/#deliver-message
6279
7257
  deliverMessage(message, retrievalHint) {
@@ -6311,13 +7289,12 @@ class MessageChannel extends TypedEventEmitter {
6311
7289
  // to determine the acknowledgement status of messages in the outgoing buffer.
6312
7290
  // See https://rfc.vac.dev/vac/raw/sds/#review-ack-status
6313
7291
  reviewAckStatus(receivedMessage) {
6314
- // the participant MUST mark all messages in the received causal_history as acknowledged.
6315
7292
  receivedMessage.causalHistory.forEach(({ messageId }) => {
6316
7293
  this.outgoingBuffer = this.outgoingBuffer.filter(({ messageId: outgoingMessageId }) => {
6317
7294
  if (outgoingMessageId !== messageId) {
6318
7295
  return true;
6319
7296
  }
6320
- this.safeDispatchEvent(MessageChannelEvent.MessageAcknowledged, {
7297
+ this.safeSendEvent(MessageChannelEvent.MessageAcknowledged, {
6321
7298
  detail: messageId
6322
7299
  });
6323
7300
  return false;
@@ -6327,7 +7304,6 @@ class MessageChannel extends TypedEventEmitter {
6327
7304
  this.filter.insert(messageId);
6328
7305
  }
6329
7306
  });
6330
- // the participant MUST mark all messages included in the bloom_filter as possibly acknowledged
6331
7307
  if (!receivedMessage.bloomFilter) {
6332
7308
  return;
6333
7309
  }
@@ -6342,7 +7318,7 @@ class MessageChannel extends TypedEventEmitter {
6342
7318
  const count = (this.acknowledgements.get(message.messageId) ?? 0) + 1;
6343
7319
  if (count < this.acknowledgementCount) {
6344
7320
  this.acknowledgements.set(message.messageId, count);
6345
- this.safeDispatchEvent(MessageChannelEvent.PartialAcknowledgement, {
7321
+ this.safeSendEvent(MessageChannelEvent.PartialAcknowledgement, {
6346
7322
  detail: {
6347
7323
  messageId: message.messageId,
6348
7324
  count
@@ -6360,4 +7336,4 @@ class MessageChannel extends TypedEventEmitter {
6360
7336
  }
6361
7337
  }
6362
7338
 
6363
- export { BloomFilter, Command, DEFAULT_BLOOM_FILTER_OPTIONS, MessageChannel, MessageChannelEvent, decodeMessage, encodeMessage };
7339
+ export { BloomFilter, MessageChannel, MessageChannelEvent, decodeMessage, encodeMessage };