npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@jcarrillosrc/cqrs

v1.0.5

Published

## Introduction

Readme

CQRS Library for TypeScript

Introduction

This library provides an implementation of the Command Query Responsibility Segregation (CQRS) pattern in TypeScript. CQRS is a design pattern that separates the responsibility of handling commands (actions that change state) from queries (actions that retrieve state). This separation improves scalability, maintainability, and security in complex applications.

Features

  • CommandBus: Handles commands that modify the system state.
  • QueryBus: Handles queries that retrieve information from the system.
  • EventBus: Manages events to notify different parts of the system about changes.
  • Middleware Support: All buses support middleware configuration to extend functionality such as logging, validation, or security checks.
  • Domain Events: Built-in support for domain events through EventStore.
  • Code Generation: Tools to generate custom bus definitions.

Installation

npm install @jcarrillosrc/cqrs

Usage

Command Bus

The Command Bus handles operations that modify the system state. Commands represent intentions to change the system (like creating a user or updating a record). Each command must have exactly one handler, and handlers should not return values.

class MyFirstCommand {
  constructor(public readonly value: string){}
}

class MyFirstCommandHandler implements CommandHandler<FooCommandStub> {
  handle(command: MyFirstCommand): Promise<void> {
    console.log('Handled command with value:', command.value);
  }
}

const bus = new CommandBus();
bus.register(MyFirstCommand, new MyFirstCommandHandler());

const message = new MyFirstCommand();
await bus.dispatch(message);

Query Bus

The Query Bus manages operations that retrieve data from the system. Unlike commands, queries don't modify state and always return a response. They are used to fetch and return data in a specific format.

class MyFirstQuery {
  constructor(public readonly id: string){}
}

class MyFirstQueryResponse {
  constructor(public readonly data: string){}
}

class MyFirstQueryHandler implements QueryHandler<MyFirstQuery, MyFirstQueryResponse> {
  handle(query: MyFirstQuery): Promise<MyFirstQueryResponse> {
    return Promise.resolve(new MyFirstQueryResponse(`Data for id: ${query.id}`));
  }
}

const bus = new QueryBus();
bus.register(MyFirstQuery, new MyFirstQueryHandler());

const query = new MyFirstQuery('123');
const response = await bus.dispatch(query);
console.log(response.data); // Outputs: "Data for id: 123"

Event Bus and Domain Events

The Event Bus manages the publication and handling of domain events. Events represent something that has already happened in the system. Multiple listeners can subscribe to the same event type.

Basic Event Handling

class MyFirstEvent {
  constructor(public readonly eventData: string){}
}

class MyFirstEventListener implements EventListener<MyFirstEvent> {
  handle(event: MyFirstEvent): Promise<void> {
    console.log('First listener handled event with data:', event.eventData);
    return Promise.resolve();
  }
}

const bus = new EventBus();
bus.register(MyFirstEvent, new MyFirstEventListener());
await bus.publish(new MyFirstEvent('Something happened!'));

Event Bus Execution Strategies

The EventBus supports three execution strategies for handling multiple listeners:

// Sequential execution
const syncBus = EventBus.createSync();

// Parallel execution (fails if any listener fails)
const allBus = EventBus.createAll();

// Parallel execution (continues even if there are failures)
const allSettledBus = EventBus.createAllSettled();

Domain Events with EventStore

class CreateUserCommand {
  constructor(public readonly userId: string) {}
}

class UserCreatedEvent {
  constructor(public readonly userId: string) {}
}

class CreateUserCommandHandler implements CommandHandler<CreateUserCommand> {
  async handle(command: CreateUserCommand, eventStore: EventStore): Promise<void> {
    // User creation logic
    eventStore.record(new UserCreatedEvent(command.userId));
  }
}

// Configure middleware to dispatch events
const eventBus = EventBus.create();
const commandBus = CommandBus.create({
  middlewareStack: new MiddlewareStack([
    new DomainEventsDispatcherMiddleware(eventBus)
  ])
});

Middleware Support

The middleware pattern allows you to create a chain of operations that wrap around the handling of messages. Each middleware in the chain has the responsibility to execute the next middleware until the final handler is reached.

class LoggingMiddleware extends Middleware<any> {
  async execute(message: any, handle: Handler<any, any>, stack: MiddlewareStack<any>, eventStore: EventStore): Promise<any> {
    console.log('Before handling:', message.constructor.name);
    const result = await stack.next().execute(message, handle, stack, eventStore);
    console.log('After handling:', message.constructor.name);
    return result;
  }
}

// Configure middleware stack for any bus
const bus = new CommandBus(
  new MiddlewareStack([
    new LoggingMiddleware(),
    // Add as many middleware as needed
  ])
);

Return Types

  • CommandBus: Always returns void
  • QueryBus: Returns the type specified by the handler
  • EventBus: No guaranteed return value (depends on execution strategy)