[{"name":"WebsocketSimple","comment":" A small, typed WebSocket client for Elm with a compact, auditable JavaScript runtime. It supports multiple connections, lifecycle events, and text, binary, or JSON messages.\n\n\n# Installation\n\nInstall the Elm package:\n\n```sh\nelm install mbr/elm-wss\n```\n\nElm packages cannot declare ports. Make `Main.elm` a `port module`, or use another application-owned `port module`, then add these declarations:\n\n    import WebsocketSimple exposing (CommandPort, EventPort)\n\n    port wsCmd : CommandPort msg\n\n    port wsMsg : EventPort msg\n\nThe JavaScript runtime expects the exact port names `wsCmd` and `wsMsg`.\n\nCopy [`js/elm-websockets.js`](https://github.com/mbr/elm-wss/blob/2.0.0/js/elm-websockets.js) into the browser assets. Load the runtime and compiled Elm application, initialize Elm, and then initialize the runtime:\n\n```html\n<script src=\"elm-websockets.js\"></script>\n<script src=\"app.js\"></script>\n<script>\nvar app = Elm.Main.init({\n  node: document.getElementById(\"elm\")\n});\nElmWebsockets.initApp(app);\n</script>\n```\n\nThe JavaScript initialization is a no-op when the application does not contain the command port, so it can remain in the bootstrap while WebSocket code is temporarily unused.\n\n\n# Ports\n\nPass the application-owned ports described by these aliases to commands and subscriptions.\n\n@docs CommandPort, EventPort\n\n\n# Basic usage\n\nSubscribe to events before opening a connection, and wait for `Connected` before transmitting:\n\n    import WebsocketPorts as Ports\n    import WebsocketSimple as WebSocket\n\n    type Msg\n        = WebSocketEvent WebSocket.RawMsg\n\n    init : () -> ( List String, Cmd Msg )\n    init _ =\n        ( [], WebSocket.open Ports.wsCmd \"ws://127.0.0.1:8765\" )\n\n    update : Msg -> List String -> ( List String, Cmd Msg )\n    update msg model =\n        case msg of\n            WebSocketEvent (WebSocket.Connected _) ->\n                ( model, WebSocket.send Ports.wsCmd (WebSocket.Transmit \"hello\") )\n\n            WebSocketEvent (WebSocket.Text value) ->\n                ( value :: model, WebSocket.close Ports.wsCmd )\n\n            WebSocketEvent (WebSocket.Binary _) ->\n                ( model, WebSocket.close Ports.wsCmd )\n\n            WebSocketEvent (WebSocket.Disconnected _) ->\n                ( model, Cmd.none )\n\n            WebSocketEvent (WebSocket.TransportError error) ->\n                ( WebSocket.errorToString error :: model, Cmd.none )\n\n    subscriptions : List String -> Sub Msg\n    subscriptions _ =\n        Sub.map WebSocketEvent (WebSocket.subscribe Ports.wsMsg)\n\n\n# Commands\n\n`send` and its convenience functions use an implicit `\"default\"` handle. Use `sendWithHandle` for multiple connections.\n\n@docs Cmd, CloseRequest, open, close, send, sendWithHandle\n\n\n# Handles\n\nEach connection is identified by an opaque handle encoded as a string at the port boundary.\n\n    chat : WebSocket.Handle\n    chat =\n        WebSocket.handle \"chat\"\n\n    alerts : WebSocket.Handle\n    alerts =\n        WebSocket.handle \"alerts\"\n\n    openConnections : Cmd msg\n    openConnections =\n        Cmd.batch\n            [ WebSocket.sendWithHandle Ports.wsCmd chat (WebSocket.Open chatUrl [])\n            , WebSocket.sendWithHandle Ports.wsCmd alerts (WebSocket.Open alertsUrl [])\n            ]\n\n@docs Handle, handle, handleToString\n\n\n# Events\n\n`subscribe` discards handle information. Use `subscribeWithHandle` to distinguish events from multiple connections.\n\n    type Msg\n        = WebSocketEvent ( WebSocket.Handle, WebSocket.RawMsg )\n\n    subscriptions : model -> Sub Msg\n    subscriptions _ =\n        Sub.map WebSocketEvent (WebSocket.subscribeWithHandle Ports.wsMsg)\n\n@docs RawMsg, CloseDetails, TransportErrorKind, TransportErrorDetails, subscribe, subscribeWithHandle, errorKindToString, errorToString\n\n\n# JSON\n\nRegular subscriptions expose incoming text and binary frames as `Text String` and `Binary Bytes`. Typed subscriptions decode text frames while keeping transport errors separate from payload decoding failures. A binary frame received through a typed JSON subscription produces an `UnsupportedData` transport failure.\n\n    import Json.Decode as Decode\n\n    type alias Payload =\n        { message : String }\n\n    payloadDecoder : Decode.Decoder Payload\n    payloadDecoder =\n        Decode.map Payload (Decode.field \"message\" Decode.string)\n\n    type Msg\n        = WebSocketMessage (WebSocket.Msg Payload)\n\n    subscriptions : model -> Sub Msg\n    subscriptions _ =\n        WebSocket.subscribeMsg Ports.wsMsg payloadDecoder WebSocketMessage\n\n@docs Msg, subscribeMsg, subscribeMsgWithHandle, transmitMsg, transmitMsgWithHandle, parseIncoming\n\n","unions":[{"name":"Cmd","comment":" Command sent to a WebSocket connection.\n\n  - `Open` opens the URL with an ordered list of requested subprotocols. An empty list requests none.\n  - `Transmit` sends a text frame.\n  - `TransmitBinary` sends a binary frame.\n  - A rejected transmission produces a `TransportError`; an accepted transmission produces no acknowledgement.\n  - `Close Nothing` preserves the browser's default close behavior. `Close (Just request)` sends the supplied code and reason unchanged, leaving validation to the browser.\n\n","args":[],"cases":[["Open",["WebsocketSimple.Url","List.List String.String"]],["Transmit",["String.String"]],["TransmitBinary",["Bytes.Bytes"]],["Close",["Maybe.Maybe WebsocketSimple.CloseRequest"]]]},{"name":"Handle","comment":" Identifies a particular WebSocket connection.\n","args":[],"cases":[]},{"name":"Msg","comment":" Typed event received from a WebSocket connection carrying JSON text frames.\n\nTransport failures remain separate from payload decoding failures. `PayloadDecodeFailure` retains both the original text and the `Json.Decode.Error`.\n\n","args":["t"],"cases":[["Established",["Maybe.Maybe String.String"]],["Closed",["WebsocketSimple.CloseDetails"]],["Received",["t"]],["TransportFailure",["WebsocketSimple.TransportErrorDetails"]],["PayloadDecodeFailure",["String.String","Json.Decode.Error"]]]},{"name":"RawMsg","comment":" Raw event received from a WebSocket connection.\n\n  - `Connected` means the connection can transmit and contains the negotiated subprotocol, if any.\n  - `Disconnected` contains the browser's close details and may occur without a preceding `Connected` event.\n  - `Text` contains a received text frame.\n  - `Binary` contains a received binary frame.\n  - `TransportError` describes a construction, send, close, browser, unsupported-data, or port-decoding failure.\n\nEvents preserve browser delivery order even though binary reads are asynchronous.\n\n","args":[],"cases":[["Connected",["Maybe.Maybe String.String"]],["Disconnected",["WebsocketSimple.CloseDetails"]],["Text",["String.String"]],["Binary",["Bytes.Bytes"]],["TransportError",["WebsocketSimple.TransportErrorDetails"]]]},{"name":"TransportErrorKind","comment":" Categorizes a WebSocket transport error.\n","args":[],"cases":[["ConstructionFailure",[]],["SendFailure",[]],["CloseFailure",[]],["BrowserFailure",[]],["SendRejection",[]],["UnsupportedData",[]],["PortDecodingFailure",[]]]}],"aliases":[{"name":"CloseDetails","comment":" Details supplied when a WebSocket closes.\n\nThe event may arrive even when the connection never opened. `initiatedLocally` records whether this client successfully requested closure.\n\n","args":[],"type":"{ code : Basics.Int, reason : String.String, wasClean : Basics.Bool, initiatedLocally : Basics.Bool }"},{"name":"CloseRequest","comment":" Describes an application-requested close.\n\nUse an empty reason to send only the explicit close code.\n\n","args":[],"type":"{ code : Basics.Int, reason : String.String }"},{"name":"CommandPort","comment":" Type of an application-owned port that sends encoded commands to the JavaScript runtime.\n","args":["msg"],"type":"( String.String, String.String, Json.Encode.Value ) -> Platform.Cmd.Cmd msg"},{"name":"EventPort","comment":" Type of an application-owned port that receives encoded events from the JavaScript runtime.\n","args":["msg"],"type":"(( String.String, String.String, Json.Encode.Value ) -> msg) -> Platform.Sub.Sub msg"},{"name":"TransportErrorDetails","comment":" Describes a categorized WebSocket transport error.\n","args":[],"type":"{ kind : WebsocketSimple.TransportErrorKind, message : String.String }"}],"values":[{"name":"close","comment":" Close the implicit default connection with the browser's default status.\n","type":"WebsocketSimple.CommandPort msg -> Platform.Cmd.Cmd msg"},{"name":"errorKindToString","comment":" Render a transport error category as a string.\n","type":"WebsocketSimple.TransportErrorKind -> String.String"},{"name":"errorToString","comment":" Render a transport error as a readable string containing its category and message.\n","type":"WebsocketSimple.TransportErrorDetails -> String.String"},{"name":"handle","comment":" Construct a WebSocket handle from its port-boundary representation.\n","type":"String.String -> WebsocketSimple.Handle"},{"name":"handleToString","comment":" Return a WebSocket handle's string representation.\n","type":"WebsocketSimple.Handle -> String.String"},{"name":"open","comment":" Open the implicit default connection without requesting a subprotocol.\n","type":"WebsocketSimple.CommandPort msg -> String.String -> Platform.Cmd.Cmd msg"},{"name":"parseIncoming","comment":" Convert a raw event into a typed JSON event.\n","type":"Json.Decode.Decoder t -> WebsocketSimple.RawMsg -> WebsocketSimple.Msg t"},{"name":"send","comment":" Send a command to the implicit `\"default\"` connection.\n","type":"WebsocketSimple.CommandPort msg -> WebsocketSimple.Cmd -> Platform.Cmd.Cmd msg"},{"name":"sendWithHandle","comment":" Send a command to the connection identified by a handle.\n","type":"WebsocketSimple.CommandPort msg -> WebsocketSimple.Handle -> WebsocketSimple.Cmd -> Platform.Cmd.Cmd msg"},{"name":"subscribe","comment":" Subscribe to raw events from the implicit default connection.\n\nThis discards the originating handle from every event.\n\n","type":"WebsocketSimple.EventPort WebsocketSimple.RawMsg -> Platform.Sub.Sub WebsocketSimple.RawMsg"},{"name":"subscribeMsg","comment":" Subscribe to typed JSON events while discarding handle information.\n","type":"WebsocketSimple.EventPort msg -> Json.Decode.Decoder t -> (WebsocketSimple.Msg t -> msg) -> Platform.Sub.Sub msg"},{"name":"subscribeMsgWithHandle","comment":" Subscribe to typed JSON events paired with their originating handles.\n","type":"WebsocketSimple.EventPort msg -> Json.Decode.Decoder t -> (( WebsocketSimple.Handle, WebsocketSimple.Msg t ) -> msg) -> Platform.Sub.Sub msg"},{"name":"subscribeWithHandle","comment":" Subscribe to raw events paired with their originating handles.\n","type":"WebsocketSimple.EventPort ( WebsocketSimple.Handle, WebsocketSimple.RawMsg ) -> Platform.Sub.Sub ( WebsocketSimple.Handle, WebsocketSimple.RawMsg )"},{"name":"transmitMsg","comment":" Encode a value as JSON and transmit it through the implicit default connection.\n","type":"WebsocketSimple.CommandPort msg -> (t -> Json.Encode.Value) -> t -> Platform.Cmd.Cmd msg"},{"name":"transmitMsgWithHandle","comment":" Encode a value as JSON and transmit it through the connection identified by a handle.\n","type":"WebsocketSimple.CommandPort msg -> WebsocketSimple.Handle -> (t -> Json.Encode.Value) -> t -> Platform.Cmd.Cmd msg"}],"binops":[]},{"name":"WebsocketSimple.Connection","comment":" A managed WebSocket connection.\n\nThe connection manager keeps a WebSocket connected and reconnects when it closes\nor reports a connection failure. By default, it retries immediately, then backs off\nexponentially from 250 milliseconds to a maximum delay of one minute. Retries are\nunlimited, and establishing a connection resets the backoff.\n\nEach attempt has its own handle by default; see Delayed replies below. The manager\nhandles connection lifecycle and retries so your application can focus on its\nprotocol.\n\nUsing the application-owned ports described in `WebsocketSimple`, this example\nreplies to server-sent text with its reverse and counts palindromic inputs:\n\n    import WebsocketPorts as Ports\n    import WebsocketSimple.Connection as Connection\n\n    type alias Model =\n        { connection : Connection.Model\n        , palindromes : Int\n        }\n\n    type Msg\n        = ConnectionMsg Connection.Msg\n        | OtherMessage\n\n    init : () -> ( Model, Cmd Msg )\n    init _ =\n        let\n            ( connection, action ) =\n                Connection.init (Connection.config \"wss://example.com/messages\")\n        in\n        ( { connection = connection, palindromes = 0 }\n        , Connection.perform Ports.wsCmd ConnectionMsg action\n        )\n\n    update : Msg -> Model -> ( Model, Cmd Msg )\n    update msg model =\n        case msg of\n            ConnectionMsg connectionMsg ->\n                let\n                    ( connection, action, incoming ) =\n                        Connection.update connectionMsg model.connection\n\n                    updated =\n                        { model | connection = connection }\n\n                    ( next, command ) =\n                        case incoming of\n                            Just event ->\n                                handleEvent event updated\n\n                            Nothing ->\n                                ( updated, Cmd.none )\n                in\n                ( next\n                , Cmd.batch [ Connection.perform Ports.wsCmd ConnectionMsg action, command ]\n                )\n\n            OtherMessage ->\n                ( model, Cmd.none )\n\n    handleEvent : Connection.Event -> Model -> ( Model, Cmd Msg )\n    handleEvent event model =\n        case event of\n            Connection.Text body ->\n                let\n                    reversed =\n                        String.reverse body\n\n                    next =\n                        if body == reversed then\n                            { model | palindromes = model.palindromes + 1 }\n\n                        else\n                            model\n                in\n                ( next\n                , Connection.send Ports.wsCmd reversed model.connection\n                )\n\n            _ ->\n                ( model, Cmd.none )\n\n    subscriptions : Model -> Sub Msg\n    subscriptions _ =\n        Connection.subscribe Ports.wsMsg |> Sub.map ConnectionMsg\n\nReceiving `\"ABC\"` sends back `\"CBA\"`. Receiving `\"ABA\"` sends back `\"ABA\"` and\nincrements `palindromes`.\n\n\n# Delayed replies\n\nBy default, the manager generates a fresh handle for each connection attempt. A\nreply command created while handling a received message in `update` stays bound to\nthat connection: reconnecting cannot redirect it to a replacement socket. This is\nnot a delivery guarantee; the socket may close before the command executes.\n\nIf work continues asynchronously after `update` returns, and its reply must not\ncross connections, use one of these approaches:\n\n  - Capture the handle from `get` when starting the work and compare it with `get`\n    when the result arrives. Discard the result if the handles no longer match.\n  - Handle `Established` by resetting connection-specific protocol state and\n    invalidating queued work or outstanding request IDs from the previous connection.\n\nThese approaches are useful when your protocol has connection-specific state, such\nas an initial snapshot followed by updates. The manager does not reset application\nstate itself; your application decides what to retain across reconnects.\n\nIf replies need not stay on their original connection, simply send using the current\nmodel. `withHandleReuse True` additionally lets already-created commands address a\nreplacement socket by reusing the same handle across attempts. This only works if\nthe replacement is open when the command executes. Handle comparisons can no longer\ndistinguish attempts, though `Established` is still emitted for each successful\nconnection. Calls to `send` and `sendBinary` while disconnected are still discarded;\nthere is no buffering or replay.\n\n\n# Caller-initiated dis- and reconnects\n\nCall `fail` when your application determines that the current connection is unusable:\n`Connection.fail \"Update sequence gap\" model.connection`. This records an\n`ApplicationError`, closes the socket, and follows the configured retry schedule\nand attempt limit. It only affects an established connection; calls while connecting,\nretrying, waiting, or exhausted do nothing. Transport failures during connection\nattempts still trigger the normal retry behavior.\n\nUse `reconnect` for a \"Reconnect now\" button. It replaces an active connection or\nskips a pending backoff, starting a fresh attempt immediately. It also works after\nexhaustion, resetting the retry count and backoff while retaining your configuration.\nOld retry callbacks cannot restart the connection again. Like automatic retries,\nit honors `withHandleReuse` and leaves application protocol state to you.\n\nBoth functions return a model and an action to pass to `perform`:\n\n    reconnectNow : Model -> ( Model, Cmd Msg )\n    reconnectNow model =\n        let\n            ( connection, action ) =\n                Connection.reconnect model.connection\n        in\n        ( { model | connection = connection }\n        , Connection.perform Ports.wsCmd ConnectionMsg action\n        )\n\n\n# Connection liveness\n\nA server can check **client liveness** by sending WebSocket protocol pings and\nwaiting for pongs. Browsers reply automatically. JavaScript cannot send or observe\nthese control frames, so they do not count as activity for client-side checks.\n\nA client can check **server liveness** by timing out a silent server. The server\nsends unsolicited heartbeat data frames, either periodically or only when otherwise\nidle. An empty binary frame works well: the application can discard `Binary` events\nwhose payload has `Bytes.width` zero. The JSON adapter passes binary frames through\ntoo, so these heartbeats need no JSON representation.\n\nEnable the client-side timeout with `Connection.withServerTimeout 45000`. It starts\nwhen the connection opens; every incoming text or binary frame counts as activity.\nIf the server stays silent for the configured milliseconds, the manager records\n`ServerTimeout`, closes the socket, and follows its retry policy. Checks are disabled\nby default and do not time out connection attempts. Choose a timeout longer than\nthe heartbeat interval, with room for network and scheduling delays.\n\n\n# Configuration\n\n@docs Config, config, withSchedule, withLimit, withHandle, withHandleReuse, withProtocols, withServerTimeout\n\n\n# State and transitions\n\n@docs Model, Msg, Event, Action, Failure\n@docs init, update, fail, reconnect, state, get\n\n\n# Integration\n\n@docs receive, subscribe, perform, send, sendBinary\n\n","unions":[{"name":"Action","comment":" One connection transition's effect, interpreted by `perform`. `Close` carries\nan optional retry delay in milliseconds and the message to deliver afterwards.\n`Replace` swaps the old handle's socket for a new connection without a retry delay.\n`ReadTime` timestamps activity; `CheckAt` waits until a deadline and supplies the\nactual wakeup time. Their callbacks return messages for `update`.\n","args":[],"cases":[["None",[]],["Open",["WebsocketSimple.Handle","String.String","List.List String.String"]],["Close",["WebsocketSimple.Handle","Maybe.Maybe ( Basics.Float, WebsocketSimple.Connection.Msg )"]],["Replace",["WebsocketSimple.Handle","WebsocketSimple.Handle","String.String","List.List String.String"]],["ReadTime",["Time.Posix -> WebsocketSimple.Connection.Msg"]],["CheckAt",["Time.Posix","Time.Posix -> WebsocketSimple.Connection.Msg"]]]},{"name":"Config","comment":" Connection settings, applied before the first attempt.\n","args":[],"cases":[]},{"name":"Event","comment":" Application events from the managed connection. `Established` includes the\nnegotiated subprotocol and lets your application initialize each new connection.\n`Error` reports errors that do not trigger reconnection; connection loss and\nretry failures are available through `state` instead.\n","args":[],"cases":[["Established",["Maybe.Maybe String.String"]],["Text",["String.String"]],["Binary",["Bytes.Bytes"]],["Error",["WebsocketSimple.TransportErrorDetails"]]]},{"name":"Failure","comment":" The reason a connection was lost or an attempt failed.\n","args":[],"cases":[["Closed",["WebsocketSimple.CloseDetails"]],["TransportError",["WebsocketSimple.TransportErrorDetails"]],["ApplicationError",["String.String"]],["ServerTimeout",[]]]},{"name":"Model","comment":" A retrying connection whose successful value is its connected socket handle.\n","args":[],"cases":[]},{"name":"Msg","comment":" Socket input, clock readings, or a scheduled retry. Route these messages back to `update`.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"config","comment":" Configure an indefinitely maintained connection with capped exponential backoff.\n","type":"String.String -> WebsocketSimple.Connection.Config"},{"name":"fail","comment":" Fail an established connection, recording an `ApplicationError` and closing\nthe socket. Retries follow the configured schedule and attempt limit. Calls in\nany other state do nothing; use `reconnect` to replace a pending attempt.\n","type":"String.String -> WebsocketSimple.Connection.Model -> ( WebsocketSimple.Connection.Model, WebsocketSimple.Connection.Action )"},{"name":"get","comment":" Get the connected socket handle, or `Nothing` while disconnected.\n","type":"WebsocketSimple.Connection.Model -> Maybe.Maybe WebsocketSimple.Handle"},{"name":"init","comment":" Begin the first connection attempt.\n","type":"WebsocketSimple.Connection.Config -> ( WebsocketSimple.Connection.Model, WebsocketSimple.Connection.Action )"},{"name":"perform","comment":" Execute one connection action through your application. A reused handle is\nreplaced with a single open command, which closes the old socket in the runtime.\n","type":"WebsocketSimple.CommandPort msg -> (WebsocketSimple.Connection.Msg -> msg) -> WebsocketSimple.Connection.Action -> Platform.Cmd.Cmd msg"},{"name":"receive","comment":" Forward an event from an existing handled WebSocket subscription.\n","type":"( WebsocketSimple.Handle, WebsocketSimple.RawMsg ) -> WebsocketSimple.Connection.Msg"},{"name":"reconnect","comment":" Start a fresh attempt immediately, replacing any active connection or skipping\nits backoff. Resets the retry count, even after exhaustion, and invalidates pending\nretry callbacks. Configuration, including handle reuse, is preserved.\n","type":"WebsocketSimple.Connection.Model -> ( WebsocketSimple.Connection.Model, WebsocketSimple.Connection.Action )"},{"name":"send","comment":" Send text through the connected socket. Disconnected sends are discarded,\nnot buffered or replayed. Delivery is best-effort.\n","type":"WebsocketSimple.CommandPort msg -> String.String -> WebsocketSimple.Connection.Model -> Platform.Cmd.Cmd msg"},{"name":"sendBinary","comment":" Send binary data with the same best-effort behavior as `send`.\n","type":"WebsocketSimple.CommandPort msg -> Bytes.Bytes -> WebsocketSimple.Connection.Model -> Platform.Cmd.Cmd msg"},{"name":"state","comment":" Inspect connection progress and the latest failure through `Again.Remote`.\n","type":"WebsocketSimple.Connection.Model -> Again.Remote.State WebsocketSimple.Connection.Failure WebsocketSimple.Handle"},{"name":"subscribe","comment":" Subscribe to socket events through an application-owned event port.\n","type":"WebsocketSimple.EventPort ( WebsocketSimple.Handle, WebsocketSimple.RawMsg ) -> Platform.Sub.Sub WebsocketSimple.Connection.Msg"},{"name":"update","comment":" Process a socket event or retry, returning an application event when appropriate.\nEvents with unrelated handles and obsolete retry messages are ignored.\n\nSocket closure, construction failure, and browser transport failure schedule\nreconnection without emitting an application event. Other errors are reported as\n`Error` without reconnecting.\n\n","type":"WebsocketSimple.Connection.Msg -> WebsocketSimple.Connection.Model -> ( WebsocketSimple.Connection.Model, WebsocketSimple.Connection.Action, Maybe.Maybe WebsocketSimple.Connection.Event )"},{"name":"withHandle","comment":" Give the manager its own handle namespace. Use distinct namespaces when\nmaintaining multiple connections; socket handles are generated within it.\n","type":"WebsocketSimple.Handle -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"},{"name":"withHandleReuse","comment":" Reuse one handle across attempts when enabled. The default is `False`.\nDelayed sends can then address a replacement socket, and handles no longer\nidentify individual attempts. Retry messages still belong to distinct attempts.\n","type":"Basics.Bool -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"},{"name":"withLimit","comment":" Limit attempts in a retry sequence, including its initial attempt.\n","type":"Again.Policy.AttemptLimit -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"},{"name":"withProtocols","comment":" Request an ordered list of WebSocket subprotocols.\n","type":"List.List String.String -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"},{"name":"withSchedule","comment":" Choose the delay between retries.\n","type":"Again.Schedule.Schedule -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"},{"name":"withServerTimeout","comment":" Reconnect after this many milliseconds without incoming data on an established\nconnection. Disabled by default. Nonpositive or non-finite values disable checks.\n","type":"Basics.Float -> WebsocketSimple.Connection.Config -> WebsocketSimple.Connection.Config"}],"binops":[]},{"name":"WebsocketSimple.Connection.Json","comment":" JSON messages over a managed connection. Keep using `Connection.Model`,\n`Connection.subscribe`, and `Connection.perform`; replace `Connection.update`\nwith `update`, supplying your message decoder.\n\n    import Json.Decode as Decode\n    import Json.Encode as Encode\n    import WebsocketSimple.Connection as Connection\n    import WebsocketSimple.Connection.Json as Json\n\n    type alias Message =\n        { text : String }\n\n    decoder : Decode.Decoder Message\n    decoder =\n        Decode.map Message (Decode.field \"text\" Decode.string)\n\n    encoder : Message -> Encode.Value\n    encoder message =\n        Encode.object [ ( \"text\", Encode.string message.text ) ]\n\n    receive : Connection.Msg -> Connection.Model -> ( Connection.Model, Connection.Action, Maybe (Json.Event Message) )\n    receive =\n        Json.update decoder\n\nTo reply, use `Json.send Ports.wsCmd encoder message connection`.\n\nA `PayloadDecodeFailure` retains the original text and decoding error without\nchanging the connection. Your application can report it, ignore it, or call\n`Connection.fail` to reconnect according to its retry policy. Binary frames pass\nthrough unchanged, unlike the JSON adapter in `WebsocketSimple`.\n\n@docs Event, update, parseIncoming, send\n\n","unions":[{"name":"Event","comment":" Typed application events. `PayloadDecodeFailure` is separate from transport\nerrors; neither event automatically triggers reconnection.\n","args":["value"],"cases":[["Established",["Maybe.Maybe String.String"]],["Received",["value"]],["PayloadDecodeFailure",["String.String","Json.Decode.Error"]],["Binary",["Bytes.Bytes"]],["Error",["WebsocketSimple.TransportErrorDetails"]]]}],"aliases":[],"values":[{"name":"parseIncoming","comment":" Decode a text event while preserving establishment, binary data, and transport\nerrors. Use this to adapt individual events after calling `Connection.update`.\n","type":"Json.Decode.Decoder value -> WebsocketSimple.Connection.Event -> WebsocketSimple.Connection.Json.Event value"},{"name":"send","comment":" Encode a value and send it as a text frame. Uses the same best-effort behavior\nas `Connection.send`: disconnected sends are discarded without buffering or replay.\n","type":"WebsocketSimple.CommandPort msg -> (value -> Json.Encode.Value) -> value -> WebsocketSimple.Connection.Model -> Platform.Cmd.Cmd msg"},{"name":"update","comment":" Apply the connection transition, then decode any accepted text event. Socket\nfiltering, retry actions, and connection state follow `Connection.update`.\n","type":"Json.Decode.Decoder value -> WebsocketSimple.Connection.Msg -> WebsocketSimple.Connection.Model -> ( WebsocketSimple.Connection.Model, WebsocketSimple.Connection.Action, Maybe.Maybe (WebsocketSimple.Connection.Json.Event value) )"}],"binops":[]}]