clean-architecture-kernel 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Readme.md ADDED
@@ -0,0 +1,224 @@
1
+ # Clean Architecture Kernel
2
+
3
+ > A lightweight, zero-dependency npm package for implementing Clean Architecture, Domain-Driven Design, and CQRS patterns in Node.js applications.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/clean-architecture-kernel.svg)](https://www.npmjs.com/package/clean-architecture-kernel)
6
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![TypeScript](https://img.shields.io/badge/built%20with-TypeScript-blue)](https://www.typescriptlang.org/)
8
+ [![Framework Agnostic](https://img.shields.io/badge/framework-agnostic-brightgreen)](https://www.typescriptlang.org/)
9
+
10
+ ## Overview
11
+ ## Overview
12
+
13
+ Clean Architecture Kernel provides the essential building blocks for implementing Clean Architecture, Domain-Driven Design (DDD), and CQRS patterns in your application.
14
+
15
+ ### Why Clean Architecture Kernel?
16
+
17
+ This package focuses on core domain patterns only, ensuring the kernel remains:
18
+
19
+ - **Small** - Minimal footprint, zero external dependencies
20
+ - **Fast** - No abstractions, direct pattern implementations
21
+ - **Framework-agnostic** - Works with any Node.js framework or runtime
22
+ - **Type-safe** - Built with TypeScript for complete type safety
23
+
24
+ ### Universal Primitives
25
+
26
+ - `Result<T>` - Functional success/failure wrapper
27
+ - `Entity` - Domain entities with identity and events
28
+ - `AggregateRoot` - Aggregate consistency boundaries
29
+ - `ValueObject` - Immutable property-defined objects
30
+ - `DomainEvent` - Domain occurrence representations
31
+ - `Mediator` - In-memory command/query dispatcher
32
+
33
+ ### Perfect For
34
+
35
+ - Backend services & REST APIs
36
+ - Microservices architectures
37
+ - Serverless functions
38
+ - Monolithic applications
39
+ - Event-driven systems
40
+
41
+ ## Table of Contents
42
+
43
+ - [Installation](#installation)
44
+ - [Core Concepts](#core-concepts)
45
+ - [Usage Examples](#usage-examples)
46
+ - [Project Structure](#project-structure)
47
+ - [Design Principles](#design-principles)
48
+ - [Roadmap](#roadmap)
49
+ - [Contributing](#contributing)
50
+ - [License](#license)
51
+
52
+ ## Installation
53
+
54
+ Choose your Node.js package manager:
55
+
56
+ ### NPM
57
+
58
+ ```bash
59
+ npm install clean-architecture-kernel
60
+ ```
61
+
62
+ ### Yarn
63
+
64
+ ```bash
65
+ yarn add clean-architecture-kernel
66
+ ```
67
+
68
+ ### PNPM
69
+
70
+ ```bash
71
+ pnpm add clean-architecture-kernel
72
+ ```
73
+
74
+ ## Core Concepts
75
+ ## Core Concepts
76
+
77
+ ### Result<T>
78
+
79
+ A functional wrapper that encapsulates success or failure states, eliminating the need for try-catch blocks.
80
+
81
+ ```typescript
82
+ const result = Result.ok(user);
83
+
84
+ if (result.isFailure) {
85
+ console.log(result.error);
86
+ }
87
+ ```
88
+
89
+ ### Entity
90
+
91
+ Base class for domain entities with identity and domain event support.
92
+
93
+ ### AggregateRoot
94
+
95
+ Specialized entity that acts as a consistency boundary for related entities.
96
+
97
+ ### ValueObject
98
+
99
+ Immutable object defined by its properties rather than identity, ensuring data integrity.
100
+
101
+ ### DomainEvent
102
+
103
+ Represents something that happened inside the domain, enabling event-driven architectures.
104
+
105
+ ### Mediator
106
+
107
+ Simple in-memory mediator pattern for dispatching commands and queries.
108
+
109
+ ## Project Structure
110
+ ## Project Structure
111
+
112
+ ```
113
+ src/
114
+ ├── core/
115
+ │ ├── Result.ts # Success/failure wrapper
116
+ │ ├── Entity.ts # Domain entity base class
117
+ │ ├── AggregateRoot.ts # Aggregate consistency boundary
118
+ │ ├── ValueObject.ts # Immutable value object
119
+ │ ├── DomainEvent.ts # Domain event base class
120
+ │ └── Mediator.ts # Command/query dispatcher
121
+ └── index.ts # Public API exports
122
+ ```
123
+
124
+ ## Usage Examples
125
+
126
+ ### 1. Creating a Value Object
127
+
128
+ ```typescript
129
+ class Email extends ValueObject<{ value: string }> {
130
+ private constructor(props) {
131
+ super(props);
132
+ }
133
+
134
+ static create(value: string): Result<Email> {
135
+ if (!value.includes("@")) {
136
+ return Result.fail("Invalid email");
137
+ }
138
+ return Result.ok(new Email({ value }));
139
+ }
140
+ }
141
+ ```
142
+
143
+ ### 2. Creating an Entity
144
+
145
+ ```typescript
146
+ class User extends AggregateRoot<string> {
147
+ constructor(id: string, public email: Email) {
148
+ super(id);
149
+ }
150
+ }
151
+ ```
152
+
153
+ ### 3. Defining a Command
154
+
155
+ ```typescript
156
+ class CreateUserCommand {
157
+ constructor(public readonly email: string) {}
158
+ }
159
+ ```
160
+
161
+ ### 4. Implementing a Command Handler
162
+
163
+ ```typescript
164
+ class CreateUserHandler {
165
+ async handle(command: CreateUserCommand) {
166
+ const emailResult = Email.create(command.email);
167
+ if (emailResult.isFailure) return emailResult;
168
+
169
+ const user = new User("123", emailResult.value);
170
+ return Result.ok(user);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### 5. Using the Mediator
176
+
177
+ ```typescript
178
+ const mediator = new Mediator();
179
+ mediator.register("CreateUserCommand", new CreateUserHandler());
180
+
181
+ const result = await mediator.send(new CreateUserCommand("test@mail.com"));
182
+ ```
183
+
184
+ ## Design Principles
185
+ ## Design Principles
186
+
187
+ ✓ **No Dependencies** - Pure TypeScript/JavaScript, zero external npm packages
188
+ ✓ **Predictable Behavior** - Consistent, deterministic pattern implementations
189
+ ✓ **Production-Ready** - Optimized for Node.js backends and microservices
190
+ ✓ **Minimal API** - Small surface area, easy to learn and understand
191
+ ✓ **Type-Safe** - Full TypeScript support out of the box
192
+ ✓ **Inspired by** - Domain-Driven Design, Clean Architecture, and CQRS
193
+
194
+ ## Roadmap
195
+
196
+ - [ ] Event Bus abstraction for decoupled event publishing
197
+ - [ ] Notification pattern implementation
198
+ - [ ] Pipeline behaviors (logging, validation, metrics)
199
+ - [ ] Async domain event dispatcher
200
+ - [ ] Optional integrations (Redis, Kafka, RabbitMQ)
201
+ - [ ] Advanced aggregate query patterns
202
+ - [ ] Built-in validation framework
203
+
204
+ ## Contributing
205
+
206
+ Contributions are welcome! To contribute:
207
+
208
+ 1. Fork the repository
209
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
210
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
211
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
212
+ 5. Open a Pull Request
213
+
214
+ Please ensure your code follows the existing style and includes appropriate tests.
215
+
216
+ ## License
217
+
218
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
219
+
220
+ ---
221
+
222
+ **Made with ❤️ by Andrés Mariño**
223
+
224
+ *For developers building scalable, maintainable architectures*
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "clean-architecture-kernel",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "type": "module"
13
+ }
@@ -0,0 +1,3 @@
1
+ import { Entity } from "./Entity";
2
+
3
+ export abstract class AggregateRoot<TId> extends Entity<TId> {}
@@ -0,0 +1,4 @@
1
+ export abstract class DomainEvent {
2
+ public readonly occurredOn: Date = new Date();
3
+ abstract eventName(): string;
4
+ }
@@ -0,0 +1,19 @@
1
+ import { DomainEvent } from "./DomainEvent";
2
+
3
+ export abstract class Entity<TId> {
4
+ private _domainEvents: DomainEvent[] = [];
5
+
6
+ constructor(public readonly id: TId) {}
7
+
8
+ get domainEvents(): DomainEvent[] {
9
+ return this._domainEvents;
10
+ }
11
+
12
+ protected addDomainEvent(event: DomainEvent): void {
13
+ this._domainEvents.push(event);
14
+ }
15
+
16
+ public clearEvents(): void {
17
+ this._domainEvents = [];
18
+ }
19
+ }
@@ -0,0 +1,13 @@
1
+ export class Mediator {
2
+ private handlers = new Map();
3
+
4
+ register(commandType: string, handler: any) {
5
+ this.handlers.set(commandType, handler);
6
+ }
7
+
8
+ async send(command: any) {
9
+ const handler = this.handlers.get(command.constructor.name);
10
+ if (!handler) throw new Error(`No handler for ${command.constructor.name}`);
11
+ return handler.handle(command);
12
+ }
13
+ }
@@ -0,0 +1,29 @@
1
+ export class Result<T> {
2
+ private constructor(
3
+ public readonly isSuccess: boolean,
4
+ public readonly error?: string,
5
+ private readonly _value?: T
6
+ ) {
7
+ if (isSuccess && error) {
8
+ throw new Error("A result cannot be successful and contain an error");
9
+ }
10
+ if (!isSuccess && !error) {
11
+ throw new Error("A failing result needs an error message");
12
+ }
13
+ }
14
+
15
+ get value(): T {
16
+ if (!this.isSuccess) {
17
+ throw new Error("Cannot get value of a failed result");
18
+ }
19
+ return this._value as T;
20
+ }
21
+
22
+ static ok<U>(value?: U): Result<U> {
23
+ return new Result<U>(true, undefined, value);
24
+ }
25
+
26
+ static fail<U>(error: string): Result<U> {
27
+ return new Result<U>(false, error);
28
+ }
29
+ }
@@ -0,0 +1,7 @@
1
+ export abstract class ValueObject<TProps> {
2
+ constructor(public readonly props: TProps) {}
3
+
4
+ equals(vo: ValueObject<TProps>): boolean {
5
+ return JSON.stringify(this.props) === JSON.stringify(vo.props);
6
+ }
7
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./core/Result";
2
+ export * from "./core/DomainEvent";
3
+ export * from "./core/Entity";
4
+ export * from "./core/AggregateRoot";
5
+ export * from "./core/ValueObject";
6
+ export * from "./core/Mediator";