Skip to content

Beryl ecosystem

Aquamarine is one piece of a small constellation of Gleam packages that together provide a Phoenix Channels–compatible client/server stack on the BEAM. This page maps out where Aquamarine sits and what each of its neighbours does.

  • Beryl — the server side of the ecosystem. A Phoenix-compatible channel server written in Gleam. Aquamarine talks to Beryl, but is not coupled to it — any Phoenix Channels–compatible server works.
  • Aquamarine — the protocol-agnostic client runtime. The socket lives in an OTP actor that owns the connection, the ref counter, the heartbeat, reconnect, and the per-topic routing table, and delegates wire format decisions to a configurable codec.
  • aquamarine/phoenix — the bundled codec adapter that makes Aquamarine speak the Phoenix Channels wire format. See Phoenix and Beryl for usage.
  • Collie — the underlying WebSocket client. It is push-shaped: inbound frames arrive at a callback rather than being pulled, which is the shape Aquamarine's socket actor wants. It passes the full Autobahn suite, reassembles fragmented messages with explicit size caps, and applies system CA certificates and hostname verification on the wss scheme.
  • Roost — the Phoenix frame library. Provides the canonical [join_ref, ref, topic, event, payload] encode/decode and the protocol event-name constants. Both Aquamarine's Phoenix codec and the Beryl server build on it, which is why they stay in sync.

The diagram above also shows what you can and cannot replace:

  • Codec is pluggable. Replace aquamarine/phoenix with your own Codec to talk to a different protocol — the channel runtime does not change.
  • Server is pluggable. Aquamarine has no compile-time dependency on Beryl. Anything that speaks the codec you configured will work.
  • Transport is swappable in principle, fixed in practice. The internal Transport seam is @internal: a Connector is handed a sink subject at connect time and pushes every inbound frame into it, and outbound sending is fire-and-forget. Collie is the only implementation shipped, and the seam mainly exists so tests can drive an in-memory transport — but it is a genuine seam, and swapping it was how Aquamarine moved off its previous transport.