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

@rozek/sds-network-websocket

v0.0.13

Published

WebSocket sync + presence provider for shareable-data-store

Readme

@rozek/sds-network-websocket

WebSocket network and presence provider for the shareable-data-store (SDS) family. Connects a local SDS_DataStore to an SDS_WebSocket_Server relay, exchanges CRDT patches in real time, and synchronises presence state between all connected peers.

Works in browsers (native WebSocket API) and Node.js 22+ (built-in WebSocket).


Prerequisites

| requirement | details | | --- | --- | | Node.js 22+ | required when using this package server-side. Node.js 22 ships a built-in WebSocket client — no polyfill needed. Download from nodejs.org. | | Modern browser | required when using this package client-side. Any evergreen browser is supported: Chrome 90+, Firefox 90+, Safari 15+, Edge 90+. | | SDS WebSocket server | the remote end must run @rozek/sds-websocket-server (or a compatible relay) to exchange CRDT patches and presence state. |

This package is isomorphic — it uses the native WebSocket API available in both environments.


Installation

pnpm add @rozek/sds-network-websocket
# @rozek/sds-core is a peer dependency:
pnpm add @rozek/sds-core

Concepts

SDS_WebSocketProvider implements both SDS_NetworkProvider and SDS_PresenceProvider from @rozek/sds-core. A single instance can therefore be passed to SDS_SyncEngine for both roles.

Wire protocol

All messages are binary frames with a one-byte type prefix:

| Byte | Name | Direction | Payload | | --- | --- | --- | --- | | 0x01 | PATCH | bidirectional | CRDT patch bytes | | 0x02 | VALUE | bidirectional | 32-byte SHA-256 hash + value bytes (≤ 1 MB) | | 0x03 | REQ_VALUE | client → server | 32-byte SHA-256 hash | | 0x04 | PRESENCE | bidirectional | UTF-8 JSON of SDS_PresenceState | | 0x05 | VALUE_CHUNK | bidirectional | hash + chunk-index + total-chunks + chunk bytes |

Values larger than 1 MB (1,048,576 bytes) are split into VALUE_CHUNK frames of at most 1 MB each and reassembled on the receiving end before the onValue callback fires. The total-chunks field in every chunk frame indicates how many frames form the complete value.

Auto-reconnect

When the WebSocket closes unexpectedly the provider transitions to 'reconnecting' and retries the connection after reconnectDelayMs milliseconds (default 2 000 ms). All patches generated while reconnecting are buffered by the sync engine and flushed once the connection is re-established.


API reference

SDS_WebSocketProvider

import { SDS_WebSocketProvider } from '@rozek/sds-network-websocket'

class SDS_WebSocketProvider implements SDS_NetworkProvider, SDS_PresenceProvider {
  constructor (StoreId:string)

  // ── SDS_NetworkProvider ──────────────────────────────────────

  readonly StoreId:string
  get ConnectionState ():SDS_ConnectionState  // 'disconnected' | 'connecting' | 'connected' | 'reconnecting'

  connect (URL:string, Options:SDS_ConnectionOptions):Promise<void>
  disconnect ():void

  sendPatch (Patch:Uint8Array):void
  sendValue (ValueHash:string, Data:Uint8Array):void
  requestValue (ValueHash:string):void

  onPatch (Callback:(Patch:Uint8Array) => void):() => void
  onValue (Callback:(ValueHash:string, Value:Uint8Array) => void):() => void
  onConnectionChange (Callback:(State:SDS_ConnectionState) => void):() => void

  // ── SDS_PresenceProvider ─────────────────────────────────────

  sendLocalState (State:SDS_LocalPresenceState):void
  onRemoteState (
    Callback:(PeerId:string, State:SDS_RemotePresenceState | undefined) => void
  ):() => void
  readonly PeerSet:ReadonlyMap<string, SDS_RemotePresenceState>
}

SDS_ConnectionOptions

interface SDS_ConnectionOptions {
  Token:string             // JWT for authentication at the relay server
  reconnectDelayMs?: number // delay before reconnect attempt (default 2000 ms)
}

All on* methods return an unsubscribe function. Call it to stop receiving the corresponding events.


Usage

With SDS_SyncEngine (recommended)

import { SDS_DataStore }                  from '@rozek/sds-core'
import { SDS_BrowserPersistenceProvider } from '@rozek/sds-persistence-browser'
import { SDS_WebSocketProvider }          from '@rozek/sds-network-websocket'
import { SDS_SyncEngine }                 from '@rozek/sds-sync-engine'

const DataStore   = SDS_DataStore.fromScratch()
const Persistence = new SDS_BrowserPersistenceProvider('my-store')
const Network     = new SDS_WebSocketProvider('my-store')

const SyncEngine = new SDS_SyncEngine(DataStore, {
  PersistenceProvider:Persistence,
  NetworkProvider: Network,
  PresenceProvider:Network,
})

await SyncEngine.start()
await SyncEngine.connectTo('wss://my-server.example.com', { Token:'<jwt>' })

// react to connection state changes
SyncEngine.onConnectionChange((State) => {
  console.log('Connection:',State)  // 'connected', 'reconnecting', …
})

Without the sync engine — direct use

import { SDS_WebSocketProvider } from '@rozek/sds-network-websocket'

const Network = new SDS_WebSocketProvider('my-store')

const unsubPatch = Network.onPatch((patch) => {
  console.log('Received patch:', patch.byteLength, 'bytes')
})

const unsubConn = Network.onConnectionChange((state) => {
  console.log('State:', state)
})

await Network.connect('wss://my-server.example.com', { Token:'<jwt>' })

// send a raw patch
Network.sendPatch(new Uint8Array([/* ... */]))

// send presence info
Network.sendLocalState({ UserName:'Alice', UserColor:'#3498db' })

// later: clean up
unsubPatch()
unsubConn()
Network.disconnect()

Tracking peer presence

// snapshot of currently active peers
for (const [PeerId,PeerState] of Network.PeerSet) {
  console.log(PeerId, PeerState.UserName, PeerState.lastSeen)
}

// react whenever a peer's state changes
Network.onRemoteState((PeerId,PeerState) => {
  if (PeerState === null) {
    console.log(PeerId, 'left')
  } else {
    console.log(PeerId, 'is at', PeerState.UserFocus?.EntryId)
  }
})

License

MIT License © Andreas Rozek