feat: add initial storage module
This commit is contained in:
121
modules/storage/schemas/image.ts
Normal file
121
modules/storage/schemas/image.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user