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

@blueshed/delta

v0.11.0

Published

Delta-doc — JSON-Patch document sync with SQLite and Postgres backends, WebSocket transport, and reactive client signals

Readme

@blueshed/delta

delta keeps shared documents live in every browser that has one open: plain tables underneath, one WebSocket between, from a JSON file on day one to a Postgres server in production.

An app is a set of documents: a venue's map, a caterer's menu, a person's calendar. Each is a live view over ordinary tables. A browser opens a document and changes it with three verbs (add, replace, remove) on paths like /courses/3/name. Every open document that holds a changed row hears about it straight away: the row arriving, changing, or leaving. With the ledger on, each person can undo their own writes while others keep writing, and a table keeps every version of its rows (unless you turn that off), so a document can be read as it stood last March.

Start on a JSON file, move to SQLite, then to Postgres in the same process, and deliver on a Postgres server. Each step changes the few lines that say where the truth lives, and nothing else: the schema, the documents, the writes and the data stay the same, and the rows move with their ids. No rewrite, no second data layer, no reload logic.

In one line: live, undoable documents over plain tables, from a file to a Postgres server without rewriting the app.

It exists because shared, live state should be one small idea rather than a stack of fetch calls, caches and sockets. The whole package is small enough to read in one sitting (and to fit in an AI's context), and there is one way to do each thing. (The skill's Backends side by side says what is the same on every backend, and the little that differs.)

Delta runs on Bun. It ships TypeScript source (the exports are .ts files), the SQLite backend uses bun:sqlite and the server uses Bun.serve. The browser code needs a bundler; Bun's HTML imports do it with no configuration.

Try it

mkdir try-delta && cd try-delta && bun add @blueshed/delta

Save this as try.ts:

import { Database } from "bun:sqlite";
import { createLocal } from "@blueshed/delta/local";
import { setLogLevel } from "@blueshed/delta/logger";
import { createTables, defineDoc, defineSchema, registerDocs } from "@blueshed/delta/sqlite";

setLogLevel("warn");

// A shopping list: a row per list, its items in a map.
const schema = defineSchema({
  lists: { columns: { title: "text?" }, temporal: false },
  items: { parent: "lists", columns: { text: "text", done: { type: "boolean", default: false } }, temporal: false },
});
const list = defineDoc("list:", { root: "lists", include: ["items"], implied: true });

const db = new Database(":memory:");
createTables(db, schema);

// Delta in this process. registerDocs(createWs(), ...) serves the same documents to browsers.
const delta = createLocal();
registerDocs(delta.server, db, schema, [list], [], { ledger: true });
delta.onPublish((doc, change) => console.log(doc, `v${change.v}`, JSON.stringify(change.ops)));

const ada = delta.as("ada");
const doc = "list:groceries";
await ada.call("open", { doc });
await ada.call("delta", { doc, cursor: "tab-1", ops: [{ op: "add", path: "/items/milk", value: { text: "milk" } }] });
await ada.call("delta", { doc, cursor: "tab-1", ops: [{ op: "replace", path: "/items/milk/done", value: true }] });
await ada.call("undo", { cursor: "tab-1" });

console.log((await ada.call("open", { doc })).result.items);

Run bun try.ts:

list:groceries v1 [{"op":"add","path":"/items/milk","value":{"id":"milk","text":"milk","lists_id":"groceries","done":false}}]
list:groceries v2 [{"op":"replace","path":"/items/milk","value":{"id":"milk","text":"milk","lists_id":"groceries","done":true}}]
list:groceries v3 [{"op":"replace","path":"/items/milk","value":{"id":"milk","text":"milk","lists_id":"groceries","done":false}}]
{
  milk: {
    id: "milk",
    text: "milk",
    lists_id: "groceries",
    done: false,
  },
}

Three writes, each heard as a change with its version. The last one is the undo, which the ledger worked out for itself. The document did not exist until its first write made it (implied: true).

Where the truth lives

