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

@oskarssylwan/event-store

v0.0.2

Published

PoC Event Store

Downloads

1

Readme

Event Store

Proof of concept for an event store implemented in nodejs.

Getting started

Assuming you have initialised a project, the following will create:

  • a http server that will parse incoming events
  • a tcp server that will publish parsed events
npm i --save @oskarssylwan/event-store
const { createEventStore } = require('@oskarssylwan/event-store')

const config = {
  httpPort: 3000,
  tcpPort: 3001,
  mongoAdress: 'mongodb://localhost:27017/dev-store',
  mongoName: 'dev-store',
  mongoCollection: 'events',
}

const aggregateRoot = {
  type: 'EXAMPLE_AGGREGATE',
  reducer: (state, event) => state,
  boundaries: [aggregate => null]
}

createEventStore(config)([ aggregateRoot ])

Aggregate root

createEventStore() takes an array of aggregate roots as an argument. Aggregate roots are responsible for validating domain boundaries as well as providing means of creating projections. An aggregate root needs to have the following properties.

type

The type property is used to identify the aggregate root and link the incoming events to a specific set of domain boundaries.

const user = { type: 'USER' }

reducer

The reducer is used to create the current state of the aggregate. Each event will be passed to the reducer function along with the previous aggregate state. It is then up to the reduce to create a new state based on the event. If you are familiar with redux this will feel quite natural for you.

const reducer = (state, event) => {
  switch (event.type) {
    case 'NAME_CHANGED':
      return { ...state, name: event.data.name }
  }
}

const user = {
  type: 'USER',
  reducer,
}

boundaries

Aggregate root boundaries are implemented as an array of functions that validates the state of the aggregate. Each function is called with the aggregate state after all events have been through the reducer. If the aggregate state breaks a domain boundary the validator function should return an error explaining why it failed validation. However, if the aggregate is valid the validator function is expected to return null.

const nameMoreThan2Characters = user => user.name.length > 2
  ? null
  : new Error('Name needs to be more than two characters long')

const user = {
  type: 'USER',
  reducer: reducer,
  boundaries: [ nameMoreThan2Characters ]
}

Events

POST /stream/:aggregateType/:aggregateId
const namedChangedEvent = {
  type: 'NAMED_CHANGED',
  data: { name: 'Harry Potter' }
}

Projections

GET /projection/:aggregateType/:aggregateId

Roadmap

  • error handling
  • event validation
  • snapshotting
  • concurrency handling