Bourse.WS.SubscribeAck (bourse v0.7.0)

Copy Markdown View Source

Classifies WebSocket subscribe acknowledgements and rejections.

Venues deliver subscribe outcomes in two ways:

  1. Correlated (deribit JSON-RPC) — ZenWebsocket.Client.send_message/2 returns {:ok, envelope} because the outbound frame carries an id.
  2. Asynchronous (alpaca, bybit, okx, hyperliquid, derive, binance, lighter) — send returns :ok and the venue reply arrives as {:websocket_message, frame} or {:websocket_unmatched_response, frame} (derive replies with a JSON-RPC envelope even when the request had no id).

Bourse.WS.subscribe/3 uses this module so both paths resolve to the same caller contract: :ok on accept, {:error, {:subscription_rejected, frame}} on reject.

Summary

Functions

Classifies a subscribe outcome frame for exchange_id.

Turns a classification into the public subscribe/3 return value.

Types

classification()

@type classification() :: :success | {:success, :data} | :not_ack | {:rejected, map()}

Functions

classify(exchange_id, frames)

@spec classify(String.t(), map() | [map()]) :: classification()

Classifies a subscribe outcome frame for exchange_id.

Returns:

  • :success — venue accepted the subscription
  • {:success, :data} — venue accepted, and the frame is also the first snapshot (re-queue after treating it as the acknowledgement)
  • {:rejected, frame} — venue rejected it (frame is the raw envelope)
  • :not_ack — not a subscribe outcome (data/heartbeat/other); leave in mailbox

to_result(arg1)

@spec to_result(classification()) ::
  :ok
  | {:error,
     :unexpected_subscription_response | {:subscription_rejected, map()}}

Turns a classification into the public subscribe/3 return value.

A non-ack correlated reply is an unexpected protocol response, not evidence that the venue accepted the subscription.