Skip to main content

lib/rpc_elixir/context.ex

defmodule RpcElixir.Context do
  @moduledoc """
  Request-scoped context threaded through middleware and into handlers.

  The transport layer (Plug, Channels) builds a `%Context{}` from the
  authentication mechanism it uses and hands it to the dispatcher.
  Middleware may read or augment the context via the surrounding
  `%RpcElixir.Resolution{}`; handlers receive the final context as their
  second argument (after the input).

  ## The `:req` field

  When a request arrives via the HTTP Plug transport, `:req` is populated with
  a plain map carrying transport-level request metadata:

      %{
        cookies: %{String.t() => String.t()},   # parsed request cookies
        headers: [{String.t(), String.t()}],     # raw header list from the conn
        remote_ip: :inet.ip_address() | nil,     # client IP
        method: String.t(),                      # always "POST" for v1
        path: String.t(),                        # request path used for dispatch
        session: map()                          # session data, empty map if Plug.Session not configured
      }

  When called in-process via `RpcElixir.call/4`, `:req` is `nil`.
  """

  @typedoc "Transport-level request metadata, populated by the Plug adapter."
  @type req :: %{
          cookies: %{optional(String.t()) => String.t()},
          headers: [{String.t(), String.t()}],
          remote_ip: :inet.ip_address() | nil,
          method: String.t(),
          path: String.t(),
          session: map()
        }

  @typedoc "Request-scoped context struct."
  @type t :: %__MODULE__{
          conn: Plug.Conn.t() | nil,
          socket: struct() | nil,
          assigns: map(),
          private: map(),
          req: req() | nil
        }

  defstruct conn: nil, socket: nil, assigns: %{}, private: %{}, req: nil
end