An open API service indexing awesome lists of open source software.

https://github.com/cbschuld/valkey-pubsub

A lightweight, TypeScript-native Pub/Sub implementation designed for use with Mercurius GraphQL, built on top of Valkey (Redis-compatible).
https://github.com/cbschuld/valkey-pubsub

Last synced: 3 months ago
JSON representation

A lightweight, TypeScript-native Pub/Sub implementation designed for use with Mercurius GraphQL, built on top of Valkey (Redis-compatible).

Awesome Lists containing this project

README

        

# valkey-pubsub

A lightweight, TypeScript-native Pub/Sub implementation designed for use with [Mercurius GraphQL](https://github.com/mercurius-js/mercurius), built on top of Valkey (Redis-compatible).

Supports broadcasting messages to multiple listeners and enables easy event-driven design for GraphQL subscriptions or internal messaging systems.

---

## Features

- ๐Ÿ” **Broadcast-style delivery**: All listeners receive each message
- โšก **Fast and simple API**: Push, subscribe, destroy
- โœ… **Compatible with Mercurius** PubSub interface
- ๐Ÿงช **Tested with Jest**
- ๐Ÿงฑ **Type-safe and modular** โ€” written in pure TypeScript

---

## Installation

```bash
pnpm add valkey-pubsub
```

## Usage

### Create the PubSub instance

```typescript
import ValkeyPubSub, { PubSubGenericQueue } from "valkey-pubsub";

const pubsub = await ValkeyPubSub.create({
addresses: [{ host: "localhost", port: 6379 }],
clusterMode: false,
});
```

### Subscribe to a topic

```typescript
const queue = new PubSubGenericQueue();

await pubsub.subscribe("my-topic", queue);

queue.onItem((message) => {
console.log("Received:", message);
});
```

### Publish a message

```typescript
await pubsub.publish({
topic: "my-topic",
payload: { hello: "world" },
});
```

## Usage with Mercurius

The original/driving force for the design was the [subscription models for Mercurius](https://mercurius.dev/#/docs/subscriptions)

```typescript
const pubsub = await ValkeyPubSub.create();

fastify.decorate("pubsub", pubsub);

fastify.register(mercurius, {
schema,
resolvers: await resolvers,
loaders: await loaders,
context: async (request: FastifyRequest) => {
return {
request,
db: server.db,
valkey: server.valkey,
pubsub: server.pubsub,
logger: server.log,
} as ServerDecorators;
},
subscription: {
context: async (_server, request) => {
return {
request,
db: server.db,
valkey: server.valkey,
pubsub: server.pubsub,
logger: server.log,
} as ServerDecorators;
},
pubsub: server.pubsub,
},
graphiql: false, // โ„น๏ธ cannot use in place with helmet
allowBatchedQueries: true,
path: "/graphql", // ๐Ÿ‘ˆ Restricts GraphQL to this endpoint
prefix: "/",
});
```

## API

### ValkeyPubSub

#### `ValkeyPubSub.create(config): Promise`

Creates a PubSub instance.

Config options:

- addresses: Array of { host, port } objects (defaults to Valkey on localhost:6379)
- protocol: 'RESP2' or 'RESP3' (default: 'RESP3')
- clusterMode: true or false (default: false)

#### `pubsub.subscribe(topic, queue)`

- Subscribes a queue to a topic. Every published message will be pushed to the queue and delivered to all its listeners.

#### `pubsub.publish({ topic, payload }, callback?)`

- Publishes a message to the specified topic. Payload will be stringified before being sent.

#### `pubsub.cleanup()`

- Cleans up all open connections and subscriptions.

### PubSubGenericQueue

#### `PubSubGenericQueue`

A generic in-memory delivery queue that stores items and allows multiple listeners.

Methods:

- `push(value: T)`: Pushes a value onto the queue
- `onItem(callback: (value: T) => void)`: Registers a callback for new items
- `isEmpty()`: Returns true if the queue is empty
- `size()`: Returns the current number of pending items
- `destroy()`: Destroys the queue and runs any registered close callbacks

## License

MIT ยฉ Chris Schuld

## Contact

- **Email** - twitter handle @ gmail.com
- **X** - @cbschuld

## Contributing

Yes, thank you! Please update the docs and tests and add your name to the package.json file.