/* =========================================================================== traffic.mjs - port-only first-touch attribution with a 30-day first-party cookie. Storage refusal keeps this landing's values in memory. Never stores full URLs. =========================================================================== */ const KEYS = [ "utm_source", "utm_medium", "utm_campaign", "ref" ]; const MAX_AGE = 30 * 86400; const COOKIE = "varkand_traffic"; /* ================ sanitizeTraffic ================ */ export function sanitizeTraffic( value ) { const result = {}; for ( const key of KEYS ) { const text = typeof value?.[key] === "string" ? value[key].trim() : ""; if ( /^[A-Za-z0-9_.-]{1,40}$/.test( text ) ) result[key] = text; } return result; } /* ================ captureTraffic ================ */ export function captureTraffic( location, document, now = Date.now() ) { let saved; try { const cookie = document.cookie.split( ";" ).map( value => value.trim() ).find( value => value.startsWith( COOKIE + "=" ) ); if ( cookie ) saved = JSON.parse( decodeURIComponent( cookie.slice( COOKIE.length + 1 ) ) ); } catch {} if ( saved && Number.isFinite( saved.expires ) && saved.expires > now && saved.expires <= now + MAX_AGE * 1000 ) { return sanitizeTraffic( saved.values ); } const params = new URLSearchParams( location.search ); const values = sanitizeTraffic( Object.fromEntries( params ) ); if ( !values.utm_source && !values.ref ) values.utm_source = "direct"; try { document.cookie = COOKIE + "=" + encodeURIComponent( JSON.stringify( { expires: now + MAX_AGE * 1000, values } ) ) + "; Max-Age=" + MAX_AGE + "; Path=/; SameSite=Lax; Secure"; } catch {} return values; } /* ================ appendTraffic ================ */ export function appendTraffic( href, base, values ) { const url = new URL( href, base ); if ( url.hostname !== "play.varkand.com" && !(url.origin === new URL( base ).origin && /^\/play(?:\/|$)/.test( url.pathname )) ) return href; if ( url.hostname !== "play.varkand.com" ) { url.hostname = "play.varkand.com"; url.protocol = "https:"; url.port = ""; url.pathname = url.pathname.replace( /^\/play/, "" ) || "/"; } for ( const [key, value] of Object.entries( sanitizeTraffic( values ) ) ) url.searchParams.set( key, value ); return url.href; } /* ================ landingTraffic ================ */ export const landingTraffic = typeof document === "undefined" ? {} : captureTraffic( globalThis.location, document ); if ( typeof document !== "undefined" ) { for ( const link of document.querySelectorAll( "a[href]" ) ) { if ( link instanceof HTMLAnchorElement ) { link.href = appendTraffic( link.href, globalThis.location.href, landingTraffic ); } } }