惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Vercel News
Vercel News
F
Fortinet All Blogs
月光博客
月光博客
G
Google Developers Blog
博客园 - Franky
GbyAI
GbyAI
The Cloudflare Blog
I
InfoQ
雷峰网
雷峰网
WordPress大学
WordPress大学
罗磊的独立博客
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
小众软件
小众软件
腾讯CDC
B
Blog
量子位
V
V2EX
S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
GitHub - russellromney/electrolite: ElectricSQL-style rea...
russellthehi · 2026-05-05 · via Hacker News: Show HN

Electric-style sync for SQLite apps, embeddable in your app.

Electrolite brings Electric-style reactive Shapes to SQLite. Your app defines a subset of rows once, the browser gets an initial snapshot, and then SQLite changes stream into the browser as live logical updates.

Example: a user opens project p1. The browser should see todos where project_id = "p1". If another request inserts, updates, moves, or deletes one of those todos, the browser should update without a full page refresh.

ElectricSQL's Electric Sync does this for Postgres: it exposes selected subsets of database rows called Shapes, sends an initial snapshot, then sends live logical changes. Electrolite is that idea for SQLite.

Electrolite does the SQLite version inside your TypeScript app using SQLite triggers, a durable change log, and an ordinary HTTP endpoint. The backend runs in plain Node using Node's built-in SQLite API. There is no native build, sidecar, npm install step, or separate sync service. The same small protocol can also be implemented by other embedded engines, starting with a tiny Python engine for Flask-style apps.

Experimental software.

SQLite becomes a live backend for browser state without letting the browser send SQL. Auth stays in your app, the sync endpoint is just a normal Request -> Response handler, and the code is small enough to read. The first target is small and medium apps where shared team, workspace, project, or document Shapes should be cheap over ordinary HTTP long-polling.

Tiny Example

You define a server-owned row set:

projectTodos: shape({
  table: "todos",
  columns: ["id", "project_id", "title", "done"],
  params: ["projectId"],
  where: ({ params }) => eq("project_id", params.projectId),
  authorize: ({ params, context }) => {
    return context.user.projects.has(params.projectId);
  },
})

Then a browser can subscribe to:

/electrolite/v1/projectTodos/p1

Meaning:

Give me todos for project p1, if this user is allowed to see p1.
Then keep me updated.

Try It

Electrolite is not published to npm yet. For now, the easiest path is to use this repository directly. You need Node 24 or newer.

git clone https://github.com/russellromney/electrolite.git
cd electrolite
npm run demo:web

Open http://localhost:3000. The left side writes todos to SQLite; the right side is a live Electrolite subscriber. Add, rename, delete, and batch-write todos to watch the Shape update.

Electrolite demo showing SQLite writes on the left and a live browser subscriber on the right

What Is A Shape?

Electrolite exposes selected subsets of database rows called Shapes.

A Shape is just:

table + columns + filter + auth scope

Example Shapes include todos for one project, photos owned by one user, events for one account, or likes on photos this user may see.

In Electrolite today, a Shape is server-defined. It contains a source table, a column allowlist, a predicate, an authorization scope, and a schema version. The predicate language is intentionally small right now: equality, IN, and conjunctions.

Browsers do not send arbitrary SQL. They request named Shapes that the host application has already defined and authorized.

That is the point. The browser can say "I want projectTodos/p1." It cannot say "run this SQL I made up."

Applications can also register dynamic, server-owned Shape routes such as /projects/:project_id/todos. The route turns request path/auth context into a concrete Shape, and the normal authorizer checks the generated authorization scope before SQLite is touched.

Use It Before npm

Until packages are published, treat Electrolite like a vendored library: add this repository to your app as a git submodule, subtree, or copied vendor/electrolite folder, then import the TypeScript-facing backend API by path:

import {
  createElectrolite,
  eq,
  shape,
} from "./vendor/electrolite/packages/electrolite-node/electrolite-node.ts";

Serve the browser client from your app, or copy clients/browser/electrolite.js into your frontend bundle.

