# Class BSV::Network::Protocol <a id="class-BSV-Network-Protocol"></a>

**Inherits:** `Object`

Protocol is the base class for all BSV network protocol definitions.

Subclasses declare their commands via the `endpoint` DSL macro. Each endpoint
maps a command name (Symbol) to an HTTP method, a path template, and a
response handler. The `subscription` macro is a placeholder for future
WebSocket support.

Subclass isolation is enforced via an `inherited` hook — each subclass
receives its own empty +@endpoints+ and +@subscriptions+ hashes. Adding
endpoints to a subclass never affects the parent.

HTTP dispatch routes through `call`: if a +call_<name>+ escape hatch method
exists on the instance, it is called; otherwise `default_call` interpolates
the URL template, makes the HTTP request, and wraps the response in a
`ProtocolResponse`.

## Example

    class MyProtocol < BSV::Network::Protocol
      endpoint :get_tx, :get, '/v1/tx/{txid}'
      endpoint :broadcast, :post, '/v1/tx', response: :json
    end

    p = MyProtocol.new(base_url: 'https://api.example.com', network: 'main')
    MyProtocol.commands #=> #<Set: {:get_tx, :broadcast}>

## Attributes
### `api_key` [R] <a id="attribute-i-api_key"></a> <a id="api_key-instance_method"></a>
Returns the value of attribute api_key.

### `auth` [R] <a id="attribute-i-auth"></a> <a id="auth-instance_method"></a>
Returns the value of attribute auth.

### `base_url` [R] <a id="attribute-i-base_url"></a> <a id="base_url-instance_method"></a>
Returns the value of attribute base_url.

### `http_client` [R] <a id="attribute-i-http_client"></a> <a id="http_client-instance_method"></a>
Returns the value of attribute http_client.

### `network` [R] <a id="attribute-i-network"></a> <a id="network-instance_method"></a>
Returns the value of attribute network.

## Public Class Methods
### `commands()` <a id="method-c-commands"></a> <a id="commands-class_method"></a>
Returns a `Set` of command names declared on this protocol class.
- **@return** [Set<Symbol>]

### `endpoint(command_name, http_method, path_template, response: = :raw)` <a id="method-c-endpoint"></a> <a id="endpoint-class_method"></a>
Registers an endpoint definition for this protocol class.
- **@param** `command_name` [Symbol] the command name (e.g. +:broadcast+)
- **@param** `http_method` [Symbol] +:get+ or +:post+
- **@param** `path_template` [String] path with +{param}+ placeholders
- **@param** `response` [Symbol, #call] response handler — +:raw+, +:json+,
+:json_array+, or a callable (lambda/proc)

### `endpoints()` <a id="method-c-endpoints"></a> <a id="endpoints-class_method"></a>
Returns a frozen copy of the endpoints hash for introspection.
- **@return** [Hash]

### `inherited(subclass)` <a id="method-c-inherited"></a> <a id="inherited-class_method"></a>
Give each subclass its own isolated +@endpoints+ and +@subscriptions+ hashes.
Deep-copies the parent's endpoints so that existing declarations are inherited
but mutations on the subclass do not affect the parent.

### `subscription(event_name, path, **opts)` <a id="method-c-subscription"></a> <a id="subscription-class_method"></a>
Registers a subscription definition. Placeholder for Phase C WebSocket
support. Stored but not callable at runtime.
- **@param** `event_name` [Symbol] the event name
- **@param** `path` [String] WebSocket path
- **@param** `opts` [Hash] additional options (reserved)

### `subscriptions()` <a id="method-c-subscriptions"></a> <a id="subscriptions-class_method"></a>
Returns a frozen copy of the subscriptions hash for introspection.
- **@return** [Hash]

## Public Instance Methods
### `call(command_name, **kwargs)` <a id="method-i-call"></a> <a id="call-instance_method"></a>
Dispatches a command by name.

If a method named +call_<command_name>+ exists on the instance it is used as
an escape hatch — that method receives `args` and `kwargs` and MUST return a
`ProtocolResponse`. Otherwise `default_call` is invoked.

Subscriptions are not callable; calling one raises `NotImplementedError`.
- **@param** `command_name` [Symbol, String] command to invoke
- **@param** `*` [Array] positional arguments forwarded to path interpolation
- **@param** `kwargs` [Hash] keyword arguments forwarded to path interpolation
- **@raise** [ArgumentError] when command_name is not registered
- **@return** [ProtocolResponse]

### `default_call(command_name, *args, **kwargs)` <a id="method-i-default_call"></a> <a id="default_call-instance_method"></a>
Dispatches a command directly via HTTP, bypassing any escape hatch.

Path placeholders (+{param}+) are filled from `kwargs` first; any remaining
placeholders are filled positionally from `args`. Named kwargs take precedence
over positional args for the same placeholder.

POST body is taken from +kwargs.delete(:body)+ (removed before path
interpolation).
- **@param** `command_name` [Symbol] registered command name
- **@param** `args` [Array] positional path parameters
- **@param** `kwargs` [Hash] named path parameters (and optional +:body+)
- **@raise** [ArgumentError] when command_name is not registered or a
required path parameter is missing
- **@return** [ProtocolResponse]

### `initialize(base_url:, api_key: = nil, auth: = nil, network: = nil, http_client: = nil)` <a id="method-i-initialize"></a> <a id="initialize-instance_method"></a>
- **@param** `base_url` [String] base URL, may contain +{network}+ placeholder
- **@param** `api_key` [String, nil] legacy API key — sends +Authorization: Bearer <key>+
- **@param** `auth` [Hash, Symbol, nil] auth config hash; takes precedence over +api_key:+.
Supported forms:
- +{ bearer: 'token' }+ → +Authorization: Bearer token+
- +{ api_key: 'key' }+ → +Authorization: key+ (no Bearer prefix, WoC style)
- +{ api_key: 'key', header: 'X-Custom' }+ → +X-Custom: key+
- +:none+ or +nil+ → no auth header
- **@param** `network` [String, Symbol, nil] network name (e.g. 'main', 'test')
- **@param** `http_client` [Object, nil] injectable HTTP client (used in Task 3)
- **@return** [Protocol] a new instance of Protocol
