import type { AssetInput, ImageAssetResolver, ImageAssetResolverContext } from '../types/images.js'; import { type SafeFetchPolicy } from '../utils/safe-fetch.js'; import type { AssetStore } from './asset-support.js'; import { ImageValidationError } from './errors.js'; /** Why the input resolver refused an input. */ export type ImageInputRejection = 'too-large' | 'too-many-pixels' | 'unmeasurable' | 'mime-mismatch' | 'unsupported-type' | 'fetch-failed' | 'blocked-url' | 'not-found'; /** * An input the resolver refused. * * Carries a machine-readable `reason` so an application can tell a user "that file is too large" * rather than surfacing a generic validation failure. */ export declare class ImageInputError extends ImageValidationError { /** Why it was refused. */ readonly reason: ImageInputRejection; /** The request option that carried the input, such as `input` or `mask`. */ readonly option: string; /** Always `IMAGE_INPUT_REJECTED`. */ readonly code = "IMAGE_INPUT_REJECTED"; constructor(message: string, /** Why it was refused. */ reason: ImageInputRejection, /** The request option that carried the input, such as `input` or `mask`. */ option: string, cause?: unknown); } /** Limits on image inputs, and how remote and stored inputs are fetched. */ export interface ImageInputPolicy extends SafeFetchPolicy { /** Largest input accepted, in bytes. Defaults to 20 MB. */ maxBytes?: number; /** * Largest input accepted, in pixels. Defaults to 40 megapixels. * * Checked from the header before anything is decoded, which is what defeats a decompression bomb: * a few kilobytes that claim a 100,000 × 100,000 canvas are refused without allocating a byte. */ maxPixels?: number; /** Defaults to PNG, JPEG, WebP, and GIF. */ allowedMimeTypes?: readonly string[]; /** * Accept a format whose dimensions cannot be read from its header. Defaults to false, because an * unmeasurable image is exactly one whose pixel ceiling cannot be enforced. */ allowUnmeasurableDimensions?: boolean; /** Defaults to 3. Each hop is validated against the SSRF policy again. */ maxRedirects?: number; /** Defaults to 15 seconds. */ timeoutMs?: number; /** Resolves `stored` locations. */ store?: AssetStore; /** Tenant stored assets are read for, when the call supplies none. */ tenantId?: string; } /** * Turns any asset location into validated bytes. * * Every path ends in the same checks, so a byte upload, a remote URL, and a stored asset are held to * one standard: the content must be the type it claims, fit the byte ceiling, and fit the pixel * ceiling. A declared `image/png` that sniffs as something else is refused rather than trusted, * since a mismatched MIME type is how a hostile payload reaches a decoder that did not expect it. */ export declare class ImageInputResolver implements ImageAssetResolver { private readonly policy; private readonly maxBytes; private readonly maxPixels; private readonly allowed; constructor(policy?: ImageInputPolicy); /** * Resolves an input to bytes, enforcing every limit. Throws `ImageInputError` for a refused * input. */ resolve(asset: AssetInput, context: ImageAssetResolverContext): Promise; private fetchRemote; private validate; } /** Builds a resolver, for passing straight into `ImageConfig.inputResolver`. */ export declare function createImageInputResolver(policy?: ImageInputPolicy): ImageInputResolver;