Paravel 
A nostr toolkit focused on creating highly a configurable client system. What paravel provides is less a library of code than a library of abstractions. Odds are you will end up creating a custom implementation of every component to suit your needs, but if you start with paravel that will be much easier than if you pile on parameters over time.
This is a monorepo which is split into several different packages.
@coracle.social/lib
Some general-purpose utilities used elsewhere in paravel.
Deferredis just a promise withresolveandrejectmethods.Emitterextends EventEmitter to supportemitter.on('*', ...).Fluentis a wrapper around arrays with chained methods that modify and copy the underlying array.LRUCacheis an implementation of an LRU cache.Queueis an implementation of an asynchronous queue.Toolsis a collection of general-purpose utility functions.
@coracle.social/util
Some nostr-specific utilities. For the most part, these will not have side effects or manage state.
Addresscontains utilities for dealing with nostr addresses.Eventscontains utilities for dealing with nostr events.Filterscontains utilities for dealing with nostr filters.Kindscontains kind constants and related utility functions.Relayscontains utilities related to relay urls.Routeris a utility for selecting relay urls based on user preferences and protocol hints.Tagsprovides a convenient way to access and modify tags.
@coracle.social/network
Utilities having to do with connection management and nostr messages.
ConnectionMetatracks stats for a givenConnection.Connectionis a wrapper forSocketwith send and receive queues, and aConnectionMetainstance.Executorimplements common nostr flows ontargetPoolis a thin wrapper aroundMapfor use withRelays.Socketis a wrapper around isomorphic-ws that handles json parsing/serialization.Subscriptionis a higher-level utility for making requests against multiple nostr relays.
Executor targets extend Emitter, and have a send method, a cleanup method, and a connections getter. They are intended to be passed to an Executor for use.
Multiallows you to compose multiple targets together.Plextakes an array of urls and aConnectionand sends and receives wrapped nostr messages over that connection.Relaytakes aConnectionand provides listeners for different verbs.Relaystakes an array ofConnections and provides listeners for different verbs, merging all events into a single stream.
Example
Functionality is split into small chunks to allow for changing out implementations as needed. This is useful when attempting to support novel use cases. Here's a simple implementation of an agent that can use a multiplexer if enabled, or can fall back to communicating directly with all relays.
class Agent {
pool = new Pool()
constructor(readonly multiplexerUrl: string) {}
getTarget(urls) {
return this.multiplexerUrl
? new Plex(urls, this.pool.get(this.multiplexerUrl))
: new Relays(urls.map(url => this.pool.get(url)))
}
subscribe(urls, filters, id, {onEvent, onEose}) {
const executor = new Executor(this.getTarget(urls))
return executor.subscribe(filters, id, {onEvent, onEose})
}
}