actions/frontend_rpc_client.ts

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, }); // 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.

Declarations
#

3 declarations

view source

create_frontend_rpc_client
#

actions/frontend_rpc_client.ts view source

<TApi extends object>(options: CreateFrontendRpcClientOptions<TApi>): FrontendRpcClient<TApi>

Build a frontend-only typed RPC client. See module doc for the bundle's design.

options

type CreateFrontendRpcClientOptions<TApi>

returns

FrontendRpcClient<TApi>

CreateFrontendRpcClientOptions
#

actions/frontend_rpc_client.ts view source

CreateFrontendRpcClientOptions<TApi>

generics

TApi

constraint object
default object

specs

Action specs the typed Proxy can dispatch. Methods absent from this list silently return undefined from the Proxy — the generic TApi cannot constrain runtime membership, so consumers must keep this list in sync with the typed surface (codegen recommended).

Protocol actions (heartbeat, cancel) are not auto-spread — they're filtered out of generated action_specs by codegen's include_protocol_actions: false default and consumers spread them in explicitly so the contract stays visible at every registration site. For WS-using consumers, spread protocol_action_specs from actions/protocol.ts here: specs: [...protocol_action_specs, ...action_specs]. HTTP-only consumers can omit them.

type ReadonlyArray<ActionSpecUnion>

path

HTTP RPC endpoint path for the default FrontendHttpTransport. Defaults to /api/rpc. Ignored when transports is provided.

type string

transports

Optional explicit transport list. When provided, the default FrontendHttpTransport(path) is not registered — the caller is responsible for at least one ready transport. Use for WS-first or WS+HTTP mixed setups.

type ReadonlyArray<Transport>

transport_for_method

Optional per-method transport selector — pure pass-through to create_rpc_client. Return the transport name to use for a given method, or undefined to fall back to the peer's default selection.

Useful when methods are registered on different backend dispatchers (e.g. streaming actions on WS, REST RPC on HTTP) — a tx-style mixed setup. Per-call RpcClientCallOptions.transport_name overrides this for individual dispatches.

on_action_event

Optional callback fired once per dispatched action — pure pass-through to create_rpc_client. Used by zzz-style consumers that thread the ActionEvent into a reactive cell (add_from_json + listen_to_action_event) for pending / failed / value derivations.

event.spec.method and event.data.method narrow to keyof TApi & string — drop the as ActionMethod cast at the call site when TApi is a generated ActionsApi interface.

type (event: ActionEvent<keyof TApi & string>) => void

lookup_action_handler

Optional handler resolver. Wired onto environment.lookup_action_handler — the registry the dispatcher uses to find handlers for inbound messages and lifecycle phases. Defaults to () => undefined, which is fine for HTTP-only frontends that never receive a server-pushed notification or register a receive_error recovery hook.

Common reasons to provide this: - Server-pushed notifications over WS — return a handler for (method, 'receive') so a remote_notification arriving on the socket dispatches to your subscriber bus (tx-style). - Per-method retry / telemetry on errors — return a handler for (method, 'receive_error'). Note that as of the extract_action_result fix, a missing handler already produces {ok: false, error} — the stub is no longer required just to surface server errors.

type ActionEventEnvironment['lookup_action_handler']

FrontendRpcClient
#

actions/frontend_rpc_client.ts view source

FrontendRpcClient<TApi>

Bundle returned by create_frontend_rpc_client.

generics

TApi

api

Typed throwing Proxy. await api.method(input) returns the unwrapped value or throws an Error with {code, data} from the JSON-RPC error. Default for call sites that don't inspect errors.

type ThrowingApi<TApi>

api_result

Typed Result-shaped Proxy. await api_result.method(input) returns Result<{value}, {error: JsonrpcErrorObject}>. Use when call sites inspect error.data.reason without try/catch, or when Error allocation per {ok: false} would be wasteful.

type TApi

peer

Underlying peer — exposed for consumers that need to register more transports or send raw messages.

environment

Action environment — exposed for consumers that need to share it (e.g. attach a notification handler registry).

Depends on
#