@thejob/schema 2.0.4 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,68 @@
1
+ import { array, boolean, number, object, string } from "yup";
2
+ import type { InferType } from "yup";
3
+ import { DbDefaultSchema } from "../common/common.schema.js";
4
+ import { PostStatus, SupportedPostStatuses } from "./post.constant.js";
5
+
6
+ export const PostSchema = object({
7
+ /** Headline shown in listings and at the top of the post. */
8
+ title: string().required().min(5).max(200).label("Title"),
9
+
10
+ /** User-friendly, unique URL identifier. */
11
+ slug: string().required().max(250).label("Slug"),
12
+
13
+ /** Short summary used in listings and meta description fallback. */
14
+ excerpt: string().max(500).optional().label("Excerpt"),
15
+
16
+ /** Rendered HTML source of truth for the post body (sanitized on write/render).
17
+ * Supports rich formatting markdown can't express (image size/alignment, etc). */
18
+ bodyHTML: string().required().min(1).label("Body (HTML)"),
19
+
20
+ /** Optional Markdown mirror of the body (portable text / search fallback).
21
+ * Kept for back-compat and plain-text derivation; bodyHTML is authoritative. */
22
+ bodyMarkdown: string().optional().label("Body (Markdown)"),
23
+
24
+ /** Cover/hero image URL. Not `.url()`-validated: the value is either an
25
+ * uploaded file URL served by this platform (which may be a bare host like
26
+ * `http://localhost:3082/...` in dev, that yup's `.url()` wrongly rejects) or
27
+ * an admin-pasted link. Kept as a plain string; empty ⇒ null. */
28
+ coverImage: string().nullable().optional().label("Cover image"),
29
+
30
+ /** Author (user id). */
31
+ authorId: string().required().label("Author ID"),
32
+
33
+ /** Free-form tags for filtering and related-posts. */
34
+ tags: array().of(string().trim().required()).default([]).label("Tags"),
35
+
36
+ /** Estimated reading time in minutes (server-derived from body length). */
37
+ readingTimeMinutes: number()
38
+ .min(0)
39
+ .optional()
40
+ .label("Reading time (minutes)"),
41
+
42
+ /** SEO overrides. */
43
+ seoTags: object({
44
+ description: string().optional().label("Description"),
45
+ keywords: array().of(string().required()).optional().label("Keywords"),
46
+ })
47
+ .nullable()
48
+ .optional()
49
+ .label("SEO Tags"),
50
+
51
+ /** When the post was first published (epoch ms). Server-owned. */
52
+ publishedAt: number().nullable().optional().label("Published at"),
53
+
54
+ /** Whether the post is featured in the blog listing. */
55
+ isFeatured: boolean().default(false).optional().label("Is featured"),
56
+
57
+ /** Publication state. */
58
+ status: string()
59
+ .oneOf(SupportedPostStatuses)
60
+ .default(PostStatus.Draft)
61
+ .required()
62
+ .label("Status"),
63
+ })
64
+ .concat(DbDefaultSchema)
65
+ .noUnknown()
66
+ .label("Post");
67
+
68
+ export type TPostSchema = InferType<typeof PostSchema>;