import { createHash } from 'crypto'; /** * URL-friendly slug from any source string. * Deterministic so the same title always maps to the same URL segment. */ export function slugify(input: string): string { const slug = input .toLowerCase() .normalize('NFKD') .replace(/[\u0300-\u036f]/g, '') // strip diacritics .replace(/^https?:\/\//, '') .replace(/[^\w\s-]/g, '') .trim() .replace(/\s+/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, '') .slice(0, 90) .replace(/-$/g, ''); return slug || 'article'; } /** * Stable dedup key for a story title: case-fold, strip punctuation, collapse * whitespace. Two feeds covering the same story usually share enough title * text to collide here; we add URL-host as a tiebreaker in the pipeline. */ export function dedupeKeyOf(title: string, host: string): string { const normalized = title .toLowerCase() .normalize('NFKD') .replace(/[\u0300-\u036f]/g, '') .replace(/[^a-z0-9\s]/g, ' ') .replace(/\s+/g, ' ') .trim(); return createHash('sha1').update(`${normalized}::${host}`).digest('hex').slice(0, 32); } export function sha1(input: string): string { return createHash('sha1').update(input).digest('hex'); }