diff --git a/.env.example b/.env.example index 865977b..3c0d218 100644 --- a/.env.example +++ b/.env.example @@ -31,4 +31,10 @@ POSTMARK_ACTIVATION_TEMPLATE= # ----------------------------------------------------------------------------- STRIPE_API_KEY= STRIPE_WEBHOOK_SECRET= -STRIPE_PRO_MONTHLY_PLAN_ID= \ No newline at end of file +STRIPE_PRO_MONTHLY_PLAN_ID= + +# ----------------------------------------------------------------------------- +# Enrichr (optional — slug generation from post titles) +# Get a free key at https://enrichrapi.dev (1,000 calls/month free) +# ----------------------------------------------------------------------------- +ENRICHR_API_KEY= \ No newline at end of file diff --git a/app/api/posts/route.ts b/app/api/posts/route.ts index 7c4c8bb..92271b2 100644 --- a/app/api/posts/route.ts +++ b/app/api/posts/route.ts @@ -3,6 +3,7 @@ import * as z from "zod" import { authOptions } from "@/lib/auth" import { db } from "@/lib/db" +import { generateSlug } from "@/lib/enrichr" import { RequiresProPlanError } from "@/lib/exceptions" import { getUserSubscriptionPlan } from "@/lib/subscription" @@ -77,7 +78,11 @@ export async function POST(req: Request) { }, }) - return new Response(JSON.stringify(post)) + // Generate a URL-safe slug from the title (Unicode-aware, handles accents/emoji). + // Requires ENRICHR_API_KEY in .env — skipped silently if not set. + const slug = await generateSlug(body.title) + + return new Response(JSON.stringify({ ...post, slug })) } catch (error) { if (error instanceof z.ZodError) { return new Response(JSON.stringify(error.issues), { status: 422 }) diff --git a/lib/enrichr.ts b/lib/enrichr.ts new file mode 100644 index 0000000..ab770ac --- /dev/null +++ b/lib/enrichr.ts @@ -0,0 +1,40 @@ +/** + * Enrichr — utility API wrapper + * Generates URL-safe slugs, validates emails, and more. + * + * Setup: add ENRICHR_API_KEY to your .env + * Get a free key at https://enrichrapi.dev (1,000 calls/month free) + */ + +const BASE = process.env.ENRICHR_BASE_URL ?? 'https://enrichrapi.dev'; + +/** + * Generate a URL-safe slug from any string. + * Handles Unicode, accents, and special characters (e.g. "Café & More" → "cafe-more"). + * Returns null if ENRICHR_API_KEY is not set (graceful degradation). + * + * @example + * const slug = await generateSlug('My First Post — Café Style!'); + * // → "my-first-post-cafe-style" + */ +export async function generateSlug( + text: string, + separator = '-' +): Promise { + const key = process.env.ENRICHR_API_KEY; + if (!key) return null; + + try { + const res = await fetch(`${BASE}/v1/generate/slug`, { + method: 'POST', + headers: { 'X-Api-Key': key, 'Content-Type': 'application/json' }, + body: JSON.stringify({ text, separator }), + cache: 'no-store', + }); + if (!res.ok) return null; + const json = await res.json(); + return (json.data as { slug: string; length: number }).slug; + } catch { + return null; + } +}