Packages

A small, typed, ergonomic WebSocket layer for Gleam applications built on top of Mist

Current section

Files

Jump to
wist src wist.erl
Raw

src/wist.erl

-module(wist).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/wist.gleam").
-export([raw_codec/0, handler/2, get_init_state/1, get_update/1]).
-export_type([context/0, close_frame/0, close_reason/0, decode_error/0, encode_error/0, socket_error/0, frame/0, event/1, effect/1, codec/2, handler/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Wist provides a transport-neutral, stateful WebSocket programming model for Gleam.\n"
"\n"
" This module contains the core data structures, codecs, events, effects, and handler\n"
" constructors. It represents the \"port\" in Wist's ports-and-adapters architecture,\n"
" defining the API interface that developers use to write WebSocket connection logic.\n"
"\n"
" Transports (like the Mist web server) consume the `Handler` defined here and run it\n"
" using a specific transport adapter (e.g. `wist/adapters/mist`).\n"
).
-type context() :: {context,
binary(),
list({binary(), binary()}),
gleam@option:option(binary())}.
-type close_frame() :: {close_frame, integer(), binary()}.
-type close_reason() :: normal | {abnormal, binary()} | unknown.
-type decode_error() :: {decode_error, binary()}.
-type encode_error() :: {encode_error, binary()}.
-type socket_error() :: {socket_error, binary()}.
-type frame() :: {text, binary()} |
{binary, bitstring()} |
{ping, bitstring()} |
{pong, bitstring()} |
{close, gleam@option:option(close_frame())}.
-type event(MZX) :: opened |
{message, MZX} |
{closed, close_reason()} |
{failed, socket_error()}.
-type effect(MZY) :: {send, MZY} |
{send_frame, frame()} |
{close_connection, gleam@option:option(close_frame())}.
-type codec(MZZ, NAA) :: {codec,
fun((frame()) -> {ok, MZZ} | {error, decode_error()}),
fun((NAA) -> {ok, frame()} | {error, encode_error()})}.
-opaque handler(NAB, NAC, NAD) :: {handler,
fun((context()) -> NAB),
fun((NAB, event(NAC)) -> {NAB, list(effect(NAD))})}.
-file("src/wist.gleam", 127).
?DOC(
" A no-op codec that maps raw `Frame`s directly to and from themselves.\n"
"\n"
" Useful for handlers that process raw text or binary frames directly.\n"
"\n"
" ### Example\n"
" ```gleam\n"
" import wist\n"
"\n"
" let codec = wist.raw_codec()\n"
" ```\n"
).
-spec raw_codec() -> codec(frame(), frame()).
raw_codec() ->
{codec, fun(Frame) -> {ok, Frame} end, fun(Frame@1) -> {ok, Frame@1} end}.
-file("src/wist.gleam", 162).
?DOC(
" Constructor to create a stateful WebSocket handler.\n"
"\n"
" The handler defines:\n"
" 1. `init_state`: How to construct the connection state from the `Context`.\n"
" 2. `update`: A pure reducer mapping state and events to state transitions and effects.\n"
"\n"
" ### Example\n"
" ```gleam\n"
" import wist\n"
"\n"
" let echo = wist.handler(\n"
" init_state: fn(_ctx) { Nil },\n"
" update: fn(state, event) {\n"
" case event {\n"
" wist.Message(frame) -> #(state, [wist.SendFrame(frame)])\n"
" _ -> #(state, [])\n"
" }\n"
" }\n"
" )\n"
" ```\n"
).
-spec handler(
fun((context()) -> NAG),
fun((NAG, event(NAH)) -> {NAG, list(effect(NAJ))})
) -> handler(NAG, NAH, NAJ).
handler(Init_state, Update) ->
{handler, Init_state, Update}.
-file("src/wist.gleam", 172).
?DOC(false).
-spec get_init_state(handler(NAP, any(), any())) -> fun((context()) -> NAP).
get_init_state(Handler) ->
erlang:element(2, Handler).
-file("src/wist.gleam", 181).
?DOC(false).
-spec get_update(handler(NAV, NAW, NAX)) -> fun((NAV, event(NAW)) -> {NAV,
list(effect(NAX))}).
get_update(Handler) ->
erlang:element(3, Handler).