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 🙏

© 2026 – Pkg Stats / Ryan Hefner

clean-architecture-kernel

v1.1.1

Published

A lightweight, zero-dependency npm package for implementing Clean Architecture, DDD, and CQRS patterns with MediatR-inspired features

Readme

Clean Architecture Kernel

A lightweight, zero-dependency npm package for implementing Clean Architecture, Domain-Driven Design, and CQRS patterns in Node.js applications.

npm version MIT License TypeScript Framework Agnostic

Overview

Overview

Clean Architecture Kernel provides the essential building blocks for implementing Clean Architecture, Domain-Driven Design (DDD), and CQRS patterns in your application.

Why Clean Architecture Kernel?

This package focuses on core domain patterns only, ensuring the kernel remains:

  • Small - Minimal footprint, zero external dependencies
  • Fast - No abstractions, direct pattern implementations
  • Framework-agnostic - Works with any Node.js framework or runtime
  • Type-safe - Built with TypeScript for complete type safety

Universal Primitives

  • Result<T> - Functional success/failure wrapper
  • Entity - Domain entities with identity and events
  • AggregateRoot - Aggregate consistency boundaries
  • ValueObject - Immutable property-defined objects
  • DomainEvent - Domain occurrence representations
  • Mediator - In-memory command/query dispatcher

Perfect For

  • Backend services & REST APIs
  • Microservices architectures
  • Serverless functions
  • Monolithic applications
  • Event-driven systems

Table of Contents

Installation

Choose your Node.js package manager:

NPM

npm install clean-architecture-kernel

Yarn

yarn add clean-architecture-kernel

PNPM

pnpm add clean-architecture-kernel

Core Concepts

Core Concepts

Result

A functional wrapper that encapsulates success or failure states, eliminating the need for try-catch blocks.

const result = Result.ok(user);

if (result.isFailure) {
    console.log(result.error);
}

Entity

Base class for domain entities with identity and domain event support.

AggregateRoot

Specialized entity that acts as a consistency boundary for related entities.

ValueObject

Immutable object defined by its properties rather than identity, ensuring data integrity.

DomainEvent

Represents something that happened inside the domain, enabling event-driven architectures.

Mediator

Simple in-memory mediator pattern for dispatching commands and queries.

Project Structure

Project Structure

src/
 ├── core/
 │   ├── Result.ts          # Success/failure wrapper
 │   ├── Entity.ts          # Domain entity base class
 │   ├── AggregateRoot.ts   # Aggregate consistency boundary
 │   ├── ValueObject.ts     # Immutable value object
 │   ├── DomainEvent.ts     # Domain event base class
 │   └── Mediator.ts        # Command/query dispatcher
 └── index.ts               # Public API exports

Usage Examples

1. Creating a Value Object

class Email extends ValueObject<{ value: string }> {
    private constructor(props) {
        super(props);
    }

    static create(value: string): Result<Email> {
        if (!value.includes("@")) {
            return Result.fail("Invalid email");
        }
        return Result.ok(new Email({ value }));
    }
}

2. Creating an Entity

class User extends AggregateRoot<string> {
    constructor(id: string, public email: Email) {
        super(id);
    }
}

3. Defining a Command

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

4. Implementing a Command Handler

class CreateUserHandler {
    async handle(command: CreateUserCommand) {
        const emailResult = Email.create(command.email);
        if (emailResult.isFailure) return emailResult;

        const user = new User("123", emailResult.value);
        return Result.ok(user);
    }
}

5. Using the Mediator

const mediator = new Mediator();
mediator.register("CreateUserCommand", new CreateUserHandler());

const result = await mediator.send(new CreateUserCommand("[email protected]"));

Design Principles

Design Principles

No Dependencies - Pure TypeScript/JavaScript, zero external npm packages
Predictable Behavior - Consistent, deterministic pattern implementations
Production-Ready - Optimized for Node.js backends and microservices
Minimal API - Small surface area, easy to learn and understand
Type-Safe - Full TypeScript support out of the box
Inspired by - Domain-Driven Design, Clean Architecture, and CQRS

Advanced Features

Beyond the core patterns, clean-architecture-kernel includes powerful MediatR-inspired features:

Validators - Request Validation

Validate requests before they reach handlers:

import { Validator, ValidationResult, IRequest } from 'clean-architecture-kernel';

