h1k.sh/l1TGF0 [ home ] [ history ] [ rev 1 ] [ rev 2 ] --- rev 1 2026-05-04 14:23 UTC +++ rev 2 2026-05-04 14:24 UTC @@ -1,3 +1,40 @@ -#lang:python +#lang:ts +const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; +const SLUG_LEN = 6; -print("hello world") +export function randomSlug(): string { + const bytes = new Uint8Array(SLUG_LEN); + crypto.getRandomValues(bytes); + let out = ''; + for (let i = 0; i < SLUG_LEN; i++) { + out += ALPHABET[bytes[i]! % 62]; + } + return out; +} + +export function isValidSlug(s: string): boolean { + if (s.length < 1 || s.length > 32) return false; + return /^[a-zA-Z0-9][a-zA-Z0-9-]*$|^[a-zA-Z0-9]$/.test(s); +} + +export function normalizeSlug(s: string): string { + return s.trim().toLowerCase(); +} + +const RESERVED = new Set([ + 'new', 'published', 'api', 'admin', 'e', 'feed', 'raw', + 'stats', 'canary', 'health', 'robots', 'sitemap', 'install', + 'random', 'search', 'help', 'about', 'legal', 'privacy', + 'terms', 'contact', 'login', 'logout', 'register', 'account', + 'settings', 'dashboard', 'profile', 'upload', 'download', +]); + +export function isValidCustomSlug(s: string): boolean { + if (s.length < 1 || s.length > 32) return false; + if (s.startsWith('-') || s.endsWith('-')) return false; + if (s.includes('--')) return false; + if (!(/^[a-z0-9-]+$/.test(s))) return false; + if (RESERVED.has(s)) return false; + return true; +} +