```js // NOTE: zod (v4) has no built-in string-to-slug transform — there is no `z.slug()` // and no `.toSlug()`/`.slugify()` string method. Zod's string layer offers only // validation plus `.trim()`, `.toLowerCase()`, `.toUpperCase()` and `.normalize()`. // So "exactly what zod's own slug transform produces" cannot be honoured as written. // The slug is defined explicitly here instead, in ONE place, and both the API and the // web client must import this module so the two sides cannot drift. import { z } from "zod"; /** * Deterministic slug: NFKD-normalise, drop combining marks (é -> e), lowercase, * collapse every run of non-alphanumerics (punctuation, spaces, emoji) to a single * "-", and trim leading/trailing separators. */ const slugify = (input) => input .normalize("NFKD") .replace(/\p{M}+/gu, "") .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, ""); export const Slug = z.string().transform(slugify); export const Article = z.object({ title: z.string().min(3), slug: Slug, }); ``` TOOLS_USED: none