UNPKG

express-zod-api

Version:

A Typescript framework to help you get an API server up and running with I/O schema validation and custom middlewares in minutes.

798 lines (797 loc) 31.8 kB
import { A as AbstractLogger, C as ensureHttpError, D as ClientMethod, E as IOSchema, N as createApiResponse, O as Method, S as defaultResultHandler, T as FinalInputSchema, _ as ServerConfig, a as Handler, b as ResultHandler, c as Middleware, d as FlatObject, f as Tag, g as CommonConfig, h as AppConfig, i as Endpoint, j as LoggerOverrides, k as BuiltinLogger, l as EmptyObject, m as getMessageFromError, n as ServeStatic, o as AbstractMiddleware, p as TagOverrides, r as AbstractEndpoint, s as ExpressMiddleware, t as Routing, u as EmptySchema, v as createConfig, w as Extension, x as arrayResultHandler, y as AbstractResultHandler, } from "./routing-xQnwfH2D.js"; import { i as OpenAPIContext } from "./documentation-helpers-C3vkQCz2.js"; import { z } from "zod"; import express, { CookieOptions, Request, Response } from "express"; import http from "node:http"; import { RequestOptions, ResponseOptions } from "node-mocks-http"; import "express-fileupload"; import { AugmentedRequest, Options, RateLimitInfo, RateLimitRequestHandler } from "express-rate-limit"; /** * @desc Directives shared by both request and response Cache-Control headers. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#cache_directives */ interface CommonDirectives { /** * @desc Response: the response remains fresh for N seconds after it was generated. * @desc Request: the client will accept a stored response that was generated at most N seconds ago. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#max-age */ maxAge?: number; /** * @desc Forces revalidation with the server before reuse. * @desc In a response this tells caches to revalidate; in a request it asks caches to revalidate. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#no-cache */ noCache?: boolean; /** * @desc Prevents storing the response in any cache. In a response this instructs caches not to store. * @desc In a request it asks caches not to store the request or its response. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#no-store */ noStore?: boolean; /** * @desc Prevents intermediaries from transforming the response body (e.g. converting images). * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#no-transform */ noTransform?: boolean; /** * @desc Allows a stale cached response to be reused for N seconds when the origin server returns an error. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#stale-if-error */ staleIfError?: number; } /** * @desc Directives that clients send in requests to express their caching preferences. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#request_directives */ interface CacheControl extends CommonDirectives { /** * @desc The client will accept a stored response that is stale for up to N seconds beyond its freshness lifetime. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#max-stale */ maxStale?: number; /** * @desc The client requires a stored response that will remain fresh for at least N more seconds. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#min-fresh */ minFresh?: number; /** * @desc The client wants a response only from the cache. Throw createHttpError(504) in this case. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#only-if-cached */ onlyIfCached?: boolean; } /** * @desc Directives that servers send in responses to control how caches store and reuse the response. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#response_directives */ interface CachePolicy extends CommonDirectives { /** * @desc Restricts which caches may store the response. * @example "public" — any cache (browser, proxy, CDN); for static assets, responses without user-specific data. * @example "private" — browser only; for user-specific and personalized content. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#response_directives */ scope?: "public" | "private"; /** * @desc Overrides max-age for shared caches (proxies, CDNs). Ignored by private (browser) caches. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#s-maxage */ sMaxAge?: number; /** * @desc Forces all caches to revalidate stale responses with the origin server before reusing them. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#must-revalidate */ mustRevalidate?: boolean; /** * @desc Forces proxies and CDNs to revalidate stale responses with the origin server before reusing them. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#proxy-revalidate */ proxyRevalidate?: boolean; /** * @desc A cache must understand the caching requirements for the response's status code before storing it. * @desc Pair with no-store as a fallback for caches that don't support it. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#must-understand */ mustUnderstand?: boolean; /** * @desc Indicates that the response body will never change while fresh. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#immutable */ immutable?: boolean; /** * @desc Allows a stale response to be served in the background while the cache revalidates it, for up to N seconds. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#stale-while-revalidate */ staleWhileRevalidate?: number; } /** * @desc Creates a Middleware providing caching helpers. * @param defaultPolicy — Optional default Cache-Control policy applied to all responses. * @example createCacheMiddleware({ noCache: true, scope: "private" }) */ declare const createCacheMiddleware: (defaultPolicy?: CachePolicy) => Middleware< FlatObject, { /** * @desc Provides the parsed If-None-Match request header into an array of ETags. Can also be '*' wildcard. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-None-Match */ readonly ifNoneMatch: string[] | "*" | undefined; /** * @desc Provides the parsed If-Modified-Since request header having the timestamp of the client's cached copy. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-Modified-Since */ readonly ifModifiedSince: Date | undefined; /** * @desc Provides the parsed Cache-Control request header to reveal the client's caching intent. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control */ readonly cacheControl: CacheControl | undefined; /** * @desc Augments the Cache-Control response header, merging with the defaultPolicy if provided. * @desc Pass `undefined` for a directive to unset the default value. * @see defaultPolicy * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching */ addCachePolicy: (policy: CachePolicy) => void; /** * @desc Sets the ETag response header with a unique identifier for this version of the resource. * @see ifNoneMatch * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag */ setETag: (value: string) => void; /** * @desc Sets the Last-Modified response header to the timestamp when the resource was last changed. * @see ifModifiedSince * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Last-Modified */ setLastModified: (date: Date) => void; /** * @desc Sets the Vary response header to the list of request headers that influence the response. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Vary */ setVary: (...headers: string[]) => void; /** * @desc Sets the Expires response header with an explicit expiration date. Consider addCachePolicy({ maxAge }). * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Expires */ setExpires: (date: Date) => void; /** * @desc Sets the Clear-Site-Data response header with the "cache" directive to remove all cached responses. * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Clear-Site-Data */ clearSiteData: () => void; /** * @desc Sends an HTTP 304 Not Modified empty response and ends the response stream. * @example return ctx.notModified() as never; // to satisfy the handler's return type * @see ifNoneMatch * @see ifModifiedSince * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/304 */ notModified: () => void; }, string, undefined >; /** * @desc Creates a Middleware providing cookie-setting convenience methods. * @param baseOptions — Default options applied to every setCookie / clearCookie call. * @example createCookieMiddleware({ httpOnly: true, secure: true, path: "/" }) */ declare const createCookieMiddleware: (baseOptions?: CookieOptions) => Middleware< FlatObject, { /** * @desc Reads a cookie value. Checks signedCookies first, then falls back to cookies. * @requires cookie-parser * @see ServerConfig.cookies * */ getCookie: (name: string) => z.core.util.JSONType | undefined; /** @desc Sets a cookie on the response. Express converts non-string values to JSON. */ setCookie: (name: string, value: string | z.core.util.JSONType, overrides?: CookieOptions) => void; /** @desc Clears a cookie on the response. */ clearCookie: (name: string, overrides?: Omit<CookieOptions, "expires" | "maxAge">) => void; }, string, undefined >; /** * @desc Creates an ExpressMiddleware that enforces rate limits using express-rate-limit. * @requires express-rate-limit * @param options — Partial options passed to the express-rate-limit constructor. * @example createRateLimitMiddleware({ windowMs: 60000, max: 100 }) */ declare const createRateLimitMiddleware: (options?: Partial<Options>) => ExpressMiddleware< AugmentedRequest, import("express-serve-static-core").Response<any, Record<string, any>, number>, { rateLimit: RateLimitInfo & Pick<RateLimitRequestHandler, "getKey" | "resetKey">; } >; interface BuildProps< IN extends IOSchema, OUT extends IOSchema | z.ZodVoid, MIN extends IOSchema | undefined, CTX extends FlatObject, SCO extends string, > { /** * @desc Input schema of the Endpoint, combining properties from all the enabled input sources (path params, headers) * @default z.object({}) * @see defaultInputSources * */ input?: IN; /** @desc The schema by which the returns of the Endpoint handler is validated */ output: OUT; /** @desc The Endpoint handler receiving the validated inputs, returns of added Middlewares (ctx) and a logger */ handler: Handler<z.output<FinalInputSchema<MIN, IN>>, z.input<OUT>, CTX>; /** @desc The operation description for the generated Documentation (may use Markdown) */ description?: string; /** @desc The operation summary for the generated Documentation (short plain string) */ summary?: string; /** @desc The operation ID for the generated Documentation (must be unique) */ operationId?: string | ((method: ClientMethod) => string); /** * @desc HTTP method(s) this endpoint can handle * @default "get" unless method is explicitly defined in Routing keys * */ method?: Method | [Method, ...Method[]]; /** * @desc Scope(s) from the list of the ones defined by the added Middlewares having "oauth2" security type * @see OAuth2Security * */ scope?: SCO | SCO[]; /** * @desc Tag(s) for generating Documentation. For establishing constraints: * @see TagOverrides * */ tag?: Tag | Tag[]; /** @desc Marks the operation deprecated in the generated Documentation */ deprecated?: boolean; } /** * @desc Creates a factory for building Endpoints. It can be extended by adding Middlewares that enrich the context * available to the Endpoint handler. It requires a ResultHandler to respond consistently. * @see Middleware * @see ResultHandler * */ declare class EndpointsFactory< IN extends IOSchema | undefined = undefined, CTX extends FlatObject = EmptyObject, SCO extends string = string, > { protected resultHandler: AbstractResultHandler; protected schema: IN; protected middlewares: AbstractMiddleware[]; /** * @param resultHandler An instance of ResultHandler for handling both Endpoint outputs and all possible errors. * @see ResultHandler * */ constructor(resultHandler: AbstractResultHandler); /** * @desc Attaches a Middleware to the factory, extending the context available to Endpoints built on it. * Accepts either a Middleware instance or a plain object compatible with the Middleware constructor. * @see Middleware * */ addMiddleware<RET extends FlatObject, ASCO extends string, AIN extends IOSchema | undefined = undefined>( subject: Middleware<CTX, RET, ASCO, AIN> | ConstructorParameters<typeof Middleware<CTX, RET, ASCO, AIN>>[0], ): EndpointsFactory<Extension<IN, AIN>, (CTX extends Record<string, never> ? RET : CTX) & RET, SCO & ASCO>; /** @desc Shorthand for .addMiddleware(createCookieMiddleware()) */ useCookies(...args: Parameters<typeof createCookieMiddleware>): EndpointsFactory< Extension<IN, undefined>, (CTX extends Record<string, never> ? { getCookie: (name: string) => z.core.util.JSONType | undefined; setCookie: ( name: string, value: string | z.core.util.JSONType, overrides?: import("express").CookieOptions, ) => void; clearCookie: (name: string, overrides?: Omit<import("express").CookieOptions, "expires" | "maxAge">) => void; } : CTX) & { getCookie: (name: string) => z.core.util.JSONType | undefined; setCookie: ( name: string, value: string | z.core.util.JSONType, overrides?: import("express").CookieOptions, ) => void; clearCookie: (name: string, overrides?: Omit<import("express").CookieOptions, "expires" | "maxAge">) => void; }, SCO >; /** @desc Shorthand for .addMiddleware(createCacheMiddleware()) */ useCache(...args: Parameters<typeof createCacheMiddleware>): EndpointsFactory< Extension<IN, undefined>, (CTX extends Record<string, never> ? { readonly ifNoneMatch: string[] | "*" | undefined; readonly ifModifiedSince: Date | undefined; readonly cacheControl: CacheControl | undefined; addCachePolicy: (policy: CachePolicy) => void; setETag: (value: string) => void; setLastModified: (date: Date) => void; setVary: (...headers: string[]) => void; setExpires: (date: Date) => void; clearSiteData: () => void; notModified: () => void; } : CTX) & { readonly ifNoneMatch: string[] | "*" | undefined; readonly ifModifiedSince: Date | undefined; readonly cacheControl: CacheControl | undefined; addCachePolicy: (policy: CachePolicy) => void; setETag: (value: string) => void; setLastModified: (date: Date) => void; setVary: (...headers: string[]) => void; setExpires: (date: Date) => void; clearSiteData: () => void; notModified: () => void; }, SCO >; /** @desc Shorthand for .addMiddleware(createRateLimitMiddleware()) */ useRateLimit(...args: Parameters<typeof createRateLimitMiddleware>): EndpointsFactory< Extension<IN, undefined>, (CTX extends Record<string, never> ? { rateLimit: import("express-rate-limit").RateLimitInfo & Pick<import("express-rate-limit").RateLimitRequestHandler, "getKey" | "resetKey">; } : CTX) & { rateLimit: import("express-rate-limit").RateLimitInfo & Pick<import("express-rate-limit").RateLimitRequestHandler, "getKey" | "resetKey">; }, SCO >; /** * @desc Shorthand for addExpressMiddleware(). Use it for wrapping native Express middlewares. * @see addExpressMiddleware * */ use: <R extends Request, S extends Response, AOUT extends FlatObject = Record<string, never>>( nativeMw: (request: R, response: S, next: import("express").NextFunction) => any, params_1?: | { provider?: ((request: R, response: S) => AOUT | Promise<AOUT>) | undefined; transformer?: (err: Error) => Error; } | undefined, ) => EndpointsFactory<Extension<IN, undefined>, (CTX extends Record<string, never> ? AOUT : CTX) & AOUT, SCO>; /** * @desc Wraps a native Express middleware and attaches it to the factory as a Middleware. Optionally, a `provider` * can extract context properties from the request and response, and a `transformer` can convert errors. * @see ExpressMiddleware * */ addExpressMiddleware<R extends Request, S extends Response, AOUT extends FlatObject = EmptyObject>( ...params: ConstructorParameters<typeof ExpressMiddleware<R, S, AOUT>> ): EndpointsFactory<Extension<IN, undefined>, (CTX extends Record<string, never> ? AOUT : CTX) & AOUT, SCO>; /** * @desc Extends the context available to Endpoints built on this factory by resolving additional properties * from an asynchronous callback. The callback receives the current accumulated context, allowing further * context values to depend on previously provided ones. This is a shorthand for addMiddleware() with no schema. * @see addMiddleware * */ addContext<RET extends FlatObject>( provider: (current: CTX) => Promise<RET>, ): EndpointsFactory<Extension<IN, undefined>, (CTX extends Record<string, never> ? RET : CTX) & RET, SCO>; /** * @desc Builds an Endpoint using the accumulated Middlewares, the ResultHandler, and the given configuration. * The output is validated against the output schema; the handler receives the validated input and context. * @see Endpoint * */ build<BOUT extends IOSchema, BIN extends IOSchema = EmptySchema>({ input, output: outputSchema, operationId, scope, tag, method, ...rest }: BuildProps<BIN, BOUT, IN, CTX, SCO>): Endpoint<FinalInputSchema<IN, BIN>, BOUT, CTX>; /** * @desc shorthand for build() having output schema assigned with an empty object * @see build * */ buildVoid<BIN extends IOSchema = EmptySchema>({ handler, ...rest }: Omit<BuildProps<BIN, z.ZodVoid, IN, CTX, SCO>, "output">): Endpoint< FinalInputSchema<IN, BIN>, z.ZodObject<{}, z.core.$strip>, CTX >; } /** * @desc The factory based on the default ResultHandler: suitable for JSON responses. * @see defaultResultHandler * */ declare const defaultEndpointsFactory: EndpointsFactory<undefined, Record<string, never>, string>; /** * @deprecated Resist the urge of using it: this factory is designed only to simplify the migration of legacy APIs. * @desc Responding with an array is a bad practice keeping your endpoints from evolving without breaking changes. * @desc The result handler of this factory expects your endpoint to have the property 'items' in the output schema */ declare const arrayEndpointsFactory: EndpointsFactory<undefined, Record<string, never>, string>; declare const attachRouting: ( config: AppConfig, routing: Routing, ) => { notFoundHandler: express.RequestHandler< import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any> >; logger: AbstractLogger | BuiltinLogger; }; declare const createServer: ( config: ServerConfig, routing: Routing, ) => { app: import("express-serve-static-core").Express; logger: AbstractLogger | BuiltinLogger; servers: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>[]; }; /** @desc An error related to the wrong Routing declaration */ declare class RoutingError extends Error { name: string; readonly cause: { method: Method; path: string; }; constructor(message: string, method: Method, path: string); } /** * @desc An error related to the generating of the documentation * */ declare class DocumentationError extends Error { name: string; readonly cause: string; constructor(message: string, { method, path, isResponse }: Pick<OpenAPIContext, "path" | "method" | "isResponse">); } /** @desc An error related to the input and output schemas declaration */ declare class IOSchemaError extends Error { name: string; } /** @desc An error of validating the Endpoint handler's returns against the Endpoint output schema */ declare class OutputValidationError extends IOSchemaError { readonly cause: z.ZodError; name: string; constructor(cause: z.ZodError); } /** @desc An error of validating the input sources against the Middleware or Endpoint input schema */ declare class InputValidationError extends IOSchemaError { readonly cause: z.ZodError; name: string; constructor(cause: z.ZodError); } declare class MissingPeerError extends Error { name: string; constructor(module: string); } interface TestingProps<REQ, LOG> { /** * @desc Additional properties to set on Request mock * @default { method: "GET", headers: { "content-type": "application/json" } } * */ requestProps?: REQ; /** * @link https://www.npmjs.com/package/node-mocks-http * @default { req: requestMock } * */ responseOptions?: ResponseOptions; /** * @desc Additional properties to set on config mock * @default { cors: false, logger } * */ configProps?: Partial<CommonConfig>; /** * @desc Additional properties to set on logger mock * @default { info, warn, error, debug } * */ loggerProps?: LOG; } declare const testEndpoint: <LOG extends FlatObject, REQ extends RequestOptions>({ endpoint, ...rest }: TestingProps<REQ, LOG> & { /** @desc The endpoint to test */ endpoint: AbstractEndpoint; }) => Promise<{ requestMock: import("node-mocks-http").MockRequest< Request< import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any> > & REQ >; responseMock: import("node-mocks-http").MockResponse<Response<any, Record<string, any>>>; loggerMock: AbstractLogger & LOG & { _getLogs: () => Record<"debug" | "info" | "warn" | "error", unknown[]>; }; }>; interface MiddlewareLike<RET extends FlatObject> { execute(...params: Parameters<AbstractMiddleware["execute"]>): Promise<RET>; } declare const testMiddleware: <LOG extends FlatObject, REQ extends RequestOptions, RET extends FlatObject>({ middleware, ctx, ...rest }: TestingProps<REQ, LOG> & { /** @desc The middleware to test */ middleware: MiddlewareLike<RET>; /** @desc The aggregated returns of previously executed middlewares */ ctx?: FlatObject; }) => Promise<{ output: Partial<RET>; requestMock: import("node-mocks-http").MockRequest< Request< import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any> > & REQ >; responseMock: import("node-mocks-http").MockResponse<Response<any, Record<string, any>>>; loggerMock: AbstractLogger & LOG & { _getLogs: () => Record<"debug" | "info" | "warn" | "error", unknown[]>; }; }>; type EventsMap = Record<string, z.ZodType>; interface Emitter<E extends EventsMap> extends FlatObject { /** @desc Returns true when the connection was closed or terminated */ isClosed: () => boolean; /** @desc Abort signal bound to the client connection lifecycle */ signal: AbortSignal; /** @desc Sends an event to the stream according to the declared schema */ emit: <K extends keyof E>(event: K, data: z.input<E[K]>) => void; } declare class EventStreamFactory<E extends EventsMap> extends EndpointsFactory<undefined, Emitter<E>> { constructor(events: E); } interface DateInParams extends z.core.GlobalMeta { examples?: string[]; } interface DateOutParams extends z.core.GlobalMeta { examples?: string[]; } declare const DEFAULT_ITEMS_NAME: "items"; /** @desc Common pagination config: shared by offset and cursor styles. */ interface CommonPaginationConfig<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> { /** @desc Zod schema for each item in the paginated list. */ itemSchema: T; /** * @desc The name of the property containing the list of items. * @default "items" * */ itemsName?: K; /** * @desc Maximum allowed page size (client request is capped to this). * @default 100 */ maxLimit?: number; /** * @desc Default page size when the client omits the limit parameter. * @default 20 */ defaultLimit?: number; } /** * @desc Configuration for offset-based pagination (limit and offset). * @example { style: "offset", itemSchema, maxLimit: 50, defaultLimit: 10 } */ interface OffsetPaginatedConfig< T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME, > extends CommonPaginationConfig<T, K> { /** @desc Discriminator for offset-style pagination. */ style: "offset"; } /** * @desc Configuration for cursor-based pagination (cursor and limit). * @example { style: "cursor", itemSchema, maxLimit: 50, defaultLimit: 10 } */ interface CursorPaginatedConfig< T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME, > extends CommonPaginationConfig<T, K> { /** @desc Discriminator for cursor-style pagination. */ style: "cursor"; } /** @desc Request params for offset pagination. */ type OffsetInput = z.ZodObject<{ /** @desc Page size (number of items per page). */ limit: z.ZodDefault<z.ZodCoercedNumber>; /** @desc Number of items to skip from the start of the list. */ offset: z.ZodDefault<z.ZodCoercedNumber>; }>; /** @desc Request params for cursor pagination. */ type CursorInput = z.ZodObject<{ /** @desc Opaque cursor for the next page; omit for the first page. */ cursor: z.ZodOptional<z.ZodString>; /** @desc Page size (number of items per page). */ limit: z.ZodDefault<z.ZodCoercedNumber>; }>; /** @desc Response shape for offset pagination. */ type OffsetOutput<T extends z.ZodType, K extends string> = z.ZodObject< { [ITEMS in K]: z.ZodArray<T> } & { /** @desc Total number of items across all pages. */ total: z.ZodNumber; /** @desc Page size used for this response. */ limit: z.ZodNumber; /** @desc Offset used for this response. */ offset: z.ZodNumber; } >; /** @desc Response shape for cursor pagination. */ type CursorOutput<T extends z.ZodType, K extends string> = z.ZodObject< { [ITEMS in K]: z.ZodArray<T> } & { /** @desc Cursor for the next page, or null if there are no more pages. */ nextCursor: z.ZodNullable<z.ZodString>; /** @desc Page size used for this response. */ limit: z.ZodNumber; } >; /** @desc Return type of ez.paginated() for offset style. */ interface OffsetPaginatedResult<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> { /** @desc Zod schema for offset pagination request params. */ input: OffsetInput; /** @desc Zod schema for offset pagination response. */ output: OffsetOutput<T, K>; } /** @desc Return type of ez.paginated() for cursor style. */ interface CursorPaginatedResult<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> { /** @desc Zod schema for cursor pagination request params. */ input: CursorInput; /** @desc Zod schema for cursor pagination response. */ output: CursorOutput<T, K>; } /** * @desc Creates a pagination helper with a single config for both request params and response shape. * Use the returned `.input` as the endpoint input schema and `.output` as the response schema. * Compose with other params via `.input.and(z.object({ ... }))`. * * @param config - Pagination config; `style` discriminates offset vs cursor; `itemSchema` defines each list item. * @returns Object with `input` (Zod schema for pagination params) and `output` (Zod schema for paginated response). * * @example * const pagination = ez.paginated({ style: "offset", maxLimit: 100, defaultLimit: 20, itemSchema: userSchema }); * endpoint.input = pagination.input.and(z.object({ ... })); * endpoint.output = pagination.output; */ declare function paginated<T extends z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME>( config: OffsetPaginatedConfig<T, K>, ): OffsetPaginatedResult<T, K>; declare function paginated<T extends z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME>( config: CursorPaginatedConfig<T, K>, ): CursorPaginatedResult<T, K>; declare const base: z.ZodObject< { raw: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>; }, z.core.$strip >; type Base = typeof base; declare const extended: <S extends z.core.$ZodShape>( extra: S, ) => z.ZodObject< ( "raw" & keyof S extends never ? { raw: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>; } & { -readonly [P in keyof S]: S[P] } : ({ raw: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>; } extends infer T_1 extends z.core.util.SomeObject ? { [K in keyof T_1 as K extends keyof S ? never : K]: T_1[K] } : never) & { [K_1 in keyof { -readonly [P in keyof S]: S[P] }]: { -readonly [P in keyof S]: S[P] }[K_1] } ) extends infer T ? { [k in keyof T]: T[k] } : never, z.core.$strip >; declare function raw(): Base; declare function raw<S extends z.core.$ZodShape>(extra: S): ReturnType<typeof extended<S>>; declare const ez: { dateIn: ({ examples, ...rest }?: DateInParams) => import("zod").ZodPipe< import("zod").ZodPipe< import("zod").ZodUnion<readonly [import("zod").ZodISODate, import("zod").ZodISODateTime]>, import("zod").ZodTransform<Date, string> >, import("zod").ZodDate >; dateOut: ( meta?: DateOutParams, ) => import("zod").ZodPipe< import("zod").ZodPipe<import("zod").ZodDate, import("zod").ZodTransform<string, Date>>, import("zod").ZodISODateTime >; form: <S extends import("zod/v4/core").$ZodShape>( base: S | import("zod").ZodObject<S>, ) => import("zod").ZodObject<S, import("zod/v4/core").$strip>; upload: () => import("zod").ZodCustom< import("express-fileupload").UploadedFile, import("express-fileupload").UploadedFile >; raw: typeof raw; buffer: () => import("zod").ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>; paginated: typeof paginated; }; export { BuiltinLogger, DocumentationError, EndpointsFactory, EventStreamFactory, InputValidationError, type LoggerOverrides, type Method, Middleware, MissingPeerError, OutputValidationError, ResultHandler, type Routing, RoutingError, ServeStatic, type TagOverrides, arrayEndpointsFactory, arrayResultHandler, attachRouting, createApiResponse, createCacheMiddleware, createConfig, createCookieMiddleware, createRateLimitMiddleware, createServer, defaultEndpointsFactory, defaultResultHandler, ensureHttpError, ez, getMessageFromError, testEndpoint, testMiddleware, };