helia-coord 1.9.1 → 1.9.2

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.
@@ -81,7 +81,10 @@ class CreateHeliaNode {
81
81
  // Configure services
82
82
  const services = {
83
83
  identify: identify(),
84
- pubsub: gossipsub({ allowPublishToZeroTopicPeers: true })
84
+ pubsub: gossipsub({
85
+ allowPublishToZeroTopicPeers: true,
86
+ emitSelf: true // Enable receiving own messages for testing
87
+ })
85
88
  }
86
89
 
87
90
  // libp2p is the networking layer that underpins Helia
@@ -26,7 +26,7 @@ async function start () {
26
26
  type: 'node.js',
27
27
  // type: 'browser'
28
28
  nodeType: 'external',
29
- debugLevel: 2
29
+ debugLevel: 3
30
30
  })
31
31
 
32
32
  await ipfsCoord.start()
@@ -15,7 +15,10 @@ class PubsubAdapter {
15
15
  // Dependency Injection
16
16
  this.ipfs = localConfig.ipfsAdapter
17
17
  if (!this.ipfs) {
18
- console.log('this.ipfs: ', this.ipfs)
18
+ // Only log if log is available (may not be during construction)
19
+ if (this.log) {
20
+ this.log.statusLog(3, `this.ipfs: ${this.ipfs}`)
21
+ }
19
22
  throw new Error(
20
23
  'Instance of IPFS adapter required when instantiating Pubsub Adapter.'
21
24
  )
@@ -89,13 +92,14 @@ class PubsubAdapter {
89
92
 
90
93
  throw new Error('Pubsub service not initialized. Ensure gossipsub is configured in libp2p services.')
91
94
  } catch (err) {
95
+ this.log.statusLog(1, `Error getting pubsub service: ${err.message}`)
92
96
  console.error('Error getting pubsub service:', err)
93
97
  throw err
94
98
  }
95
99
  }
96
100
 
97
101
  // Set up a single global message listener that routes to topic-specific handlers
98
- _setupGlobalMessageListener () {
102
+ async _setupGlobalMessageListener () {
99
103
  if (this._globalListenerSetup) {
100
104
  this.log.statusLog(3, 'Global message listener already set up, skipping')
101
105
  return
@@ -104,19 +108,73 @@ class PubsubAdapter {
104
108
  try {
105
109
  const pubsub = this._getPubsubService()
106
110
 
111
+ this.log.statusLog(3, `Pubsub service: ${pubsub.constructor?.name || 'unknown'}, type: ${typeof pubsub}`)
112
+ this.log.statusLog(3, `Has addEventListener: ${typeof pubsub.addEventListener}, has on: ${typeof pubsub.on}`)
113
+
107
114
  this.log.statusLog(2, 'Setting up global pubsub message listener...')
108
115
 
109
- // Set up a single event listener for all messages
110
- pubsub.addEventListener('message', (event) => {
111
- this.log.statusLog(3, 'Pubsub message event received')
112
- this._routeMessage(event)
113
- })
116
+ // Try multiple event listener patterns for compatibility
117
+ let listenerAttached = false
118
+
119
+ // Check if service is started (it's a property, not a method)
120
+ // Services are typically started automatically by libp2p, but verify
121
+ if (pubsub.isStarted === false && typeof pubsub.start === 'function') {
122
+ this.log.statusLog(2, 'Pubsub service not started, starting...')
123
+ await pubsub.start()
124
+ this.log.statusLog(2, 'Pubsub service started')
125
+ }
126
+
127
+ // Pattern 1: addEventListener (EventTarget pattern) - for 'message' event
128
+ if (typeof pubsub.addEventListener === 'function') {
129
+ this.log.statusLog(3, 'Using addEventListener pattern for "message" event')
130
+ const messageHandler = (event) => {
131
+ this.log.statusLog(3, `Pubsub message event received (addEventListener), topic: ${event.detail?.topic || 'unknown'}`)
132
+ this._routeMessage(event)
133
+ }
134
+ pubsub.addEventListener('message', messageHandler)
135
+ // Store handler reference for potential cleanup
136
+ this._messageHandler = messageHandler
137
+ listenerAttached = true
138
+ this.log.statusLog(3, 'addEventListener attached successfully')
139
+ }
140
+
141
+ // Pattern 2: on() method (EventEmitter pattern) - for 'message' event
142
+ if (typeof pubsub.on === 'function') {
143
+ this.log.statusLog(3, 'Using on() pattern for "message" event')
144
+ pubsub.on('message', (event) => {
145
+ this.log.statusLog(3, `Pubsub message event received (on), topic: ${event.detail?.topic || 'unknown'}`)
146
+ this._routeMessage(event)
147
+ })
148
+ listenerAttached = true
149
+ }
150
+
151
+ // Pattern 3: Also listen for 'gossipsub:message' event (gossipsub-specific)
152
+ if (typeof pubsub.addEventListener === 'function') {
153
+ this.log.statusLog(3, 'Also listening for "gossipsub:message" event')
154
+ const gossipsubMessageHandler = (event) => {
155
+ // Convert gossipsub:message to message format
156
+ if (event.detail?.msg) {
157
+ const convertedEvent = {
158
+ detail: event.detail.msg
159
+ }
160
+ this.log.statusLog(3, `Pubsub gossipsub:message event received, converting, topic: ${event.detail.msg?.topic || 'unknown'}`)
161
+ this._routeMessage(convertedEvent)
162
+ }
163
+ }
164
+ pubsub.addEventListener('gossipsub:message', gossipsubMessageHandler)
165
+ this._gossipsubMessageHandler = gossipsubMessageHandler
166
+ this.log.statusLog(3, 'gossipsub:message listener attached successfully')
167
+ }
168
+
169
+ if (!listenerAttached) {
170
+ throw new Error('No supported event listener method found on pubsub service')
171
+ }
114
172
 
115
173
  this._globalListenerSetup = true
116
174
  this.log.statusLog(0, 'Global pubsub message listener successfully set up')
117
175
  } catch (err) {
118
- console.error('Error setting up global message listener:', err)
119
176
  this.log.statusLog(1, `Error setting up global message listener: ${err.message}`)
177
+ console.error('Error setting up global message listener:', err)
120
178
  throw err
121
179
  }
122
180
  }
@@ -124,13 +182,12 @@ class PubsubAdapter {
124
182
  // Route incoming messages to the appropriate handler based on topic
125
183
  async _routeMessage (event) {
126
184
  try {
127
- // Handle both event.detail and direct event properties
128
- // In libp2p v3/gossipsub, events typically have event.detail structure
129
- // Extract the message data - prefer event.detail if it exists
130
- const msgDetail = event.detail || event
185
+ // In Helia v6/gossipsub, the 'message' event has event.detail as the Message object directly
186
+ // Message structure: { type: 'signed'|'unsigned', topic: string, data: Uint8Array, from?: PeerId, sequenceNumber?: bigint, ... }
187
+ const message = event.detail || event
131
188
 
132
- // Extract topic - check multiple possible locations
133
- const topic = msgDetail.topic || event.topic
189
+ // Extract topic from the Message object
190
+ const topic = message.topic
134
191
 
135
192
  if (!topic) {
136
193
  this.log.statusLog(1, `Received pubsub message without topic. Event keys: ${Object.keys(event).join(', ')}`)
@@ -143,14 +200,14 @@ class PubsubAdapter {
143
200
  const handler = this.topicHandlers.get(topic)
144
201
 
145
202
  if (handler) {
146
- // Wrap event in expected format (msg.detail structure)
147
- // Ensure we have the proper structure that existing handlers expect
203
+ // Wrap message in expected format (msg.detail structure) for backward compatibility
204
+ // The existing handlers expect: { detail: { topic, from, data, sequenceNumber } }
148
205
  const wrappedEvent = {
149
206
  detail: {
150
- topic,
151
- from: msgDetail.from || event.from,
152
- data: msgDetail.data || event.data,
153
- sequenceNumber: msgDetail.sequenceNumber || event.sequenceNumber
207
+ topic: message.topic,
208
+ from: message.from, // PeerId object
209
+ data: message.data, // Uint8Array
210
+ sequenceNumber: message.sequenceNumber // bigint
154
211
  }
155
212
  }
156
213
 
@@ -163,8 +220,8 @@ class PubsubAdapter {
163
220
  this.log.statusLog(3, `No handler registered for topic: ${topic}. Registered topics: ${Array.from(this.topicHandlers.keys()).join(', ')}`)
164
221
  }
165
222
  } catch (err) {
166
- console.error('Error routing pubsub message:', err)
167
223
  this.log.statusLog(1, `Error routing pubsub message: ${err.message}`)
224
+ console.error('Error routing pubsub message:', err)
168
225
  }
169
226
  }
170
227
 
@@ -179,7 +236,7 @@ class PubsubAdapter {
179
236
  async subscribeToPubsubChannel (chanName, handler, thisNode) {
180
237
  try {
181
238
  // Ensure global listener is set up
182
- this._setupGlobalMessageListener()
239
+ await this._setupGlobalMessageListener()
183
240
 
184
241
  // Get and validate pubsub service
185
242
  const pubsub = this._getPubsubService()
@@ -232,8 +289,8 @@ class PubsubAdapter {
232
289
 
233
290
  return true
234
291
  } catch (err) {
235
- console.error('Error in subscribeToPubsubChannel():', err)
236
292
  this.log.statusLog(1, `Error subscribing to pubsub channel ${chanName}: ${err.message}`)
293
+ console.error('Error in subscribeToPubsubChannel():', err)
237
294
  throw err
238
295
  }
239
296
  }
@@ -246,7 +303,7 @@ class PubsubAdapter {
246
303
  const { chanName, handler } = inObj
247
304
 
248
305
  // Ensure global listener is set up
249
- this._setupGlobalMessageListener()
306
+ await this._setupGlobalMessageListener()
250
307
 
251
308
  // Get and validate pubsub service
252
309
  const pubsub = this._getPubsubService()
@@ -263,8 +320,8 @@ class PubsubAdapter {
263
320
 
264
321
  return true
265
322
  } catch (err) {
266
- console.error('Error in subscribeToCoordChannel():', err)
267
323
  this.log.statusLog(1, `Error subscribing to coordination channel: ${err.message}`)
324
+ console.error('Error in subscribeToCoordChannel():', err)
268
325
  throw err
269
326
  }
270
327
  }
@@ -294,7 +351,8 @@ class PubsubAdapter {
294
351
 
295
352
  return false
296
353
  } catch (err) {
297
- console.error('Error in handleNewMessage()')
354
+ this.log.statusLog(1, `Error in handleNewMessage(): ${err.message}`)
355
+ console.error('Error in handleNewMessage()', err)
298
356
  throw err
299
357
  }
300
358
  }
@@ -340,9 +398,9 @@ class PubsubAdapter {
340
398
  }
341
399
 
342
400
  // This is not an /about JSON RPC query.
343
- // console.log('JSON RPC is not targeting the /about endpoint')
344
401
  return false
345
402
  } catch (err) {
403
+ this.log.statusLog(1, `Error in captureMetrics: ${err.message}`)
346
404
  console.error('Error in captureMetrics: ', err)
347
405
  return false
348
406
  }
@@ -404,8 +462,8 @@ class PubsubAdapter {
404
462
 
405
463
  return true
406
464
  } catch (err) {
407
- console.error('Error in parsePubsubMessage(): ', err.message)
408
465
  this.log.statusLog(2, `Error in parsePubsubMessage(): ${err.message}`)
466
+ console.error('Error in parsePubsubMessage(): ', err)
409
467
  // Do not throw an error. This is a top-level function.
410
468
 
411
469
  return false
@@ -453,14 +511,21 @@ class PubsubAdapter {
453
511
  const topics = pubsub.getTopics ? pubsub.getTopics() : []
454
512
  const registeredHandlers = Array.from(this.topicHandlers.keys())
455
513
 
514
+ // Log debug info at level 2
515
+ this.log.statusLog(2, `Pubsub service available: ${!!pubsub}, listener setup: ${this._globalListenerSetup}, topics: ${topics.length}, handlers: ${this.topicHandlers.size}`)
516
+
456
517
  return {
457
518
  serviceAvailable: true,
458
519
  globalListenerSetup: this._globalListenerSetup,
459
520
  subscribedTopics: topics,
460
521
  registeredHandlers,
461
- handlerCount: this.topicHandlers.size
522
+ handlerCount: this.topicHandlers.size,
523
+ hasAddEventListener: typeof pubsub.addEventListener === 'function',
524
+ hasOn: typeof pubsub.on === 'function'
462
525
  }
463
526
  } catch (err) {
527
+ this.log.statusLog(1, `Error in getPubsubStatus: ${err.message}`)
528
+ console.error('Error in getPubsubStatus:', err)
464
529
  return {
465
530
  serviceAvailable: false,
466
531
  error: err.message,
@@ -74,7 +74,8 @@ class Messaging {
74
74
 
75
75
  return true
76
76
  } catch (err) {
77
- console.error('Error in messaging.js/sendMsg()')
77
+ this.log.statusLog(1, `Error in messaging.js/sendMsg(): ${err.message}`)
78
+ console.error('Error in messaging.js/sendMsg()', err)
78
79
  throw err
79
80
  }
80
81
  }
@@ -90,12 +91,13 @@ class Messaging {
90
91
 
91
92
  return true
92
93
  } catch (err) {
93
- console.error('Error in sendAck()')
94
+ this.log.statusLog(1, `Error in sendAck(): ${err.message}`)
95
+ console.error('Error in sendAck()', err)
94
96
  throw err
95
97
  }
96
98
  }
97
99
 
98
- // A handler function that is called when a new message is recieved on the
100
+ // A handler function that is called when a new message is received on the
99
101
  // pubsub channel for this IPFS node. It does the following:
100
102
  // - Decrypts the message.
101
103
  // - Sends an ACK message to the sender of the message.
@@ -180,6 +182,7 @@ class Messaging {
180
182
 
181
183
  return retObj
182
184
  } catch (err) {
185
+ this.log.statusLog(1, `Error in handleIncomingData(): ${err.message}`)
183
186
  console.error('Error in helia-coord/lib/adpaters/pubsub-adapter/messaging.js/handleIncomingData(): ', err)
184
187
 
185
188
  // Do not throw an error. This is a top-level function called by an Interval.
@@ -218,7 +221,8 @@ class Messaging {
218
221
 
219
222
  return outMsgObj
220
223
  } catch (err) {
221
- console.log('Error in generateMsgObj()')
224
+ this.log.statusLog(1, `Error in generateMsgObj(): ${err.message}`)
225
+ console.error('Error in generateMsgObj()', err)
222
226
  throw err
223
227
  }
224
228
  }
@@ -240,7 +244,7 @@ class Messaging {
240
244
  // 3/24/24 CT - Debugging issue with passing data between ipfs-bch-wallet
241
245
  // -service and -consumer.
242
246
  if (!peerData || !peerData[0] || !peerData[0].data) {
243
- console.log(`peerData[0]: ${JSON.stringify(peerData[0])}`)
247
+ this.log.statusLog(3, `peerData[0]: ${JSON.stringify(peerData[0])}`)
244
248
  throw new Error('Required encryption information for peer is not available.')
245
249
  }
246
250
 
@@ -274,6 +278,7 @@ class Messaging {
274
278
 
275
279
  return outMsgObj
276
280
  } catch (err) {
281
+ this.log.statusLog(1, `Error in generateAckMsg(): ${err.message}`)
277
282
  console.error('Error in generateAckMsg()', err)
278
283
  throw err
279
284
  }
@@ -302,6 +307,7 @@ class Messaging {
302
307
 
303
308
  throw new Error('Pubsub service not initialized. Ensure gossipsub is configured in libp2p services.')
304
309
  } catch (err) {
310
+ this.log.statusLog(1, `Error getting pubsub service: ${err.message}`)
305
311
  console.error('Error getting pubsub service:', err)
306
312
  throw err
307
313
  }
@@ -335,8 +341,8 @@ class Messaging {
335
341
 
336
342
  return true
337
343
  } catch (err) {
338
- console.error('Error in publishToPubsubChannel():', err)
339
344
  this.log.statusLog(1, `Error publishing to channel ${chanName}: ${err.message}`)
345
+ console.error('Error in publishToPubsubChannel():', err)
340
346
  throw err
341
347
  }
342
348
  }
@@ -410,7 +416,8 @@ class Messaging {
410
416
 
411
417
  return msgObj
412
418
  } catch (err) {
413
- console.error('Error in addMsgToQueue')
419
+ this.log.statusLog(1, `Error in addMsgToQueue: ${err.message}`)
420
+ console.error('Error in addMsgToQueue', err)
414
421
  throw err
415
422
  }
416
423
  }
@@ -21,7 +21,11 @@ class ResendMsg {
21
21
  // console.log(`resendMsg() msgObj: ${JSON.stringify(msgObj, null, 2)}`)
22
22
 
23
23
  if (!this.msgObj) {
24
- console.log('ipfs-coord-esm/lib/adapters/pubsub-adapter/resend-msg.js/resend() given empty message object. Can not resend message. Skipping.')
24
+ if (this.msgLib?.log) {
25
+ this.msgLib.log.statusLog(3, 'resend() given empty message object. Can not resend message. Skipping.')
26
+ } else {
27
+ console.log('ipfs-coord-esm/lib/adapters/pubsub-adapter/resend-msg.js/resend() given empty message object. Can not resend message. Skipping.')
28
+ }
25
29
  return 0
26
30
  }
27
31
 
@@ -48,6 +52,9 @@ class ResendMsg {
48
52
  return 2
49
53
  }
50
54
  } catch (err) {
55
+ if (this.msgLib?.log) {
56
+ this.msgLib.log.statusLog(1, `Error in resendMsg(): ${err.message}`)
57
+ }
51
58
  console.error('Error in resendMsg(): ', err)
52
59
  // Do not throw an error. This is a top-level function called by an Interval.
53
60
  return 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helia-coord",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "A JS library for helping IPFS peers coordinate, find a common interest, and stay connected around that interest.",
5
5
  "main": "./index.js",
6
6
  "type": "module",
@@ -37,7 +37,7 @@
37
37
  "cross-env": "7.0.3",
38
38
  "datastore-fs": "10.0.2",
39
39
  "delay": "6.0.0",
40
- "helia": "5.2.1",
40
+ "helia": "6.0.16",
41
41
  "lodash.clonedeep": "4.5.0",
42
42
  "minimal-slp-wallet": "7.1.4",
43
43
  "mocha": "10.0.0",