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

@bimetal/server-sync

v0.39.0

Published

Node sync-server skeleton for @bimetal/sync. WebSocket layer over a consumer-supplied http.Server, pluggable EventStore as authority. No HTTP framework; optional per-connection authentication and read/write authorization hooks.

Readme

@bimetal/server-sync

Ein Node-Sync-Server-Skelett für @bimetal/sync. Es legt eine WebSocket-Schicht über einen konsumenten-gelieferten http.Server und nutzt einen einsteckbaren EventStore als Autorität.

Bewusst minimal: kein HTTP-Framework. Das Paket kümmert sich um das WebSocket-Sync-Protokoll, das Weiterreichen an die EventStore-Autorität und — wenn der Konsument die Haken setzt — um die Befugnis je Verbindung (bimetal-304). Ohne die Haken darf jede Verbindung, die das Upgrade überlebt, jeden Strom lesen und in jeden schreiben; Auth gehört dann in eine HTTP-Middleware vor dem Upgrade.

Installation

npm install @bimetal/server-sync @bimetal/sync @bimetal/event-sourcing

Was das Paket liefert

| Export | Zweck | |--------|-------| | createSyncWebSocketServer(options) | Hängt den Sync-WebSocket-Handler an einen bestehenden http.Server und bedient verbundene Clients gegen den als Autorität übergebenen EventStore (Append validiert über Optimistic Locking, Broadcast an Subscriber). | | SyncWebSocketServerOptions.undoDomain | Schaltet das Undo-Kommando frei (undo/redo aus @bimetal/sync): Stream lesen → expectFrame gegen die envelope.id des jüngsten Events dieser Entität prüfen → Aggregat falten → Umkehrung bauen → über eventStore.append anfügen. Kein Löschen, kein Rückspulen; jeder Subscriber sieht die Umkehrung als gewöhnliches Live-Event, weil sie den normalen Append-Weg nimmt. Der Typ ist SyncUndoDomain aus @bimetal/sync — ein Port (Aggregat + Kommando-Bauer), kein Domain-Import. Kollidiert expectFrame, kommt append-rejected mit Grund concurrency und der Stream wächst nicht. Ohne undoDomain antwortet der Server mit einer benannten Ablehnung (Grund unknown, der Text nennt undoDomain), damit ein wartender Client nicht in seine Zeitgrenze läuft. Ob der Server das Kommando trägt, sagt er jedem Client im ersten Frame der Verbindung (hello, bimetal-292); @bimetal/sync-ws setzt undo/redo nur bei Zusage. |

Befugnis je Verbindung (bimetal-304)

| Option | Wirkung | |--------|---------| | authenticate(req) | Läuft beim Upgrade, bevor ein WebSocket entsteht. null/undefined → 401, kein Upgrade; ein Wurf → 500. Jeder andere Wert ist der principal dieser Verbindung. | | readOnly: true | Jedes Schreiben wird mit append-rejected, Grund auth, abgewiesen — append ebenso wie die Kommandos undo/redo. Der Store wird nicht berührt. Der Frame trägt bei auth keine Versionsfelder (expectedVersion/actualVersion): gemessen wurde keine Version, eine Zahl wäre erfunden (bimetal-323). Dasselbe gilt für jeden Grund ausser concurrency (bimetal-341). | | authorizeAppend(ctx) | ctx = { principal, connectionId, streamId, events, expectedVersion }; gefragt wird vor dem Store (bei undo/redo mit der gebauten Umkehrung). false → append-rejected/auth, ein Wurf → append-rejected/unknown. | | authorizeSubscribe(ctx) | ctx = { principal, connectionId, streamId, fromVersion }. false → der eigene Frame subscribe-rejected (Grund auth, bei einem Wurf unknown): kein Events-Frame, kein Snapshot, kein caught-up, am Store wird nichts abonniert. Die Verbindung bleibt stehen; @bimetal/sync-ws beendet die Subscription endgültig (kein Reconnect) und meldet sie über onRejected. |

Versionsfelder nur bei concurrency (bimetal-341). append-rejected trägt expectedVersion/actualVersion nur, wo eine Version gemessen ist: beim Konflikt aus dem Store (ConcurrencyError) beide, bei der expectFrame-Kollision eines undo/redo nur actualVersion (die Erwartung war eine Frame-Marke, keine Version). Die Gründe auth, unknown (Wurf von authorizeAppend, Kommando ohne undoDomain) und validation (unbekannter Store-Fehler, werfendes Aggregat) kommen ohne Versionsfelder. Der Decoder in @bimetal/sync lässt die Felder eines älteren Servers bei diesen Gründen fallen.

Wire-Bruch in Gegenrichtung: Ein Client bis 0.38 an einem Server ab 0.39 verträgt das nicht. Sein Decoder verlangt expectedVersion/actualVersion bei jedem Grund ausser auth als Zahl; der Frame zu validation/ unknown und die expectFrame-Kollision (ohne expectedVersion) gelten ihm als Protokollfehler — er schliesst die Verbindung (4002) und verbindet neu, das offene Append endet als Abbruch statt mit dem benannten Grund. Client und Server gehören zur selben Version.

principal und connectionId sind die Nachweisspur „wer hat über welche Verbindung was versucht" — geführt wird sie im Haken des Konsumenten, der Server schreibt kein Protokoll.

Die Gegenseite im Browser ist @bimetal/sync-ws (SyncTransport-Adapter mit Reconnect + transparenter Subscription-Wiederherstellung).

Architektur

Cross-cutting (Server-Seite von sync). Tiefe: Event-Sourcing-Konzept und Backend-Überblick — dort auch „Wie groß wird das?“, die Grenze des Log-im-Client.