import type { UserContent } from "ai"; import type { CrossChannelReceiveFn } from "#channel/cross-channel-receive.js"; import type { SessionAuthContext, SessionCallback } from "#channel/types.js"; import type { InputResponse } from "#runtime/input/types.js"; import type { Session } from "#channel/session.js"; import type { RunMode } from "#shared/run-mode.js"; import type { JsonObject } from "#shared/json.js"; import type { ChannelMethod } from "#public/definitions/channel.js"; type WebSocketHeaders = Headers | readonly (readonly [string, string])[] | Record; /** * Second argument passed to every route handler. `send` starts or continues a * session on this channel; `getSession` looks one up by id; `receive` hands * inbound work to a different channel; `params` contains the matched path * parameters; `waitUntil` keeps background work alive past the response; * `requestIp` is the client IP, or `null` when the host cannot provide it. */ export interface RouteHandlerArgs { send: SendFn; getSession: GetSessionFn; /** * Starts a session on a different channel to hand off inbound work (e.g. an * HTTP webhook routing the conversation onto Slack). The target's authored * `receive` hook owns continuation-token format and initial state; the caller * supplies the payload, channel-specific args, and auth. */ receive: CrossChannelReceiveFn; params: Readonly>; waitUntil: (task: Promise) => void; requestIp: string | null; } export interface SendPayload { readonly message?: string | UserContent; readonly inputResponses?: readonly InputResponse[]; /** * Context strings contributed by the channel. eve appends each entry * as a `role: "user"` message to `session.history` before the delivery * message and persists it across the session. */ readonly context?: readonly string[]; /** * Run-scoped JSON schema the turn's result must match. Orthogonal to * {@link BaseSendOptions.mode}: eve enforces the schema in either mode; mode * only decides the failure behavior. A conversation run parks recoverably and * waits for more input; a task run (which cannot wait) finishes as an error. */ readonly outputSchema?: JsonObject; } /** * Starts or continues a session on this channel. Accepts a plain string, * `UserContent`, or a {@link SendPayload}, plus {@link SendOptions} (auth, * continuation token, run mode, and an optional seed `state` for stateful * channels). Resolves to the resulting {@link Session}. */ export type SendFn = (input: string | UserContent | SendPayload, options: SendOptions) => Promise; type BaseSendOptions = { auth: SessionAuthContext | null; callback?: SessionCallback; continuationToken: string; mode?: RunMode; }; /** * Options for {@link SendFn}. The channel owns its continuation-token * format: pass the channel-local raw token (the framework prepends * the channel name). Stateful channels also seed initial adapter * state via {@link state}, which becomes the new session's `state` * on first `runtime.run()` and is ignored on subsequent `deliver`s. */ export type SendOptions = [TState] extends [undefined] ? BaseSendOptions : BaseSendOptions & { state: TState; }; /** * Resolves an existing {@link Session} by id, for example to read its event * stream from within a route handler. */ export type GetSessionFn = (sessionId: string) => Session; export type RouteHandler = (req: Request, args: RouteHandlerArgs) => Promise; /** * A connected WebSocket peer passed to every {@link WebSocketRouteHooks} * callback. Send frames with `send`; manage pub/sub topics with `subscribe`, * `unsubscribe`, and `publish` (`topics` is the current subscription set). * `close` closes gracefully; `terminate` aborts the socket immediately. */ export interface WebSocketPeer { readonly id: string; readonly context: Record; readonly namespace: string; readonly request: Request; readonly remoteAddress?: string; readonly topics: Set; close(code?: number, reason?: string): void; publish(topic: string, data: unknown, options?: { compress?: boolean; }): void; send(data: unknown, options?: { compress?: boolean; }): number | void | undefined; subscribe(topic: string): void; terminate(): void; unsubscribe(topic: string): void; } /** * An inbound WebSocket frame passed to the `message` hook. `rawData` is the * original payload as received; `data` is the decoded value. Use `json`, * `text`, `arrayBuffer`, `blob`, or `uint8Array` to decode it explicitly. */ export interface WebSocketMessage { readonly data: unknown; readonly id: string; readonly rawData: unknown; arrayBuffer(): ArrayBuffer | SharedArrayBuffer; blob(): Blob; json(): T; text(): string; uint8Array(): Uint8Array; } /** * The `Request` passed to the `upgrade` hook, extended with an optional * `context` bag carrying host-supplied data for the upgrade. */ export interface WebSocketUpgradeRequest extends Request { readonly context?: Record; } /** * Return value of the `upgrade` hook. Return an object to attach `context`, * `headers`, or a `namespace`, or to mark the upgrade `handled`; return a * `Response` to reject the handshake; return `void` to proceed with defaults. */ export type WebSocketUpgradeResult = { readonly context?: Record; readonly handled?: boolean; readonly headers?: WebSocketHeaders; readonly namespace?: string; } | Response | void; /** * Lifecycle callbacks for a WebSocket connection. `open`, `message`, `close`, * and `error` react to peer activity; `upgrade` runs first and may rewrite or * short-circuit the handshake by returning a {@link WebSocketUpgradeResult}. */ export interface WebSocketRouteHooks { close?(peer: WebSocketPeer, details: { code?: number; reason?: string; }): void | Promise; error?(peer: WebSocketPeer, error: Error): void | Promise; message?(peer: WebSocketPeer, message: WebSocketMessage): void | Promise; open?(peer: WebSocketPeer): void | Promise; upgrade?(request: WebSocketUpgradeRequest): Promise | WebSocketUpgradeResult; } /** * Handler for a {@link WS} route. Runs once per upgrade request and returns the * {@link WebSocketRouteHooks} for that connection. */ export type WebSocketRouteHandler = (req: Request, args: RouteHandlerArgs) => Promise | WebSocketRouteHooks; /** * An HTTP route descriptor (method, path, handler). `transport` is optional and * treated as `"http"`: any route whose `transport` is not `"websocket"` is * dispatched over HTTP. */ export interface HttpRouteDefinition { readonly transport?: "http"; readonly method: ChannelMethod; readonly path: string; readonly handler: RouteHandler; } /** * A WebSocket route descriptor produced by {@link WS}. Its `handler` returns the * {@link WebSocketRouteHooks} for each connection. */ export interface WebSocketRouteDefinition { readonly transport: "websocket"; readonly method: "WEBSOCKET"; readonly path: string; readonly handler: WebSocketRouteHandler; } /** * A single channel route: either an {@link HttpRouteDefinition} or a * {@link WebSocketRouteDefinition}. Produced by the {@link GET}, {@link POST}, * {@link PUT}, {@link PATCH}, {@link DELETE}, and {@link WS} helpers and listed * in a channel's `routes` array. */ export type RouteDefinition = HttpRouteDefinition | WebSocketRouteDefinition; /** * Declares an HTTP `GET` route at `path`, dispatching to `handler`. The handler * receives the `Request` and {@link RouteHandlerArgs}. */ export declare function GET(path: string, handler: RouteHandler): HttpRouteDefinition; /** * Declares an HTTP `POST` route at `path`. See {@link GET} for the handler * contract. */ export declare function POST(path: string, handler: RouteHandler): HttpRouteDefinition; /** * Declares an HTTP `PUT` route at `path`. See {@link GET} for the handler * contract. */ export declare function PUT(path: string, handler: RouteHandler): HttpRouteDefinition; /** * Declares an HTTP `PATCH` route at `path`. See {@link GET} for the handler * contract. */ export declare function PATCH(path: string, handler: RouteHandler): HttpRouteDefinition; /** * Declares an HTTP `DELETE` route at `path`. See {@link GET} for the handler * contract. */ export declare function DELETE(path: string, handler: RouteHandler): HttpRouteDefinition; /** * Declares a WebSocket channel route. * * The handler runs once per upgrade request and returns lifecycle hooks for * that connection. The hooks are eve-owned structural types so channel authors * can use CrossWS-compatible helpers without eve exposing CrossWS directly. */ export declare function WS(path: string, handler: WebSocketRouteHandler): WebSocketRouteDefinition; export declare function isHttpRouteDefinition(route: RouteDefinition): route is HttpRouteDefinition; export declare function isWebSocketRouteDefinition(route: RouteDefinition): route is WebSocketRouteDefinition; export {};