export function slugify(input: string): string { return input .trim() .toLowerCase() .replace(/['"]/g, "") .replace(/[^a-z0-9]+/g, "-") .replace(/^-+|-+$/g, ""); } export async function generateUniqueSlug(opts: { base: string; isTaken: (slug: string) => Promise; maxAttempts?: number; }): Promise { const maxAttempts = opts.maxAttempts ?? 50; const normalizedBase = slugify(opts.base) || "item"; let candidate = normalizedBase; for (let i = 0; i < maxAttempts; i++) { // First try the base, then base-2, base-3, ... candidate = i === 0 ? normalizedBase : `${normalizedBase}-${i + 1}`; // eslint-disable-next-line no-await-in-loop const taken = await opts.isTaken(candidate); if (!taken) return candidate; } // Last resort: append timestamp to avoid collisions return `${normalizedBase}-${Date.now()}`; }