/** Factory matching ts-validation's `v.string()` / `v.number()` style. */ export declare function file(): FileValidator; /** * `schema.file()` — chainable validator for uploaded files * (stacksjs/stacks#1856). * * Mirrors the ergonomics of `schema.string()` / `schema.number()` / * `schema.enum()` from ts-validation but targets the `UploadedFile` * shape that `req.file('avatar')` / `req.files` return. Conforms to the * `{ rule: { validate(value): { valid, errors? } } }` contract that the * Action layer ({@link `@stacksjs/router`} → `validateActionInput`) * iterates, so file validations slot into the same `validations:` block * as the rest of the field rules: * * @example * ```ts * new Action({ * method: 'POST', * validations: { * avatar: { rule: schema.file().image().maxBytes(2 * 1024 * 1024) }, * }, * async handle(req) { * const file = req.file('avatar')! * const { url } = await Storage.put(file, { disk: 'public', dir: 'avatars' }) * // … * }, * }) * ``` * * The validator is intentionally narrow on the input it accepts: a * structural shape with `size: number` and either `mimetype` or * `mimeType`, optionally with `originalName` / `name`. Both the * router's wrapping `UploadedFile` class and the raw multipart-parse * shape satisfy it. */ /** Shape this validator runs against. */ export declare interface FileLike { size: number mimetype?: string mimeType?: string originalName?: string name?: string } declare interface ValidationError { message: string } declare interface ValidationResult { valid: boolean, errors?: ValidationError[] } /** * Chainable file validator. Each method returns `this` so callers can * stack constraints in any order; rules accumulate into an internal * list and run sequentially on `.validate()`. * * Designed to be cheap to construct — most validators in an Action's * `validations:` block are built once at module load. No I/O happens * here; image dimension / content-sniffing rules belong in a separate * `@stacksjs/storage/image` opt-in (deliverable 5 of #1856). */ export declare class FileValidator { required(): this; image(): this; mimeTypes(allowed: string[]): this; maxBytes(max: number): this; minBytes(min: number): this; extensions(allowed: string[]): this; custom(rule: (file: FileLike) => string | null): this; validate(value: unknown): ValidationResult; }