/** * Query parameters that only exist to record where a link travelled. They * are dropped so the copy button hands back something clean and the cache * does not store one post under a dozen keys. */ const TRACKING_PARAMS = new Set([ 'igsh', 'igshid', 'img_index', 'fbclid', 'gclid', 'mibextid', 'ref_src', 'ref_url', 'ref', 'source', 'checksum', 'social_sharing', 's', 't', 'si', 'xmt', '_r', '_t', '_d', 'is_from_webapp', 'sender_device', 'sender_web_id', 'web_id', 'share_app_id', 'share_link_id', 'share_item_id', 'tt_from', ]); export function stripTracking(url: URL): URL { const cleaned = new URL(url.href); for (const key of [...cleaned.searchParams.keys()]) { if (TRACKING_PARAMS.has(key) || key.startsWith('utm_')) { cleaned.searchParams.delete(key); } } cleaned.hash = ''; return cleaned; } /** Exact-host or subdomain match, e.g. `tiktok.com` and `vm.tiktok.com`. */ export function hostMatcher(...domains: string[]): (host: string) => boolean { return (host) => domains.some((d) => host === d || host.endsWith(`.${d}`)); }