The examples in this repo use the same path-import setup. There is no registry account, install token, or sidecar service involved.

Electrolite uses Node's built-in SQLite engine:

const electrolite = createElectrolite({ dbPath: "./app.db" });

Run the main test suite:

npm test

Run every package test:

npm run test:all

TypeScript Quick Start

Backend:

import {
  createElectrolite,
  eq,
  shape,
} from "./vendor/electrolite/packages/electrolite-node/electrolite-node.ts";

const electrolite = createElectrolite<{ user: { projects: Set<string> } }>({
  dbPath: "./app.db",
  shapes: {
    projectTodos: shape({
      table: "todos",
      columns: ["id", "project_id", "title", "done"],
      params: ["projectId"],
      where: ({ params }) => eq("project_id", params.projectId),
      scope: ({ params }) => `project:${params.projectId}`,
      authorize: ({ params, context }) => {
        return context.user.projects.has(params.projectId);
      },
    }),
  },
});

electrolite.executeBatch(`
  CREATE TABLE IF NOT EXISTS todos (
    id INTEGER PRIMARY KEY,
    project_id TEXT NOT NULL,
    title TEXT NOT NULL,
    done BOOLEAN NOT NULL DEFAULT 0
  );
`);
electrolite.installTriggers("todos");

export async function GET(request: Request) {
  const session = await getSession(request);
  return electrolite.handle(request, {
    user: { projects: await projectsForUser(session.userId) },
  });
}

Browser:

import { ShapeClient } from "./vendor/electrolite/clients/browser/electrolite.js";

const todos = new ShapeClient("/electrolite/v1/projectTodos/project-123");

todos.subscribe((rows) => {
  renderTodos(rows);
});

todos.start();

What happens:

  1. Browser asks for /electrolite/v1/projectTodos/project-123?offset=-1.
  2. Your TypeScript app checks the user can see project-123.
  3. Electrolite returns the current matching rows.
  4. Browser asks again with the returned offset and live=true.
  5. When matching SQLite rows change, the browser receives the change.

Under the hood, Electrolite installs SQLite triggers, records a durable logical change log, normalizes Shape handles against the SQLite schema, and uses replay boundaries so browsers do not publish half-applied batches.

You do not need to run a separate sync service for this path.

What Works Now

Electrolite currently supports server-defined Shapes with app-owned authorization, initial snapshots, live=true long-polling, inserts, updates, deletes, primary-key changes, and explicit batches. The browser client has IndexedDB persistence, retry, replay draining, multi-tab coordination, and durable log_id / shape_handle validation so cached rows are only reused against the right SQLite log and Shape definition.

The backend also handles key-column metadata, composite primary keys, retained-log resync, schema-normalized predicates, and targeted live wakeups for affected Shapes. This is still early, but the main TypeScript path works end to end, with E2E tests and a basic real web app example.

Fanout Smoke Test

The fanout demo starts many in-process browser clients against the embedded handler, puts them all into a live wait, performs one SQLite write, and checks that every client materializes the new row.

npm run demo:fanout
ELECTROLITE_FANOUT_CLIENTS=1000 npm run demo:fanout

On one local run, a single SQLite write woke 1000/1000 live Shape clients and all 1000 materialized the new row in about 100ms. This is a smoke test, not a network benchmark.

Future Direction

Next likely work: React hooks, tiny framework examples, benchmark numbers for snapshot/replay/live fanout, and Shape diagnostics that explain predicates, key columns, trigger status, and suggested SQLite indexes. Retention auto-compaction, better shared-Shape fanout, cacheable response chunks, and optional object-storage mode for immutable authorized Shape chunks are also on the table. Offline writes and conflict handling are a separate later track.

Non-goals

Electrolite is not trying to be Postgres replication, arbitrary client-provided SQL, offline writes or conflict resolution in the first version, or a required standalone sync daemon.

Roadmap

See ROADMAP.md. Completed work is tracked in CHANGELOG.md.

For the user-facing TypeScript API, start with packages/electrolite-node/README.md. For other embedded engines, see engines/.