/**
 * Frontend-only typed RPC client factory.
 *
 * Bundles the `ActionRegistry + ActionEventEnvironment + Transports +
 * ActionPeer + create_rpc_client + create_throwing_api` boilerplate every
 * consumer repeats. `lookup_action_handler` defaults to `() => undefined`
 * (HTTP-only frontends rarely need handlers); pass `options.lookup_action_handler`
 * to wire WS-pushed `remote_notification` dispatch or a `receive_error` /
 * `local_call` hook.
 *
 * Returns both Proxy shapes from one factory call:
 *
 * - `api` — typed throwing Proxy. `await api.foo(input)` returns the
 *   unwrapped value or throws an `Error` carrying `{code, data}` from the
 *   JSON-RPC error. Use at hot-path call sites.
 * - `api_result` — typed Result-shaped Proxy. `await api_result.foo(input)`
 *   returns `Result<{value}, {error: JsonrpcErrorObject}>`. Use when call
 *   sites want to inspect `error.data.reason` without try/catch — and
 *   anywhere allocating an `Error` per `{ok: false}` is wasteful (e.g.
 *   reconnect-storm `service_unavailable` paths). Result is the protocol
 *   primitive; the throwing form is a wrapper over it. Both share the
 *   same underlying transport — pick per call site, no construction cost.
 *
 * Generic `TApi` is the consumer's typed Proxy interface. The `as unknown
 * as TApi` double cast happens inside the helper so call sites get a
 * typed return value without the cast hostility. `api`'s type is
 * `ThrowingApi<TApi>` — the mapped type strips the Result wrapper.
 *
 * ```ts
 * const {api, api_result} = create_frontend_rpc_client<MyActionsApi>({
 *   specs: all_specs,
 * });
 * // hot path:    await api.account_verify()
 * // rare branch: const r = await api_result.account_verify(); if (!r.ok) { … }
 * ```
 *
 * Returns the underlying `peer` and `environment` alongside the two api
 * shapes so advanced consumers (zzz-style frontends needing extra
 * transports / WS notification handlers / action-history wiring) can
 * extend without recreating the bundle.
 *
 * `local_call` specs in `specs` no-op unless `lookup_action_handler`
 * resolves a handler for the `'execute'` phase. Frontend-side `local_call`
 * is uncommon; the factory targets wire-dispatched actions by default.
 *
 * @module
 */
import { ActionRegistry } from './action_registry.js';
import { ActionPeer } from './action_peer.js';
import { Transports } from './transports.js';
import { FrontendHttpTransport } from './transports_http.js';
import { create_rpc_client, create_throwing_api, } from './rpc_client.js';
/** Build a frontend-only typed RPC client. See module doc for the bundle's design. */
export const create_frontend_rpc_client = (options) => {
    const registry = new ActionRegistry([...options.specs]);
    const environment = {
        executor: 'frontend',
        lookup_action_spec: (method) => registry.spec_by_method.get(method),
        lookup_action_handler: options.lookup_action_handler ?? (() => undefined),
    };
    const transports = new Transports();
    if (options.transports) {
        for (const t of options.transports)
            transports.register_transport(t);
    }
    else {
        transports.register_transport(new FrontendHttpTransport(options.path ?? '/api/rpc'));
    }
    const peer = new ActionPeer({ environment, transports });
    const api_result = create_rpc_client({
        peer,
        environment,
        on_action_event: options.on_action_event,
        transport_for_method: options.transport_for_method,
    });
    const api = create_throwing_api(api_result);
    return { api, api_result, peer, environment };
};
