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 🙏

© 2024 – Pkg Stats / Ryan Hefner

saga-transaction-lib

v1.0.2

Published

A TypeScript library for implementing the Saga pattern to manage distributed transactions and complex workflows

Downloads

34

Readme

Saga Transaction Library

A TypeScript library for implementing the Saga pattern to manage distributed transactions and complex workflows.

Features

  • TypeScript-first implementation
  • Flexible and extensible architecture
  • Built-in error handling and compensation
  • Customizable logging
  • Transaction context management
  • Decorators for fine-grained control over step execution and compensation

Installation

npm install saga-transaction-lib

Configuration

TypeScript Configuration

To use the decorators in this library, you need to enable experimental decorators in your tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true
    ... other options
  }
}

Basic Usage

import { Saga, IStep } from 'saga-transaction-lib';

// 1. Define your context type
interface MyContext {
  // your context properties
}

// 2. Implement your steps
class MyStep implements IStep<MyContext> {
  name = 'My Step';

  async invoke(context: MyContext): Promise<void> {
    // Implementation
  }

  async compensate(context: MyContext): Promise<void> {
    // Compensation logic
  }
}

// 3. Create and execute the saga
async function runMyTransaction() {
  const saga = new Saga<MyContext>();
  const context: MyContext = {
    /* ... */
  };
  const steps: IStep<MyContext>[] = [new MyStep()];

  try {
    const result = await saga.execute(context, steps);
    console.log('Transaction completed successfully');
  } catch (error) {
    console.error('Transaction failed:', error);
  }
}

Advanced Usage

Using Decorators

The library provides two decorators for fine-grained control over step execution and compensation:

@BeforeInvoke & @BeforeCompensate()

  • The @BeforeInvoke decorator checks if the step can proceed by returning true. If it does, the invoke method is executed.
  • The @BeforeCompensate decorator does not require any condition checks and will directly execute the compensation logic when necessary.
import { BeforeInvoke, IStep } from 'saga-transaction-lib';

class MyStep implements IStep<MyContext> {
  name = 'My Step';

  @BeforeInvoke<MyStep, MyContext>(async ({ instance, context }) => {
    console.log(`Preparing to execute ${instance.name}`);
    // Perform checks or preparations
    return true; // Return true to proceed, false to skip this step
  })
  async invoke(context: MyContext): Promise<void> {
    // Step implementation
  }

  @BeforeCompensate()
  async compensate(context: MyContext): Promise<void> {
    // Compensation logic
  }
}

Custom Logger

import { ILogger } from 'saga-transaction-lib';

class CustomLogger implements ILogger {
  log(message: string): void {
    // Custom implementation
  }

  error(message: string, error?: Error): void {
    // Custom implementation
  }

  warn(message: string): void {
    // Custom implementation
  }

  debug(message: string): void {
    // Custom implementation
  }
}

Custom Error Handler

import { IErrorHandler, TransactionContext } from 'saga-transaction-lib';

class CustomErrorHandler<TContext>
  implements IErrorHandler<TransactionContext<TContext>>
{
  async handleError(
    error: Error,
    context: TransactionContext<TContext>
  ): Promise<void> {
    // Custom error handling logic
  }
}

NestJS Saga Module

// saga.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { Saga, SagaOptions } from 'saga-transaction-lib';

@Module({})
export class SagaModule {
  static forRoot<TContext>(options?: SagaOptions<TContext>): DynamicModule {
    return {
      module: SagaModule,
      providers: [
        {
          provide: 'SAGA',
          useFactory: () => new Saga<TContext>(options),
        },
      ],
      exports: ['SAGA'],
    };
  }
}

// app.module.ts
@Module({
  imports: [
    SagaModule.forRoot<YourContextType>({
      logger: new CustomLogger(),
    }),
  ],
})
export class AppModule {}

// your.service.ts
@Injectable()
export class YourService {
  constructor(
    @Inject('SAGA')
    private readonly saga: Saga<YourContextType>
  ) {}

  async executeTransaction() {
    // Use saga here
  }
}

Best Practices

  1. Keep steps atomic and focused
  2. Implement proper compensation logic
  3. Use meaningful step names
  4. Handle errors appropriately
  5. Use typing to ensure compile-time safety
  6. Use decorators to add pre-execution and pre-compensation logic when needed
  7. Ensure isBreakStep is properly managed in your step implementations

Example Usage

A detailed example can be found in the main.ts file located in the example folder. This example demonstrates how to implement a transaction step using both the @BeforeInvoke and @BeforeCompensate decorators.

License

MIT

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests.

Support

If you have any questions or need help, please open an issue on GitHub.