@beignet/core
Version:
Core framework primitives for Beignet
156 lines • 7.84 kB
TypeScript
import type { StandardSchemaV1 } from "@standard-schema/spec";
import { type ContractDeprecationMeta } from "./lifecycle.js";
import type { OpenAPIOperationMeta } from "./openapi-meta.js";
import type { BodyHttpMethod, ContractErrorResponses, ContractHeaderSchemas, ContractMeta, ContractResponses, HttpContractConfig, HttpMethod, MergeContractMeta, MergedContractErrorResponses, OmitMetaKeys, ResponsesFromErrorDefinitions, StandardSchema } from "./types.js";
/**
* Fluent builder for one HTTP contract.
*
* A contract describes the transport boundary for one endpoint: method, path,
* request schemas, response schemas, metadata, and route-owned catalog errors.
* Builder methods are immutable; each call returns a new builder with narrower
* types.
*/
export declare class ContractBuilder<TMethod extends HttpMethod, TPathParams extends StandardSchema | null, TQuery extends StandardSchema | null, TBody extends StandardSchema | null, THeaders extends ContractHeaderSchemas, TResponses extends ContractResponses, TMeta extends ContractMeta, TPath extends string = string> {
readonly kind: "http";
readonly name: string;
readonly namespace?: string;
readonly localName: string;
readonly method: TMethod;
private readonly _path;
private readonly _pathParams;
private readonly _query;
private readonly _body;
private readonly _headers;
private readonly _responses;
private readonly _meta;
constructor(config: HttpContractConfig<TMethod, TPathParams, TQuery, TBody, TResponses, TMeta, TPath, THeaders>);
/**
* Request and response schemas attached to this contract.
*
* Server adapters use these for validation. Client and frontend integrations
* use them for local validation and type inference.
*/
get schema(): {
pathParams: TPathParams;
query: TQuery;
headers: THeaders;
body: TBody;
responses: TResponses;
};
/**
* Response schemas keyed by HTTP status code.
*/
get responseSchemas(): TResponses;
/**
* URL path template for this contract.
*/
get path(): TPath;
/**
* Metadata consumed by hooks, OpenAPI generation, and app conventions.
*/
get metadata(): TMeta;
/**
* Plain contract config consumed by framework internals and integrations.
*/
get config(): HttpContractConfig<TMethod, TPathParams, TQuery, TBody, TResponses, TMeta, TPath, THeaders>;
/**
* Attach a schema for dynamic path parameters.
*
* The schema validates parameters parsed from path templates such as
* `/posts/:id` or `/posts/[id]`.
*/
pathParams<TNewPathParams extends StandardSchemaV1>(schema: TNewPathParams): ContractBuilder<TMethod, TNewPathParams, TQuery, TBody, THeaders, TResponses, TMeta, TPath>;
/**
* Attach a schema for query parameters.
*/
query<TNewQuery extends StandardSchemaV1>(schema: TNewQuery): ContractBuilder<TMethod, TPathParams, TNewQuery, TBody, THeaders, TResponses, TMeta, TPath>;
/**
* Attach a schema for a JSON request body.
*
* This method is only available on POST, PUT, and PATCH contracts.
*/
body<TNewBody extends StandardSchemaV1>(this: ContractBuilder<BodyHttpMethod, StandardSchema | null, StandardSchema | null, StandardSchema | null, ContractHeaderSchemas, ContractResponses, ContractMeta, TPath>, schema: TNewBody): ContractBuilder<TMethod, TPathParams, TQuery, TNewBody, THeaders, TResponses, TMeta, TPath>;
/**
* Attach a request header schema.
*
* Multiple schemas are evaluated in declaration order and their parsed
* outputs are merged. This lets a contract inherit shared group headers and
* still declare route-specific headers.
*/
headers<TNewHeaders extends StandardSchemaV1>(schema: TNewHeaders): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders extends readonly StandardSchema[] ? readonly [...THeaders, TNewHeaders] : THeaders extends StandardSchema ? readonly [THeaders, TNewHeaders] : readonly [TNewHeaders], TResponses, TMeta, TPath>;
/**
* Add or replace route-owned response schemas by status code.
*
* These schemas describe business responses returned by route handlers.
* Framework-owned errors such as request validation failures do not need to be
* declared here.
*
* Use `null` for void/empty responses such as 204 No Content.
*/
responses<TNewResponses extends ContractResponses>(responseSchemas: TNewResponses): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders, Omit<TResponses, keyof TNewResponses> & TNewResponses, TMeta, TPath>;
/**
* Declare route-owned application errors from an error catalog.
*
* Catalog errors use Beignet's standard error response envelope and remain
* distinguishable from framework-owned errors. Declarations merge with
* previously declared catalog errors, including shared group errors; later
* declarations win when the same catalog key is declared twice. Use
* `.responses()` when a route needs a custom error response body instead of
* catalog semantics.
*/
errors<TErrorDefs extends ContractErrorResponses>(errorDefs: TErrorDefs): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders, Omit<TResponses, keyof ResponsesFromErrorDefinitions<TErrorDefs>> & ResponsesFromErrorDefinitions<TErrorDefs>, OmitMetaKeys<TMeta, "errors"> & {
errors: MergedContractErrorResponses<TMeta, TErrorDefs>;
}, TPath>;
/**
* Merge metadata into this contract.
*
* Hooks and tooling can read metadata for concerns such as auth, rate limits,
* idempotency, OpenAPI, or app-specific conventions.
*/
meta<TNewMeta extends ContractMeta>(newMeta: TNewMeta): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders, TResponses, MergeContractMeta<TMeta, TNewMeta>, TPath>;
/**
* Mark this contract as deprecated for external clients.
*/
deprecated<const TDeprecation extends ContractDeprecationMeta>(deprecation: TDeprecation): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders, TResponses, MergeContractMeta<TMeta, {
deprecation: TDeprecation;
}>, TPath>;
/**
* Merge OpenAPI operation metadata into this contract.
*/
openapi<TPatch extends Partial<OpenAPIOperationMeta>>(patch: TPatch): ContractBuilder<TMethod, TPathParams, TQuery, TBody, THeaders, TResponses, MergeContractMeta<TMeta, {
openapi: TPatch;
}>, TPath>;
}
/**
* Options for creating one contract with `defineContract(...)`.
*/
export type DefineContractOptions<TMethod extends HttpMethod = HttpMethod, TPath extends string = string> = {
/** HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) */
method: TMethod;
/** URL path template (e.g., "/api/users/:id") */
path: TPath;
/** Optional contract name (auto-generated from method + path if not provided) */
name?: string;
};
/**
* Create a new HTTP contract builder.
*
* Most apps prefer `defineContractGroup().namespace(...).prefix(...)` for
* related feature contracts. Use this lower-level factory when a standalone
* contract is clearer.
*
* @example
* ```ts
* const getTodo = defineContract({
* method: "GET",
* path: "/api/todos/:id",
* })
* .pathParams(z.object({ id: z.string() }))
* .responses({ 200: TodoSchema });
* ```
*
* @param options - HTTP method, path template, and optional contract name.
* @returns A fluent contract builder.
*/
export declare function defineContract<TMethod extends HttpMethod, const TPath extends string>(options: DefineContractOptions<TMethod, TPath>): ContractBuilder<TMethod, null, null, null, null, Record<never, never>, ContractMeta, TPath>;
//# sourceMappingURL=contract-builder.d.ts.map