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/fold

v3.0.5

Published

Pure resource event fold algebra

Readme

@ossy/fold

Pure resource event fold algebra for the Ossy platform. Isomorphic (Node + browser), no I/O — the same functions run on the server when rebuilding snapshots and on the client for optimistic UI.

Named after the FP / event-sourcing fold: reducing a stream of events into resource state.

Core concepts

A resource is a versioned platform instance with a standard envelope (resourceId, type, name, location, belongsTo, access, audit fields) plus schema-defined content.

Events in eventstore use this shape:

{
  id: 'V1StGXR8_Z',                         // unique event id
  type: '@ossy/booking/schema/booking',     // schema id
  resourceId: 'x7kP2mN9qR',                 // resource instance
  event: 'Patched',                          // lifecycle name
  version: 7,
  payload: { … },
  created: 1718640000000,
  createdBy: 'user_…',
}

Standard lifecycle events:

| event | Semantics | payload | |---------|-----------|-----------| | Created | Birth | Full envelope + full content | | Patched | Partial merge | Partial envelope and/or partial content; undefined keys omitted; deep merge | | Updated | Hard replace | Full content required | | Deleted | Tombstone | Folded state gets status: ['removed'] |

Installation

npm install @ossy/fold

Resource folding

import { fold, createDefaultReducer, applyPatch, applyUpdate } from '@ossy/fold'

// Fold a single event
const state = fold({}, {
  id: 'evt1',
  type: '@ossy/booking/schema/booking',
  resourceId: 'res1',
  event: 'Created',
  version: 1,
  created: Date.now(),
  createdBy: 'user1',
  payload: {
    name: 'Booking',
    location: '/b/',
    belongsTo: 'ws1',
    access: 'workspace',
    content: { clientEmail: '[email protected]' },
  },
})

// Fold an entire stream
const reduce = createDefaultReducer()
const snapshot = reduce(events, initialState)

// Custom handlers for non-lifecycle events
const reduceWithHooks = createDefaultReducer(schema, {
  Signed: (state, event) => ({ ...state, signedAt: event.created }),
})

API reference

| Export | Signature | Description | |---|---|---| | fold | (state, event, handlers?) => state | Fold one event into resource state. Custom handlers[event.event] override defaults. | | createDefaultReducer | (schema?, handlers?) => (events, state?) => state | Reduce an event array left-to-right. | | applyPatch | (base, partial) => state | Deep merge; omit undefined keys (used by Patched). | | applyUpdate | (state, content) => state | Replace content (used by Updated). |

Projection helpers

Projection aggregates (kind: 'projection') fold foreign resource events into scope-keyed read models.

import { matchesSource, applyProjection, resolveProjectionUpdates } from '@ossy/fold'

// Match event against a projection source descriptor
matchesSource(
  { type: '@ossy/booking/schema/booking', event: 'Created' },
  event,
)

// Incremental projection step
const next = applyProjection(event, currentState, ProjectionClass)

// Resolve all projection updates for one event
const updates = resolveProjectionUpdates(event, registeredProjections)
// => [{ projection, scopeId, state }, …]

Match helpers

| Export | Description | |---|---| | getByPath(obj, path) | Read a dotted path (payload.content.status). | | matchesGlob(pattern, value) | Glob match for trigger match values (ws_*). | | matchesSource(source, evt) | Match type, event, and optional match glob fields on payload. | | applyProjection(event, state, projection) | Run projection.Apply when a source matches; returns null when no match. | | resolveProjectionUpdates(event, projections) | Collect scope-keyed updates for all matching projections. |

Where it is used

| Consumer | Role | |---|---| | @ossy/resources | createDefaultReducer when saving resource snapshots | | @ossy/event-store | createDefaultReducer in aggregate rebuild; matchesSource in projection dispatch and push invalidation | | @ossy/sdk-react | fold for optimistic read-cache updates |

Design constraints

  • Strictly pure — no Mongo, no network, no side effects. Server and client must stay in sync.
  • Envelope is uniform*.schema.js declares fields[] for content only; lifecycle reducers handle the platform envelope.
  • Custom events — pass a handlers map to fold / createDefaultReducer for schema-specific event names beyond the four lifecycle events.