/** * Getting an image into Substack. * * Substack's upload endpoint takes a data URI under `image`, not a file upload * and not a URL. So whichever way the caller supplies the image, it has to be * read into memory and encoded first. * * Two hazards worth guarding, because this is the one tool that takes an * arbitrary URL from a model and fetches it: * - SSRF. A model can be talked into passing http://169.254.169.254/ or a * localhost address, which would make this server a proxy into a private * network. Private, loopback and link-local destinations are refused, and * redirects are followed manually so the check applies to every hop. * - Size. An unbounded download becomes an unbounded base64 string in memory * and then a rejected request, so it is capped before that happens. */ export declare const MAX_IMAGE_BYTES: number; export declare function detectMimeType(bytes: Buffer): string | null; /** RFC 1918, loopback, link-local and unique-local ranges. */ export declare function isPrivateAddress(address: string): boolean; /** Download an image and return it as a data URI, checking every redirect hop. */ export declare function fetchImageAsDataUri(url: string, userAgent: string, timeoutMs: number): Promise<{ dataUri: string; mimeType: string; bytes: number; }>; /** Read a local file and return it as a data URI. */ export declare function readImageFileAsDataUri(path: string): Promise<{ dataUri: string; mimeType: string; bytes: number; }>;