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

@prufs/sync

v0.1.0

Published

Bidirectional sync engine between @prufs/store (local SQLite) and @prufs/cloud (api.prufs.ai + R2)

Downloads

98

Readme

@prufs/sync

Bidirectional sync engine between @prufs/store (local SQLite) and @prufs/cloud (api.prufs.ai + R2).

Part of the Prufs platform: a complete replacement for Git and GitHub, purpose-built for agentic coding. See https://prufs.ai for the full story.

Install

npm install @prufs/sync

Quick start

import { SyncEngine, HttpCloudClient } from "@prufs/sync";
import { PrufsStore } from "@prufs/store";

const store = new PrufsStore({ path: ".prufs/store.db" });

const cloud = new HttpCloudClient({
  apiKey: process.env.PRUFS_API_KEY!,
  orgSlug: "cognitionhive",
});

const engine = new SyncEngine(store, cloud);

engine.on("sync:complete", (e) => {
  console.log(`synced ${e.count} commits`);
});

const summary = await engine.sync();
console.log(summary);
// { pulled: 3, pushed: 7, duplicates: 0, rejected: 0, errors: 0, branches: ["main"], duration_ms: 428 }

What the sync engine does

  1. Pull fetches commits from the cloud that are not present locally and writes them to the local store.
  2. Push sends commits from the local store to the cloud that are not yet present there.
  3. Sync runs pull then push, reaching eventual consistency with a single call.
  4. Status reports what a sync would do, without making any changes.

Design properties

  • Content-addressed. Commits are identified by SHA-256 hash of their canonical JSON. Equality implies identity, so the sync engine can compare logs by ID alone.
  • Idempotent. Pushing the same commit twice is a no-op on the server. The engine treats duplicate responses as success.
  • CRDT-friendly. Merge conflict resolution is delegated to @prufs/store's three-tier merge: disjoint auto-merge, last-write-wins for overlapping non-restricted changes, and human gate for restricted-sensitivity overlaps.
  • Retry with jitter. Transient failures are retried with exponential backoff and full jitter, preventing thundering herd when multiple clients sync simultaneously.
  • Event-driven progress. The engine extends SyncEmitter and emits typed events (sync:start, pull:commit, push:commit, merge:conflict, sync:complete) for progress reporting in CLIs and dashboards.

API

new SyncEngine(store, cloud, options?)

Construct a sync engine bound to a local store and a cloud client.

Options:

  • batchSize?: number - maximum commits per push batch (default 25)
  • maxRetries?: number - maximum retry attempts on transient failure (default 3)
  • retryBaseMs?: number - base delay in ms for exponential backoff (default 200)
  • logger?: (message: string) => void - optional verbose logger

engine.sync(branch?) -> Promise<SyncSummary>

Run pull then push across all branches (or a single branch if specified).

engine.pull(branch?) -> Promise<number>

Pull cloud commits not present locally. Returns the number of commits pulled.

engine.push(branch?) -> Promise<[pushed, duplicates, rejected]>

Push local commits not present in the cloud. Returns a tuple of counts.

engine.status() -> Promise<SyncStatus>

Dry-run: report what a sync would do. Classifies each branch as in_sync, local_ahead, cloud_ahead, or diverged.

engine.on(event, listener)

Subscribe to progress events. Use "*" to subscribe to all events.

Events

| Event | When emitted | |---|---| | sync:start | At the beginning of a sync() call | | sync:complete | At the end of a successful sync() call | | sync:error | When a commit is rejected or an unrecoverable error occurs | | pull:start | At the beginning of a pull operation | | pull:commit | After each commit is pulled and stored locally | | pull:complete | At the end of a pull operation | | push:start | At the beginning of a push operation | | push:commit | After each commit is pushed (accepted or duplicate) | | push:complete | At the end of a push operation | | merge:conflict | When a restricted-sensitivity merge requires human review | | merge:resolved | When an auto-merge completes successfully |

Test coverage

61 tests across 16 suites:

  • Backoff (8 tests): exponential envelope, jitter, delay cap, retry success and exhaustion, non-retryable errors, sleep duration
  • Diff (9 tests): empty logs, all-local, all-cloud, shared commits, divergent histories, order preservation, branch grouping
  • Emitter (7 tests): registration, specific listeners, wildcard listeners, off, chaining, empty emit tolerance
  • Engine pull (4 tests): empty, full cloud, partial overlap, events
  • Engine push (6 tests): empty, full local, duplicates, rejections, retry on transient failure, batching
  • Engine sync (3 tests): pull-then-push, eventual consistency, events
  • Engine status (4 tests): in_sync, local_ahead, cloud_ahead, diverged
  • isCausalCommit type guard (3 tests): well-formed, non-objects, missing fields
  • HttpCloudClient constructor (4 tests): missing fields, default URL, trailing slash stripping
  • HttpCloudClient pushCommit (5 tests): accepted, duplicate, rejected, 5xx throw, auth header
  • HttpCloudClient fetchLog (3 tests): success, branch query param, error propagation
  • HttpCloudClient fetchCommit (3 tests): success, 404 null return, full=true param
  • HttpCloudClient fetchBranches (2 tests): success, empty fallback

All tests use the Node.js built-in test runner, consistent with every other package in the Prufs monorepo. No Jest, no Vitest, no external test framework dependencies.

Build

npm run build

Produces dist/ with compiled JavaScript, declaration files, and source maps.

Test

npm test

License

MIT