import 'reflect-metadata'; import type { HttpContext } from '@adonisjs/core/http'; import type { WireRequestPayload, WireResponse, AdowireConfig } from './types.js'; import { SnapshotManager } from './snapshot.js'; import type { ComponentRegistry } from './component_registry.js'; /** * Handles the `POST /adowire/message` endpoint. * * For each component in the batched request payload it runs the full lifecycle: * * 1. Verify HMAC checksum * 2. Hydrate component from snapshot * 3. boot() — every request * 4. hydrate() — subsequent requests only * 5. Apply property updates (with @Locked guard + updating/updated hooks) * 6. Call action methods (with IoC DI + @Renderless support) * 7. dehydrate() * 8. Render Edge template (unless skipRender is set) * 9. Dehydrate new snapshot * 10. Return JSON response with effects * * Errors are routed through the component's `exception()` hook first. * Validation errors from VineJS / `component.validate()` are caught and * converted to `$errors` on the component, then re-rendered normally. */ export declare class WireRequestHandler { private readonly registry; private readonly config; private readonly edge?; private snapshot; constructor(registry: ComponentRegistry, config: AdowireConfig, secretOrSnapshot: string | SnapshotManager, edge?: any | undefined); /** * Handle a parsed `POST /adowire/message` request. * * @param payload The parsed request body * @param ctx The AdonisJS HTTP context for this request */ handle(payload: WireRequestPayload, ctx: HttpContext): Promise; /** * Convenience method — parse the request body from `ctx`, run the handler, * and write the JSON response. * * When the client sends `Accept: text/event-stream` the handler switches * to **SSE streaming mode**: each `$stream()` call inside an action is * flushed to the browser immediately as an SSE `stream` event, giving the * user a real-time word-by-word experience (e.g. AI/LLM output). The * final component response (snapshot + effects + HTML) is sent as the * last `response` event before the connection is closed. * * Non-streaming requests (the default) still receive a plain JSON body. */ handleRequest(ctx: HttpContext): Promise; /** * Handle a request in SSE streaming mode. * * 1. Open the response as `text/event-stream`. * 2. Wire up each component's `$streamWriter` so that `$stream()` calls * flush an SSE `event: stream` immediately. * 3. After all actions complete, send the final component response as * `event: response` and close the connection. */ private handleStreamingRequest; /** * Run a single component's lifecycle with a real-time stream writer * attached so `$stream()` flushes immediately over SSE. */ private handleComponentStreaming; private handleComponent; private runLifecycle; /** * Apply all incoming property updates from the client. * * For each property: * 1. Guard against @Locked properties * 2. Call `updating(name, value)` and `updatingPropertyName(value)` * 3. Set the value * 4. Call `updated(name, value)` and `updatedPropertyName(value)` * (with key variant for array/object updates: `updatedPropertyName(value, key)`) */ private applyUpdates; /** * Call a single action method on the component. * * 1. Guard: `$isCallable()` must return true * 2. Resolve method parameters via AdonisJS IoC container * 3. Call the method * 4. If @Renderless, set skipRender * 5. Catch ValidationException → populate $errors, continue (no re-throw) */ private callAction; /** * Handle magic `$` actions sent from the client. * These mirror the `$set`, `$toggle`, `$refresh`, `$dispatch`, `$redirect` * methods on WireComponent but are invoked by name from the client. */ private callMagicAction; /** * Resolve method arguments by merging: * 1. Client-supplied `params` (positional, from the left) * 2. IoC container injections for remaining parameters (via type metadata) * * If `emitDecoratorMetadata` is enabled and the method has a `design:paramtypes` * metadata entry, we attempt to resolve remaining args from the IoC container. * Otherwise we fall back to client params only. */ private resolveMethodArgs; /** * If a property has `@Validate` with `onUpdate: true`, run validation * for that property immediately after the value is set. * * Validation errors are stored in `component.$errors` but do NOT throw — * we accumulate them and let the render pass display them. */ private maybeValidateOnUpdate; /** * Route an error through the component's `exception()` hook. * If `stopPropagation()` is called inside the hook, the error is swallowed. * Otherwise it is re-thrown. */ private handleComponentError; /** * Call a lifecycle hook method on the component, catching and re-wrapping * errors with phase information. */ private runHook; private getLockedProperties; }