npm package: @mahyar-kd/nestjs-saga
Description: <p align="center">   <img src="https://nestjs.com/img/logo_text.svg" alt="NestJS Logo" width="50%"> </p>
Author: Mahyar KaKavand
Latest version: 1.0.0

<p align="center">
  <img src="https://nestjs.com/img/logo_text.svg" alt="NestJS Logo" width="50%">
</p>

<h3 align="center">
  <br>
  <br>
  Saga Module for Nestjs framework
  <br>
  <br>
</h3>

<p align="center">

  <img src="https://img.shields.io/npm/v/@mahyar-kd/nestjs-saga" alt="NPM Version">
  <img src="https://img.shields.io/npm/dm/@mahyar-kd/nestjs-saga" alt="NPM Downloads">
  <img src="https://img.shields.io/npm/l/@mahyar-kd/nestjs-saga" alt="Package License">
  <img src="https://img.shields.io/github/last-commit/MahyaR-Kd/nestjs-saga" alt="GitHub last commit">
</p>

<p align="center">
<a href="https://www.buymeacoffee.com/mahyar.kd"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=mahyar.kd&button_colour=FF5F5F&font_colour=ffffff&font_family=Cookie&outline_colour=000000&coffee_colour=FFDD00" /></a>

</p>

## Description

This is a NestJS module designed to facilitate the implementation and management of sagas. Sagas are a pattern for managing distributed transactions and long-running processes in a reliable and consistent manner. This package provides a structured way to define, execute, and handle compensations for sagas, ensuring that your application can maintain data consistency across multiple services and operations.

## Installation

```bash
npm install @mahyar-kd/nestjs-saga
```
OR
```bash
yard add @mahyar-kd/nestjs-saga
```

## Usage

### Create Saga Command

This class represents a command that will be used in the saga. It contains the data required for the saga to execute.

```typescript
export class SampleSagaCommand {
  constructor(
    public readonly sampleData: any,
  ) {}
}
```

### Create Saga Step

This class implements the `SagaStep` interface and defines the steps of the saga. It includes methods for invoking the step and handling compensation in case of failure.

```typescript
import { SagaStep } from '@mahyar-kd/nestjs-saga';

@Injectable()
export class SampleSagaStep implements SagaStep {
  private logger: Logger = new Logger(SampleSagaStep.name, {
    timestamp: true,
  });

  constructor(
    @Inject(CommandBus)
    public readonly commandBus: CommandBus,
    @Inject(QueryBus)
    private readonly queryBus: QueryBus,
  ) {}

  /**
   * Invokes the saga step with the given command.
   * @param cmd - The command to be executed in this step.
   */
  async invoke(cmd: SampleSagaCommand) {}

  /**
   * Handles compensation logic for the saga step in case of failure.
   * @param cmd - The command to be compensated.
   */
  async withCompensation(cmd: SampleSagaCommand) {}
}
```

### Create Saga

This class defines the saga itself, using the `SagaBuilder` to chain the steps together. It specifies the command to be used and the steps to be executed.

```typescript
import { SagaStep } from '@mahyar-kd/nestjs-saga';

@Saga(SampleSagaCommand)
export class SampleSaga {
    constructor(
    @Inject(SampleSagaStep)
    public readonly sampleSagaStep: SampleSagaStep,
  ) {}
  // Define `saga` field using Builder<SampleSagaCommand> or if you want to return
  // some value use: SagaBuilder<SampleSagaStep, SampleSagaResponse>
  
  saga = new SagaBuilder<SampleSagaCommand>()

    .step(SampleSagaStep.name)
    .invoke(async (cmd: SampleSagaCommand) =>
      this.sampleSagaStep.invoke(cmd),
    )
    .withCompensation(async (cmd: SampleSagaCommand) =>
      this.sampleSagaStep.withCompensation(cmd),
    )
}
```

### Executing the Saga Command

This code snippet shows how to execute the saga command using the `CommandBus`. It also demonstrates how to handle exceptions using the `SagaExceptionConverterHelper`.

```typescript
await this.commandBus
  .execute(new SampleSagaCommand(sampleData))
  .catch((error) =>
    SagaExceptionConverterHelper.toHttpException(error.originalError),
  );
```