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

@livevariant/postgres

v0.1.1

Published

PostgreSQL state store for LiveVariant: a StateStore adapter whose event log and derived cache live in Postgres, plus the drizzle schema so an embedding application can own the migrations

Readme

@livevariant/postgres

PostgreSQL state store for LiveVariant: the event log and derived cache in Postgres, behind the same StateStore contract the Durable Object deployment implements.

npm install @livevariant/postgres

Use it

import { createApp } from "@livevariant/server";
import { PostgresStore, poolQueryable } from "@livevariant/postgres";
import pg from "pg";

const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const app = createApp({ store: new PostgresStore(poolQueryable(pool)) });

poolQueryable covers node-postgres. Anything else that can run a parameterized statement and open a transaction can implement Queryable directly: it is two methods, and the store needs nothing else.

The driver must support transactions (replaceDerived and updatePolicy use them), which rules out HTTP-only drivers such as drizzle-orm/neon-http. Use a wire-protocol connection.

The tables

Five: livevariant_assignments (the event log), plus livevariant_counters, livevariant_blobs, livevariant_shapes and livevariant_policies. There are two ways to create them, and which one you want depends on whether you already run migrations.

If you use drizzle, re-export the schema and let your own drizzle-kit generate own these tables alongside your app's:

// src/db/schema.ts
export * from "@livevariant/postgres/schema";

drizzle-kit picks up re-exported tables, so they land in your migration chain, get reviewed in your pull requests, and a column added by a future version of this package shows up as a pending migration rather than as drift. drizzle-orm is an optional peer dependency; only this entry point needs it.

Otherwise, run the SQL:

import { LIVEVARIANT_SCHEMA_SQL } from "@livevariant/postgres";
await pool.query(LIVEVARIANT_SCHEMA_SQL);

It is idempotent, so running it on every boot is fine.

Why the SQL is written out

Every method the store contract calls atomic is one statement, and the shape of each one is load-bearing:

  • putAssignmentIfAbsent upserts with a no-op DO UPDATE, so RETURNING fires on the conflict path and the loser of a race reads back the winner in the same round trip. xmax = 0 distinguishes the insert.
  • addReward returns the post-update row, so subtracting the delta recovers the previous total; that is what makes first fire exactly once per assignment.
  • putBlob is a compare-and-set: the WHERE on the DO UPDATE is re-evaluated under the row lock, so of N writers holding the same version exactly one wins.
  • incrCounters drops zero deltas, so a serve upserts one row rather than rewriting a thousand-element array.

The Durable Object deployment gets serialization for free and can use plain read-modify-write. Postgres does not, and an adapter written that way passes every sequential test and then loses conversions under real traffic.

That claim is tested rather than asserted: the package runs LiveVariant's storeContract twice, once against PGlite (real Postgres in WASM, no server needed) and once against a real server when LV_TEST_POSTGRES_URL is set. Only the second one proves the concurrency cases, because PGlite is a single connection and the races serialize; CI runs both.

License

AGPL-3.0