@waku/core 0.0.33-f599932.0 → 0.0.34-09108d9.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 (93) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/bundle/base_protocol-Bp5a9PNG.js +152 -0
  3. package/bundle/{index-BVysxsMu.js → index-G1eRBjeI.js} +136 -215
  4. package/bundle/index.js +1963 -621
  5. package/bundle/lib/base_protocol.js +2 -2
  6. package/bundle/lib/message/version_0.js +2 -2
  7. package/bundle/{version_0-C5ObpJ_0.js → version_0-DJZG2fB2.js} +285 -41
  8. package/dist/.tsbuildinfo +1 -1
  9. package/dist/index.d.ts +2 -5
  10. package/dist/index.js +2 -5
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/base_protocol.d.ts +3 -23
  13. package/dist/lib/base_protocol.js +3 -51
  14. package/dist/lib/base_protocol.js.map +1 -1
  15. package/dist/lib/connection_manager/connection_manager.d.ts +118 -0
  16. package/dist/lib/{connection_manager.js → connection_manager/connection_manager.js} +136 -36
  17. package/dist/lib/connection_manager/connection_manager.js.map +1 -0
  18. package/dist/lib/connection_manager/index.d.ts +1 -0
  19. package/dist/lib/connection_manager/index.js +2 -0
  20. package/dist/lib/connection_manager/index.js.map +1 -0
  21. package/dist/lib/{keep_alive_manager.d.ts → connection_manager/keep_alive_manager.d.ts} +4 -2
  22. package/dist/lib/{keep_alive_manager.js → connection_manager/keep_alive_manager.js} +2 -2
  23. package/dist/lib/connection_manager/keep_alive_manager.js.map +1 -0
  24. package/dist/lib/connection_manager/utils.d.ts +7 -0
  25. package/dist/lib/connection_manager/utils.js +22 -0
  26. package/dist/lib/connection_manager/utils.js.map +1 -0
  27. package/dist/lib/filter/filter.d.ts +18 -0
  28. package/dist/lib/filter/filter.js +209 -0
  29. package/dist/lib/filter/filter.js.map +1 -0
  30. package/dist/lib/filter/index.d.ts +1 -19
  31. package/dist/lib/filter/index.js +1 -211
  32. package/dist/lib/filter/index.js.map +1 -1
  33. package/dist/lib/light_push/index.d.ts +1 -15
  34. package/dist/lib/light_push/index.js +1 -143
  35. package/dist/lib/light_push/index.js.map +1 -1
  36. package/dist/lib/light_push/light_push.d.ts +15 -0
  37. package/dist/lib/light_push/light_push.js +144 -0
  38. package/dist/lib/light_push/light_push.js.map +1 -0
  39. package/dist/lib/light_push/utils.d.ts +0 -2
  40. package/dist/lib/light_push/utils.js +8 -16
  41. package/dist/lib/light_push/utils.js.map +1 -1
  42. package/dist/lib/metadata/index.d.ts +1 -3
  43. package/dist/lib/metadata/index.js +1 -118
  44. package/dist/lib/metadata/index.js.map +1 -1
  45. package/dist/lib/metadata/metadata.d.ts +3 -0
  46. package/dist/lib/metadata/metadata.js +119 -0
  47. package/dist/lib/metadata/metadata.js.map +1 -0
  48. package/dist/lib/store/index.d.ts +1 -9
  49. package/dist/lib/store/index.js +1 -82
  50. package/dist/lib/store/index.js.map +1 -1
  51. package/dist/lib/store/store.d.ts +9 -0
  52. package/dist/lib/store/store.js +83 -0
  53. package/dist/lib/store/store.js.map +1 -0
  54. package/dist/lib/stream_manager/stream_manager.d.ts +13 -10
  55. package/dist/lib/stream_manager/stream_manager.js +88 -58
  56. package/dist/lib/stream_manager/stream_manager.js.map +1 -1
  57. package/dist/lib/stream_manager/utils.d.ts +1 -1
  58. package/dist/lib/stream_manager/utils.js +5 -17
  59. package/dist/lib/stream_manager/utils.js.map +1 -1
  60. package/package.json +1 -1
  61. package/src/index.ts +2 -7
  62. package/src/lib/base_protocol.ts +3 -82
  63. package/src/lib/{connection_manager.ts → connection_manager/connection_manager.ts} +168 -63
  64. package/src/lib/connection_manager/index.ts +1 -0
  65. package/src/lib/{keep_alive_manager.ts → connection_manager/keep_alive_manager.ts} +7 -3
  66. package/src/lib/connection_manager/utils.ts +25 -0
  67. package/src/lib/filter/filter.ts +315 -0
  68. package/src/lib/filter/index.ts +1 -323
  69. package/src/lib/light_push/index.ts +1 -188
  70. package/src/lib/light_push/light_push.ts +188 -0
  71. package/src/lib/light_push/utils.ts +12 -20
  72. package/src/lib/metadata/index.ts +1 -182
  73. package/src/lib/metadata/metadata.ts +182 -0
  74. package/src/lib/store/index.ts +1 -136
  75. package/src/lib/store/store.ts +136 -0
  76. package/src/lib/stream_manager/stream_manager.ts +125 -69
  77. package/src/lib/stream_manager/utils.ts +5 -17
  78. package/bundle/base_protocol-CS0EDeEY.js +0 -260
  79. package/dist/lib/connection_manager.d.ts +0 -62
  80. package/dist/lib/connection_manager.js.map +0 -1
  81. package/dist/lib/filterPeers.d.ts +0 -13
  82. package/dist/lib/filterPeers.js +0 -38
  83. package/dist/lib/filterPeers.js.map +0 -1
  84. package/dist/lib/health_manager.d.ts +0 -14
  85. package/dist/lib/health_manager.js +0 -70
  86. package/dist/lib/health_manager.js.map +0 -1
  87. package/dist/lib/keep_alive_manager.js.map +0 -1
  88. package/dist/lib/wait_for_remote_peer.d.ts +0 -22
  89. package/dist/lib/wait_for_remote_peer.js +0 -142
  90. package/dist/lib/wait_for_remote_peer.js.map +0 -1
  91. package/src/lib/filterPeers.ts +0 -51
  92. package/src/lib/health_manager.ts +0 -90
  93. package/src/lib/wait_for_remote_peer.ts +0 -200
