UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

132 lines 7.36 kB
import { ContractBuilder } from "./contract-builder.js"; import { type ContractDeprecationMeta } from "./lifecycle.js"; import type { ContractErrorResponses, ContractHeaderSchemas, ContractMeta, ContractResponses, MergeContractMeta, MergedContractErrorResponses, OmitMetaKeys, ResponsesFromErrorDefinitions, StandardSchema } from "./types.js"; type TrimLeadingSlash<T extends string> = T extends `/${infer Rest}` ? TrimLeadingSlash<Rest> : T; type TrimTrailingSlash<T extends string> = T extends "/" ? "" : T extends `${infer Rest}/` ? TrimTrailingSlash<Rest> : T; type NormalizedPrefix<T extends string> = T extends "" | "/" ? "" : TrimTrailingSlash<T>; type NormalizedChildPath<T extends string> = TrimTrailingSlash<TrimLeadingSlash<T>>; type JoinPaths<TPrefix extends string, TPath extends string> = string extends TPrefix | TPath ? string : NormalizedPrefix<TPrefix> extends "" ? TPath : NormalizedChildPath<TPath> extends "" ? NormalizedPrefix<TPrefix> : `${NormalizedPrefix<TPrefix>}/${NormalizedChildPath<TPath>}`; /** * Feature-scoped factory for related HTTP contracts. * * Contract groups let a feature share a namespace, path prefix, headers, * responses, errors, and metadata across multiple endpoint contracts. The group * is immutable: every configuration method returns a new group. */ export declare class ContractGroup<TSharedResponses extends ContractResponses = Record<never, never>, TSharedMeta extends ContractMeta = ContractMeta, TSharedHeaders extends ContractHeaderSchemas = null, TPathPrefix extends string = ""> { private readonly _namespace; private readonly _meta; private readonly _responses; private readonly _headers; private readonly _pathPrefix; constructor(state?: { namespace?: string; meta?: TSharedMeta; responses?: TSharedResponses; headers?: TSharedHeaders; pathPrefix?: TPathPrefix; }); /** * Set the namespace for contracts created from this group. * * The namespace prefixes contract names, not paths. Use `prefix(...)` for * path composition. */ namespace(ns: string): ContractGroup<TSharedResponses, TSharedMeta, TSharedHeaders, TPathPrefix>; /** * Add a path prefix to contracts created from this group. * * Prefixes compose immutably, so `prefix("/api").prefix("/v1")` produces * paths under `/api/v1`. */ prefix<const TNewPrefix extends string>(pathPrefix: TNewPrefix): ContractGroup<TSharedResponses, TSharedMeta, TSharedHeaders, JoinPaths<TPathPrefix, TNewPrefix>>; /** * Merge shared metadata into contracts created from this group. */ meta<TNewMeta extends ContractMeta>(meta: TNewMeta): ContractGroup<TSharedResponses, MergeContractMeta<TSharedMeta, TNewMeta>, TSharedHeaders, TPathPrefix>; /** * Mark every contract created from this group as deprecated. */ deprecated<const TDeprecation extends ContractDeprecationMeta>(deprecation: TDeprecation): ContractGroup<TSharedResponses, MergeContractMeta<TSharedMeta, { deprecation: TDeprecation; }>, TSharedHeaders, TPathPrefix>; /** * Add shared route-owned response schemas to contracts created from this group. * * Framework-owned responses, such as validation or auth hook failures, do not * need to be declared here. */ responses<TNewResponses extends ContractResponses>(responseSchemas: TNewResponses): ContractGroup<Omit<TSharedResponses, keyof TNewResponses> & TNewResponses, TSharedMeta, TSharedHeaders, TPathPrefix>; /** * Declare shared route-owned application errors for contracts in this group. * * Catalog errors use Beignet's standard error envelope and remain separate * from framework-owned errors. Declarations merge with previously declared * group errors, and contracts created from the group merge these shared * errors with route-level `.errors()` declarations; later declarations win * when the same catalog key is declared twice. */ errors<TErrorDefs extends ContractErrorResponses>(errorDefs: TErrorDefs): ContractGroup<Omit<TSharedResponses, keyof ResponsesFromErrorDefinitions<TErrorDefs>> & ResponsesFromErrorDefinitions<TErrorDefs>, OmitMetaKeys<TSharedMeta, "errors"> & { errors: MergedContractErrorResponses<TSharedMeta, TErrorDefs>; }, TSharedHeaders, TPathPrefix>; /** * Add a shared request header schema to contracts created from this group. */ headers<TNewHeaders extends StandardSchema>(schema: TNewHeaders): ContractGroup<TSharedResponses, TSharedMeta, TSharedHeaders extends readonly StandardSchema[] ? readonly [...TSharedHeaders, TNewHeaders] : TSharedHeaders extends StandardSchema ? readonly [TSharedHeaders, TNewHeaders] : readonly [TNewHeaders], TPathPrefix>; /** * Create a GET contract under this group. */ get<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"GET", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create a POST contract under this group. */ post<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"POST", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create a PUT contract under this group. */ put<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"PUT", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create a PATCH contract under this group. */ patch<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"PATCH", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create a DELETE contract under this group. */ delete<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"DELETE", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create a HEAD contract under this group. */ head<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"HEAD", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Create an OPTIONS contract under this group. */ options<const TPath extends string>(path: TPath, name?: string): ContractBuilder<"OPTIONS", null, null, null, TSharedHeaders, TSharedResponses, TSharedMeta, JoinPaths<TPathPrefix, TPath>>; /** * Internal helper to create a contract builder with shared config */ private createBuilder; } /** * Create a new feature contract group. * * Start here for most feature HTTP surfaces, then add a namespace and path * prefix before defining individual contracts. * * @example * ```ts * const todos = defineContractGroup() * .namespace("todos") * .prefix("/api/todos") * .meta({ auth: "required" }) * .responses({ * 401: z.object({ message: z.literal("Unauthorized") }), * }); * * const getTodo = todos.get("/:id")... * ``` * * @returns An empty immutable contract group. */ export declare function defineContractGroup(): ContractGroup<Record<never, never>, ContractMeta, null, "">; export {}; //# sourceMappingURL=contract-group.d.ts.map