async function fetchEvents (relayUrls, filter, timeoutMs = 10000) {
  logger.debug(`Fetching events with filter: ${JSON.stringify(filter)}`)
  const events = []

  for (const url of relayUrls) {
    try {
      const ws = new WebSocket(url)

      const relayEvents = await new Promise((resolve, reject) => {
        const timeout = setTimeout(() => {
          ws.close()
          resolve([]) // Resolve with empty array on timeout
        }, timeoutMs)

        const localEvents = []

        ws.on('open', () => {
          // Create a unique request ID
          const requestId = `req${Math.floor(Math.random() * 10000)}`

          // Format and send the request
          const request = JSON.stringify(['REQ', requestId, filter])
          ws.send(request)

          ws.on('message', (data) => {
            try {
              const message = JSON.parse(data.toString())

              // Check if it's an EVENT message
              if (message[0] === 'EVENT' && message[2]) {
                localEvents.push(message[2])
              } else if (message[0] === 'EOSE') {
                clearTimeout(timeout)
                ws.close()
                resolve(localEvents)
              }
            } catch (error) {
              logger.debug(`Error parsing message: ${error.message}`)
            }
          })
        })

        ws.on('error', (error) => {
          logger.debug(`WebSocket error for ${url}: ${error.message}`)
          clearTimeout(timeout)
          resolve([]) // Resolve with empty array on error
        })

        ws.on('close', () => {
          clearTimeout(timeout)
          resolve(localEvents)
        })
      })

      logger.debug(`Got ${relayEvents.length} events from ${url}`)
      events.push(...relayEvents)
    } catch (error) {
      logger.debug(`Error connecting to ${url}: ${error.message}`)
    }
  }

  // Remove duplicates based on event ID
  const uniqueEvents = {}
  events.forEach(event => {
    if (!uniqueEvents[event.id]) {
      uniqueEvents[event.id] = event
    }
  })

  return Object.values(uniqueEvents)
}
Fetches events from Nostr relays using WebSockets
@param {Array} relayUrls - Array of relay URLs
@param {Object} filter - Nostr filter object
@param {Number} timeoutMs - Timeout in milliseconds
@returns {Promise<Array>} - Array of events matching the filter