/** * Route contracts — the static half of an HTTP surface. * * A contract is pure data at module scope: method + path + zod schemas + * a stable id. No handler, no services, no I/O. That split is what makes * three things possible at once: * * - `configure` can register it in the DOT manifest (configure is sync); * - OpenAPI generation is static — no boot required; * - the handler signature is fully inferred when the contract is bound * (see `routes().bind()` in `bundle.ts`). */ import type { z } from 'zod'; import type { RouteMeta } from './openapi.js'; /** Methods a {@link RouteContract} can declare. */ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; /** * Path-parameter names extracted from a path literal at the type level: * `'/orders/:id/items/:itemId'` → `'id' | 'itemId'`. */ export type PathParams = TPath extends `${string}:${infer Rest}` ? Rest extends `${infer Param}/${infer Tail}` ? Param | PathParams<`/${Tail}`> : Rest : never; /** Typed view of a path's parameters: every value is a string. */ export type ParamsOf = Readonly, string>>; /** * The minimal schema surface the engine needs (`parse` only). Every zod * schema satisfies it structurally, which lets mixed-generic contracts * live in one array without variance fights. Values MUST be zod schemas — * `toOpenApi` converts them via `z.toJSONSchema`. */ export type SchemaLike = { parse(input: unknown): unknown; }; /** * A JSON route contract. Create via {@link route}. The generics carry the * validated input/output types into the bound handler's signature. */ export type RouteContract = { readonly kind: 'http'; /** Stable identifier — lands in the manifest and OpenAPI `operationId`. */ readonly id: string; readonly method: HttpMethod; readonly path: TPath; readonly summary?: string; readonly query?: z.ZodType; readonly body?: z.ZodType; readonly output?: z.ZodType; toDotAction(): RouteMeta; }; /** * A typed server-sent-events contract. Create via {@link route.sse}. The * bound handler is an async generator; every yielded value is validated * against `event` and framed as an SSE `data:` message. */ export type SseContract = { readonly kind: 'sse'; readonly id: string; readonly method: 'GET'; readonly path: TPath; readonly summary?: string; readonly query?: z.ZodType; /** Schema every yielded event is validated against. */ readonly event: z.ZodType; /** Emit `:keepalive` comments at this interval. Off when omitted. */ readonly heartbeatMs?: number; toDotAction(): RouteMeta; }; /** * Generics-erased view of a contract — what bundles store and the engine, * manifest registration, and OpenAPI generation consume. Both contract * types are structurally assignable to it; no casts involved. */ export type ContractLike = { readonly kind: 'http' | 'sse'; readonly id: string; readonly method: HttpMethod; readonly path: string; readonly summary?: string; readonly query?: SchemaLike; readonly body?: SchemaLike; readonly output?: SchemaLike; readonly event?: SchemaLike; readonly heartbeatMs?: number; toDotAction(): RouteMeta; }; type RouteDef = { readonly id: string; readonly summary?: string; readonly query?: z.ZodType; readonly body?: z.ZodType; readonly output?: z.ZodType; }; /** * Contract factories, one per method, plus {@link route.sse} for typed * event streams. * * ```ts * export const listOrders = route.get('/orders', { * id: 'orders.list', * query: z.object({ status: z.enum(['open', 'shipped']).optional() }), * output: z.array(Order), * }); * * export const progress = route.sse('/orders/:id/progress', { * id: 'orders.progress', * event: z.discriminatedUnion('type', [Queued, Shipped]), * }); * ``` */ export declare const route: { get: (path: TPath, def: RouteDef) => RouteContract; post: (path: TPath, def: RouteDef) => RouteContract; put: (path: TPath, def: RouteDef) => RouteContract; patch: (path: TPath, def: RouteDef) => RouteContract; delete: (path: TPath, def: RouteDef) => RouteContract; sse: (path: TPath, def: { readonly id: string; readonly summary?: string; readonly query?: z.ZodType; readonly event: z.ZodType; readonly heartbeatMs?: number; }) => SseContract; }; export {}; //# sourceMappingURL=contract.d.ts.map