Barazo AppView backend
barazo.forum
1import { z } from 'zod/v4'
2import { maturityRatingSchema } from './categories.js'
3import { reactionSetSchema } from './reactions.js'
4
5// ---------------------------------------------------------------------------
6// Request schemas
7// ---------------------------------------------------------------------------
8
9/** Hex color code pattern: # followed by 3, 4, 6, or 8 hex digits. */
10const hexColorPattern = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/
11
12/** Schema for updating community settings (all fields optional). */
13export const updateSettingsSchema = z.object({
14 communityName: z
15 .string()
16 .trim()
17 .min(1, 'Community name is required')
18 .max(100, 'Community name must be at most 100 characters')
19 .optional(),
20 maturityRating: maturityRatingSchema.optional(),
21 reactionSet: reactionSetSchema.optional(),
22 communityDescription: z
23 .string()
24 .trim()
25 .max(500, 'Community description must be at most 500 characters')
26 .nullable()
27 .optional(),
28 communityLogoUrl: z.url('Community logo must be a valid URL').nullable().optional(),
29 faviconUrl: z.url('Favicon must be a valid URL').nullable().optional(),
30 headerLogoUrl: z.url('Header logo must be a valid URL').nullable().optional(),
31 showCommunityName: z.boolean().optional(),
32 primaryColor: z
33 .string()
34 .regex(hexColorPattern, 'Primary color must be a valid hex color (e.g., #ff0000)')
35 .nullable()
36 .optional(),
37 accentColor: z
38 .string()
39 .regex(hexColorPattern, 'Accent color must be a valid hex color (e.g., #00ff00)')
40 .nullable()
41 .optional(),
42 jurisdictionCountry: z
43 .string()
44 .length(2, 'Jurisdiction country must be a 2-letter ISO 3166-1 alpha-2 code')
45 .regex(/^[A-Z]{2}$/, 'Jurisdiction country must be uppercase letters')
46 .nullable()
47 .optional(),
48 ageThreshold: z
49 .number()
50 .int('Age threshold must be an integer')
51 .min(13, 'Age threshold must be at least 13')
52 .max(18, 'Age threshold must be at most 18')
53 .optional(),
54 requireLoginForMature: z.boolean().optional(),
55 maxReplyDepth: z
56 .number()
57 .int('Max reply depth must be an integer')
58 .min(1, 'Max reply depth must be at least 1')
59 .max(9999, 'Max reply depth must be at most 9999')
60 .optional(),
61})
62
63export type UpdateSettingsInput = z.infer<typeof updateSettingsSchema>
64
65// ---------------------------------------------------------------------------
66// Response schemas (for OpenAPI documentation)
67// ---------------------------------------------------------------------------
68
69/** Schema describing community settings in API responses. */
70export const settingsResponseSchema = z.object({
71 id: z.string(),
72 initialized: z.boolean(),
73 communityDid: z.string().nullable(),
74 adminDid: z.string().nullable(),
75 communityName: z.string(),
76 maturityRating: maturityRatingSchema,
77 reactionSet: z.array(z.string()),
78 communityDescription: z.string().nullable(),
79 communityLogoUrl: z.string().nullable(),
80 faviconUrl: z.string().nullable(),
81 headerLogoUrl: z.string().nullable(),
82 showCommunityName: z.boolean(),
83 primaryColor: z.string().nullable(),
84 accentColor: z.string().nullable(),
85 jurisdictionCountry: z.string().nullable(),
86 ageThreshold: z.number(),
87 maxReplyDepth: z.number(),
88 requireLoginForMature: z.boolean(),
89 createdAt: z.string(),
90 updatedAt: z.string(),
91})
92
93export type SettingsResponse = z.infer<typeof settingsResponseSchema>