MoonBit implementation of a Cumulo-style diff transport.
The structural diff and patch engine now lives in tiye/cumulo/recollect. The root tiye/cumulo package keeps the sample state and the demo-facing types used by the examples in this repository.
This repo also contains a full end-to-end demo with:
- authoritative server state
- per-session twig projection
- WebSocket snapshot and delta sync
- browser client applying structural patches
Core packages:
recollect: standalone structural diff/patch enginetiye/cumulo: sample types and compatibility helpers aroundrecollect
Mainline demo packages:
app/shared: domain model, client protocol, pure updater, twig projectionapp/server: authoritative store plus the Node WebSocket runtime entryapp/browser: browser UI, WebSocket client runtime, and browser JS entry
Example packages:
examples/todo-sync/shared: sync protocol and pure reducer for the typed todo exampleexamples/todo-sync/server: in-memory authoritative store for the exampleexamples/todo-sync/client: client-side patch application for the exampleexamples/todo-sync: runnable example entry withmoon run ./examples/todo-sync
Package-level API notes for recollect live in recollect/README.md.
Install the Node runtime dependencies and start the app:
npm install
npm startThen open http://127.0.0.1:5173.
Notes:
- Vite serves the page shell on port
5173. - The MoonBit backend only owns the WebSocket server on port
5022. - When the browser is served from Vite, the client connects directly to
ws://127.0.0.1:5022/ws. localhost:5173usually works too, but127.0.0.1avoids local IPv6 collisions if another dev server is already bound on::1:5173.
Quick smoke login:
- username:
demo - password:
demo
moon test ./recollect
moon test ./app/shared ./app/server
moon test ./examples/todo-sync/client
moon run ./examples/todo-sync
npm run buildDerived MoonBit enum JSON uses array form for payload-bearing constructors.
Examples:
["UserLogIn", {"username": "demo", "password": "demo"}]
["RouteChange", {"route": "Members"}]Server events are also enum arrays, for example:
["Snapshot", {"seq": 1, "store": {"session_id": "..."}}]
["Delta", {"seq": 2, "patches": [["Set", {"path": [["Field", "logged_in"]], "value": true}]]}]recollect is intentionally kept as a leaf package:
- its public API lives under
recollect/ - its package-level docs live in
recollect/README.md - it only depends on
moonbitlang/core/json
That means the future publishing paths stay simple:
- move
recollect/into its own repository and make it the new MoonBit module root - or keep this repo as the integration/demo repo and promote
recollect/into a dedicated MoonBit workspace/module that is published on its own
The current repo shape already keeps that extraction mechanical. No extra workspace-specific publishing metadata is required yet.
The current implementation was validated with:
npm run build- HTTP shell served from
http://127.0.0.1:5173 - WebSocket backend served from
ws://localhost:5022/ws - initial WebSocket
Snapshot - login operation returning a
Delta - multi-page bulletin sync confirmed between two browser tabs