import { z } from 'zod'; const checksum = z .string() .regex(/^[a-f0-9]{64}$/, '必须是 SHA-256 十六进制摘要'); export const createMediaUploadIntentRequestSchema = z .object({ purpose: z.literal('watermark_image'), filename: z.string().trim().min(1).max(255), content_type: z.enum(['image/png', 'image/jpeg', 'image/webp']), byte_size: z .number() .int() .min(1) .max(5 * 1024 * 1024), checksum_sha256: checksum, }) .strict(); export const completeMediaUploadIntentRequestSchema = z .object({ checksum_sha256: checksum, }) .strict(); export const createMediaAccessUrlRequestSchema = z .object({ purpose: z.literal('preview'), }) .strict(); export type CreateMediaUploadIntentRequest = z.infer< typeof createMediaUploadIntentRequestSchema >; export type CompleteMediaUploadIntentRequest = z.infer< typeof completeMediaUploadIntentRequestSchema >; // ── 只读响应类型(由前端 AI 按 docs/api/watermarks-and-assets.md §1 补充,后端请复核) ── /** 预签名直传端点:前端必须按返回的 method/url/headers 原样上传 */ export type MediaUploadEndpoint = { method: string; url: string; headers: Record; }; /** POST /api/media/upload-intents 响应 */ export type MediaUploadIntent = { upload_id: string; expires_at: string; upload: MediaUploadEndpoint; }; /** 校验通过后创建/复用的素材 */ export type MediaAsset = { id: string; content_type: string; byte_size: number; width_px: number | null; height_px: number | null; created_at: string; }; /** POST /api/media-assets/{asset_id}/access-urls 响应(短时预览 URL) */ export type MediaAccessUrl = { url: string; expires_at: string; };