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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@loro-dev/flock

v3.1.0

Published

TypeScript bindings for the Flock CRDT with mergeable export/import utilities.

Readme

@loro-dev/flock

TypeScript bindings for the Flock Conflict-free Replicated Data Type (CRDT). Flock stores JSON-like values at composite keys, keeps causal metadata, and synchronises peers through mergeable export bundles. This package wraps the core MoonBit implementation and exposes a typed Flock class for JavaScript runtimes (Node.js ≥18, modern browsers, and workers).

Installation

pnpm add @loro-dev/flock
# or
npm install @loro-dev/flock
# or
yarn add @loro-dev/flock

The library ships ESM, CommonJS, and TypeScript declaration files. It has no runtime dependencies beyond the standard Web Crypto API for secure peer identifiers (falls back to Math.random when unavailable).

Quick Start

import { Flock } from "@loro-dev/flock";

// Each replica uses a stable UTF-8 peer id (<128 bytes) to maintain version vectors.
const peerId = crypto.randomUUID();
const store = new Flock(peerId);

store.put(["users", "42"], { name: "Ada", online: true });
console.log(store.get(["users", "42"]));

// Share incremental updates with a remote replica.
const bundle = store.exportJson();

// On another node, merge and materialise the same data.
const other = new Flock();
other.importJson(bundle);
other.merge(store);

// Subscribe to local or remote mutations.
const unsubscribe = store.subscribe(({ source, events }) => {
  for (const { key, value } of events) {
    console.log(`[${source}]`, key, value ?? "<deleted>");
  }
});

store.delete(["users", "42"]);
unsubscribe();

Replication Workflow

  • Call exportJson() to serialise local changes since an optional version vector.
  • Distribute bundles via your transport of choice (HTTP, WebSocket, etc.).
  • Apply remote bundles with importJson() and reconcile replicas using merge().
  • Track causal progress with version() and getMaxPhysicalTime() when orchestrating incremental syncs.
  • Use Flock.checkConsistency() in tests to assert that two replicas converged to the same state.

Type Basics

  • Value: JSON-compatible data (string, number, boolean, null, nested arrays/objects).
  • KeyPart: string | number | boolean. Keys are arrays of parts (e.g. ["users", 42]). Invalid keys raise at runtime.
  • ExportRecord: { c: string; d?: Value } – CRDT payload with hybrid logical clock data.
  • ExportBundle: Record<string, ExportRecord> mapping composite keys to last-writer metadata.
  • VersionVector: Record<string, { physicalTime: number; logicalCounter: number }> indexed by peer identifiers (UTF-8 strings ordered by their byte representation).
  • ScanRow: { key: KeyPart[]; raw: ExportRecord; value?: Value } returned by scan().
  • EventBatch: { source: string; events: Array<{ key: KeyPart[]; value?: Value }> } emitted to subscribers.

All types are exported from the package entry point for use in TypeScript projects.

API Reference

Constructor

new Flock(peerId?: string) – creates a replica. When omitted, a random 64-character hex peer id is generated. The id persists only in memory; persist it yourself for durable replicas.

Static Members

  • Flock.fromJson(bundle: ExportBundle, peerId: string): Flock – instantiate directly from a full snapshot bundle.
  • Flock.checkConsistency(a: Flock, b: Flock): boolean – deep equality check useful for tests; returns true when both replicas expose the same key/value pairs and metadata.

Replica Management

  • setPeerId(peerId: string): void – replace the current peer id. Use cautiously; changing ids affects causality tracking.
  • peerId(): string – returns the identifier for the replica.
  • getMaxPhysicalTime(): number – highest physical timestamp observed by this replica (same units as the timestamps you pass to now, e.g. Date.now() output). Helpful for synchronising clocks and diagnosing divergence.
  • version(): VersionVector – current version vector including logical counters per peer.
  • checkInvariants(): void – throws if internal CRDT invariants are violated. Intended for assertions in tests or diagnostics, not for production control flow.

Mutations

  • put(key: KeyPart[], value: Value, now?: number): void – write a JSON value. The optional now overrides the physical time (numeric timestamp such as Date.now() output) used for the replica’s hybrid logical clock. Invalid keys or non-finite timestamps throw.
  • set(key: KeyPart[], value: Value, now?: number): void – alias of put for frameworks that prefer “set” terminology.
  • delete(key: KeyPart[], now?: number): void – tombstone a key. The optional time override follows the same rules as put.
  • putMvr(key: KeyPart[], value: Value, now?: number): void – attach a value to the key’s Multi-Value Register. Unlike put, concurrent writes remain alongside each other.

Reads

  • get(key: KeyPart[]): Value | undefined – fetch the latest visible value. Deleted keys resolve to undefined.
  • getMvr(key: KeyPart[]): Value[] – read all concurrent values associated with a key’s Multi-Value Register (empty array when unset).
  • kvToJson(): ExportBundle – snapshot of every key/value pair including tombstones. Useful for debugging or serialising the entire store.
  • scan(options?: ScanOptions): ScanRow[] – in-order range scan. Supports:
    • start / end: { kind: "inclusive" | "exclusive"; key: KeyPart[] } or { kind: "unbounded" }.
    • prefix: restrict results to keys beginning with the provided prefix. Results include the materialised value (if any) and raw CRDT record.

Replication

  • exportJson(from?: VersionVector): ExportBundle – export causal updates. Provide a VersionVector from a remote replica to stream only novel changes; omit to export the entire dataset.
  • importJson(bundle: ExportBundle): void – apply a bundle received from another replica. Invalid payloads throw.
  • merge(other: Flock): void – merge another replica instance directly (both replicas end up with the joined state).

Events

  • subscribe(listener: (batch: EventBatch) => void): () => void – register for mutation batches. Each callback receives the source ("local" for writes on this replica, peer id string for remote batches when available) and an ordered list of events. Return value unsubscribes the listener.

Utilities

  • exportJson, importJson, kvToJson, and fromJson all work with plain JavaScript objects, so they serialise cleanly through JSON or structured clone.
  • Keys are encoded using MoonBit’s memcomparable format; use simple scalars and natural ordering for predictable scans.

Error Handling

  • Methods that accept keys validate them at runtime. Passing unsupported key parts (like objects or undefined) throws a TypeError.
  • Passing malformed bundles or version vectors throws a TypeError or propagates an underlying runtime error from the native module.
  • Always wrap replication IO in try/catch when dealing with untrusted data.

Testing Tips

  • Use Flock.checkConsistency() to assert two replicas match after a sequence of operations.
  • checkInvariants() is safe inside unit tests to catch bugs in integration layers.
  • Vitest users can combine exportJson snapshots with expect to capture deterministic state transitions.

License

MIT © Loro contributors