hollywood-js

Event Sourcing DDD CQRS tool kit

Usage no npm install needed!

<script type="module">
  import hollywoodJs from 'https://cdn.skypack.dev/hollywood-js';
</script>

README

Hollywood

Build Status Coverage Status

Hollywood-js is a Framework for building very modular and high scalable server side applications following CQRS (Command Query Responsibility Segregation) and enforcing IoC.

It provides a Bounded Context oriented architecture, enforcing isolation and event driven communication between them. Hollywood-js it's strongly CQRS structured, allowing you to define or not a DDD / Clean Architecture project.

Includes advanced Event Sourcing capabilities like Event Store abstractions, Event Store Snapshots, Projections and Event Bus (Listeners and Subscribers).

Installation

NPM:

npm install hollywood-js

Yarn:

yarn add hollywood-js

CQRS Framework with Event Sourcing support.

Features:

  • Dependency Injection (Built around Inversify).
    • Module hierarchy for Bounded Context isolation.
  • DDD toolbox
    • Event Driven
      • Support for different event streams
    • In Memory implementations for testing
    • AggregateRoot and EventSourced abstractions
  • Event Store
    • Event Store decoupled from storage implementation thanks to DBAL (Database Abstraction Layer)
    • In Memory Event Store DBAL implementations for testing
    • Configurable SnapshotStore support.
    • In Memory Snapshot DBAL implementation for testing
    • Built in Event Bus
  • Command and Query Bus
    • Command and Query handlers autowiring
    • Middlewares support for Command and Query bus
  • Libraries should NOT log, I don't log, I throw Errors.
  • Not a server framework but tested with express and fastify (this last one the one I recommend, see /examples).

Basic Usage

import ModuleContext from "./ModuleContext";
import Kernel from "./Kernel";
import {inject} from "inversify";

const parameters = new Map([
  ['hello.style', 'hey']
]);

class Hey {
  constructor(@inject('hello.style') private readonly style: string) {}

  hello(): string {
    return this.style
  }
}

const MainModule = new ModuleContext({
  services: [
    ['hey', {instance: Hey}]
  ]
})

const kernel = new Kernel('dev', true, parameters, MainModule);

kernel.container.get<Hey>('key').hello() // 'key'

Module dependencies

import ModuleContext from "./ModuleContext";
import Kernel from "./Kernel";
import {inject} from "inversify";

const parameters = new Map([
  ['hello.style', 'hey']
]);

class Hey {
  constructor(@inject('hello.style') private readonly style: string) {}

  hello(): string {
    return this.style
  }
}

const HeyModule = new ModuleContext({
  services: [
    ['hey', {instance: Hey}]
  ]
})

class Person {
    constructor(@inject('hey') private readonly hey: Hey) {}

    sayHello(): string {
        return this.key.hello()
    }
}

const PersonModule = new ModuleContext({
  services: [
    ['person', {instance: Person}]
  ],
  modules: [HeyModule]
})
const kernel = new Kernel('dev', true, parameters, MainModule);

kernel.container.get<Person>('person').sayHello() // 'key'

Overwrite during testing

import ModuleContext from "./ModuleContext";
import Kernel from "./Kernel";
import {inject} from "inversify";

const parameters = new Map([
  ['hello.style', 'hey']
]);

const TestingParameters = new Map([
  ['hello.style', 'HELLOOOOOOO!']
]);

class Hey {
  constructor(@inject('hello.style') private readonly style: string) {}

  hello(): string {
    return this.style
  }
}

const HeyModule = new ModuleContext({
  services: [
    ['hey', {instance: Hey}]
  ]
})

class Person {
    constructor(@inject('hey') private readonly hey: Hey) {}

    sayHello(): string {
        return this.key.hello()
    }
}

const PersonModule = new ModuleContext({
  services: [
    ['person', {instance: Person}]
  ],
  modules: [HeyModule]
})
const kernel = new Kernel('dev', true, parameters, MainModule, TestingParameters);

kernel.container.get<Person>('person').sayHello() // 'HELLOOOOOOO!'