actions/action_bridge.ts view source
ActionEventOptions import type {ActionEventOptions} from '@fuzdev/fuz_app/actions/action_bridge.js'; Options for deriving an EventSpec from an ActionSpec.
channel?
type string
Bridge functions to derive RouteSpec and EventSpec from ActionSpec.
Action specs define the contract (method, input/output, auth, side effects). Bridge functions produce transport-specific specs from them. HTTP-specific concerns (path, handler) come from options.
5 declarations
actions/action_bridge.ts view source
ActionEventOptions import type {ActionEventOptions} from '@fuzdev/fuz_app/actions/action_bridge.js'; Options for deriving an EventSpec from an ActionSpec.
channel?type string
actions/action_bridge.ts view source
ActionRouteOptions import type {ActionRouteOptions} from '@fuzdev/fuz_app/actions/action_bridge.js'; Options for deriving a RouteSpec from an ActionSpec.
pathtype string
handlertype (c: Context<any, any, {}>, route: RouteContext): Response | Promise<Response>
cContext<any, any, {}>routeResponse | Promise<Response>params?URL path parameter schema. Use z.strictObject() with string fields matching :param segments.
type ZodObject<$ZodLooseShape, $strip>
query?URL query parameter schema. Use z.strictObject() with string fields.
type ZodObject<$ZodLooseShape, $strip>
http_method?Override the default HTTP method (default: side_effects → POST, else GET).
type RouteMethod
auth?Override the route's auth shape — defaults to the action spec's auth
(the canonical shape from http/auth_shape.ts is shared verbatim between
action specs and route specs, so no mapping is needed).
The bridge fills in required_scope on whichever shape it ends up with,
so an override still gets the token-scope gate; declare required_scope
here to name a different capability (e.g. surface:<name> when the
bridged route is a stream rather than a request/response call — see the
token-scope note on create_action_route_spec).
Overriding to *widen* (admitting a credential the action's own gate refused) makes this route the consumer's to audit, not the spine's.
type RouteAuth
errors?Handler-specific error schemas (HTTP status code → Zod schema). Transport-specific — not on ActionSpec.
type Partial<Record<number, ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>>>>
actions/action_bridge.ts view source
(spec: { method: string; kind: "request_response" | "remote_notification" | "local_call"; initiator: "frontend" | "backend" | "both"; auth: { account: "optional" | "none" | "required"; actor: "optional" | ... 1 more ... | "required"; roles?: readonly string[] | undefined; credential_types?: readonly string[] | undefined; required_scope?: string | undefined; } | null; ... 7 more ...; rate_limit?: "both" | ... 2 more ... | undefined; }, options?: ActionEventOptions | undefined): EventSpec import {create_action_event_spec} from '@fuzdev/fuz_app/actions/action_bridge.js'; Derive an EventSpec from an ActionSpec.
Only remote_notification actions can become push events.
specthe action spec (must have kind: 'remote_notification')
options?optional event-specific options (channel)
EventSpec an EventSpec ready for create_validated_broadcaster
Error - if `spec.kind` is not `'remote_notification'`actions/action_bridge.ts view source
(spec: { method: string; kind: "request_response" | "remote_notification" | "local_call"; initiator: "frontend" | "backend" | "both"; auth: { account: "optional" | "none" | "required"; actor: "optional" | ... 1 more ... | "required"; roles?: readonly string[] | undefined; credential_types?: readonly string[] | undefined; required_scope?: string | undefined; } | null; ... 7 more ...; rate_limit?: "both" | ... 2 more ... | undefined; }, options: ActionRouteOptions): RouteSpec import {create_action_route_spec} from '@fuzdev/fuz_app/actions/action_bridge.js'; Derive a RouteSpec from an ActionSpec and options.
Only request_response actions (which require non-null auth) can become routes.
remote_notification actions (auth null) should use create_action_event_spec.
local_call actions are not for HTTP transport.
Error schemas are transport-specific (keyed by HTTP status codes) and belong on the options, not the action spec. Action specs define the contract; transport concerns like HTTP error codes are added at the bridge layer.
The bridge carries the token-scope gate across for you. A bridged route
runs options.handler through the REST pipeline and never reaches
perform_action, so the dispatcher's per-method scope check cannot fire on
it — which would leave a bearer-reachable route that a narrowed api token
walks straight through. So the derived spec declares
auth.required_scope: 'rpc:<method>', and fuz_auth_guard_resolver mounts
the same refusal ahead of the role gate. A token that lists the method
reaches the bridged route; one that doesn't gets the 403 it would have gotten
over RPC.
Per-method rather than rule 3's blanket refusal because a bridged route
*has* a method identity — which is exactly what the non-RPC surfaces rule 3
covers (the db browser, a bare-hash read, a stream) do not, and why that rule
is all-or-nothing there. Bridge something with no request/response shape —
an SSE stream, a file download — and rule 3's reasoning applies instead:
pass options.auth with required_scope: 'surface:<name>', naming your own
surface. See docs/security.md §Token scoping.
Skipped for a public action (account: 'none', actor: 'none'), where the
same holder reaches the route by dropping the credential, so the guard would
enforce nothing — the shape fuz_auth_guard_resolver refuses outright.
specthe action spec (must have non-null auth)
optionsHTTP-specific options (path, handler, optional overrides)
RouteSpec a RouteSpec ready for apply_route_specs
Error - if `spec.auth` is null (only `request_response` actions can
become routes; notifications and local calls cannot)actions/action_bridge.ts view source
(side_effects: boolean): RouteMethod import {derive_http_method} from '@fuzdev/fuz_app/actions/action_bridge.js'; Derive the default HTTP method from side effects.
side_effectsboolean