import type { DeliveredMessage } from './delivered-message.js'; import type { DispatchReceipt } from './dispatch.js'; import type { FabricActor } from './types.js'; /** * Channels turn platform webhooks (Slack, GitHub, …) into agent dispatches. Handlers are written * against the Web `Request`/`Response` API and `crypto.subtle`, so the same channel runs on Node and * Cloudflare. A channel is a stateless route container plus a conversation-id (de)serializer — * session continuity falls out of the key (same thread → same key → same session). */ export interface ChannelRoute { /** HTTP method, uppercase (e.g. "POST"). */ method: string; /** Absolute path suffix mounted under `/channels/:name` (e.g. "/events"). */ path: string; handler: (request: Request, context: ChannelContext) => Promise | Response; } export interface Channel { /** Optional stable name; the mount name usually comes from the file/registration. */ readonly name?: string; readonly routes: readonly ChannelRoute[]; /** Serialize a platform reference (e.g. a Slack thread) into a stable instance id. */ conversationKey(ref: unknown): string; /** Parse an instance id back into the platform reference. */ parseConversationKey(id: string): unknown; } export interface ChannelDispatchRequest { /** Target persistent-agent instance id — typically `channel.conversationKey(ref)`. */ instanceId: string; session?: string; /** * The message delivered to the session. Channels should construct signals * (`kind: 'signal'`) for platform activity; preferred over `input`. */ message?: DeliveredMessage; /** Legacy JSON payload. Normalized into a user-kind message at admission. */ input?: unknown; /** Stable key (e.g. the platform event id) → `dispatchId` for exactly-once delivery. */ dedupeKey?: string; tenantId?: string; actor?: FabricActor; } export type ChannelDispatch = (agent: string, request: ChannelDispatchRequest) => Promise; export interface ChannelContext { /** Dispatch to a persistent agent. Provided by the runtime mounting the channel. */ dispatch: ChannelDispatch; env: Record; } /** Validates and brands a channel's routes. */ export declare function defineChannel(channel: Channel): Channel; export declare function hmacSha256(secret: string | Uint8Array, message: Uint8Array): Promise; /** Constant-time HMAC-SHA256 verification (via `crypto.subtle.verify`). */ export declare function verifyHmacSha256(secret: string | Uint8Array, message: Uint8Array, signature: Uint8Array): Promise; export declare function bytesToHex(bytes: Uint8Array): string; export declare function hexToBytes(hex: string): Uint8Array; export declare function conversationKey(provider: string, version: string, ...segments: string[]): string; export interface ParsedConversationKey { provider: string; version: string; segments: string[]; } export declare function parseConversationKey(key: string): ParsedConversationKey; /** * Reads the full request body as bytes, or returns undefined if it exceeds `limitBytes`. * * NOTE: this consumes the request stream (single read). Signature-verifying channels need the *exact* * bytes for HMAC and the parsed JSON afterward — don't call `request.json()` as well. Use * {@link readJsonBody} to get both from one read. */ export declare function readRequestBody(request: Request, limitBytes?: number): Promise; export interface RequestBody { /** Exact bytes — use these (or `text`) for signature verification. */ raw: Uint8Array; /** UTF-8 decode of `raw`. */ text: string; /** Parsed JSON, or `undefined` if the body isn't valid JSON. */ json: unknown; } /** * Reads the body once and returns the raw bytes, the decoded text, and the parsed JSON together — so a * channel can HMAC-verify the exact bytes and use the JSON without re-reading the (already consumed) * stream. Returns undefined only when the body exceeds `limitBytes`. */ export declare function readJsonBody(request: Request, limitBytes?: number): Promise; //# sourceMappingURL=channel.d.ts.map