class CreateUserCommand implements IRequest<User> {
    constructor(public readonly email: string) {}
}

class CreateUserValidator extends Validator<CreateUserCommand> {
    validate(command: CreateUserCommand): ValidationResult {
        const errors = [];
        
        if (!command.email.includes('@')) {
            errors.push({ property: 'email', message: 'Invalid email format' });
        }
        if (command.email.length > 100) {
            errors.push({ property: 'email', message: 'Email too long' });
        }

        return errors.length > 0
            ? ValidationResult.failure(errors)
            : ValidationResult.success();
    }
}

// Register and use
const mediator = new Mediator();
mediator.registerValidator('CreateUserCommand', new CreateUserValidator());
mediator.registerHandler('CreateUserCommand', new CreateUserHandler());

try {
    const user = await mediator.send(new CreateUserCommand('invalid'));
} catch (error) {
    if (error instanceof ValidationError) {
        console.log('Validation errors:', error.errors);
    }
}

Notifications - Publish-Subscribe Pattern

Trigger actions in response to domain events:

import { NotificationHandler, INotification, Mediator } from 'clean-architecture-kernel';

class UserCreatedNotification implements INotification {
    constructor(public readonly userId: string, public readonly email: string) {}
}

class SendWelcomeEmailHandler extends NotificationHandler<UserCreatedNotification> {
    async handle(notification: UserCreatedNotification) {
        console.log(`Sending welcome email to ${notification.email}`);
        // Send email logic
    }
}

class LogUserCreationHandler extends NotificationHandler<UserCreatedNotification> {
    async handle(notification: UserCreatedNotification) {
        console.log(`User created: ${notification.userId}`);
        // Logging logic
    }
}

// Multiple handlers subscribe to the same notification
const mediator = new Mediator();
mediator.subscribeNotification('UserCreatedNotification', new SendWelcomeEmailHandler());
mediator.subscribeNotification('UserCreatedNotification', new LogUserCreationHandler());

// Publish to all handlers (executes in parallel)
await mediator.publish(new UserCreatedNotification('123', '[email protected]'));

Pipeline Behaviors - Cross-Cutting Concerns

Add logging, metrics, and other behaviors to your request pipeline:

import { PipelineBehavior, IRequest } from 'clean-architecture-kernel';

class LoggingBehavior<TRequest extends IRequest<TResponse>, TResponse>
    extends PipelineBehavior<TRequest, TResponse>
{
    async handle(request: TRequest, next: () => Promise<TResponse>): Promise<TResponse> {
        console.log(`[${new Date().toISOString()}] Handling ${request.constructor.name}`);
        
        try {
            const result = await next();
            console.log(`[SUCCESS] ${request.constructor.name} completed`);
            return result;
        } catch (error) {
            console.error(`[ERROR] ${request.constructor.name} failed:`, error);
            throw error;
        }
    }
}

class PerformanceBehavior<TRequest extends IRequest<TResponse>, TResponse>
    extends PipelineBehavior<TRequest, TResponse>
{
    async handle(request: TRequest, next: () => Promise<TResponse>): Promise<TResponse> {
        const start = Date.now();
        const result = await next();
        const duration = Date.now() - start;
        
        console.log(`${request.constructor.name} took ${duration}ms`);
        return result;
    }
}

// Register behaviors (they execute in the order added)
const mediator = new Mediator();
mediator.registerBehavior('CreateUserCommand', new LoggingBehavior());
mediator.registerBehavior('CreateUserCommand', new PerformanceBehavior());
mediator.registerHandler('CreateUserCommand', new CreateUserHandler());

// Behaviors wrap the handler execution
const user = await mediator.send(new CreateUserCommand('[email protected]'));

Roadmap

  • [x] Request validation with Validators
  • [x] Notification pattern for pub/sub messaging
  • [x] Pipeline behaviors (logging, validation, metrics)
  • [ ] Async domain event dispatcher with saga pattern
  • [ ] Optional integrations (Redis, Kafka, RabbitMQ)
  • [ ] Advanced aggregate query patterns
  • [ ] Built-in error handling middleware
  • [ ] Request/response compression behaviors

Contributing

Contributions are welcome! To contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure your code follows the existing style and includes appropriate tests.

License

This project is licensed under the MIT License - see the LICENSE file for details.


Made with ❤️ by Andrés Mariño

For developers building scalable, maintainable architectures