# `Bourse.Emulation`
[🔗](https://github.com/ZenHive/bourse/blob/main/lib/bourse/emulation.ex#L1)

Runtime emulation dispatch for Bourse unified methods.

Uses extracted emulated method metadata to decide when a method should be
derived at runtime instead of issuing HTTP or WebSocket requests.

Emulated reads forward the incoming parameter map into the nested method.
Only selectors listed in `@consumed_delegated_params` are stripped first
(local picks such as a singular `symbol` rewritten as `symbols`, or an
`id` used to select one row). Everything else, including `until` and
venue-native options, reaches the delegated call.

The metadata index is cached in `:persistent_term` for the life of the VM.
In a long-running dev session, `recompile/0` reloads modules but does not
invalidate that cache — after editing a venue's `emulated_methods` slice,
call `Bourse.Emulation.reload!/0` or the stale index keeps answering.

# `dispatch_result`

```elixir
@type dispatch_result() :: :passthrough | {:ok, term()} | {:error, Bourse.Error.t()}
```

# `entry`

```elixir
@type entry() :: map()
```

# `scope`

```elixir
@type scope() :: :rest | :ws
```

# `dispatch`

```elixir
@spec dispatch(Bourse.Exchange.t(), atom(), scope(), map()) :: dispatch_result()
```

Dispatches emulated method calls.

Returns `:passthrough` when the method is not emulated for this exchange,
`{:ok, result}` when emulation succeeds, or `{:error, reason}` on failure.

# `emulated?`

```elixir
@spec emulated?(Bourse.Exchange.t(), atom(), scope()) :: boolean()
```

Returns true if a method is emulated for the exchange and scope.

# `entry`

```elixir
@spec entry(Bourse.Exchange.t(), atom(), scope()) :: entry() | nil
```

Returns emulated metadata for a method (or nil if not emulated).

# `handle_fetch_currencies`

```elixir
@spec handle_fetch_currencies(Bourse.Exchange.t(), module(), map(), keyword()) ::
  dispatch_result()
```

Derives unified currencies from fetchMarkets output (emulation strategy).

# `implemented_methods`

```elixir
@spec implemented_methods() :: MapSet.t(atom())
```

Returns the set of emulated methods with runtime handlers implemented.

# `method_atom`

```elixir
@spec method_atom(String.t() | nil) :: atom() | nil
```

Maps an extractor JS method name to its snake_case atom.

Resolves via `Unified.method_atom_for_js_name/1` (method_defs) plus a small
explicit map for WS names not yet in method_defs. Unknown names return `nil`
rather than minting atoms.

# `reload!`

```elixir
@spec reload!() :: map()
```

Reloads emulation index (bypasses cache).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
