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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ossy/event-store

v3.7.0

Published

Ossy Event Store — Aggregate, EventStore, and MongoDB client

Readme

@ossy/event-store

Event sourcing primitives for the Ossy platform. Provides Aggregate (ADR 0008 entity streams), EventStore (resource event I/O), ProjectionRebuild / getProjection (derived read models), PushInvalidation (SSE cache invalidation), and AggregateRebuild (startup snapshot rebuilding) on top of MongoDB.

Exports

| Export | Module | Purpose | |--------|--------|---------| | Mongo | mongodb.js | Connect to MongoDB | | Aggregate | aggregate.js | Entity stream facade (delegates to SchemaStream) | | SchemaStream | schema-stream.js | Low-level ADR 0008 entity stream I/O | | EventStore | event-store.js | Append and query resource events | | AggregateRebuild | aggregate-rebuild.js | Startup snapshot rebuild for entities and resources | | ProjectionRebuild | projection-rebuild.js | Incremental and full projection rebuild | | getProjection | projection-queries.js | Read a projection snapshot by scope | | PushInvalidation | push-invalidation.js | Workspace-scoped SSE fan-out | | buildInvalidationKeys, buildPushMessage | push-invalidation.js | Derive client cache keys from events |

Core concepts

The event store keeps two MongoDB collections:

  • eventstore — every resource/entity event ever appended. Immutable. ADR 0008 documents use type (schema id), resourceId, event (lifecycle name), version, payload, created, and createdBy.
  • aggregates — denormalized state snapshots: entity/resource folds keyed by id, and projection snapshots keyed by { id: scopeId, type: projectionId, kind: 'projection' }. Rebuilt at startup and updated on the changestream.

Aggregate

Facade over SchemaStream for entity aggregates that declare static SchemaId. All methods return Promises.

Reading the current state

import { Aggregate } from '@ossy/event-store'
import { User } from '@ossy/users/server'

const state = await Aggregate.Of(User, userId).then(Aggregate.View())

Creating a new entity

Pass a creation event as the identifier. The event is appended and the stream is returned.

const createdEvent = UsersEvents.Created({ email, firstName, lastName })
const userView = await Aggregate.Of(User, createdEvent).then(Aggregate.View())

resourceId in the event is the entity id; if absent, the event factory generates one.

Appending to an existing entity

await Aggregate.Of(User, userId)
  .then(Aggregate.Add(UsersEvents.NameUpdated({ firstName, lastName, createdBy: userId })))
  .then(Aggregate.Save())

API reference

| Method | Signature | Description | |---|---|---| | Aggregate.Of(Root, id) | (class, string) => Promise<Stream> | Load an entity stream by resourceId. | | Aggregate.Of(Root, event) | (class, object) => Promise<Stream> | Create a new entity by appending the first event. | | Aggregate.Add(event) | (event) => (stream) => Promise<Stream> | Append an event. Chainable. | | Aggregate.Save() | () => (stream) => Promise<void> | Persist the folded snapshot to aggregates. | | Aggregate.View(fn?) | (fn?) => (stream) => state | Fold events through the aggregate View reducer. | | Aggregate.Validate(fn) | (fn) => (stream) => Promise<Stream> | Run validation against (events, savedState). | | Aggregate.Find(id) | (string) => Promise<object \| null> | Find a snapshot document in aggregates by id. | | Aggregate.Collection | Collection | Direct access to the MongoDB aggregates collection. |

Entity aggregate classes require static SchemaId (ADR 0008). Resource documents use @ossy/resources commitResource / mutateResource instead.


EventStore

Low-level access to the eventstore collection.

import { EventStore } from '@ossy/event-store'

| Method | Signature | Description | |---|---|---| | EventStore.AppendResourceEvent(event) | (object) => Promise<object> | Insert an ADR 0008 event document. | | EventStore.GetResourceStream({ resourceId, fromVersion? }) | => Promise<object[]> | Events for one resourceId, optionally after a version. | | EventStore.GetResourceStreams() | => Promise<{ resourceId, type }[]> | All known (resourceId, schemaId) pairs. | | EventStore.FindEvent(query) | (MongoQuery) => Promise<object> | Find a single event. Rejects when not found. | | EventStore.FindEvents(query) | (MongoQuery) => Promise<object[]> | Find multiple events. Rejects when none found. | | EventStore.Aggregate(pipeline) | (Pipeline) => Promise<object[]> | Run a MongoDB aggregation pipeline. | | EventStore.Collection | Collection | Direct access to the eventstore collection. |


Projections

Projection aggregates (kind: 'projection') fold resource events into scope-keyed read models (e.g. workspace booking list).

import { getProjection } from '@ossy/event-store'

const list = await getProjection(workspaceId, '@ossy/booking/data/booking-list')

| API | Description | |-----|-------------| | ProjectionRebuild.registerProjection({ id, Aggregate }) | Register a projection class (also called via AggregateRebuild.registerAggregate when kind === 'projection') | | ProjectionRebuild.dispatch(event) | Apply one changestream event to matching projections | | ProjectionRebuild.rebuildAll() | Replay source events at startup (called from AggregateRebuild.BuildAndSaveAll()) |

Projection classes declare static sources, static scopeFromEvent(event), static Apply(event, state), and optionally static cacheKeys(scopeId, event).


Push invalidation (ADR 0008 §9)

After changestream rebuild, PushInvalidation.publish(event) fans out SSE messages to workspace subscribers.

  • Server: GET /events (workspace-scoped via workspaceId header or user settings cookie)
  • Client: sdk.subscribePush({ onMessage }) — opt in via PushInvalidationSubscriber or enablePushInvalidation in app config (off by default; see @ossy/sdk-react README)
  • Keys: resource:{id}, location:{path}, projection:{id}:{scopeId}, action:{actionId}

Use buildInvalidationKeys(event) to derive keys server-side; buildPushMessage(event) wraps them for SSE payloads. Projection aggregates may define static cacheKeys(scopeId, event) for bespoke list-action keys.


AggregateRebuild

Rebuilds entity/resource snapshots from scratch at startup. Called automatically by @ossy/platform.

import { AggregateRebuild } from '@ossy/event-store'

AggregateRebuild.registerAggregate({ id: 'User', Aggregate: User })
await AggregateRebuild.BuildAndSaveAll()

registerAggregate routes projection modules (Aggregate.kind === 'projection') to ProjectionRebuild. Entity classes are indexed by Aggregate.SchemaId for resource rebuilds.


*.aggregate.js primitive

The platform auto-discovers aggregate files from installed packages. Entity aggregates export { id, Aggregate } with Aggregate.SchemaId; projection aggregates set Aggregate.kind = 'projection'. See PRIMITIVES.md.


MongoDB setup

import { Mongo } from '@ossy/event-store'

await Mongo.connect(process.env.DB_URL)

Recommended indexes (created at startup by ensureEventStoreIndexes):

// eventstore
{ resourceId: 1, version: 1 }  // stream queries

// aggregates
{ id: 1 }                                      // snapshot get-by-id
{ type: 1, 'state.email': 1 }                  // user lookup (sparse)
{ 'state.belongsTo': 1, 'state.location': 1 }  // folder list/search (sparse)

{ type: 1, event: 1 } on eventstore is still useful for projection replay / task triggers but is not created automatically.


Testing

npm test -w @ossy/event-store

Runs unit tests for push invalidation key derivation (push-invalidation.spec.js).