@aglyn/shared-util-first-touch 1.0.0-beta.186
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +66 -0
- package/package.json +34 -0
- package/src/index.d.ts +20 -0
- package/src/index.js +21 -0
- package/src/index.js.map +1 -0
- package/src/lib/channel-rules.d.ts +96 -0
- package/src/lib/channel-rules.js +169 -0
- package/src/lib/channel-rules.js.map +1 -0
- package/src/lib/first-touch-page.d.ts +43 -0
- package/src/lib/first-touch-page.js +52 -0
- package/src/lib/first-touch-page.js.map +1 -0
- package/src/lib/first-touch-script.d.ts +39 -0
- package/src/lib/first-touch-script.js +52 -0
- package/src/lib/first-touch-script.js.map +1 -0
- package/src/lib/first-touch.d.ts +212 -0
- package/src/lib/first-touch.js +677 -0
- package/src/lib/first-touch.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/shared/util/first-touch/src/lib/first-touch.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * First-touch capture: where a visitor first arrived from, kept on their\n * device until an account is created and the platform writes it down.\n *\n * ## The one rule everything else follows from\n *\n * A visitor rarely signs up on the page they landed on, and the page they\n * landed on is not always the marketing site. They find a guide on the docs\n * host through a search engine, read the pricing page, then sign up on the\n * console. Three hosts, and only the first one saw where they came from.\n *\n * So every surface the platform serves includes this capture, and every one\n * of them agrees on which referrers are its own. **An internal referrer is\n * never a first touch.** Only an external referrer, or a landing with no\n * referrer at all, starts the record; a hop between two of our own hosts\n * carries the record forward and never replaces it. \"docs → pricing →\n * signup\" therefore still reports the search engine that started it.\n *\n * ## Where the record lives\n *\n * - **A cookie on the registrable domain** of the surface (`.example.com`),\n * found by asking the browser rather than by carrying a public-suffix list:\n * the broadest domain that accepts a cookie is the registrable one. Every\n * subdomain, and so every console door under it, reads the same value.\n * - **`sessionStorage`**, when the browser refuses the cookie. It dies with\n * the tab and does not cross subdomains, which is the price of a browser\n * that refuses storage.\n * - **Memory**, while the visitor's consent is unresolved or has been refused\n * for this surface. Nothing is written to the device. A link to another of\n * our hosts can still carry the record, sealed, in its URL (below).\n *\n * The cookie is re-written on every load with a fresh lifetime, because some\n * browsers cap the life of a script-written cookie at a week of inactivity;\n * the VALUE never changes once set.\n *\n * ## Crossing to a host the cookie cannot reach\n *\n * A surface on a different registrable domain, or any hop made while the\n * record is held in memory, cannot read the cookie. For those links the\n * capture asks the platform to SEAL the record (an HMAC over it and an\n * expiry, signed with a secret no page holds) and appends the sealed token as\n * `_ft` at the moment the link is followed. The receiving surface strips the\n * parameter from its address bar at once, asks the platform to OPEN it, and\n * adopts what comes back. Adoption is a merge, and the merge keeps the\n * earlier record, so replaying a token can never move a first touch later.\n *\n * What the seal proves is narrow and worth stating exactly: that this install\n * produced the record, recently, and nobody edited it on the way. It does not\n * prove the record is TRUE — a visitor can put any `utm_*` they like on a URL\n * and always could. Attribution is a label, and it grants nothing.\n *\n * ## What is never recorded\n *\n * No identifier. The record says how a visit began, and two visitors who\n * arrived the same way carry the same record give or take a timestamp. Click\n * ids are kept as PRESENCE only — \"this arrived from a paid click\" — and their\n * values never leave the URL they came on. Referrers are kept as a HOST, never\n * a path, because a referring path can carry a search query or an account\n * page. `utm_*` values are trimmed, refused when shaped like an email\n * address, and capped, the same scrub the signup campaign parser applies.\n *\n * ## Why the whole runtime is one function\n *\n * The same code must run as a module a Next app imports and as a script tag\n * on a page no bundler touches (a hosted forum, a status page). So the\n * runtime is ONE self-contained function, {@link createFirstTouchKit}, that\n * references nothing outside itself: the served script is that function's own\n * source text followed by a call to it. The constraint that keeps it working\n * is the same one `next-themes` lives under — no imports, no module-level\n * values, and no syntax a compiler would lower into a shared helper (object\n * spread, classes, `async`). `first-touch-script.spec.ts` runs the\n * stringified function in a bare context to hold that.\n */\n\n/** Click identifiers whose PRESENCE the record keeps; their values never leave the URL. */\nexport const FIRST_TOUCH_CLICK_IDS = ['gclid', 'fbclid', 'msclkid'] as const\nexport type FirstTouchClickId = (typeof FIRST_TOUCH_CLICK_IDS)[number]\n\n/** The `utm_*` parameters the record keeps, named without their prefix. */\nexport const FIRST_TOUCH_UTM_KEYS = [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n] as const\nexport type FirstTouchUtmKey = (typeof FIRST_TOUCH_UTM_KEYS)[number]\nexport type FirstTouchUtm = Partial<Record<FirstTouchUtmKey, string>>\n\n/** The cookie the record is kept in, on the surface's registrable domain. */\nexport const FIRST_TOUCH_COOKIE = 'aglyn_ft'\n/** The query parameter a sealed hand-off rides on. */\nexport const FIRST_TOUCH_HANDOFF_PARAM = '_ft'\n\n/** How a visit began, as the capture records it. */\nexport interface FirstTouch {\n /** Record format. A reader refuses any other value rather than guess. */\n v: 1\n /** When the visitor landed, epoch milliseconds. */\n at: number\n /** The host of the first page they landed on. */\n host: string\n /** That page's path, without its query string or fragment. */\n path: string\n /** The EXTERNAL host that sent them, or null when nothing external did. */\n ref: string | null\n /**\n * One of our own hosts they arrived from before any surface had recorded\n * them — the tell of a surface that does not include the capture yet.\n */\n via?: string\n /** The `utm_*` parameters the landing URL carried. */\n utm?: FirstTouchUtm\n /** Which click identifiers the landing URL carried. */\n click?: FirstTouchClickId[]\n}\n\n/** What {@link FirstTouchKit.buildFirstTouch} reads a landing from. */\nexport interface FirstTouchLanding {\n /** The URL the visitor landed on. */\n href: string\n /** `document.referrer` at that moment; empty when there was none. */\n referrer?: string | null\n /** The hosts this install serves itself — see {@link FirstTouchConfig.hosts}. */\n hosts: readonly string[]\n /** The time to stamp, epoch milliseconds. */\n now: number\n}\n\n/** How a surface configures the capture. */\nexport interface FirstTouchConfig {\n /**\n * The hosts this install serves itself. An entry is an exact host\n * (`example.com`) or a wildcard for every subdomain of one at any depth\n * (`*.example.com`, which does not match `example.com` itself). A leading\n * `!` EXCLUDES what the rest of the entry names, whatever else matches it:\n * `!*.sites.example.com` keeps customer sites served under the operator's\n * own domain external. A referrer on an included host is internal, and the\n * capture runs only on a page whose host is included.\n */\n hosts: readonly string[]\n /**\n * Whether this surface may keep the record on the device. `null` means the\n * visitor's consent is not resolved yet: the record is held in memory and\n * written the moment {@link FirstTouchRuntime.setStorage} grants it.\n * Omitted means true, the posture of a surface with no consent gate.\n */\n storage?: boolean | null\n /**\n * The platform endpoint that seals and opens hand-off tokens: absolute, or\n * a path on the current origin. Without it no link is decorated and no\n * token is adopted, and the cookie alone carries the record.\n */\n handoffUrl?: string | null\n}\n\n/** Where the record currently lives on this page. */\nexport type FirstTouchTier = 'cookie' | 'session' | 'memory'\n\n/** The handle a booted capture returns. */\nexport interface FirstTouchRuntime {\n /** The first touch as this page knows it, or null. */\n read(): FirstTouch | null\n /** Grant, refuse or un-resolve device storage for this surface. */\n setStorage(allowed: boolean | null): void\n /** Where the record lives right now, or null when there is none. */\n tier(): FirstTouchTier | null\n}\n\n/** Everything the capture does, as one closure — see the file comment for why. */\nexport interface FirstTouchKit {\n /** A bare lowercase host, or '' when the value is not one. */\n normalizeHost(value: unknown): string\n /** Whether `host` is one of `hosts` — see {@link FirstTouchConfig.hosts}. */\n isFirstPartyHost(host: unknown, hosts: readonly string[]): boolean\n /** The touch a landing describes, or null when the URL is not a web page. */\n buildFirstTouch(landing: FirstTouchLanding): FirstTouch | null\n /**\n * Rebuild a record from an untrusted value, keeping only known fields, each\n * re-scrubbed; null when it is not a record. `now`, when given, refuses a\n * record stamped more than a day into the future.\n */\n sanitizeFirstTouch(value: unknown, now?: number): FirstTouch | null\n /** The first of two records: the earlier `at` wins, and a tie keeps `a`. */\n mergeFirstTouch(\n a: FirstTouch | null | undefined,\n b: FirstTouch | null | undefined,\n ): FirstTouch | null\n /** The cookie-safe text form of a record. */\n encodeFirstTouch(touch: FirstTouch): string\n /** A record from its cookie text, sanitized; null for anything else. */\n decodeFirstTouch(value: unknown): FirstTouch | null\n /** The record a `Cookie` header carries, for a server that receives one. */\n readFirstTouchCookie(cookieHeader: string | null | undefined): FirstTouch | null\n /** Start capturing on this page. Idempotent; a second call updates the config. */\n boot(config: FirstTouchConfig): FirstTouchRuntime\n /** The booted runtime's record, or whatever the device holds when none booted. */\n read(): FirstTouch | null\n}\n\n/**\n * Build the capture. Self-contained by construction: nothing in the body may\n * reference a value declared outside it (types are erased and do not count).\n */\nexport function createFirstTouchKit(): FirstTouchKit {\n const CLICK_IDS = ['gclid', 'fbclid', 'msclkid']\n const UTM_KEYS = ['source', 'medium', 'campaign', 'content', 'term']\n const COOKIE = 'aglyn_ft'\n const PROBE = 'aglyn_ft_probe'\n const SESSION_KEY = 'aglyn:first-touch'\n const GLOBAL_KEY = '__aglynFirstTouch'\n const PARAM = '_ft'\n // A visit worth attributing can take months between the first read and the\n // signup; the value is refreshed on every visit, so this bounds inactivity.\n const MAX_AGE_SECONDS = 180 * 24 * 60 * 60\n const MAX_VALUE = 100\n const MAX_PATH = 200\n const MAX_HOST = 253\n const MAX_TOKEN = 4096\n const FUTURE_SKEW_MS = 24 * 60 * 60 * 1000\n const TOKEN_MARGIN_MS = 60 * 1000\n const EMAIL_SHAPED = /[^\\s@]+@[^\\s@]+\\.[^\\s@]+/\n const HOST_SHAPE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/\n // Control characters are exactly what this pattern exists to find: a\n // `utm_*` value is refused its line breaks, NULs and escapes, not its text.\n // eslint-disable-next-line no-control-regex\n const CONTROL = /[\\u0000-\\u001f\\u007f]/g\n\n const state = {\n booted: false,\n hosts: [] as string[],\n storage: true as boolean | null,\n handoffUrl: '' as string,\n touch: null as FirstTouch | null,\n tier: null as FirstTouchTier | null,\n domain: undefined as string | undefined,\n token: null as { value: string; exp: number } | null,\n sealing: false,\n }\n\n function normalizeHost(value: unknown): string {\n if (typeof value !== 'string') return ''\n let host = value.trim().toLowerCase()\n if (host.charAt(host.length - 1) === '.') host = host.slice(0, -1)\n if (!host || host.length > MAX_HOST || !HOST_SHAPE.test(host)) return ''\n return host\n }\n\n function normalizePattern(value: unknown): string {\n if (typeof value !== 'string') return ''\n let raw = value.trim().toLowerCase()\n const negated = raw.charAt(0) === '!'\n if (negated) raw = raw.slice(1).trim()\n const base = raw.indexOf('*.') === 0 ? normalizeHost(raw.slice(2)) : ''\n const pattern = base ? '*.' + base : raw.indexOf('*.') === 0 ? '' : normalizeHost(raw)\n return pattern && negated ? '!' + pattern : pattern\n }\n\n function patternMatches(host: string, pattern: string): boolean {\n if (pattern.indexOf('*.') !== 0) return host === pattern\n const suffix = pattern.slice(1)\n return host.length > suffix.length && host.slice(-suffix.length) === suffix\n }\n\n function normalizeHostList(hosts: unknown): string[] {\n const out: string[] = []\n if (!hosts || typeof (hosts as unknown[]).length !== 'number') return out\n const list = hosts as unknown[]\n for (let i = 0; i < list.length; i++) {\n const pattern = normalizePattern(list[i])\n if (pattern && out.indexOf(pattern) < 0) out.push(pattern)\n }\n return out\n }\n\n function isFirstPartyHost(host: unknown, hosts: readonly string[]): boolean {\n const bare = normalizeHost(host)\n if (!bare) return false\n const patterns = normalizeHostList(hosts)\n let included = false\n for (let i = 0; i < patterns.length; i++) {\n const pattern = patterns[i]\n if (pattern.charAt(0) === '!') {\n if (patternMatches(bare, pattern.slice(1))) return false\n } else if (!included && patternMatches(bare, pattern)) {\n included = true\n }\n }\n return included\n }\n\n function scrub(value: unknown): string {\n if (typeof value !== 'string') return ''\n const clean = value.replace(CONTROL, '').trim()\n if (!clean || EMAIL_SHAPED.test(clean)) return ''\n return clean.slice(0, MAX_VALUE)\n }\n\n function scrubPath(value: unknown): string {\n if (typeof value !== 'string') return '/'\n let clean = value.replace(CONTROL, '')\n const cut = clean.search(/[?#]/)\n if (cut >= 0) clean = clean.slice(0, cut)\n if (clean.charAt(0) !== '/') clean = '/' + clean\n return clean.slice(0, MAX_PATH)\n }\n\n function parseUrl(value: unknown, base?: string): URL | null {\n if (typeof value !== 'string' || !value) return null\n try {\n const url = base ? new URL(value, base) : new URL(value)\n return url.protocol === 'http:' || url.protocol === 'https:' ? url : null\n } catch {\n return null\n }\n }\n\n function readUtm(params: URLSearchParams): FirstTouchUtm | null {\n const utm: FirstTouchUtm = {}\n let found = false\n for (let i = 0; i < UTM_KEYS.length; i++) {\n const value = scrub(params.get('utm_' + UTM_KEYS[i]))\n if (value) {\n utm[UTM_KEYS[i] as FirstTouchUtmKey] = value\n found = true\n }\n }\n return found ? utm : null\n }\n\n function readClickIds(params: URLSearchParams): FirstTouchClickId[] {\n const present: FirstTouchClickId[] = []\n for (let i = 0; i < CLICK_IDS.length; i++) {\n const value = params.get(CLICK_IDS[i])\n if (value && value.trim()) present.push(CLICK_IDS[i] as FirstTouchClickId)\n }\n return present\n }\n\n function buildFirstTouch(landing: FirstTouchLanding): FirstTouch | null {\n if (!landing) return null\n const url = parseUrl(landing.href)\n const host = url ? normalizeHost(url.hostname) : ''\n if (!url || !host) return null\n const at = typeof landing.now === 'number' && landing.now > 0 ? landing.now : 0\n if (!at) return null\n const touch: FirstTouch = { v: 1, at: at, host: host, path: scrubPath(url.pathname), ref: null }\n const referrer = parseUrl(landing.referrer)\n const refHost = referrer ? normalizeHost(referrer.hostname) : ''\n if (refHost && refHost !== host) {\n if (isFirstPartyHost(refHost, landing.hosts)) touch.via = refHost\n else touch.ref = refHost\n }\n const utm = readUtm(url.searchParams)\n if (utm) touch.utm = utm\n const click = readClickIds(url.searchParams)\n if (click.length) touch.click = click\n return touch\n }\n\n function sanitizeFirstTouch(value: unknown, now?: number): FirstTouch | null {\n if (!value || typeof value !== 'object') return null\n const raw = value as Record<string, unknown>\n if (raw['v'] !== 1) return null\n const at = raw['at']\n if (typeof at !== 'number' || !isFinite(at) || at <= 0) return null\n if (typeof now === 'number' && at > now + FUTURE_SKEW_MS) return null\n const host = normalizeHost(raw['host'])\n if (!host) return null\n const touch: FirstTouch = {\n v: 1,\n at: Math.floor(at),\n host: host,\n path: scrubPath(raw['path']),\n ref: normalizeHost(raw['ref']) || null,\n }\n const via = normalizeHost(raw['via'])\n if (via) touch.via = via\n const rawUtm = raw['utm']\n if (rawUtm && typeof rawUtm === 'object') {\n const utm: FirstTouchUtm = {}\n let found = false\n for (let i = 0; i < UTM_KEYS.length; i++) {\n const utmValue = scrub((rawUtm as Record<string, unknown>)[UTM_KEYS[i]])\n if (utmValue) {\n utm[UTM_KEYS[i] as FirstTouchUtmKey] = utmValue\n found = true\n }\n }\n if (found) touch.utm = utm\n }\n const rawClick = raw['click']\n if (rawClick && typeof (rawClick as unknown[]).length === 'number') {\n const click: FirstTouchClickId[] = []\n for (let j = 0; j < CLICK_IDS.length; j++) {\n if ((rawClick as unknown[]).indexOf(CLICK_IDS[j]) >= 0) {\n click.push(CLICK_IDS[j] as FirstTouchClickId)\n }\n }\n if (click.length) touch.click = click\n }\n return touch\n }\n\n function mergeFirstTouch(\n a: FirstTouch | null | undefined,\n b: FirstTouch | null | undefined,\n ): FirstTouch | null {\n if (!a) return b || null\n if (!b) return a\n return b.at < a.at ? b : a\n }\n\n function encodeFirstTouch(touch: FirstTouch): string {\n return encodeURIComponent(JSON.stringify(touch))\n }\n\n function decodeFirstTouch(value: unknown): FirstTouch | null {\n if (typeof value !== 'string' || !value) return null\n try {\n return sanitizeFirstTouch(JSON.parse(decodeURIComponent(value)))\n } catch {\n return null\n }\n }\n\n function cookieValue(header: string | null | undefined, name: string): string {\n if (typeof header !== 'string' || !header) return ''\n const parts = header.split(';')\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i].trim()\n if (part.indexOf(name + '=') === 0) return part.slice(name.length + 1)\n }\n return ''\n }\n\n function readFirstTouchCookie(cookieHeader: string | null | undefined): FirstTouch | null {\n return decodeFirstTouch(cookieValue(cookieHeader, COOKIE))\n }\n\n // Never `typeof window`, or `typeof` of any host global. This kit reaches\n // the browser as the text of a function compiled into a SERVER bundle, and a\n // server compile may settle those checks in advance: Next's replaces\n // `typeof window` with \"undefined\", after which the minifier drops every DOM\n // path as dead code. Reading the global is something no compiler can decide:\n // it throws where the global is missing and is an object where it is not.\n function hasDom(): boolean {\n try {\n return Boolean(document && location)\n } catch {\n return false\n }\n }\n\n function hasFetch(): boolean {\n try {\n return Boolean(fetch)\n } catch {\n return false\n }\n }\n\n function secureSuffix(): string {\n return location.protocol === 'https:' ? '; Secure' : ''\n }\n\n function cookieDomain(): string {\n if (state.domain !== undefined) return state.domain\n const host = location.hostname\n let found = ''\n if (host && host.indexOf('.') > 0 && !/^[\\d.]+$/.test(host)) {\n const labels = host.split('.')\n for (let i = labels.length - 2; i >= 0 && !found; i--) {\n const candidate = labels.slice(i).join('.')\n try {\n document.cookie =\n PROBE + '=1; Path=/; Domain=' + candidate + '; SameSite=Lax' + secureSuffix()\n if (cookieValue(document.cookie, PROBE) === '1') {\n found = candidate\n document.cookie =\n PROBE + '=; Path=/; Domain=' + candidate + '; Max-Age=0' + secureSuffix()\n }\n } catch {\n break\n }\n }\n }\n state.domain = found\n return found\n }\n\n function writeCookie(touch: FirstTouch): boolean {\n try {\n const domain = cookieDomain()\n const encoded = encodeFirstTouch(touch)\n document.cookie =\n COOKIE +\n '=' +\n encoded +\n '; Path=/' +\n (domain ? '; Domain=' + domain : '') +\n '; Max-Age=' +\n MAX_AGE_SECONDS +\n '; SameSite=Lax' +\n secureSuffix()\n return cookieValue(document.cookie, COOKIE) === encoded\n } catch {\n return false\n }\n }\n\n function sessionStore(): Storage | null {\n try {\n return window.sessionStorage || null\n } catch {\n return null\n }\n }\n\n function writeSession(touch: FirstTouch): boolean {\n const store = sessionStore()\n if (!store) return false\n try {\n store.setItem(SESSION_KEY, JSON.stringify(touch))\n return true\n } catch {\n return false\n }\n }\n\n function readSession(): FirstTouch | null {\n const store = sessionStore()\n if (!store) return null\n try {\n const raw = store.getItem(SESSION_KEY)\n return raw ? sanitizeFirstTouch(JSON.parse(raw)) : null\n } catch {\n return null\n }\n }\n\n function eraseStored(): void {\n try {\n const domain = cookieDomain()\n document.cookie = COOKIE + '=; Path=/; Max-Age=0' + secureSuffix()\n if (domain) {\n document.cookie =\n COOKIE + '=; Path=/; Domain=' + domain + '; Max-Age=0' + secureSuffix()\n }\n } catch {\n // A cookie the browser will not let us touch is one it did not keep.\n }\n const store = sessionStore()\n if (store) {\n try {\n store.removeItem(SESSION_KEY)\n } catch {\n // Same: an unreadable store holds nothing to erase.\n }\n }\n }\n\n function exposed(): FirstTouch | null {\n try {\n return sanitizeFirstTouch((window as unknown as Record<string, unknown>)[GLOBAL_KEY])\n } catch {\n return null\n }\n }\n\n function expose(touch: FirstTouch | null): void {\n try {\n ;(window as unknown as Record<string, unknown>)[GLOBAL_KEY] = touch\n } catch {\n // A frozen window costs a second reader on this page, never the capture.\n }\n }\n\n function readCookie(): FirstTouch | null {\n try {\n return decodeFirstTouch(cookieValue(document.cookie, COOKIE))\n } catch {\n return null\n }\n }\n\n function loadStored(): FirstTouch | null {\n return mergeFirstTouch(mergeFirstTouch(readCookie(), readSession()), exposed())\n }\n\n function save(): void {\n const touch = state.touch\n expose(touch)\n if (!touch) {\n state.tier = null\n return\n }\n if (state.storage !== true) state.tier = 'memory'\n else if (writeCookie(touch)) state.tier = 'cookie'\n else if (writeSession(touch)) state.tier = 'session'\n else state.tier = 'memory'\n }\n\n function adopt(touch: FirstTouch | null): void {\n const next = mergeFirstTouch(state.touch, touch)\n if (next !== state.touch) {\n state.touch = next\n state.token = null\n }\n save()\n }\n\n function takeHandoffToken(): string {\n try {\n const params = new URLSearchParams(location.search)\n const token = params.get(PARAM) || ''\n if (!token) return ''\n params.delete(PARAM)\n const search = params.toString()\n history.replaceState(\n history.state,\n '',\n location.pathname + (search ? '?' + search : '') + location.hash,\n )\n return token.length <= MAX_TOKEN ? token : ''\n } catch {\n return ''\n }\n }\n\n function post(body: unknown): Promise<Record<string, unknown> | null> {\n if (!state.handoffUrl || !hasFetch()) return Promise.resolve(null)\n return fetch(state.handoffUrl, {\n method: 'POST',\n body: JSON.stringify(body),\n headers: { 'content-type': 'text/plain;charset=UTF-8' },\n credentials: 'omit',\n keepalive: true,\n })\n .then(function (response): Promise<Record<string, unknown>> | null {\n return response.ok ? response.json() : null\n })\n .catch(function (): null {\n return null\n })\n }\n\n function tokenIsFresh(): boolean {\n return Boolean(state.token && Date.now() < state.token.exp - TOKEN_MARGIN_MS)\n }\n\n function requestToken(): void {\n if (!state.touch || state.sealing || tokenIsFresh()) return\n state.sealing = true\n const sealed = state.touch\n post({ seal: sealed }).then(function (result) {\n state.sealing = false\n if (\n result &&\n typeof result['token'] === 'string' &&\n typeof result['exp'] === 'number' &&\n state.touch === sealed\n ) {\n state.token = { value: result['token'] as string, exp: result['exp'] as number }\n }\n })\n }\n\n function underCookieDomain(host: string): boolean {\n const domain = state.domain\n if (!domain) return false\n return host === domain || host.slice(-(domain.length + 1)) === '.' + domain\n }\n\n function handoffTarget(node: unknown): { anchor: Element; url: URL } | null {\n const element = node as Element | null\n if (!element || typeof element.closest !== 'function') return null\n const anchor = element.closest('a[href]')\n if (!anchor) return null\n const url = parseUrl(anchor.getAttribute('href') || '', location.href)\n if (!url) return null\n const host = normalizeHost(url.hostname)\n if (!host || host === normalizeHost(location.hostname)) return null\n if (!isFirstPartyHost(host, state.hosts)) return null\n if (state.tier === 'cookie' && underCookieDomain(host)) return null\n return { anchor: anchor, url: url }\n }\n\n function installDecoration(): void {\n const onIntent = function (event: Event): void {\n try {\n if (handoffTarget(event.target)) requestToken()\n } catch {\n // Attribution never costs a navigation.\n }\n }\n const onActivate = function (event: Event): void {\n try {\n const target = handoffTarget(event.target)\n if (!target) return\n if (!tokenIsFresh()) {\n requestToken()\n return\n }\n target.url.searchParams.set(PARAM, (state.token as { value: string }).value)\n target.anchor.setAttribute('href', target.url.toString())\n } catch {\n // Same: a link that throws here would be a link that does not work.\n }\n }\n document.addEventListener('pointerover', onIntent, true)\n document.addEventListener('focusin', onIntent, true)\n document.addEventListener('pointerdown', onActivate, true)\n document.addEventListener('click', onActivate, true)\n const links = document.links\n for (let i = 0; i < links.length; i++) {\n if (handoffTarget(links[i])) {\n requestToken()\n break\n }\n }\n }\n\n function configure(config: FirstTouchConfig): void {\n const input = config || ({} as FirstTouchConfig)\n state.hosts = normalizeHostList(input.hosts)\n state.storage =\n input.storage === false ? false : input.storage === null ? null : true\n const url = typeof input.handoffUrl === 'string' ? input.handoffUrl.trim() : ''\n state.handoffUrl =\n url.charAt(0) === '/' && url.charAt(1) !== '/' ? url : parseUrl(url) ? url : ''\n }\n\n const runtime: FirstTouchRuntime = {\n read: function () {\n return state.touch\n },\n setStorage: function (allowed) {\n const next = allowed === true ? true : allowed === false ? false : null\n const granted = next === true && state.storage !== true\n state.storage = next\n if (!hasDom()) return\n if (next === false) {\n eraseStored()\n state.tier = state.touch ? 'memory' : null\n return\n }\n if (granted) {\n state.touch = mergeFirstTouch(loadStored(), state.touch)\n save()\n }\n },\n tier: function () {\n return state.tier\n },\n }\n\n function boot(config: FirstTouchConfig): FirstTouchRuntime {\n const hadHandoff = Boolean(state.handoffUrl)\n configure(config)\n if (!hasDom()) return runtime\n if (state.booted) {\n if (!hadHandoff && state.handoffUrl) installDecoration()\n return runtime\n }\n // Only a host the install names as its own captures. A copy of the tag\n // pasted onto anybody else's page records nothing and decorates nothing.\n if (!isFirstPartyHost(location.hostname, state.hosts)) return runtime\n state.booted = true\n const token = takeHandoffToken()\n const current = buildFirstTouch({\n href: location.href,\n referrer: document.referrer,\n hosts: state.hosts,\n now: Date.now(),\n })\n state.touch = mergeFirstTouch(loadStored(), current)\n save()\n if (token && state.handoffUrl) {\n post({ open: token }).then(function (result) {\n adopt(sanitizeFirstTouch(result && result['touch'], Date.now()))\n })\n }\n if (state.handoffUrl) installDecoration()\n return runtime\n }\n\n function read(): FirstTouch | null {\n if (state.touch) return state.touch\n return hasDom() ? loadStored() : null\n }\n\n return {\n normalizeHost: normalizeHost,\n isFirstPartyHost: isFirstPartyHost,\n buildFirstTouch: buildFirstTouch,\n sanitizeFirstTouch: sanitizeFirstTouch,\n mergeFirstTouch: mergeFirstTouch,\n encodeFirstTouch: encodeFirstTouch,\n decodeFirstTouch: decodeFirstTouch,\n readFirstTouchCookie: readFirstTouchCookie,\n boot: boot,\n read: read,\n }\n}\n\n/**\n * The page's one capture. A bundle that imports this module shares it, so a\n * surface that boots it and a form that reads it see the same record.\n */\nconst kit = createFirstTouchKit()\n\nexport const normalizeFirstTouchHost = kit.normalizeHost\nexport const isFirstPartyHost = kit.isFirstPartyHost\nexport const buildFirstTouch = kit.buildFirstTouch\nexport const sanitizeFirstTouch = kit.sanitizeFirstTouch\nexport const mergeFirstTouch = kit.mergeFirstTouch\nexport const encodeFirstTouch = kit.encodeFirstTouch\nexport const decodeFirstTouch = kit.decodeFirstTouch\nexport const readFirstTouchCookie = kit.readFirstTouchCookie\nexport const bootFirstTouch = kit.boot\nexport const readFirstTouch = kit.read\n"],"names":["FIRST_TOUCH_CLICK_IDS","FIRST_TOUCH_UTM_KEYS","FIRST_TOUCH_COOKIE","FIRST_TOUCH_HANDOFF_PARAM","createFirstTouchKit","CLICK_IDS","UTM_KEYS","COOKIE","PROBE","SESSION_KEY","GLOBAL_KEY","PARAM","MAX_AGE_SECONDS","MAX_VALUE","MAX_PATH","MAX_HOST","MAX_TOKEN","FUTURE_SKEW_MS","TOKEN_MARGIN_MS","EMAIL_SHAPED","HOST_SHAPE","CONTROL","state","booted","hosts","storage","handoffUrl","touch","tier","domain","undefined","token","sealing","normalizeHost","value","host","trim","toLowerCase","charAt","length","slice","test","normalizePattern","raw","negated","base","indexOf","pattern","patternMatches","suffix","normalizeHostList","out","list","i","push","isFirstPartyHost","bare","patterns","included","scrub","clean","replace","scrubPath","cut","search","parseUrl","url","URL","protocol","readUtm","params","utm","found","get","readClickIds","present","buildFirstTouch","landing","href","hostname","at","now","v","path","pathname","ref","referrer","refHost","via","searchParams","click","sanitizeFirstTouch","isFinite","Math","floor","rawUtm","utmValue","rawClick","j","mergeFirstTouch","a","b","encodeFirstTouch","encodeURIComponent","JSON","stringify","decodeFirstTouch","parse","decodeURIComponent","cookieValue","header","name","parts","split","part","readFirstTouchCookie","cookieHeader","hasDom","Boolean","document","location","hasFetch","fetch","secureSuffix","cookieDomain","labels","candidate","join","cookie","writeCookie","encoded","sessionStore","window","sessionStorage","writeSession","store","setItem","readSession","getItem","eraseStored","removeItem","exposed","expose","readCookie","loadStored","save","adopt","next","takeHandoffToken","URLSearchParams","delete","toString","history","replaceState","hash","post","body","Promise","resolve","method","headers","credentials","keepalive","then","response","ok","json","catch","tokenIsFresh","Date","exp","requestToken","sealed","seal","result","underCookieDomain","handoffTarget","node","element","closest","anchor","getAttribute","installDecoration","onIntent","event","target","onActivate","set","setAttribute","addEventListener","links","configure","config","input","runtime","read","setStorage","allowed","granted","boot","hadHandoff","current","open","kit","normalizeFirstTouchHost","bootFirstTouch","readFirstTouch"],"mappings":"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"}
|