Gate/Bitfinex/Bitget-style subscribe frame keyed on an "event" field.
Accepts two caller conventions per channel list:
Plain strings — the pattern owns envelope construction.
# Gate-style (list payload) EventSubscribe.subscribe(["BTC_USDT"], %{channel_field: "channel", channel_value: "spot.tickers"}) # => %{"event" => "subscribe", "channel" => "spot.tickers", "payload" => ["BTC_USDT"]} # Bitfinex-style (single string under args_field) EventSubscribe.subscribe(["tBTCUSD"], %{args_field: "symbol", args_format: :string, channel_field: "channel", channel_value: "ticker"}) # => %{"event" => "subscribe", "channel" => "ticker", "symbol" => "tBTCUSD"}Single pre-shaped map — the caller supplies the per-subscribe fields directly; they are spread alongside
"event" => "subscribe". Used by callers that already know the exchange-native shape (bitfinex with%{"channel" => "ticker", "symbol" => "tBTCUSD"}, gate with%{"channel" => "spot.tickers", "payload" => ["BTC_USDT"]}).EventSubscribe.subscribe([%{"channel" => "ticker", "symbol" => "tBTCUSD"}], %{}) # => %{"event" => "subscribe", "channel" => "ticker", "symbol" => "tBTCUSD"}
Multiple maps per call are not supported for this single-envelope pattern —
subscribe/2 returns {:error, :multiple_maps_not_supported} in that case.
Lists that mix maps and strings return {:error, :mixed_channel_types}
(also rejected, since silently shipping a heterogeneous payload was the
exact failure mode T98/T99 set out to fix).
Config keys (string-channel branch only):
:op_field— default"event":args_field— default"payload"; set to"symbol"for Bitfinex-style:args_format—:stringfor single-channel,:object_listfor object payloads, otherwise (default) an array of strings:channel_field— extra field carrying the channel name; its value comes fromconfig[:channel_value].