Skip to content

284km/mere-notes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mere-notes

A realtime app written in Mere, built outside the compiler monorepo to dogfood the package system and surface real pain. See PAIN.md for the running friction log — that log is the point of this project as much as the app is.

main.mere is the collaborative note (milestone 4c). Earlier milestones are preserved in git history.

Milestones

  1. Single-instance WebSocket chat — JS-side auto-relay hub + server announcements via ws_broadcast. (m1 tag.)
  2. Multi-instance SSE + Redis pub/sub fan-out — a POST to any instance reaches SSE clients on every instance. Switched from WS to SSE+POST because cross-instance fan-out needs the server to see each message (PAIN P5/P6). (in the Milestone 2 commit.)
  3. Collaborative note (LWW) — a shared document with Redis as the authoritative store; edits POST the full text and fan out live. WS inbound was avoided via POST+Redis (PAIN P5). (Milestone 3 commit.)
  4. CRDT collaborative note. Edits are character-level RGA operations (crdt.mere) on a Redis op log, so concurrent edits converge with nothing lost — fixing M3's last-write-wins (PAIN P8).
    • 4b: server maps index intents to ops (convergent, but positions can drift under simultaneous typing). (Milestone 4b commit.)
    • 4c ← you are here: the RGA runs client-side and emits ops with real element ids, so editing is intent-preserving; the server is a thin op relay. Full Unicode code points client-side. (GET /api/note server-render is ASCII-only — Mere strings are byte-oriented, PAIN P10.)

Dependencies

Declared in mere.toml and installed with mere install (v0.2 package system) — .mere_modules/ is generated, not committed:

  • httpcontrib/http from merelang/mere (router / sse / escape / …)
  • dbcontrib/db from merelang/mere (redis / …)

mere install also pulls the transitive log package (contrib/http's access_log imports ../log/log.mere) and writes mere.lock with the resolved commit + a content hash. Packages land under their bare source-dir names so .mere_modules/ mirrors contrib/ and cross-package relative imports resolve — see PAIN P2.

Build & run

Only a mere binary is needed — mere install fetches both the contrib dependencies (.mere_modules/) and the Node runtime host (.mere_host/, from the [host] entry), so no compiler source tree is required at runtime. mere serve runs the compiled wasm on that vendored host.

mere install                                   # deps + host from mere.toml
docker run -d --name mere-notes-redis -p 15604:6379 redis:7   # pub/sub

mere -w main.mere > notes.wat
wat2wasm --enable-tail-call notes.wat -o notes.wasm

mere serve notes.wasm                          # → :8080

# two instances, to see cross-instance convergence (two shells)
PORT=8080 mere serve notes.wasm
PORT=8081 mere serve notes.wasm
# open http://localhost:8080/ and http://localhost:8081/ , type in one → the other converges

(mere serve just runs node .mere_host/run_http_server.js notes.wasm.)

Realtime needs the persistent node host (run_http_server.js + the sse_redis_bridge.js subscribe bridge), not a stateless Cloudflare Worker — long-lived streaming connections don't fit the request-scoped Worker model. Those host files are now vendored into .mere_host/ by mere install (PAIN P7), so the app carries its own runtime.

About

A realtime app built in Mere to dogfood its package system

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors