Your Cloudflare backend just went local-first. π
lunora now ships a Zero-class sync engine:
β shapes β declarative partial replication
β custom mutators β optimistic, server-authoritative
β a poke diff protocol β row-ops, not re-run queries
β offline outbox + live WebSocket sync
β TanStack DB collections, on-device
Instant, offline, real-time. On infra you own.
PolinRider has expanded beyond npm.
Socket researchers found malicious artifacts across npm, Packagist, Go modules, and Chrome extensions tied to the broader North Korean Contagious Interview / Famous Chollima campaign.
Details β https://t.co/DDpgAyjaAb
@CameronPak@reactjs@vuejs@solid_js@sveltejs It's not fully documented but lunora has a registry implementation, https://t.co/RDG7nszN1t it works like shadcn but for frontend and backend code π€―
Should lunora provide you default auth components, for @reactjs, @vuejs, @solid_js and @sveltejs on the init or add command?
The components will be inside our code, so editing adjusting will be super easy.
That's exactly how it works, it's called shapes.
You subscribe to a partition (a where predicate, server-resolved), and on each write we read our CDC op-log since your checkpoint and send only the row-level diff.
No full re-sync, no re-query, just the membership delta, merged in place on the client.
Reconnect resumes from your cursor.
Your Cloudflare backend just went local-first. π
lunora now ships a Zero-class sync engine:
β shapes β declarative partial replication
β custom mutators β optimistic, server-authoritative
β a poke diff protocol β row-ops, not re-run queries
β offline outbox + live WebSocket sync
β TanStack DB collections, on-device
Instant, offline, real-time. On infra you own.
Out of the box:
- Per-agent isolated DO SQLite: β .shardBy().
- Clients consuming the same live shapes: β shipped (defineShape + TanStack DB, exactly ElectricSQL-shape semantics).
What is missing:
- "Sync shapes from the multitenant Hyperdrive Postgres into those DOs": β no native CDC/replication and no DO-as-shape-consumer β but a manual ctx.sql (action) β ctx.db projection bridges it as a pull, after which shapes-to-clients is automatic.
What you can do today for the Postgresβagent part
Hand-roll the projection, which Lunora explicitly recommends as the reactive bridge:
1. In an action on the agent's DO, read the tenant-scoped slice from Hyperdrive: ctx.sql.query("β¦ WHERE tenant_id = $1", [tenantId]). (Multitenancy here is your WHERE clause. Hyperdrive gives one connection string per binding, no built-in tenant routing.)
2. Write those rows through ctx.db.insert/patch into the DO's own (sharded) SQLite. That write is tracked.
3. From there, defineShape + @lunora/db give you the full live shape β client story for free.
The Syncing shapes from multitenant Hyperdrive Postgres into the per-agent DO SQLite will be in the next version ;)
Thanks for the question, the next version of lunora will have this part fixed :)
client.onMutationSettled fires on every queued write's verdict, even post-reload, when the original Promise is long gone (hadAwaiter: false). the vanishing row now tells you why.
https://t.co/Dl5TgBGCoJ
@mats_zip - Tanstack db is used for the client?
- We do support hyperdrive https://t.co/hHcognmn64
Can you explain the durable object part more about the required shapes?
Did you know Lunora has auth built in?
@better_auth on your own Cloudflare account: email/password, OAuth, passkeys, 2FA, magic links, orgs. No separate auth service to run.
What are you using for auth right now, and what do you wish it did better?
Did you know Lunora lints your schema and queries?
Advisors flag unindexed foreign keys, duplicate indexes, and filters with no index behind them, before they hit prod.
What's the worst index mistake you've shipped?
On the client it's TanStack DB. lunoraCollectionOptions({ shape }) syncs a shape into a collection; useMutator(handle) runs the optimistic txn + watermarked push. Reads stay on useLiveQuery β no new query hook:
import { useLiveQuery } from "@tanstack/react-db";
import { useMutator } from "@lunora/react";
const { data: messages } = useLiveQuery((q) => q.from({ m: messagesCollection }));
const send = useMutator(api.mutators.sendMessage);
It's alpha β the sync engine is the newest thing in the repo. Try it on a side project and tell me where it breaks.
https://t.co/bteC3q03Jk
https://t.co/f4Q0mzzuYL
The shard DO is serialized, so there's no OCC-retry loop. Write only the columns you change with ctx.db.patch(id, { field }) and two offline edits to different fields of the same row both survive β per-column convergence end to end, no CRDT.
A watermark protocol (stable clientId + monotonic clientSeq) makes pushes idempotent and ordered.