package/bundle/index.js CHANGED
@@ -1,8 +1,518 @@
1
- import { v as version_0, e as encodingLength, a as encode$1, d as decode$1, M as MessagePush, F as FilterSubscribeRequest, b as FilterSubscribeResponse$1, P as PushRpc$1, c as PushResponse, S as StoreQueryRequest$1, f as StoreQueryResponse$1, g as createEncoder, p as pubsubTopicToSingleShardInfo, s as shardInfoToPubsubTopics, W as WakuMetadataRequest, h as pubsubTopicsToShardInfo, i as WakuMetadataResponse } from './version_0-C5ObpJ_0.js';
2
- export { j as createDecoder } from './version_0-C5ObpJ_0.js';
3
- import { a as allocUnsafe, b as alloc, L as Logger, P as ProtocolError, c as Protocols, u as utf8ToBytes, T as Tags, E as EPeersByDiscoveryEvents, d as EConnectionStateEvents, H as HealthStatus } from './index-BVysxsMu.js';
4
- import { B as BaseProtocol } from './base_protocol-CS0EDeEY.js';
5
- export { S as StreamManager } from './base_protocol-CS0EDeEY.js';
1
+ import { v as version_0, a as allocUnsafe, b as alloc, e as encodingLength$1, c as encode$2, d as decode$4, M as MessagePush, F as FilterSubscribeRequest, f as FilterSubscribeResponse$1, P as PushRpc$1, g as PushResponse, S as StoreQueryRequest$1, h as StoreQueryResponse$1, t as toString$1, i as bases, j as fromString, u as utf8ToBytes, k as createEncoder, p as pubsubTopicToSingleShardInfo, l as bytesToUtf8, s as shardInfoToPubsubTopics, W as WakuMetadataRequest, m as pubsubTopicsToShardInfo, n as WakuMetadataResponse } from './version_0-DJZG2fB2.js';
2
+ export { o as createDecoder } from './version_0-DJZG2fB2.js';
3
+ import { c as coerce, e as equals$2, b as base36, a as base32, d as base58btc, L as Logger, P as ProtocolError, T as Tags, E as EPeersByDiscoveryEvents, f as EConnectionStateEvents } from './index-G1eRBjeI.js';
4
+ import { B as BaseProtocol } from './base_protocol-Bp5a9PNG.js';
5
+ export { S as StreamManager } from './base_protocol-Bp5a9PNG.js';
6
+
7
+ /* eslint-disable */
8
+ var encode_1 = encode$1;
9
+ var MSB = 0x80, MSBALL = -128, INT = Math.pow(2, 31);
10
+ /**
11
+ * @param {number} num
12
+ * @param {number[]} out
13
+ * @param {number} offset
14
+ */
15
+ function encode$1(num, out, offset) {
16
+ out = out || [];
17
+ offset = offset || 0;
18
+ var oldOffset = offset;
19
+ while (num >= INT) {
20
+ out[offset++] = (num & 0xFF) | MSB;
21
+ num /= 128;
22
+ }
23
+ while (num & MSBALL) {
24
+ out[offset++] = (num & 0xFF) | MSB;
25
+ num >>>= 7;
26
+ }
27
+ out[offset] = num | 0;
28
+ // @ts-ignore
29
+ encode$1.bytes = offset - oldOffset + 1;
30
+ return out;
31
+ }
32
+ var decode$3 = read;
33
+ var MSB$1 = 0x80, REST$1 = 0x7F;
34
+ /**
35
+ * @param {string | any[]} buf
36
+ * @param {number} offset
37
+ */
38
+ function read(buf, offset) {
39
+ var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
40
+ do {
41
+ if (counter >= l) {
42
+ // @ts-ignore
43
+ read.bytes = 0;
44
+ throw new RangeError('Could not decode varint');
45
+ }
46
+ b = buf[counter++];
47
+ res += shift < 28
48
+ ? (b & REST$1) << shift
49
+ : (b & REST$1) * Math.pow(2, shift);
50
+ shift += 7;
51
+ } while (b >= MSB$1);
52
+ // @ts-ignore
53
+ read.bytes = counter - offset;
54
+ return res;
55
+ }
56
+ var N1 = Math.pow(2, 7);
57
+ var N2 = Math.pow(2, 14);
58
+ var N3 = Math.pow(2, 21);
59
+ var N4 = Math.pow(2, 28);
60
+ var N5 = Math.pow(2, 35);
61
+ var N6 = Math.pow(2, 42);
62
+ var N7 = Math.pow(2, 49);
63
+ var N8 = Math.pow(2, 56);
64
+ var N9 = Math.pow(2, 63);
65
+ var length = function (/** @type {number} */ value) {
66
+ return (value < N1 ? 1
67
+ : value < N2 ? 2
68
+ : value < N3 ? 3
69
+ : value < N4 ? 4
70
+ : value < N5 ? 5
71
+ : value < N6 ? 6
72
+ : value < N7 ? 7
73
+ : value < N8 ? 8
74
+ : value < N9 ? 9
75
+ : 10);
76
+ };
77
+ var varint = {
78
+ encode: encode_1,
79
+ decode: decode$3,
80
+ encodingLength: length
81
+ };
82
+ var _brrp_varint = varint;
83
+
84
+ function decode$2(data, offset = 0) {
85
+ const code = _brrp_varint.decode(data, offset);
86
+ return [code, _brrp_varint.decode.bytes];
87
+ }
88
+ function encodeTo(int, target, offset = 0) {
89
+ _brrp_varint.encode(int, target, offset);
90
+ return target;
91
+ }
92
+ function encodingLength(int) {
93
+ return _brrp_varint.encodingLength(int);
94
+ }
95
+
96
+ /**
97
+ * Creates a multihash digest.
98
+ */
99
+ function create(code, digest) {
100
+ const size = digest.byteLength;
101
+ const sizeOffset = encodingLength(code);
102
+ const digestOffset = sizeOffset + encodingLength(size);
103
+ const bytes = new Uint8Array(digestOffset + size);
104
+ encodeTo(code, bytes, 0);
105
+ encodeTo(size, bytes, sizeOffset);
106
+ bytes.set(digest, digestOffset);
107
+ return new Digest(code, size, digest, bytes);
108
+ }
109
+ /**
110
+ * Turns bytes representation of multihash digest into an instance.
111
+ */
112
+ function decode$1(multihash) {
113
+ const bytes = coerce(multihash);
114
+ const [code, sizeOffset] = decode$2(bytes);
115
+ const [size, digestOffset] = decode$2(bytes.subarray(sizeOffset));
116
+ const digest = bytes.subarray(sizeOffset + digestOffset);
117
+ if (digest.byteLength !== size) {
118
+ throw new Error('Incorrect length');
119
+ }
120
+ return new Digest(code, size, digest, bytes);
121
+ }
122
+ function equals$1(a, b) {
123
+ if (a === b) {
124
+ return true;
125
+ }
126
+ else {
127
+ const data = b;
128
+ return (a.code === data.code &&
129
+ a.size === data.size &&
130
+ data.bytes instanceof Uint8Array &&
131
+ equals$2(a.bytes, data.bytes));
132
+ }
133
+ }
134
+ /**
135
+ * Represents a multihash digest which carries information about the
136
+ * hashing algorithm and an actual hash digest.
137
+ */
138
+ class Digest {
139
+ code;
140
+ size;
141
+ digest;
142
+ bytes;
143
+ /**
144
+ * Creates a multihash digest.
145
+ */
146
+ constructor(code, size, digest, bytes) {
147
+ this.code = code;
148
+ this.size = size;
149
+ this.digest = digest;
150
+ this.bytes = bytes;
151
+ }
152
+ }
153
+
154
+ function format(link, base) {
155
+ const { bytes, version } = link;
156
+ switch (version) {
157
+ case 0:
158
+ return toStringV0(bytes, baseCache(link), base ?? base58btc.encoder);
159
+ default:
160
+ return toStringV1(bytes, baseCache(link), (base ?? base32.encoder));
161
+ }
162
+ }
163
+ const cache = new WeakMap();
164
+ function baseCache(cid) {
165
+ const baseCache = cache.get(cid);
166
+ if (baseCache == null) {
167
+ const baseCache = new Map();
168
+ cache.set(cid, baseCache);
169
+ return baseCache;
170
+ }
171
+ return baseCache;
172
+ }
173
+ class CID {
174
+ code;
175
+ version;
176
+ multihash;
177
+ bytes;
178
+ '/';
179
+ /**
180
+ * @param version - Version of the CID
181
+ * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
182
+ * @param multihash - (Multi)hash of the of the content.
183
+ */
184
+ constructor(version, code, multihash, bytes) {
185
+ this.code = code;
186
+ this.version = version;
187
+ this.multihash = multihash;
188
+ this.bytes = bytes;
189
+ // flag to serializers that this is a CID and
190
+ // should be treated specially
191
+ this['/'] = bytes;
192
+ }
193
+ /**
194
+ * Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
195
+ * please either use `CID.asCID(cid)` or switch to new signalling mechanism
196
+ *
197
+ * @deprecated
198
+ */
199
+ get asCID() {
200
+ return this;
201
+ }
202
+ // ArrayBufferView
203
+ get byteOffset() {
204
+ return this.bytes.byteOffset;
205
+ }
206
+ // ArrayBufferView
207
+ get byteLength() {
208
+ return this.bytes.byteLength;
209
+ }
210
+ toV0() {
211
+ switch (this.version) {
212
+ case 0: {
213
+ return this;
214
+ }
215
+ case 1: {
216
+ const { code, multihash } = this;
217
+ if (code !== DAG_PB_CODE) {
218
+ throw new Error('Cannot convert a non dag-pb CID to CIDv0');
219
+ }
220
+ // sha2-256
221
+ if (multihash.code !== SHA_256_CODE) {
222
+ throw new Error('Cannot convert non sha2-256 multihash CID to CIDv0');
223
+ }
224
+ return (CID.createV0(multihash));
225
+ }
226
+ default: {
227
+ throw Error(`Can not convert CID version ${this.version} to version 0. This is a bug please report`);
228
+ }
229
+ }
230
+ }
231
+ toV1() {
232
+ switch (this.version) {
233
+ case 0: {
234
+ const { code, digest } = this.multihash;
235
+ const multihash = create(code, digest);
236
+ return (CID.createV1(this.code, multihash));
237
+ }
238
+ case 1: {
239
+ return this;
240
+ }
241
+ default: {
242
+ throw Error(`Can not convert CID version ${this.version} to version 1. This is a bug please report`);
243
+ }
244
+ }
245
+ }
246
+ equals(other) {
247
+ return CID.equals(this, other);
248
+ }
249
+ static equals(self, other) {
250
+ const unknown = other;
251
+ return (unknown != null &&
252
+ self.code === unknown.code &&
253
+ self.version === unknown.version &&
254
+ equals$1(self.multihash, unknown.multihash));
255
+ }
256
+ toString(base) {
257
+ return format(this, base);
258
+ }
259
+ toJSON() {
260
+ return { '/': format(this) };
261
+ }
262
+ link() {
263
+ return this;
264
+ }
265
+ [Symbol.toStringTag] = 'CID';
266
+ // Legacy
267
+ [Symbol.for('nodejs.util.inspect.custom')]() {
268
+ return `CID(${this.toString()})`;
269
+ }
270
+ /**
271
+ * Takes any input `value` and returns a `CID` instance if it was
272
+ * a `CID` otherwise returns `null`. If `value` is instanceof `CID`
273
+ * it will return value back. If `value` is not instance of this CID
274
+ * class, but is compatible CID it will return new instance of this
275
+ * `CID` class. Otherwise returns null.
276
+ *
277
+ * This allows two different incompatible versions of CID library to
278
+ * co-exist and interop as long as binary interface is compatible.
279
+ */
280
+ static asCID(input) {
281
+ if (input == null) {
282
+ return null;
283
+ }
284
+ const value = input;
285
+ if (value instanceof CID) {
286
+ // If value is instance of CID then we're all set.
287
+ return value;
288
+ }
289
+ else if ((value['/'] != null && value['/'] === value.bytes) || value.asCID === value) {
290
+ // If value isn't instance of this CID class but `this.asCID === this` or
291
+ // `value['/'] === value.bytes` is true it is CID instance coming from a
292
+ // different implementation (diff version or duplicate). In that case we
293
+ // rebase it to this `CID` implementation so caller is guaranteed to get
294
+ // instance with expected API.
295
+ const { version, code, multihash, bytes } = value;
296
+ return new CID(version, code, multihash, bytes ?? encodeCID(version, code, multihash.bytes));
297
+ }
298
+ else if (value[cidSymbol] === true) {
299
+ // If value is a CID from older implementation that used to be tagged via
300
+ // symbol we still rebase it to the this `CID` implementation by
301
+ // delegating that to a constructor.
302
+ const { version, multihash, code } = value;
303
+ const digest = decode$1(multihash);
304
+ return CID.create(version, code, digest);
305
+ }
306
+ else {
307
+ // Otherwise value is not a CID (or an incompatible version of it) in
308
+ // which case we return `null`.
309
+ return null;
310
+ }
311
+ }
312
+ /**
313
+ * @param version - Version of the CID
314
+ * @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
315
+ * @param digest - (Multi)hash of the of the content.
316
+ */
317
+ static create(version, code, digest) {
318
+ if (typeof code !== 'number') {
319
+ throw new Error('String codecs are no longer supported');
320
+ }
321
+ if (!(digest.bytes instanceof Uint8Array)) {
322
+ throw new Error('Invalid digest');
323
+ }
324
+ switch (version) {
325
+ case 0: {
326
+ if (code !== DAG_PB_CODE) {
327
+ throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE}) block encoding`);
328
+ }
329
+ else {
330
+ return new CID(version, code, digest, digest.bytes);
331
+ }
332
+ }
333
+ case 1: {
334
+ const bytes = encodeCID(version, code, digest.bytes);
335
+ return new CID(version, code, digest, bytes);
336
+ }
337
+ default: {
338
+ throw new Error('Invalid version');
339
+ }
340
+ }
341
+ }
342
+ /**
343
+ * Simplified version of `create` for CIDv0.
344
+ */
345
+ static createV0(digest) {
346
+ return CID.create(0, DAG_PB_CODE, digest);
347
+ }
348
+ /**
349
+ * Simplified version of `create` for CIDv1.
350
+ *
351
+ * @param code - Content encoding format code.
352
+ * @param digest - Multihash of the content.
353
+ */
354
+ static createV1(code, digest) {
355
+ return CID.create(1, code, digest);
356
+ }
357
+ /**
358
+ * Decoded a CID from its binary representation. The byte array must contain
359
+ * only the CID with no additional bytes.
360
+ *
361
+ * An error will be thrown if the bytes provided do not contain a valid
362
+ * binary representation of a CID.
363
+ */
364
+ static decode(bytes) {
365
+ const [cid, remainder] = CID.decodeFirst(bytes);
366
+ if (remainder.length !== 0) {
367
+ throw new Error('Incorrect length');
368
+ }
369
+ return cid;
370
+ }
371
+ /**
372
+ * Decoded a CID from its binary representation at the beginning of a byte
373
+ * array.
374
+ *
375
+ * Returns an array with the first element containing the CID and the second
376
+ * element containing the remainder of the original byte array. The remainder
377
+ * will be a zero-length byte array if the provided bytes only contained a
378
+ * binary CID representation.
379
+ */
380
+ static decodeFirst(bytes) {
381
+ const specs = CID.inspectBytes(bytes);
382
+ const prefixSize = specs.size - specs.multihashSize;
383
+ const multihashBytes = coerce(bytes.subarray(prefixSize, prefixSize + specs.multihashSize));
384
+ if (multihashBytes.byteLength !== specs.multihashSize) {
385
+ throw new Error('Incorrect length');
386
+ }
387
+ const digestBytes = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
388
+ const digest = new Digest(specs.multihashCode, specs.digestSize, digestBytes, multihashBytes);
389
+ const cid = specs.version === 0
390
+ ? CID.createV0(digest)
391
+ : CID.createV1(specs.codec, digest);
392
+ return [cid, bytes.subarray(specs.size)];
393
+ }
394
+ /**
395
+ * Inspect the initial bytes of a CID to determine its properties.
396
+ *
397
+ * Involves decoding up to 4 varints. Typically this will require only 4 to 6
398
+ * bytes but for larger multicodec code values and larger multihash digest
399
+ * lengths these varints can be quite large. It is recommended that at least
400
+ * 10 bytes be made available in the `initialBytes` argument for a complete
401
+ * inspection.
402
+ */
403
+ static inspectBytes(initialBytes) {
404
+ let offset = 0;
405
+ const next = () => {
406
+ const [i, length] = decode$2(initialBytes.subarray(offset));
407
+ offset += length;
408
+ return i;
409
+ };
410
+ let version = next();
411
+ let codec = DAG_PB_CODE;
412
+ if (version === 18) {
413
+ // CIDv0
414
+ version = 0;
415
+ offset = 0;
416
+ }
417
+ else {
418
+ codec = next();
419
+ }
420
+ if (version !== 0 && version !== 1) {
421
+ throw new RangeError(`Invalid CID version ${version}`);
422
+ }
423
+ const prefixSize = offset;
424
+ const multihashCode = next(); // multihash code
425
+ const digestSize = next(); // multihash length
426
+ const size = offset + digestSize;
427
+ const multihashSize = size - prefixSize;
428
+ return { version, codec, multihashCode, digestSize, multihashSize, size };
429
+ }
430
+ /**
431
+ * Takes cid in a string representation and creates an instance. If `base`
432
+ * decoder is not provided will use a default from the configuration. It will
433
+ * throw an error if encoding of the CID is not compatible with supplied (or
434
+ * a default decoder).
435
+ */
436
+ static parse(source, base) {
437
+ const [prefix, bytes] = parseCIDtoBytes(source, base);
438
+ const cid = CID.decode(bytes);
439
+ if (cid.version === 0 && source[0] !== 'Q') {
440
+ throw Error('Version 0 CID string must not include multibase prefix');
441
+ }
442
+ // Cache string representation to avoid computing it on `this.toString()`
443
+ baseCache(cid).set(prefix, source);
444
+ return cid;
445
+ }
446
+ }
447
+ function parseCIDtoBytes(source, base) {
448
+ switch (source[0]) {
449
+ // CIDv0 is parsed differently
450
+ case 'Q': {
451
+ const decoder = base ?? base58btc;
452
+ return [
453
+ base58btc.prefix,
454
+ decoder.decode(`${base58btc.prefix}${source}`)
455
+ ];
456
+ }
457
+ case base58btc.prefix: {
458
+ const decoder = base ?? base58btc;
459
+ return [base58btc.prefix, decoder.decode(source)];
460
+ }
461
+ case base32.prefix: {
462
+ const decoder = base ?? base32;
463
+ return [base32.prefix, decoder.decode(source)];
464
+ }
465
+ case base36.prefix: {
466
+ const decoder = base ?? base36;
467
+ return [base36.prefix, decoder.decode(source)];
468
+ }
469
+ default: {
470
+ if (base == null) {
471
+ throw Error('To parse non base32, base36 or base58btc encoded CID multibase decoder must be provided');
472
+ }
473
+ return [source[0], base.decode(source)];
474
+ }
475
+ }
476
+ }
477
+ function toStringV0(bytes, cache, base) {
478
+ const { prefix } = base;
479
+ if (prefix !== base58btc.prefix) {
480
+ throw Error(`Cannot string encode V0 in ${base.name} encoding`);
481
+ }
482
+ const cid = cache.get(prefix);
483
+ if (cid == null) {
484
+ const cid = base.encode(bytes).slice(1);
485
+ cache.set(prefix, cid);
486
+ return cid;
487
+ }
488
+ else {
489
+ return cid;
490
+ }
491
+ }
492
+ function toStringV1(bytes, cache, base) {
493
+ const { prefix } = base;
494
+ const cid = cache.get(prefix);
495
+ if (cid == null) {
496
+ const cid = base.encode(bytes);
497
+ cache.set(prefix, cid);
498
+ return cid;
499
+ }
500
+ else {
501
+ return cid;
502
+ }
503
+ }
504
+ const DAG_PB_CODE = 0x70;
505
+ const SHA_256_CODE = 0x12;
506
+ function encodeCID(version, code, multihash) {
507
+ const codeOffset = encodingLength(version);
508
+ const hashOffset = codeOffset + encodingLength(code);
509
+ const bytes = new Uint8Array(hashOffset + multihash.byteLength);
510
+ encodeTo(version, bytes, 0);
511
+ encodeTo(code, bytes, codeOffset);
512
+ bytes.set(multihash, hashOffset);
513
+ return bytes;
514
+ }
515
+ const cidSymbol = Symbol.for('@ipld/js-cid/CID');
6
516
 
7
517
  const MB = 1024 ** 2;
8
518
  const SIZE_CAP_IN_MB = 1;
@@ -258,7 +768,7 @@ function equals(a, b) {
258
768
  *
259
769
  * Borrows liberally from [bl](https://www.npmjs.com/package/bl) but only uses native JS types.
260
770
  */
261
- const symbol = Symbol.for('@achingbrain/uint8arraylist');
771
+ const symbol$1 = Symbol.for('@achingbrain/uint8arraylist');
262
772
  function findBufAndOffset(bufs, index) {
263
773
  if (index == null || index < 0) {
264
774
  throw new RangeError('index is out of bounds');
@@ -290,12 +800,12 @@ function findBufAndOffset(bufs, index) {
290
800
  * ```
291
801
  */
292
802
  function isUint8ArrayList(value) {
293
- return Boolean(value?.[symbol]);
803
+ return Boolean(value?.[symbol$1]);
294
804
  }
295
805
  class Uint8ArrayList {
296
806
  bufs;
297
807
  length;
298
- [symbol] = true;
808
+ [symbol$1] = true;
299
809
  constructor(...data) {
300
810
  this.bufs = [];
301
811
  this.length = 0;
@@ -751,9 +1261,9 @@ function isAsyncIterable$2(thing) {
751
1261
  }
752
1262
 
753
1263
  const defaultEncoder = (length) => {
754
- const lengthLength = encodingLength(length);
1264
+ const lengthLength = encodingLength$1(length);
755
1265
  const lengthBuf = allocUnsafe(lengthLength);
756
- encode$1(length, lengthBuf);
1266
+ encode$2(length, lengthBuf);
757
1267
  defaultEncoder.bytes = lengthLength;
758
1268
  return lengthBuf;
759
1269
  };
@@ -840,8 +1350,8 @@ var ReadMode;
840
1350
  ReadMode[ReadMode["DATA"] = 1] = "DATA";
841
1351
  })(ReadMode || (ReadMode = {}));
842
1352
  const defaultDecoder = (buf) => {
843
- const length = decode$1(buf);
844
- defaultDecoder.bytes = encodingLength(length);
1353
+ const length = decode$4(buf);
1354
+ defaultDecoder.bytes = encodingLength$1(length);
845
1355
  return length;
846
1356
  };
847
1357
  defaultDecoder.bytes = 0;
@@ -1094,7 +1604,7 @@ class FIFO {
1094
1604
  * // [ [1, 2, 3] ]
1095
1605
  * ```
1096
1606
  */
1097
- let AbortError$1 = class AbortError extends Error {
1607
+ class AbortError extends Error {
1098
1608
  type;
1099
1609
  code;
1100
1610
  constructor(message, code) {
@@ -1102,7 +1612,7 @@ let AbortError$1 = class AbortError extends Error {
1102
1612
  this.type = 'aborted';
1103
1613
  this.code = code ?? 'ABORT_ERR';
1104
1614
  }
1105
- };
1615
+ }
1106
1616
  function pushable(options = {}) {
1107
1617
  const getNext = (buffer) => {
1108
1618
  const next = buffer.shift();
@@ -1222,7 +1732,7 @@ function _pushable(getNext, options) {
1222
1732
  if (signal != null) {
1223
1733
  cancel = new Promise((resolve, reject) => {
1224
1734
  listener = () => {
1225
- reject(new AbortError$1());
1735
+ reject(new AbortError());
1226
1736
  };
1227
1737
  signal.addEventListener('abort', listener);
1228
1738
  });
@@ -1491,7 +2001,7 @@ var native = {
1491
2001
  };
1492
2002
 
1493
2003
  function v4(options, buf, offset) {
1494
- if (native.randomUUID && !buf && !options) {
2004
+ if (native.randomUUID && true && !options) {
1495
2005
  return native.randomUUID();
1496
2006
  }
1497
2007
 
@@ -1611,73 +2121,71 @@ class FilterSubscribeResponse {
1611
2121
  }
1612
2122
  }
1613
2123
 
1614
- const log$6 = new Logger("filter:v2");
2124
+ const log$5 = new Logger("filter:v2");
1615
2125
  const FilterCodecs = {
1616
2126
  SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
1617
2127
  PUSH: "/vac/waku/filter-push/2.0.0-beta1"
1618
2128
  };
1619
2129
  class FilterCore extends BaseProtocol {
1620
2130
  handleIncomingMessage;
1621
- handleError;
1622
2131
  pubsubTopics;
1623
- constructor(handleIncomingMessage, handleError, pubsubTopics, libp2p) {
1624
- super(FilterCodecs.SUBSCRIBE, libp2p.components, log$6, pubsubTopics);
2132
+ constructor(handleIncomingMessage, pubsubTopics, libp2p) {
2133
+ super(FilterCodecs.SUBSCRIBE, libp2p.components, pubsubTopics);
1625
2134
  this.handleIncomingMessage = handleIncomingMessage;
1626
- this.handleError = handleError;
1627
2135
  this.pubsubTopics = pubsubTopics;
1628
2136
  libp2p
1629
2137
  .handle(FilterCodecs.PUSH, this.onRequest.bind(this), {
1630
2138
  maxInboundStreams: 100
1631
2139
  })
1632
2140
  .catch((e) => {
1633
- log$6.error("Failed to register ", FilterCodecs.PUSH, e);
2141
+ log$5.error("Failed to register ", FilterCodecs.PUSH, e);
1634
2142
  });
1635
2143
  }
1636
- async subscribe(pubsubTopic, peer, contentTopics) {
1637
- const stream = await this.getStream(peer);
2144
+ async subscribe(pubsubTopic, peerId, contentTopics) {
2145
+ const stream = await this.getStream(peerId);
1638
2146
  const request = FilterSubscribeRpc.createSubscribeRequest(pubsubTopic, contentTopics);
1639
2147
  let res;
1640
2148
  try {
1641
2149
  res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
1642
2150
  }
1643
2151
  catch (error) {
1644
- log$6.error("Failed to send subscribe request", error);
2152
+ log$5.error("Failed to send subscribe request", error);
1645
2153
  return {
1646
2154
  success: null,
1647
2155
  failure: {
1648
2156
  error: ProtocolError.GENERIC_FAIL,
1649
- peerId: peer.id
2157
+ peerId: peerId
1650
2158
  }
1651
2159
  };
1652
2160
  }
1653
2161
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
1654
2162
  if (statusCode < 200 || statusCode >= 300) {
1655
- log$6.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2163
+ log$5.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
1656
2164
  return {
1657
2165
  failure: {
1658
2166
  error: ProtocolError.REMOTE_PEER_REJECTED,
1659
- peerId: peer.id
2167
+ peerId: peerId
1660
2168
  },
1661
2169
  success: null
1662
2170
  };
1663
2171
  }
1664
2172
  return {
1665
2173
  failure: null,
1666
- success: peer.id
2174
+ success: peerId
1667
2175
  };
1668
2176
  }
1669
- async unsubscribe(pubsubTopic, peer, contentTopics) {
2177
+ async unsubscribe(pubsubTopic, peerId, contentTopics) {
1670
2178
  let stream;
1671
2179
  try {
1672
- stream = await this.getStream(peer);
2180
+ stream = await this.getStream(peerId);
1673
2181
  }
1674
2182
  catch (error) {
1675
- log$6.error(`Failed to get a stream for remote peer${peer.id.toString()}`, error);
2183
+ log$5.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
1676
2184
  return {
1677
2185
  success: null,
1678
2186
  failure: {
1679
2187
  error: ProtocolError.NO_STREAM_AVAILABLE,
1680
- peerId: peer.id
2188
+ peerId: peerId
1681
2189
  }
1682
2190
  };
1683
2191
  }
@@ -1686,61 +2194,61 @@ class FilterCore extends BaseProtocol {
1686
2194
  await pipe([unsubscribeRequest.encode()], encode, stream.sink);
1687
2195
  }
1688
2196
  catch (error) {
1689
- log$6.error("Failed to send unsubscribe request", error);
2197
+ log$5.error("Failed to send unsubscribe request", error);
1690
2198
  return {
1691
2199
  success: null,
1692
2200
  failure: {
1693
2201
  error: ProtocolError.GENERIC_FAIL,
1694
- peerId: peer.id
2202
+ peerId: peerId
1695
2203
  }
1696
2204
  };
1697
2205
  }
1698
2206
  return {
1699
- success: peer.id,
2207
+ success: peerId,
1700
2208
  failure: null
1701
2209
  };
1702
2210
  }
1703
- async unsubscribeAll(pubsubTopic, peer) {
1704
- const stream = await this.getStream(peer);
2211
+ async unsubscribeAll(pubsubTopic, peerId) {
2212
+ const stream = await this.getStream(peerId);
1705
2213
  const request = FilterSubscribeRpc.createUnsubscribeAllRequest(pubsubTopic);
1706
2214
  const res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
1707
2215
  if (!res || !res.length) {
1708
2216
  return {
1709
2217
  failure: {
1710
2218
  error: ProtocolError.NO_RESPONSE,
1711
- peerId: peer.id
2219
+ peerId: peerId
1712
2220
  },
1713
2221
  success: null
1714
2222
  };
1715
2223
  }
1716
2224
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
1717
2225
  if (statusCode < 200 || statusCode >= 300) {
1718
- log$6.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2226
+ log$5.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
1719
2227
  return {
1720
2228
  failure: {
1721
2229
  error: ProtocolError.REMOTE_PEER_REJECTED,
1722
- peerId: peer.id
2230
+ peerId: peerId
1723
2231
  },
1724
2232
  success: null
1725
2233
  };
1726
2234
  }
1727
2235
  return {
1728
2236
  failure: null,
1729
- success: peer.id
2237
+ success: peerId
1730
2238
  };
1731
2239
  }
1732
- async ping(peer) {
2240
+ async ping(peerId) {
1733
2241
  let stream;
1734
2242
  try {
1735
- stream = await this.getStream(peer);
2243
+ stream = await this.getStream(peerId);
1736
2244
  }
1737
2245
  catch (error) {
1738
- log$6.error(`Failed to get a stream for remote peer${peer.id.toString()}`, error);
2246
+ log$5.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
1739
2247
  return {
1740
2248
  success: null,
1741
2249
  failure: {
1742
2250
  error: ProtocolError.NO_STREAM_AVAILABLE,
1743
- peerId: peer.id
2251
+ peerId: peerId
1744
2252
  }
1745
2253
  };
1746
2254
  }
@@ -1750,12 +2258,12 @@ class FilterCore extends BaseProtocol {
1750
2258
  res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
1751
2259
  }
1752
2260
  catch (error) {
1753
- log$6.error("Failed to send ping request", error);
2261
+ log$5.error("Failed to send ping request", error);
1754
2262
  return {
1755
2263
  success: null,
1756
2264
  failure: {
1757
2265
  error: ProtocolError.GENERIC_FAIL,
1758
- peerId: peer.id
2266
+ peerId: peerId
1759
2267
  }
1760
2268
  };
1761
2269
  }
@@ -1764,54 +2272,53 @@ class FilterCore extends BaseProtocol {
1764
2272
  success: null,
1765
2273
  failure: {
1766
2274
  error: ProtocolError.NO_RESPONSE,
1767
- peerId: peer.id
2275
+ peerId: peerId
1768
2276
  }
1769
2277
  };
1770
2278
  }
1771
2279
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
1772
2280
  if (statusCode < 200 || statusCode >= 300) {
1773
- log$6.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2281
+ log$5.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
1774
2282
  return {
1775
2283
  success: null,
1776
2284
  failure: {
1777
2285
  error: ProtocolError.REMOTE_PEER_REJECTED,
1778
- peerId: peer.id
2286
+ peerId: peerId
1779
2287
  }
1780
2288
  };
1781
2289
  }
1782
2290
  return {
1783
- success: peer.id,
2291
+ success: peerId,
1784
2292
  failure: null
1785
2293
  };
1786
2294
  }
1787
2295
  onRequest(streamData) {
1788
2296
  const { connection, stream } = streamData;
1789
2297
  const { remotePeer } = connection;
1790
- log$6.info(`Received message from ${remotePeer.toString()}`);
2298
+ log$5.info(`Received message from ${remotePeer.toString()}`);
1791
2299
  try {
1792
2300
  pipe(stream, decode, async (source) => {
1793
2301
  for await (const bytes of source) {
1794
2302
  const response = FilterPushRpc.decode(bytes.slice());
1795
2303
  const { pubsubTopic, wakuMessage } = response;
1796
2304
  if (!wakuMessage) {
1797
- log$6.error("Received empty message");
2305
+ log$5.error("Received empty message");
1798
2306
  return;
1799
2307
  }
1800
2308
  if (!pubsubTopic) {
1801
- log$6.error("Pubsub topic missing from push message");
2309
+ log$5.error("Pubsub topic missing from push message");
1802
2310
  return;
1803
2311
  }
1804
2312
  await this.handleIncomingMessage(pubsubTopic, wakuMessage, connection.remotePeer.toString());
1805
2313
  }
1806
2314
  }).then(() => {
1807
- log$6.info("Receiving pipe closed.");
2315
+ log$5.info("Receiving pipe closed.");
1808
2316
  }, async (e) => {
1809
- log$6.error("Error with receiving pipe", e, " -- ", "on peer ", connection.remotePeer.toString(), " -- ", "stream ", stream);
1810
- await this.handleError(e);
2317
+ log$5.error(`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `, e);
1811
2318
  });
1812
2319
  }
1813
2320
  catch (e) {
1814
- log$6.error("Error decoding message", e);
2321
+ log$5.error("Error decoding message", e);
1815
2322
  }
1816
2323
  }
1817
2324
  }
@@ -1856,28 +2363,21 @@ class PushRpc {
1856
2363
  // https://github.com/waku-org/nwaku/blob/c3cb06ac6c03f0f382d3941ea53b330f6a8dd127/waku/waku_rln_relay/rln_relay.nim#L309
1857
2364
  // https://github.com/waku-org/nwaku/blob/c3cb06ac6c03f0f382d3941ea53b330f6a8dd127/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim#L20
1858
2365
  const RLN_GENERATION_PREFIX_ERROR = "could not generate rln-v2 proof";
2366
+ const RLN_MESSAGE_ID_PREFIX_ERROR = "could not get new message id to generate an rln proof";
2367
+ // rare case on nwaku side
2368
+ // https://github.com/waku-org/nwaku/blob/a4e92a3d02448fd708857b7b6cac2a7faa7eb4f9/waku/waku_lightpush/callbacks.nim#L49
2369
+ // https://github.com/waku-org/nwaku/blob/a4e92a3d02448fd708857b7b6cac2a7faa7eb4f9/waku/node/waku_node.nim#L1117
2370
+ const RLN_REMOTE_VALIDATION = "RLN validation failed";
1859
2371
  const isRLNResponseError = (info) => {
1860
2372
  if (!info) {
1861
2373
  return false;
1862
2374
  }
1863
- return info.includes(RLN_GENERATION_PREFIX_ERROR);
1864
- };
1865
- const matchRLNErrorMessage = (info) => {
1866
- const rlnErrorMap = {
1867
- [ProtocolError.RLN_IDENTITY_MISSING]: ProtocolError.RLN_IDENTITY_MISSING,
1868
- [ProtocolError.RLN_MEMBERSHIP_INDEX]: ProtocolError.RLN_MEMBERSHIP_INDEX,
1869
- [ProtocolError.RLN_LIMIT_MISSING]: ProtocolError.RLN_LIMIT_MISSING
1870
- };
1871
- const infoLowerCase = info.toLowerCase();
1872
- for (const errorKey in rlnErrorMap) {
1873
- if (infoLowerCase.includes(errorKey.toLowerCase())) {
1874
- return rlnErrorMap[errorKey];
1875
- }
1876
- }
1877
- return ProtocolError.RLN_PROOF_GENERATION;
2375
+ return (info.includes(RLN_GENERATION_PREFIX_ERROR) ||
2376
+ info.includes(RLN_MESSAGE_ID_PREFIX_ERROR) ||
2377
+ info.includes(RLN_REMOTE_VALIDATION));
1878
2378
  };
1879
2379
 
1880
- const log$5 = new Logger("light-push");
2380
+ const log$4 = new Logger("light-push");
1881
2381
  const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
1882
2382
  /**
1883
2383
  * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
@@ -1885,22 +2385,22 @@ const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
1885
2385
  class LightPushCore extends BaseProtocol {
1886
2386
  pubsubTopics;
1887
2387
  constructor(pubsubTopics, libp2p) {
1888
- super(LightPushCodec, libp2p.components, log$5, pubsubTopics);
2388
+ super(LightPushCodec, libp2p.components, pubsubTopics);
1889
2389
  this.pubsubTopics = pubsubTopics;
1890
2390
  }
1891
2391
  async preparePushMessage(encoder, message) {
1892
2392
  try {
1893
2393
  if (!message.payload || message.payload.length === 0) {
1894
- log$5.error("Failed to send waku light push: payload is empty");
2394
+ log$4.error("Failed to send waku light push: payload is empty");
1895
2395
  return { query: null, error: ProtocolError.EMPTY_PAYLOAD };
1896
2396
  }
1897
2397
  if (!(await isMessageSizeUnderCap(encoder, message))) {
1898
- log$5.error("Failed to send waku light push: message is bigger than 1MB");
2398
+ log$4.error("Failed to send waku light push: message is bigger than 1MB");
1899
2399
  return { query: null, error: ProtocolError.SIZE_TOO_BIG };
1900
2400
  }
1901
2401
  const protoMessage = await encoder.toProtoObj(message);
1902
2402
  if (!protoMessage) {
1903
- log$5.error("Failed to encode to protoMessage, aborting push");
2403
+ log$4.error("Failed to encode to protoMessage, aborting push");
1904
2404
  return {
1905
2405
  query: null,
1906
2406
  error: ProtocolError.ENCODE_FAILED
@@ -1910,35 +2410,35 @@ class LightPushCore extends BaseProtocol {
1910
2410
  return { query, error: null };
1911
2411
  }
1912
2412
  catch (error) {
1913
- log$5.error("Failed to prepare push message", error);
2413
+ log$4.error("Failed to prepare push message", error);
1914
2414
  return {
1915
2415
  query: null,
1916
2416
  error: ProtocolError.GENERIC_FAIL
1917
2417
  };
1918
2418
  }
1919
2419
  }
1920
- async send(encoder, message, peer) {
2420
+ async send(encoder, message, peerId) {
1921
2421
  const { query, error: preparationError } = await this.preparePushMessage(encoder, message);
1922
2422
  if (preparationError || !query) {
1923
2423
  return {
1924
2424
  success: null,
1925
2425
  failure: {
1926
2426
  error: preparationError,
1927
- peerId: peer.id
2427
+ peerId
1928
2428
  }
1929
2429
  };
1930
2430
  }
1931
2431
  let stream;
1932
2432
  try {
1933
- stream = await this.getStream(peer);
2433
+ stream = await this.getStream(peerId);
1934
2434
  }
1935
2435
  catch (error) {
1936
- log$5.error("Failed to get stream", error);
2436
+ log$4.error("Failed to get stream", error);
1937
2437
  return {
1938
2438
  success: null,
1939
2439
  failure: {
1940
2440
  error: ProtocolError.NO_STREAM_AVAILABLE,
1941
- peerId: peer.id
2441
+ peerId: peerId
1942
2442
  }
1943
2443
  };
1944
2444
  }
@@ -1947,12 +2447,13 @@ class LightPushCore extends BaseProtocol {
1947
2447
  res = await pipe([query.encode()], encode, stream, decode, async (source) => await all(source));
1948
2448
  }
1949
2449
  catch (err) {
1950
- log$5.error("Failed to send waku light push request", err);
2450
+ // can fail only because of `stream` abortion
2451
+ log$4.error("Failed to send waku light push request", err);
1951
2452
  return {
1952
2453
  success: null,
1953
2454
  failure: {
1954
- error: ProtocolError.GENERIC_FAIL,
1955
- peerId: peer.id
2455
+ error: ProtocolError.STREAM_ABORTED,
2456
+ peerId: peerId
1956
2457
  }
1957
2458
  };
1958
2459
  }
@@ -1965,47 +2466,46 @@ class LightPushCore extends BaseProtocol {
1965
2466
  response = PushRpc.decode(bytes).response;
1966
2467
  }
1967
2468
  catch (err) {
1968
- log$5.error("Failed to decode push reply", err);
2469
+ log$4.error("Failed to decode push reply", err);
1969
2470
  return {
1970
2471
  success: null,
1971
2472
  failure: {
1972
2473
  error: ProtocolError.DECODE_FAILED,
1973
- peerId: peer.id
2474
+ peerId: peerId
1974
2475
  }
1975
2476
  };
1976
2477
  }
1977
2478
  if (!response) {
1978
- log$5.error("Remote peer fault: No response in PushRPC");
2479
+ log$4.error("Remote peer fault: No response in PushRPC");
1979
2480
  return {
1980
2481
  success: null,
1981
2482
  failure: {
1982
2483
  error: ProtocolError.NO_RESPONSE,
1983
- peerId: peer.id
2484
+ peerId: peerId
1984
2485
  }
1985
2486
  };
1986
2487
  }
1987
2488
  if (isRLNResponseError(response.info)) {
1988
- const rlnErrorCase = matchRLNErrorMessage(response.info);
1989
- log$5.error("Remote peer rejected the message: ", rlnErrorCase);
2489
+ log$4.error("Remote peer fault: RLN generation");
1990
2490
  return {
1991
2491
  success: null,
1992
2492
  failure: {
1993
- error: rlnErrorCase,
1994
- peerId: peer.id
2493
+ error: ProtocolError.RLN_PROOF_GENERATION,
2494
+ peerId: peerId
1995
2495
  }
1996
2496
  };
1997
2497
  }
1998
2498
  if (!response.isSuccess) {
1999
- log$5.error("Remote peer rejected the message: ", response.info);
2499
+ log$4.error("Remote peer rejected the message: ", response.info);
2000
2500
  return {
2001
2501
  success: null,
2002
2502
  failure: {
2003
2503
  error: ProtocolError.REMOTE_PEER_REJECTED,
2004
- peerId: peer.id
2504
+ peerId: peerId
2005
2505
  }
2006
2506
  };
2007
2507
  }
2008
- return { success: peer.id, failure: null };
2508
+ return { success: peerId, failure: null };
2009
2509
  }
2010
2510
  }
2011
2511
 
@@ -2101,15 +2601,15 @@ class StoreQueryResponse {
2101
2601
  }
2102
2602
  }
2103
2603
 
2104
- const log$4 = new Logger("store");
2604
+ const log$3 = new Logger("store");
2105
2605
  const StoreCodec = "/vac/waku/store-query/3.0.0";
2106
2606
  class StoreCore extends BaseProtocol {
2107
2607
  pubsubTopics;
2108
2608
  constructor(pubsubTopics, libp2p) {
2109
- super(StoreCodec, libp2p.components, log$4, pubsubTopics);
2609
+ super(StoreCodec, libp2p.components, pubsubTopics);
2110
2610
  this.pubsubTopics = pubsubTopics;
2111
2611
  }
2112
- async *queryPerPage(queryOpts, decoders, peer) {
2612
+ async *queryPerPage(queryOpts, decoders, peerId) {
2113
2613
  if (queryOpts.contentTopics.toString() !==
2114
2614
  Array.from(decoders.keys()).toString()) {
2115
2615
  throw new Error("Internal error, the decoders should match the query's content topics");
@@ -2122,10 +2622,10 @@ class StoreCore extends BaseProtocol {
2122
2622
  });
2123
2623
  let stream;
2124
2624
  try {
2125
- stream = await this.getStream(peer);
2625
+ stream = await this.getStream(peerId);
2126
2626
  }
2127
2627
  catch (e) {
2128
- log$4.error("Failed to get stream", e);
2628
+ log$3.error("Failed to get stream", e);
2129
2629
  break;
2130
2630
  }
2131
2631
  const res = await pipe([storeQueryRequest.encode()], encode, stream, decode, async (source) => await all(source));
@@ -2137,14 +2637,14 @@ class StoreCore extends BaseProtocol {
2137
2637
  if (!storeQueryResponse.statusCode ||
2138
2638
  storeQueryResponse.statusCode >= 300) {
2139
2639
  const errorMessage = `Store query failed with status code: ${storeQueryResponse.statusCode}, description: ${storeQueryResponse.statusDesc}`;
2140
- log$4.error(errorMessage);
2640
+ log$3.error(errorMessage);
2141
2641
  throw new Error(errorMessage);
2142
2642
  }
2143
2643
  if (!storeQueryResponse.messages || !storeQueryResponse.messages.length) {
2144
- log$4.warn("Stopping pagination due to empty messages in response");
2644
+ log$3.warn("Stopping pagination due to empty messages in response");
2145
2645
  break;
2146
2646
  }
2147
- log$4.info(`${storeQueryResponse.messages.length} messages retrieved from store`);
2647
+ log$3.info(`${storeQueryResponse.messages.length} messages retrieved from store`);
2148
2648
  const decodedMessages = storeQueryResponse.messages.map((protoMsg) => {
2149
2649
  if (!protoMsg.message) {
2150
2650
  return Promise.resolve(undefined);
@@ -2182,381 +2682,26 @@ var index = /*#__PURE__*/Object.freeze({
2182
2682
  StoreCore: StoreCore
2183
2683
  });
2184
2684
 
2185
- class TimeoutError extends Error {
2186
- constructor(message) {
2187
- super(message);
2188
- this.name = 'TimeoutError';
2189
- }
2190
- }
2191
-
2192
- /**
2193
- An error to be thrown when the request is aborted by AbortController.
2194
- DOMException is thrown instead of this Error when DOMException is available.
2195
- */
2196
- class AbortError extends Error {
2197
- constructor(message) {
2198
- super();
2199
- this.name = 'AbortError';
2200
- this.message = message;
2201
- }
2202
- }
2203
-
2204
- /**
2205
- TODO: Remove AbortError and just throw DOMException when targeting Node 18.
2206
- */
2207
- const getDOMException = errorMessage => globalThis.DOMException === undefined
2208
- ? new AbortError(errorMessage)
2209
- : new DOMException(errorMessage);
2210
-
2211
- /**
2212
- TODO: Remove below function and just 'reject(signal.reason)' when targeting Node 18.
2213
- */
2214
- const getAbortedReason = signal => {
2215
- const reason = signal.reason === undefined
2216
- ? getDOMException('This operation was aborted.')
2217
- : signal.reason;
2218
-
2219
- return reason instanceof Error ? reason : getDOMException(reason);
2220
- };
2221
-
2222
- function pTimeout(promise, options) {
2223
- const {
2224
- milliseconds,
2225
- fallback,
2226
- message,
2227
- customTimers = {setTimeout, clearTimeout},
2228
- } = options;
2229
-
2230
- let timer;
2231
-
2232
- const wrappedPromise = new Promise((resolve, reject) => {
2233
- if (typeof milliseconds !== 'number' || Math.sign(milliseconds) !== 1) {
2234
- throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
2235
- }
2236
-
2237
- if (options.signal) {
2238
- const {signal} = options;
2239
- if (signal.aborted) {
2240
- reject(getAbortedReason(signal));
2241
- }
2242
-
2243
- signal.addEventListener('abort', () => {
2244
- reject(getAbortedReason(signal));
2245
- });
2246
- }
2247
-
2248
- if (milliseconds === Number.POSITIVE_INFINITY) {
2249
- promise.then(resolve, reject);
2250
- return;
2251
- }
2252
-
2253
- // We create the error outside of `setTimeout` to preserve the stack trace.
2254
- const timeoutError = new TimeoutError();
2255
-
2256
- timer = customTimers.setTimeout.call(undefined, () => {
2257
- if (fallback) {
2258
- try {
2259
- resolve(fallback());
2260
- } catch (error) {
2261
- reject(error);
2262
- }
2263
-
2264
- return;
2265
- }
2266
-
2267
- if (typeof promise.cancel === 'function') {
2268
- promise.cancel();
2269
- }
2270
-
2271
- if (message === false) {
2272
- resolve();
2273
- } else if (message instanceof Error) {
2274
- reject(message);
2275
- } else {
2276
- timeoutError.message = message ?? `Promise timed out after ${milliseconds} milliseconds`;
2277
- reject(timeoutError);
2278
- }
2279
- }, milliseconds);
2280
-
2281
- (async () => {
2282
- try {
2283
- resolve(await promise);
2284
- } catch (error) {
2285
- reject(error);
2286
- }
2287
- })();
2288
- });
2289
-
2290
- const cancelablePromise = wrappedPromise.finally(() => {
2291
- cancelablePromise.clear();
2292
- });
2293
-
2294
- cancelablePromise.clear = () => {
2295
- customTimers.clearTimeout.call(undefined, timer);
2296
- timer = undefined;
2297
- };
2298
-
2299
- return cancelablePromise;
2300
- }
2301
-
2302
- const normalizeEmitter = emitter => {
2303
- const addListener = emitter.addEventListener || emitter.on || emitter.addListener;
2304
- const removeListener = emitter.removeEventListener || emitter.off || emitter.removeListener;
2305
-
2306
- if (!addListener || !removeListener) {
2307
- throw new TypeError('Emitter is not compatible');
2308
- }
2309
-
2310
- return {
2311
- addListener: addListener.bind(emitter),
2312
- removeListener: removeListener.bind(emitter),
2313
- };
2314
- };
2315
-
2316
- function pEventMultiple(emitter, event, options) {
2317
- let cancel;
2318
- const returnValue = new Promise((resolve, reject) => {
2319
- options = {
2320
- rejectionEvents: ['error'],
2321
- multiArgs: false,
2322
- resolveImmediately: false,
2323
- ...options,
2324
- };
2325
-
2326
- if (!(options.count >= 0 && (options.count === Number.POSITIVE_INFINITY || Number.isInteger(options.count)))) {
2327
- throw new TypeError('The `count` option should be at least 0 or more');
2328
- }
2329
-
2330
- options.signal?.throwIfAborted();
2331
-
2332
- // Allow multiple events
2333
- const events = [event].flat();
2334
-
2335
- const items = [];
2336
- const {addListener, removeListener} = normalizeEmitter(emitter);
2337
-
2338
- const onItem = (...arguments_) => {
2339
- const value = options.multiArgs ? arguments_ : arguments_[0];
2340
-
2341
- // eslint-disable-next-line unicorn/no-array-callback-reference
2342
- if (options.filter && !options.filter(value)) {
2343
- return;
2344
- }
2345
-
2346
- items.push(value);
2347
-
2348
- if (options.count === items.length) {
2349
- cancel();
2350
- resolve(items);
2351
- }
2352
- };
2353
-
2354
- const rejectHandler = error => {
2355
- cancel();
2356
- reject(error);
2357
- };
2358
-
2359
- cancel = () => {
2360
- for (const event of events) {
2361
- removeListener(event, onItem);
2362
- }
2363
-
2364
- for (const rejectionEvent of options.rejectionEvents) {
2365
- removeListener(rejectionEvent, rejectHandler);
2366
- }
2367
- };
2368
-
2369
- for (const event of events) {
2370
- addListener(event, onItem);
2371
- }
2372
-
2373
- for (const rejectionEvent of options.rejectionEvents) {
2374
- addListener(rejectionEvent, rejectHandler);
2375
- }
2376
-
2377
- if (options.signal) {
2378
- options.signal.addEventListener('abort', () => {
2379
- rejectHandler(options.signal.reason);
2380
- }, {once: true});
2381
- }
2382
-
2383
- if (options.resolveImmediately) {
2384
- resolve(items);
2385
- }
2386
- });
2387
-
2388
- returnValue.cancel = cancel;
2389
-
2390
- if (typeof options.timeout === 'number') {
2391
- const timeout = pTimeout(returnValue, {milliseconds: options.timeout});
2392
- timeout.cancel = cancel;
2393
- return timeout;
2394
- }
2395
-
2396
- return returnValue;
2397
- }
2398
-
2399
- function pEvent(emitter, event, options) {
2400
- if (typeof options === 'function') {
2401
- options = {filter: options};
2402
- }
2403
-
2404
- options = {
2405
- ...options,
2406
- count: 1,
2407
- resolveImmediately: false,
2408
- };
2409
-
2410
- const arrayPromise = pEventMultiple(emitter, event, options);
2411
- const promise = arrayPromise.then(array => array[0]);
2412
- promise.cancel = arrayPromise.cancel;
2413
-
2414
- return promise;
2415
- }
2416
-
2417
- const log$3 = new Logger("wait-for-remote-peer");
2418
- //TODO: move this function within the Waku class: https://github.com/waku-org/js-waku/issues/1761
2419
2685
  /**
2420
- * Wait for a remote peer to be ready given the passed protocols.
2421
- * Must be used after attempting to connect to nodes, using
2422
- * {@link @waku/sdk!WakuNode.dial} or a bootstrap method with
2423
- * {@link @waku/sdk!createLightNode}.
2424
- *
2425
- * If the passed protocols is a GossipSub protocol, then it resolves only once
2426
- * a peer is in a mesh, to help ensure that other peers will send and receive
2427
- * message to us.
2428
- *
2429
- * @param waku The Waku Node
2430
- * @param protocols The protocols that need to be enabled by remote peers.
2431
- * @param timeoutMs A timeout value in milliseconds..
2432
- *
2433
- * @returns A promise that **resolves** if all desired protocols are fulfilled by
2434
- * remote nodes, **rejects** if the timeoutMs is reached.
2435
- * @throws If passing a protocol that is not mounted
2436
- * @default Wait for remote peers with protocols enabled locally and no time out is applied.
2686
+ * All PeerId implementations must use this symbol as the name of a property
2687
+ * with a boolean `true` value
2437
2688
  */
2438
- async function waitForRemotePeer(waku, protocols, timeoutMs) {
2439
- protocols = protocols ?? getEnabledProtocols(waku);
2440
- if (!waku.isStarted())
2441
- return Promise.reject("Waku node is not started");
2442
- const promises = [];
2443
- if (protocols.includes(Protocols.Relay)) {
2444
- if (!waku.relay)
2445
- throw new Error("Cannot wait for Relay peer: protocol not mounted");
2446
- promises.push(waitForGossipSubPeerInMesh(waku.relay));
2447
- }
2448
- if (protocols.includes(Protocols.Store)) {
2449
- if (!waku.store)
2450
- throw new Error("Cannot wait for Store peer: protocol not mounted");
2451
- promises.push(waitForConnectedPeer(waku.store.protocol, waku.libp2p.services.metadata));
2452
- }
2453
- if (protocols.includes(Protocols.LightPush)) {
2454
- if (!waku.lightPush)
2455
- throw new Error("Cannot wait for LightPush peer: protocol not mounted");
2456
- promises.push(waitForConnectedPeer(waku.lightPush.protocol, waku.libp2p.services.metadata));
2457
- }
2458
- if (protocols.includes(Protocols.Filter)) {
2459
- if (!waku.filter)
2460
- throw new Error("Cannot wait for Filter peer: protocol not mounted");
2461
- promises.push(waitForConnectedPeer(waku.filter.protocol, waku.libp2p.services.metadata));
2462
- }
2463
- if (timeoutMs) {
2464
- await rejectOnTimeout(Promise.all(promises), timeoutMs, "Timed out waiting for a remote peer.");
2465
- }
2466
- else {
2467
- await Promise.all(promises);
2468
- }
2469
- }
2470
- //TODO: move this function within protocol SDK class: https://github.com/waku-org/js-waku/issues/1761
2689
+ const peerIdSymbol = Symbol.for('@libp2p/peer-id');
2471
2690
  /**
2472
- * Wait for a peer with the given protocol to be connected.
2473
- * If sharding is enabled on the node, it will also wait for the peer to be confirmed by the metadata service.
2691
+ * Returns true if the passed argument is a PeerId implementation
2474
2692
  */
2475
- async function waitForConnectedPeer(protocol, metadataService) {
2476
- const codec = protocol.multicodec;
2477
- const peers = await protocol.connectedPeers();
2478
- if (peers.length) {
2479
- if (!metadataService) {
2480
- log$3.info(`${codec} peer found: `, peers[0].id.toString());
2481
- return;
2482
- }
2483
- // once a peer is connected, we need to confirm the metadata handshake with at least one of those peers if sharding is enabled
2484
- try {
2485
- await Promise.any(peers.map((peer) => metadataService.confirmOrAttemptHandshake(peer.id)));
2486
- return;
2487
- }
2488
- catch (e) {
2489
- if (e.code === "ERR_CONNECTION_BEING_CLOSED")
2490
- log$3.error(`Connection with the peer was closed and possibly because it's on a different shard. Error: ${e}`);
2491
- log$3.error(`Error waiting for handshake confirmation: ${e}`);
2492
- }
2493
- }
2494
- log$3.info(`Waiting for ${codec} peer`);
2495
- // else we'll just wait for the next peer to connect
2496
- await new Promise((resolve) => {
2497
- const cb = (evt) => {
2498
- if (evt.detail?.protocols?.includes(codec)) {
2499
- if (metadataService) {
2500
- metadataService
2501
- .confirmOrAttemptHandshake(evt.detail.peerId)
2502
- .then(() => {
2503
- protocol.removeLibp2pEventListener("peer:identify", cb);
2504
- resolve();
2505
- })
2506
- .catch((e) => {
2507
- if (e.code === "ERR_CONNECTION_BEING_CLOSED")
2508
- log$3.error(`Connection with the peer was closed and possibly because it's on a different shard. Error: ${e}`);
2509
- log$3.error(`Error waiting for handshake confirmation: ${e}`);
2510
- });
2511
- }
2512
- else {
2513
- protocol.removeLibp2pEventListener("peer:identify", cb);
2514
- resolve();
2515
- }
2516
- }
2517
- };
2518
- protocol.addLibp2pEventListener("peer:identify", cb);
2519
- });
2693
+ function isPeerId(other) {
2694
+ return Boolean(other?.[peerIdSymbol]);
2520
2695
  }
2696
+
2521
2697
  /**
2522
- * Wait for at least one peer with the given protocol to be connected and in the gossipsub
2523
- * mesh for all pubsubTopics.
2698
+ * Noop for browser compatibility
2524
2699
  */
2525
- async function waitForGossipSubPeerInMesh(waku) {
2526
- let peers = waku.getMeshPeers();
2527
- const pubsubTopics = waku.pubsubTopics;
2528
- for (const topic of pubsubTopics) {
2529
- while (peers.length == 0) {
2530
- await pEvent(waku.gossipSub, "gossipsub:heartbeat");
2531
- peers = waku.getMeshPeers(topic);
2532
- }
2533
- }
2534
- }
2535
- const awaitTimeout = (ms, rejectReason) => new Promise((_resolve, reject) => setTimeout(() => reject(rejectReason), ms));
2536
- async function rejectOnTimeout(promise, timeoutMs, rejectReason) {
2537
- await Promise.race([promise, awaitTimeout(timeoutMs, rejectReason)]);
2538
- }
2539
- function getEnabledProtocols(waku) {
2540
- const protocols = [];
2541
- if (waku.relay) {
2542
- protocols.push(Protocols.Relay);
2543
- }
2544
- if (waku.filter) {
2545
- protocols.push(Protocols.Filter);
2546
- }
2547
- if (waku.store) {
2548
- protocols.push(Protocols.Store);
2549
- }
2550
- if (waku.lightPush) {
2551
- protocols.push(Protocols.LightPush);
2552
- }
2553
- return protocols;
2554
- }
2555
-
2556
- /** Noop for browser compatibility */
2557
2700
  function setMaxListeners$1() { }
2558
2701
 
2559
- // create a setMaxListeners that doesn't break browser usage
2702
+ /**
2703
+ * Create a setMaxListeners that doesn't break browser usage
2704
+ */
2560
2705
  const setMaxListeners = (n, ...eventTargets) => {
2561
2706
  try {
2562
2707
  setMaxListeners$1(n, ...eventTargets);
@@ -2620,52 +2765,1199 @@ class TypedEventEmitter extends EventTarget {
2620
2765
  return this.dispatchEvent(new CustomEvent(type, detail));
2621
2766
  }
2622
2767
  }
2623
- const CustomEvent = globalThis.CustomEvent;
2624
2768
 
2625
- const RelayPingContentTopic = "/relay-ping/1/ping/null";
2626
- const log$2 = new Logger("keep-alive");
2627
- class KeepAliveManager {
2628
- relay;
2629
- libp2p;
2630
- options;
2631
- pingKeepAliveTimers = new Map();
2632
- relayKeepAliveTimers = new Map();
2633
- constructor({ options, relay, libp2p }) {
2634
- this.options = options;
2635
- this.relay = relay;
2636
- this.libp2p = libp2p;
2769
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
2770
+ class Parser {
2771
+ index = 0;
2772
+ input = "";
2773
+ new(input) {
2774
+ this.index = 0;
2775
+ this.input = input;
2776
+ return this;
2777
+ }
2778
+ /** Run a parser, and restore the pre-parse state if it fails. */
2779
+ readAtomically(fn) {
2780
+ const index = this.index;
2781
+ const result = fn();
2782
+ if (result === undefined) {
2783
+ this.index = index;
2784
+ }
2785
+ return result;
2637
2786
  }
2638
- start(peerId) {
2639
- // Just in case a timer already exists for this peer
2640
- this.stop(peerId);
2641
- const { pingKeepAlive: pingPeriodSecs, relayKeepAlive: relayPeriodSecs } = this.options;
2642
- const peerIdStr = peerId.toString();
2643
- // Ping the peer every pingPeriodSecs seconds
2644
- // if pingPeriodSecs is 0, don't ping the peer
2645
- if (pingPeriodSecs !== 0) {
2646
- const interval = setInterval(() => {
2647
- void (async () => {
2648
- let ping;
2649
- try {
2650
- // ping the peer for keep alive
2651
- // also update the peer store with the latency
2652
- try {
2653
- ping = await this.libp2p.services.ping.ping(peerId);
2654
- log$2.info(`Ping succeeded (${peerIdStr})`, ping);
2655
- }
2656
- catch (error) {
2657
- log$2.error(`Ping failed for peer (${peerIdStr}).
2658
- Next ping will be attempted in ${pingPeriodSecs} seconds.
2659
- `);
2660
- return;
2661
- }
2662
- try {
2663
- await this.libp2p.peerStore.merge(peerId, {
2664
- metadata: {
2665
- ping: utf8ToBytes(ping.toString())
2666
- }
2667
- });
2668
- }
2787
+ /** Run a parser, but fail if the entire input wasn't consumed. Doesn't run atomically. */
2788
+ parseWith(fn) {
2789
+ const result = fn();
2790
+ if (this.index !== this.input.length) {
2791
+ return undefined;
2792
+ }
2793
+ return result;
2794
+ }
2795
+ /** Peek the next character from the input */
2796
+ peekChar() {
2797
+ if (this.index >= this.input.length) {
2798
+ return undefined;
2799
+ }
2800
+ return this.input[this.index];
2801
+ }
2802
+ /** Read the next character from the input */
2803
+ readChar() {
2804
+ if (this.index >= this.input.length) {
2805
+ return undefined;
2806
+ }
2807
+ return this.input[this.index++];
2808
+ }
2809
+ /** Read the next character from the input if it matches the target. */
2810
+ readGivenChar(target) {
2811
+ return this.readAtomically(() => {
2812
+ const char = this.readChar();
2813
+ if (char !== target) {
2814
+ return undefined;
2815
+ }
2816
+ return char;
2817
+ });
2818
+ }
2819
+ /**
2820
+ * Helper for reading separators in an indexed loop. Reads the separator
2821
+ * character iff index > 0, then runs the parser. When used in a loop,
2822
+ * the separator character will only be read on index > 0 (see
2823
+ * readIPv4Addr for an example)
2824
+ */
2825
+ readSeparator(sep, index, inner) {
2826
+ return this.readAtomically(() => {
2827
+ if (index > 0) {
2828
+ if (this.readGivenChar(sep) === undefined) {
2829
+ return undefined;
2830
+ }
2831
+ }
2832
+ return inner();
2833
+ });
2834
+ }
2835
+ /**
2836
+ * Read a number off the front of the input in the given radix, stopping
2837
+ * at the first non-digit character or eof. Fails if the number has more
2838
+ * digits than max_digits or if there is no number.
2839
+ */
2840
+ readNumber(radix, maxDigits, allowZeroPrefix, maxBytes) {
2841
+ return this.readAtomically(() => {
2842
+ let result = 0;
2843
+ let digitCount = 0;
2844
+ const leadingChar = this.peekChar();
2845
+ if (leadingChar === undefined) {
2846
+ return undefined;
2847
+ }
2848
+ const hasLeadingZero = leadingChar === "0";
2849
+ const maxValue = 2 ** (8 * maxBytes) - 1;
2850
+ // eslint-disable-next-line no-constant-condition
2851
+ while (true) {
2852
+ const digit = this.readAtomically(() => {
2853
+ const char = this.readChar();
2854
+ if (char === undefined) {
2855
+ return undefined;
2856
+ }
2857
+ const num = Number.parseInt(char, radix);
2858
+ if (Number.isNaN(num)) {
2859
+ return undefined;
2860
+ }
2861
+ return num;
2862
+ });
2863
+ if (digit === undefined) {
2864
+ break;
2865
+ }
2866
+ result *= radix;
2867
+ result += digit;
2868
+ if (result > maxValue) {
2869
+ return undefined;
2870
+ }
2871
+ digitCount += 1;
2872
+ if (maxDigits !== undefined) {
2873
+ if (digitCount > maxDigits) {
2874
+ return undefined;
2875
+ }
2876
+ }
2877
+ }
2878
+ if (digitCount === 0) {
2879
+ return undefined;
2880
+ }
2881
+ else if (!allowZeroPrefix && hasLeadingZero && digitCount > 1) {
2882
+ return undefined;
2883
+ }
2884
+ else {
2885
+ return result;
2886
+ }
2887
+ });
2888
+ }
2889
+ /** Read an IPv4 address. */
2890
+ readIPv4Addr() {
2891
+ return this.readAtomically(() => {
2892
+ const out = new Uint8Array(4);
2893
+ for (let i = 0; i < out.length; i++) {
2894
+ const ix = this.readSeparator(".", i, () => this.readNumber(10, 3, false, 1));
2895
+ if (ix === undefined) {
2896
+ return undefined;
2897
+ }
2898
+ out[i] = ix;
2899
+ }
2900
+ return out;
2901
+ });
2902
+ }
2903
+ /** Read an IPv6 Address. */
2904
+ readIPv6Addr() {
2905
+ /**
2906
+ * Read a chunk of an IPv6 address into `groups`. Returns the number
2907
+ * of groups read, along with a bool indicating if an embedded
2908
+ * trailing IPv4 address was read. Specifically, read a series of
2909
+ * colon-separated IPv6 groups (0x0000 - 0xFFFF), with an optional
2910
+ * trailing embedded IPv4 address.
2911
+ */
2912
+ const readGroups = (groups) => {
2913
+ for (let i = 0; i < groups.length / 2; i++) {
2914
+ const ix = i * 2;
2915
+ // Try to read a trailing embedded IPv4 address. There must be at least 4 groups left.
2916
+ if (i < groups.length - 3) {
2917
+ const ipv4 = this.readSeparator(":", i, () => this.readIPv4Addr());
2918
+ if (ipv4 !== undefined) {
2919
+ groups[ix] = ipv4[0];
2920
+ groups[ix + 1] = ipv4[1];
2921
+ groups[ix + 2] = ipv4[2];
2922
+ groups[ix + 3] = ipv4[3];
2923
+ return [ix + 4, true];
2924
+ }
2925
+ }
2926
+ const group = this.readSeparator(":", i, () => this.readNumber(16, 4, true, 2));
2927
+ if (group === undefined) {
2928
+ return [ix, false];
2929
+ }
2930
+ groups[ix] = group >> 8;
2931
+ groups[ix + 1] = group & 255;
2932
+ }
2933
+ return [groups.length, false];
2934
+ };
2935
+ return this.readAtomically(() => {
2936
+ // Read the front part of the address; either the whole thing, or up to the first ::
2937
+ const head = new Uint8Array(16);
2938
+ const [headSize, headIp4] = readGroups(head);
2939
+ if (headSize === 16) {
2940
+ return head;
2941
+ }
2942
+ // IPv4 part is not allowed before `::`
2943
+ if (headIp4) {
2944
+ return undefined;
2945
+ }
2946
+ // Read `::` if previous code parsed less than 8 groups.
2947
+ // `::` indicates one or more groups of 16 bits of zeros.
2948
+ if (this.readGivenChar(":") === undefined) {
2949
+ return undefined;
2950
+ }
2951
+ if (this.readGivenChar(":") === undefined) {
2952
+ return undefined;
2953
+ }
2954
+ // Read the back part of the address. The :: must contain at least one
2955
+ // set of zeroes, so our max length is 7.
2956
+ const tail = new Uint8Array(14);
2957
+ const limit = 16 - (headSize + 2);
2958
+ const [tailSize] = readGroups(tail.subarray(0, limit));
2959
+ // Concat the head and tail of the IP address
2960
+ head.set(tail.subarray(0, tailSize), 16 - tailSize);
2961
+ return head;
2962
+ });
2963
+ }
2964
+ /** Read an IP Address, either IPv4 or IPv6. */
2965
+ readIPAddr() {
2966
+ return this.readIPv4Addr() ?? this.readIPv6Addr();
2967
+ }
2968
+ }
2969
+
2970
+ // See https://stackoverflow.com/questions/166132/maximum-length-of-the-textual-representation-of-an-ipv6-address
2971
+ const MAX_IPV6_LENGTH = 45;
2972
+ const MAX_IPV4_LENGTH = 15;
2973
+ const parser = new Parser();
2974
+ /** Parse `input` into IPv4 bytes. */
2975
+ function parseIPv4(input) {
2976
+ if (input.length > MAX_IPV4_LENGTH) {
2977
+ return undefined;
2978
+ }
2979
+ return parser.new(input).parseWith(() => parser.readIPv4Addr());
2980
+ }
2981
+ /** Parse `input` into IPv6 bytes. */
2982
+ function parseIPv6(input) {
2983
+ // strip zone index if it is present
2984
+ if (input.includes("%")) {
2985
+ input = input.split("%")[0];
2986
+ }
2987
+ if (input.length > MAX_IPV6_LENGTH) {
2988
+ return undefined;
2989
+ }
2990
+ return parser.new(input).parseWith(() => parser.readIPv6Addr());
2991
+ }
2992
+ /** Parse `input` into IPv4 or IPv6 bytes. */
2993
+ function parseIP(input, mapIPv4ToIPv6 = false) {
2994
+ // strip zone index if it is present
2995
+ if (input.includes("%")) {
2996
+ input = input.split("%")[0];
2997
+ }
2998
+ if (input.length > MAX_IPV6_LENGTH) {
2999
+ return undefined;
3000
+ }
3001
+ const addr = parser.new(input).parseWith(() => parser.readIPAddr());
3002
+ if (!addr) {
3003
+ return undefined;
3004
+ }
3005
+ if (mapIPv4ToIPv6 && addr.length === 4) {
3006
+ return Uint8Array.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, addr[0], addr[1], addr[2], addr[3]]);
3007
+ }
3008
+ return addr;
3009
+ }
3010
+
3011
+ /** Check if `input` is IPv4. */
3012
+ function isIPv4(input) {
3013
+ return Boolean(parseIPv4(input));
3014
+ }
3015
+ /** Check if `input` is IPv6. */
3016
+ function isIPv6(input) {
3017
+ return Boolean(parseIPv6(input));
3018
+ }
3019
+ /** Check if `input` is IPv4 or IPv6. */
3020
+ function isIP(input) {
3021
+ return Boolean(parseIP(input));
3022
+ }
3023
+
3024
+ const isV4 = isIPv4;
3025
+ const isV6 = isIPv6;
3026
+ // Copied from https://github.com/indutny/node-ip/blob/master/lib/ip.js#L7
3027
+ // but with buf/offset args removed because we don't use them
3028
+ const toBytes = function (ip) {
3029
+ let offset = 0;
3030
+ ip = ip.toString().trim();
3031
+ if (isV4(ip)) {
3032
+ const bytes = new Uint8Array(offset + 4);
3033
+ ip.split(/\./g).forEach((byte) => {
3034
+ bytes[offset++] = parseInt(byte, 10) & 0xff;
3035
+ });
3036
+ return bytes;
3037
+ }
3038
+ if (isV6(ip)) {
3039
+ const sections = ip.split(':', 8);
3040
+ let i;
3041
+ for (i = 0; i < sections.length; i++) {
3042
+ const isv4 = isV4(sections[i]);
3043
+ let v4Buffer;
3044
+ if (isv4) {
3045
+ v4Buffer = toBytes(sections[i]);
3046
+ sections[i] = toString$1(v4Buffer.slice(0, 2), 'base16');
3047
+ }
3048
+ if (v4Buffer != null && ++i < 8) {
3049
+ sections.splice(i, 0, toString$1(v4Buffer.slice(2, 4), 'base16'));
3050
+ }
3051
+ }
3052
+ if (sections[0] === '') {
3053
+ while (sections.length < 8)
3054
+ sections.unshift('0');
3055
+ }
3056
+ else if (sections[sections.length - 1] === '') {
3057
+ while (sections.length < 8)
3058
+ sections.push('0');
3059
+ }
3060
+ else if (sections.length < 8) {
3061
+ for (i = 0; i < sections.length && sections[i] !== ''; i++)
3062
+ ;
3063
+ const argv = [i, 1];
3064
+ for (i = 9 - sections.length; i > 0; i--) {
3065
+ argv.push('0');
3066
+ }
3067
+ sections.splice.apply(sections, argv);
3068
+ }
3069
+ const bytes = new Uint8Array(offset + 16);
3070
+ for (i = 0; i < sections.length; i++) {
3071
+ const word = parseInt(sections[i], 16);
3072
+ bytes[offset++] = (word >> 8) & 0xff;
3073
+ bytes[offset++] = word & 0xff;
3074
+ }
3075
+ return bytes;
3076
+ }
3077
+ throw new Error('invalid ip address');
3078
+ };
3079
+ // Copied from https://github.com/indutny/node-ip/blob/master/lib/ip.js#L63
3080
+ const toString = function (buf, offset = 0, length) {
3081
+ offset = ~~offset;
3082
+ length = length ?? (buf.length - offset);
3083
+ const view = new DataView(buf.buffer);
3084
+ if (length === 4) {
3085
+ const result = [];
3086
+ // IPv4
3087
+ for (let i = 0; i < length; i++) {
3088
+ result.push(buf[offset + i]);
3089
+ }
3090
+ return result.join('.');
3091
+ }
3092
+ if (length === 16) {
3093
+ const result = [];
3094
+ // IPv6
3095
+ for (let i = 0; i < length; i += 2) {
3096
+ result.push(view.getUint16(offset + i).toString(16));
3097
+ }
3098
+ return result.join(':')
3099
+ .replace(/(^|:)0(:0)*:0(:|$)/, '$1::$3')
3100
+ .replace(/:{3,4}/, '::');
3101
+ }
3102
+ return '';
3103
+ };
3104
+
3105
+ const V = -1;
3106
+ const names = {};
3107
+ const codes = {};
3108
+ const table = [
3109
+ [4, 32, 'ip4'],
3110
+ [6, 16, 'tcp'],
3111
+ [33, 16, 'dccp'],
3112
+ [41, 128, 'ip6'],
3113
+ [42, V, 'ip6zone'],
3114
+ [43, 8, 'ipcidr'],
3115
+ [53, V, 'dns', true],
3116
+ [54, V, 'dns4', true],
3117
+ [55, V, 'dns6', true],
3118
+ [56, V, 'dnsaddr', true],
3119
+ [132, 16, 'sctp'],
3120
+ [273, 16, 'udp'],
3121
+ [275, 0, 'p2p-webrtc-star'],
3122
+ [276, 0, 'p2p-webrtc-direct'],
3123
+ [277, 0, 'p2p-stardust'],
3124
+ [280, 0, 'webrtc-direct'],
3125
+ [281, 0, 'webrtc'],
3126
+ [290, 0, 'p2p-circuit'],
3127
+ [301, 0, 'udt'],
3128
+ [302, 0, 'utp'],
3129
+ [400, V, 'unix', false, true],
3130
+ // `ipfs` is added before `p2p` for legacy support.
3131
+ // All text representations will default to `p2p`, but `ipfs` will
3132
+ // still be supported
3133
+ [421, V, 'ipfs'],
3134
+ // `p2p` is the preferred name for 421, and is now the default
3135
+ [421, V, 'p2p'],
3136
+ [443, 0, 'https'],
3137
+ [444, 96, 'onion'],
3138
+ [445, 296, 'onion3'],
3139
+ [446, V, 'garlic64'],
3140
+ [448, 0, 'tls'],
3141
+ [449, V, 'sni'],
3142
+ [460, 0, 'quic'],
3143
+ [461, 0, 'quic-v1'],
3144
+ [465, 0, 'webtransport'],
3145
+ [466, V, 'certhash'],
3146
+ [477, 0, 'ws'],
3147
+ [478, 0, 'wss'],
3148
+ [479, 0, 'p2p-websocket-star'],
3149
+ [480, 0, 'http'],
3150
+ [481, V, 'http-path'],
3151
+ [777, V, 'memory']
3152
+ ];
3153
+ // populate tables
3154
+ table.forEach(row => {
3155
+ const proto = createProtocol(...row);
3156
+ codes[proto.code] = proto;
3157
+ names[proto.name] = proto;
3158
+ });
3159
+ function createProtocol(code, size, name, resolvable, path) {
3160
+ return {
3161
+ code,
3162
+ size,
3163
+ name,
3164
+ resolvable: Boolean(resolvable),
3165
+ path: Boolean(path)
3166
+ };
3167
+ }
3168
+ /**
3169
+ * For the passed proto string or number, return a {@link Protocol}
3170
+ *
3171
+ * @example
3172
+ *
3173
+ * ```js
3174
+ * import { protocol } from '@multiformats/multiaddr'
3175
+ *
3176
+ * console.info(protocol(4))
3177
+ * // { code: 4, size: 32, name: 'ip4', resolvable: false, path: false }
3178
+ * ```
3179
+ */
3180
+ function getProtocol(proto) {
3181
+ if (typeof proto === 'number') {
3182
+ if (codes[proto] != null) {
3183
+ return codes[proto];
3184
+ }
3185
+ throw new Error(`no protocol with code: ${proto}`);
3186
+ }
3187
+ else if (typeof proto === 'string') {
3188
+ if (names[proto] != null) {
3189
+ return names[proto];
3190
+ }
3191
+ throw new Error(`no protocol with name: ${proto}`);
3192
+ }
3193
+ throw new Error(`invalid protocol id type: ${typeof proto}`);
3194
+ }
3195
+
3196
+ getProtocol('ip4');
3197
+ getProtocol('ip6');
3198
+ getProtocol('ipcidr');
3199
+ /**
3200
+ * Convert [code,Uint8Array] to string
3201
+ */
3202
+ // eslint-disable-next-line complexity
3203
+ function convertToString(proto, buf) {
3204
+ const protocol = getProtocol(proto);
3205
+ switch (protocol.code) {
3206
+ case 4: // ipv4
3207
+ case 41: // ipv6
3208
+ return bytes2ip(buf);
3209
+ case 42: // ipv6zone
3210
+ return bytes2str(buf);
3211
+ case 43: // ipcidr
3212
+ return toString$1(buf, 'base10');
3213
+ case 6: // tcp
3214
+ case 273: // udp
3215
+ case 33: // dccp
3216
+ case 132: // sctp
3217
+ return bytes2port(buf).toString();
3218
+ case 53: // dns
3219
+ case 54: // dns4
3220
+ case 55: // dns6
3221
+ case 56: // dnsaddr
3222
+ case 400: // unix
3223
+ case 449: // sni
3224
+ case 777: // memory
3225
+ return bytes2str(buf);
3226
+ case 421: // ipfs
3227
+ return bytes2mh(buf);
3228
+ case 444: // onion
3229
+ return bytes2onion(buf);
3230
+ case 445: // onion3
3231
+ return bytes2onion(buf);
3232
+ case 466: // certhash
3233
+ return bytes2mb(buf);
3234
+ case 481: // http-path
3235
+ return globalThis.encodeURIComponent(bytes2str(buf));
3236
+ default:
3237
+ return toString$1(buf, 'base16'); // no clue. convert to hex
3238
+ }
3239
+ }
3240
+ // eslint-disable-next-line complexity
3241
+ function convertToBytes(proto, str) {
3242
+ const protocol = getProtocol(proto);
3243
+ switch (protocol.code) {
3244
+ case 4: // ipv4
3245
+ return ip2bytes(str);
3246
+ case 41: // ipv6
3247
+ return ip2bytes(str);
3248
+ case 42: // ipv6zone
3249
+ return str2bytes(str);
3250
+ case 43: // ipcidr
3251
+ return fromString(str, 'base10');
3252
+ case 6: // tcp
3253
+ case 273: // udp
3254
+ case 33: // dccp
3255
+ case 132: // sctp
3256
+ return port2bytes(parseInt(str, 10));
3257
+ case 53: // dns
3258
+ case 54: // dns4
3259
+ case 55: // dns6
3260
+ case 56: // dnsaddr
3261
+ case 400: // unix
3262
+ case 449: // sni
3263
+ case 777: // memory
3264
+ return str2bytes(str);
3265
+ case 421: // ipfs
3266
+ return mh2bytes(str);
3267
+ case 444: // onion
3268
+ return onion2bytes(str);
3269
+ case 445: // onion3
3270
+ return onion32bytes(str);
3271
+ case 466: // certhash
3272
+ return mb2bytes(str);
3273
+ case 481: // http-path
3274
+ return str2bytes(globalThis.decodeURIComponent(str));
3275
+ default:
3276
+ return fromString(str, 'base16'); // no clue. convert from hex
3277
+ }
3278
+ }
3279
+ const decoders = Object.values(bases).map((c) => c.decoder);
3280
+ const anybaseDecoder = (function () {
3281
+ let acc = decoders[0].or(decoders[1]);
3282
+ decoders.slice(2).forEach((d) => (acc = acc.or(d)));
3283
+ return acc;
3284
+ })();
3285
+ function ip2bytes(ipString) {
3286
+ if (!isIP(ipString)) {
3287
+ throw new Error('invalid ip address');
3288
+ }
3289
+ return toBytes(ipString);
3290
+ }
3291
+ function bytes2ip(ipBuff) {
3292
+ const ipString = toString(ipBuff, 0, ipBuff.length);
3293
+ if (ipString == null) {
3294
+ throw new Error('ipBuff is required');
3295
+ }
3296
+ if (!isIP(ipString)) {
3297
+ throw new Error('invalid ip address');
3298
+ }
3299
+ return ipString;
3300
+ }
3301
+ function port2bytes(port) {
3302
+ const buf = new ArrayBuffer(2);
3303
+ const view = new DataView(buf);
3304
+ view.setUint16(0, port);
3305
+ return new Uint8Array(buf);
3306
+ }
3307
+ function bytes2port(buf) {
3308
+ const view = new DataView(buf.buffer);
3309
+ return view.getUint16(buf.byteOffset);
3310
+ }
3311
+ function str2bytes(str) {
3312
+ const buf = fromString(str);
3313
+ const size = Uint8Array.from(encode$2(buf.length));
3314
+ return concat([size, buf], size.length + buf.length);
3315
+ }
3316
+ function bytes2str(buf) {
3317
+ const size = decode$4(buf);
3318
+ buf = buf.slice(encodingLength$1(size));
3319
+ if (buf.length !== size) {
3320
+ throw new Error('inconsistent lengths');
3321
+ }
3322
+ return toString$1(buf);
3323
+ }
3324
+ function mh2bytes(hash) {
3325
+ let mh;
3326
+ if (hash[0] === 'Q' || hash[0] === '1') {
3327
+ mh = decode$1(base58btc.decode(`z${hash}`)).bytes;
3328
+ }
3329
+ else {
3330
+ mh = CID.parse(hash).multihash.bytes;
3331
+ }
3332
+ // the address is a varint prefixed multihash string representation
3333
+ const size = Uint8Array.from(encode$2(mh.length));
3334
+ return concat([size, mh], size.length + mh.length);
3335
+ }
3336
+ function mb2bytes(mbstr) {
3337
+ const mb = anybaseDecoder.decode(mbstr);
3338
+ const size = Uint8Array.from(encode$2(mb.length));
3339
+ return concat([size, mb], size.length + mb.length);
3340
+ }
3341
+ function bytes2mb(buf) {
3342
+ const size = decode$4(buf);
3343
+ const hash = buf.slice(encodingLength$1(size));
3344
+ if (hash.length !== size) {
3345
+ throw new Error('inconsistent lengths');
3346
+ }
3347
+ return 'u' + toString$1(hash, 'base64url');
3348
+ }
3349
+ /**
3350
+ * Converts bytes to bas58btc string
3351
+ */
3352
+ function bytes2mh(buf) {
3353
+ const size = decode$4(buf);
3354
+ const address = buf.slice(encodingLength$1(size));
3355
+ if (address.length !== size) {
3356
+ throw new Error('inconsistent lengths');
3357
+ }
3358
+ return toString$1(address, 'base58btc');
3359
+ }
3360
+ function onion2bytes(str) {
3361
+ const addr = str.split(':');
3362
+ if (addr.length !== 2) {
3363
+ throw new Error(`failed to parse onion addr: ["'${addr.join('", "')}'"]' does not contain a port number`);
3364
+ }
3365
+ if (addr[0].length !== 16) {
3366
+ throw new Error(`failed to parse onion addr: ${addr[0]} not a Tor onion address.`);
3367
+ }
3368
+ // onion addresses do not include the multibase prefix, add it before decoding
3369
+ const buf = base32.decode('b' + addr[0]);
3370
+ // onion port number
3371
+ const port = parseInt(addr[1], 10);
3372
+ if (port < 1 || port > 65536) {
3373
+ throw new Error('Port number is not in range(1, 65536)');
3374
+ }
3375
+ const portBuf = port2bytes(port);
3376
+ return concat([buf, portBuf], buf.length + portBuf.length);
3377
+ }
3378
+ function onion32bytes(str) {
3379
+ const addr = str.split(':');
3380
+ if (addr.length !== 2) {
3381
+ throw new Error(`failed to parse onion addr: ["'${addr.join('", "')}'"]' does not contain a port number`);
3382
+ }
3383
+ if (addr[0].length !== 56) {
3384
+ throw new Error(`failed to parse onion addr: ${addr[0]} not a Tor onion3 address.`);
3385
+ }
3386
+ // onion addresses do not include the multibase prefix, add it before decoding
3387
+ const buf = base32.decode(`b${addr[0]}`);
3388
+ // onion port number
3389
+ const port = parseInt(addr[1], 10);
3390
+ if (port < 1 || port > 65536) {
3391
+ throw new Error('Port number is not in range(1, 65536)');
3392
+ }
3393
+ const portBuf = port2bytes(port);
3394
+ return concat([buf, portBuf], buf.length + portBuf.length);
3395
+ }
3396
+ function bytes2onion(buf) {
3397
+ const addrBytes = buf.slice(0, buf.length - 2);
3398
+ const portBytes = buf.slice(buf.length - 2);
3399
+ const addr = toString$1(addrBytes, 'base32');
3400
+ const port = bytes2port(portBytes);
3401
+ return `${addr}:${port}`;
3402
+ }
3403
+
3404
+ function stringToMultiaddrParts(str) {
3405
+ str = cleanPath(str);
3406
+ const tuples = [];
3407
+ const stringTuples = [];
3408
+ let path = null;
3409
+ const parts = str.split('/').slice(1);
3410
+ if (parts.length === 1 && parts[0] === '') {
3411
+ return {
3412
+ bytes: new Uint8Array(),
3413
+ string: '/',
3414
+ tuples: [],
3415
+ stringTuples: [],
3416
+ path: null
3417
+ };
3418
+ }
3419
+ for (let p = 0; p < parts.length; p++) {
3420
+ const part = parts[p];
3421
+ const proto = getProtocol(part);
3422
+ if (proto.size === 0) {
3423
+ tuples.push([proto.code]);
3424
+ stringTuples.push([proto.code]);
3425
+ // eslint-disable-next-line no-continue
3426
+ continue;
3427
+ }
3428
+ p++; // advance addr part
3429
+ if (p >= parts.length) {
3430
+ throw ParseError('invalid address: ' + str);
3431
+ }
3432
+ // if it's a path proto, take the rest
3433
+ if (proto.path === true) {
3434
+ // should we need to check each path part to see if it's a proto?
3435
+ // This would allow for other protocols to be added after a unix path,
3436
+ // however it would have issues if the path had a protocol name in the path
3437
+ path = cleanPath(parts.slice(p).join('/'));
3438
+ tuples.push([proto.code, convertToBytes(proto.code, path)]);
3439
+ stringTuples.push([proto.code, path]);
3440
+ break;
3441
+ }
3442
+ const bytes = convertToBytes(proto.code, parts[p]);
3443
+ tuples.push([proto.code, bytes]);
3444
+ stringTuples.push([proto.code, convertToString(proto.code, bytes)]);
3445
+ }
3446
+ return {
3447
+ string: stringTuplesToString(stringTuples),
3448
+ bytes: tuplesToBytes(tuples),
3449
+ tuples,
3450
+ stringTuples,
3451
+ path
3452
+ };
3453
+ }
3454
+ function bytesToMultiaddrParts(bytes) {
3455
+ const tuples = [];
3456
+ const stringTuples = [];
3457
+ let path = null;
3458
+ let i = 0;
3459
+ while (i < bytes.length) {
3460
+ const code = decode$4(bytes, i);
3461
+ const n = encodingLength$1(code);
3462
+ const p = getProtocol(code);
3463
+ const size = sizeForAddr(p, bytes.slice(i + n));
3464
+ if (size === 0) {
3465
+ tuples.push([code]);
3466
+ stringTuples.push([code]);
3467
+ i += n;
3468
+ // eslint-disable-next-line no-continue
3469
+ continue;
3470
+ }
3471
+ const addr = bytes.slice(i + n, i + n + size);
3472
+ i += (size + n);
3473
+ if (i > bytes.length) { // did not end _exactly_ at buffer.length
3474
+ throw ParseError('Invalid address Uint8Array: ' + toString$1(bytes, 'base16'));
3475
+ }
3476
+ // ok, tuple seems good.
3477
+ tuples.push([code, addr]);
3478
+ const stringAddr = convertToString(code, addr);
3479
+ stringTuples.push([code, stringAddr]);
3480
+ if (p.path === true) {
3481
+ // should we need to check each path part to see if it's a proto?
3482
+ // This would allow for other protocols to be added after a unix path,
3483
+ // however it would have issues if the path had a protocol name in the path
3484
+ path = stringAddr;
3485
+ break;
3486
+ }
3487
+ }
3488
+ return {
3489
+ bytes: Uint8Array.from(bytes),
3490
+ string: stringTuplesToString(stringTuples),
3491
+ tuples,
3492
+ stringTuples,
3493
+ path
3494
+ };
3495
+ }
3496
+ /**
3497
+ * [[str name, str addr]... ] -> string
3498
+ */
3499
+ function stringTuplesToString(tuples) {
3500
+ const parts = [];
3501
+ tuples.map((tup) => {
3502
+ const proto = getProtocol(tup[0]);
3503
+ parts.push(proto.name);
3504
+ if (tup.length > 1 && tup[1] != null) {
3505
+ parts.push(tup[1]);
3506
+ }
3507
+ return null;
3508
+ });
3509
+ return cleanPath(parts.join('/'));
3510
+ }
3511
+ /**
3512
+ * [[int code, Uint8Array ]... ] -> Uint8Array
3513
+ */
3514
+ function tuplesToBytes(tuples) {
3515
+ return concat(tuples.map((tup) => {
3516
+ const proto = getProtocol(tup[0]);
3517
+ let buf = Uint8Array.from(encode$2(proto.code));
3518
+ if (tup.length > 1 && tup[1] != null) {
3519
+ buf = concat([buf, tup[1]]); // add address buffer
3520
+ }
3521
+ return buf;
3522
+ }));
3523
+ }
3524
+ /**
3525
+ * For the passed address, return the serialized size
3526
+ */
3527
+ function sizeForAddr(p, addr) {
3528
+ if (p.size > 0) {
3529
+ return p.size / 8;
3530
+ }
3531
+ else if (p.size === 0) {
3532
+ return 0;
3533
+ }
3534
+ else {
3535
+ const size = decode$4(addr instanceof Uint8Array ? addr : Uint8Array.from(addr));
3536
+ return size + encodingLength$1(size);
3537
+ }
3538
+ }
3539
+ function cleanPath(str) {
3540
+ return '/' + str.trim().split('/').filter((a) => a).join('/');
3541
+ }
3542
+ function ParseError(str) {
3543
+ return new Error('Error parsing address: ' + str);
3544
+ }
3545
+
3546
+ const inspect = Symbol.for('nodejs.util.inspect.custom');
3547
+ const symbol = Symbol.for('@multiformats/js-multiaddr/multiaddr');
3548
+ const DNS_CODES = [
3549
+ getProtocol('dns').code,
3550
+ getProtocol('dns4').code,
3551
+ getProtocol('dns6').code,
3552
+ getProtocol('dnsaddr').code
3553
+ ];
3554
+ class NoAvailableResolverError extends Error {
3555
+ constructor(message = 'No available resolver') {
3556
+ super(message);
3557
+ this.name = 'NoAvailableResolverError';
3558
+ }
3559
+ }
3560
+ /**
3561
+ * Creates a {@link Multiaddr} from a {@link MultiaddrInput}
3562
+ */
3563
+ class Multiaddr {
3564
+ bytes;
3565
+ #string;
3566
+ #tuples;
3567
+ #stringTuples;
3568
+ #path;
3569
+ [symbol] = true;
3570
+ constructor(addr) {
3571
+ // default
3572
+ if (addr == null) {
3573
+ addr = '';
3574
+ }
3575
+ let parts;
3576
+ if (addr instanceof Uint8Array) {
3577
+ parts = bytesToMultiaddrParts(addr);
3578
+ }
3579
+ else if (typeof addr === 'string') {
3580
+ if (addr.length > 0 && addr.charAt(0) !== '/') {
3581
+ throw new Error(`multiaddr "${addr}" must start with a "/"`);
3582
+ }
3583
+ parts = stringToMultiaddrParts(addr);
3584
+ }
3585
+ else if (isMultiaddr(addr)) { // Multiaddr
3586
+ parts = bytesToMultiaddrParts(addr.bytes);
3587
+ }
3588
+ else {
3589
+ throw new Error('addr must be a string, Buffer, or another Multiaddr');
3590
+ }
3591
+ this.bytes = parts.bytes;
3592
+ this.#string = parts.string;
3593
+ this.#tuples = parts.tuples;
3594
+ this.#stringTuples = parts.stringTuples;
3595
+ this.#path = parts.path;
3596
+ }
3597
+ toString() {
3598
+ return this.#string;
3599
+ }
3600
+ toJSON() {
3601
+ return this.toString();
3602
+ }
3603
+ toOptions() {
3604
+ let family;
3605
+ let transport;
3606
+ let host;
3607
+ let port;
3608
+ let zone = '';
3609
+ const tcp = getProtocol('tcp');
3610
+ const udp = getProtocol('udp');
3611
+ const ip4 = getProtocol('ip4');
3612
+ const ip6 = getProtocol('ip6');
3613
+ const dns6 = getProtocol('dns6');
3614
+ const ip6zone = getProtocol('ip6zone');
3615
+ for (const [code, value] of this.stringTuples()) {
3616
+ if (code === ip6zone.code) {
3617
+ zone = `%${value ?? ''}`;
3618
+ }
3619
+ // default to https when protocol & port are omitted from DNS addrs
3620
+ if (DNS_CODES.includes(code)) {
3621
+ transport = tcp.name;
3622
+ port = 443;
3623
+ host = `${value ?? ''}${zone}`;
3624
+ family = code === dns6.code ? 6 : 4;
3625
+ }
3626
+ if (code === tcp.code || code === udp.code) {
3627
+ transport = getProtocol(code).name;
3628
+ port = parseInt(value ?? '');
3629
+ }
3630
+ if (code === ip4.code || code === ip6.code) {
3631
+ transport = getProtocol(code).name;
3632
+ host = `${value ?? ''}${zone}`;
3633
+ family = code === ip6.code ? 6 : 4;
3634
+ }
3635
+ }
3636
+ if (family == null || transport == null || host == null || port == null) {
3637
+ throw new Error('multiaddr must have a valid format: "/{ip4, ip6, dns4, dns6, dnsaddr}/{address}/{tcp, udp}/{port}".');
3638
+ }
3639
+ const opts = {
3640
+ family,
3641
+ host,
3642
+ transport,
3643
+ port
3644
+ };
3645
+ return opts;
3646
+ }
3647
+ protos() {
3648
+ return this.#tuples.map(([code]) => Object.assign({}, getProtocol(code)));
3649
+ }
3650
+ protoCodes() {
3651
+ return this.#tuples.map(([code]) => code);
3652
+ }
3653
+ protoNames() {
3654
+ return this.#tuples.map(([code]) => getProtocol(code).name);
3655
+ }
3656
+ tuples() {
3657
+ return this.#tuples.map(([code, value]) => {
3658
+ if (value == null) {
3659
+ return [code];
3660
+ }
3661
+ return [code, value];
3662
+ });
3663
+ }
3664
+ stringTuples() {
3665
+ return this.#stringTuples.map(([code, value]) => {
3666
+ if (value == null) {
3667
+ return [code];
3668
+ }
3669
+ return [code, value];
3670
+ });
3671
+ }
3672
+ encapsulate(addr) {
3673
+ addr = new Multiaddr(addr);
3674
+ return new Multiaddr(this.toString() + addr.toString());
3675
+ }
3676
+ decapsulate(addr) {
3677
+ const addrString = addr.toString();
3678
+ const s = this.toString();
3679
+ const i = s.lastIndexOf(addrString);
3680
+ if (i < 0) {
3681
+ throw new Error(`Address ${this.toString()} does not contain subaddress: ${addr.toString()}`);
3682
+ }
3683
+ return new Multiaddr(s.slice(0, i));
3684
+ }
3685
+ decapsulateCode(code) {
3686
+ const tuples = this.tuples();
3687
+ for (let i = tuples.length - 1; i >= 0; i--) {
3688
+ if (tuples[i][0] === code) {
3689
+ return new Multiaddr(tuplesToBytes(tuples.slice(0, i)));
3690
+ }
3691
+ }
3692
+ return this;
3693
+ }
3694
+ getPeerId() {
3695
+ try {
3696
+ let tuples = [];
3697
+ this.stringTuples().forEach(([code, name]) => {
3698
+ if (code === names.p2p.code) {
3699
+ tuples.push([code, name]);
3700
+ }
3701
+ // if this is a p2p-circuit address, return the target peer id if present
3702
+ // not the peer id of the relay
3703
+ if (code === names['p2p-circuit'].code) {
3704
+ tuples = [];
3705
+ }
3706
+ });
3707
+ // Get the last ipfs tuple ['p2p', 'peerid string']
3708
+ const tuple = tuples.pop();
3709
+ if (tuple?.[1] != null) {
3710
+ const peerIdStr = tuple[1];
3711
+ // peer id is base58btc encoded string but not multibase encoded so add the `z`
3712
+ // prefix so we can validate that it is correctly encoded
3713
+ if (peerIdStr[0] === 'Q' || peerIdStr[0] === '1') {
3714
+ return toString$1(base58btc.decode(`z${peerIdStr}`), 'base58btc');
3715
+ }
3716
+ // try to parse peer id as CID
3717
+ return toString$1(CID.parse(peerIdStr).multihash.bytes, 'base58btc');
3718
+ }
3719
+ return null;
3720
+ }
3721
+ catch (e) {
3722
+ return null;
3723
+ }
3724
+ }
3725
+ getPath() {
3726
+ return this.#path;
3727
+ }
3728
+ equals(addr) {
3729
+ return equals(this.bytes, addr.bytes);
3730
+ }
3731
+ async resolve(options) {
3732
+ const resolvableProto = this.protos().find((p) => p.resolvable);
3733
+ // Multiaddr is not resolvable?
3734
+ if (resolvableProto == null) {
3735
+ return [this];
3736
+ }
3737
+ const resolver = resolvers.get(resolvableProto.name);
3738
+ if (resolver == null) {
3739
+ throw new NoAvailableResolverError(`no available resolver for ${resolvableProto.name}`);
3740
+ }
3741
+ const result = await resolver(this, options);
3742
+ return result.map(str => multiaddr(str));
3743
+ }
3744
+ nodeAddress() {
3745
+ const options = this.toOptions();
3746
+ if (options.transport !== 'tcp' && options.transport !== 'udp') {
3747
+ throw new Error(`multiaddr must have a valid format - no protocol with name: "${options.transport}". Must have a valid transport protocol: "{tcp, udp}"`);
3748
+ }
3749
+ return {
3750
+ family: options.family,
3751
+ address: options.host,
3752
+ port: options.port
3753
+ };
3754
+ }
3755
+ isThinWaistAddress(addr) {
3756
+ const protos = (addr ?? this).protos();
3757
+ if (protos.length !== 2) {
3758
+ return false;
3759
+ }
3760
+ if (protos[0].code !== 4 && protos[0].code !== 41) {
3761
+ return false;
3762
+ }
3763
+ if (protos[1].code !== 6 && protos[1].code !== 273) {
3764
+ return false;
3765
+ }
3766
+ return true;
3767
+ }
3768
+ /**
3769
+ * Returns Multiaddr as a human-readable string
3770
+ * https://nodejs.org/api/util.html#utilinspectcustom
3771
+ *
3772
+ * @example
3773
+ * ```js
3774
+ * import { multiaddr } from '@multiformats/multiaddr'
3775
+ *
3776
+ * console.info(multiaddr('/ip4/127.0.0.1/tcp/4001'))
3777
+ * // 'Multiaddr(/ip4/127.0.0.1/tcp/4001)'
3778
+ * ```
3779
+ */
3780
+ [inspect]() {
3781
+ return `Multiaddr(${this.#string})`;
3782
+ }
3783
+ }
3784
+
3785
+ /**
3786
+ * @packageDocumentation
3787
+ *
3788
+ * A standard way to represent addresses that
3789
+ *
3790
+ * - support any standard network protocol
3791
+ * - are self-describing
3792
+ * - have a binary packed format
3793
+ * - have a nice string representation
3794
+ * - encapsulate well
3795
+ *
3796
+ * @example
3797
+ *
3798
+ * ```TypeScript
3799
+ * import { multiaddr } from '@multiformats/multiaddr'
3800
+ *
3801
+ * const addr = multiaddr('/ip4/127.0.0.1/udp/1234')
3802
+ * // Multiaddr(/ip4/127.0.0.1/udp/1234)
3803
+ *
3804
+ * addr.bytes
3805
+ * // <Uint8Array 04 7f 00 00 01 11 04 d2>
3806
+ *
3807
+ * addr.toString()
3808
+ * // '/ip4/127.0.0.1/udp/1234'
3809
+ *
3810
+ * addr.protos()
3811
+ * // [
3812
+ * // {code: 4, name: 'ip4', size: 32},
3813
+ * // {code: 273, name: 'udp', size: 16}
3814
+ * // ]
3815
+ *
3816
+ * // gives you an object that is friendly with what Node.js core modules expect for addresses
3817
+ * addr.nodeAddress()
3818
+ * // {
3819
+ * // family: 4,
3820
+ * // port: 1234,
3821
+ * // address: "127.0.0.1"
3822
+ * // }
3823
+ *
3824
+ * addr.encapsulate('/sctp/5678')
3825
+ * // Multiaddr(/ip4/127.0.0.1/udp/1234/sctp/5678)
3826
+ * ```
3827
+ *
3828
+ * ## Resolving DNSADDR addresses
3829
+ *
3830
+ * [DNSADDR](https://github.com/multiformats/multiaddr/blob/master/protocols/DNSADDR.md) is a spec that allows storing a TXT DNS record that contains a Multiaddr.
3831
+ *
3832
+ * To resolve DNSADDR addresses, call the `.resolve()` function the multiaddr, optionally passing a `DNS` resolver.
3833
+ *
3834
+ * DNSADDR addresses can resolve to multiple multiaddrs, since there is no limit to the number of TXT records that can be stored.
3835
+ *
3836
+ * @example Resolving DNSADDR Multiaddrs
3837
+ *
3838
+ * ```TypeScript
3839
+ * import { multiaddr, resolvers } from '@multiformats/multiaddr'
3840
+ * import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
3841
+ *
3842
+ * resolvers.set('dnsaddr', dnsaddrResolver)
3843
+ *
3844
+ * const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')
3845
+ *
3846
+ * // resolve with a 5s timeout
3847
+ * const resolved = await ma.resolve({
3848
+ * signal: AbortSignal.timeout(5000)
3849
+ * })
3850
+ *
3851
+ * console.info(resolved)
3852
+ * // [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]
3853
+ * ```
3854
+ *
3855
+ * @example Using a custom DNS resolver to resolve DNSADDR Multiaddrs
3856
+ *
3857
+ * See the docs for [@multiformats/dns](https://www.npmjs.com/package/@multiformats/dns) for a full breakdown of how to specify multiple resolvers or resolvers that can be used for specific TLDs.
3858
+ *
3859
+ * ```TypeScript
3860
+ * import { multiaddr } from '@multiformats/multiaddr'
3861
+ * import { dns } from '@multiformats/dns'
3862
+ * import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'
3863
+ *
3864
+ * const resolver = dns({
3865
+ * resolvers: {
3866
+ * '.': dnsJsonOverHttps('https://cloudflare-dns.com/dns-query')
3867
+ * }
3868
+ * })
3869
+ *
3870
+ * const ma = multiaddr('/dnsaddr/bootstrap.libp2p.io')
3871
+ * const resolved = await ma.resolve({
3872
+ * dns: resolver
3873
+ * })
3874
+ *
3875
+ * console.info(resolved)
3876
+ * // [Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...'), Multiaddr('/ip4/147.75...')...]
3877
+ * ```
3878
+ */
3879
+ /**
3880
+ * All configured {@link Resolver}s
3881
+ */
3882
+ const resolvers = new Map();
3883
+ /**
3884
+ * Check if object is a {@link Multiaddr} instance
3885
+ *
3886
+ * @example
3887
+ *
3888
+ * ```js
3889
+ * import { isMultiaddr, multiaddr } from '@multiformats/multiaddr'
3890
+ *
3891
+ * isMultiaddr(5)
3892
+ * // false
3893
+ * isMultiaddr(multiaddr('/ip4/127.0.0.1'))
3894
+ * // true
3895
+ * ```
3896
+ */
3897
+ function isMultiaddr(value) {
3898
+ return Boolean(value?.[symbol]);
3899
+ }
3900
+ /**
3901
+ * A function that takes a {@link MultiaddrInput} and returns a {@link Multiaddr}
3902
+ *
3903
+ * @example
3904
+ * ```js
3905
+ * import { multiaddr } from '@libp2p/multiaddr'
3906
+ *
3907
+ * multiaddr('/ip4/127.0.0.1/tcp/4001')
3908
+ * // Multiaddr(/ip4/127.0.0.1/tcp/4001)
3909
+ * ```
3910
+ *
3911
+ * @param {MultiaddrInput} [addr] - If String or Uint8Array, needs to adhere to the address format of a [multiaddr](https://github.com/multiformats/multiaddr#string-format)
3912
+ */
3913
+ function multiaddr(addr) {
3914
+ return new Multiaddr(addr);
3915
+ }
3916
+
3917
+ const RelayPingContentTopic = "/relay-ping/1/ping/null";
3918
+ const log$2 = new Logger("keep-alive");
3919
+ class KeepAliveManager {
3920
+ relay;
3921
+ libp2p;
3922
+ options;
3923
+ pingKeepAliveTimers = new Map();
3924
+ relayKeepAliveTimers = new Map();
3925
+ constructor({ options, relay, libp2p }) {
3926
+ this.options = options;
3927
+ this.relay = relay;
3928
+ this.libp2p = libp2p;
3929
+ }
3930
+ start(peerId) {
3931
+ // Just in case a timer already exists for this peer
3932
+ this.stop(peerId);
3933
+ const { pingKeepAlive: pingPeriodSecs, relayKeepAlive: relayPeriodSecs } = this.options;
3934
+ const peerIdStr = peerId.toString();
3935
+ // Ping the peer every pingPeriodSecs seconds
3936
+ // if pingPeriodSecs is 0, don't ping the peer
3937
+ if (pingPeriodSecs !== 0) {
3938
+ const interval = setInterval(() => {
3939
+ void (async () => {
3940
+ let ping;
3941
+ try {
3942
+ // ping the peer for keep alive
3943
+ // also update the peer store with the latency
3944
+ try {
3945
+ ping = await this.libp2p.services.ping.ping(peerId);
3946
+ log$2.info(`Ping succeeded (${peerIdStr})`, ping);
3947
+ }
3948
+ catch (error) {
3949
+ log$2.error(`Ping failed for peer (${peerIdStr}).
3950
+ Next ping will be attempted in ${pingPeriodSecs} seconds.
3951
+ `);
3952
+ return;
3953
+ }
3954
+ try {
3955
+ await this.libp2p.peerStore.merge(peerId, {
3956
+ metadata: {
3957
+ ping: utf8ToBytes(ping.toString())
3958
+ }
3959
+ });
3960
+ }
2669
3961
  catch (e) {
2670
3962
  log$2.error("Failed to update ping", e);
2671
3963
  }
@@ -2731,13 +4023,36 @@ class KeepAliveManager {
2731
4023
  }
2732
4024
  }
2733
4025
 
4026
+ /**
4027
+ * Reads peer's metadata and retrieves ping value.
4028
+ * @param peer Peer or null
4029
+ * @returns -1 if no ping attached, otherwise returns ping value
4030
+ */
4031
+ const getPeerPing = (peer) => {
4032
+ if (!peer) {
4033
+ return -1;
4034
+ }
4035
+ try {
4036
+ const bytes = peer.metadata.get("ping");
4037
+ if (!bytes) {
4038
+ return -1;
4039
+ }
4040
+ return Number(bytesToUtf8(bytes));
4041
+ }
4042
+ catch (e) {
4043
+ return -1;
4044
+ }
4045
+ };
4046
+
2734
4047
  const log$1 = new Logger("connection-manager");
2735
4048
  const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1;
2736
4049
  const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3;
2737
4050
  const DEFAULT_MAX_PARALLEL_DIALS = 3;
4051
+ const DEFAULT_PING_KEEP_ALIVE_SEC = 5 * 60;
4052
+ const DEFAULT_RELAY_KEEP_ALIVE_SEC = 5 * 60;
2738
4053
  class ConnectionManager extends TypedEventEmitter {
2739
- configuredPubsubTopics;
2740
- static instances = new Map();
4054
+ // TODO(weboko): make it private
4055
+ pubsubTopics;
2741
4056
  keepAliveManager;
2742
4057
  options;
2743
4058
  libp2p;
@@ -2752,14 +4067,6 @@ class ConnectionManager extends TypedEventEmitter {
2752
4067
  }
2753
4068
  return this.isP2PNetworkConnected;
2754
4069
  }
2755
- static create(peerId, libp2p, keepAliveOptions, pubsubTopics, relay, options) {
2756
- let instance = ConnectionManager.instances.get(peerId);
2757
- if (!instance) {
2758
- instance = new ConnectionManager(libp2p, keepAliveOptions, pubsubTopics, relay, options);
2759
- ConnectionManager.instances.set(peerId, instance);
2760
- }
2761
- return instance;
2762
- }
2763
4070
  stop() {
2764
4071
  this.keepAliveManager.stopAll();
2765
4072
  this.libp2p.removeEventListener("peer:connect", this.onEventHandlers["peer:connect"]);
@@ -2826,21 +4133,25 @@ class ConnectionManager extends TypedEventEmitter {
2826
4133
  }
2827
4134
  };
2828
4135
  }
2829
- constructor(libp2p, keepAliveOptions, configuredPubsubTopics, relay, options) {
4136
+ constructor(options) {
2830
4137
  super();
2831
- this.configuredPubsubTopics = configuredPubsubTopics;
2832
- this.libp2p = libp2p;
2833
- this.configuredPubsubTopics = configuredPubsubTopics;
4138
+ this.libp2p = options.libp2p;
4139
+ this.pubsubTopics = options.pubsubTopics;
2834
4140
  this.options = {
2835
4141
  maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER,
2836
4142
  maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED,
2837
4143
  maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS,
2838
- ...options
4144
+ pingKeepAlive: DEFAULT_PING_KEEP_ALIVE_SEC,
4145
+ relayKeepAlive: DEFAULT_RELAY_KEEP_ALIVE_SEC,
4146
+ ...options.config
2839
4147
  };
2840
4148
  this.keepAliveManager = new KeepAliveManager({
2841
- relay,
2842
- libp2p,
2843
- options: keepAliveOptions
4149
+ relay: options.relay,
4150
+ libp2p: options.libp2p,
4151
+ options: {
4152
+ pingKeepAlive: this.options.pingKeepAlive,
4153
+ relayKeepAlive: this.options.relayKeepAlive
4154
+ }
2844
4155
  });
2845
4156
  this.startEventListeners()
2846
4157
  .then(() => log$1.info(`Connection Manager is now running`))
@@ -2850,6 +4161,24 @@ class ConnectionManager extends TypedEventEmitter {
2850
4161
  // we will dial the peers in peerStore ONCE before we start to listen to the `peer:discovery` events within the ConnectionManager
2851
4162
  this.dialPeerStorePeers().catch((error) => log$1.error(`Unexpected error while dialing peer store peers`, error));
2852
4163
  }
4164
+ async getConnectedPeers(codec) {
4165
+ const peerIDs = this.libp2p.getPeers();
4166
+ if (peerIDs.length === 0) {
4167
+ return [];
4168
+ }
4169
+ const peers = await Promise.all(peerIDs.map(async (id) => {
4170
+ try {
4171
+ return await this.libp2p.peerStore.get(id);
4172
+ }
4173
+ catch (e) {
4174
+ return null;
4175
+ }
4176
+ }));
4177
+ return peers
4178
+ .filter((p) => !!p)
4179
+ .filter((p) => (codec ? p.protocols.includes(codec) : true))
4180
+ .sort((left, right) => getPeerPing(left) - getPeerPing(right));
4181
+ }
2853
4182
  async dialPeerStorePeers() {
2854
4183
  const peerInfos = await this.libp2p.peerStore.all();
2855
4184
  const dialPromises = [];
@@ -2871,13 +4200,59 @@ class ConnectionManager extends TypedEventEmitter {
2871
4200
  this.startPeerDisconnectionListener();
2872
4201
  this.startNetworkStatusListener();
2873
4202
  }
2874
- async dialPeer(peerId) {
4203
+ /**
4204
+ * Attempts to establish a connection with a peer and set up specified protocols.
4205
+ * The method handles both PeerId and Multiaddr inputs, manages connection attempts,
4206
+ * and maintains the connection state.
4207
+ *
4208
+ * The dialing process includes:
4209
+ * 1. Converting input to dialable peer info
4210
+ * 2. Managing parallel dial attempts
4211
+ * 3. Attempting to establish protocol-specific connections
4212
+ * 4. Handling connection failures and retries
4213
+ * 5. Updating the peer store and connection state
4214
+ *
4215
+ * @param {PeerId | MultiaddrInput} peer - The peer to connect to, either as a PeerId or multiaddr
4216
+ * @param {string[]} [protocolCodecs] - Optional array of protocol-specific codec strings to establish
4217
+ * (e.g., for LightPush, Filter, Store protocols)
4218
+ *
4219
+ * @throws {Error} If the multiaddr is missing a peer ID
4220
+ * @throws {Error} If the maximum dial attempts are reached and the peer cannot be dialed
4221
+ * @throws {Error} If there's an error deleting an undialable peer from the peer store
4222
+ *
4223
+ * @example
4224
+ * ```typescript
4225
+ * // Dial using PeerId
4226
+ * await connectionManager.dialPeer(peerId);
4227
+ *
4228
+ * // Dial using multiaddr with specific protocols
4229
+ * await connectionManager.dialPeer(multiaddr, [
4230
+ * "/vac/waku/relay/2.0.0",
4231
+ * "/vac/waku/lightpush/2.0.0-beta1"
4232
+ * ]);
4233
+ * ```
4234
+ *
4235
+ * @remarks
4236
+ * - The method implements exponential backoff through multiple dial attempts
4237
+ * - Maintains a queue for parallel dial attempts (limited by maxParallelDials)
4238
+ * - Integrates with the KeepAliveManager for connection maintenance
4239
+ * - Updates the peer store and connection state after successful/failed attempts
4240
+ * - If all dial attempts fail, triggers DNS discovery as a fallback
4241
+ */
4242
+ async dialPeer(peer) {
4243
+ let connection;
4244
+ let peerId;
4245
+ const peerDialInfo = this.getDialablePeerInfo(peer);
4246
+ const peerIdStr = isPeerId(peerDialInfo)
4247
+ ? peerDialInfo.toString()
4248
+ : peerDialInfo.getPeerId();
2875
4249
  this.currentActiveParallelDialCount += 1;
2876
4250
  let dialAttempt = 0;
2877
4251
  while (dialAttempt < this.options.maxDialAttemptsForPeer) {
2878
4252
  try {
2879
- log$1.info(`Dialing peer ${peerId.toString()} on attempt ${dialAttempt + 1}`);
2880
- await this.libp2p.dial(peerId);
4253
+ log$1.info(`Dialing peer ${peerDialInfo} on attempt ${dialAttempt + 1}`);
4254
+ connection = await this.libp2p.dial(peerDialInfo);
4255
+ peerId = connection.remotePeer;
2881
4256
  const tags = await this.getTagNamesForPeer(peerId);
2882
4257
  // add tag to connection describing discovery mechanism
2883
4258
  // don't add duplicate tags
@@ -2894,15 +4269,15 @@ class ConnectionManager extends TypedEventEmitter {
2894
4269
  catch (error) {
2895
4270
  if (error instanceof AggregateError) {
2896
4271
  // Handle AggregateError
2897
- log$1.error(`Error dialing peer ${peerId.toString()} - ${error.errors}`);
4272
+ log$1.error(`Error dialing peer ${peerIdStr} - ${error.errors}`);
2898
4273
  }
2899
4274
  else {
2900
4275
  // Handle generic error
2901
- log$1.error(`Error dialing peer ${peerId.toString()} - ${error.message}`);
4276
+ log$1.error(`Error dialing peer ${peerIdStr} - ${error.message}`);
2902
4277
  }
2903
- this.dialErrorsForPeer.set(peerId.toString(), error);
4278
+ this.dialErrorsForPeer.set(peerIdStr, error);
2904
4279
  dialAttempt++;
2905
- this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt);
4280
+ this.dialAttemptsForPeer.set(peerIdStr, dialAttempt);
2906
4281
  }
2907
4282
  }
2908
4283
  // Always decrease the active dial count and process the dial queue
@@ -2911,7 +4286,7 @@ class ConnectionManager extends TypedEventEmitter {
2911
4286
  // If max dial attempts reached and dialing failed, delete the peer
2912
4287
  if (dialAttempt === this.options.maxDialAttemptsForPeer) {
2913
4288
  try {
2914
- const error = this.dialErrorsForPeer.get(peerId.toString());
4289
+ const error = this.dialErrorsForPeer.get(peerIdStr);
2915
4290
  if (error) {
2916
4291
  let errorMessage;
2917
4292
  if (error instanceof AggregateError) {
@@ -2928,16 +4303,52 @@ class ConnectionManager extends TypedEventEmitter {
2928
4303
  else {
2929
4304
  errorMessage = error.message;
2930
4305
  }
2931
- log$1.info(`Deleting undialable peer ${peerId.toString()} from peer store. Reason: ${errorMessage}`);
4306
+ log$1.info(`Deleting undialable peer ${peerIdStr} from peer store. Reason: ${errorMessage}`);
4307
+ }
4308
+ this.dialErrorsForPeer.delete(peerIdStr);
4309
+ if (peerId) {
4310
+ await this.libp2p.peerStore.delete(peerId);
2932
4311
  }
2933
- this.dialErrorsForPeer.delete(peerId.toString());
2934
- await this.libp2p.peerStore.delete(peerId);
2935
4312
  // if it was last available peer - attempt DNS discovery
2936
4313
  await this.attemptDnsDiscovery();
2937
4314
  }
2938
4315
  catch (error) {
2939
- throw new Error(`Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`);
4316
+ throw new Error(`Error deleting undialable peer ${peerIdStr} from peer store - ${error}`);
4317
+ }
4318
+ }
4319
+ if (!connection) {
4320
+ throw new Error(`Failed to dial peer ${peerDialInfo}`);
4321
+ }
4322
+ return connection;
4323
+ }
4324
+ /**
4325
+ * Dial a peer with specific protocols.
4326
+ * This method is a raw proxy to the libp2p dialProtocol method.
4327
+ * @param peer - The peer to connect to, either as a PeerId or multiaddr
4328
+ * @param protocolCodecs - Optional array of protocol-specific codec strings to establish
4329
+ * @returns A stream to the peer
4330
+ */
4331
+ async rawDialPeerWithProtocols(peer, protocolCodecs) {
4332
+ const peerDialInfo = this.getDialablePeerInfo(peer);
4333
+ return await this.libp2p.dialProtocol(peerDialInfo, protocolCodecs);
4334
+ }
4335
+ /**
4336
+ * Internal utility to extract a PeerId or Multiaddr from a peer input.
4337
+ * This is used internally by the connection manager to handle different peer input formats.
4338
+ * @internal
4339
+ */
4340
+ getDialablePeerInfo(peer) {
4341
+ if (isPeerId(peer)) {
4342
+ return peer;
4343
+ }
4344
+ else {
4345
+ // peer is of MultiaddrInput type
4346
+ const ma = multiaddr(peer);
4347
+ const peerIdStr = ma.getPeerId();
4348
+ if (!peerIdStr) {
4349
+ throw new Error("Failed to dial multiaddr: missing peer ID");
2940
4350
  }
4351
+ return ma;
2941
4352
  }
2942
4353
  }
2943
4354
  async attemptDnsDiscovery() {
@@ -3065,7 +4476,7 @@ class ConnectionManager extends TypedEventEmitter {
3065
4476
  const isSameShard = await this.isPeerTopicConfigured(peerId);
3066
4477
  if (!isSameShard) {
3067
4478
  const shardInfo = await this.getPeerShardInfo(peerId, this.libp2p.peerStore);
3068
- log$1.warn(`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${this.configuredPubsubTopics}).
4479
+ log$1.warn(`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${this.pubsubTopics}).
3069
4480
  Not dialing.`);
3070
4481
  return false;
3071
4482
  }
@@ -3126,7 +4537,7 @@ class ConnectionManager extends TypedEventEmitter {
3126
4537
  if (!shardInfo)
3127
4538
  return true;
3128
4539
  const pubsubTopics = shardInfoToPubsubTopics(shardInfo);
3129
- const isTopicConfigured = pubsubTopics.some((topic) => this.configuredPubsubTopics.includes(topic));
4540
+ const isTopicConfigured = pubsubTopics.some((topic) => this.pubsubTopics.includes(topic));
3130
4541
  return isTopicConfigured;
3131
4542
  }
3132
4543
  async getPeerShardInfo(peerId, peerStore) {
@@ -3174,75 +4585,6 @@ class ConnectionManager extends TypedEventEmitter {
3174
4585
  }
3175
4586
  }
3176
4587
 
3177
- class HealthManager {
3178
- static instance;
3179
- health;
3180
- constructor() {
3181
- this.health = {
3182
- overallStatus: HealthStatus.Unhealthy,
3183
- protocolStatuses: new Map()
3184
- };
3185
- }
3186
- static getInstance() {
3187
- if (!HealthManager.instance) {
3188
- HealthManager.instance = new HealthManager();
3189
- }
3190
- return HealthManager.instance;
3191
- }
3192
- getHealthStatus() {
3193
- return this.health.overallStatus;
3194
- }
3195
- getProtocolStatus(protocol) {
3196
- return this.health.protocolStatuses.get(protocol);
3197
- }
3198
- updateProtocolHealth(multicodec, connectedPeers) {
3199
- const protocol = this.getNameFromMulticodec(multicodec);
3200
- let status = HealthStatus.Unhealthy;
3201
- if (connectedPeers == 1) {
3202
- status = HealthStatus.MinimallyHealthy;
3203
- }
3204
- else if (connectedPeers >= 2) {
3205
- status = HealthStatus.SufficientlyHealthy;
3206
- }
3207
- this.health.protocolStatuses.set(protocol, {
3208
- name: protocol,
3209
- status: status,
3210
- lastUpdate: new Date()
3211
- });
3212
- this.updateOverallHealth();
3213
- }
3214
- getNameFromMulticodec(multicodec) {
3215
- let name;
3216
- if (multicodec.includes("filter")) {
3217
- name = Protocols.Filter;
3218
- }
3219
- else if (multicodec.includes("lightpush")) {
3220
- name = Protocols.LightPush;
3221
- }
3222
- else if (multicodec.includes("store")) {
3223
- name = Protocols.Store;
3224
- }
3225
- else {
3226
- throw new Error(`Unknown protocol: ${multicodec}`);
3227
- }
3228
- return name;
3229
- }
3230
- updateOverallHealth() {
3231
- const relevantProtocols = [Protocols.LightPush, Protocols.Filter];
3232
- const statuses = relevantProtocols.map((p) => this.getProtocolStatus(p)?.status);
3233
- if (statuses.some((status) => status === HealthStatus.Unhealthy)) {
3234
- this.health.overallStatus = HealthStatus.Unhealthy;
3235
- }
3236
- else if (statuses.some((status) => status === HealthStatus.MinimallyHealthy)) {
3237
- this.health.overallStatus = HealthStatus.MinimallyHealthy;
3238
- }
3239
- else {
3240
- this.health.overallStatus = HealthStatus.SufficientlyHealthy;
3241
- }
3242
- }
3243
- }
3244
- const getHealthManager = () => HealthManager.getInstance();
3245
-
3246
4588
  const log = new Logger("metadata");
3247
4589
  const MetadataCodec = "/vac/waku/metadata/1.0.0";
3248
4590
  class Metadata extends BaseProtocol {
@@ -3250,7 +4592,7 @@ class Metadata extends BaseProtocol {
3250
4592
  libp2pComponents;
3251
4593
  handshakesConfirmed = new Map();
3252
4594
  constructor(pubsubTopics, libp2p) {
3253
- super(MetadataCodec, libp2p.components, log, pubsubTopics);
4595
+ super(MetadataCodec, libp2p.components, pubsubTopics);
3254
4596
  this.pubsubTopics = pubsubTopics;
3255
4597
  this.libp2pComponents = libp2p;
3256
4598
  void libp2p.registrar.handle(MetadataCodec, (streamData) => {
@@ -3271,7 +4613,7 @@ class Metadata extends BaseProtocol {
3271
4613
  }
3272
4614
  let stream;
3273
4615
  try {
3274
- stream = await this.getStream(peer);
4616
+ stream = await this.getStream(peerId);
3275
4617
  }
3276
4618
  catch (error) {
3277
4619
  log.error("Failed to get stream", error);
@@ -3354,4 +4696,4 @@ function wakuMetadata(pubsubTopics) {
3354
4696
  return (components) => new Metadata(pubsubTopics, components);
3355
4697
  }
3356
4698
 
3357
- export { ConnectionManager, FilterCodecs, FilterCore, KeepAliveManager, LightPushCodec, LightPushCore, MetadataCodec, StoreCore, createEncoder, getHealthManager, index$3 as message, waitForRemotePeer, wakuMetadata, index$2 as waku_filter, index$1 as waku_light_push, index as waku_store };
4699
+ export { ConnectionManager, FilterCodecs, FilterCore, LightPushCodec, LightPushCore, MetadataCodec, StoreCodec, StoreCore, createEncoder, index$3 as message, wakuMetadata, index$2 as waku_filter, index$1 as waku_light_push, index as waku_store };