@btravstack/contract / zod
zod
Type Aliases
PageLimits
type PageLimits = object;Defined in: zod.ts:10
How large a page may be, and how large it is when the caller says nothing.
Both are the API's decision rather than the framework's, so both are overridable — the defaults are a listing that behaves reasonably when nobody has thought about it yet.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
defaultLimit? | readonly | number | The size of a page whose caller named none. Default 20. | zod.ts:12 |
maxLimit? | readonly | number | The largest page a caller may ask for. Default 100. | zod.ts:14 |
Functions
pageOf()
function pageOf<Item>(item): ZodUnion<readonly [ZodObject<{
hasNextPage: ZodLiteral<false>;
hasPreviousPage: ZodLiteral<false>;
items: ZodArray<Item>;
}, $strict>, ZodObject<{
hasNextPage: ZodLiteral<true>;
hasPreviousPage: ZodLiteral<false>;
items: ZodArray<Item>;
nextCursor: ZodString;
}, $strict>, ZodObject<{
hasNextPage: ZodLiteral<false>;
hasPreviousPage: ZodLiteral<true>;
items: ZodArray<Item>;
previousCursor: ZodString;
}, $strict>, ZodObject<{
hasNextPage: ZodLiteral<true>;
hasPreviousPage: ZodLiteral<true>;
items: ZodArray<Item>;
nextCursor: ZodString;
previousCursor: ZodString;
}, $strict>]>;Defined in: zod.ts:45
The schema of one page of item: the four pages that exist, as four closed objects.
A union rather than an intersection, because allOf of closed objects validates nothing in JSON Schema and the emitted OpenAPI document is an interop surface. strictObject, so a cursor on a closed side is refused rather than stripped: the arms differ by which fields they carry, and the schema this generates already says additionalProperties: false — a stripping parser would accept what its own published schema rejects.
What it parses to is assignable to Page<T>, which pagination.test-d.ts pins, and every page page builds parses against it, which pagination.spec.ts pins — so a field dropped, loosened or renamed on either side fails a check. Widening Page<T> with a field no page carries is the one drift neither sees.
Type Parameters
| Type Parameter |
|---|
Item extends ZodType<unknown, unknown, $ZodTypeInternals<unknown, unknown>> |
Parameters
| Parameter | Type |
|---|---|
item | Item |
Returns
ZodUnion<readonly [ZodObject<{ hasNextPage: ZodLiteral<false>; hasPreviousPage: ZodLiteral<false>; items: ZodArray<Item>; }, $strict>, ZodObject<{ hasNextPage: ZodLiteral<true>; hasPreviousPage: ZodLiteral<false>; items: ZodArray<Item>; nextCursor: ZodString; }, $strict>, ZodObject<{ hasNextPage: ZodLiteral<false>; hasPreviousPage: ZodLiteral<true>; items: ZodArray<Item>; previousCursor: ZodString; }, $strict>, ZodObject<{ hasNextPage: ZodLiteral<true>; hasPreviousPage: ZodLiteral<true>; items: ZodArray<Item>; nextCursor: ZodString; previousCursor: ZodString; }, $strict>]>
pageRequestOf()
function pageRequestOf<Filters>(filters, limits?): ZodObject<{ [k in string | number | symbol]: ((("limit" | "after" | "before") & keyof Filters) extends never ? { after: ZodOptional<ZodString>; before: ZodOptional<ZodString>; limit: ZodPrefault<ZodNumber> } & { -readonly [P in string | number | symbol]: Filters[P] } : { [K in "limit" | "after" | "before" as K extends keyof Filters ? never : K]: { after: ZodOptional<ZodString>; before: ZodOptional<ZodString>; limit: ZodPrefault<ZodNumber> }[K] } & { [K in string | number | symbol]: { -readonly [P in string | number | symbol]: Filters[P] }[K] })[k] }, $strip>;Defined in: zod.ts:75
The schema of a page input: a bounded limit, the two opaque cursors, at most one of them, and whatever else this listing filters by.
The pair is refused by the schema rather than by the handler, so the refusal is published in the OpenAPI document and answered as a validation error rather than as application logic. What survives it is still two optional fields; pageRequest is what turns a parsed input into the one-direction PageRequest a port takes.
filters is required, and {} is how a listing says it has none — an absent argument and an empty shape would be the same call spelled two ways. limit, after and before are the page's own and cannot be among them: a filter replacing one would silently unbound the limit or re-type a cursor, so the shape refuses it at the call.
Type Parameters
| Type Parameter |
|---|
Filters extends ReservedKeysFree |
Parameters
| Parameter | Type |
|---|---|
filters | Filters |
limits | PageLimits |
Returns
ZodObject<{ [k in string | number | symbol]: ((("limit" | "after" | "before") & keyof Filters) extends never ? { after: ZodOptional<ZodString>; before: ZodOptional<ZodString>; limit: ZodPrefault<ZodNumber> } & { -readonly [P in string | number | symbol]: Filters[P] } : { [K in "limit" | "after" | "before" as K extends keyof Filters ? never : K]: { after: ZodOptional<ZodString>; before: ZodOptional<ZodString>; limit: ZodPrefault<ZodNumber> }[K] } & { [K in string | number | symbol]: { -readonly [P in string | number | symbol]: Filters[P] }[K] })[k] }, $strip>