This commit is contained in:
crisjonblvx 2026-04-21 01:27:21 +00:00 committed by GitHub
commit a3026d56c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 2 deletions

View file

@ -31,4 +31,10 @@ POSTMARK_ACTIVATION_TEMPLATE=
# -----------------------------------------------------------------------------
STRIPE_API_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_PRO_MONTHLY_PLAN_ID=
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=

View file

@ -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 })

40
lib/enrichr.ts Normal file
View file

@ -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<string | null> {
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;
}
}