@waku/core 0.0.34-c43cec2.0 → 0.0.34-caeafce.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 (64) hide show
  1. package/bundle/{base_protocol-DxFKDXX2.js → base_protocol-Bp5a9PNG.js} +19 -20
  2. package/bundle/{index-yLOEQnIE.js → index-G1eRBjeI.js} +115 -84
  3. package/bundle/index.js +1828 -153
  4. package/bundle/lib/base_protocol.js +2 -2
  5. package/bundle/lib/message/version_0.js +2 -2
  6. package/bundle/{version_0-Che4t3mN.js → version_0-DJZG2fB2.js} +163 -42
  7. package/dist/.tsbuildinfo +1 -1
  8. package/dist/index.d.ts +0 -1
  9. package/dist/index.js +0 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/base_protocol.d.ts +2 -2
  12. package/dist/lib/base_protocol.js +2 -2
  13. package/dist/lib/base_protocol.js.map +1 -1
  14. package/dist/lib/connection_manager/connection_manager.d.ts +56 -3
  15. package/dist/lib/connection_manager/connection_manager.js +96 -13
  16. package/dist/lib/connection_manager/connection_manager.js.map +1 -1
  17. package/dist/lib/filter/filter.d.ts +18 -0
  18. package/dist/lib/filter/filter.js +209 -0
  19. package/dist/lib/filter/filter.js.map +1 -0
  20. package/dist/lib/filter/index.d.ts +1 -18
  21. package/dist/lib/filter/index.js +1 -208
  22. package/dist/lib/filter/index.js.map +1 -1
  23. package/dist/lib/light_push/index.d.ts +1 -15
  24. package/dist/lib/light_push/index.js +1 -144
  25. package/dist/lib/light_push/index.js.map +1 -1
  26. package/dist/lib/light_push/light_push.d.ts +15 -0
  27. package/dist/lib/light_push/light_push.js +144 -0
  28. package/dist/lib/light_push/light_push.js.map +1 -0
  29. package/dist/lib/light_push/utils.d.ts +0 -2
  30. package/dist/lib/light_push/utils.js +9 -17
  31. package/dist/lib/light_push/utils.js.map +1 -1
  32. package/dist/lib/metadata/index.d.ts +1 -3
  33. package/dist/lib/metadata/index.js +1 -118
  34. package/dist/lib/metadata/index.js.map +1 -1
  35. package/dist/lib/metadata/metadata.d.ts +3 -0
  36. package/dist/lib/metadata/metadata.js +119 -0
  37. package/dist/lib/metadata/metadata.js.map +1 -0
  38. package/dist/lib/store/index.d.ts +1 -9
  39. package/dist/lib/store/index.js +1 -82
  40. package/dist/lib/store/index.js.map +1 -1
  41. package/dist/lib/store/store.d.ts +9 -0
  42. package/dist/lib/store/store.js +83 -0
  43. package/dist/lib/store/store.js.map +1 -0
  44. package/dist/lib/stream_manager/stream_manager.d.ts +2 -2
  45. package/dist/lib/stream_manager/stream_manager.js +16 -17
  46. package/dist/lib/stream_manager/stream_manager.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/index.ts +0 -2
  49. package/src/lib/base_protocol.ts +3 -3
  50. package/src/lib/connection_manager/connection_manager.ts +114 -20
  51. package/src/lib/filter/filter.ts +315 -0
  52. package/src/lib/filter/index.ts +1 -315
  53. package/src/lib/light_push/index.ts +1 -189
  54. package/src/lib/light_push/light_push.ts +188 -0
  55. package/src/lib/light_push/utils.ts +13 -21
  56. package/src/lib/metadata/index.ts +1 -182
  57. package/src/lib/metadata/metadata.ts +182 -0
  58. package/src/lib/store/index.ts +1 -136
  59. package/src/lib/store/store.ts +136 -0
  60. package/src/lib/stream_manager/stream_manager.ts +16 -18
  61. package/dist/lib/health_manager.d.ts +0 -14
  62. package/dist/lib/health_manager.js +0 -70
  63. package/dist/lib/health_manager.js.map +0 -1
  64. package/src/lib/health_manager.ts +0 -90