Each kind of document registers on the same server, and the browser opens every one of them the same way.

| The truth is | Register it with | From | |---|---|---| | a JSON file | registerDocs(ws, file, schema, docs) | @blueshed/delta/json | | a SQLite database | registerDocs(ws, db, schema, docs) | @blueshed/delta/sqlite | | Postgres in this process | openPglite(dir?), then as a Postgres database | @blueshed/delta/pglite | | a Postgres database, shared by processes | createDocListener(ws, pool) and registerDocType(docTypeFromDef(def, pool)) | @blueshed/delta/postgres | | one free-form JSON document | await registerDoc(ws, name, { file, empty }) | @blueshed/delta/server | | this process (who is online) | registerMemory(ws, { prefix, empty }) | @blueshed/delta/kinds | | outside (a sensor, an API) | registerSource(ws, { prefix, read, every }) | @blueshed/delta/kinds | | the release (countries, units) | registerStatic(ws, { prefix, value }) | @blueshed/delta/kinds |

Start with a JSON file; move to SQLite, then Postgres in this process, then a Postgres server, without changing the app: the same schema, the same documents, the same writes, and the same answers from each -- serial ids, a write told to every open document that holds the rows it changed, one scope rule. Carry the data with exportTables from where it is and importTables into where it goes; ids and sequences carry, so the next row named follows on.

Undo comes with the ledger

Pass { ledger: true } to the JSON file, SQLite or Postgres and every write is recorded in the write's own transaction: what it did, its inverse, the document's version, who made it and the cursor undo walks. undo, redo and history then work with no more code. Over a socket the cursor is the connection, so a browser undoes only what it wrote:

const ws = connectWs("/ws");
await ws.send({ action: "undo" });   // or "redo"; answers null when there is nothing to walk
await ws.send({ action: "undo", change: 7 });   // one change of this cursor's, by its entry, not its last

On Postgres the ledger is in the database, so a write made in one process can be undone from another.

In the browser, or in the same process

Served over a socket with createWs(), a browser opens a document as a reactive value (the client needs @blueshed/railroad: bun add @blueshed/railroad):

import { connectWs, openDoc } from "@blueshed/delta/client";

const doc = openDoc("list:groceries", connectWs("/ws"));
await doc.ready;
doc.onOps((ops) => render(ops));   // every change, including your own
await doc.send([{ op: "replace", path: "/items/milk/done", value: true }]);

In a clone of this repository (examples/ is not in the npm package), bun examples/shared-state/server.ts runs a chat in two browser tabs on a JSON file, with no database and no schema.

Run in the same process with createLocal(), as in the example above, a server that renders its own pages, a job or a test speaks to delta by function call. as(identity) says who is writing, and onPublish is the one stream of changes to redraw from.

Pairs with

  • @blueshed/railroad draws in the browser. doc.data is a railroad signal, so its list() renders a collection row by row.
  • delta keeps the documents.
  • eta, a private server-rendering kernel, builds on delta in-process through createLocal().

Starting a new app? bun create blueshed my-app sets up delta and railroad together.

Optional peers

bun add @blueshed/delta installs none of these; add the ones the parts you use need.

| You use | Also add | |---|---| | @blueshed/delta/client (the browser) | @blueshed/railroad | | @blueshed/delta/postgres | pg (and @types/pg to type-check: delta ships TypeScript source) | | @blueshed/delta/auth-jwt | jose and pg |

The core, the JSON-file and SQLite backends, local, kinds, dom-ops and logger need nothing else.

Where to go next

  • The delta-doc skill is the manual: SKILL.md routes, reference.md has the API, patterns, auth, row-level security, the ledger, the kinds and the wire protocol. bunx @blueshed/delta install-skills copies it into your project for Claude Code.
  • examples/: shared-state (JSON file), sites-bbox (custom views on SQLite and Postgres), kanban (Postgres with railroad), todos-vs-rls (row-level security).
  • CHANGELOG.md for what changed in each release.

MIT licence.