@hanzo/event 0.3.31 → 0.3.33

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/attribution.ts","../src/dsn.ts","../src/scrub.ts","../src/anon.js","../src/uid.ts","../src/version.ts","../src/sentry.ts","../src/exception.ts","../src/storage.ts","../src/core.ts","../src/goals.ts"],"names":["truncate","normalizeError"],"mappings":"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","file":"index.mjs","sourcesContent":["// Pure attribution helpers: parse first-touch UTM/referrer/refCode from a URL,\n// derive the acquisition channel, and compute the ISO week for the signup cohort.\n// No I/O, no globals — trivially testable.\n\nimport type { Attribution } from './types'\n\nconst SOCIAL_HOSTS = [\n 'facebook.', 'instagram.', 'twitter.', 'x.com', 't.co', 'linkedin.',\n 'reddit.', 'youtube.', 'tiktok.', 'pinterest.', 'news.ycombinator.com',\n]\nconst SEARCH_HOSTS = ['google.', 'bing.', 'duckduckgo.', 'yahoo.', 'baidu.', 'ecosia.']\n\n/** parseAttribution reads UTM params + ref/refCode from a query string and pairs\n * them with the referrer. `search` is a location.search value (\"?utm_source=…\"). */\nexport function parseAttribution(search: string, referrer: string): Attribution {\n const q = new URLSearchParams(search || '')\n const get = (k: string) => {\n const v = q.get(k)\n return v ? v.trim() : undefined\n }\n const a: Attribution = {\n utm: {\n source: get('utm_source'),\n medium: get('utm_medium'),\n campaign: get('utm_campaign'),\n term: get('utm_term'),\n content: get('utm_content'),\n },\n referrer: referrer ? referrer.trim() : undefined,\n refCode: get('ref') || get('refCode') || get('ref_code') || undefined,\n }\n a.channel = deriveChannel(a)\n return a\n}\n\n/** deriveChannel classifies the visit: paid | referral | social | organic | direct. */\nexport function deriveChannel(a: Attribution): string {\n const medium = (a.utm.medium || '').toLowerCase()\n if (/(cpc|ppc|paid|paidsearch|display|cpm)/.test(medium)) return 'paid'\n if (a.utm.source || a.utm.campaign) return 'campaign'\n if (a.refCode) return 'referral'\n const host = hostOf(a.referrer)\n if (!host) return 'direct'\n if (SOCIAL_HOSTS.some((h) => host.includes(h))) return 'social'\n if (SEARCH_HOSTS.some((h) => host.includes(h))) return 'organic'\n return 'referral'\n}\n\n/** hostOf extracts a bare lowercase host from a URL; \"\" when unparseable. */\nexport function hostOf(raw?: string): string {\n if (!raw) return ''\n let s = raw.trim()\n const scheme = s.indexOf('://')\n if (scheme >= 0) s = s.slice(scheme + 3)\n const cut = s.search(/[/?#]/)\n if (cut >= 0) s = s.slice(0, cut)\n const at = s.indexOf('@')\n if (at >= 0) s = s.slice(at + 1)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s.toLowerCase().trim()\n}\n\n/** hasAttribution reports whether anything was captured (so we don't persist an\n * empty first-touch that would shadow a later real one). */\nexport function hasAttribution(a: Attribution): boolean {\n return Boolean(\n a.utm.source || a.utm.medium || a.utm.campaign || a.utm.term ||\n a.utm.content || a.refCode || (a.referrer && hostOf(a.referrer)),\n )\n}\n\n/** isoWeek returns the ISO-8601 week label, e.g. \"2026-W28\". */\nexport function isoWeek(d: Date): string {\n // Copy to UTC midnight; ISO week: Thursday-anchored.\n const date = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()))\n const day = date.getUTCDay() || 7\n date.setUTCDate(date.getUTCDate() + 4 - day)\n const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1))\n const week = Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7)\n return `${date.getUTCFullYear()}-W${String(week).padStart(2, '0')}`\n}\n","/**\n * The product → Sentinel DSN registry.\n *\n * An app declares WHAT it is (`product: 'console'`); this module knows WHERE its\n * errors go. That split is the whole point: no surface has to learn a DSN, carry\n * a build argument, or grow a config file to report errors — declaring the\n * product it already declares is enough.\n *\n * A Sentinel DSN is PUBLIC by construction. It ships inside the client bundle and\n * is readable in devtools on any deployed page, and it grants exactly one\n * capability: submitting new events. It cannot read issues, projects, or any\n * other data. So committing it is not leaking a secret — it is recording a public\n * identifier next to the code that needs it. (Contrast the server-side collector\n * DSN in the `team-analytics-sentry` Secret, which is HMAC-derived and revocable\n * precisely because a server-side credential is NOT public.)\n *\n * Why a literal map instead of deriving `hanzo-${product}`: the projects predate\n * this registry and do not derive cleanly — `site` lives in `hanzo-ai`, not\n * `hanzo-site`. An explicit map is honest about that; a derivation rule plus an\n * exception table is the same data with a trap in it.\n *\n * Projects are org-scoped and named `<org>-<app>`. To add one: create the project\n * (POST /v1/sentinel/projects with X-Org-Id), then add its `dsn` here keyed by the\n * product name the app passes to `createAnalytics`.\n */\n\n/** PRODUCT_PROJECT maps a `product` to its Sentinel project id. The DSN's KEY is no\n * longer a per-project secret — it is the ONE org publishable key (below), so a\n * surface's errors ride the SAME key its events do. The id only names WHICH\n * project the errors group under, and cloud auto-provisions that project on first\n * keyed ingest, so a new id needs nothing minted. `site` lives in the `hanzo-ai`\n * project — an explicit map, because the projects predate this and do not derive\n * cleanly from the product name. */\nexport const PRODUCT_PROJECT: Readonly<Record<string, string>> = Object.freeze({\n console: '019fa40b-94ae-7f1d-8f7b-e92f123fad42', // console.hanzo.ai\n app: '019f9b1e-57eb-7171-9d92-72c0b85e4b4b', // hanzo.app\n site: '019f9b1e-5785-7359-ad0b-f75db8e58c99', // hanzo.ai (marketing; product `site`)\n})\n\n/** dsnForProduct builds the product's Sentinel DSN from the caller's resolved\n * publishable `key` and the product's project — the SAME key the event stream\n * carries, at the product's envelope endpoint. Returns undefined when there is no\n * key or no project for the product, leaving the error plane inert rather than\n * posting into the wrong one. The key is NOT baked here: it is the value the\n * surface resolved (an explicit `ingestKey`, or the KMS-sourced\n * NEXT_PUBLIC_PUBLISHABLE_KEY the build inlines) — the ONE live source, never a\n * literal committed beside the code. */\nexport function dsnForProduct(\n product: string | undefined,\n key: string | undefined\n): string | undefined {\n if (!product || !key) return undefined\n const projectId = PRODUCT_PROJECT[product]\n if (!projectId) return undefined\n return `https://${key}@api.hanzo.ai/v1/event/${projectId}`\n}\n","// Client-side redaction for error text — a faithful port of the server's\n// errortracking scrub (o11y pkg/modules/errortracking/implerrortracking/scrub.go),\n// applied BEFORE anything leaves the browser. Two layers, default-secure:\n//\n// - Secret shapes are ALWAYS redacted (sk-… keys, bearer/JWT tokens, DB DSNs,\n// PANs, cloud keys). There is no mode that ships a secret off-device.\n// - PII (email/IP) is scrubbed UNLESS capturePII is explicitly enabled.\n//\n// The server scrubs again — this is defense in depth, not a substitute — but the\n// point is that a Hanzo browser never emits a raw secret/email/IP in the first\n// place. Pure, no I/O.\n\nconst REDACTED = '[redacted]'\nconst EMAIL_MARK = '[email]'\nconst IP_MARK = '[ip]'\n\n// Secret patterns mirror scrub.go's secretPatterns. Order matters (broad DSN/PAN\n// rules run last). All are applied unconditionally.\nconst SECRET_PATTERNS: RegExp[] = [\n /-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,\n /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}/g, // JWT\n /\\bbearer\\s+[A-Za-z0-9._~+/-]{12,}=*/gi, // bearer token\n /\\b(?:sk|pk|rk)-[A-Za-z0-9]{2,}-?[A-Za-z0-9]{12,}/g, // openai-style\n /\\b(?:sk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, // stripe\n /\\bhk-[A-Za-z0-9]{16,}/g, // hanzo key\n /\\bAKIA[0-9A-Z]{16}\\b/g, // aws access key id\n /\\bASIA[0-9A-Z]{16}\\b/g, // aws sts key id\n /\\bAIza[0-9A-Za-z_-]{20,}/g, // google api key\n /\\bgh[posru]_[A-Za-z0-9]{20,}/g, // github token\n /\\bxox[baprs]-[A-Za-z0-9-]{10,}/g, // slack token\n // Creds in a URL/DSN. The repetition is BOUNDED on purpose: the unbounded form\n // ([^\\s:@/]+:[^\\s@/]+@) backtracks quadratically on colon-rich text with no\n // terminating '@' — an HTML error page pasted into an error message took 4.9s\n // at 32KB and >60s at 128KB, freezing the main thread from inside captureError.\n // Real userinfo is far below these caps, so bounding costs nothing.\n /[a-zA-Z][a-zA-Z0-9+.-]{0,32}:\\/\\/[^\\s:@/]{1,256}:[^\\s@/]{1,256}@/g,\n]\n\n/** Candidate card numbers. Gated by Luhn below — the bare digit-run pattern is a\n * false-positive cannon that redacts every millisecond epoch, order id and\n * phone number it sees (\"request 1753468800000 timed out\" became\n * \"request [redacted]timed out\"), which destroys the readability of the very\n * error messages this client exists to deliver. */\nconst RE_PAN = /\\b(?:\\d[ -]?){13,19}\\b/g\n\n/** luhn reports whether a digit string satisfies the Luhn checksum. Every real\n * card number does, so gating redaction on it removes the false positives\n * WITHOUT introducing a false negative — the safe direction for a redactor. */\nfunction luhn(digits: string): boolean {\n let sum = 0\n let alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) {\n d *= 2\n if (d > 9) d -= 9\n }\n sum += d\n alt = !alt\n }\n return sum % 10 === 0\n}\n\n/** redactPAN removes digit runs that actually check out as card numbers. */\nfunction redactPAN(s: string): string {\n return s.replace(RE_PAN, (m) => {\n const digits = m.replace(/[ -]/g, '')\n if (digits.length < 13 || digits.length > 19) return m\n return luhn(digits) ? REDACTED : m\n })\n}\n\n// Bounded to the RFC 5321 maxima (local-part 64, domain 255) for the same reason\n// as the creds-in-URL rule: the unbounded form backtracks quadratically across a\n// long run of local-part-legal characters that never reaches an '@' — measured at\n// 20ms on an 8KB worst case, on the main thread, per captured error. No real\n// address is excluded by these caps.\nconst RE_EMAIL = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\\.[A-Za-z]{2,24}/g\nconst RE_IPV4 = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g\nconst RE_IPV6 = /\\b(?:[0-9A-Fa-f]{1,4}:){2,7}[0-9A-Fa-f]{1,4}\\b/g\n\n// A CREDENTIAL IN A QUERY PARAM HAS NO SHAPE TO MATCH.\n//\n// Every pattern above recognises a secret by what it LOOKS like — a JWT's three\n// dots, `sk-`, `AKIA`, `ghp_`. An OAuth `code`, a `state`, a password-reset\n// nonce and an invite token are opaque random strings, indistinguishable from a\n// page id, so none of them match and all of them survive.\n//\n// That matters because the client stamps `url: window.location.href` on EVERY\n// event, not just pageviews. So one visit to `/callback?code=…&state=…` puts a\n// live authorization code on the wire, once per event, in cleartext — and the\n// code is exchangeable until it is redeemed.\n//\n// The fix is to redact by the NAME the value is filed under rather than by the\n// value's shape, which is the only signal available for an opaque token. The\n// name half is bounded (`{1,32}`) and the value half stops at the first\n// separator, so neither half can backtrack across a long string — the same\n// discipline the creds-in-URL pattern above documents.\nconst CREDENTIAL_PARAMS = [\n 'code', 'state', 'token', 'access_token', 'id_token', 'refresh_token',\n 'auth', 'authorization', 'secret', 'client_secret', 'password', 'passwd', 'pwd',\n 'api_key', 'apikey', 'key', 'session', 'session_id', 'sid',\n 'sig', 'signature', 'nonce', 'otp', 'invite', 'invitation',\n 'reset_token', 'confirmation_token', 'magic', 'ticket', 'assertion',\n]\nconst RE_CREDENTIAL_PARAM = new RegExp(\n '([?&#;](?:' + CREDENTIAL_PARAMS.join('|') + ')=)[^&#;\\\\s]{1,4096}',\n 'gi',\n)\n\n/** redactCredentialParams removes the VALUE of any query parameter whose NAME\n * says it carries a credential, leaving the name so the URL still reads. */\nexport function redactCredentialParams(s: string): string {\n return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix: string) => prefix + REDACTED)\n}\n\n/** redactSecrets removes known secret shapes. Always applied. */\nexport function redactSecrets(s: string): string {\n s = redactCredentialParams(s)\n for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED)\n return redactPAN(s)\n}\n\n/** scrubPII masks emails and IPs. Applied unless PII capture is enabled. */\nexport function scrubPII(s: string): string {\n s = s.replace(RE_EMAIL, EMAIL_MARK)\n s = s.replace(RE_IPV6, IP_MARK)\n s = s.replace(RE_IPV4, IP_MARK)\n return s\n}\n\n/** Longest free-text field this module will scrub. Every pattern here is a regex\n * run synchronously on the main thread, and the input is attacker-influenced —\n * `throw new Error(await res.text())` against an HTML error page is a one-line\n * way to hand us 128KB. Bounding the INPUT bounds the work regardless of which\n * pattern is pathological. 8KB is far beyond any real error message. */\nexport const MAX_SCRUB_LEN = 8192\n\n/** truncate caps a string at MAX_SCRUB_LEN, marking that it was cut so a reader\n * never mistakes a truncated message for the whole one. */\nexport function truncate(s: string, max = MAX_SCRUB_LEN): string {\n return s.length > max ? s.slice(0, max) + '… [truncated]' : s\n}\n\n/** scrubText applies the redaction policy to a free-text field. Input is capped\n * first: unbounded text is a denial-of-service surface, not just a size problem. */\nexport function scrubText(s: string | undefined, capturePII = false): string {\n if (!s) return s ?? ''\n s = truncate(s)\n s = redactSecrets(s)\n if (!capturePII) s = scrubPII(s)\n return s\n}\n","/*! anon.js — THE anonymous-identity chain. ONE implementation, three distributions.\n *\n * One browser is ONE person on every Hanzo surface, whichever client a page\n * happens to have loaded. There were three implementations writing TWO keys —\n * `hz_anon_id` (the npm client, the hosted tag) and `hz_id` (hz.js) — so the same\n * visitor was several people depending on which snippet the surface shipped.\n *\n * The three call sites:\n * 1. src/storage.ts — the bundled npm client; IMPORTS this file.\n * 2. hz.js — the no-build script tag; INLINES the marked region.\n * 3. hanzoai/cloud apps/analytics/tag.js — the tag the door hosts at\n * /v1/event.js; vendors this file and its tag.go serves the marked region\n * with the tag as one asset, so the door holds no second copy either.\n *\n * (2) and (3) have no bundler and cannot import anything, which is why the chain\n * lives in a file that is plain ES5 rather than in a .ts: the region between the\n * BEGIN and END markers is COPIED VERBATIM, and src/anon.test.ts fails if hz.js's\n * copy is so much as a byte different. Keep the region ES5, dependency-free,\n * `hz`-prefixed (it is spliced into other people's scopes) and unformatted — a\n * reformat of one copy is a diff against the other.\n */\n\n/* ── BEGIN hz anon chain — copied VERBATIM into hz.js and hanzoai/cloud ────── */\n\n/** The ONE anonymous-id key, on every surface and in every distribution. */\nvar HZ_ANON_KEY = 'hz_anon_id'\n\n/** hz.js used to write `hz_id` — a SECOND identity space, so the one-paste tag\n * and the npm client were two different people on one page. It is READ and never\n * written: an id already in the wild is ADOPTED into the shared identity, because\n * minting over one detaches a returning visitor from their own history. */\nvar HZ_ANON_LEGACY_KEY = 'hz_id'\n\n/** The registrable domain the cookie is scoped to, so docs, cloud, console,\n * studio, pay, id and www all read the ONE id. localStorage cannot do this: it is\n * ORIGIN-scoped, which is what made one journey arrive as several strangers. */\nvar HZ_ANON_DOMAIN = 'hanzo.ai'\n\n/** Two years, rewritten on every read, so the cookie rolls forward with the\n * visitor instead of expiring two years after first touch. Safari caps a\n * SCRIPT-written cookie at 7 days no matter what this says, so the rewrite is\n * what keeps a returning Safari visitor: each read re-arms the 7-day window. */\nvar HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60\n\n/** Last resort for a browser that refuses cookies AND localStorage: without it\n * every event in a page load would mint an id of its own. */\nvar hzAnonMemo\n\n/**\n * hzUuidv7 mints a time-ordered UUIDv7 (RFC 9562 §5.7) for `now` in epoch ms.\n *\n * It has to be v7, and this is the only minter any distribution may use. The\n * session rollups on the event plane derive a session's start instant FROM THE ID\n * and admit only ids whose version nibble is 7, so a crypto.randomUUID() (v4) id\n * is not merely unordered there — it is DISCARDED, silently, and the rollup stays\n * empty. Without crypto only the ENTROPY degrades; the shape is always a valid v7.\n */\nfunction hzUuidv7(now) {\n var b = new Uint8Array(16)\n var i\n var c = typeof crypto !== 'undefined' ? crypto : undefined\n if (c && typeof c.getRandomValues === 'function') c.getRandomValues(b)\n else for (i = 0; i < 16; i++) b[i] = (Math.random() * 256) | 0\n var t = Math.floor(now === undefined ? Date.now() : now)\n for (i = 5; i >= 0; i--) {\n b[i] = t % 256\n t = Math.floor(t / 256)\n }\n b[6] = 0x70 | (b[6] & 0x0f) // version 7\n b[8] = 0x80 | (b[8] & 0x3f) // variant 0b10\n var h = ''\n for (i = 0; i < 16; i++) {\n h += (b[i] + 0x100).toString(16).slice(1)\n if (i === 3 || i === 5 || i === 7 || i === 9) h += '-'\n }\n return h\n}\n\n/** The cookie jar, or null wherever there is no document to read one from. */\nfunction hzAnonJar() {\n try {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null\n return document\n } catch (e) {\n return null // sandboxed frame with an opaque origin\n }\n}\n\n/** localStorage, or null when the browser refuses it (Safari private mode). */\nfunction hzAnonStore() {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null\n return window.localStorage\n } catch (e) {\n return null\n }\n}\n\n/** One stored value, or '' — a jar can read as well as refuse to. */\nfunction hzAnonItem(store, name) {\n try {\n return (store && store.getItem(name)) || ''\n } catch (e) {\n return ''\n }\n}\n\n/** The value of cookie `name`, or ''. */\nfunction hzAnonCookie(name) {\n var d = hzAnonJar()\n if (!d) return ''\n var parts = d.cookie.split(';')\n for (var i = 0; i < parts.length; i++) {\n var eq = parts[i].indexOf('=')\n if (eq < 0 || parts[i].slice(0, eq).trim() !== name) continue\n var v = parts[i].slice(eq + 1).trim()\n if (!v) continue\n try {\n return decodeURIComponent(v)\n } catch (e) {\n return v // not percent-encoded — take it as written\n }\n }\n return ''\n}\n\n/** Writes `name` on the registrable domain, for as long as the browser allows. */\nfunction hzAnonWrite(name, value) {\n var d = hzAnonJar()\n if (!d) return\n var host = ''\n var secure = false\n try {\n if (typeof window !== 'undefined' && window.location) {\n host = window.location.hostname || ''\n // A Secure cookie is refused outright by a non-secure origin, which would\n // strand http://localhost dev on the localStorage path.\n secure = window.location.protocol === 'https:'\n }\n } catch (e) {\n /* location unreachable — write a host-only, non-secure cookie */\n }\n // encodeURIComponent leaves a UUID byte-identical while making any value that is\n // not one unable to forge a `;` and inject an attribute.\n var c = name + '=' + encodeURIComponent(value)\n c += '; Path=/; Max-Age=' + HZ_ANON_MAX_AGE + '; SameSite=Lax'\n // Off hanzo.ai (localhost, previews, other registrable domains) the attribute\n // would be rejected and the whole cookie dropped, so it stays host-only there.\n // Prefixing both sides with '.' matches the domain itself and its subdomains\n // while refusing a suffix that merely ends in the same letters (evilhanzo.ai).\n if (('.' + host).slice(-(HZ_ANON_DOMAIN.length + 1)) === '.' + HZ_ANON_DOMAIN) {\n c += '; Domain=' + HZ_ANON_DOMAIN\n }\n if (secure) c += '; Secure'\n try {\n d.cookie = c\n } catch (e) {\n /* cookies refused — localStorage still carries the id */\n }\n}\n\n/**\n * hzAnonId returns the stable anonymous id for this browser, '' during SSR.\n *\n * Resolution is strictly ADDITIVE — every id that already exists is ADOPTED, and\n * only a browser holding none of them is given a new one:\n *\n * cookie · localStorage hz_anon_id · localStorage hz_id · in-memory · mint\n *\n * Minting over an id resets a returning visitor and detaches them from their own\n * history, so the order is the migration: the cookie is the shared home, the two\n * localStorage keys are what the three implementations wrote before it existed,\n * and each is read until nothing is left to adopt.\n *\n * localStorage keeps being written, so a rollback finds everyone where it left\n * them, and a browser that refuses cookies still holds one id per origin.\n */\nfunction hzAnonId() {\n if (typeof window === 'undefined') return '' // SSR / prerender: no browser to identify\n var s = hzAnonStore()\n var id =\n hzAnonCookie(HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_LEGACY_KEY) ||\n hzAnonMemo ||\n hzUuidv7()\n hzAnonMemo = id\n hzAnonWrite(HZ_ANON_KEY, id)\n try {\n if (s && s.getItem(HZ_ANON_KEY) !== id) s.setItem(HZ_ANON_KEY, id)\n } catch (e) {\n /* quota exhausted, or a private-mode jar that reads but refuses writes */\n }\n return id\n}\n\n/* ── END hz anon chain ─────────────────────────────────────────────────────── */\n\nexport { hzAnonId, hzUuidv7 }\n","// The ONE id minter for this client — UUIDv7 (RFC 9562 §5.7).\n//\n// The implementation is `hzUuidv7` in ./anon.js and this file only re-exports it.\n// It lives there because the anonymous-id chain has to mint too, and that chain is\n// inlined verbatim by two distributions that have no bundler (hz.js, and the tag\n// the door hosts) — a minter here as well would be a second implementation, and\n// the version nibble it produces is exactly the thing that must never diverge.\n//\n// WHY NOT crypto.randomUUID(): it mints v4, whose 122 bits are pure entropy and\n// carry no time. The session rollups on the event plane derive a session's start\n// instant FROM THE ID — their PARTITION BY and ORDER BY are\n// `fromUnixTimestamp(intDiv(toUInt64(bitShiftRight(session_id_v7, 80)), 1000))` —\n// so they admit only ids whose version nibble is 7\n// (`bitAnd(bitShiftRight(toUInt128(session_id), 76), 15) = 7`). A v4 session id is\n// not merely unordered there: it is DISCARDED at the door, silently, and the\n// rollup stays empty forever. Minting v7 is the whole reason those rollups can\n// exist; it also clusters index writes by time instead of scattering them across\n// the keyspace.\n//\n// Layout, 16 bytes big-endian:\n// 0..5 unix_ts_ms — 48-bit millisecond timestamp\n// 6 0111 (version 7) in the high nibble | rand_a\n// 7 rand_a\n// 8 10 (variant) in the high 2 bits | rand_b\n// 9..15 rand_b\n//\n// Never returns a non-UUID shape. The old minters fell back to `'a-' + base36`\n// when crypto was absent, and the plane casts a session id with\n// accurateCastOrNull(…, 'UUID') — a shape that does not parse becomes NULL and is\n// dropped by the same gate, so the fallback failed exactly like v4 did. Only the\n// ENTROPY degrades without crypto; the shape is always a valid v7 UUID.\n\n/**\n * uuidv7 mints a time-ordered UUIDv7 for `now` (epoch milliseconds).\n *\n * Two ids minted in the same millisecond sort arbitrarily between themselves; ids\n * from different milliseconds sort by time, lexically and numerically alike.\n */\nexport { hzUuidv7 as uuidv7 } from './anon.js'\n\n/** The millisecond timestamp a v7 id was minted at — the inverse of uuidv7. */\nexport function uuidv7Time(id: string): number {\n return parseInt(id.slice(0, 8) + id.slice(9, 13), 16)\n}\n","// The library version, stamped on every event (`libraryVersion`) and on the\n// Sentry `sdk` block. It lives alone so `sentry.ts` can read it without importing\n// `core.ts` — core imports sentry, so the reverse would be an import cycle.\nexport const VERSION = '0.3.31'\n","// Pure builders for the error path: parse a Hanzo-minted DSN, turn a JS Error into\n// a Sentry `event`, and frame it into a Sentry envelope. No I/O, no globals — the\n// Analytics client (core.ts) wires these to identity + transport.\n//\n// The wire shapes are a from-scratch model of the PUBLIC, documented Sentry ingest\n// protocol (develop.sentry.dev), verified against the Hanzo /v1/event ingest\n// (o11y pkg/modules/errortracking/implerrortracking: parseEnvelope, SentryEvent,\n// normalizeEvent, computeFingerprint). No upstream (FSL) code is used.\n\nimport { scrubText } from './scrub'\nimport { uuidv7 } from './uid'\nimport { VERSION } from './version'\nimport type {\n CaptureErrorOptions,\n Dsn,\n SentryEvent,\n SentryFrame,\n SentryLevel,\n} from './types'\n\n/** Max stack frames kept — well under the server's 250 cap, plenty for grouping. */\nconst MAX_FRAMES = 50\n/** Max stack lines examined, and max length of a line worth examining. Guards the\n * frame regexes against a hostile `stack` string (see framesFromStack). */\nconst MAX_LINES = 500\nconst MAX_LINE_LEN = 2048\n/** Max tag string length, so one huge property can't bloat the envelope. */\nconst MAX_TAG_LEN = 1024\n/** Max tags copied from properties. */\nconst MAX_TAGS = 50\n\n/** eventId mints a 32-hex-char id (no dashes) — the Sentry event_id shape. Same\n * minter as everything else, just formatted for Sentry's wire. */\nexport function eventId(): string {\n return uuidv7().replace(/-/g, '')\n}\n\n/** byteLen returns the UTF-8 byte length used for envelope item framing. */\nfunction byteLen(s: string): number {\n if (typeof TextEncoder !== 'undefined') return new TextEncoder().encode(s).length\n // Node fallback.\n if (typeof Buffer !== 'undefined') return Buffer.byteLength(s, 'utf8')\n return s.length\n}\n\n/**\n * parseDsn parses \"https://<version>:<hmac>@<host>/v1/event/<projectId>\" into its\n * public key + the derived envelope ingest URL. The key (which itself contains a\n * ':') is taken verbatim as the userinfo — we do NOT split it as user:pass. The\n * key rides ?sentry_key= (not the DSN in the body) because that is the credential\n * channel the server trusts AND the only one sendBeacon can carry on unload.\n * Returns null for anything malformed (fail-safe: the caller then stays inert).\n */\nexport function parseDsn(dsn: string | undefined | null): Dsn | null {\n if (!dsn) return null\n const m = /^(https?):\\/\\/([^@]+)@([^/]+)(\\/.*)?$/.exec(dsn.trim())\n if (!m) return null\n const scheme = m[1]\n const publicKey = m[2]\n const host = m[3]\n const path = m[4] ?? ''\n if (!publicKey || !host) return null\n const segs = path.split('/').filter(Boolean)\n const projectId = segs.length > 0 ? segs[segs.length - 1] : ''\n if (!projectId) return null\n const origin = `${scheme}://${host}`\n // THE DSN'S OWN PATH IS THE ADDRESS — derived here, never restated. It used to\n // be rebuilt as a literal, which threw away the path the DSN carried and wrote\n // the ingest address a second time; buildEnvelope wrote it a third. Three copies\n // of one fact. dsnForProduct (dsn.ts) is the ONE place it is spelled; this\n // follows it.\n const base = `${origin}/${segs.map(encodeURIComponent).join('/')}`\n const ingestUrl = `${base}/envelope/?sentry_key=${encodeURIComponent(publicKey)}`\n return { publicKey, origin, projectId, base, ingestUrl }\n}\n\nconst V8_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+)|([^)]+))\\)?\\s*$/\nconst MOZ_FRAME = /^\\s*(?:(.*?)@)?(.+?):(\\d+):(\\d+)\\s*$/\n\n/** inApp marks a frame as the app's own code (vs vendor/runtime) for grouping. */\nfunction inApp(file: string): boolean {\n if (!file) return false\n return !(\n file.includes('node_modules') ||\n file.startsWith('webpack-internal') ||\n file.startsWith('webpack://') ||\n file.startsWith('chrome-extension://') ||\n file.startsWith('moz-extension://')\n )\n}\n\n/**\n * framesFromStack parses a browser Error.stack into Sentry frames, OLDEST-FIRST\n * (Sentry orders caller->callee; the crash site is last — matching the server's\n * pickCrashFrame). Handles both V8 (\"at fn (file:li:co)\") and\n * Firefox/Safari (\"fn@file:li:co\"). Unparseable lines are skipped.\n */\nexport function framesFromStack(stack: string | undefined): SentryFrame[] {\n if (!stack) return []\n // Both frame regexes use lazy nested quantifiers, which backtrack badly on a\n // long line that never matches. A stack is attacker-influenced (a thrown value\n // can carry any `stack` string), so bound the work: skip absurd lines and stop\n // after MAX_LINES. Only the innermost MAX_FRAMES are kept anyway.\n const lines = stack.split('\\n', MAX_LINES)\n const frames: SentryFrame[] = []\n for (const raw of lines) {\n if (raw.length > MAX_LINE_LEN) continue\n const line = raw.trimEnd()\n if (!line) continue\n // Header lines like \"TypeError: x is not a function\" match neither frame\n // regex (no \"at \" prefix, no trailing :line:col) and are skipped naturally.\n let fn: string | undefined\n let file = ''\n let lineno = 0\n let colno = 0\n const v = V8_FRAME.exec(line)\n if (v) {\n fn = v[1]\n if (v[2]) {\n file = v[2]\n lineno = Number(v[3]) || 0\n colno = Number(v[4]) || 0\n } else {\n file = (v[5] || '').trim()\n }\n } else {\n const f = MOZ_FRAME.exec(line)\n if (!f) continue\n fn = f[1]\n file = f[2]\n lineno = Number(f[3]) || 0\n colno = Number(f[4]) || 0\n }\n if (!file && !fn) continue\n frames.push({\n function: fn || '<anonymous>',\n filename: file,\n abs_path: file,\n lineno,\n colno,\n in_app: inApp(file),\n })\n }\n // Reverse to oldest-first and cap to the innermost MAX_FRAMES.\n frames.reverse()\n if (frames.length > MAX_FRAMES) return frames.slice(frames.length - MAX_FRAMES)\n return frames\n}\n\n/** normalizeError coerces an unknown throwable into {name, message, stack}. */\nexport function normalizeError(err: unknown): { name: string; message: string; stack?: string } {\n if (err instanceof Error) {\n // `name`, `message` and `stack` are ordinary getters, and the thrown object is\n // the least trustworthy input this library handles — any of them may throw.\n // Losing the whole report to a hostile getter is not acceptable.\n const name = read(err, 'name')\n const message = read(err, 'message')\n const stack = read(err, 'stack')\n return {\n name: typeof name === 'string' && name ? name : 'Error',\n message: typeof message === 'string' && message ? message : str(err),\n stack: typeof stack === 'string' ? stack : undefined,\n }\n }\n if (typeof err === 'string') return { name: 'Error', message: err }\n try {\n return { name: 'Error', message: JSON.stringify(err) ?? str(err) }\n } catch {\n return { name: 'Error', message: str(err) }\n }\n}\n\n/** read pulls a property off a possibly-hostile value without letting a throwing\n * getter escape. */\nfunction read(o: unknown, k: string): unknown {\n try {\n return (o as Record<string, unknown>)[k]\n } catch {\n return undefined\n }\n}\n\n/** str coerces to a string without letting a throwing toString/Symbol.toPrimitive\n * escape. */\nfunction str(v: unknown): string {\n try {\n return String(v)\n } catch {\n return '[unstringifiable]'\n }\n}\n\n/** Identity carried onto every error event — the SAME ids analytics uses. */\nexport interface ErrorIdentity {\n /** OIDC sub (post-identify) or anon id. NEVER email/PII. */\n userId?: string\n sessionId?: string\n product?: string\n release?: string\n environment?: string\n}\n\nexport interface BuildEventInput {\n error: unknown\n options?: CaptureErrorOptions\n identity: ErrorIdentity\n capturePII?: boolean\n /** Injectable for deterministic tests. */\n now?: number\n id?: string\n}\n\nfunction coerceTag(v: unknown): string {\n const s = typeof v === 'string' ? v : (() => {\n try {\n return JSON.stringify(v) ?? String(v)\n } catch {\n try {\n return String(v) // circular — fall back to the primitive coercion\n } catch {\n return '[unstringifiable]' // ...which a throwing toString can also refuse\n }\n }\n })()\n return s.length > MAX_TAG_LEN ? s.slice(0, MAX_TAG_LEN) : s\n}\n\n/**\n * buildSentryEvent turns a throwable + identity into a Sentry `event`. The message\n * (the leak surface) is scrubbed client-side; the user is ONLY the stable subject\n * id — never email/username/ip. Level defaults to error, or fatal for uncaught.\n */\nexport function buildSentryEvent(input: BuildEventInput): SentryEvent {\n const { error, options = {}, identity, capturePII = false } = input\n const norm = normalizeError(error)\n const handled = options.handled !== false\n const level: SentryLevel = options.level ?? (handled ? 'error' : 'fatal')\n\n const tags: Record<string, string> = { handled: String(handled) }\n if (identity.product) tags.product = identity.product\n if (identity.sessionId) tags.session = identity.sessionId\n // Tags come from arbitrary caller `properties`. Read each key in isolation:\n // Object.entries() invokes every getter at once, so one throwing getter would\n // cost us the entire envelope — losing the stack trace to save a tag. Keys are\n // optional; the exception is not.\n try {\n const props = (options.properties ?? {}) as Record<string, unknown>\n let n = 0\n for (const k of Object.keys(props)) {\n if (n >= MAX_TAGS) break\n try {\n const val = props[k]\n if (val === undefined || val === null) continue\n tags[k] = scrubText(coerceTag(val), capturePII)\n n++\n } catch {\n continue // throwing getter or unstringifiable value — skip this key only\n }\n }\n } catch {\n /* unenumerable/exotic properties object — ship the exception without tags */\n }\n\n const event: SentryEvent = {\n event_id: input.id ?? eventId(),\n timestamp: (input.now ?? Date.now()) / 1000,\n platform: 'javascript',\n level,\n logger: identity.product,\n environment: identity.environment,\n release: identity.release,\n exception: {\n values: [\n {\n type: norm.name,\n value: scrubText(norm.message, capturePII),\n stacktrace: { frames: framesFromStack(norm.stack) },\n },\n ],\n },\n tags,\n sdk: { name: '@hanzo/event', version: VERSION },\n }\n if (identity.userId) event.user = { id: identity.userId }\n return event\n}\n\n/**\n * buildEnvelope frames a Sentry event into a newline-delimited envelope:\n *\n * {\"event_id\",\"dsn\",\"sent_at\"}\\n\n * {\"type\":\"event\",\"content_type\":\"application/json\",\"length\":N}\\n\n * <event json>\\n\n *\n * The item is length-delimited (N = UTF-8 byte length) — the framing the server's\n * parseEnvelope reads first (falling back to newline-delimited otherwise).\n */\nexport function buildEnvelope(event: SentryEvent, dsn: Dsn, sentAt?: string): string {\n const payload = JSON.stringify(event)\n const header = JSON.stringify({\n event_id: event.event_id,\n dsn: dsn.base,\n sent_at: sentAt ?? new Date().toISOString(),\n })\n const itemHeader = JSON.stringify({\n type: 'event',\n content_type: 'application/json',\n length: byteLen(payload),\n })\n return `${header}\\n${itemHeader}\\n${payload}\\n`\n}\n","// The `$exception` product-event shape — pure builders, no I/O.\n//\n// An exception reaches TWO destinations, and they read different shapes:\n//\n// 1. The ERROR PLANE — a Sentry envelope to the DSN host (sentry.ts). Untouched\n// by this module.\n// 2. ERROR TRACKING in Hanzo Insights — reads the PRODUCT-EVENT plane\n// (`insights.events WHERE event = '$exception'`) and expects the PostHog\n// exception vocabulary: `$exception_list` plus the denormalized `$exception_*`\n// properties. This module builds that.\n//\n// WHY THE FULLY-DERIVED SHAPE. Upstream, a server stage (Cymbal) symbolicates\n// frames and computes `$exception_fingerprint`, `$exception_types`, `_values`,\n// `_sources`, `_functions`, then REPLACES the property bag. That stage is not in\n// Hanzo's path: the door writes `event.fact` and a materialized view projects it\n// into `insights.events`, so nothing between the client and the warehouse derives\n// anything. Whatever the product reads, the client has to have sent. Two\n// consequences are load-bearing rather than cosmetic:\n//\n// • The issue query drops any event whose `$exception_fingerprint` is null, so an\n// event without one is invisible no matter how well-formed the rest is.\n// • `stacktrace.type` must be the literal 'resolved'; on any other value the\n// renderer falls through both match arms and draws nothing under the header.\n//\n// If that server stage is ever put in front of this plane it replaces these\n// properties wholesale, so sending them stays correct either way.\n//\n// FRAME ORDER is bottom-up: frames[0] is the entry point and the LAST frame is the\n// throw site. framesFromStack (sentry.ts) already returns that order, which is why\n// this module reuses it rather than re-parsing.\n\nimport { framesFromStack, normalizeError } from './sentry'\nimport type {\n ExceptionEntry,\n ExceptionFrame,\n ExceptionProperties,\n SentryFrame,\n SentryLevel,\n} from './types'\n\n/** Cap on the frames carried per exception, matching the Sentry path's budget. */\nconst MAX_FRAMES = 50\n/** Cap on `value`, so one enormous message cannot dominate a batch. The product\n * truncates for display anyway; this bounds the wire. */\nconst MAX_VALUE = 4096\n\n/**\n * digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.\n *\n * Grouping keys are needed on the capture path, which is synchronous and may be\n * running inside an unload handler — SubtleCrypto is async and unavailable on\n * insecure origins, so it cannot be used here. This is FNV-1a run over four seeds\n * and concatenated. It is a GROUPING key, never a security boundary: it is not\n * collision-resistant against a chosen-input adversary, and nothing authorizes or\n * authenticates on it. The product treats the value as opaque.\n */\nexport function digest(s: string): string {\n let out = ''\n for (const seed of [0x811c9dc5, 0x01000193, 0x9e3779b9, 0x85ebca6b]) {\n let h = seed >>> 0\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n // FNV prime 16777619, via shifts to stay in 32-bit integer math.\n h = (h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0\n }\n out += h.toString(16).padStart(8, '0')\n }\n return out\n}\n\n/**\n * frameOf converts one parsed stack frame into the shape the product renders.\n *\n * The product's frame vocabulary is the POST-symbolication one (`mangled_name`,\n * `source`, `line`, `column`), so that is what is emitted. `resolved` is false and\n * honest: a browser bundle is minified and no symbol set has been uploaded, so the\n * original name and line are genuinely unknown. Claiming `resolved: true` would\n * trade an accurate \"upload your symbol sets\" hint for a misleading \"source code is\n * not available\" error.\n */\nfunction frameOf(f: SentryFrame): ExceptionFrame {\n const source = f.filename ?? ''\n const name = f.function ?? '<anonymous>'\n const line = f.lineno ?? 0\n const column = f.colno ?? 0\n return {\n // Stable per code location, so the same frame groups and re-renders under one\n // key. The '/part' suffix is the product's format for one raw frame expanding\n // into several resolved ones; a browser frame is always part 0.\n raw_id: `${digest(`${source}|${name}|${line}|${column}`)}/0`,\n mangled_name: name,\n source,\n line,\n column,\n in_app: f.in_app ?? false,\n lang: 'javascript',\n resolved: false,\n resolve_failure: 'no symbol set uploaded for this release',\n resolved_name: null,\n module: null,\n }\n}\n\n/** truncate bounds a free-text field without splitting a surrogate pair. */\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s\n let end = max\n const c = s.charCodeAt(end - 1)\n // A high surrogate at the cut point would leave a lone half.\n if (c >= 0xd800 && c <= 0xdbff) end--\n return s.slice(0, end)\n}\n\n/**\n * exceptionEntry builds the single `$exception_list` entry for a throwable.\n *\n * One entry, not a chain: `Error.cause` chaining is a distinct fact with its own\n * ordering rules, and emitting it wrongly is worse than not emitting it.\n */\nexport function exceptionEntry(\n err: unknown,\n opts: { handled: boolean; id: string },\n): ExceptionEntry {\n const n = normalizeError(err)\n const frames = framesFromStack(n.stack).slice(-MAX_FRAMES)\n const entry: ExceptionEntry = {\n id: opts.id,\n type: n.name,\n value: truncate(n.message, MAX_VALUE),\n mechanism: {\n type: 'generic',\n handled: opts.handled,\n // An exception the app reported by hand was constructed, not thrown by the\n // runtime at a real call site.\n synthetic: !(err instanceof Error),\n },\n }\n if (frames.length > 0) {\n // 'resolved' names the SHAPE of the frame list, not the symbolication state of\n // any frame — the renderer only walks frames on this exact value.\n entry.stacktrace = { type: 'resolved', frames: frames.map(frameOf) }\n }\n return entry\n}\n\n/**\n * fingerprint is the issue grouping key.\n *\n * Keyed on exception type plus each in-app frame's function and source — the same\n * pieces the server-side grouper records (\"Exception Type\", \"Resolved function\n * name\", \"Source file name\"). Deliberately NOT the message: `Loading chunk 3324\n * failed` and `Loading chunk 998 failed` are one bug, and grouping on message is\n * precisely the mistake that made every distinct error string its own event name.\n *\n * Falls back to the type alone when no in-app frame survived, which keeps\n * stackless errors (`Script error.`, cross-origin) in one issue instead of\n * scattering them.\n */\nexport function fingerprint(entry: ExceptionEntry): string {\n const frames = entry.stacktrace?.frames ?? []\n const pieces = frames\n .filter((f) => f.in_app)\n .map((f) => `${f.mangled_name}@${f.source}`)\n return digest([entry.type, ...pieces].join('\\n'))\n}\n\n/**\n * exceptionProperties builds the full `$exception_*` property bag for one captured\n * throwable — everything Error Tracking reads off the event.\n *\n * The denormalized arrays are ordered like `frames`: last element is the throw\n * site, which is the element the issue list indexes at -1 for its source/function\n * columns.\n */\nexport function exceptionProperties(\n err: unknown,\n opts: { handled: boolean; id: string; level?: SentryLevel },\n): ExceptionProperties {\n const entry = exceptionEntry(err, opts)\n const frames = entry.stacktrace?.frames ?? []\n const fp = fingerprint(entry)\n return {\n $exception_list: [entry],\n $exception_fingerprint: fp,\n // Records WHY this fingerprint holds. 'manual' is the honest value: the client\n // supplied the key rather than a server grouper deriving one.\n $exception_fingerprint_record: [{ type: 'manual' }],\n $exception_type: entry.type,\n $exception_message: entry.value,\n $exception_level: opts.level ?? 'error',\n $exception_handled: opts.handled,\n $exception_synthetic: entry.mechanism?.synthetic ?? false,\n $exception_types: [entry.type],\n $exception_values: [entry.value],\n $exception_sources: frames.map((f) => f.source).filter((s): s is string => !!s),\n $exception_functions: frames\n .map((f) => f.resolved_name ?? f.mangled_name)\n .filter((s): s is string => !!s),\n }\n}\n","// SSR-safe browser storage for stable identifiers and first-touch state. Every\n// accessor no-ops (returns undefined) when there is no window/localStorage, so the\n// client imports cleanly in a Next.js server component.\n//\n// The anonymous id is the one value that must outlive an ORIGIN, and it is also\n// the one value the OTHER two distributions must agree with, so its chain lives in\n// ./anon.js and this file only calls it. Everything else here stays origin-local.\n\nimport { hzAnonId } from './anon.js'\nimport type { Attribution, Cohort } from './types'\nimport { uuidv7 } from './uid'\n\nconst KEY = {\n session: 'hz_session',\n firstTouch: 'hz_first_touch',\n cohort: 'hz_cohort',\n} as const\n\n/** 30-minute inactivity window defines a session (PostHog/GA convention). */\nconst SESSION_TTL_MS = 30 * 60 * 1000\n\nfunction ls(): Storage | undefined {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return undefined\n return window.localStorage\n } catch {\n return undefined // Safari private mode / blocked storage\n }\n}\n\n/**\n * Stable anonymous id, shared by every *.hanzo.ai surface AND by every Hanzo\n * client on the page — the npm client, hz.js and the hosted tag all run the one\n * chain in ./anon.js, so which snippet a surface loaded no longer decides who the\n * visitor is.\n *\n * It lives in a first-party cookie on the registrable domain because localStorage\n * is ORIGIN-scoped: docs, cloud and console each minted their own id for the same\n * person, so one marketing → docs → signup → checkout journey arrived as several\n * strangers — 463 anonymous identities carried 545 events in a week, about 1.2\n * events each.\n */\nexport function anonId(): string | undefined {\n return hzAnonId() || undefined // '' during SSR / prerender\n}\n\ninterface SessionState {\n id: string\n last: number\n}\n\n/**\n * Current session id, rotated after SESSION_TTL_MS of inactivity.\n *\n * Minted at `now`, so the v7 timestamp the id carries IS the session's start\n * instant — which is what the session rollups partition and order on. Passing the\n * caller's clock rather than reading Date.now() again keeps the id's embedded time\n * and the recorded `last` from disagreeing.\n */\nexport function sessionId(now = Date.now()): string | undefined {\n const s = ls()\n if (!s) return undefined\n let state: SessionState | null = null\n try {\n state = JSON.parse(s.getItem(KEY.session) || 'null')\n } catch {\n state = null\n }\n if (!state || now - state.last > SESSION_TTL_MS) {\n state = { id: uuidv7(now), last: now }\n } else {\n state.last = now\n }\n s.setItem(KEY.session, JSON.stringify(state))\n return state.id\n}\n\n/** Read the persisted first-touch attribution. */\nexport function getFirstTouch(): Attribution | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.firstTouch)\n return v ? (JSON.parse(v) as Attribution) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Persist first-touch attribution ONCE — never overwrite an existing record. */\nexport function setFirstTouchOnce(a: Attribution): Attribution {\n const s = ls()\n const existing = getFirstTouch()\n if (existing) return existing\n if (s) s.setItem(KEY.firstTouch, JSON.stringify(a))\n return a\n}\n\n/** Read persisted cohort dimensions. */\nexport function getCohort(): Cohort | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.cohort)\n return v ? (JSON.parse(v) as Cohort) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Merge + persist cohort dimensions (signupWeek set once). */\nexport function mergeCohort(patch: Cohort): Cohort {\n const s = ls()\n const cur = getCohort() || {}\n const next: Cohort = {\n signupWeek: cur.signupWeek || patch.signupWeek,\n channel: patch.channel || cur.channel,\n refCode: cur.refCode || patch.refCode,\n }\n if (s) s.setItem(KEY.cohort, JSON.stringify(next))\n return next\n}\n","// The framework-agnostic event client. ONE API surface over TWO orthogonal\n// planes, sharing one session and one identity:\n//\n// 1. EVENT STREAM — buffered pageview/event/identify/group, flushed as ONE\n// batch to the Hanzo Cloud front door:\n// POST {host}/v1/event body: { batch: [Event, …] } -> { accepted, dropped }\n// Cloud resolves the tenant server-side (validated session, or the signed\n// publishable key) and stamps it; the client NEVER sends the org.\n//\n// 2. ERROR PLANE — every captured exception is ALSO framed as a real Sentry\n// envelope and POSTed to the error host named by the DSN:\n// POST {dsn.base}/envelope/?sentry_key=… ({base} = /v1/event/{projectId})\n// This is what reaches sentry.hanzo.ai (issues, grouping, stack frames).\n//\n// These are NOT the same pipe and one does NOT feed the other. The event stream\n// stores a `type:'error'` row in the cloud event warehouse (readable via\n// GET /v1/errors) — that is product signal, not error tracking. There is no\n// server-side fan-out from /v1/event into Sentry; without the envelope below,\n// nothing ever reaches sentry.hanzo.ai. An earlier revision of this file claimed\n// the one door was \"lensed server-side into … error tracking (sentry)\". It was\n// wrong, and it silently cost the fleet all of its error telemetry.\n//\n// The error plane is inert (fail-safe) when no DSN is configured: nothing is\n// sent, nothing throws, and the event stream is unaffected.\n//\n// Auth is orthogonal — the SAME body to the SAME door, differing only in how the\n// caller proves its tenant:\n//\n// • cookie/session app (host:'') — same-origin credentials ride the request.\n// • bearer app (getToken) — Authorization: Bearer <jwt>.\n// • publishable-key app (ingestKey: 'pk-…') — ?ingest_key=pk-… on the query, on\n// the fetch and the beacon alike, with a text/plain body. Write-only and safe\n// to ship in a bundle; the door resolves it to an org server-side. The query\n// is the carrier neither send needs a header for, which is what keeps both\n// CORS-simple and therefore sendable from a customer's own origin.\n//\n// The wire is the canonical `Event` (== the cloud CaptureEvent): its `type` field\n// is what Cloud folds to event_type='error', which is how the event WAREHOUSE\n// classifies the row (GET /v1/errors). That is the extent of it — the fold does\n// not forward anything to Sentry. The error dashboard is fed only by the envelope\n// in plane 2 above, and only when a DSN is set.\n\nimport {\n parseAttribution,\n hasAttribution,\n deriveChannel,\n} from './attribution'\nimport { dsnForProduct } from './dsn'\nimport { EXCEPTION, PAGEVIEW } from './events'\nimport { exceptionProperties } from './exception'\nimport { scrubText } from './scrub'\nimport {\n buildEnvelope,\n buildSentryEvent,\n normalizeError as normalizeThrowable,\n parseDsn,\n type ErrorIdentity,\n} from './sentry'\nimport {\n anonId,\n sessionId,\n getFirstTouch,\n setFirstTouchOnce,\n getCohort,\n mergeCohort,\n} from './storage'\nimport { uuidv7 } from './uid'\nimport type {\n AnalyticsConfig,\n Attribution,\n CaptureErrorOptions,\n Cohort,\n Dsn,\n EventKind,\n Exception,\n Transport,\n WireEvent,\n} from './types'\nimport { VERSION } from './version'\n\nexport { VERSION }\n\nconst EVENT_PATH = '/v1/event' // the ONE canonical ingestion front door\nconst DEFAULT_HOST = 'https://api.hanzo.ai' // the one edge; cookie apps pass host:''\nconst ENVELOPE_CONTENT_TYPE = 'application/x-sentry-envelope'\n// The beacon body's type. text/plain is CORS-SAFELISTED, which is the whole\n// property: a safelisted type makes the POST a SIMPLE request, and a simple\n// request needs no preflight. An unloading document does not get a second round\n// trip, so cross-origin a preflighted beacon is never sent at all. The door reads\n// the raw body and dispatches on its first non-space byte, so the type names the\n// CORS class and nothing else.\nconst BEACON_CONTENT_TYPE = 'text/plain'\n\n/** readEnvDsn resolves a DSN from the public env when config omits one, so an app\n * gets the error plane by setting ONE build-time variable and nothing else.\n * Next/Vite inline these at build; the access is guarded so it is safe in a bare\n * browser and during SSR/prerender where `process` may not exist. */\nfunction readEnvDsn(): string | undefined {\n try {\n if (typeof process !== 'undefined' && process.env) {\n return process.env.NEXT_PUBLIC_HANZO_EVENT_DSN || process.env.HANZO_EVENT_DSN || undefined\n }\n } catch {\n /* no process — browser without inlined env */\n }\n return undefined\n}\n\n/** readEnv reads an inlined build-time variable, guarded like readEnvDsn. */\nfunction readEnv(name: string): string | undefined {\n try {\n if (typeof process !== 'undefined' && process.env) return process.env[name] || undefined\n } catch {\n /* no process */\n }\n return undefined\n}\n\n/** appendQuery adds a single query param to a URL string — used to carry a\n * publishable key on either send (?ingest_key=…). */\nfunction appendQuery(url: string, key: string, value: string): string {\n return url + (url.includes('?') ? '&' : '?') + key + '=' + encodeURIComponent(value)\n}\n\n/** Normalize anything thrown (Error | string | unknown) into an Exception. */\n/** normalizeError adapts the shared, hostile-input-safe normalizer (sentry.ts) to\n * the event stream's Exception shape. ONE normalizer serves both planes: a thrown\n * object may define `name`/`message`/`stack` as throwing getters, and when each\n * plane rolled its own reader the stream still lost the report that the error\n * plane had already survived. */\nfunction normalizeError(err: unknown): Exception {\n const n = normalizeThrowable(err)\n return { type: n.name, message: n.message, stack: n.stack }\n}\n\n// React Native defines a `window` but no `document` (and no `window.location`),\n// so `typeof window !== 'undefined'` alone took the browser path there and\n// `init()` threw on `window.location.search`. Requiring `document` makes RN read\n// as non-browser: `init()` returns early (skips attribution + the visibility/\n// unload listeners RN doesn't have), while `capture()`/`flush()` — which are NOT\n// gated on this and post through plain `fetch` — still emit. So the client is\n// inert-safe under SSR/Node and live on RN, without a second transport.\nconst isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined'\n\n/** serializeBatch stringifies a batch, salvaging what it can. `properties` is\n * arbitrary caller data — a DOM node, a React synthetic event, an axios error are\n * all circular, and a getter on one can throw — so a whole batch must never be\n * lost to a single poisoned event. Falls back to per-event serialization, then to\n * keeping the event and dropping its properties. Returns null only when nothing\n * at all survives. */\nfunction serializeBatch(batch: WireEvent[]): string | null {\n try {\n return JSON.stringify({ batch })\n } catch {\n /* one bad event — salvage the rest below */\n }\n const parts: string[] = []\n for (const e of batch) {\n try {\n parts.push(JSON.stringify(e))\n } catch {\n try {\n // Keep the event (identity, session, type all matter); drop the payload\n // that could not be serialized, and say so rather than lying by omission.\n parts.push(JSON.stringify({ ...e, properties: { $unserializable: true } }))\n } catch {\n /* unsalvageable — drop this ONE event, never the batch */\n }\n }\n }\n return parts.length > 0 ? '{\"batch\":[' + parts.join(',') + ']}' : null\n}\n\n/** DefaultTransport: fetch(keepalive) for authenticated/normal sends;\n * navigator.sendBeacon for page-unload beacons.\n *\n * A publishable key rides the ?ingest_key query on BOTH, which is what keeps\n * both CORS-simple: the query is the one carrier neither send needs a header\n * for, and a simple request leaves the browser from any origin — permission is\n * asked to READ a cross-origin response, never to send one. That is what lets a\n * bundled client run on a customer's own page. A JWT is first-party by\n * construction, so it keeps Authorization and the session it travels with.\n *\n * `contentType` names the FETCH request's Content-Type (the error plane sets the\n * envelope type there, and keeps the header carrier with it). The beacon body is\n * always BEACON_CONTENT_TYPE: its type is a CORS class, not a payload\n * description, and a beacon that is not a simple request is never sent. */\nclass DefaultTransport implements Transport {\n send(\n url: string,\n body: string,\n opts: {\n beacon: boolean\n token?: string\n ingestKey?: string\n contentType?: string\n debug?: boolean\n },\n ): void {\n if (opts.beacon && isBrowser() && typeof navigator.sendBeacon === 'function') {\n const beaconUrl = opts.ingestKey ? appendQuery(url, 'ingest_key', opts.ingestKey) : url\n try {\n // The answer is whether the agent QUEUED the batch — false for a body past\n // the beacon size limit, or a full queue. Only a queued batch ends the\n // send; a refused one falls through to the keepalive fetch below.\n const queued = navigator.sendBeacon(\n beaconUrl,\n new Blob([body], { type: BEACON_CONTENT_TYPE }),\n )\n if (queued) return\n if (opts.debug) console.warn('[event] beacon refused, falling back to fetch')\n } catch {\n /* fall through to fetch */\n }\n }\n if (typeof fetch !== 'function') return\n // A publishable key makes the send a CORS SIMPLE request: the key rides the\n // query, the body is text/plain, and nothing asks for credentials. That is what\n // lets a bundled client run on a customer's own page — every send from there is\n // cross-origin, and an Authorization header or a JSON type preflights the POST\n // for an origin that cannot pass one. A JWT is first-party by construction, so\n // it keeps the header and the session it travels with, and so does the error\n // plane, which names its own envelope type.\n const simple = opts.ingestKey !== undefined && opts.contentType === undefined\n const headers: Record<string, string> = {\n 'Content-Type': simple ? BEACON_CONTENT_TYPE : (opts.contentType ?? 'application/json'),\n }\n const bearer = simple ? undefined : (opts.ingestKey ?? opts.token)\n if (bearer) headers.Authorization = `Bearer ${bearer}`\n void fetch(simple ? appendQuery(url, 'ingest_key', opts.ingestKey!) : url, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n credentials: simple ? 'omit' : 'include',\n })\n .then((res) => {\n // Telemetry loss never throws into the app — but silence is how this\n // client lost the fleet's errors in the first place. Under `debug`, say\n // so. A rejected ingest (the CORS allowlist 403s non-production origins,\n // so local dev NEVER reports) is otherwise indistinguishable from success.\n if (!res.ok && opts.debug) {\n console.warn('[event] ingest rejected', res.status, url.split('?')[0])\n }\n })\n .catch((e: unknown) => {\n if (opts.debug) console.warn('[event] ingest failed', url.split('?')[0], e)\n })\n }\n}\n\nexport class Analytics {\n private cfg: Required<\n Pick<AnalyticsConfig, 'product' | 'batchSize' | 'flushIntervalMs' | 'enabled' | 'captureErrors'>\n > &\n AnalyticsConfig\n private transport: Transport\n private queue: WireEvent[] = []\n private timer: ReturnType<typeof setTimeout> | null = null\n private personId?: string\n private attribution: Attribution = { utm: {} }\n private cohort: Cohort = {}\n private started = false\n /** The view pageview() last counted — path + location. */\n private counted?: string\n /** Parsed error-plane DSN, or null when the plane is inert. */\n private dsn: Dsn | null\n /** Guards against an error thrown *inside* the error path re-entering it. */\n private reentrant = false\n\n constructor(config: AnalyticsConfig) {\n this.cfg = {\n host: DEFAULT_HOST,\n batchSize: 20,\n flushIntervalMs: 5000,\n enabled: true,\n captureErrors: true,\n ...config,\n // The publishable key resolves from ONE live source, never a literal baked\n // beside the code. Most specific first:\n // 1. an explicit `ingestKey` in config;\n // 2. NEXT_PUBLIC_PUBLISHABLE_KEY, the inlined build-time env the fleet\n // carries end to end — KMS `deploy/PUBLISHABLE_KEY` -> the PUBLISHABLE_KEY\n // build-arg -> the NEXT_PUBLIC_ prefix Next inlines.\n //\n // A surface that provides neither has no key, and its anonymous traffic\n // files under `$public` (which drops track/identify/group and answers 200);\n // the fix is to give it the KMS-sourced env, not to hardcode the org key\n // here. The key is a credential-class value: its home is KMS, and the ONE\n // build reads it from there.\n ingestKey: config.ingestKey ?? readEnv('NEXT_PUBLIC_PUBLISHABLE_KEY'),\n }\n this.transport = config.transport ?? new DefaultTransport()\n // Error plane, most specific source first: an explicit DSN wins, then the\n // inlined build-time env (a per-deploy override), then the product registry —\n // whose DSN carries the SAME resolved key (not a baked one), so declaring\n // `product` + providing the key is enough to report errors. Malformed or\n // absent => null => inert, never throwing into the host app.\n this.dsn = parseDsn(\n config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product, this.cfg.ingestKey)\n )\n }\n\n /** adopt gives this client a credential it does not have. The key belongs to\n * the stream, not to whichever caller happened to ask for the handle first,\n * so a later caller carrying one hands it over. The error plane derives from\n * the key, so it comes up here too when it was inert for want of one.\n * Present fields are never overwritten: the first caller's key stays. */\n adopt(config: AnalyticsConfig): void {\n if (config.ingestKey && !this.cfg.ingestKey) this.cfg.ingestKey = config.ingestKey\n if (config.getToken && !this.cfg.getToken) this.cfg.getToken = config.getToken\n if (!this.dsn) {\n this.dsn = parseDsn(\n config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product, this.cfg.ingestKey),\n )\n }\n }\n\n /** errorPlaneEnabled reports whether captured exceptions can actually reach the\n * error host. False means a DSN was never configured — the documented\n * fail-safe. Exposed so an app (or a test) can assert its wiring instead of\n * discovering months later that nothing was ever reported. */\n get errorPlaneEnabled(): boolean {\n return this.dsn !== null\n }\n\n /** errorIngestUrl is the fully-derived envelope endpoint, or undefined when the\n * plane is inert. Diagnostics only. */\n get errorIngestUrl(): string | undefined {\n return this.dsn?.ingestUrl\n }\n\n /** init is idempotent and browser-only for its side effects: capture first-touch\n * attribution, hydrate cohort, register the unload flush, and (unless opted out)\n * auto-capture unhandled errors. Safe to call from a React effect on every\n * render. */\n init(): void {\n if (this.started || !this.cfg.enabled) return\n this.started = true\n if (!isBrowser()) return\n\n const parsed = parseAttribution(window.location.search, document.referrer)\n this.attribution = hasAttribution(parsed)\n ? setFirstTouchOnce(parsed)\n : getFirstTouch() ?? parsed\n this.cohort = mergeCohort({\n channel: this.attribution.channel ?? deriveChannel(this.attribution),\n refCode: this.attribution.refCode,\n })\n\n const flushHidden = () => {\n if (document.visibilityState === 'hidden') this.flush(true)\n }\n window.addEventListener('visibilitychange', flushHidden)\n window.addEventListener('pagehide', () => this.flush(true))\n\n // Auto error capture — the drop-in @sentry replacement. Unhandled errors and\n // rejected promises are reported on BOTH planes: a Sentry envelope to the DSN\n // host (what reaches the error dashboard — requires a DSN) and a type:'error'\n // event on the stream (product signal in the warehouse).\n if (this.cfg.captureErrors) {\n window.addEventListener('error', (e: ErrorEvent) => {\n this.captureError(e.error ?? e.message, { handled: false })\n })\n window.addEventListener('unhandledrejection', (e: PromiseRejectionEvent) => {\n this.captureError(e.reason, { handled: false })\n })\n }\n }\n\n /** identify binds the current visitor to a stable person id (post-login). */\n identify(personId: string, traits?: Record<string, unknown>): void {\n this.personId = personId\n this.enqueue('identify', undefined, { properties: traits })\n }\n\n /** group associates the visitor with an org/team (analytics grouping, not the\n * server tenant — the server still derives tenant from the session). */\n group(groupId: string, traits?: Record<string, unknown>): void {\n this.enqueue('group', undefined, { groupId, properties: traits })\n }\n\n /** pageview records a $pageview for the current (or given) location, once per\n * view. A view is the path plus the full location, so a query or hash change\n * is a new one and a repeat call for the same place is not. */\n pageview(path?: string, properties?: Record<string, unknown>): void {\n // No `url` here: build() reads window.location.href for every event, in the\n // same tick, so this recomputed it to the identical value. Only `path` is\n // passed, because a route change fires before window.location has caught up\n // and the caller's value has to win.\n const p = path ?? (isBrowser() ? window.location.pathname : undefined)\n // Counting a page once is the client's rule, not each caller's. A page holds\n // several emitters that each correctly believe they count the first view —\n // the provider's autoPageview, a router hook, a nav autocapture — and per\n // emitter state cannot see the others. On the stream they are one page.\n const view = (p ?? '') + '\\0' + (isBrowser() ? window.location.href : '')\n if (view === this.counted) return\n this.counted = view\n this.enqueue('pageview', PAGEVIEW, { path: p, properties })\n }\n\n /** capture records a named product event with optional properties. Commerce\n * fields (productId/quantity/revenue/currency) may be passed for order events. */\n capture(\n event: string,\n properties?: Record<string, unknown>,\n commerce?: Pick<WireEvent, 'productId' | 'quantity' | 'revenue' | 'currency'>,\n ): void {\n this.enqueue('event', event, { properties, ...commerce })\n }\n\n /** captureError reports a caught error, an unhandled rejection, a React render\n * error, or a manual report to BOTH planes, from one call:\n *\n * - the ERROR PLANE — a real Sentry envelope to the DSN host. This is the one\n * that produces an issue in sentry.hanzo.ai (grouping, stack frames, AST).\n * Inert when no DSN is configured.\n * - the EVENT STREAM — a `type:'error'` row in the cloud event warehouse, so\n * an error stays correlated with the session's pageviews for product\n * analysis (readable via GET /v1/errors).\n *\n * Both carry the SAME session and subject id, so an error and the pageview\n * before it join up. Never throws back into the app; errors are higher-signal\n * than pageviews, so both planes flush promptly (a crash may unload the page\n * moments later). */\n captureError(err: unknown, context?: CaptureErrorOptions): void {\n // A failure inside the error path must not recurse through the global handlers.\n if (this.reentrant) return\n this.reentrant = true\n try {\n // ERROR PLANE FIRST, in its own try. The planes are independent, so neither\n // may be able to starve the other: `properties` is arbitrary caller data\n // (a DOM node, a React synthetic event, an axios error — all circular and\n // all common), and serializing it on the event stream can throw. When the\n // stream ran first, that throw escaped to the outer catch and the crash\n // report was never sent — silently losing exactly the signal this client\n // exists to deliver. Order and isolation are the fix.\n try {\n this.sendError(err, context)\n } catch {\n /* the error plane must never take the event stream down with it */\n }\n\n try {\n const handled = context?.handled ?? true\n const ex = normalizeError(err)\n ex.handled = handled\n // NAME: the reserved '$exception', never the message. The message was the\n // name until 0.3.20, which put every distinct error string — one per failed\n // chunk id, per ResizeObserver notification — permanently into the event\n // taxonomy, and left Error Tracking (which reads this exact name) at zero.\n //\n // TYPE 'event', not 'error'. `type` alone picks the storage plane: 'error'\n // routes to the error plane, which the product-event projection does not\n // read, so an exception filed there is invisible to Error Tracking however\n // well-formed it is. The full error record still reaches the error plane as\n // a Sentry envelope above — this row is the product-analytics breadcrumb,\n // which is what keeps a crash correlated with the session's pageviews.\n //\n // `error` is still carried: the server folds it into properties.$exception\n // (scrubbing message and stack on the way), which is the shape existing\n // readers bind to.\n this.enqueue('event', EXCEPTION, {\n error: ex,\n properties: {\n ...context?.properties,\n ...exceptionProperties(err, {\n handled,\n id: uuidv7(),\n level: context?.level,\n }),\n },\n })\n this.flush()\n } catch {\n /* nor the reverse */\n }\n } finally {\n this.reentrant = false\n }\n }\n\n /** setCohort persists cohort dimensions (e.g. signupWeek at signup) so they ride\n * every subsequent event. */\n setCohort(patch: Cohort): void {\n this.cohort = mergeCohort(patch)\n }\n\n /** flush drains the buffer to the server as ONE batch through the ONE ingest\n * front door POST /v1/event, body { batch: [Event…] }. beacon=true selects the\n * unload-safe transport. Auth is orthogonal to the wire:\n *\n * • publishable key set → rides ?ingest_key=pk-… on both sends, keeping each\n * a CORS-simple request that any origin may send.\n * • else a bearer JWT rides Authorization (fetch only — sendBeacon cannot\n * carry a header, so token apps fall back to keepalive fetch on unload).\n * • else a cookie app rides same-origin credentials (beacon carries the\n * cookie fine).\n */\n flush(beacon = false): void {\n if (!this.cfg.enabled || this.queue.length === 0) return\n const batch = this.queue\n this.queue = []\n this.clearTimer()\n\n // A publishable key and a bearer JWT are mutually exclusive doors, and the\n // BEARER WINS. It names a real principal and resolves to THAT person's org;\n // a pk- names one org for everybody holding it. So the key is what attributes\n // a visitor nobody has vouched for, and it must never displace someone who\n // has been.\n //\n // The precedence used to run the other way, which was survivable only while\n // the key had to be passed in code. Once it also resolves from the build env,\n // key-wins means setting one variable silently blanks every signed-in user's\n // token and re-files their events under whichever org minted the key — on a\n // console served to several brands from one bundle, that is a cross-tenant\n // leak introduced by an env var.\n const token = this.cfg.getToken?.() ?? undefined\n const key = token ? undefined : this.cfg.ingestKey?.trim() || undefined\n // Only a bearer JWT blocks the beacon: sendBeacon cannot set an Authorization\n // header. A pk- rides ?ingest_key; a cookie rides credentials.\n const useBeacon = beacon && !token\n const body = serializeBatch(batch)\n if (body === null) {\n if (this.cfg.debug) console.debug('[event] flush → dropped, batch unserializable')\n return\n }\n if (this.cfg.debug) console.debug('[event] flush →', EVENT_PATH, batch.length)\n this.transport.send(this.cfg.host + EVENT_PATH, body, {\n beacon: useBeacon,\n token,\n ingestKey: key,\n debug: this.cfg.debug,\n })\n }\n\n // ── internals ────────────────────────────────────────────────────────────\n\n /** sendError frames one exception as a Sentry envelope and posts it to the DSN's\n * ingest URL. The DSN's own key rides ?sentry_key= (the credential channel the\n * server trusts, and the only one a headerless beacon can carry), so NO bearer\n * or publishable key is attached here — the two planes authenticate\n * independently. Errors are sent one envelope per event, immediately: batching\n * a crash report is how you lose it. */\n private sendError(err: unknown, options?: CaptureErrorOptions): void {\n if (!this.cfg.enabled || !this.dsn) return\n const event = buildSentryEvent({\n error: err,\n options,\n identity: this.errorIdentity(),\n capturePII: this.cfg.capturePII ?? false,\n })\n const body = buildEnvelope(event, this.dsn)\n if (this.cfg.debug) console.debug('[event] error →', this.dsn.ingestUrl, event.event_id)\n this.transport.send(this.dsn.ingestUrl, body, {\n beacon: false,\n contentType: ENVELOPE_CONTENT_TYPE,\n debug: this.cfg.debug,\n })\n }\n\n /** errorIdentity is the SAME identity the event stream stamps — the OIDC subject\n * once identify() has run, else the anon id. Never email/PII. */\n private errorIdentity(): ErrorIdentity {\n return {\n userId: this.personId ?? anonId(),\n sessionId: sessionId(),\n product: this.cfg.product,\n release: this.cfg.release ?? readEnv('NEXT_PUBLIC_HANZO_RELEASE'),\n environment: this.cfg.environment ?? readEnv('NODE_ENV'),\n }\n }\n\n private enqueue(kind: EventKind, event: string | undefined, extra: Partial<WireEvent>): void {\n if (!this.cfg.enabled) return\n if (!this.started) this.init()\n this.queue.push(this.build(kind, event, extra))\n if (this.queue.length >= this.cfg.batchSize) this.flush()\n else this.schedule()\n }\n\n private build(kind: EventKind, event: string | undefined, extra: Partial<WireEvent>): WireEvent {\n const anon = anonId()\n const wire: WireEvent = {\n messageId: uuidv7(),\n type: kind,\n event,\n timestamp: new Date().toISOString(),\n distinctId: this.personId ?? anon,\n anonymousId: anon,\n personId: this.personId,\n sessionId: sessionId(),\n product: this.cfg.product,\n referrer: this.attribution.referrer,\n utm: this.attribution.utm,\n refCode: this.cohort.refCode ?? this.attribution.refCode,\n channel: this.cohort.channel ?? this.attribution.channel,\n signupWeek: this.cohort.signupWeek,\n // Where the event happened, stamped for every kind rather than only for\n // pageviews. An interaction is reported against the page it happened on,\n // and autocapture ($click/$input/$change) reaches the wire through\n // capture(), which supplies no location — so every click arrived with an\n // empty url and path, and `host`, derived from url, was empty with them.\n // That is unattributable to a page, which is the one thing a heatmap\n // needs. Read here, at the single point every event is built, so it\n // cannot go missing from a call site again.\n //\n // Before `...extra`: pageview() passes an explicit path for route\n // changes that fire before window.location has caught up, and that value\n // has to win over the one read here.\n url: isBrowser() ? window.location.href : undefined,\n path: isBrowser() ? window.location.pathname : undefined,\n library: '@hanzo/event',\n libraryVersion: VERSION,\n ...extra,\n }\n\n // A location is free text an attacker (or an ordinary product flow) controls,\n // and it is now stamped on EVERY event rather than only pageviews — so the\n // one field that is always a URL gets the same policy the error plane has\n // always applied to error text. A password-reset, invite or magic link puts\n // a JWT in the query and an address in `?email=`; without this, one click on\n // that page ships both to the warehouse in cleartext, and every later click\n // repeats it.\n //\n // AFTER `...extra`, deliberately. A call site can pass its own location —\n // pageview() passes `path`, and until this commit it passed `url` too — and\n // `extra` merges over the fields read above, so scrubbing at the read would\n // have left the highest-volume event emitting a raw location while looking\n // scrubbed. Applied to the ASSEMBLED record, the guarantee holds for every\n // call site, including ones not written yet.\n //\n // `scrubText` is the SAME policy as the error plane (secrets always,\n // PII unless capturePII) rather than a second URL-specific redactor: one\n // definition of \"must not leave the browser\", already tested, mirroring the\n // server's. Guarded on presence so an absent field stays absent instead of\n // becoming the empty string that `host` derivation reads as a page.\n const capturePII = this.cfg.capturePII ?? false\n if (wire.url) wire.url = scrubText(wire.url, capturePII)\n if (wire.path) wire.path = scrubText(wire.path, capturePII)\n if (wire.referrer) wire.referrer = scrubText(wire.referrer, capturePII)\n return wire\n }\n\n private schedule(): void {\n if (this.timer || !this.cfg.enabled) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.flush()\n }, this.cfg.flushIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer)\n this.timer = null\n }\n }\n}\n\n// ── one stream, one client ──────────────────────────────────────────────────\n//\n// A page has ONE event stream per (host, product): one queue, one anon id, one\n// credential. Two clients on it split the batch and double the pageview, and\n// the half built by the caller that had no key is refused at the door — so the\n// same page is both over- and under-counted, and neither number says so.\n//\n// Two callers ask for that stream on any real page and both are right to: the\n// app mounts a provider, and the component library mounts its own telemetry.\n// Neither can see the other, so the fix cannot live in either. It lives here,\n// where the stream is: asking twice returns the same client.\n//\n// The registry is on the PAGE, under a `Symbol.for` slot, not in module scope.\n// `@hanzo/event` and `@hanzo/event/react` are separate bundles that each carry\n// a copy of this module, so a module-scope map is per-copy and the two copies\n// never see each other's — which is exactly how the duplicate arises. A\n// well-known symbol is the one slot every copy resolves to the same value.\n//\n// Browser only. A server process serves many visitors, and one client shared\n// across requests would carry one visitor's personId into the next.\nconst CLIENTS = Symbol.for('hanzo.event.clients')\n\nfunction registry(): Map<string, Analytics> {\n const g = globalThis as unknown as Record<symbol, Map<string, Analytics> | undefined>\n const existing = g[CLIENTS]\n if (existing) return existing\n const fresh = new Map<string, Analytics>()\n g[CLIENTS] = fresh\n return fresh\n}\n\n/** createAnalytics returns the client for a stream, building it on first ask.\n * This is the ONE way to get a client: `new Analytics` bypasses the registry\n * and is for tests and for a deliberately separate instance. */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n // A disabled client emits nothing, so it can double nothing and does not take\n // the stream. Callers reach their answer at different moments — a provider\n // whose ownership resolves in an effect renders once saying `false` before it\n // has decided anything — and the client built in that moment must not become\n // the one the page keeps. Registering it would silence the page, and adopting\n // `enabled` from a later caller would let one surface overrule another's\n // reading of consent. Neither: it is simply not the stream's client.\n if (!isBrowser() || config.enabled === false) return new Analytics(config)\n const key = (config.host ?? DEFAULT_HOST) + '\\0' + config.product\n const clients = registry()\n const existing = clients.get(key)\n if (existing) {\n existing.adopt(config)\n return existing\n }\n const fresh = new Analytics(config)\n clients.set(key, fresh)\n return fresh\n}\n\n// Re-export the hydrate helpers so consumers can read persisted cohort/attribution\n// (e.g. to send refCode to the referrals API) without reaching into storage.\nexport { getCohort, getFirstTouch }\n","// Insights goals + cohorts, defined once as data so the console/insights UI and\n// every product agree on what \"a Signup\", \"a Sale\", and \"upgrade intent\" mean.\n// This is the machine-readable spec — the shared source of truth a sync step can\n// push into Insights, and what TAXONOMY.md documents.\n//\n// A goal answers \"what counts as a conversion\". A funnel answers \"by what path\".\n// The paths live in funnels.ts and a goal REFERENCES one by id: the steps are\n// written down exactly once.\n\nimport { EVENTS } from './events'\nimport { eventsOf, type FunnelId } from './funnels'\n\nexport interface GoalDef {\n /** Human label shown in Insights. */\n label: string\n /** The event whose occurrence counts as the goal conversion. */\n event: string\n /** The funnel leading to the goal — an id into FUNNELS (see funnels.ts). */\n funnelId?: FunnelId\n /** The ordered event names of `funnelId`, derived — never hand-written. */\n funnel?: string[]\n /** Optional property equality filter that qualifies the conversion. */\n filter?: { property: string; equals: string }\n}\n\nexport const GOALS: Record<'signup' | 'sale' | 'upgradeIntent' | 'activation', GoalDef> = {\n // Signup: the conversion is signup_completed, along the site signup funnel.\n signup: {\n label: 'Signup',\n event: EVENTS.SIGNUP_COMPLETED,\n funnelId: 'signup',\n funnel: eventsOf('signup'),\n },\n // Sale: a completed order qualified as a plan purchase (kind=plan).\n sale: {\n label: 'Sale',\n event: EVENTS.ORDER_COMPLETED,\n funnelId: 'upgrade',\n funnel: eventsOf('upgrade'),\n filter: { property: 'kind', equals: 'plan' },\n },\n // Upgrade intent: a plan click; pricing_viewed is the top of its funnel.\n upgradeIntent: {\n label: 'Upgrade Intent',\n event: EVENTS.PLAN_CLICKED,\n funnelId: 'upgrade',\n funnel: eventsOf('upgrade'),\n },\n // Activation: the ONE north-star conversion — an account that did the first\n // valuable thing (a successful API call, a live app, a chat answer).\n activation: {\n label: 'Activation',\n event: EVENTS.FIRST_ACTION,\n funnelId: 'apiActivation',\n funnel: eventsOf('apiActivation'),\n },\n}\n\nexport interface CohortDef {\n /** The hanzo.events column the cohort dimension maps to. */\n field: string\n label: string\n}\n\nexport const COHORTS: Record<'signupWeek' | 'channel' | 'refCode', CohortDef> = {\n signupWeek: { field: 'signup_week', label: 'Signup week' },\n channel: { field: 'channel', label: 'Acquisition channel' },\n refCode: { field: 'ref_code', label: 'Referral code' },\n}\n"]}
1
+ {"version":3,"sources":["../src/attribution.ts","../src/dsn.ts","../src/scrub.ts","../src/anon.js","../src/uid.ts","../src/version.ts","../src/sentry.ts","../src/exception.ts","../src/storage.ts","../src/core.ts","../src/goals.ts"],"names":["truncate","normalizeError"],"mappings":";;;;AAMA,IAAM,YAAA,GAAe;AAAA,EACnB,WAAA;AAAA,EAAa,YAAA;AAAA,EAAc,UAAA;AAAA,EAAY,OAAA;AAAA,EAAS,MAAA;AAAA,EAAQ,WAAA;AAAA,EACxD,SAAA;AAAA,EAAW,UAAA;AAAA,EAAY,SAAA;AAAA,EAAW,YAAA;AAAA,EAAc;AAClD,CAAA;AACA,IAAM,eAAe,CAAC,SAAA,EAAW,SAAS,aAAA,EAAe,QAAA,EAAU,UAAU,SAAS,CAAA;AAI/E,SAAS,gBAAA,CAAiB,QAAgB,QAAA,EAA+B;AAC9E,EAAA,MAAM,CAAA,GAAI,IAAI,eAAA,CAAgB,MAAA,IAAU,EAAE,CAAA;AAC1C,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAc;AACzB,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA;AACjB,IAAA,OAAO,CAAA,GAAI,CAAA,CAAE,IAAA,EAAK,GAAI,MAAA;AAAA,EACxB,CAAA;AACA,EAAA,MAAM,CAAA,GAAiB;AAAA,IACrB,GAAA,EAAK;AAAA,MACH,MAAA,EAAQ,IAAI,YAAY,CAAA;AAAA,MACxB,MAAA,EAAQ,IAAI,YAAY,CAAA;AAAA,MACxB,QAAA,EAAU,IAAI,cAAc,CAAA;AAAA,MAC5B,IAAA,EAAM,IAAI,UAAU,CAAA;AAAA,MACpB,OAAA,EAAS,IAAI,aAAa;AAAA,KAC5B;AAAA,IACA,QAAA,EAAU,QAAA,GAAW,QAAA,CAAS,IAAA,EAAK,GAAI,MAAA;AAAA,IACvC,OAAA,EAAS,IAAI,KAAK,CAAA,IAAK,IAAI,SAAS,CAAA,IAAK,GAAA,CAAI,UAAU,CAAA,IAAK;AAAA,GAC9D;AACA,EAAA,CAAA,CAAE,OAAA,GAAU,cAAc,CAAC,CAAA;AAC3B,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,cAAc,CAAA,EAAwB;AACpD,EAAA,MAAM,MAAA,GAAA,CAAU,CAAA,CAAE,GAAA,CAAI,MAAA,IAAU,IAAI,WAAA,EAAY;AAChD,EAAA,IAAI,uCAAA,CAAwC,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,MAAA;AACjE,EAAA,IAAI,EAAE,GAAA,CAAI,MAAA,IAAU,CAAA,CAAE,GAAA,CAAI,UAAU,OAAO,UAAA;AAC3C,EAAA,IAAI,CAAA,CAAE,SAAS,OAAO,UAAA;AACtB,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,CAAE,QAAQ,CAAA;AAC9B,EAAA,IAAI,CAAC,MAAM,OAAO,QAAA;AAClB,EAAA,IAAI,YAAA,CAAa,KAAK,CAAC,CAAA,KAAM,KAAK,QAAA,CAAS,CAAC,CAAC,CAAA,EAAG,OAAO,QAAA;AACvD,EAAA,IAAI,YAAA,CAAa,KAAK,CAAC,CAAA,KAAM,KAAK,QAAA,CAAS,CAAC,CAAC,CAAA,EAAG,OAAO,SAAA;AACvD,EAAA,OAAO,UAAA;AACT;AAGO,SAAS,OAAO,GAAA,EAAsB;AAC3C,EAAA,IAAI,CAAC,KAAK,OAAO,EAAA;AACjB,EAAA,IAAI,CAAA,GAAI,IAAI,IAAA,EAAK;AACjB,EAAA,MAAM,MAAA,GAAS,CAAA,CAAE,OAAA,CAAQ,KAAK,CAAA;AAC9B,EAAA,IAAI,UAAU,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,SAAS,CAAC,CAAA;AACvC,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AAC5B,EAAA,IAAI,OAAO,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AAChC,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AACxB,EAAA,IAAI,MAAM,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,KAAK,CAAC,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,IAAI,SAAS,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,KAAA,CAAM,GAAG,KAAK,CAAA;AACpC,EAAA,OAAO,CAAA,CAAE,WAAA,EAAY,CAAE,IAAA,EAAK;AAC9B;AAIO,SAAS,eAAe,CAAA,EAAyB;AACtD,EAAA,OAAO,OAAA;AAAA,IACL,CAAA,CAAE,IAAI,MAAA,IAAU,CAAA,CAAE,IAAI,MAAA,IAAU,CAAA,CAAE,IAAI,QAAA,IAAY,CAAA,CAAE,IAAI,IAAA,IACtD,CAAA,CAAE,IAAI,OAAA,IAAW,CAAA,CAAE,WAAY,CAAA,CAAE,QAAA,IAAY,MAAA,CAAO,CAAA,CAAE,QAAQ;AAAA,GAClE;AACF;AAGO,SAAS,QAAQ,CAAA,EAAiB;AAEvC,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA,CAAE,cAAA,EAAe,EAAG,CAAA,CAAE,WAAA,EAAY,EAAG,CAAA,CAAE,UAAA,EAAY,CAAC,CAAA;AACnF,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,SAAA,EAAU,IAAK,CAAA;AAChC,EAAA,IAAA,CAAK,UAAA,CAAW,IAAA,CAAK,UAAA,EAAW,GAAI,IAAI,GAAG,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,IAAI,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,cAAA,EAAe,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAChE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAA,CAAA,CAAO,IAAA,CAAK,OAAA,EAAQ,GAAI,SAAA,CAAU,OAAA,EAAQ,IAAK,KAAA,GAAW,CAAA,IAAK,CAAC,CAAA;AAClF,EAAA,OAAO,CAAA,EAAG,IAAA,CAAK,cAAA,EAAgB,CAAA,EAAA,EAAK,MAAA,CAAO,IAAI,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AACnE;;;AChDO,IAAM,eAAA,GAAoD,OAAO,MAAA,CAAO;AAAA,EAC7E,OAAA,EAAS,sCAAA;AAAA;AAAA,EACT,GAAA,EAAK,sCAAA;AAAA;AAAA,EACL,IAAA,EAAM;AAAA;AACR,CAAC;AAUM,SAAS,aAAA,CACd,SACA,GAAA,EACoB;AACpB,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,GAAA,EAAK,OAAO,MAAA;AAC7B,EAAA,MAAM,SAAA,GAAY,gBAAgB,OAAO,CAAA;AACzC,EAAA,IAAI,CAAC,WAAW,OAAO,MAAA;AACvB,EAAA,OAAO,CAAA,QAAA,EAAW,GAAG,CAAA,uBAAA,EAA0B,SAAS,CAAA,CAAA;AAC1D;;;AC3CA,IAAM,QAAA,GAAW,YAAA;AACjB,IAAM,UAAA,GAAa,SAAA;AACnB,IAAM,OAAA,GAAU,MAAA;AAIhB,IAAM,eAAA,GAA4B;AAAA,EAChC,2EAAA;AAAA,EACA,6DAAA;AAAA;AAAA,EACA,uCAAA;AAAA;AAAA,EACA,mDAAA;AAAA;AAAA,EACA,6CAAA;AAAA;AAAA,EACA,wBAAA;AAAA;AAAA,EACA,uBAAA;AAAA;AAAA,EACA,uBAAA;AAAA;AAAA,EACA,2BAAA;AAAA;AAAA,EACA,+BAAA;AAAA;AAAA,EACA,iCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AACF,CAAA;AAOA,IAAM,MAAA,GAAS,yBAAA;AAKf,SAAS,KAAK,MAAA,EAAyB;AACrC,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,GAAA,GAAM,KAAA;AACV,EAAA,KAAA,IAAS,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AAC3C,IAAA,IAAI,CAAA,GAAI,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA,GAAI,EAAA;AAC/B,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,CAAA,IAAK,CAAA;AACL,MAAA,IAAI,CAAA,GAAI,GAAG,CAAA,IAAK,CAAA;AAAA,IAClB;AACA,IAAA,GAAA,IAAO,CAAA;AACP,IAAA,GAAA,GAAM,CAAC,GAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAM,EAAA,KAAO,CAAA;AACtB;AAGA,SAAS,UAAU,CAAA,EAAmB;AACpC,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,CAAC,CAAA,KAAM;AAC9B,IAAA,MAAM,MAAA,GAAS,CAAA,CAAE,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AACpC,IAAA,IAAI,OAAO,MAAA,GAAS,EAAA,IAAM,MAAA,CAAO,MAAA,GAAS,IAAI,OAAO,CAAA;AACrD,IAAA,OAAO,IAAA,CAAK,MAAM,CAAA,GAAI,QAAA,GAAW,CAAA;AAAA,EACnC,CAAC,CAAA;AACH;AAOA,IAAM,QAAA,GAAW,8DAAA;AACjB,IAAM,OAAA,GAAU,8BAAA;AAChB,IAAM,OAAA,GAAU,iDAAA;AAmBhB,IAAM,iBAAA,GAAoB;AAAA,EACxB,MAAA;AAAA,EAAQ,OAAA;AAAA,EAAS,OAAA;AAAA,EAAS,cAAA;AAAA,EAAgB,UAAA;AAAA,EAAY,eAAA;AAAA,EACtD,MAAA;AAAA,EAAQ,eAAA;AAAA,EAAiB,QAAA;AAAA,EAAU,eAAA;AAAA,EAAiB,UAAA;AAAA,EAAY,QAAA;AAAA,EAAU,KAAA;AAAA,EAC1E,SAAA;AAAA,EAAW,QAAA;AAAA,EAAU,KAAA;AAAA,EAAO,SAAA;AAAA,EAAW,YAAA;AAAA,EAAc,KAAA;AAAA,EACrD,KAAA;AAAA,EAAO,WAAA;AAAA,EAAa,OAAA;AAAA,EAAS,KAAA;AAAA,EAAO,QAAA;AAAA,EAAU,YAAA;AAAA,EAC9C,aAAA;AAAA,EAAe,oBAAA;AAAA,EAAsB,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU;AAC1D,CAAA;AACA,IAAM,sBAAsB,IAAI,MAAA;AAAA,EAC9B,YAAA,GAAe,iBAAA,CAAkB,IAAA,CAAK,GAAG,CAAA,GAAI,sBAAA;AAAA,EAC7C;AACF,CAAA;AAIO,SAAS,uBAAuB,CAAA,EAAmB;AACxD,EAAA,OAAO,EAAE,OAAA,CAAQ,mBAAA,EAAqB,CAAC,EAAA,EAAI,MAAA,KAAmB,SAAS,QAAQ,CAAA;AACjF;AAGO,SAAS,cAAc,CAAA,EAAmB;AAC/C,EAAA,CAAA,GAAI,uBAAuB,CAAC,CAAA;AAC5B,EAAA,KAAA,MAAW,MAAM,eAAA,EAAiB,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,IAAI,QAAQ,CAAA;AAC5D,EAAA,OAAO,UAAU,CAAC,CAAA;AACpB;AAGO,SAAS,SAAS,CAAA,EAAmB;AAC1C,EAAA,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,QAAA,EAAU,UAAU,CAAA;AAClC,EAAA,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,OAAA,EAAS,OAAO,CAAA;AAC9B,EAAA,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,OAAA,EAAS,OAAO,CAAA;AAC9B,EAAA,OAAO,CAAA;AACT;AAOO,IAAM,aAAA,GAAgB,IAAA;AAItB,SAAS,QAAA,CAAS,CAAA,EAAW,GAAA,GAAM,aAAA,EAAuB;AAC/D,EAAA,OAAO,CAAA,CAAE,SAAS,GAAA,GAAM,CAAA,CAAE,MAAM,CAAA,EAAG,GAAG,IAAI,oBAAA,GAAkB,CAAA;AAC9D;AAIO,SAAS,SAAA,CAAU,CAAA,EAAuB,UAAA,GAAa,KAAA,EAAe;AAC3E,EAAA,IAAI,CAAC,CAAA,EAAG,OAAO,CAAA,IAAK,EAAA;AACpB,EAAA,CAAA,GAAI,SAAS,CAAC,CAAA;AACd,EAAA,CAAA,GAAI,cAAc,CAAC,CAAA;AACnB,EAAA,IAAI,CAAC,UAAA,EAAY,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA;AAC/B,EAAA,OAAO,CAAA;AACT;;;AC/HA,IAAI,WAAA,GAAc,YAAA;AAMlB,IAAI,kBAAA,GAAqB,OAAA;AAKzB,IAAI,cAAA,GAAiB,UAAA;AAMrB,IAAI,eAAA,GAAkB,CAAA,GAAI,GAAA,GAAM,EAAA,GAAK,EAAA,GAAK,EAAA;AAI1C,IAAI,UAAA;AAWJ,SAAS,SAAS,GAAA,EAAK;AACrB,EAAA,IAAI,CAAA,GAAI,IAAI,UAAA,CAAW,EAAE,CAAA;AACzB,EAAA,IAAI,CAAA;AACJ,EAAA,IAAI,CAAA,GAAI,OAAO,MAAA,KAAW,WAAA,GAAc,MAAA,GAAS,MAAA;AACjD,EAAA,IAAI,KAAK,OAAO,CAAA,CAAE,oBAAoB,UAAA,EAAY,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAAA,OAChE,KAAK,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,GAAK,IAAA,CAAK,MAAA,EAAO,GAAI,GAAA,GAAO,CAAA;AAC7D,EAAA,IAAI,CAAA,GAAI,KAAK,KAAA,CAAM,GAAA,KAAQ,SAAY,IAAA,CAAK,GAAA,KAAQ,GAAG,CAAA;AACvD,EAAA,KAAK,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AACvB,IAAA,CAAA,CAAE,CAAC,IAAI,CAAA,GAAI,GAAA;AACX,IAAA,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA;AAAA,EACxB;AACA,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,GAAA,GAAQ,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AACtB,EAAA,CAAA,CAAE,CAAC,CAAA,GAAI,GAAA,GAAQ,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AACtB,EAAA,IAAI,CAAA,GAAI,EAAA;AACR,EAAA,KAAK,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AACvB,IAAA,CAAA,IAAA,CAAM,CAAA,CAAE,CAAC,CAAA,GAAI,GAAA,EAAO,SAAS,EAAE,CAAA,CAAE,MAAM,CAAC,CAAA;AACxC,IAAA,IAAI,CAAA,KAAM,KAAK,CAAA,KAAM,CAAA,IAAK,MAAM,CAAA,IAAK,CAAA,KAAM,GAAG,CAAA,IAAK,GAAA;AAAA,EACrD;AACA,EAAA,OAAO,CAAA;AACT;AAGA,SAAS,SAAA,GAAY;AACnB,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,QAAA,CAAS,MAAA,KAAW,UAAU,OAAO,IAAA;AACnF,IAAA,OAAO,QAAA;AAAA,EACT,SAAS,CAAA,EAAG;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGA,SAAS,WAAA,GAAc;AACrB,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,MAAA,CAAO,cAAc,OAAO,IAAA;AAClE,IAAA,OAAO,MAAA,CAAO,YAAA;AAAA,EAChB,SAAS,CAAA,EAAG;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGA,SAAS,UAAA,CAAW,OAAO,IAAA,EAAM;AAC/B,EAAA,IAAI;AACF,IAAA,OAAQ,KAAA,IAAS,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAM,EAAA;AAAA,EAC3C,SAAS,CAAA,EAAG;AACV,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AAGA,SAAS,aAAa,IAAA,EAAM;AAC1B,EAAA,IAAI,IAAI,SAAA,EAAU;AAClB,EAAA,IAAI,CAAC,GAAG,OAAO,EAAA;AACf,EAAA,IAAI,KAAA,GAAQ,CAAA,CAAE,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAC9B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,IAAA,IAAI,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,CAAE,QAAQ,GAAG,CAAA;AAC7B,IAAA,IAAI,EAAA,GAAK,CAAA,IAAK,KAAA,CAAM,CAAC,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,EAAK,KAAM,IAAA,EAAM;AACrD,IAAA,IAAI,CAAA,GAAI,MAAM,CAAC,CAAA,CAAE,MAAM,EAAA,GAAK,CAAC,EAAE,IAAA,EAAK;AACpC,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,IAAI;AACF,MAAA,OAAO,mBAAmB,CAAC,CAAA;AAAA,IAC7B,SAAS,CAAA,EAAG;AACV,MAAA,OAAO,CAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,EAAA;AACT;AAGA,SAAS,WAAA,CAAY,MAAM,KAAA,EAAO;AAChC,EAAA,IAAI,IAAI,SAAA,EAAU;AAClB,EAAA,IAAI,CAAC,CAAA,EAAG;AACR,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,MAAA,CAAO,QAAA,EAAU;AACpD,MAAA,IAAA,GAAO,MAAA,CAAO,SAAS,QAAA,IAAY,EAAA;AAGnC,MAAA,MAAA,GAAS,MAAA,CAAO,SAAS,QAAA,KAAa,QAAA;AAAA,IACxC;AAAA,EACF,SAAS,CAAA,EAAG;AAAA,EAEZ;AAGA,EAAA,IAAI,CAAA,GAAI,IAAA,GAAO,GAAA,GAAM,kBAAA,CAAmB,KAAK,CAAA;AAC7C,EAAA,CAAA,IAAK,uBAAuB,eAAA,GAAkB,gBAAA;AAK9C,EAAA,IAAA,CAAK,GAAA,GAAM,MAAM,KAAA,CAAM,EAAE,eAAe,MAAA,GAAS,CAAA,CAAE,CAAA,KAAM,GAAA,GAAM,cAAA,EAAgB;AAC7E,IAAA,CAAA,IAAK,WAAA,GAAc,cAAA;AAAA,EACrB;AACA,EAAA,IAAI,QAAQ,CAAA,IAAK,UAAA;AACjB,EAAA,IAAI;AACF,IAAA,CAAA,CAAE,MAAA,GAAS,CAAA;AAAA,EACb,SAAS,CAAA,EAAG;AAAA,EAEZ;AACF;AAkBA,SAAS,QAAA,GAAW;AAClB,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,EAAa,OAAO,EAAA;AAC1C,EAAA,IAAI,IAAI,WAAA,EAAY;AACpB,EAAA,IAAI,EAAA,GACF,YAAA,CAAa,WAAW,CAAA,IACxB,UAAA,CAAW,CAAA,EAAG,WAAW,CAAA,IACzB,UAAA,CAAW,CAAA,EAAG,kBAAkB,CAAA,IAChC,cACA,QAAA,EAAS;AACX,EAAA,UAAA,GAAa,EAAA;AACb,EAAA,WAAA,CAAY,aAAa,EAAE,CAAA;AAC3B,EAAA,IAAI;AACF,IAAA,IAAI,CAAA,IAAK,EAAE,OAAA,CAAQ,WAAW,MAAM,EAAA,EAAI,CAAA,CAAE,OAAA,CAAQ,WAAA,EAAa,EAAE,CAAA;AAAA,EACnE,SAAS,CAAA,EAAG;AAAA,EAEZ;AACA,EAAA,OAAO,EAAA;AACT;;;ACzJO,SAAS,WAAW,EAAA,EAAoB;AAC7C,EAAA,OAAO,QAAA,CAAS,EAAA,CAAG,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,EAAG,EAAE,CAAA;AACtD;;;ACxCO,IAAM,OAAA,GAAU;;;ACkBvB,IAAM,UAAA,GAAa,EAAA;AAGnB,IAAM,SAAA,GAAY,GAAA;AAClB,IAAM,YAAA,GAAe,IAAA;AAErB,IAAM,WAAA,GAAc,IAAA;AAEpB,IAAM,QAAA,GAAW,EAAA;AAIV,SAAS,OAAA,GAAkB;AAChC,EAAA,OAAO,QAAA,EAAO,CAAE,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAClC;AAGA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,IAAI,OAAO,gBAAgB,WAAA,EAAa,OAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,CAAC,CAAA,CAAE,MAAA;AAE3E,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,SAAoB,MAAA,CAAO,UAAA,CAAW,GAAG,MAAM,CAAA;AACrE,EAAA,OAAO,CAAA,CAAE,MAAA;AACX;AAUO,SAAS,SAAS,GAAA,EAA4C;AACnE,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,MAAM,CAAA,GAAI,uCAAA,CAAwC,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AACjE,EAAA,IAAI,CAAC,GAAG,OAAO,IAAA;AACf,EAAA,MAAM,MAAA,GAAS,EAAE,CAAC,CAAA;AAClB,EAAA,MAAM,SAAA,GAAY,EAAE,CAAC,CAAA;AACrB,EAAA,MAAM,IAAA,GAAO,EAAE,CAAC,CAAA;AAChB,EAAA,MAAM,IAAA,GAAO,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AACrB,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,IAAA,EAAM,OAAO,IAAA;AAChC,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,KAAK,MAAA,GAAS,CAAA,GAAI,KAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,GAAI,EAAA;AAC5D,EAAA,IAAI,CAAC,WAAW,OAAO,IAAA;AACvB,EAAA,MAAM,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA;AAMlC,EAAA,MAAM,IAAA,GAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,kBAAkB,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAChE,EAAA,MAAM,YAAY,CAAA,EAAG,IAAI,CAAA,sBAAA,EAAyB,kBAAA,CAAmB,SAAS,CAAC,CAAA,CAAA;AAC/E,EAAA,OAAO,EAAE,SAAA,EAAW,MAAA,EAAQ,SAAA,EAAW,MAAM,SAAA,EAAU;AACzD;AAEA,IAAM,QAAA,GAAW,8DAAA;AACjB,IAAM,SAAA,GAAY,sCAAA;AAGlB,SAAS,MAAM,IAAA,EAAuB;AACpC,EAAA,IAAI,CAAC,MAAM,OAAO,KAAA;AAClB,EAAA,OAAO,EACL,IAAA,CAAK,QAAA,CAAS,cAAc,CAAA,IAC5B,IAAA,CAAK,WAAW,kBAAkB,CAAA,IAClC,KAAK,UAAA,CAAW,YAAY,KAC5B,IAAA,CAAK,UAAA,CAAW,qBAAqB,CAAA,IACrC,IAAA,CAAK,WAAW,kBAAkB,CAAA,CAAA;AAEtC;AAQO,SAAS,gBAAgB,KAAA,EAA0C;AACxE,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAC;AAKpB,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,IAAA,EAAM,SAAS,CAAA;AACzC,EAAA,MAAM,SAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,OAAO,KAAA,EAAO;AACvB,IAAA,IAAI,GAAA,CAAI,SAAS,YAAA,EAAc;AAC/B,IAAA,MAAM,IAAA,GAAO,IAAI,OAAA,EAAQ;AACzB,IAAA,IAAI,CAAC,IAAA,EAAM;AAGX,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI,IAAA,GAAO,EAAA;AACX,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,IAAA,MAAM,CAAA,GAAI,QAAA,CAAS,IAAA,CAAK,IAAI,CAAA;AAC5B,IAAA,IAAI,CAAA,EAAG;AACL,MAAA,EAAA,GAAK,EAAE,CAAC,CAAA;AACR,MAAA,IAAI,CAAA,CAAE,CAAC,CAAA,EAAG;AACR,QAAA,IAAA,GAAO,EAAE,CAAC,CAAA;AACV,QAAA,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,IAAK,CAAA;AACzB,QAAA,KAAA,GAAQ,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,IAAK,CAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,IAAA,GAAA,CAAQ,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA,EAAI,IAAA,EAAK;AAAA,MAC3B;AAAA,IACF,CAAA,MAAO;AACL,MAAA,MAAM,CAAA,GAAI,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA;AAC7B,MAAA,IAAI,CAAC,CAAA,EAAG;AACR,MAAA,EAAA,GAAK,EAAE,CAAC,CAAA;AACR,MAAA,IAAA,GAAO,EAAE,CAAC,CAAA;AACV,MAAA,MAAA,GAAS,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,IAAK,CAAA;AACzB,MAAA,KAAA,GAAQ,MAAA,CAAO,CAAA,CAAE,CAAC,CAAC,CAAA,IAAK,CAAA;AAAA,IAC1B;AACA,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,EAAA,EAAI;AAClB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA,MACV,UAAU,EAAA,IAAM,aAAA;AAAA,MAChB,QAAA,EAAU,IAAA;AAAA,MACV,QAAA,EAAU,IAAA;AAAA,MACV,MAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA,EAAQ,MAAM,IAAI;AAAA,KACnB,CAAA;AAAA,EACH;AAEA,EAAA,MAAA,CAAO,OAAA,EAAQ;AACf,EAAA,IAAI,MAAA,CAAO,SAAS,UAAA,EAAY,OAAO,OAAO,KAAA,CAAM,MAAA,CAAO,SAAS,UAAU,CAAA;AAC9E,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,eAAe,GAAA,EAAiE;AAC9F,EAAA,IAAI,eAAe,KAAA,EAAO;AAIxB,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,EAAK,MAAM,CAAA;AAC7B,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,SAAS,CAAA;AACnC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,EAAK,OAAO,CAAA;AAC/B,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,GAAO,OAAA;AAAA,MAChD,SAAS,OAAO,OAAA,KAAY,YAAY,OAAA,GAAU,OAAA,GAAU,IAAI,GAAG,CAAA;AAAA,MACnE,KAAA,EAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ;AAAA,KAC7C;AAAA,EACF;AACA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,GAAA,EAAI;AAClE,EAAA,IAAI;AACF,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,IAAA,CAAK,UAAU,GAAG,CAAA,IAAK,GAAA,CAAI,GAAG,CAAA,EAAE;AAAA,EACnE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,GAAA,CAAI,GAAG,CAAA,EAAE;AAAA,EAC5C;AACF;AAIA,SAAS,IAAA,CAAK,GAAY,CAAA,EAAoB;AAC5C,EAAA,IAAI;AACF,IAAA,OAAQ,EAA8B,CAAC,CAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAIA,SAAS,IAAI,CAAA,EAAoB;AAC/B,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,CAAC,CAAA;AAAA,EACjB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,mBAAA;AAAA,EACT;AACF;AAsBA,SAAS,UAAU,CAAA,EAAoB;AACrC,EAAA,MAAM,CAAA,GAAI,OAAO,CAAA,KAAM,QAAA,GAAW,KAAK,MAAM;AAC3C,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,CAAC,CAAA,IAAK,OAAO,CAAC,CAAA;AAAA,IACtC,CAAA,CAAA,MAAQ;AACN,MAAA,IAAI;AACF,QAAA,OAAO,OAAO,CAAC,CAAA;AAAA,MACjB,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,mBAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAA,GAAG;AACH,EAAA,OAAO,EAAE,MAAA,GAAS,WAAA,GAAc,EAAE,KAAA,CAAM,CAAA,EAAG,WAAW,CAAA,GAAI,CAAA;AAC5D;AAOO,SAAS,iBAAiB,KAAA,EAAqC;AACpE,EAAA,MAAM,EAAE,OAAO,OAAA,GAAU,IAAI,QAAA,EAAU,UAAA,GAAa,OAAM,GAAI,KAAA;AAC9D,EAAA,MAAM,IAAA,GAAO,eAAe,KAAK,CAAA;AACjC,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,KAAY,KAAA;AACpC,EAAA,MAAM,KAAA,GAAqB,OAAA,CAAQ,KAAA,KAAU,OAAA,GAAU,OAAA,GAAU,OAAA,CAAA;AAEjE,EAAA,MAAM,IAAA,GAA+B,EAAE,OAAA,EAAS,MAAA,CAAO,OAAO,CAAA,EAAE;AAChE,EAAA,IAAI,QAAA,CAAS,OAAA,EAAS,IAAA,CAAK,OAAA,GAAU,QAAA,CAAS,OAAA;AAC9C,EAAA,IAAI,QAAA,CAAS,SAAA,EAAW,IAAA,CAAK,OAAA,GAAU,QAAA,CAAS,SAAA;AAKhD,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAS,OAAA,CAAQ,UAAA,IAAc,EAAC;AACtC,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,EAAG;AAClC,MAAA,IAAI,KAAK,QAAA,EAAU;AACnB,MAAA,IAAI;AACF,QAAA,MAAM,GAAA,GAAM,MAAM,CAAC,CAAA;AACnB,QAAA,IAAI,GAAA,KAAQ,KAAA,CAAA,IAAa,GAAA,KAAQ,IAAA,EAAM;AACvC,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,SAAA,CAAU,SAAA,CAAU,GAAG,GAAG,UAAU,CAAA;AAC9C,QAAA,CAAA,EAAA;AAAA,MACF,CAAA,CAAA,MAAQ;AACN,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,MAAM,KAAA,GAAqB;AAAA,IACzB,QAAA,EAAU,KAAA,CAAM,EAAA,IAAM,OAAA,EAAQ;AAAA,IAC9B,SAAA,EAAA,CAAY,KAAA,CAAM,GAAA,IAAO,IAAA,CAAK,KAAI,IAAK,GAAA;AAAA,IACvC,QAAA,EAAU,YAAA;AAAA,IACV,KAAA;AAAA,IACA,QAAQ,QAAA,CAAS,OAAA;AAAA,IACjB,aAAa,QAAA,CAAS,WAAA;AAAA,IACtB,SAAS,QAAA,CAAS,OAAA;AAAA,IAClB,SAAA,EAAW;AAAA,MACT,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,KAAA,EAAO,SAAA,CAAU,IAAA,CAAK,OAAA,EAAS,UAAU,CAAA;AAAA,UACzC,YAAY,EAAE,MAAA,EAAQ,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA;AAAE;AACpD;AACF,KACF;AAAA,IACA,IAAA;AAAA,IACA,GAAA,EAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,SAAS,OAAA;AAAQ,GAChD;AACA,EAAA,IAAI,SAAS,MAAA,EAAQ,KAAA,CAAM,OAAO,EAAE,EAAA,EAAI,SAAS,MAAA,EAAO;AACxD,EAAA,OAAO,KAAA;AACT;AAYO,SAAS,aAAA,CAAc,KAAA,EAAoB,GAAA,EAAU,MAAA,EAAyB;AACnF,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACpC,EAAA,MAAM,MAAA,GAAS,KAAK,SAAA,CAAU;AAAA,IAC5B,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,KAAK,GAAA,CAAI,IAAA;AAAA,IACT,OAAA,EAAS,MAAA,IAAA,iBAAU,IAAI,IAAA,IAAO,WAAA;AAAY,GAC3C,CAAA;AACD,EAAA,MAAM,UAAA,GAAa,KAAK,SAAA,CAAU;AAAA,IAChC,IAAA,EAAM,OAAA;AAAA,IACN,YAAA,EAAc,kBAAA;AAAA,IACd,MAAA,EAAQ,QAAQ,OAAO;AAAA,GACxB,CAAA;AACD,EAAA,OAAO,GAAG,MAAM;AAAA,EAAK,UAAU;AAAA,EAAK,OAAO;AAAA,CAAA;AAC7C;AC1QA,IAAM,SAAA,GAAY,IAAA;AAYX,SAAS,OAAO,CAAA,EAAmB;AACxC,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,KAAA,MAAW,QAAQ,CAAC,UAAA,EAAY,QAAA,EAAY,UAAA,EAAY,UAAU,CAAA,EAAG;AACnE,IAAA,IAAI,IAAI,IAAA,KAAS,CAAA;AACjB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK;AACjC,MAAA,CAAA,IAAK,CAAA,CAAE,WAAW,CAAC,CAAA;AAEnB,MAAA,CAAA,GAAK,CAAA,IAAK,CAAA,IAAK,CAAA,CAAA,IAAM,CAAA,IAAK,CAAA,CAAA,IAAM,KAAK,CAAA,CAAA,IAAM,CAAA,IAAK,CAAA,CAAA,IAAM,CAAA,IAAK,EAAA,CAAA,KAAS,CAAA;AAAA,IACtE;AACA,IAAA,GAAA,IAAO,EAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,GAAA;AACT;AAYA,SAAS,QAAQ,CAAA,EAAgC;AAC/C,EAAA,MAAM,MAAA,GAAS,EAAE,QAAA,IAAY,EAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,EAAE,QAAA,IAAY,aAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,EAAE,MAAA,IAAU,CAAA;AACzB,EAAA,MAAM,MAAA,GAAS,EAAE,KAAA,IAAS,CAAA;AAC1B,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAA,EAAQ,CAAA,EAAG,MAAA,CAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE,CAAC,CAAA,EAAA,CAAA;AAAA,IACxD,YAAA,EAAc,IAAA;AAAA,IACd,MAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA,EAAQ,EAAE,MAAA,IAAU,KAAA;AAAA,IACpB,IAAA,EAAM,YAAA;AAAA,IACN,QAAA,EAAU,KAAA;AAAA,IACV,eAAA,EAAiB,yCAAA;AAAA,IACjB,aAAA,EAAe,IAAA;AAAA,IACf,MAAA,EAAQ;AAAA,GACV;AACF;AAGA,SAASA,SAAAA,CAAS,GAAW,GAAA,EAAqB;AAChD,EAAA,IAAI,CAAA,CAAE,MAAA,IAAU,GAAA,EAAK,OAAO,CAAA;AAC5B,EAAA,IAAI,GAAA,GAAM,GAAA;AACV,EAAA,MAAM,CAAA,GAAI,CAAA,CAAE,UAAA,CAAW,GAAA,GAAM,CAAC,CAAA;AAE9B,EAAA,IAAI,CAAA,IAAK,KAAA,IAAU,CAAA,IAAK,KAAA,EAAQ,GAAA,EAAA;AAChC,EAAA,OAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AACvB;AAQO,SAAS,cAAA,CACd,KACA,IAAA,EACgB;AAChB,EAAA,MAAM,CAAA,GAAI,eAAe,GAAG,CAAA;AAC5B,EAAA,MAAM,SAAS,eAAA,CAAgB,CAAA,CAAE,KAAK,CAAA,CAAE,KAAA,CAAM,GAAW,CAAA;AACzD,EAAA,MAAM,KAAA,GAAwB;AAAA,IAC5B,IAAI,IAAA,CAAK,EAAA;AAAA,IACT,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,KAAA,EAAOA,SAAAA,CAAS,CAAA,CAAE,OAAA,EAAS,SAAS,CAAA;AAAA,IACpC,SAAA,EAAW;AAAA,MACT,IAAA,EAAM,SAAA;AAAA,MACN,SAAS,IAAA,CAAK,OAAA;AAAA;AAAA;AAAA,MAGd,SAAA,EAAW,EAAE,GAAA,YAAe,KAAA;AAAA;AAC9B,GACF;AACA,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AAGrB,IAAA,KAAA,CAAM,UAAA,GAAa,EAAE,IAAA,EAAM,UAAA,EAAY,QAAQ,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA,EAAE;AAAA,EACrE;AACA,EAAA,OAAO,KAAA;AACT;AAeO,SAAS,YAAY,KAAA,EAA+B;AACzD,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,UAAA,EAAY,MAAA,IAAU,EAAC;AAC5C,EAAA,MAAM,SAAS,MAAA,CACZ,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,MAAM,CAAA,CACtB,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAA,CAAE,YAAY,CAAA,CAAA,EAAI,CAAA,CAAE,MAAM,CAAA,CAAE,CAAA;AAC7C,EAAA,OAAO,MAAA,CAAO,CAAC,KAAA,CAAM,IAAA,EAAM,GAAG,MAAM,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAClD;AAUO,SAAS,mBAAA,CACd,KACA,IAAA,EACqB;AACrB,EAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,GAAA,EAAK,IAAI,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,UAAA,EAAY,MAAA,IAAU,EAAC;AAC5C,EAAA,MAAM,EAAA,GAAK,YAAY,KAAK,CAAA;AAC5B,EAAA,OAAO;AAAA,IACL,eAAA,EAAiB,CAAC,KAAK,CAAA;AAAA,IACvB,sBAAA,EAAwB,EAAA;AAAA;AAAA;AAAA,IAGxB,6BAAA,EAA+B,CAAC,EAAE,IAAA,EAAM,UAAU,CAAA;AAAA,IAClD,iBAAiB,KAAA,CAAM,IAAA;AAAA,IACvB,oBAAoB,KAAA,CAAM,KAAA;AAAA,IAC1B,gBAAA,EAAkB,KAAK,KAAA,IAAS,OAAA;AAAA,IAChC,oBAAoB,IAAA,CAAK,OAAA;AAAA,IACzB,oBAAA,EAAsB,KAAA,CAAM,SAAA,EAAW,SAAA,IAAa,KAAA;AAAA,IACpD,gBAAA,EAAkB,CAAC,KAAA,CAAM,IAAI,CAAA;AAAA,IAC7B,iBAAA,EAAmB,CAAC,KAAA,CAAM,KAAK,CAAA;AAAA,IAC/B,kBAAA,EAAoB,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAmB,CAAC,CAAC,CAAC,CAAA;AAAA,IAC9E,oBAAA,EAAsB,MAAA,CACnB,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,aAAA,IAAiB,CAAA,CAAE,YAAY,EAC5C,MAAA,CAAO,CAAC,CAAA,KAAmB,CAAC,CAAC,CAAC;AAAA,GACnC;AACF;;;AC3LA,IAAM,GAAA,GAAM;AAAA,EACV,OAAA,EAAS,YAAA;AAAA,EACT,UAAA,EAAY,gBAAA;AAAA,EACZ,MAAA,EAAQ;AACV,CAAA;AAGA,IAAM,cAAA,GAAiB,KAAK,EAAA,GAAK,GAAA;AAEjC,SAAS,EAAA,GAA0B;AACjC,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,MAAA,CAAO,cAAc,OAAO,KAAA,CAAA;AAClE,IAAA,OAAO,MAAA,CAAO,YAAA;AAAA,EAChB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAcO,SAAS,MAAA,GAA6B;AAC3C,EAAA,OAAO,UAAS,IAAK,MAAA;AACvB;AAeO,SAAS,SAAA,CAAU,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,EAAuB;AAC9D,EAAA,MAAM,IAAI,EAAA,EAAG;AACb,EAAA,IAAI,CAAC,GAAG,OAAO,MAAA;AACf,EAAA,IAAI,KAAA,GAA6B,IAAA;AACjC,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,KAAK,KAAA,CAAM,CAAA,CAAE,QAAQ,GAAA,CAAI,OAAO,KAAK,MAAM,CAAA;AAAA,EACrD,CAAA,CAAA,MAAQ;AACN,IAAA,KAAA,GAAQ,IAAA;AAAA,EACV;AACA,EAAA,IAAI,CAAC,KAAA,IAAS,GAAA,GAAM,KAAA,CAAM,OAAO,cAAA,EAAgB;AAC/C,IAAA,KAAA,GAAQ,EAAE,EAAA,EAAI,QAAA,CAAO,GAAG,CAAA,EAAG,MAAM,GAAA,EAAI;AAAA,EACvC,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,IAAA,GAAO,GAAA;AAAA,EACf;AACA,EAAA,CAAA,CAAE,QAAQ,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,EAAA;AACf;AAGO,SAAS,aAAA,GAAyC;AACvD,EAAA,MAAM,IAAI,EAAA,EAAG;AACb,EAAA,IAAI,CAAC,GAAG,OAAO,MAAA;AACf,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA;AAClC,IAAA,OAAO,CAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAoB,KAAA,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,kBAAkB,CAAA,EAA6B;AAC7D,EAAA,MAAM,IAAI,EAAA,EAAG;AACb,EAAA,MAAM,WAAW,aAAA,EAAc;AAC/B,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,IAAI,CAAA,IAAK,OAAA,CAAQ,GAAA,CAAI,YAAY,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAClD,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,SAAA,GAAgC;AAC9C,EAAA,MAAM,IAAI,EAAA,EAAG;AACb,EAAA,IAAI,CAAC,GAAG,OAAO,MAAA;AACf,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AAC9B,IAAA,OAAO,CAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAe,KAAA,CAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAGO,SAAS,YAAY,KAAA,EAAuB;AACjD,EAAA,MAAM,IAAI,EAAA,EAAG;AACb,EAAA,MAAM,GAAA,GAAM,SAAA,EAAU,IAAK,EAAC;AAC5B,EAAA,MAAM,IAAA,GAAe;AAAA,IACnB,UAAA,EAAY,GAAA,CAAI,UAAA,IAAc,KAAA,CAAM,UAAA;AAAA,IACpC,OAAA,EAAS,KAAA,CAAM,OAAA,IAAW,GAAA,CAAI,OAAA;AAAA,IAC9B,OAAA,EAAS,GAAA,CAAI,OAAA,IAAW,KAAA,CAAM;AAAA,GAChC;AACA,EAAA,IAAI,CAAA,IAAK,OAAA,CAAQ,GAAA,CAAI,QAAQ,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AACjD,EAAA,OAAO,IAAA;AACT;;;ACvCA,IAAM,UAAA,GAAa,WAAA;AACnB,IAAM,YAAA,GAAe,sBAAA;AACrB,IAAM,qBAAA,GAAwB,+BAAA;AAO9B,IAAM,mBAAA,GAAsB,YAAA;AAM5B,SAAS,UAAA,GAAiC;AACxC,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,OAAA,KAAY,WAAA,IAAe,OAAA,CAAQ,GAAA,EAAK;AACjD,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,2BAAA,IAA+B,OAAA,CAAQ,IAAI,eAAA,IAAmB,KAAA,CAAA;AAAA,IACnF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,MAAA;AACT;AAGA,SAAS,QAAQ,IAAA,EAAkC;AACjD,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,YAAY,WAAA,IAAe,OAAA,CAAQ,KAAK,OAAO,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,IAAK,KAAA,CAAA;AAAA,EACjF,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,MAAA;AACT;AAIA,SAAS,WAAA,CAAY,GAAA,EAAa,GAAA,EAAa,KAAA,EAAuB;AACpE,EAAA,OAAO,GAAA,IAAO,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,GAAI,MAAM,GAAA,CAAA,GAAO,GAAA,GAAM,GAAA,GAAM,kBAAA,CAAmB,KAAK,CAAA;AACrF;AAQA,SAASC,gBAAe,GAAA,EAAyB;AAC/C,EAAA,MAAM,CAAA,GAAI,eAAmB,GAAG,CAAA;AAChC,EAAA,OAAO,EAAE,MAAM,CAAA,CAAE,IAAA,EAAM,SAAS,CAAA,CAAE,OAAA,EAAS,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM;AAC5D;AASA,IAAM,YAAY,MAAM,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,QAAA,KAAa,WAAA;AAQ7E,SAAS,eAAe,KAAA,EAAmC;AACzD,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,EAAE,KAAA,EAAO,CAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,IAC9B,CAAA,CAAA,MAAQ;AACN,MAAA,IAAI;AAGF,QAAA,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,CAAA,EAAG,UAAA,EAAY,EAAE,eAAA,EAAiB,IAAA,EAAK,EAAG,CAAC,CAAA;AAAA,MAC5E,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,SAAS,CAAA,GAAI,YAAA,GAAe,MAAM,IAAA,CAAK,GAAG,IAAI,IAAA,GAAO,IAAA;AACpE;AAgBA,IAAM,mBAAN,MAA4C;AAAA,EAC1C,IAAA,CACE,GAAA,EACA,IAAA,EACA,IAAA,EAOM;AACN,IAAA,IAAI,KAAK,MAAA,IAAU,SAAA,MAAe,OAAO,SAAA,CAAU,eAAe,UAAA,EAAY;AAC5E,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,GAAY,WAAA,CAAY,KAAK,YAAA,EAAc,IAAA,CAAK,SAAS,CAAA,GAAI,GAAA;AACpF,MAAA,IAAI;AAIF,QAAA,MAAM,SAAS,SAAA,CAAU,UAAA;AAAA,UACvB,SAAA;AAAA,UACA,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,IAAA,EAAM,qBAAqB;AAAA,SAChD;AACA,QAAA,IAAI,MAAA,EAAQ;AACZ,QAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,+CAA+C,CAAA;AAAA,MAC9E,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAQjC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,SAAA,KAAc,MAAA,IAAa,KAAK,WAAA,KAAgB,MAAA;AACpE,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,cAAA,EAAgB,MAAA,GAAS,mBAAA,GAAuB,IAAA,CAAK,WAAA,IAAe;AAAA,KACtE;AACA,IAAA,MAAM,MAAA,GAAS,MAAA,GAAS,MAAA,GAAa,IAAA,CAAK,aAAa,IAAA,CAAK,KAAA;AAC5D,IAAA,IAAI,MAAA,EAAQ,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,MAAM,CAAA,CAAA;AACpD,IAAA,KAAK,KAAA,CAAM,SAAS,WAAA,CAAY,GAAA,EAAK,cAAc,IAAA,CAAK,SAAU,IAAI,GAAA,EAAK;AAAA,MACzE,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA,EAAW,IAAA;AAAA,MACX,WAAA,EAAa,SAAS,MAAA,GAAS;AAAA,KAChC,CAAA,CACE,IAAA,CAAK,CAAC,GAAA,KAAQ;AAKb,MAAA,IAAI,CAAC,GAAA,CAAI,EAAA,IAAM,IAAA,CAAK,KAAA,EAAO;AACzB,QAAA,OAAA,CAAQ,IAAA,CAAK,2BAA2B,GAAA,CAAI,MAAA,EAAQ,IAAI,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,MACvE;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,CAAA,KAAe;AACrB,MAAA,IAAI,IAAA,CAAK,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,uBAAA,EAAyB,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,IAC5E,CAAC,CAAA;AAAA,EACL;AACF,CAAA;AAEO,IAAM,YAAN,MAAgB;AAAA,EAmBrB,YAAY,MAAA,EAAyB;AAbrC,IAAA,IAAA,CAAQ,QAAqB,EAAC;AAC9B,IAAA,IAAA,CAAQ,KAAA,GAA8C,IAAA;AAEtD,IAAA,IAAA,CAAQ,WAAA,GAA2B,EAAE,GAAA,EAAK,EAAC,EAAE;AAC7C,IAAA,IAAA,CAAQ,SAAiB,EAAC;AAC1B,IAAA,IAAA,CAAQ,OAAA,GAAU,KAAA;AAMlB;AAAA,IAAA,IAAA,CAAQ,SAAA,GAAY,KAAA;AAGlB,IAAA,IAAA,CAAK,GAAA,GAAM;AAAA,MACT,IAAA,EAAM,YAAA;AAAA,MACN,SAAA,EAAW,EAAA;AAAA,MACX,eAAA,EAAiB,GAAA;AAAA,MACjB,OAAA,EAAS,IAAA;AAAA,MACT,aAAA,EAAe,IAAA;AAAA,MACf,GAAG,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaH,SAAA,EAAW,MAAA,CAAO,SAAA,IAAa,OAAA,CAAQ,6BAA6B;AAAA,KACtE;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,MAAA,CAAO,SAAA,IAAa,IAAI,gBAAA,EAAiB;AAM1D,IAAA,IAAA,CAAK,GAAA,GAAM,QAAA;AAAA,MACT,MAAA,CAAO,GAAA,IAAO,UAAA,EAAW,IAAK,aAAA,CAAc,KAAK,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,SAAS;AAAA,KAClF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAA,EAA+B;AACnC,IAAA,IAAI,MAAA,CAAO,aAAa,CAAC,IAAA,CAAK,IAAI,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,MAAA,CAAO,SAAA;AACzE,IAAA,IAAI,MAAA,CAAO,YAAY,CAAC,IAAA,CAAK,IAAI,QAAA,EAAU,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,MAAA,CAAO,QAAA;AACtE,IAAA,IAAI,CAAC,KAAK,GAAA,EAAK;AACb,MAAA,IAAA,CAAK,GAAA,GAAM,QAAA;AAAA,QACT,MAAA,CAAO,GAAA,IAAO,UAAA,EAAW,IAAK,aAAA,CAAc,KAAK,GAAA,CAAI,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,SAAS;AAAA,OAClF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,iBAAA,GAA6B;AAC/B,IAAA,OAAO,KAAK,GAAA,KAAQ,IAAA;AAAA,EACtB;AAAA;AAAA;AAAA,EAIA,IAAI,cAAA,GAAqC;AACvC,IAAA,OAAO,KAAK,GAAA,EAAK,SAAA;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAA,GAAa;AACX,IAAA,IAAI,IAAA,CAAK,OAAA,IAAW,CAAC,IAAA,CAAK,IAAI,OAAA,EAAS;AACvC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAI,CAAC,WAAU,EAAG;AAElB,IAAA,MAAM,SAAS,gBAAA,CAAiB,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,SAAS,QAAQ,CAAA;AACzE,IAAA,IAAA,CAAK,WAAA,GAAc,eAAe,MAAM,CAAA,GACpC,kBAAkB,MAAM,CAAA,GACxB,eAAc,IAAK,MAAA;AACvB,IAAA,IAAA,CAAK,SAAS,WAAA,CAAY;AAAA,MACxB,SAAS,IAAA,CAAK,WAAA,CAAY,OAAA,IAAW,aAAA,CAAc,KAAK,WAAW,CAAA;AAAA,MACnE,OAAA,EAAS,KAAK,WAAA,CAAY;AAAA,KAC3B,CAAA;AAED,IAAA,MAAM,cAAc,MAAM;AACxB,MAAA,IAAI,QAAA,CAAS,eAAA,KAAoB,QAAA,EAAU,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IAC5D,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,oBAAoB,WAAW,CAAA;AACvD,IAAA,MAAA,CAAO,iBAAiB,UAAA,EAAY,MAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAA;AAM1D,IAAA,IAAI,IAAA,CAAK,IAAI,aAAA,EAAe;AAC1B,MAAA,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,CAAC,CAAA,KAAkB;AAClD,QAAA,IAAA,CAAK,YAAA,CAAa,EAAE,KAAA,IAAS,CAAA,CAAE,SAAS,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,MAC5D,CAAC,CAAA;AACD,MAAA,MAAA,CAAO,gBAAA,CAAiB,oBAAA,EAAsB,CAAC,CAAA,KAA6B;AAC1E,QAAA,IAAA,CAAK,aAAa,CAAA,CAAE,MAAA,EAAQ,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,MAChD,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,QAAA,CAAS,UAAkB,MAAA,EAAwC;AACjE,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,QAAQ,UAAA,EAAY,MAAA,EAAW,EAAE,UAAA,EAAY,QAAQ,CAAA;AAAA,EAC5D;AAAA;AAAA;AAAA,EAIA,KAAA,CAAM,SAAiB,MAAA,EAAwC;AAC7D,IAAA,IAAA,CAAK,QAAQ,OAAA,EAAS,MAAA,EAAW,EAAE,OAAA,EAAS,UAAA,EAAY,QAAQ,CAAA;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,QAAA,CAAS,MAAe,UAAA,EAA4C;AAKlE,IAAA,MAAM,IAAI,IAAA,KAAS,SAAA,EAAU,GAAI,MAAA,CAAO,SAAS,QAAA,GAAW,MAAA,CAAA;AAK5D,IAAA,MAAM,IAAA,GAAA,CAAQ,KAAK,EAAA,IAAM,IAAA,IAAQ,WAAU,GAAI,MAAA,CAAO,SAAS,IAAA,GAAO,EAAA,CAAA;AACtE,IAAA,IAAI,IAAA,KAAS,KAAK,OAAA,EAAS;AAC3B,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,QAAQ,UAAA,EAAY,QAAA,EAAU,EAAE,IAAA,EAAM,CAAA,EAAG,YAAY,CAAA;AAAA,EAC5D;AAAA;AAAA;AAAA,EAIA,OAAA,CACE,KAAA,EACA,UAAA,EACA,QAAA,EACM;AACN,IAAA,IAAA,CAAK,QAAQ,OAAA,EAAS,KAAA,EAAO,EAAE,UAAA,EAAY,GAAG,UAAU,CAAA;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,YAAA,CAAa,KAAc,OAAA,EAAqC;AAE9D,IAAA,IAAI,KAAK,SAAA,EAAW;AACpB,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AACjB,IAAA,IAAI;AAQF,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,SAAA,CAAU,KAAK,OAAO,CAAA;AAAA,MAC7B,CAAA,CAAA,MAAQ;AAAA,MAER;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,IAAA;AACpC,QAAA,MAAM,EAAA,GAAKA,gBAAe,GAAG,CAAA;AAC7B,QAAA,EAAA,CAAG,OAAA,GAAU,OAAA;AAgBb,QAAA,IAAA,CAAK,OAAA,CAAQ,SAAS,SAAA,EAAW;AAAA,UAC/B,KAAA,EAAO,EAAA;AAAA,UACP,UAAA,EAAY;AAAA,YACV,GAAG,OAAA,EAAS,UAAA;AAAA,YACZ,GAAG,oBAAoB,GAAA,EAAK;AAAA,cAC1B,OAAA;AAAA,cACA,IAAI,QAAA,EAAO;AAAA,cACX,OAAO,OAAA,EAAS;AAAA,aACjB;AAAA;AACH,SACD,CAAA;AACD,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,SAAA,GAAY,KAAA;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,UAAU,KAAA,EAAqB;AAC7B,IAAA,IAAA,CAAK,MAAA,GAAS,YAAY,KAAK,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,KAAA,CAAM,SAAS,KAAA,EAAa;AAC1B,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,WAAW,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AAClD,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA;AACnB,IAAA,IAAA,CAAK,QAAQ,EAAC;AACd,IAAA,IAAA,CAAK,UAAA,EAAW;AAchB,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,QAAA,IAAW,IAAK,MAAA;AACvC,IAAA,MAAM,MAAM,KAAA,GAAQ,MAAA,GAAY,KAAK,GAAA,CAAI,SAAA,EAAW,MAAK,IAAK,MAAA;AAG9D,IAAA,MAAM,SAAA,GAAY,UAAU,CAAC,KAAA;AAC7B,IAAA,MAAM,IAAA,GAAO,eAAe,KAAK,CAAA;AACjC,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAA,CAAQ,MAAM,oDAA+C,CAAA;AACjF,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,IAAI,KAAA,EAAO,OAAA,CAAQ,MAAM,sBAAA,EAAmB,UAAA,EAAY,MAAM,MAAM,CAAA;AAC7E,IAAA,IAAA,CAAK,UAAU,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,IAAA,GAAO,YAAY,IAAA,EAAM;AAAA,MACpD,MAAA,EAAQ,SAAA;AAAA,MACR,KAAA;AAAA,MACA,SAAA,EAAW,GAAA;AAAA,MACX,KAAA,EAAO,KAAK,GAAA,CAAI;AAAA,KACjB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,SAAA,CAAU,KAAc,OAAA,EAAqC;AACnE,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,OAAA,IAAW,CAAC,KAAK,GAAA,EAAK;AACpC,IAAA,MAAM,QAAQ,gBAAA,CAAiB;AAAA,MAC7B,KAAA,EAAO,GAAA;AAAA,MACP,OAAA;AAAA,MACA,QAAA,EAAU,KAAK,aAAA,EAAc;AAAA,MAC7B,UAAA,EAAY,IAAA,CAAK,GAAA,CAAI,UAAA,IAAc;AAAA,KACpC,CAAA;AACD,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,KAAA,EAAO,IAAA,CAAK,GAAG,CAAA;AAC1C,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,wBAAmB,IAAA,CAAK,GAAA,CAAI,SAAA,EAAW,KAAA,CAAM,QAAQ,CAAA;AACvF,IAAA,IAAA,CAAK,SAAA,CAAU,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,WAAW,IAAA,EAAM;AAAA,MAC5C,MAAA,EAAQ,KAAA;AAAA,MACR,WAAA,EAAa,qBAAA;AAAA,MACb,KAAA,EAAO,KAAK,GAAA,CAAI;AAAA,KACjB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA,EAIQ,aAAA,GAA+B;AACrC,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,IAAA,CAAK,QAAA,IAAY,MAAA,EAAO;AAAA,MAChC,WAAW,SAAA,EAAU;AAAA,MACrB,OAAA,EAAS,KAAK,GAAA,CAAI,OAAA;AAAA,MAClB,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,OAAA,IAAW,QAAQ,2BAA2B,CAAA;AAAA,MAChE,WAAA,EAAa,IAAA,CAAK,GAAA,CAAI,WAAA,IAAe,QAAQ,UAAU;AAAA,KACzD;AAAA,EACF;AAAA,EAEQ,OAAA,CAAQ,IAAA,EAAiB,KAAA,EAA2B,KAAA,EAAiC;AAC3F,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS;AACvB,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,IAAA,EAAK;AAC7B,IAAA,IAAA,CAAK,MAAM,IAAA,CAAK,IAAA,CAAK,MAAM,IAAA,EAAM,KAAA,EAAO,KAAK,CAAC,CAAA;AAC9C,IAAA,IAAI,KAAK,KAAA,CAAM,MAAA,IAAU,KAAK,GAAA,CAAI,SAAA,OAAgB,KAAA,EAAM;AAAA,cAC9C,QAAA,EAAS;AAAA,EACrB;AAAA,EAEQ,KAAA,CAAM,IAAA,EAAiB,KAAA,EAA2B,KAAA,EAAsC;AAC9F,IAAA,MAAM,OAAO,MAAA,EAAO;AACpB,IAAA,MAAM,IAAA,GAAkB;AAAA,MACtB,WAAW,QAAA,EAAO;AAAA,MAClB,IAAA,EAAM,IAAA;AAAA,MACN,KAAA;AAAA,MACA,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,UAAA,EAAY,KAAK,QAAA,IAAY,IAAA;AAAA,MAC7B,WAAA,EAAa,IAAA;AAAA,MACb,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,WAAW,SAAA,EAAU;AAAA,MACrB,OAAA,EAAS,KAAK,GAAA,CAAI,OAAA;AAAA,MAClB,QAAA,EAAU,KAAK,WAAA,CAAY,QAAA;AAAA,MAC3B,GAAA,EAAK,KAAK,WAAA,CAAY,GAAA;AAAA,MACtB,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,KAAK,WAAA,CAAY,OAAA;AAAA,MACjD,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,KAAK,WAAA,CAAY,OAAA;AAAA,MACjD,UAAA,EAAY,KAAK,MAAA,CAAO,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaxB,GAAA,EAAK,SAAA,EAAU,GAAI,MAAA,CAAO,SAAS,IAAA,GAAO,MAAA;AAAA,MAC1C,IAAA,EAAM,SAAA,EAAU,GAAI,MAAA,CAAO,SAAS,QAAA,GAAW,MAAA;AAAA,MAC/C,OAAA,EAAS,cAAA;AAAA,MACT,cAAA,EAAgB,OAAA;AAAA,MAChB,GAAG;AAAA,KACL;AAsBA,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,UAAA,IAAc,KAAA;AAC1C,IAAA,IAAI,KAAK,GAAA,EAAK,IAAA,CAAK,MAAM,SAAA,CAAU,IAAA,CAAK,KAAK,UAAU,CAAA;AACvD,IAAA,IAAI,KAAK,IAAA,EAAM,IAAA,CAAK,OAAO,SAAA,CAAU,IAAA,CAAK,MAAM,UAAU,CAAA;AAC1D,IAAA,IAAI,KAAK,QAAA,EAAU,IAAA,CAAK,WAAW,SAAA,CAAU,IAAA,CAAK,UAAU,UAAU,CAAA;AACtE,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEQ,QAAA,GAAiB;AACvB,IAAA,IAAI,IAAA,CAAK,KAAA,IAAS,CAAC,IAAA,CAAK,IAAI,OAAA,EAAS;AACrC,IAAA,IAAA,CAAK,KAAA,GAAQ,WAAW,MAAM;AAC5B,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA;AAAA,EAC7B;AAAA,EAEQ,UAAA,GAAmB;AACzB,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,YAAA,CAAa,KAAK,KAAK,CAAA;AACvB,MAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAAA,IACf;AAAA,EACF;AACF;AAsBA,IAAM,OAAA,mBAAU,MAAA,CAAO,GAAA,CAAI,qBAAqB,CAAA;AAEhD,SAAS,QAAA,GAAmC;AAC1C,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,MAAM,QAAA,GAAW,EAAE,OAAO,CAAA;AAC1B,EAAA,IAAI,UAAU,OAAO,QAAA;AACrB,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAuB;AACzC,EAAA,CAAA,CAAE,OAAO,CAAA,GAAI,KAAA;AACb,EAAA,OAAO,KAAA;AACT;AAKO,SAAS,gBAAgB,MAAA,EAAoC;AAQlE,EAAA,IAAI,CAAC,WAAU,IAAK,MAAA,CAAO,YAAY,KAAA,EAAO,OAAO,IAAI,SAAA,CAAU,MAAM,CAAA;AACzE,EAAA,MAAM,GAAA,GAAA,CAAO,MAAA,CAAO,IAAA,IAAQ,YAAA,IAAgB,OAAO,MAAA,CAAO,OAAA;AAC1D,EAAA,MAAM,UAAU,QAAA,EAAS;AACzB,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AAChC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,QAAA,CAAS,MAAM,MAAM,CAAA;AACrB,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GAAQ,IAAI,SAAA,CAAU,MAAM,CAAA;AAClC,EAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AACtB,EAAA,OAAO,KAAA;AACT;;;AChrBO,IAAM,KAAA,GAA6E;AAAA;AAAA,EAExF,MAAA,EAAQ;AAAA,IACN,KAAA,EAAO,QAAA;AAAA,IACP,OAAO,MAAA,CAAO,gBAAA;AAAA,IACd,QAAA,EAAU,QAAA;AAAA,IACV,MAAA,EAAQ,SAAS,QAAQ;AAAA,GAC3B;AAAA;AAAA,EAEA,IAAA,EAAM;AAAA,IACJ,KAAA,EAAO,MAAA;AAAA,IACP,OAAO,MAAA,CAAO,eAAA;AAAA,IACd,QAAA,EAAU,SAAA;AAAA,IACV,MAAA,EAAQ,SAAS,SAAS,CAAA;AAAA,IAC1B,MAAA,EAAQ,EAAE,QAAA,EAAU,MAAA,EAAQ,QAAQ,MAAA;AAAO,GAC7C;AAAA;AAAA,EAEA,aAAA,EAAe;AAAA,IACb,KAAA,EAAO,gBAAA;AAAA,IACP,OAAO,MAAA,CAAO,YAAA;AAAA,IACd,QAAA,EAAU,SAAA;AAAA,IACV,MAAA,EAAQ,SAAS,SAAS;AAAA,GAC5B;AAAA;AAAA;AAAA,EAGA,UAAA,EAAY;AAAA,IACV,KAAA,EAAO,YAAA;AAAA,IACP,OAAO,MAAA,CAAO,YAAA;AAAA,IACd,QAAA,EAAU,eAAA;AAAA,IACV,MAAA,EAAQ,SAAS,eAAe;AAAA;AAEpC;AAQO,IAAM,OAAA,GAAmE;AAAA,EAC9E,UAAA,EAAY,EAAE,KAAA,EAAO,aAAA,EAAe,OAAO,aAAA,EAAc;AAAA,EACzD,OAAA,EAAS,EAAE,KAAA,EAAO,SAAA,EAAW,OAAO,qBAAA,EAAsB;AAAA,EAC1D,OAAA,EAAS,EAAE,KAAA,EAAO,UAAA,EAAY,OAAO,eAAA;AACvC","file":"index.mjs","sourcesContent":["// Pure attribution helpers: parse first-touch UTM/referrer/refCode from a URL,\n// derive the acquisition channel, and compute the ISO week for the signup cohort.\n// No I/O, no globals — trivially testable.\n\nimport type { Attribution } from './types'\n\nconst SOCIAL_HOSTS = [\n 'facebook.', 'instagram.', 'twitter.', 'x.com', 't.co', 'linkedin.',\n 'reddit.', 'youtube.', 'tiktok.', 'pinterest.', 'news.ycombinator.com',\n]\nconst SEARCH_HOSTS = ['google.', 'bing.', 'duckduckgo.', 'yahoo.', 'baidu.', 'ecosia.']\n\n/** parseAttribution reads UTM params + ref/refCode from a query string and pairs\n * them with the referrer. `search` is a location.search value (\"?utm_source=…\"). */\nexport function parseAttribution(search: string, referrer: string): Attribution {\n const q = new URLSearchParams(search || '')\n const get = (k: string) => {\n const v = q.get(k)\n return v ? v.trim() : undefined\n }\n const a: Attribution = {\n utm: {\n source: get('utm_source'),\n medium: get('utm_medium'),\n campaign: get('utm_campaign'),\n term: get('utm_term'),\n content: get('utm_content'),\n },\n referrer: referrer ? referrer.trim() : undefined,\n refCode: get('ref') || get('refCode') || get('ref_code') || undefined,\n }\n a.channel = deriveChannel(a)\n return a\n}\n\n/** deriveChannel classifies the visit: paid | referral | social | organic | direct. */\nexport function deriveChannel(a: Attribution): string {\n const medium = (a.utm.medium || '').toLowerCase()\n if (/(cpc|ppc|paid|paidsearch|display|cpm)/.test(medium)) return 'paid'\n if (a.utm.source || a.utm.campaign) return 'campaign'\n if (a.refCode) return 'referral'\n const host = hostOf(a.referrer)\n if (!host) return 'direct'\n if (SOCIAL_HOSTS.some((h) => host.includes(h))) return 'social'\n if (SEARCH_HOSTS.some((h) => host.includes(h))) return 'organic'\n return 'referral'\n}\n\n/** hostOf extracts a bare lowercase host from a URL; \"\" when unparseable. */\nexport function hostOf(raw?: string): string {\n if (!raw) return ''\n let s = raw.trim()\n const scheme = s.indexOf('://')\n if (scheme >= 0) s = s.slice(scheme + 3)\n const cut = s.search(/[/?#]/)\n if (cut >= 0) s = s.slice(0, cut)\n const at = s.indexOf('@')\n if (at >= 0) s = s.slice(at + 1)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s.toLowerCase().trim()\n}\n\n/** hasAttribution reports whether anything was captured (so we don't persist an\n * empty first-touch that would shadow a later real one). */\nexport function hasAttribution(a: Attribution): boolean {\n return Boolean(\n a.utm.source || a.utm.medium || a.utm.campaign || a.utm.term ||\n a.utm.content || a.refCode || (a.referrer && hostOf(a.referrer)),\n )\n}\n\n/** isoWeek returns the ISO-8601 week label, e.g. \"2026-W28\". */\nexport function isoWeek(d: Date): string {\n // Copy to UTC midnight; ISO week: Thursday-anchored.\n const date = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()))\n const day = date.getUTCDay() || 7\n date.setUTCDate(date.getUTCDate() + 4 - day)\n const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1))\n const week = Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7)\n return `${date.getUTCFullYear()}-W${String(week).padStart(2, '0')}`\n}\n","/**\n * The product → Sentinel DSN registry.\n *\n * An app declares WHAT it is (`product: 'console'`); this module knows WHERE its\n * errors go. That split is the whole point: no surface has to learn a DSN, carry\n * a build argument, or grow a config file to report errors — declaring the\n * product it already declares is enough.\n *\n * A Sentinel DSN is PUBLIC by construction. It ships inside the client bundle and\n * is readable in devtools on any deployed page, and it grants exactly one\n * capability: submitting new events. It cannot read issues, projects, or any\n * other data. So committing it is not leaking a secret — it is recording a public\n * identifier next to the code that needs it. (Contrast the server-side collector\n * DSN in the `team-analytics-sentry` Secret, which is HMAC-derived and revocable\n * precisely because a server-side credential is NOT public.)\n *\n * Why a literal map instead of deriving `hanzo-${product}`: the projects predate\n * this registry and do not derive cleanly — `site` lives in `hanzo-ai`, not\n * `hanzo-site`. An explicit map is honest about that; a derivation rule plus an\n * exception table is the same data with a trap in it.\n *\n * Projects are org-scoped and named `<org>-<app>`. To add one: create the project\n * (POST /v1/sentinel/projects with X-Org-Id), then add its `dsn` here keyed by the\n * product name the app passes to `createAnalytics`.\n */\n\n/** PRODUCT_PROJECT maps a `product` to its Sentinel project id. The DSN's KEY is no\n * longer a per-project secret — it is the ONE org publishable key (below), so a\n * surface's errors ride the SAME key its events do. The id only names WHICH\n * project the errors group under, and cloud auto-provisions that project on first\n * keyed ingest, so a new id needs nothing minted. `site` lives in the `hanzo-ai`\n * project — an explicit map, because the projects predate this and do not derive\n * cleanly from the product name. */\nexport const PRODUCT_PROJECT: Readonly<Record<string, string>> = Object.freeze({\n console: '019fa40b-94ae-7f1d-8f7b-e92f123fad42', // console.hanzo.ai\n app: '019f9b1e-57eb-7171-9d92-72c0b85e4b4b', // hanzo.app\n site: '019f9b1e-5785-7359-ad0b-f75db8e58c99', // hanzo.ai (marketing; product `site`)\n})\n\n/** dsnForProduct builds the product's Sentinel DSN from the caller's resolved\n * publishable `key` and the product's project — the SAME key the event stream\n * carries, at the product's envelope endpoint. Returns undefined when there is no\n * key or no project for the product, leaving the error plane inert rather than\n * posting into the wrong one. The key is NOT baked here: it is the value the\n * surface resolved (an explicit `ingestKey`, or the KMS-sourced\n * NEXT_PUBLIC_PUBLISHABLE_KEY the build inlines) — the ONE live source, never a\n * literal committed beside the code. */\nexport function dsnForProduct(\n product: string | undefined,\n key: string | undefined\n): string | undefined {\n if (!product || !key) return undefined\n const projectId = PRODUCT_PROJECT[product]\n if (!projectId) return undefined\n return `https://${key}@api.hanzo.ai/v1/event/${projectId}`\n}\n","// Client-side redaction for error text — a faithful port of the server's\n// errortracking scrub (o11y pkg/modules/errortracking/implerrortracking/scrub.go),\n// applied BEFORE anything leaves the browser. Two layers, default-secure:\n//\n// - Secret shapes are ALWAYS redacted (sk-… keys, bearer/JWT tokens, DB DSNs,\n// PANs, cloud keys). There is no mode that ships a secret off-device.\n// - PII (email/IP) is scrubbed UNLESS capturePII is explicitly enabled.\n//\n// The server scrubs again — this is defense in depth, not a substitute — but the\n// point is that a Hanzo browser never emits a raw secret/email/IP in the first\n// place. Pure, no I/O.\n\nconst REDACTED = '[redacted]'\nconst EMAIL_MARK = '[email]'\nconst IP_MARK = '[ip]'\n\n// Secret patterns mirror scrub.go's secretPatterns. Order matters (broad DSN/PAN\n// rules run last). All are applied unconditionally.\nconst SECRET_PATTERNS: RegExp[] = [\n /-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,\n /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}/g, // JWT\n /\\bbearer\\s+[A-Za-z0-9._~+/-]{12,}=*/gi, // bearer token\n /\\b(?:sk|pk|rk)-[A-Za-z0-9]{2,}-?[A-Za-z0-9]{12,}/g, // openai-style\n /\\b(?:sk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, // stripe\n /\\bhk-[A-Za-z0-9]{16,}/g, // hanzo key\n /\\bAKIA[0-9A-Z]{16}\\b/g, // aws access key id\n /\\bASIA[0-9A-Z]{16}\\b/g, // aws sts key id\n /\\bAIza[0-9A-Za-z_-]{20,}/g, // google api key\n /\\bgh[posru]_[A-Za-z0-9]{20,}/g, // github token\n /\\bxox[baprs]-[A-Za-z0-9-]{10,}/g, // slack token\n // Creds in a URL/DSN. The repetition is BOUNDED on purpose: the unbounded form\n // ([^\\s:@/]+:[^\\s@/]+@) backtracks quadratically on colon-rich text with no\n // terminating '@' — an HTML error page pasted into an error message took 4.9s\n // at 32KB and >60s at 128KB, freezing the main thread from inside captureError.\n // Real userinfo is far below these caps, so bounding costs nothing.\n /[a-zA-Z][a-zA-Z0-9+.-]{0,32}:\\/\\/[^\\s:@/]{1,256}:[^\\s@/]{1,256}@/g,\n]\n\n/** Candidate card numbers. Gated by Luhn below — the bare digit-run pattern is a\n * false-positive cannon that redacts every millisecond epoch, order id and\n * phone number it sees (\"request 1753468800000 timed out\" became\n * \"request [redacted]timed out\"), which destroys the readability of the very\n * error messages this client exists to deliver. */\nconst RE_PAN = /\\b(?:\\d[ -]?){13,19}\\b/g\n\n/** luhn reports whether a digit string satisfies the Luhn checksum. Every real\n * card number does, so gating redaction on it removes the false positives\n * WITHOUT introducing a false negative — the safe direction for a redactor. */\nfunction luhn(digits: string): boolean {\n let sum = 0\n let alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) {\n d *= 2\n if (d > 9) d -= 9\n }\n sum += d\n alt = !alt\n }\n return sum % 10 === 0\n}\n\n/** redactPAN removes digit runs that actually check out as card numbers. */\nfunction redactPAN(s: string): string {\n return s.replace(RE_PAN, (m) => {\n const digits = m.replace(/[ -]/g, '')\n if (digits.length < 13 || digits.length > 19) return m\n return luhn(digits) ? REDACTED : m\n })\n}\n\n// Bounded to the RFC 5321 maxima (local-part 64, domain 255) for the same reason\n// as the creds-in-URL rule: the unbounded form backtracks quadratically across a\n// long run of local-part-legal characters that never reaches an '@' — measured at\n// 20ms on an 8KB worst case, on the main thread, per captured error. No real\n// address is excluded by these caps.\nconst RE_EMAIL = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\\.[A-Za-z]{2,24}/g\nconst RE_IPV4 = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g\nconst RE_IPV6 = /\\b(?:[0-9A-Fa-f]{1,4}:){2,7}[0-9A-Fa-f]{1,4}\\b/g\n\n// A CREDENTIAL IN A QUERY PARAM HAS NO SHAPE TO MATCH.\n//\n// Every pattern above recognises a secret by what it LOOKS like — a JWT's three\n// dots, `sk-`, `AKIA`, `ghp_`. An OAuth `code`, a `state`, a password-reset\n// nonce and an invite token are opaque random strings, indistinguishable from a\n// page id, so none of them match and all of them survive.\n//\n// That matters because the client stamps `url: window.location.href` on EVERY\n// event, not just pageviews. So one visit to `/callback?code=…&state=…` puts a\n// live authorization code on the wire, once per event, in cleartext — and the\n// code is exchangeable until it is redeemed.\n//\n// The fix is to redact by the NAME the value is filed under rather than by the\n// value's shape, which is the only signal available for an opaque token. The\n// name half is bounded (`{1,32}`) and the value half stops at the first\n// separator, so neither half can backtrack across a long string — the same\n// discipline the creds-in-URL pattern above documents.\nconst CREDENTIAL_PARAMS = [\n 'code', 'state', 'token', 'access_token', 'id_token', 'refresh_token',\n 'auth', 'authorization', 'secret', 'client_secret', 'password', 'passwd', 'pwd',\n 'api_key', 'apikey', 'key', 'session', 'session_id', 'sid',\n 'sig', 'signature', 'nonce', 'otp', 'invite', 'invitation',\n 'reset_token', 'confirmation_token', 'magic', 'ticket', 'assertion',\n]\nconst RE_CREDENTIAL_PARAM = new RegExp(\n '([?&#;](?:' + CREDENTIAL_PARAMS.join('|') + ')=)[^&#;\\\\s]{1,4096}',\n 'gi',\n)\n\n/** redactCredentialParams removes the VALUE of any query parameter whose NAME\n * says it carries a credential, leaving the name so the URL still reads. */\nexport function redactCredentialParams(s: string): string {\n return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix: string) => prefix + REDACTED)\n}\n\n/** redactSecrets removes known secret shapes. Always applied. */\nexport function redactSecrets(s: string): string {\n s = redactCredentialParams(s)\n for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED)\n return redactPAN(s)\n}\n\n/** scrubPII masks emails and IPs. Applied unless PII capture is enabled. */\nexport function scrubPII(s: string): string {\n s = s.replace(RE_EMAIL, EMAIL_MARK)\n s = s.replace(RE_IPV6, IP_MARK)\n s = s.replace(RE_IPV4, IP_MARK)\n return s\n}\n\n/** Longest free-text field this module will scrub. Every pattern here is a regex\n * run synchronously on the main thread, and the input is attacker-influenced —\n * `throw new Error(await res.text())` against an HTML error page is a one-line\n * way to hand us 128KB. Bounding the INPUT bounds the work regardless of which\n * pattern is pathological. 8KB is far beyond any real error message. */\nexport const MAX_SCRUB_LEN = 8192\n\n/** truncate caps a string at MAX_SCRUB_LEN, marking that it was cut so a reader\n * never mistakes a truncated message for the whole one. */\nexport function truncate(s: string, max = MAX_SCRUB_LEN): string {\n return s.length > max ? s.slice(0, max) + '… [truncated]' : s\n}\n\n/** scrubText applies the redaction policy to a free-text field. Input is capped\n * first: unbounded text is a denial-of-service surface, not just a size problem. */\nexport function scrubText(s: string | undefined, capturePII = false): string {\n if (!s) return s ?? ''\n s = truncate(s)\n s = redactSecrets(s)\n if (!capturePII) s = scrubPII(s)\n return s\n}\n","/*! anon.js — THE anonymous-identity chain. ONE implementation, two distributions.\n *\n * One browser is ONE person on every Hanzo surface, whichever client a page\n * happens to have loaded. There were once three implementations writing TWO keys —\n * `hz_anon_id` and `hz_id` — so the same visitor was several people depending on\n * which snippet the surface shipped.\n *\n * The two call sites:\n * 1. src/storage.ts — the bundled npm client; IMPORTS this file.\n * 2. hanzoai/cloud apps/analytics/tag.js — the tag the door hosts at\n * /v1/event.js; vendors this file and its tag.go serves the marked region\n * with the tag as one asset, so the door holds no second copy either.\n *\n * (2) has no bundler and cannot import anything, which is why the chain lives in a\n * file that is plain ES5 rather than in a .ts: the region between the BEGIN and END\n * markers is COPIED VERBATIM. Keep it ES5, dependency-free, `hz`-prefixed (it is\n * spliced into other people's scopes) and unformatted — a reformat here is a diff\n * against the vendored copy. After editing, resync the door:\n *\n * curl -fsSL https://unpkg.com/@hanzo/event/src/anon.js -o apps/analytics/anon.js\n */\n\n/* ── BEGIN hz anon chain — copied VERBATIM into hanzoai/cloud ──────────────── */\n\n/** The ONE anonymous-id key, on every surface and in every distribution. */\nvar HZ_ANON_KEY = 'hz_anon_id'\n\n/** `hz_id` is a SECOND identity space a no-build tag once wrote, so one page could\n * hold two people. It is READ and never written: an id already in the wild is\n * ADOPTED into the shared identity, because minting over one detaches a returning\n * visitor from their own history. */\nvar HZ_ANON_LEGACY_KEY = 'hz_id'\n\n/** The registrable domain the cookie is scoped to, so docs, cloud, console,\n * studio, pay, id and www all read the ONE id. localStorage cannot do this: it is\n * ORIGIN-scoped, which is what made one journey arrive as several strangers. */\nvar HZ_ANON_DOMAIN = 'hanzo.ai'\n\n/** Two years, rewritten on every read, so the cookie rolls forward with the\n * visitor instead of expiring two years after first touch. Safari caps a\n * SCRIPT-written cookie at 7 days no matter what this says, so the rewrite is\n * what keeps a returning Safari visitor: each read re-arms the 7-day window. */\nvar HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60\n\n/** Last resort for a browser that refuses cookies AND localStorage: without it\n * every event in a page load would mint an id of its own. */\nvar hzAnonMemo\n\n/**\n * hzUuidv7 mints a time-ordered UUIDv7 (RFC 9562 §5.7) for `now` in epoch ms.\n *\n * It has to be v7, and this is the only minter any distribution may use. The\n * session rollups on the event plane derive a session's start instant FROM THE ID\n * and admit only ids whose version nibble is 7, so a crypto.randomUUID() (v4) id\n * is not merely unordered there — it is DISCARDED, silently, and the rollup stays\n * empty. Without crypto only the ENTROPY degrades; the shape is always a valid v7.\n */\nfunction hzUuidv7(now) {\n var b = new Uint8Array(16)\n var i\n var c = typeof crypto !== 'undefined' ? crypto : undefined\n if (c && typeof c.getRandomValues === 'function') c.getRandomValues(b)\n else for (i = 0; i < 16; i++) b[i] = (Math.random() * 256) | 0\n var t = Math.floor(now === undefined ? Date.now() : now)\n for (i = 5; i >= 0; i--) {\n b[i] = t % 256\n t = Math.floor(t / 256)\n }\n b[6] = 0x70 | (b[6] & 0x0f) // version 7\n b[8] = 0x80 | (b[8] & 0x3f) // variant 0b10\n var h = ''\n for (i = 0; i < 16; i++) {\n h += (b[i] + 0x100).toString(16).slice(1)\n if (i === 3 || i === 5 || i === 7 || i === 9) h += '-'\n }\n return h\n}\n\n/** The cookie jar, or null wherever there is no document to read one from. */\nfunction hzAnonJar() {\n try {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null\n return document\n } catch (e) {\n return null // sandboxed frame with an opaque origin\n }\n}\n\n/** localStorage, or null when the browser refuses it (Safari private mode). */\nfunction hzAnonStore() {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null\n return window.localStorage\n } catch (e) {\n return null\n }\n}\n\n/** One stored value, or '' — a jar can read as well as refuse to. */\nfunction hzAnonItem(store, name) {\n try {\n return (store && store.getItem(name)) || ''\n } catch (e) {\n return ''\n }\n}\n\n/** The value of cookie `name`, or ''. */\nfunction hzAnonCookie(name) {\n var d = hzAnonJar()\n if (!d) return ''\n var parts = d.cookie.split(';')\n for (var i = 0; i < parts.length; i++) {\n var eq = parts[i].indexOf('=')\n if (eq < 0 || parts[i].slice(0, eq).trim() !== name) continue\n var v = parts[i].slice(eq + 1).trim()\n if (!v) continue\n try {\n return decodeURIComponent(v)\n } catch (e) {\n return v // not percent-encoded — take it as written\n }\n }\n return ''\n}\n\n/** Writes `name` on the registrable domain, for as long as the browser allows. */\nfunction hzAnonWrite(name, value) {\n var d = hzAnonJar()\n if (!d) return\n var host = ''\n var secure = false\n try {\n if (typeof window !== 'undefined' && window.location) {\n host = window.location.hostname || ''\n // A Secure cookie is refused outright by a non-secure origin, which would\n // strand http://localhost dev on the localStorage path.\n secure = window.location.protocol === 'https:'\n }\n } catch (e) {\n /* location unreachable — write a host-only, non-secure cookie */\n }\n // encodeURIComponent leaves a UUID byte-identical while making any value that is\n // not one unable to forge a `;` and inject an attribute.\n var c = name + '=' + encodeURIComponent(value)\n c += '; Path=/; Max-Age=' + HZ_ANON_MAX_AGE + '; SameSite=Lax'\n // Off hanzo.ai (localhost, previews, other registrable domains) the attribute\n // would be rejected and the whole cookie dropped, so it stays host-only there.\n // Prefixing both sides with '.' matches the domain itself and its subdomains\n // while refusing a suffix that merely ends in the same letters (evilhanzo.ai).\n if (('.' + host).slice(-(HZ_ANON_DOMAIN.length + 1)) === '.' + HZ_ANON_DOMAIN) {\n c += '; Domain=' + HZ_ANON_DOMAIN\n }\n if (secure) c += '; Secure'\n try {\n d.cookie = c\n } catch (e) {\n /* cookies refused — localStorage still carries the id */\n }\n}\n\n/**\n * hzAnonId returns the stable anonymous id for this browser, '' during SSR.\n *\n * Resolution is strictly ADDITIVE — every id that already exists is ADOPTED, and\n * only a browser holding none of them is given a new one:\n *\n * cookie · localStorage hz_anon_id · localStorage hz_id · in-memory · mint\n *\n * Minting over an id resets a returning visitor and detaches them from their own\n * history, so the order is the migration: the cookie is the shared home, the two\n * localStorage keys are what the three implementations wrote before it existed,\n * and each is read until nothing is left to adopt.\n *\n * localStorage keeps being written, so a rollback finds everyone where it left\n * them, and a browser that refuses cookies still holds one id per origin.\n */\nfunction hzAnonId() {\n if (typeof window === 'undefined') return '' // SSR / prerender: no browser to identify\n var s = hzAnonStore()\n var id =\n hzAnonCookie(HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_LEGACY_KEY) ||\n hzAnonMemo ||\n hzUuidv7()\n hzAnonMemo = id\n hzAnonWrite(HZ_ANON_KEY, id)\n try {\n if (s && s.getItem(HZ_ANON_KEY) !== id) s.setItem(HZ_ANON_KEY, id)\n } catch (e) {\n /* quota exhausted, or a private-mode jar that reads but refuses writes */\n }\n return id\n}\n\n/* ── END hz anon chain ─────────────────────────────────────────────────────── */\n\nexport { hzAnonId, hzUuidv7 }\n","// The ONE id minter for this client — UUIDv7 (RFC 9562 §5.7).\n//\n// The implementation is `hzUuidv7` in ./anon.js and this file only re-exports it.\n// It lives there because the anonymous-id chain has to mint too, and that chain is\n// inlined verbatim by the distribution that has no bundler (the tag\n// the door hosts) — a minter here as well would be a second implementation, and\n// the version nibble it produces is exactly the thing that must never diverge.\n//\n// WHY NOT crypto.randomUUID(): it mints v4, whose 122 bits are pure entropy and\n// carry no time. The session rollups on the event plane derive a session's start\n// instant FROM THE ID — their PARTITION BY and ORDER BY are\n// `fromUnixTimestamp(intDiv(toUInt64(bitShiftRight(session_id_v7, 80)), 1000))` —\n// so they admit only ids whose version nibble is 7\n// (`bitAnd(bitShiftRight(toUInt128(session_id), 76), 15) = 7`). A v4 session id is\n// not merely unordered there: it is DISCARDED at the door, silently, and the\n// rollup stays empty forever. Minting v7 is the whole reason those rollups can\n// exist; it also clusters index writes by time instead of scattering them across\n// the keyspace.\n//\n// Layout, 16 bytes big-endian:\n// 0..5 unix_ts_ms — 48-bit millisecond timestamp\n// 6 0111 (version 7) in the high nibble | rand_a\n// 7 rand_a\n// 8 10 (variant) in the high 2 bits | rand_b\n// 9..15 rand_b\n//\n// Never returns a non-UUID shape. The old minters fell back to `'a-' + base36`\n// when crypto was absent, and the plane casts a session id with\n// accurateCastOrNull(…, 'UUID') — a shape that does not parse becomes NULL and is\n// dropped by the same gate, so the fallback failed exactly like v4 did. Only the\n// ENTROPY degrades without crypto; the shape is always a valid v7 UUID.\n\n/**\n * uuidv7 mints a time-ordered UUIDv7 for `now` (epoch milliseconds).\n *\n * Two ids minted in the same millisecond sort arbitrarily between themselves; ids\n * from different milliseconds sort by time, lexically and numerically alike.\n */\nexport { hzUuidv7 as uuidv7 } from './anon.js'\n\n/** The millisecond timestamp a v7 id was minted at — the inverse of uuidv7. */\nexport function uuidv7Time(id: string): number {\n return parseInt(id.slice(0, 8) + id.slice(9, 13), 16)\n}\n","// The library version, stamped on every event (`libraryVersion`) and on the\n// Sentry `sdk` block. It lives alone so `sentry.ts` can read it without importing\n// `core.ts` — core imports sentry, so the reverse would be an import cycle.\nexport const VERSION = '0.3.33'\n","// Pure builders for the error path: parse a Hanzo-minted DSN, turn a JS Error into\n// a Sentry `event`, and frame it into a Sentry envelope. No I/O, no globals — the\n// Analytics client (core.ts) wires these to identity + transport.\n//\n// The wire shapes are a from-scratch model of the PUBLIC, documented Sentry ingest\n// protocol (develop.sentry.dev), verified against the Hanzo /v1/event ingest\n// (o11y pkg/modules/errortracking/implerrortracking: parseEnvelope, SentryEvent,\n// normalizeEvent, computeFingerprint). No upstream (FSL) code is used.\n\nimport { scrubText } from './scrub'\nimport { uuidv7 } from './uid'\nimport { VERSION } from './version'\nimport type {\n CaptureErrorOptions,\n Dsn,\n SentryEvent,\n SentryFrame,\n SentryLevel,\n} from './types'\n\n/** Max stack frames kept — well under the server's 250 cap, plenty for grouping. */\nconst MAX_FRAMES = 50\n/** Max stack lines examined, and max length of a line worth examining. Guards the\n * frame regexes against a hostile `stack` string (see framesFromStack). */\nconst MAX_LINES = 500\nconst MAX_LINE_LEN = 2048\n/** Max tag string length, so one huge property can't bloat the envelope. */\nconst MAX_TAG_LEN = 1024\n/** Max tags copied from properties. */\nconst MAX_TAGS = 50\n\n/** eventId mints a 32-hex-char id (no dashes) — the Sentry event_id shape. Same\n * minter as everything else, just formatted for Sentry's wire. */\nexport function eventId(): string {\n return uuidv7().replace(/-/g, '')\n}\n\n/** byteLen returns the UTF-8 byte length used for envelope item framing. */\nfunction byteLen(s: string): number {\n if (typeof TextEncoder !== 'undefined') return new TextEncoder().encode(s).length\n // Node fallback.\n if (typeof Buffer !== 'undefined') return Buffer.byteLength(s, 'utf8')\n return s.length\n}\n\n/**\n * parseDsn parses \"https://<version>:<hmac>@<host>/v1/event/<projectId>\" into its\n * public key + the derived envelope ingest URL. The key (which itself contains a\n * ':') is taken verbatim as the userinfo — we do NOT split it as user:pass. The\n * key rides ?sentry_key= (not the DSN in the body) because that is the credential\n * channel the server trusts AND the only one sendBeacon can carry on unload.\n * Returns null for anything malformed (fail-safe: the caller then stays inert).\n */\nexport function parseDsn(dsn: string | undefined | null): Dsn | null {\n if (!dsn) return null\n const m = /^(https?):\\/\\/([^@]+)@([^/]+)(\\/.*)?$/.exec(dsn.trim())\n if (!m) return null\n const scheme = m[1]\n const publicKey = m[2]\n const host = m[3]\n const path = m[4] ?? ''\n if (!publicKey || !host) return null\n const segs = path.split('/').filter(Boolean)\n const projectId = segs.length > 0 ? segs[segs.length - 1] : ''\n if (!projectId) return null\n const origin = `${scheme}://${host}`\n // THE DSN'S OWN PATH IS THE ADDRESS — derived here, never restated. It used to\n // be rebuilt as a literal, which threw away the path the DSN carried and wrote\n // the ingest address a second time; buildEnvelope wrote it a third. Three copies\n // of one fact. dsnForProduct (dsn.ts) is the ONE place it is spelled; this\n // follows it.\n const base = `${origin}/${segs.map(encodeURIComponent).join('/')}`\n const ingestUrl = `${base}/envelope/?sentry_key=${encodeURIComponent(publicKey)}`\n return { publicKey, origin, projectId, base, ingestUrl }\n}\n\nconst V8_FRAME = /^\\s*at\\s+(?:(.+?)\\s+\\()?(?:(.+?):(\\d+):(\\d+)|([^)]+))\\)?\\s*$/\nconst MOZ_FRAME = /^\\s*(?:(.*?)@)?(.+?):(\\d+):(\\d+)\\s*$/\n\n/** inApp marks a frame as the app's own code (vs vendor/runtime) for grouping. */\nfunction inApp(file: string): boolean {\n if (!file) return false\n return !(\n file.includes('node_modules') ||\n file.startsWith('webpack-internal') ||\n file.startsWith('webpack://') ||\n file.startsWith('chrome-extension://') ||\n file.startsWith('moz-extension://')\n )\n}\n\n/**\n * framesFromStack parses a browser Error.stack into Sentry frames, OLDEST-FIRST\n * (Sentry orders caller->callee; the crash site is last — matching the server's\n * pickCrashFrame). Handles both V8 (\"at fn (file:li:co)\") and\n * Firefox/Safari (\"fn@file:li:co\"). Unparseable lines are skipped.\n */\nexport function framesFromStack(stack: string | undefined): SentryFrame[] {\n if (!stack) return []\n // Both frame regexes use lazy nested quantifiers, which backtrack badly on a\n // long line that never matches. A stack is attacker-influenced (a thrown value\n // can carry any `stack` string), so bound the work: skip absurd lines and stop\n // after MAX_LINES. Only the innermost MAX_FRAMES are kept anyway.\n const lines = stack.split('\\n', MAX_LINES)\n const frames: SentryFrame[] = []\n for (const raw of lines) {\n if (raw.length > MAX_LINE_LEN) continue\n const line = raw.trimEnd()\n if (!line) continue\n // Header lines like \"TypeError: x is not a function\" match neither frame\n // regex (no \"at \" prefix, no trailing :line:col) and are skipped naturally.\n let fn: string | undefined\n let file = ''\n let lineno = 0\n let colno = 0\n const v = V8_FRAME.exec(line)\n if (v) {\n fn = v[1]\n if (v[2]) {\n file = v[2]\n lineno = Number(v[3]) || 0\n colno = Number(v[4]) || 0\n } else {\n file = (v[5] || '').trim()\n }\n } else {\n const f = MOZ_FRAME.exec(line)\n if (!f) continue\n fn = f[1]\n file = f[2]\n lineno = Number(f[3]) || 0\n colno = Number(f[4]) || 0\n }\n if (!file && !fn) continue\n frames.push({\n function: fn || '<anonymous>',\n filename: file,\n abs_path: file,\n lineno,\n colno,\n in_app: inApp(file),\n })\n }\n // Reverse to oldest-first and cap to the innermost MAX_FRAMES.\n frames.reverse()\n if (frames.length > MAX_FRAMES) return frames.slice(frames.length - MAX_FRAMES)\n return frames\n}\n\n/** normalizeError coerces an unknown throwable into {name, message, stack}. */\nexport function normalizeError(err: unknown): { name: string; message: string; stack?: string } {\n if (err instanceof Error) {\n // `name`, `message` and `stack` are ordinary getters, and the thrown object is\n // the least trustworthy input this library handles — any of them may throw.\n // Losing the whole report to a hostile getter is not acceptable.\n const name = read(err, 'name')\n const message = read(err, 'message')\n const stack = read(err, 'stack')\n return {\n name: typeof name === 'string' && name ? name : 'Error',\n message: typeof message === 'string' && message ? message : str(err),\n stack: typeof stack === 'string' ? stack : undefined,\n }\n }\n if (typeof err === 'string') return { name: 'Error', message: err }\n try {\n return { name: 'Error', message: JSON.stringify(err) ?? str(err) }\n } catch {\n return { name: 'Error', message: str(err) }\n }\n}\n\n/** read pulls a property off a possibly-hostile value without letting a throwing\n * getter escape. */\nfunction read(o: unknown, k: string): unknown {\n try {\n return (o as Record<string, unknown>)[k]\n } catch {\n return undefined\n }\n}\n\n/** str coerces to a string without letting a throwing toString/Symbol.toPrimitive\n * escape. */\nfunction str(v: unknown): string {\n try {\n return String(v)\n } catch {\n return '[unstringifiable]'\n }\n}\n\n/** Identity carried onto every error event — the SAME ids analytics uses. */\nexport interface ErrorIdentity {\n /** OIDC sub (post-identify) or anon id. NEVER email/PII. */\n userId?: string\n sessionId?: string\n product?: string\n release?: string\n environment?: string\n}\n\nexport interface BuildEventInput {\n error: unknown\n options?: CaptureErrorOptions\n identity: ErrorIdentity\n capturePII?: boolean\n /** Injectable for deterministic tests. */\n now?: number\n id?: string\n}\n\nfunction coerceTag(v: unknown): string {\n const s = typeof v === 'string' ? v : (() => {\n try {\n return JSON.stringify(v) ?? String(v)\n } catch {\n try {\n return String(v) // circular — fall back to the primitive coercion\n } catch {\n return '[unstringifiable]' // ...which a throwing toString can also refuse\n }\n }\n })()\n return s.length > MAX_TAG_LEN ? s.slice(0, MAX_TAG_LEN) : s\n}\n\n/**\n * buildSentryEvent turns a throwable + identity into a Sentry `event`. The message\n * (the leak surface) is scrubbed client-side; the user is ONLY the stable subject\n * id — never email/username/ip. Level defaults to error, or fatal for uncaught.\n */\nexport function buildSentryEvent(input: BuildEventInput): SentryEvent {\n const { error, options = {}, identity, capturePII = false } = input\n const norm = normalizeError(error)\n const handled = options.handled !== false\n const level: SentryLevel = options.level ?? (handled ? 'error' : 'fatal')\n\n const tags: Record<string, string> = { handled: String(handled) }\n if (identity.product) tags.product = identity.product\n if (identity.sessionId) tags.session = identity.sessionId\n // Tags come from arbitrary caller `properties`. Read each key in isolation:\n // Object.entries() invokes every getter at once, so one throwing getter would\n // cost us the entire envelope — losing the stack trace to save a tag. Keys are\n // optional; the exception is not.\n try {\n const props = (options.properties ?? {}) as Record<string, unknown>\n let n = 0\n for (const k of Object.keys(props)) {\n if (n >= MAX_TAGS) break\n try {\n const val = props[k]\n if (val === undefined || val === null) continue\n tags[k] = scrubText(coerceTag(val), capturePII)\n n++\n } catch {\n continue // throwing getter or unstringifiable value — skip this key only\n }\n }\n } catch {\n /* unenumerable/exotic properties object — ship the exception without tags */\n }\n\n const event: SentryEvent = {\n event_id: input.id ?? eventId(),\n timestamp: (input.now ?? Date.now()) / 1000,\n platform: 'javascript',\n level,\n logger: identity.product,\n environment: identity.environment,\n release: identity.release,\n exception: {\n values: [\n {\n type: norm.name,\n value: scrubText(norm.message, capturePII),\n stacktrace: { frames: framesFromStack(norm.stack) },\n },\n ],\n },\n tags,\n sdk: { name: '@hanzo/event', version: VERSION },\n }\n if (identity.userId) event.user = { id: identity.userId }\n return event\n}\n\n/**\n * buildEnvelope frames a Sentry event into a newline-delimited envelope:\n *\n * {\"event_id\",\"dsn\",\"sent_at\"}\\n\n * {\"type\":\"event\",\"content_type\":\"application/json\",\"length\":N}\\n\n * <event json>\\n\n *\n * The item is length-delimited (N = UTF-8 byte length) — the framing the server's\n * parseEnvelope reads first (falling back to newline-delimited otherwise).\n */\nexport function buildEnvelope(event: SentryEvent, dsn: Dsn, sentAt?: string): string {\n const payload = JSON.stringify(event)\n const header = JSON.stringify({\n event_id: event.event_id,\n dsn: dsn.base,\n sent_at: sentAt ?? new Date().toISOString(),\n })\n const itemHeader = JSON.stringify({\n type: 'event',\n content_type: 'application/json',\n length: byteLen(payload),\n })\n return `${header}\\n${itemHeader}\\n${payload}\\n`\n}\n","// The `$exception` product-event shape — pure builders, no I/O.\n//\n// An exception reaches TWO destinations, and they read different shapes:\n//\n// 1. The ERROR PLANE — a Sentry envelope to the DSN host (sentry.ts). Untouched\n// by this module.\n// 2. ERROR TRACKING in Hanzo Insights — reads the PRODUCT-EVENT plane\n// (`insights.events WHERE event = '$exception'`) and expects the PostHog\n// exception vocabulary: `$exception_list` plus the denormalized `$exception_*`\n// properties. This module builds that.\n//\n// WHY THE FULLY-DERIVED SHAPE. Upstream, a server stage (Cymbal) symbolicates\n// frames and computes `$exception_fingerprint`, `$exception_types`, `_values`,\n// `_sources`, `_functions`, then REPLACES the property bag. That stage is not in\n// Hanzo's path: the door writes `event.fact` and a materialized view projects it\n// into `insights.events`, so nothing between the client and the warehouse derives\n// anything. Whatever the product reads, the client has to have sent. Two\n// consequences are load-bearing rather than cosmetic:\n//\n// • The issue query drops any event whose `$exception_fingerprint` is null, so an\n// event without one is invisible no matter how well-formed the rest is.\n// • `stacktrace.type` must be the literal 'resolved'; on any other value the\n// renderer falls through both match arms and draws nothing under the header.\n//\n// If that server stage is ever put in front of this plane it replaces these\n// properties wholesale, so sending them stays correct either way.\n//\n// FRAME ORDER is bottom-up: frames[0] is the entry point and the LAST frame is the\n// throw site. framesFromStack (sentry.ts) already returns that order, which is why\n// this module reuses it rather than re-parsing.\n\nimport { framesFromStack, normalizeError } from './sentry'\nimport type {\n ExceptionEntry,\n ExceptionFrame,\n ExceptionProperties,\n SentryFrame,\n SentryLevel,\n} from './types'\n\n/** Cap on the frames carried per exception, matching the Sentry path's budget. */\nconst MAX_FRAMES = 50\n/** Cap on `value`, so one enormous message cannot dominate a batch. The product\n * truncates for display anyway; this bounds the wire. */\nconst MAX_VALUE = 4096\n\n/**\n * digest is a stable 32-hex-char (128-bit) content hash, computed synchronously.\n *\n * Grouping keys are needed on the capture path, which is synchronous and may be\n * running inside an unload handler — SubtleCrypto is async and unavailable on\n * insecure origins, so it cannot be used here. This is FNV-1a run over four seeds\n * and concatenated. It is a GROUPING key, never a security boundary: it is not\n * collision-resistant against a chosen-input adversary, and nothing authorizes or\n * authenticates on it. The product treats the value as opaque.\n */\nexport function digest(s: string): string {\n let out = ''\n for (const seed of [0x811c9dc5, 0x01000193, 0x9e3779b9, 0x85ebca6b]) {\n let h = seed >>> 0\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n // FNV prime 16777619, via shifts to stay in 32-bit integer math.\n h = (h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) >>> 0\n }\n out += h.toString(16).padStart(8, '0')\n }\n return out\n}\n\n/**\n * frameOf converts one parsed stack frame into the shape the product renders.\n *\n * The product's frame vocabulary is the POST-symbolication one (`mangled_name`,\n * `source`, `line`, `column`), so that is what is emitted. `resolved` is false and\n * honest: a browser bundle is minified and no symbol set has been uploaded, so the\n * original name and line are genuinely unknown. Claiming `resolved: true` would\n * trade an accurate \"upload your symbol sets\" hint for a misleading \"source code is\n * not available\" error.\n */\nfunction frameOf(f: SentryFrame): ExceptionFrame {\n const source = f.filename ?? ''\n const name = f.function ?? '<anonymous>'\n const line = f.lineno ?? 0\n const column = f.colno ?? 0\n return {\n // Stable per code location, so the same frame groups and re-renders under one\n // key. The '/part' suffix is the product's format for one raw frame expanding\n // into several resolved ones; a browser frame is always part 0.\n raw_id: `${digest(`${source}|${name}|${line}|${column}`)}/0`,\n mangled_name: name,\n source,\n line,\n column,\n in_app: f.in_app ?? false,\n lang: 'javascript',\n resolved: false,\n resolve_failure: 'no symbol set uploaded for this release',\n resolved_name: null,\n module: null,\n }\n}\n\n/** truncate bounds a free-text field without splitting a surrogate pair. */\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s\n let end = max\n const c = s.charCodeAt(end - 1)\n // A high surrogate at the cut point would leave a lone half.\n if (c >= 0xd800 && c <= 0xdbff) end--\n return s.slice(0, end)\n}\n\n/**\n * exceptionEntry builds the single `$exception_list` entry for a throwable.\n *\n * One entry, not a chain: `Error.cause` chaining is a distinct fact with its own\n * ordering rules, and emitting it wrongly is worse than not emitting it.\n */\nexport function exceptionEntry(\n err: unknown,\n opts: { handled: boolean; id: string },\n): ExceptionEntry {\n const n = normalizeError(err)\n const frames = framesFromStack(n.stack).slice(-MAX_FRAMES)\n const entry: ExceptionEntry = {\n id: opts.id,\n type: n.name,\n value: truncate(n.message, MAX_VALUE),\n mechanism: {\n type: 'generic',\n handled: opts.handled,\n // An exception the app reported by hand was constructed, not thrown by the\n // runtime at a real call site.\n synthetic: !(err instanceof Error),\n },\n }\n if (frames.length > 0) {\n // 'resolved' names the SHAPE of the frame list, not the symbolication state of\n // any frame — the renderer only walks frames on this exact value.\n entry.stacktrace = { type: 'resolved', frames: frames.map(frameOf) }\n }\n return entry\n}\n\n/**\n * fingerprint is the issue grouping key.\n *\n * Keyed on exception type plus each in-app frame's function and source — the same\n * pieces the server-side grouper records (\"Exception Type\", \"Resolved function\n * name\", \"Source file name\"). Deliberately NOT the message: `Loading chunk 3324\n * failed` and `Loading chunk 998 failed` are one bug, and grouping on message is\n * precisely the mistake that made every distinct error string its own event name.\n *\n * Falls back to the type alone when no in-app frame survived, which keeps\n * stackless errors (`Script error.`, cross-origin) in one issue instead of\n * scattering them.\n */\nexport function fingerprint(entry: ExceptionEntry): string {\n const frames = entry.stacktrace?.frames ?? []\n const pieces = frames\n .filter((f) => f.in_app)\n .map((f) => `${f.mangled_name}@${f.source}`)\n return digest([entry.type, ...pieces].join('\\n'))\n}\n\n/**\n * exceptionProperties builds the full `$exception_*` property bag for one captured\n * throwable — everything Error Tracking reads off the event.\n *\n * The denormalized arrays are ordered like `frames`: last element is the throw\n * site, which is the element the issue list indexes at -1 for its source/function\n * columns.\n */\nexport function exceptionProperties(\n err: unknown,\n opts: { handled: boolean; id: string; level?: SentryLevel },\n): ExceptionProperties {\n const entry = exceptionEntry(err, opts)\n const frames = entry.stacktrace?.frames ?? []\n const fp = fingerprint(entry)\n return {\n $exception_list: [entry],\n $exception_fingerprint: fp,\n // Records WHY this fingerprint holds. 'manual' is the honest value: the client\n // supplied the key rather than a server grouper deriving one.\n $exception_fingerprint_record: [{ type: 'manual' }],\n $exception_type: entry.type,\n $exception_message: entry.value,\n $exception_level: opts.level ?? 'error',\n $exception_handled: opts.handled,\n $exception_synthetic: entry.mechanism?.synthetic ?? false,\n $exception_types: [entry.type],\n $exception_values: [entry.value],\n $exception_sources: frames.map((f) => f.source).filter((s): s is string => !!s),\n $exception_functions: frames\n .map((f) => f.resolved_name ?? f.mangled_name)\n .filter((s): s is string => !!s),\n }\n}\n","// SSR-safe browser storage for stable identifiers and first-touch state. Every\n// accessor no-ops (returns undefined) when there is no window/localStorage, so the\n// client imports cleanly in a Next.js server component.\n//\n// The anonymous id is the one value that must outlive an ORIGIN, and it is also\n// the one value the OTHER two distributions must agree with, so its chain lives in\n// ./anon.js and this file only calls it. Everything else here stays origin-local.\n\nimport { hzAnonId } from './anon.js'\nimport type { Attribution, Cohort } from './types'\nimport { uuidv7 } from './uid'\n\nconst KEY = {\n session: 'hz_session',\n firstTouch: 'hz_first_touch',\n cohort: 'hz_cohort',\n} as const\n\n/** 30-minute inactivity window defines a session (PostHog/GA convention). */\nconst SESSION_TTL_MS = 30 * 60 * 1000\n\nfunction ls(): Storage | undefined {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return undefined\n return window.localStorage\n } catch {\n return undefined // Safari private mode / blocked storage\n }\n}\n\n/**\n * Stable anonymous id, shared by every *.hanzo.ai surface AND by every Hanzo\n * client on the page — the npm client and the hosted tag both run the one\n * chain in ./anon.js, so which snippet a surface loaded no longer decides who the\n * visitor is.\n *\n * It lives in a first-party cookie on the registrable domain because localStorage\n * is ORIGIN-scoped: docs, cloud and console each minted their own id for the same\n * person, so one marketing → docs → signup → checkout journey arrived as several\n * strangers — 463 anonymous identities carried 545 events in a week, about 1.2\n * events each.\n */\nexport function anonId(): string | undefined {\n return hzAnonId() || undefined // '' during SSR / prerender\n}\n\ninterface SessionState {\n id: string\n last: number\n}\n\n/**\n * Current session id, rotated after SESSION_TTL_MS of inactivity.\n *\n * Minted at `now`, so the v7 timestamp the id carries IS the session's start\n * instant — which is what the session rollups partition and order on. Passing the\n * caller's clock rather than reading Date.now() again keeps the id's embedded time\n * and the recorded `last` from disagreeing.\n */\nexport function sessionId(now = Date.now()): string | undefined {\n const s = ls()\n if (!s) return undefined\n let state: SessionState | null = null\n try {\n state = JSON.parse(s.getItem(KEY.session) || 'null')\n } catch {\n state = null\n }\n if (!state || now - state.last > SESSION_TTL_MS) {\n state = { id: uuidv7(now), last: now }\n } else {\n state.last = now\n }\n s.setItem(KEY.session, JSON.stringify(state))\n return state.id\n}\n\n/** Read the persisted first-touch attribution. */\nexport function getFirstTouch(): Attribution | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.firstTouch)\n return v ? (JSON.parse(v) as Attribution) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Persist first-touch attribution ONCE — never overwrite an existing record. */\nexport function setFirstTouchOnce(a: Attribution): Attribution {\n const s = ls()\n const existing = getFirstTouch()\n if (existing) return existing\n if (s) s.setItem(KEY.firstTouch, JSON.stringify(a))\n return a\n}\n\n/** Read persisted cohort dimensions. */\nexport function getCohort(): Cohort | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.cohort)\n return v ? (JSON.parse(v) as Cohort) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Merge + persist cohort dimensions (signupWeek set once). */\nexport function mergeCohort(patch: Cohort): Cohort {\n const s = ls()\n const cur = getCohort() || {}\n const next: Cohort = {\n signupWeek: cur.signupWeek || patch.signupWeek,\n channel: patch.channel || cur.channel,\n refCode: cur.refCode || patch.refCode,\n }\n if (s) s.setItem(KEY.cohort, JSON.stringify(next))\n return next\n}\n","// The framework-agnostic event client. ONE API surface over TWO orthogonal\n// planes, sharing one session and one identity:\n//\n// 1. EVENT STREAM — buffered pageview/event/identify/group, flushed as ONE\n// batch to the Hanzo Cloud front door:\n// POST {host}/v1/event body: { batch: [Event, …] } -> { accepted, dropped }\n// Cloud resolves the tenant server-side (validated session, or the signed\n// publishable key) and stamps it; the client NEVER sends the org.\n//\n// 2. ERROR PLANE — every captured exception is ALSO framed as a real Sentry\n// envelope and POSTed to the error host named by the DSN:\n// POST {dsn.base}/envelope/?sentry_key=… ({base} = /v1/event/{projectId})\n// This is what reaches sentry.hanzo.ai (issues, grouping, stack frames).\n//\n// These are NOT the same pipe and one does NOT feed the other. The event stream\n// stores a `type:'error'` row in the cloud event warehouse (readable via\n// GET /v1/errors) — that is product signal, not error tracking. There is no\n// server-side fan-out from /v1/event into Sentry; without the envelope below,\n// nothing ever reaches sentry.hanzo.ai. An earlier revision of this file claimed\n// the one door was \"lensed server-side into … error tracking (sentry)\". It was\n// wrong, and it silently cost the fleet all of its error telemetry.\n//\n// The error plane is inert (fail-safe) when no DSN is configured: nothing is\n// sent, nothing throws, and the event stream is unaffected.\n//\n// Auth is orthogonal — the SAME body to the SAME door, differing only in how the\n// caller proves its tenant:\n//\n// • cookie/session app (host:'') — same-origin credentials ride the request.\n// • bearer app (getToken) — Authorization: Bearer <jwt>.\n// • publishable-key app (ingestKey: 'pk-…') — ?ingest_key=pk-… on the query, on\n// the fetch and the beacon alike, with a text/plain body. Write-only and safe\n// to ship in a bundle; the door resolves it to an org server-side. The query\n// is the carrier neither send needs a header for, which is what keeps both\n// CORS-simple and therefore sendable from a customer's own origin.\n//\n// The wire is the canonical `Event` (== the cloud CaptureEvent): its `type` field\n// is what Cloud folds to event_type='error', which is how the event WAREHOUSE\n// classifies the row (GET /v1/errors). That is the extent of it — the fold does\n// not forward anything to Sentry. The error dashboard is fed only by the envelope\n// in plane 2 above, and only when a DSN is set.\n\nimport {\n parseAttribution,\n hasAttribution,\n deriveChannel,\n} from './attribution'\nimport { dsnForProduct } from './dsn'\nimport { EXCEPTION, PAGEVIEW } from './events'\nimport { exceptionProperties } from './exception'\nimport { scrubText } from './scrub'\nimport {\n buildEnvelope,\n buildSentryEvent,\n normalizeError as normalizeThrowable,\n parseDsn,\n type ErrorIdentity,\n} from './sentry'\nimport {\n anonId,\n sessionId,\n getFirstTouch,\n setFirstTouchOnce,\n getCohort,\n mergeCohort,\n} from './storage'\nimport { uuidv7 } from './uid'\nimport type {\n AnalyticsConfig,\n Attribution,\n CaptureErrorOptions,\n Cohort,\n Dsn,\n EventKind,\n Exception,\n Transport,\n WireEvent,\n} from './types'\nimport { VERSION } from './version'\n\nexport { VERSION }\n\nconst EVENT_PATH = '/v1/event' // the ONE canonical ingestion front door\nconst DEFAULT_HOST = 'https://api.hanzo.ai' // the one edge; cookie apps pass host:''\nconst ENVELOPE_CONTENT_TYPE = 'application/x-sentry-envelope'\n// The beacon body's type. text/plain is CORS-SAFELISTED, which is the whole\n// property: a safelisted type makes the POST a SIMPLE request, and a simple\n// request needs no preflight. An unloading document does not get a second round\n// trip, so cross-origin a preflighted beacon is never sent at all. The door reads\n// the raw body and dispatches on its first non-space byte, so the type names the\n// CORS class and nothing else.\nconst BEACON_CONTENT_TYPE = 'text/plain'\n\n/** readEnvDsn resolves a DSN from the public env when config omits one, so an app\n * gets the error plane by setting ONE build-time variable and nothing else.\n * Next/Vite inline these at build; the access is guarded so it is safe in a bare\n * browser and during SSR/prerender where `process` may not exist. */\nfunction readEnvDsn(): string | undefined {\n try {\n if (typeof process !== 'undefined' && process.env) {\n return process.env.NEXT_PUBLIC_HANZO_EVENT_DSN || process.env.HANZO_EVENT_DSN || undefined\n }\n } catch {\n /* no process — browser without inlined env */\n }\n return undefined\n}\n\n/** readEnv reads an inlined build-time variable, guarded like readEnvDsn. */\nfunction readEnv(name: string): string | undefined {\n try {\n if (typeof process !== 'undefined' && process.env) return process.env[name] || undefined\n } catch {\n /* no process */\n }\n return undefined\n}\n\n/** appendQuery adds a single query param to a URL string — used to carry a\n * publishable key on either send (?ingest_key=…). */\nfunction appendQuery(url: string, key: string, value: string): string {\n return url + (url.includes('?') ? '&' : '?') + key + '=' + encodeURIComponent(value)\n}\n\n/** Normalize anything thrown (Error | string | unknown) into an Exception. */\n/** normalizeError adapts the shared, hostile-input-safe normalizer (sentry.ts) to\n * the event stream's Exception shape. ONE normalizer serves both planes: a thrown\n * object may define `name`/`message`/`stack` as throwing getters, and when each\n * plane rolled its own reader the stream still lost the report that the error\n * plane had already survived. */\nfunction normalizeError(err: unknown): Exception {\n const n = normalizeThrowable(err)\n return { type: n.name, message: n.message, stack: n.stack }\n}\n\n// React Native defines a `window` but no `document` (and no `window.location`),\n// so `typeof window !== 'undefined'` alone took the browser path there and\n// `init()` threw on `window.location.search`. Requiring `document` makes RN read\n// as non-browser: `init()` returns early (skips attribution + the visibility/\n// unload listeners RN doesn't have), while `capture()`/`flush()` — which are NOT\n// gated on this and post through plain `fetch` — still emit. So the client is\n// inert-safe under SSR/Node and live on RN, without a second transport.\nconst isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined'\n\n/** serializeBatch stringifies a batch, salvaging what it can. `properties` is\n * arbitrary caller data — a DOM node, a React synthetic event, an axios error are\n * all circular, and a getter on one can throw — so a whole batch must never be\n * lost to a single poisoned event. Falls back to per-event serialization, then to\n * keeping the event and dropping its properties. Returns null only when nothing\n * at all survives. */\nfunction serializeBatch(batch: WireEvent[]): string | null {\n try {\n return JSON.stringify({ batch })\n } catch {\n /* one bad event — salvage the rest below */\n }\n const parts: string[] = []\n for (const e of batch) {\n try {\n parts.push(JSON.stringify(e))\n } catch {\n try {\n // Keep the event (identity, session, type all matter); drop the payload\n // that could not be serialized, and say so rather than lying by omission.\n parts.push(JSON.stringify({ ...e, properties: { $unserializable: true } }))\n } catch {\n /* unsalvageable — drop this ONE event, never the batch */\n }\n }\n }\n return parts.length > 0 ? '{\"batch\":[' + parts.join(',') + ']}' : null\n}\n\n/** DefaultTransport: fetch(keepalive) for authenticated/normal sends;\n * navigator.sendBeacon for page-unload beacons.\n *\n * A publishable key rides the ?ingest_key query on BOTH, which is what keeps\n * both CORS-simple: the query is the one carrier neither send needs a header\n * for, and a simple request leaves the browser from any origin — permission is\n * asked to READ a cross-origin response, never to send one. That is what lets a\n * bundled client run on a customer's own page. A JWT is first-party by\n * construction, so it keeps Authorization and the session it travels with.\n *\n * `contentType` names the FETCH request's Content-Type (the error plane sets the\n * envelope type there, and keeps the header carrier with it). The beacon body is\n * always BEACON_CONTENT_TYPE: its type is a CORS class, not a payload\n * description, and a beacon that is not a simple request is never sent. */\nclass DefaultTransport implements Transport {\n send(\n url: string,\n body: string,\n opts: {\n beacon: boolean\n token?: string\n ingestKey?: string\n contentType?: string\n debug?: boolean\n },\n ): void {\n if (opts.beacon && isBrowser() && typeof navigator.sendBeacon === 'function') {\n const beaconUrl = opts.ingestKey ? appendQuery(url, 'ingest_key', opts.ingestKey) : url\n try {\n // The answer is whether the agent QUEUED the batch — false for a body past\n // the beacon size limit, or a full queue. Only a queued batch ends the\n // send; a refused one falls through to the keepalive fetch below.\n const queued = navigator.sendBeacon(\n beaconUrl,\n new Blob([body], { type: BEACON_CONTENT_TYPE }),\n )\n if (queued) return\n if (opts.debug) console.warn('[event] beacon refused, falling back to fetch')\n } catch {\n /* fall through to fetch */\n }\n }\n if (typeof fetch !== 'function') return\n // A publishable key makes the send a CORS SIMPLE request: the key rides the\n // query, the body is text/plain, and nothing asks for credentials. That is what\n // lets a bundled client run on a customer's own page — every send from there is\n // cross-origin, and an Authorization header or a JSON type preflights the POST\n // for an origin that cannot pass one. A JWT is first-party by construction, so\n // it keeps the header and the session it travels with, and so does the error\n // plane, which names its own envelope type.\n const simple = opts.ingestKey !== undefined && opts.contentType === undefined\n const headers: Record<string, string> = {\n 'Content-Type': simple ? BEACON_CONTENT_TYPE : (opts.contentType ?? 'application/json'),\n }\n const bearer = simple ? undefined : (opts.ingestKey ?? opts.token)\n if (bearer) headers.Authorization = `Bearer ${bearer}`\n void fetch(simple ? appendQuery(url, 'ingest_key', opts.ingestKey!) : url, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n credentials: simple ? 'omit' : 'include',\n })\n .then((res) => {\n // Telemetry loss never throws into the app — but silence is how this\n // client lost the fleet's errors in the first place. Under `debug`, say\n // so. A rejected ingest (the CORS allowlist 403s non-production origins,\n // so local dev NEVER reports) is otherwise indistinguishable from success.\n if (!res.ok && opts.debug) {\n console.warn('[event] ingest rejected', res.status, url.split('?')[0])\n }\n })\n .catch((e: unknown) => {\n if (opts.debug) console.warn('[event] ingest failed', url.split('?')[0], e)\n })\n }\n}\n\nexport class Analytics {\n private cfg: Required<\n Pick<AnalyticsConfig, 'product' | 'batchSize' | 'flushIntervalMs' | 'enabled' | 'captureErrors'>\n > &\n AnalyticsConfig\n private transport: Transport\n private queue: WireEvent[] = []\n private timer: ReturnType<typeof setTimeout> | null = null\n private personId?: string\n private attribution: Attribution = { utm: {} }\n private cohort: Cohort = {}\n private started = false\n /** The view pageview() last counted — path + location. */\n private counted?: string\n /** Parsed error-plane DSN, or null when the plane is inert. */\n private dsn: Dsn | null\n /** Guards against an error thrown *inside* the error path re-entering it. */\n private reentrant = false\n\n constructor(config: AnalyticsConfig) {\n this.cfg = {\n host: DEFAULT_HOST,\n batchSize: 20,\n flushIntervalMs: 5000,\n enabled: true,\n captureErrors: true,\n ...config,\n // The publishable key resolves from ONE live source, never a literal baked\n // beside the code. Most specific first:\n // 1. an explicit `ingestKey` in config;\n // 2. NEXT_PUBLIC_PUBLISHABLE_KEY, the inlined build-time env the fleet\n // carries end to end — KMS `deploy/PUBLISHABLE_KEY` -> the PUBLISHABLE_KEY\n // build-arg -> the NEXT_PUBLIC_ prefix Next inlines.\n //\n // A surface that provides neither has no key, and its anonymous traffic\n // files under `$public` (which drops track/identify/group and answers 200);\n // the fix is to give it the KMS-sourced env, not to hardcode the org key\n // here. The key is a credential-class value: its home is KMS, and the ONE\n // build reads it from there.\n ingestKey: config.ingestKey ?? readEnv('NEXT_PUBLIC_PUBLISHABLE_KEY'),\n }\n this.transport = config.transport ?? new DefaultTransport()\n // Error plane, most specific source first: an explicit DSN wins, then the\n // inlined build-time env (a per-deploy override), then the product registry —\n // whose DSN carries the SAME resolved key (not a baked one), so declaring\n // `product` + providing the key is enough to report errors. Malformed or\n // absent => null => inert, never throwing into the host app.\n this.dsn = parseDsn(\n config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product, this.cfg.ingestKey)\n )\n }\n\n /** adopt gives this client a credential it does not have. The key belongs to\n * the stream, not to whichever caller happened to ask for the handle first,\n * so a later caller carrying one hands it over. The error plane derives from\n * the key, so it comes up here too when it was inert for want of one.\n * Present fields are never overwritten: the first caller's key stays. */\n adopt(config: AnalyticsConfig): void {\n if (config.ingestKey && !this.cfg.ingestKey) this.cfg.ingestKey = config.ingestKey\n if (config.getToken && !this.cfg.getToken) this.cfg.getToken = config.getToken\n if (!this.dsn) {\n this.dsn = parseDsn(\n config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product, this.cfg.ingestKey),\n )\n }\n }\n\n /** errorPlaneEnabled reports whether captured exceptions can actually reach the\n * error host. False means a DSN was never configured — the documented\n * fail-safe. Exposed so an app (or a test) can assert its wiring instead of\n * discovering months later that nothing was ever reported. */\n get errorPlaneEnabled(): boolean {\n return this.dsn !== null\n }\n\n /** errorIngestUrl is the fully-derived envelope endpoint, or undefined when the\n * plane is inert. Diagnostics only. */\n get errorIngestUrl(): string | undefined {\n return this.dsn?.ingestUrl\n }\n\n /** init is idempotent and browser-only for its side effects: capture first-touch\n * attribution, hydrate cohort, register the unload flush, and (unless opted out)\n * auto-capture unhandled errors. Safe to call from a React effect on every\n * render. */\n init(): void {\n if (this.started || !this.cfg.enabled) return\n this.started = true\n if (!isBrowser()) return\n\n const parsed = parseAttribution(window.location.search, document.referrer)\n this.attribution = hasAttribution(parsed)\n ? setFirstTouchOnce(parsed)\n : getFirstTouch() ?? parsed\n this.cohort = mergeCohort({\n channel: this.attribution.channel ?? deriveChannel(this.attribution),\n refCode: this.attribution.refCode,\n })\n\n const flushHidden = () => {\n if (document.visibilityState === 'hidden') this.flush(true)\n }\n window.addEventListener('visibilitychange', flushHidden)\n window.addEventListener('pagehide', () => this.flush(true))\n\n // Auto error capture — the drop-in @sentry replacement. Unhandled errors and\n // rejected promises are reported on BOTH planes: a Sentry envelope to the DSN\n // host (what reaches the error dashboard — requires a DSN) and a type:'error'\n // event on the stream (product signal in the warehouse).\n if (this.cfg.captureErrors) {\n window.addEventListener('error', (e: ErrorEvent) => {\n this.captureError(e.error ?? e.message, { handled: false })\n })\n window.addEventListener('unhandledrejection', (e: PromiseRejectionEvent) => {\n this.captureError(e.reason, { handled: false })\n })\n }\n }\n\n /** identify binds the current visitor to a stable person id (post-login). */\n identify(personId: string, traits?: Record<string, unknown>): void {\n this.personId = personId\n this.enqueue('identify', undefined, { properties: traits })\n }\n\n /** group associates the visitor with an org/team (analytics grouping, not the\n * server tenant — the server still derives tenant from the session). */\n group(groupId: string, traits?: Record<string, unknown>): void {\n this.enqueue('group', undefined, { groupId, properties: traits })\n }\n\n /** pageview records a $pageview for the current (or given) location, once per\n * view. A view is the path plus the full location, so a query or hash change\n * is a new one and a repeat call for the same place is not. */\n pageview(path?: string, properties?: Record<string, unknown>): void {\n // No `url` here: build() reads window.location.href for every event, in the\n // same tick, so this recomputed it to the identical value. Only `path` is\n // passed, because a route change fires before window.location has caught up\n // and the caller's value has to win.\n const p = path ?? (isBrowser() ? window.location.pathname : undefined)\n // Counting a page once is the client's rule, not each caller's. A page holds\n // several emitters that each correctly believe they count the first view —\n // the provider's autoPageview, a router hook, a nav autocapture — and per\n // emitter state cannot see the others. On the stream they are one page.\n const view = (p ?? '') + '\\0' + (isBrowser() ? window.location.href : '')\n if (view === this.counted) return\n this.counted = view\n this.enqueue('pageview', PAGEVIEW, { path: p, properties })\n }\n\n /** capture records a named product event with optional properties. Commerce\n * fields (productId/quantity/revenue/currency) may be passed for order events. */\n capture(\n event: string,\n properties?: Record<string, unknown>,\n commerce?: Pick<WireEvent, 'productId' | 'quantity' | 'revenue' | 'currency'>,\n ): void {\n this.enqueue('event', event, { properties, ...commerce })\n }\n\n /** captureError reports a caught error, an unhandled rejection, a React render\n * error, or a manual report to BOTH planes, from one call:\n *\n * - the ERROR PLANE — a real Sentry envelope to the DSN host. This is the one\n * that produces an issue in sentry.hanzo.ai (grouping, stack frames, AST).\n * Inert when no DSN is configured.\n * - the EVENT STREAM — a `type:'error'` row in the cloud event warehouse, so\n * an error stays correlated with the session's pageviews for product\n * analysis (readable via GET /v1/errors).\n *\n * Both carry the SAME session and subject id, so an error and the pageview\n * before it join up. Never throws back into the app; errors are higher-signal\n * than pageviews, so both planes flush promptly (a crash may unload the page\n * moments later). */\n captureError(err: unknown, context?: CaptureErrorOptions): void {\n // A failure inside the error path must not recurse through the global handlers.\n if (this.reentrant) return\n this.reentrant = true\n try {\n // ERROR PLANE FIRST, in its own try. The planes are independent, so neither\n // may be able to starve the other: `properties` is arbitrary caller data\n // (a DOM node, a React synthetic event, an axios error — all circular and\n // all common), and serializing it on the event stream can throw. When the\n // stream ran first, that throw escaped to the outer catch and the crash\n // report was never sent — silently losing exactly the signal this client\n // exists to deliver. Order and isolation are the fix.\n try {\n this.sendError(err, context)\n } catch {\n /* the error plane must never take the event stream down with it */\n }\n\n try {\n const handled = context?.handled ?? true\n const ex = normalizeError(err)\n ex.handled = handled\n // NAME: the reserved '$exception', never the message. The message was the\n // name until 0.3.20, which put every distinct error string — one per failed\n // chunk id, per ResizeObserver notification — permanently into the event\n // taxonomy, and left Error Tracking (which reads this exact name) at zero.\n //\n // TYPE 'event', not 'error'. `type` alone picks the storage plane: 'error'\n // routes to the error plane, which the product-event projection does not\n // read, so an exception filed there is invisible to Error Tracking however\n // well-formed it is. The full error record still reaches the error plane as\n // a Sentry envelope above — this row is the product-analytics breadcrumb,\n // which is what keeps a crash correlated with the session's pageviews.\n //\n // `error` is still carried: the server folds it into properties.$exception\n // (scrubbing message and stack on the way), which is the shape existing\n // readers bind to.\n this.enqueue('event', EXCEPTION, {\n error: ex,\n properties: {\n ...context?.properties,\n ...exceptionProperties(err, {\n handled,\n id: uuidv7(),\n level: context?.level,\n }),\n },\n })\n this.flush()\n } catch {\n /* nor the reverse */\n }\n } finally {\n this.reentrant = false\n }\n }\n\n /** setCohort persists cohort dimensions (e.g. signupWeek at signup) so they ride\n * every subsequent event. */\n setCohort(patch: Cohort): void {\n this.cohort = mergeCohort(patch)\n }\n\n /** flush drains the buffer to the server as ONE batch through the ONE ingest\n * front door POST /v1/event, body { batch: [Event…] }. beacon=true selects the\n * unload-safe transport. Auth is orthogonal to the wire:\n *\n * • publishable key set → rides ?ingest_key=pk-… on both sends, keeping each\n * a CORS-simple request that any origin may send.\n * • else a bearer JWT rides Authorization (fetch only — sendBeacon cannot\n * carry a header, so token apps fall back to keepalive fetch on unload).\n * • else a cookie app rides same-origin credentials (beacon carries the\n * cookie fine).\n */\n flush(beacon = false): void {\n if (!this.cfg.enabled || this.queue.length === 0) return\n const batch = this.queue\n this.queue = []\n this.clearTimer()\n\n // A publishable key and a bearer JWT are mutually exclusive doors, and the\n // BEARER WINS. It names a real principal and resolves to THAT person's org;\n // a pk- names one org for everybody holding it. So the key is what attributes\n // a visitor nobody has vouched for, and it must never displace someone who\n // has been.\n //\n // The precedence used to run the other way, which was survivable only while\n // the key had to be passed in code. Once it also resolves from the build env,\n // key-wins means setting one variable silently blanks every signed-in user's\n // token and re-files their events under whichever org minted the key — on a\n // console served to several brands from one bundle, that is a cross-tenant\n // leak introduced by an env var.\n const token = this.cfg.getToken?.() ?? undefined\n const key = token ? undefined : this.cfg.ingestKey?.trim() || undefined\n // Only a bearer JWT blocks the beacon: sendBeacon cannot set an Authorization\n // header. A pk- rides ?ingest_key; a cookie rides credentials.\n const useBeacon = beacon && !token\n const body = serializeBatch(batch)\n if (body === null) {\n if (this.cfg.debug) console.debug('[event] flush → dropped, batch unserializable')\n return\n }\n if (this.cfg.debug) console.debug('[event] flush →', EVENT_PATH, batch.length)\n this.transport.send(this.cfg.host + EVENT_PATH, body, {\n beacon: useBeacon,\n token,\n ingestKey: key,\n debug: this.cfg.debug,\n })\n }\n\n // ── internals ────────────────────────────────────────────────────────────\n\n /** sendError frames one exception as a Sentry envelope and posts it to the DSN's\n * ingest URL. The DSN's own key rides ?sentry_key= (the credential channel the\n * server trusts, and the only one a headerless beacon can carry), so NO bearer\n * or publishable key is attached here — the two planes authenticate\n * independently. Errors are sent one envelope per event, immediately: batching\n * a crash report is how you lose it. */\n private sendError(err: unknown, options?: CaptureErrorOptions): void {\n if (!this.cfg.enabled || !this.dsn) return\n const event = buildSentryEvent({\n error: err,\n options,\n identity: this.errorIdentity(),\n capturePII: this.cfg.capturePII ?? false,\n })\n const body = buildEnvelope(event, this.dsn)\n if (this.cfg.debug) console.debug('[event] error →', this.dsn.ingestUrl, event.event_id)\n this.transport.send(this.dsn.ingestUrl, body, {\n beacon: false,\n contentType: ENVELOPE_CONTENT_TYPE,\n debug: this.cfg.debug,\n })\n }\n\n /** errorIdentity is the SAME identity the event stream stamps — the OIDC subject\n * once identify() has run, else the anon id. Never email/PII. */\n private errorIdentity(): ErrorIdentity {\n return {\n userId: this.personId ?? anonId(),\n sessionId: sessionId(),\n product: this.cfg.product,\n release: this.cfg.release ?? readEnv('NEXT_PUBLIC_HANZO_RELEASE'),\n environment: this.cfg.environment ?? readEnv('NODE_ENV'),\n }\n }\n\n private enqueue(kind: EventKind, event: string | undefined, extra: Partial<WireEvent>): void {\n if (!this.cfg.enabled) return\n if (!this.started) this.init()\n this.queue.push(this.build(kind, event, extra))\n if (this.queue.length >= this.cfg.batchSize) this.flush()\n else this.schedule()\n }\n\n private build(kind: EventKind, event: string | undefined, extra: Partial<WireEvent>): WireEvent {\n const anon = anonId()\n const wire: WireEvent = {\n messageId: uuidv7(),\n type: kind,\n event,\n timestamp: new Date().toISOString(),\n distinctId: this.personId ?? anon,\n anonymousId: anon,\n personId: this.personId,\n sessionId: sessionId(),\n product: this.cfg.product,\n referrer: this.attribution.referrer,\n utm: this.attribution.utm,\n refCode: this.cohort.refCode ?? this.attribution.refCode,\n channel: this.cohort.channel ?? this.attribution.channel,\n signupWeek: this.cohort.signupWeek,\n // Where the event happened, stamped for every kind rather than only for\n // pageviews. An interaction is reported against the page it happened on,\n // and autocapture ($click/$input/$change) reaches the wire through\n // capture(), which supplies no location — so every click arrived with an\n // empty url and path, and `host`, derived from url, was empty with them.\n // That is unattributable to a page, which is the one thing a heatmap\n // needs. Read here, at the single point every event is built, so it\n // cannot go missing from a call site again.\n //\n // Before `...extra`: pageview() passes an explicit path for route\n // changes that fire before window.location has caught up, and that value\n // has to win over the one read here.\n url: isBrowser() ? window.location.href : undefined,\n path: isBrowser() ? window.location.pathname : undefined,\n library: '@hanzo/event',\n libraryVersion: VERSION,\n ...extra,\n }\n\n // A location is free text an attacker (or an ordinary product flow) controls,\n // and it is now stamped on EVERY event rather than only pageviews — so the\n // one field that is always a URL gets the same policy the error plane has\n // always applied to error text. A password-reset, invite or magic link puts\n // a JWT in the query and an address in `?email=`; without this, one click on\n // that page ships both to the warehouse in cleartext, and every later click\n // repeats it.\n //\n // AFTER `...extra`, deliberately. A call site can pass its own location —\n // pageview() passes `path`, and until this commit it passed `url` too — and\n // `extra` merges over the fields read above, so scrubbing at the read would\n // have left the highest-volume event emitting a raw location while looking\n // scrubbed. Applied to the ASSEMBLED record, the guarantee holds for every\n // call site, including ones not written yet.\n //\n // `scrubText` is the SAME policy as the error plane (secrets always,\n // PII unless capturePII) rather than a second URL-specific redactor: one\n // definition of \"must not leave the browser\", already tested, mirroring the\n // server's. Guarded on presence so an absent field stays absent instead of\n // becoming the empty string that `host` derivation reads as a page.\n const capturePII = this.cfg.capturePII ?? false\n if (wire.url) wire.url = scrubText(wire.url, capturePII)\n if (wire.path) wire.path = scrubText(wire.path, capturePII)\n if (wire.referrer) wire.referrer = scrubText(wire.referrer, capturePII)\n return wire\n }\n\n private schedule(): void {\n if (this.timer || !this.cfg.enabled) return\n this.timer = setTimeout(() => {\n this.timer = null\n this.flush()\n }, this.cfg.flushIntervalMs)\n }\n\n private clearTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer)\n this.timer = null\n }\n }\n}\n\n// ── one stream, one client ──────────────────────────────────────────────────\n//\n// A page has ONE event stream per (host, product): one queue, one anon id, one\n// credential. Two clients on it split the batch and double the pageview, and\n// the half built by the caller that had no key is refused at the door — so the\n// same page is both over- and under-counted, and neither number says so.\n//\n// Two callers ask for that stream on any real page and both are right to: the\n// app mounts a provider, and the component library mounts its own telemetry.\n// Neither can see the other, so the fix cannot live in either. It lives here,\n// where the stream is: asking twice returns the same client.\n//\n// The registry is on the PAGE, under a `Symbol.for` slot, not in module scope.\n// `@hanzo/event` and `@hanzo/event/react` are separate bundles that each carry\n// a copy of this module, so a module-scope map is per-copy and the two copies\n// never see each other's — which is exactly how the duplicate arises. A\n// well-known symbol is the one slot every copy resolves to the same value.\n//\n// Browser only. A server process serves many visitors, and one client shared\n// across requests would carry one visitor's personId into the next.\nconst CLIENTS = Symbol.for('hanzo.event.clients')\n\nfunction registry(): Map<string, Analytics> {\n const g = globalThis as unknown as Record<symbol, Map<string, Analytics> | undefined>\n const existing = g[CLIENTS]\n if (existing) return existing\n const fresh = new Map<string, Analytics>()\n g[CLIENTS] = fresh\n return fresh\n}\n\n/** createAnalytics returns the client for a stream, building it on first ask.\n * This is the ONE way to get a client: `new Analytics` bypasses the registry\n * and is for tests and for a deliberately separate instance. */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n // A disabled client emits nothing, so it can double nothing and does not take\n // the stream. Callers reach their answer at different moments — a provider\n // whose ownership resolves in an effect renders once saying `false` before it\n // has decided anything — and the client built in that moment must not become\n // the one the page keeps. Registering it would silence the page, and adopting\n // `enabled` from a later caller would let one surface overrule another's\n // reading of consent. Neither: it is simply not the stream's client.\n if (!isBrowser() || config.enabled === false) return new Analytics(config)\n const key = (config.host ?? DEFAULT_HOST) + '\\0' + config.product\n const clients = registry()\n const existing = clients.get(key)\n if (existing) {\n existing.adopt(config)\n return existing\n }\n const fresh = new Analytics(config)\n clients.set(key, fresh)\n return fresh\n}\n\n// Re-export the hydrate helpers so consumers can read persisted cohort/attribution\n// (e.g. to send refCode to the referrals API) without reaching into storage.\nexport { getCohort, getFirstTouch }\n","// Insights goals + cohorts, defined once as data so the console/insights UI and\n// every product agree on what \"a Signup\", \"a Sale\", and \"upgrade intent\" mean.\n// This is the machine-readable spec — the shared source of truth a sync step can\n// push into Insights, and what TAXONOMY.md documents.\n//\n// A goal answers \"what counts as a conversion\". A funnel answers \"by what path\".\n// The paths live in funnels.ts and a goal REFERENCES one by id: the steps are\n// written down exactly once.\n\nimport { EVENTS } from './events'\nimport { eventsOf, type FunnelId } from './funnels'\n\nexport interface GoalDef {\n /** Human label shown in Insights. */\n label: string\n /** The event whose occurrence counts as the goal conversion. */\n event: string\n /** The funnel leading to the goal — an id into FUNNELS (see funnels.ts). */\n funnelId?: FunnelId\n /** The ordered event names of `funnelId`, derived — never hand-written. */\n funnel?: string[]\n /** Optional property equality filter that qualifies the conversion. */\n filter?: { property: string; equals: string }\n}\n\nexport const GOALS: Record<'signup' | 'sale' | 'upgradeIntent' | 'activation', GoalDef> = {\n // Signup: the conversion is signup_completed, along the site signup funnel.\n signup: {\n label: 'Signup',\n event: EVENTS.SIGNUP_COMPLETED,\n funnelId: 'signup',\n funnel: eventsOf('signup'),\n },\n // Sale: a completed order qualified as a plan purchase (kind=plan).\n sale: {\n label: 'Sale',\n event: EVENTS.ORDER_COMPLETED,\n funnelId: 'upgrade',\n funnel: eventsOf('upgrade'),\n filter: { property: 'kind', equals: 'plan' },\n },\n // Upgrade intent: a plan click; pricing_viewed is the top of its funnel.\n upgradeIntent: {\n label: 'Upgrade Intent',\n event: EVENTS.PLAN_CLICKED,\n funnelId: 'upgrade',\n funnel: eventsOf('upgrade'),\n },\n // Activation: the ONE north-star conversion — an account that did the first\n // valuable thing (a successful API call, a live app, a chat answer).\n activation: {\n label: 'Activation',\n event: EVENTS.FIRST_ACTION,\n funnelId: 'apiActivation',\n funnel: eventsOf('apiActivation'),\n },\n}\n\nexport interface CohortDef {\n /** The hanzo.events column the cohort dimension maps to. */\n field: string\n label: string\n}\n\nexport const COHORTS: Record<'signupWeek' | 'channel' | 'refCode', CohortDef> = {\n signupWeek: { field: 'signup_week', label: 'Signup week' },\n channel: { field: 'channel', label: 'Acquisition channel' },\n refCode: { field: 'ref_code', label: 'Referral code' },\n}\n"]}