@@ -1,5 +1,14 @@
1
- import type { Peer, PeerId, PeerInfo, PeerStore } from "@libp2p/interface";
2
- import { TypedEventEmitter } from "@libp2p/interface";
1
+ import {
2
+ type Connection,
3
+ isPeerId,
4
+ type Peer,
5
+ type PeerId,
6
+ type PeerInfo,
7
+ type PeerStore,
8
+ type Stream,
9
+ TypedEventEmitter
10
+ } from "@libp2p/interface";
11
+ import { Multiaddr, multiaddr, MultiaddrInput } from "@multiformats/multiaddr";
3
12
  import {
4
13
  ConnectionManagerOptions,
5
14
  DiscoveryTrigger,
@@ -230,15 +239,60 @@ export class ConnectionManager
230
239
  this.startNetworkStatusListener();
231
240
  }
232
241
 
233
- private async dialPeer(peerId: PeerId): Promise<void> {
242
+ /**
243
+ * Attempts to establish a connection with a peer and set up specified protocols.
244
+ * The method handles both PeerId and Multiaddr inputs, manages connection attempts,
245
+ * and maintains the connection state.
246
+ *
247
+ * The dialing process includes:
248
+ * 1. Converting input to dialable peer info
249
+ * 2. Managing parallel dial attempts
250
+ * 3. Attempting to establish protocol-specific connections
251
+ * 4. Handling connection failures and retries
252
+ * 5. Updating the peer store and connection state
253
+ *
254
+ * @param {PeerId | MultiaddrInput} peer - The peer to connect to, either as a PeerId or multiaddr
255
+ * @param {string[]} [protocolCodecs] - Optional array of protocol-specific codec strings to establish
256
+ * (e.g., for LightPush, Filter, Store protocols)
257
+ *
258
+ * @throws {Error} If the multiaddr is missing a peer ID
259
+ * @throws {Error} If the maximum dial attempts are reached and the peer cannot be dialed
260
+ * @throws {Error} If there's an error deleting an undialable peer from the peer store
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * // Dial using PeerId
265
+ * await connectionManager.dialPeer(peerId);
266
+ *
267
+ * // Dial using multiaddr with specific protocols
268
+ * await connectionManager.dialPeer(multiaddr, [
269
+ * "/vac/waku/relay/2.0.0",
270
+ * "/vac/waku/lightpush/2.0.0-beta1"
271
+ * ]);
272
+ * ```
273
+ *
274
+ * @remarks
275
+ * - The method implements exponential backoff through multiple dial attempts
276
+ * - Maintains a queue for parallel dial attempts (limited by maxParallelDials)
277
+ * - Integrates with the KeepAliveManager for connection maintenance
278
+ * - Updates the peer store and connection state after successful/failed attempts
279
+ * - If all dial attempts fail, triggers DNS discovery as a fallback
280
+ */
281
+ public async dialPeer(peer: PeerId | MultiaddrInput): Promise<Connection> {
282
+ let connection: Connection | undefined;
283
+ let peerId: PeerId | undefined;
284
+ const peerDialInfo = this.getDialablePeerInfo(peer);
285
+ const peerIdStr = isPeerId(peerDialInfo)
286
+ ? peerDialInfo.toString()
287
+ : peerDialInfo.getPeerId()!;
288
+
234
289
  this.currentActiveParallelDialCount += 1;
235
290
  let dialAttempt = 0;
236
291
  while (dialAttempt < this.options.maxDialAttemptsForPeer) {
237
292
  try {
238
- log.info(
239
- `Dialing peer ${peerId.toString()} on attempt ${dialAttempt + 1}`
240
- );
241
- await this.libp2p.dial(peerId);
293
+ log.info(`Dialing peer ${peerDialInfo} on attempt ${dialAttempt + 1}`);
294
+ connection = await this.libp2p.dial(peerDialInfo);
295
+ peerId = connection.remotePeer;
242
296
 
243
297
  const tags = await this.getTagNamesForPeer(peerId);
244
298
  // add tag to connection describing discovery mechanism
@@ -257,21 +311,17 @@ export class ConnectionManager
257
311
  } catch (error) {
258
312
  if (error instanceof AggregateError) {
259
313
  // Handle AggregateError
260
- log.error(
261
- `Error dialing peer ${peerId.toString()} - ${error.errors}`
262
- );
314
+ log.error(`Error dialing peer ${peerIdStr} - ${error.errors}`);
263
315
  } else {
264
316
  // Handle generic error
265
317
  log.error(
266
- `Error dialing peer ${peerId.toString()} - ${
267
- (error as any).message
268
- }`
318
+ `Error dialing peer ${peerIdStr} - ${(error as any).message}`
269
319
  );
270
320
  }
271
- this.dialErrorsForPeer.set(peerId.toString(), error);
321
+ this.dialErrorsForPeer.set(peerIdStr, error);
272
322
 
273
323
  dialAttempt++;
274
- this.dialAttemptsForPeer.set(peerId.toString(), dialAttempt);
324
+ this.dialAttemptsForPeer.set(peerIdStr, dialAttempt);
275
325
  }
276
326
  }
277
327
 
@@ -282,7 +332,7 @@ export class ConnectionManager
282
332
  // If max dial attempts reached and dialing failed, delete the peer
283
333
  if (dialAttempt === this.options.maxDialAttemptsForPeer) {
284
334
  try {
285
- const error = this.dialErrorsForPeer.get(peerId.toString());
335
+ const error = this.dialErrorsForPeer.get(peerIdStr);
286
336
 
287
337
  if (error) {
288
338
  let errorMessage;
@@ -299,21 +349,65 @@ export class ConnectionManager
299
349
  }
300
350
 
301
351
  log.info(
302
- `Deleting undialable peer ${peerId.toString()} from peer store. Reason: ${errorMessage}`
352
+ `Deleting undialable peer ${peerIdStr} from peer store. Reason: ${errorMessage}`
303
353
  );
304
354
  }
305
355
 
306
- this.dialErrorsForPeer.delete(peerId.toString());
307
- await this.libp2p.peerStore.delete(peerId);
356
+ this.dialErrorsForPeer.delete(peerIdStr);
357
+ if (peerId) {
358
+ await this.libp2p.peerStore.delete(peerId);
359
+ }
308
360
 
309
361
  // if it was last available peer - attempt DNS discovery
310
362
  await this.attemptDnsDiscovery();
311
363
  } catch (error) {
312
364
  throw new Error(
313
- `Error deleting undialable peer ${peerId.toString()} from peer store - ${error}`
365
+ `Error deleting undialable peer ${peerIdStr} from peer store - ${error}`
314
366
  );
315
367
  }
316
368
  }
369
+
370
+ if (!connection) {
371
+ throw new Error(`Failed to dial peer ${peerDialInfo}`);
372
+ }
373
+
374
+ return connection;
375
+ }
376
+
377
+ /**
378
+ * Dial a peer with specific protocols.
379
+ * This method is a raw proxy to the libp2p dialProtocol method.
380
+ * @param peer - The peer to connect to, either as a PeerId or multiaddr
381
+ * @param protocolCodecs - Optional array of protocol-specific codec strings to establish
382
+ * @returns A stream to the peer
383
+ */
384
+ public async rawDialPeerWithProtocols(
385
+ peer: PeerId | MultiaddrInput,
386
+ protocolCodecs: string[]
387
+ ): Promise<Stream> {
388
+ const peerDialInfo = this.getDialablePeerInfo(peer);
389
+ return await this.libp2p.dialProtocol(peerDialInfo, protocolCodecs);
390
+ }
391
+
392
+ /**
393
+ * Internal utility to extract a PeerId or Multiaddr from a peer input.
394
+ * This is used internally by the connection manager to handle different peer input formats.
395
+ * @internal
396
+ */
397
+ private getDialablePeerInfo(
398
+ peer: PeerId | MultiaddrInput
399
+ ): PeerId | Multiaddr {
400
+ if (isPeerId(peer)) {
401
+ return peer;
402
+ } else {
403
+ // peer is of MultiaddrInput type
404
+ const ma = multiaddr(peer);
405
+ const peerIdStr = ma.getPeerId();
406
+ if (!peerIdStr) {
407
+ throw new Error("Failed to dial multiaddr: missing peer ID");
408
+ }
409
+ return ma;
410
+ }
317
411
  }
