Fluid protocol surface for Gleam

Canonical Fluid events as Socket.IO frames.

dewdrop sits between windsock's transport primitives and the full Fluid protocol model. It names the canonical events, keeps their positional payloads visible, and gives client and server runtimes a narrow adapter boundary.

Event names
dependency-free constants in dewdrop/events
Frame shape
windsock encodes Socket.IO text frames
Adapters
aquamarine client codec and beryl server codec
Status
pre-1.0, API unstable, not published on Hex

Fluid events over a narrow transport boundary.

dewdrop boundaryconnect_document(payload) -> 42["connect_document", payload]
Transport
windsock owns the raw event envelope.
Fluid name
connect_document lives in dewdrop/events.
Fluid payload
dewdrop keeps event arguments positional and explicit.
Runtime edge
Client and server adapters translate events into codec messages.
  1. encoded
  2. decoded
  3. response encoded

Small API, exact output.

Add the pre-1.0 git dependency, encode and decode Fluid event names through windsock, import the shared vocabulary, and use the beryl server codec when tests need the same adapter boundary.

  1. 1

    Add the git dependency

    Until Hex publishing, pin the Git dependency explicitly.

    Add the git dependency
    [dependencies]
    dewdrop = { git = "https://github.com/tylerbutler/dewdrop", ref = "main" }
  2. 2

    Encode a Fluid event

    Fluid meaning comes from the event name and positional args.

    Encode a Fluid event
    import dewdrop
    import gleam/json
    pub fn connect_frame() {
    dewdrop.encode_connect(
    json.object([#("id", json.string("doc-123"))])
    )
    }
    // 42["connect_document",{"id":"doc-123"}]
  3. 3

    Submit operations

    Operation messages stay in the ordered argument list.

    Submit operations
    import dewdrop
    import gleam/json
    pub fn submit_frame() {
    dewdrop.encode_submit_op(
    json.string("c1"),
    json.preprocessed_array([]),
    )
    }
    // 42["submitOp","c1",[]]
  4. 4

    Use the server codec

    beryl can decode and encode the same Fluid event stream.

    Use the server codec
    import dewdrop/server
    pub fn codec() {
    server.server_codec()
    }

The split is a stack, not a bigger package.

Each layer owns one kind of knowledge. Transport envelopes, Fluid event names, protocol semantics, and server behavior stay separate.

windsock

Transport framing primitives

Owns the lower-level event envelope and heartbeat packets that dewdrop builds on.

dewdrop

Fluid events and adapters

Names the Fluid event vocabulary and exposes client/server adapters over windsock.

spillway

Fluid protocol semantics

Owns typed Fluid messages, sequencing/session rules, summaries, signals, nacks, and JWT validation above the event adapter.

levee

Server runtime target

Consumes the protocol layers to run Fluid-compatible collaboration services in Gleam.

Complete Fluid event vocabulary, ready to import.

The constants live in dewdrop/events so protocol packages can share names without pulling in aquamarine or beryl. The groups below mirror the collaboration lifecycle instead of forcing you to reconstruct it from one flat list.

EventDirectionPurpose
Connection
connect_documentclient → serverBegin collaboration for a document.
connect_document_successserver → clientAcknowledge a successful document connection.
connect_document_errorserver → clientReject a document connection attempt.
closeeitherClose the document connection.
Operations
submitOpclient → serverSubmit operation messages for sequencing.
opserver → clientDeliver sequenced operations back to clients.
nackserver → clientReject submitted operations explicitly.
Signals
submitSignalclient → serverSend non-persistent collaboration signals.
signalserver → clientBroadcast non-persistent collaboration signals.
Summaries
submitSummaryclient → serverSubmit a summary for the document.
summaryAckserver → clientAcknowledge an accepted summary.
summaryNackserver → clientReject a submitted summary.