import { isCidString, isEncodingString, isTidString } from "@atproto/lex" import { z } from "astro/zod" import { IMAGE_ENCODINGS, MAX_IMAGE_BYTES } from "../config" interface ImageFileOptions { encodings: readonly string[] maxBytes: number emptyMessage: string sizeMessage: string typeMessage: string } function imageFileSchema(options: ImageFileOptions) { return z.instanceof(File).transform((file, context) => { if (!file.size) { context.addIssue({ code: "custom", message: options.emptyMessage }) return z.NEVER } if (file.size > options.maxBytes) { context.addIssue({ code: "custom", message: options.sizeMessage }) return z.NEVER } const encoding = file.type if (!isEncodingString(encoding) || !options.encodings.includes(encoding)) { context.addIssue({ code: "custom", message: options.typeMessage }) return z.NEVER } return { file, encoding } }) } export const imageFile = imageFileSchema({ encodings: IMAGE_ENCODINGS, maxBytes: MAX_IMAGE_BYTES, emptyMessage: "Choose an image to upload", sizeMessage: "Images must be 50 MB or smaller", typeMessage: "Images must be JPEG, PNG, WebP, GIF, AVIF, or HEIC", }) export const imageUpload = z.object({ image: imageFile, alt: z .string() .trim() .max(2000) .nullish() .transform((alt) => alt ?? ""), }) export const ImageQualitySchema = z.enum(["placeholder", "low", "medium", "high", "original"]) export const imageCid = z.string().refine(isCidString, "Invalid image CID") export const imageGetParams = z.object({ cid: imageCid, quality: ImageQualitySchema.optional() }) export const imageDeletion = z.object({ rkey: z.string().refine(isTidString, "Invalid image record key"), recordCid: imageCid, })