Supervised WebSocket client for T3's Effect RPC protocol (/ws).

This is a separate authentication audience from MCP. Supply an environment access token (:token) or an RPC WebSocket ticket (:ticket), not an MCP OAuth token. T3 rejects MCP client credentials on this surface. :dpop accepts a caller-created proof for a proof-bound credential (token headers then use the DPoP authorization scheme; :auth_scheme can explicitly select it). Credentials never persist. :max_pending defaults to 128 and :max_message_bytes to 16 MiB.

Obtain a route-bound ticket with an environment HTTP credential:

http = T3.HTTP.new(base_url: "http://127.0.0.1:3773", token: environment_token)
{:ok, response} = T3.HTTP.Auth.web_socket_ticket_for(http, "rpc")
{:ok, rpc} = T3.RPC.start_link(
  url: "ws://127.0.0.1:3773/ws", ticket: response.body["ticket"]
)

For proof-bound tickets supply a new DPoP proof that hashes that ticket. The SDK transports caller-created proofs; it does not generate or manage signing keys.

{:ok, rpc} = T3.RPC.start_link(url: "ws://127.0.0.1:3773/ws", token: token)
{:ok, config} = T3.RPC.call(rpc, "server.getConfig", %{})
{:ok, subscription} = T3.RPC.subscribe(rpc, "orchestration.subscribeShell", %{})
receive do
  {:t3_rpc, ^subscription, {:chunk, values}} ->
    IO.inspect(values)
    :ok = T3.RPC.ack(rpc, subscription)
  {:t3_rpc, ^subscription, {:done, _}} -> :ok
  {:t3_rpc, ^subscription, {:error, error}} -> IO.puts(Exception.message(error))
after
  5_000 -> :ok
end
:ok = T3.RPC.unsubscribe(rpc, subscription)
:ok = T3.RPC.close(rpc)

Subscriptions use explicit acknowledgements: acknowledge each chunk after consuming it. This retains the server's back-pressure instead of buffering an unbounded event queue. Terminal messages are {:t3_rpc, id, {:done, value}} or {:t3_rpc, id, {:error, error}}. Subscriber death cancels its request.

call/4 defaults to a 30-second deadline. Subscription :timeout defaults to :infinity; pass milliseconds for a total deadline. No operation is replayed or retried after disconnect. Use T3.RPC.Reader for opt-in supervised read subscription recovery and T3.LocalAuth for local service credentials. Payloads and results retain the upstream string keys; T3.RPC.Catalog lists the pinned upstream methods and streaming flags.

Summary

Functions

Acknowledge the outstanding chunk of a subscription.

Returns a specification to start this module under a supervisor.

Reply to a server-originated request delivered to the configured :owner.

Interrupt a subscription and release its local state. Idempotent.

Types

result()

@type result() :: {:ok, term()} | {:error, T3.Error.t()}

subscription()

@type subscription() :: String.t()

Functions

ack(rpc, id)

Acknowledge the outstanding chunk of a subscription.

call(rpc, method, payload \\ %{}, opts \\ [])

@spec call(GenServer.server(), String.t(), term(), keyword()) :: result()

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

close(rpc)

ping(rpc)

respond(rpc, id, arg)

Reply to a server-originated request delivered to the configured :owner.

start_link(opts)

subscribe(rpc, method, payload \\ %{}, opts \\ [])

@spec subscribe(GenServer.server(), String.t(), term(), keyword()) ::
  {:ok, subscription()} | {:error, T3.Error.t()}

unsubscribe(rpc, id)

Interrupt a subscription and release its local state. Idempotent.