npm package: @hmpsn/ts-ddd
Description: Base classes for implementing Domain-Driven Design (DDD) applications in TypeScript
Author: Thomas Hampson
Latest version: 1.0.0

# ts-ddd

[![npm version](https://badge.fury.io/js/ts-ddd.svg)](https://www.npmjs.com/package/ts-ddd)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Base classes for implementing Domain-Driven Design (DDD) applications in TypeScript.

## Installation

```bash
npm install ts-ddd
```

## Features

This package provides the following DDD building blocks:

- **Entity**: Base class for entities with unique identifiers
- **ValueObject**: Base class for immutable value objects
- **AggregateRoot**: Base class for aggregate roots with domain event support
- **DomainEvent**: Base class for domain events
- **Repository**: Interface for repository pattern
- **UniqueEntityID**: Utility class for generating unique identifiers

## Usage

### Entity

Entities are objects that have a unique identity that runs through time and different representations.

```typescript
import { Entity } from 'ts-ddd';

interface UserProps {
  name: string;
  email: string;
}

class User extends Entity<string> {
  get name(): string {
    return this.props.name;
  }

  get email(): string {
    return this.props.email;
  }

  public updateEmail(newEmail: string): void {
    this.props.email = newEmail;
  }
}

// Create a new user
const user = new User('user-123', { name: 'John Doe', email: 'john@example.com' });
console.log(user.id); // 'user-123'
console.log(user.name); // 'John Doe'
```

### ValueObject

Value Objects are immutable objects that are defined by their attributes rather than a unique identity.

```typescript
import { ValueObject } from 'ts-ddd';

interface AddressProps {
  street: string;
  city: string;
  zipCode: string;
}

class Address extends ValueObject<AddressProps> {
  get street(): string {
    return this.props.street;
  }

  get city(): string {
    return this.props.city;
  }

  get zipCode(): string {
    return this.props.zipCode;
  }
}

// Create addresses
const address1 = new Address({ street: '123 Main St', city: 'Springfield', zipCode: '12345' });
const address2 = new Address({ street: '123 Main St', city: 'Springfield', zipCode: '12345' });

// Value objects with same properties are equal
console.log(address1.equals(address2)); // true
```

### AggregateRoot

An Aggregate Root is an entity that is the root of an aggregate, which is a cluster of domain objects that can be treated as a single unit.

```typescript
import { AggregateRoot, DomainEvent, UniqueEntityID } from 'ts-ddd';

class OrderPlacedEvent extends DomainEvent {
  constructor(aggregateId: UniqueEntityID, public readonly total: number) {
    super(aggregateId);
  }
}

interface OrderProps {
  total: number;
  status: string;
}

class Order extends AggregateRoot<string> {
  get total(): number {
    return this.props.total;
  }

  get status(): string {
    return this.props.status;
  }

  public placeOrder(): void {
    this.props.status = 'placed';
    const event = new OrderPlacedEvent(new UniqueEntityID(this.id), this.total);
    this.addDomainEvent(event);
  }
}

// Create and place an order
const order = new Order({ total: 100, status: 'pending' }, 'order-123');
order.placeOrder();

// Access domain events
console.log(order.domainEvents.length); // 1
console.log(order.domainEvents[0] instanceof OrderPlacedEvent); // true

// Clear events after dispatching
order.clearEvents();
```

### Repository Interface

The Repository interface provides a contract for data access objects.

```typescript
import { IRepository } from 'ts-ddd';

class UserRepository implements IRepository<User> {
  async findById(id: string): Promise<User | null> {
    // Implementation
    return null;
  }

  async save(entity: User): Promise<void> {
    // Implementation
  }

  async delete(entity: User): Promise<void> {
    // Implementation
  }
}
```

## Development

```bash
# Install dependencies
npm install

# Build the package
npm run build

# Run tests
npm test

# Lint code
npm run lint

# Format code
npm run format
```

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

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

## License

MIT