@sh1n4ps/plasma-client
v0.2.0
Published
IndexedDB engine, optimistic mutate, push/pull sync with rebase, and reactive live queries. Runs against any HTTP endpoint that speaks the plasma sync protocol.
Downloads
80
Maintainers
Readme
@sh1n4ps/plasma-client
Browser-side runtime for plasma. Owns the IndexedDB storage, the reactive engine live queries subscribe to, and the sync loop — outbox → push → pull → rebase → notify.
Install
pnpm add @sh1n4ps/plasma-client @sh1n4ps/plasma-coreQuick shape
import { createPlasmaClient, createWebSocketSubscription } from "@sh1n4ps/plasma-client"
const plasma = createPlasmaClient({
schema, mutators, // from @sh1n4ps/plasma-core
dbName: "todos",
endpoint: "/sync", // your worker route
schemaVersion: "v1",
clientGroupID: getInstallId(), // persist yourself
getContext: () => ({ userId: currentUser.id }), // per-mutation ctx
subscribe: createWebSocketSubscription({
url: "wss://api/sync/coordinator",
room: "global",
}),
})
plasma.start()
// Reads
const todos = await plasma.db.select().from(todos)
const live = plasma.db.select().from(todos).where(eq(todos.done, 0)).live()
live.subscribe(rows => render(rows))
// Optimistic mutation (rebase v1 heals if the server rejects)
await plasma.mutate("createTodo", {
id: plasma.newId(),
title: "buy milk",
updatedAt: Date.now(),
})What lives here
createPlasmaClient— the top-level factory. Wires the IDB engine, outbox, cookie, identity, push, pull, rebase, and (optional) realtime subscription. Exposesdb,mutate,newId,pullOnce,pushOnce,start,stop,flush.createIdbEngine— the naive but honest AST evaluator. Usesidbunder the hood. Also exportspauseNotifications/resumeNotificationswhich the sync client uses to silence reactive subscribers during a rebuild.createWebSocketSubscription— auto-reconnecting WS client for theSyncCoordinatorDO. Yieldssubscribe: (onPoke) => unsubscribeyou plug straight intoPlasmaClientOptions.subscribe.baseStoreName,META_STORE,OUTBOX_STORE— the internal IDB store names, exported for tooling (a DevTools panel etc.).
Design notes
- Rebase v1: every user table has a shadow
_plasma_base_<name>store that mirrors server-canonical rows. After each pull the outbox drops confirmed mutations, then the optimistic view is rebuilt from base + replayed outbox. A mutation the server silently rejected (auth deny / errored mutator) heals on the next round-trip with no manual reset. - Inflight queue: pushes, pulls, and mutations are chained through a single-slot inflight promise so concurrent calls stay FIFO consistent with the outbox on disk.
newId(): pre-generate the mutation's id at the call site (before passing intoargs) so the optimistic and canonical runs agree.
Runtime footprint
Browser-only ESM with a single runtime dependency: idb.
