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.
const {api, api_result} = create_frontend_rpc_client<MyActionsApi>({
specs: all_specs,
});
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.