UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

139 lines 6.43 kB
import type { ContractLike, ResolveContract } from "./contract-like.js"; import type { AddedCtxFromHooks, Handler, RouteHook } from "./http.js"; import type { AnyUseCaseLike, AnyUseCaseRouteDef, UseCaseRouteDef, ValidatedRouteInputs } from "./use-case-route.js"; /** * Route registration that connects a contract to the handler implementing it. * * Most apps keep route definitions in `features/<feature>/routes.ts` and * compose them with `defineRoutes(...)`. */ export type HandlerRouteDef<Ctx, CLike extends ContractLike = ContractLike, Hooks extends readonly RouteHook<Ctx, object>[] = readonly RouteHook<Ctx, object>[]> = { /** * Contract builder or plain contract config for this route. */ contract: CLike; /** * Route-scoped hooks that run after group hooks and before the handler. */ hooks?: Hooks; /** * Handler that implements the contract. */ handle: Handler<Ctx & AddedCtxFromHooks<Hooks>, ResolveContract<CLike>>; useCase?: never; input?: never; status?: never; }; /** * Route registration for one contract. * * Routes either bind the contract directly to a use case (`{ contract, * useCase }`) or implement a full handler (`{ contract, handle }`). The full * handler form is the escape hatch for response headers, streaming, native * `Response` values, and multi-status handling. */ export type RouteDef<Ctx, CLike extends ContractLike = ContractLike, Hooks extends readonly RouteHook<Ctx, object>[] = readonly RouteHook<Ctx, object>[]> = HandlerRouteDef<Ctx, CLike, Hooks> | AnyUseCaseRouteDef<Ctx, CLike, Hooks>; type AnyRouteDef = RouteDef<any, any>; type PlainRouteDef<Ctx> = RouteDef<Ctx, any, readonly []>; type AnyContractRouteDef<Ctx> = RouteDef<Ctx, any>; declare const ROUTE_GROUP_KIND = "beignet.route-group"; /** * Named collection of related route registrations. * * Route groups colocate feature routes and can apply scoped route hooks to * every route in the group. `defineRoutes(...)` flattens them before server * registration while preserving those hooks. */ export type RouteGroup<Ctx, Routes extends readonly AnyRouteDef[] = readonly AnyRouteDef[]> = { /** * Internal marker used by `defineRoutes(...)`. */ kind: typeof ROUTE_GROUP_KIND; /** * Human-readable group name. */ name: string; /** * Hooks applied to every route in this group. */ hooks?: readonly RouteHook<Ctx, object>[]; /** * Route definitions in this group. */ routes: Routes; }; type RouteInput<Ctx> = AnyContractRouteDef<Ctx> | AnyRouteDef | RouteGroup<Ctx, readonly AnyRouteDef[]>; type ContextualRouteInput<Ctx> = PlainRouteDef<Ctx> | RouteGroup<Ctx, readonly AnyRouteDef[]>; /** * App-bound builder for one route registration. */ export type RouteDefinitionBuilder<Ctx> = { <CLike extends ContractLike, UC extends AnyUseCaseLike, const Hooks extends readonly RouteHook<Ctx, object>[] = readonly []>(route: UseCaseRouteDef<Ctx, CLike, UC, Hooks>): UseCaseRouteDef<Ctx, CLike, UC, Hooks>; <CLike extends ContractLike, const Hooks extends readonly RouteHook<Ctx, object>[] = readonly []>(route: HandlerRouteDef<Ctx, CLike, Hooks>): HandlerRouteDef<Ctx, CLike, Hooks>; }; /** * App-bound builder for a named route group. */ export type RouteGroupBuilder<Ctx> = { <const GroupHooks extends readonly RouteHook<Ctx, object>[] = readonly [], const R extends readonly PlainRouteDef<Ctx & AddedCtxFromHooks<GroupHooks>>[] = readonly PlainRouteDef<Ctx & AddedCtxFromHooks<GroupHooks>>[]>(group: { name: string; hooks?: GroupHooks; routes: R & ValidatedRouteInputs<Ctx & AddedCtxFromHooks<GroupHooks>, R>; }): RouteGroup<Ctx, R>; <const GroupHooks extends readonly RouteHook<Ctx, object>[] = readonly [], const R extends readonly AnyRouteDef[] = readonly AnyRouteDef[]>(group: { name: string; hooks?: GroupHooks; routes: R & ValidatedRouteInputs<Ctx & AddedCtxFromHooks<GroupHooks>, R>; }): RouteGroup<Ctx, R>; }; /** * Route declaration builders bound to an application context type. */ export interface Routes<Ctx> { /** Define one route registration. */ defineRoute: RouteDefinitionBuilder<Ctx>; /** Define a named group of related route registrations. */ defineRouteGroup: RouteGroupBuilder<Ctx>; } type RoutesFromInput<Input> = Input extends RouteGroup<infer _Ctx, infer Routes> ? Routes : Input extends AnyRouteDef ? readonly [Input] : readonly []; type FlattenRouteInputs<Inputs extends readonly unknown[]> = number extends Inputs["length"] ? readonly AnyRouteDef[] : Inputs extends readonly [infer First, ...infer Rest] ? readonly [...RoutesFromInput<First>, ...FlattenRouteInputs<Rest>] : readonly []; type ContractsFromRouteList<Routes extends readonly RouteDef<any, any>[]> = { readonly [Index in keyof Routes]: Routes[Index] extends RouteDef<any, infer CLike> ? ResolveContract<CLike> : never; }; /** * Define and flatten route registrations with strong type inference. * * Pass route definitions and route groups here before `createServer(...)`. * Group entries are flattened so downstream tooling receives one route list. * * @example * ```ts * const routes = defineRoutes<AppContext>([ * { contract: listPosts, useCase: listPostsUseCase }, * ]); * ``` */ export declare function defineRoutes<Ctx, const R extends readonly ContextualRouteInput<Ctx>[] = readonly ContextualRouteInput<Ctx>[]>(routes: R & ValidatedRouteInputs<Ctx, R>): FlattenRouteInputs<R>; export declare function defineRoutes<Ctx, const R extends readonly RouteInput<Ctx>[] = readonly RouteInput<Ctx>[]>(routes: R & ValidatedRouteInputs<Ctx, R>): FlattenRouteInputs<R>; /** * Extract contract configs from a route list. * * Use this to drive clients, OpenAPI, and docs from the same route list passed * to `createServer(...)`. */ export declare function contractsFromRoutes<const R extends readonly RouteDef<any, any>[]>(routes: R): ContractsFromRouteList<R>; /** * Create route declaration builders bound to an application context type. * * Call this once in `lib/routes.ts`, then import the app-bound builders from * feature route files. * * @example * ```ts * export const { defineRoute, defineRouteGroup } = * createRoutes<AppContext>(); * ``` */ export declare function createRoutes<Ctx>(): Routes<Ctx>; export {}; //# sourceMappingURL=route-definitions.d.ts.map