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

@rotorsoft/act-sqlite

v1.13.0

Published

act sqlite adapters

Downloads

2,789

Readme

@rotorsoft/act-sqlite

NPM Version NPM Downloads License: MIT

SQLite event store for @rotorsoft/act via @libsql/client. File-based, edge-ready, ACID — for single-node deployments. Lane-aware claim/ack via streams.lane + streams_lane_ix since v0.9.0 (ACT-1103).

Why this package

Not every Act app needs Postgres. Single-server apps, embedded deployments, edge functions, and unit tests all want the same thing: a real event store with ACID guarantees, but no operational overhead. SqliteStore is that — @libsql/client under the hood (zero native bindings, browser-incompatible parts already stripped), full conformance with Act's Store port, the same one-line bootstrap swap.

SQLite serializes all writes at the database level. For a single-server deployment this gives you the same isolation guarantees as Postgres's FOR UPDATE SKIP LOCKED without any coordination layer. When you outgrow that — multi-server distributed processing, sub-poll cross-process wakeup — swap in @rotorsoft/act-pg. Application code doesn't change.

Installation

pnpm add @rotorsoft/act @rotorsoft/act-sqlite

Quick start

import { act, state, store } from "@rotorsoft/act";
import { SqliteStore } from "@rotorsoft/act-sqlite";
import { z } from "zod";

// File-based persistence
store(new SqliteStore({ url: "file:myapp.db" }));

// One-time schema setup (idempotent — safe to leave in your bootstrap).
await store().seed();

const Counter = state({ Counter: z.object({ count: z.number() }) })
  .init(() => ({ count: 0 }))
  .emits({ Incremented: z.object({ amount: z.number() }) })
  .patch({ Incremented: ({ data }, s) => ({ count: s.count + data.amount }) })
  .on({ increment: z.object({ by: z.number() }) })
  .emit((a) => ["Incremented", { amount: a.by }])
  .build();

const app = act().withState(Counter).build();
await app.do("increment", { stream: "c1", actor: { id: "1", name: "u" } }, { by: 1 });

API

  • SqliteStore — class implementing Act's Store port. Construct once, pass to store().
  • SqliteConfig — constructor options (url, authToken).

Full type reference: typedoc.

Configuration

| Option | Default | Description | |---|---|---| | url | required | libSQL connection URL. Use file:path.db for a persistent file, libsql://… for Turso, :memory: for the shared in-memory database. | | authToken | — | Auth token for libSQL server connections (Turso). |

File-based persistence

store(new SqliteStore({ url: "file:data/events.db" }));

In-memory (tests / quick experiments)

store(new SqliteStore({ url: ":memory:" }));

There is no default url — a store has to be told where to write, and constructing one without a URL throws. libSQL gives every connection its own private in-memory database and does not pin statements to a single connection, so a zero-config store used to accept writes into a database the next statement could not see. :memory: is therefore normalized to libSQL's shared-cache form, the only one that round-trips.

That comes with a caveat: the shared-cache database is one per process, visible to every store pointed at it, and it outlives dispose(). For isolated throwaway state — parallel tests, two independent stores in one process — use InMemoryStore from @rotorsoft/act, or give each store its own file: path.

Turso (edge)

store(new SqliteStore({
  url: process.env.TURSO_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN,
}));

Common patterns

Schema setup

await store().seed();

Idempotent. Creates the events table, the streams (subscription) table, and the indexes that support claim ordering. PRAGMA journal_mode=WAL is set at the same time so readers don't block writers. Safe to leave in your bootstrap.

Concurrency model

SQLite serializes write transactions at the database level. No application-layer locking, no FOR UPDATE SKIP LOCKED needed — writes queue automatically and ack/block validate leased_by to prevent stale workers from interfering. For a single-server deployment, this gives the same isolation guarantees as Postgres.

Database schema reference

Created by seed():

  • Events (events): id (INTEGER PRIMARY KEY AUTOINCREMENT), name, data (TEXT/JSON), stream, version, created (ISO 8601), meta (TEXT/JSON). Unique index on (stream, version).
  • Streams (streams): stream (PK), source, at, retry, blocked, error, leased_by, leased_until, priority. Composite index on (blocked, priority DESC, at).

When to use this vs act-pg

| You want… | Use | |---|---| | Single server / embedded / edge | act-sqlite | | Zero infrastructure setup (file path is the config) | act-sqlite | | Edge runtime with Turso replication | act-sqlite (with Turso URL) | | Multi-server, distributed processing | act-pg | | Sub-poll cross-process reaction latency | act-pg (with notify: true) | | Heavy write contention across many writers | act-pg |

Both adapters pass the same runStoreTck suite. Application code doesn't change between them; only the bootstrap line differs.

What's intentionally not implemented

Store.notify is absent. The notify hook is a cross-process wake-up signal that lets a horizontally-scaled deployment skip polling lag on remote commits. SQLite is single-node by design — there's no remote writer to be notified of — so the Act orchestrator falls back to the existing debounce/poll path, which is correct for this topology. If you outgrow it, switch to @rotorsoft/act-pg.

Compatibility

  • Node: >=22.18.0
  • Peer: @rotorsoft/act >=0.39.0, zod ^4.4.3
  • Bundled deps: @libsql/client ^0.17.3 (no native bindings)
  • Module formats: ESM + CJS
  • Runtimes: Node, Bun, Deno (libSQL pure-TS implementation); also runs in Turso-compatible edge environments

Stability

Public API governed by the Act Stability Charter. SqliteStore implements the Store contract from @rotorsoft/act and is validated against @rotorsoft/act-tck on @libsql/client pinned + latest in CI. Charter is in effect as of 1.0.0; the milestone tracker is milestone 1.0.

Versioning note. Version 1.0.0 is reserved on the npm registry from a prior publish and cannot be republished. The first 1.x release of this package on npm is 1.0.1; its public surface is identical to the intended 1.0.0 cut.

Related packages

Documentation

License

MIT