LiveEndpoint
The HTTP live loop terminus: verifies a request, dispatches it to a mounted component's `handle()`, re-renders, and returns a response the client can apply. This is the controller the 2026-07-08 lab audit found missing — Sync/Transport/Security were all individually proven but never wired to a real entrypoint. Trust model: the client cannot hold the HMAC signing secret, so it never builds a signed envelope itself. Instead it echoes back — byte for byte — the last `<milpa-state>` envelope the server signed and handed it (first embedded in the SSR'd page, then refreshed on every response). Verifying that envelope (`StateTransferCodecInterface::decodeState()`) is what proves the state hasn't been tampered with since this server last saw it; `action`/`payload` are ordinary untrusted input, constrained instead by the CSRF guard and the contract-based action allowlist. One endpoint per page (greenhouse decisions/0211): `$components` may be a {@see \Milpa\Live\Runtime\CompositeComponentRegistry} over the host's and every plugin's components (only `has`/`get` are needed), and `$renderers` may be a {@see ComponentRendererRegistry} instead of a hand-wired name => renderer array — it answers per name (`registerFor()`), exactly what the array did — then one endpoint re-renders every plugin's components and a {@see RenderEffect} resolves across layers. The session id the CSRF token is checked against is {@see LiveHttpRequest::$sessionId}, and the contract is that the host's adapter fills it from the request body's `sessionId` — the runtime echoes the boot the host issued with {@see LiveBoot::issue()} — not from a cookie. This endpoint cannot see where the adapter took it from; keeping that contract is the adapter's job.
LiveEndpoint::__construct()
public function __construct(Milpa\Live\Contracts\Component\ComponentRegistryInterface $components, Milpa\Live\Contracts\Transport\StateTransferCodecInterface $codec, Milpa\Live\Contracts\Security\InteractionAuthorizerInterface $authorizer, Milpa\Live\Contracts\Security\CsrfGuardInterface $csrf, string $route, Milpa\Live\Rendering\ComponentRendererRegistry|array $renderers = [], array $renderProps = [], ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface $dispatcher = null, Milpa\Live\Assets\ComponentAssetOrchestrator $assetOrchestrator = new ComponentAssetOrchestrator(), string $locale = Milpa\Live\Assets\ComponentMessages::DEFAULT_LOCALE):Parameters
| Name | Type | Description |
|---|---|---|
| $components | Milpa\Live\Contracts\Component\ComponentRegistryInterface | |
| $codec | Milpa\Live\Contracts\Transport\StateTransferCodecInterface | |
| $authorizer | Milpa\Live\Contracts\Security\InteractionAuthorizerInterface | |
| $csrf | Milpa\Live\Contracts\Security\CsrfGuardInterface | |
| $route | string | |
| $renderers | (array<string, ComponentRendererInterface> | ComponentRendererRegistry) | component name => renderer used to re-render after handle(), or a registry answering {@see ComponentRendererRegistry::resolveFor()} per name (its `registerFor()`ed renderers only — like the array, no fallback) |
| $renderProps | array<string, array<string, mixed>> | component name => base render props needed to re-render faithfully (e.g. the live endpoint URL) |
| $dispatcher | ?Milpa\Interfaces\Event\MilpaEventDispatcherInterface | |
| $assetOrchestrator | Milpa\Live\Assets\ComponentAssetOrchestrator | |
| $locale | string |
LiveEndpoint::handle()
public function handle(Milpa\Live\Http\LiveHttpRequest $request, ?Milpa\Live\ValueObjects\SecurityPrincipal $principal = null): Milpa\Live\Http\LiveHttpResponseProcesses one interaction request end to end: method/CSRF/state- signature checks, authorization, dispatch to {@see \Milpa\Live\Contracts\Component\ComponentDefinitionInterface::handle()}, and (when a renderer is registered for the component) re-rendering to HTML. Every failure path returns an {@see LiveHttpResponse} error rather than throwing — this method MUST NOT throw for ordinary bad input (wrong method, missing fields, invalid/expired state signature, failed CSRF/authorization); it is the single point that turns those into the appropriate HTTP status code. `$principal` MUST already be resolved by the caller (e.g. via a {@see \Milpa\Live\Contracts\Security\TokenVerifierInterface}) — this method only consumes it for authorization, it does not perform authentication itself. When the guard implements {@see CsrfTokenLifetimeInterface} and the presented token has less than a tenth of its TTL left, the OK response carries a fresh `csrfToken` for the same session and route; the remote runtime stores it in the boot for the next action.
Parameters
| Name | Type | Description |
|---|---|---|
| $request | Milpa\Live\Http\LiveHttpRequest | |
| $principal | ?Milpa\Live\ValueObjects\SecurityPrincipal |