318
412
 
319
413
  private async attemptDnsDiscovery(): Promise<void> {
@@ -0,0 +1,315 @@
1
+ import type { PeerId, Stream } from "@libp2p/interface";
2
+ import type { IncomingStreamData } from "@libp2p/interface-internal";
3
+ import {
4
+ type ContentTopic,
5
+ type CoreProtocolResult,
6
+ type IBaseProtocolCore,
7
+ type Libp2p,
8
+ ProtocolError,
9
+ type PubsubTopic
10
+ } from "@waku/interfaces";
11
+ import { WakuMessage } from "@waku/proto";
12
+ import { Logger } from "@waku/utils";
13
+ import all from "it-all";
14
+ import * as lp from "it-length-prefixed";
15
+ import { pipe } from "it-pipe";
16
+ import { Uint8ArrayList } from "uint8arraylist";
17
+
18
+ import { BaseProtocol } from "../base_protocol.js";
19
+
20
+ import {
21
+ FilterPushRpc,
22
+ FilterSubscribeResponse,
23
+ FilterSubscribeRpc
24
+ } from "./filter_rpc.js";
25
+
26
+ const log = new Logger("filter:v2");
27
+
28
+ export const FilterCodecs = {
29
+ SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
30
+ PUSH: "/vac/waku/filter-push/2.0.0-beta1"
31
+ };
32
+
33
+ export class FilterCore extends BaseProtocol implements IBaseProtocolCore {
34
+ public constructor(
35
+ private handleIncomingMessage: (
36
+ pubsubTopic: PubsubTopic,
37
+ wakuMessage: WakuMessage,
38
+ peerIdStr: string
39
+ ) => Promise<void>,
40
+ public readonly pubsubTopics: PubsubTopic[],
41
+ libp2p: Libp2p
42
+ ) {
43
+ super(FilterCodecs.SUBSCRIBE, libp2p.components, pubsubTopics);
44
+
45
+ libp2p
46
+ .handle(FilterCodecs.PUSH, this.onRequest.bind(this), {
47
+ maxInboundStreams: 100
48
+ })
49
+ .catch((e) => {
50
+ log.error("Failed to register ", FilterCodecs.PUSH, e);
51
+ });
52
+ }
53
+
54
+ public async subscribe(
55
+ pubsubTopic: PubsubTopic,
56
+ peerId: PeerId,
57
+ contentTopics: ContentTopic[]
58
+ ): Promise<CoreProtocolResult> {
59
+ const stream = await this.getStream(peerId);
60
+
61
+ const request = FilterSubscribeRpc.createSubscribeRequest(
62
+ pubsubTopic,
63
+ contentTopics
64
+ );
65
+
66
+ let res: Uint8ArrayList[] | undefined;
67
+ try {
68
+ res = await pipe(
69
+ [request.encode()],
70
+ lp.encode,
71
+ stream,
72
+ lp.decode,
73
+ async (source) => await all(source)
74
+ );
75
+ } catch (error) {
76
+ log.error("Failed to send subscribe request", error);
77
+ return {
78
+ success: null,
79
+ failure: {
80
+ error: ProtocolError.GENERIC_FAIL,
81
+ peerId: peerId
82
+ }
83
+ };
84
+ }
85
+
86
+ const { statusCode, requestId, statusDesc } =
87
+ FilterSubscribeResponse.decode(res[0].slice());
88
+
89
+ if (statusCode < 200 || statusCode >= 300) {
90
+ log.error(
91
+ `Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
92
+ );
93
+ return {
94
+ failure: {
95
+ error: ProtocolError.REMOTE_PEER_REJECTED,
96
+ peerId: peerId
97
+ },
98
+ success: null
99
+ };
100
+ }
101
+
102
+ return {
103
+ failure: null,
104
+ success: peerId
105
+ };
106
+ }
107
+
108
+ public async unsubscribe(
109
+ pubsubTopic: PubsubTopic,
110
+ peerId: PeerId,
111
+ contentTopics: ContentTopic[]
112
+ ): Promise<CoreProtocolResult> {
113
+ let stream: Stream | undefined;
114
+ try {
115
+ stream = await this.getStream(peerId);
116
+ } catch (error) {
117
+ log.error(
118
+ `Failed to get a stream for remote peer${peerId.toString()}`,
119
+ error
120
+ );
121
+ return {
122
+ success: null,
123
+ failure: {
124
+ error: ProtocolError.NO_STREAM_AVAILABLE,
125
+ peerId: peerId
126
+ }
127
+ };
128
+ }
129
+
130
+ const unsubscribeRequest = FilterSubscribeRpc.createUnsubscribeRequest(
131
+ pubsubTopic,
132
+ contentTopics
133
+ );
134
+
135
+ try {
136
+ await pipe([unsubscribeRequest.encode()], lp.encode, stream.sink);
137
+ } catch (error) {
138
+ log.error("Failed to send unsubscribe request", error);
139
+ return {
140
+ success: null,
141
+ failure: {
142
+ error: ProtocolError.GENERIC_FAIL,
143
+ peerId: peerId
144
+ }
145
+ };
146
+ }
147
+
148
+ return {
149
+ success: peerId,
150
+ failure: null
151
+ };
152
+ }
153
+
154
+ public async unsubscribeAll(
155
+ pubsubTopic: PubsubTopic,
156
+ peerId: PeerId
157
+ ): Promise<CoreProtocolResult> {
158
+ const stream = await this.getStream(peerId);
159
+
160
+ const request = FilterSubscribeRpc.createUnsubscribeAllRequest(pubsubTopic);
161
+
162
+ const res = await pipe(
163
+ [request.encode()],
164
+ lp.encode,
165
+ stream,
166
+ lp.decode,
167
+ async (source) => await all(source)
168
+ );
169
+
170
+ if (!res || !res.length) {
171
+ return {
172
+ failure: {
173
+ error: ProtocolError.NO_RESPONSE,
174
+ peerId: peerId
175
+ },
176
+ success: null
177
+ };
178
+ }
179
+
180
+ const { statusCode, requestId, statusDesc } =
181
+ FilterSubscribeResponse.decode(res[0].slice());
182
+
183
+ if (statusCode < 200 || statusCode >= 300) {
184
+ log.error(
185
+ `Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
186
+ );
187
+ return {
188
+ failure: {
189
+ error: ProtocolError.REMOTE_PEER_REJECTED,
190
+ peerId: peerId
191
+ },
192
+ success: null
193
+ };
194
+ }
195
+
196
+ return {
197
+ failure: null,
198
+ success: peerId
199
+ };
200
+ }
201
+
202
+ public async ping(peerId: PeerId): Promise<CoreProtocolResult> {
203
+ let stream: Stream | undefined;
204
+ try {
205
+ stream = await this.getStream(peerId);
206
+ } catch (error) {
207
+ log.error(
208
+ `Failed to get a stream for remote peer${peerId.toString()}`,
209
+ error
210
+ );
211
+ return {
212
+ success: null,
213
+ failure: {
214
+ error: ProtocolError.NO_STREAM_AVAILABLE,
215
+ peerId: peerId
216
+ }
217
+ };
218
+ }
219
+
220
+ const request = FilterSubscribeRpc.createSubscriberPingRequest();
221
+
222
+ let res: Uint8ArrayList[] | undefined;
223
+ try {
224
+ res = await pipe(
225
+ [request.encode()],
226
+ lp.encode,
227
+ stream,
228
+ lp.decode,
229
+ async (source) => await all(source)
230
+ );
231
+ } catch (error) {
232
+ log.error("Failed to send ping request", error);
233
+ return {
234
+ success: null,
235
+ failure: {
236
+ error: ProtocolError.GENERIC_FAIL,
237
+ peerId: peerId
238
+ }
239
+ };
240
+ }
241
+
242
+ if (!res || !res.length) {
243
+ return {
244
+ success: null,
245
+ failure: {
246
+ error: ProtocolError.NO_RESPONSE,
247
+ peerId: peerId
248
+ }
249
+ };
250
+ }
251
+
252
+ const { statusCode, requestId, statusDesc } =
253
+ FilterSubscribeResponse.decode(res[0].slice());
254
+
255
+ if (statusCode < 200 || statusCode >= 300) {
256
+ log.error(
257
+ `Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`
258
+ );
259
+ return {
260
+ success: null,
261
+ failure: {
262
+ error: ProtocolError.REMOTE_PEER_REJECTED,
263
+ peerId: peerId
264
+ }
265
+ };
266
+ }
267
+ return {
268
+ success: peerId,
269
+ failure: null
270
+ };
271
+ }
272
+
273
+ private onRequest(streamData: IncomingStreamData): void {
274
+ const { connection, stream } = streamData;
275
+ const { remotePeer } = connection;
276
+ log.info(`Received message from ${remotePeer.toString()}`);
277
+ try {
278
+ pipe(stream, lp.decode, async (source) => {
279
+ for await (const bytes of source) {
280
+ const response = FilterPushRpc.decode(bytes.slice());
281
+
282
+ const { pubsubTopic, wakuMessage } = response;
283
+
284
+ if (!wakuMessage) {
285
+ log.error("Received empty message");
286
+ return;
287
+ }
288
+
289
+ if (!pubsubTopic) {
290
+ log.error("Pubsub topic missing from push message");
291
+ return;
292
+ }
293
+
294
+ await this.handleIncomingMessage(
295
+ pubsubTopic,
296
+ wakuMessage,
297
+ connection.remotePeer.toString()
298
+ );
299
+ }
300
+ }).then(
301
+ () => {
302
+ log.info("Receiving pipe closed.");
303
+ },
304
+ async (e) => {
305
+ log.error(
306
+ `Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `,
307
+ e
308
+ );
309
+ }
310
+ );
311
+ } catch (e) {
312
+ log.error("Error decoding message", e);
313
+ }
314
+ }
315
+ }