Files
2026-01-22 15:30:31 +01:00

124 lines
3.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import z from "zod";
/**
* Supported image formats as string literals.
*/
const IMAGE_FORMATS = ["png", "jpeg", "gif", "webp", "bmp"] as const;
/**
* Map of supported image format keys to their MIME types.
*/
const MIME_MAP = {
png: "image/png",
jpeg: "image/jpeg",
gif: "image/gif",
webp: "image/webp",
bmp: "image/bmp",
} as const;
/*
|--------------------------------------------------------------------------------
| Raw Image
|--------------------------------------------------------------------------------
|
| Defines the raw structure of an image as stored in the database.
|
| This schema captures all the immutable attributes of an image (id, folder
| reference, URL, file metadata, etc.) but does not include any derived values
| such as the MIME type.
|
*/
const RawImageSchema = z.strictObject({
_id: z.uuid().describe("Primary identifier of the image"),
folderId: z.uuid().optional().describe("Primary identifier of the folder the image belongs to"),
name: z.string().min(1).describe("Original file name (e.g., cat.png)"),
format: z.enum(IMAGE_FORMATS).describe("Image format"),
size: z.number().positive().max(500).describe("File size in bytes"),
hash: z.string().min(1).describe("Image hash to ensure we don't store the same image multiple times"),
width: z.number().positive().describe("Image width in pixels"),
height: z.number().positive().describe("Image height in pixels"),
url: z.url().describe("Public URL to access the image"),
description: z.string().max(500).optional().describe("Optional description or caption (max 500 chars)"),
tags: z.array(z.string().min(1)).default([]).describe("Array of tags for search / categorization"),
createdAt: z.coerce.date().describe("Timestamp when the image was stored"),
});
/*
|--------------------------------------------------------------------------------
| Image
|--------------------------------------------------------------------------------
|
| A strict representation of an image that includes a derived `mime` field. The
| `ImageSchema` takes `RawImageSchema` and attaches the MIME type based on the
| format. No extra keys are permitted.
|
*/
export const ImageSchema = RawImageSchema.transform((data) => ({
...data,
mime: mimeForFormat(data.format),
}));
export type Image = z.output<typeof ImageSchema>;
/*
|--------------------------------------------------------------------------------
| Database
|--------------------------------------------------------------------------------
|
| Schemas used for interacting with the persistence layer.
|
| `ImageInsertSchema` is used when inserting a new image it omits
| automatically generated fields such as `_id` and `createdAt`. It also
| normalises the `tags` array to contain unique values.
|
*/
/**
* Schema used when inserting a new image.
* It omits _id, and createdAt those are generated by the DB.
*/
export const ImageInsertSchema = z
.strictObject({
...RawImageSchema.omit({ _id: true, createdAt: true }).shape,
})
.transform((data) => ({
...data,
tags: Array.from(new Set(data.tags)),
}));
export type ImageInsert = z.input<typeof ImageInsertSchema>;
/*
|--------------------------------------------------------------------------------
| Utilities
|--------------------------------------------------------------------------------
*/
/**
* Returns the MIME type corresponding to the given image format.
* If the format is unknown, defaults to "application/octet-stream".
*
* @param format - The image format key (e.g., "png").
*
* @returns The MIME type string.
*/
function mimeForFormat<TKey extends keyof MIMEMap>(format: TKey): MIMEMap[TKey] | "application/octet-stream" {
return MIME_MAP[format] ?? "application/octet-stream";
}
/*
|--------------------------------------------------------------------------------
| Types
|--------------------------------------------------------------------------------
*/
type MIMEMap = typeof MIME_MAP;