diff --git a/src/modules/creator/creator-profile.schemas.ts b/src/modules/creator/creator-profile.schemas.ts index 69f7aec..d7d4e7e 100644 --- a/src/modules/creator/creator-profile.schemas.ts +++ b/src/modules/creator/creator-profile.schemas.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { withCreatorSlugEmptyStringNormalization } from './creator-slug-input.utils'; /** * Shared creator profile identifier schema for route params. @@ -7,11 +8,13 @@ import { z } from 'zod'; * and keep this centralized for future route extensions. */ export const CreatorProfileParamsSchema = z.object({ - creatorId: z - .string() - .trim() - .min(1, 'Creator ID is required') - .max(128, 'Creator ID is too long'), + creatorId: withCreatorSlugEmptyStringNormalization( + z + .string() + .trim() + .min(1, 'Creator ID is required') + .max(128, 'Creator ID is too long') + ), }); /** @@ -50,7 +53,11 @@ export const UpsertCreatorProfileBodySchema = z.object({ .trim() .max(1000, 'Bio must be at most 1000 characters') .optional(), - avatarUrl: z.string().trim().url('Avatar URL must be a valid URL').optional(), + avatarUrl: z + .string() + .trim() + .url('Avatar URL must be a valid URL') + .optional(), links: z .array( z.object({ diff --git a/src/modules/creator/creator-slug-input.utils.ts b/src/modules/creator/creator-slug-input.utils.ts new file mode 100644 index 0000000..6ae949b --- /dev/null +++ b/src/modules/creator/creator-slug-input.utils.ts @@ -0,0 +1,36 @@ +import { z, ZodTypeAny } from 'zod'; + +/** + * Normalizes creator slug route input before validation. + * + * Scope is intentionally narrow: + * - exact empty-string input becomes `undefined` + * - `null` / `undefined` become `undefined` + * - all other values pass through unchanged + * + * This lets creator route schemas treat empty-string slug params the same way + * as omitted params without introducing broader slug rewriting behavior. + */ +export function normalizeCreatorSlugEmptyString(value: unknown): unknown { + if (value === null || value === undefined) { + return undefined; + } + + if (value === '') { + return undefined; + } + + return value; +} + +/** + * Wraps a Zod schema with {@link normalizeCreatorSlugEmptyString} preprocessing. + * + * Use for creator route params that may receive slug-shaped input from HTTP + * layers before the actual route schema runs. + */ +export function withCreatorSlugEmptyStringNormalization( + schema: T +) { + return z.preprocess(normalizeCreatorSlugEmptyString, schema); +}