@hanzo/event 0.3.35 → 0.3.37

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.
Files changed (62) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +8 -8
  3. package/TAXONOMY.md +1 -1
  4. package/dist/attribution.d.ts +14 -0
  5. package/dist/attribution.d.ts.map +1 -0
  6. package/dist/core.d.ts +102 -0
  7. package/dist/core.d.ts.map +1 -0
  8. package/dist/dsn.d.ts +43 -0
  9. package/dist/dsn.d.ts.map +1 -0
  10. package/dist/events.d.ts +21 -0
  11. package/dist/events.d.ts.map +1 -0
  12. package/dist/exception.d.ts +50 -0
  13. package/dist/exception.d.ts.map +1 -0
  14. package/dist/funnels.d.ts +14 -0
  15. package/dist/funnels.d.ts.map +1 -0
  16. package/dist/goals.d.ts +24 -0
  17. package/dist/goals.d.ts.map +1 -0
  18. package/dist/index.cjs +24 -8
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +22 -292
  21. package/dist/index.d.ts +22 -292
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.mjs +24 -8
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/org.d.ts +74 -0
  26. package/dist/org.d.ts.map +1 -0
  27. package/dist/react.cjs +24 -8
  28. package/dist/react.cjs.map +1 -1
  29. package/dist/react.d.cts +13 -14
  30. package/dist/react.d.ts +13 -14
  31. package/dist/react.d.ts.map +1 -0
  32. package/dist/react.mjs +24 -8
  33. package/dist/react.mjs.map +1 -1
  34. package/dist/scrub.d.ts +20 -0
  35. package/dist/scrub.d.ts.map +1 -0
  36. package/dist/sentry.d.ts +62 -0
  37. package/dist/sentry.d.ts.map +1 -0
  38. package/dist/stack.d.ts +25 -0
  39. package/dist/stack.d.ts.map +1 -0
  40. package/dist/storage.d.ts +32 -0
  41. package/dist/storage.d.ts.map +1 -0
  42. package/dist/{core-CIhI2R7S.d.cts → types.d.ts} +21 -119
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/uid.d.ts +10 -0
  45. package/dist/uid.d.ts.map +1 -0
  46. package/dist/version.d.ts +2 -0
  47. package/dist/version.d.ts.map +1 -0
  48. package/package.json +11 -11
  49. package/src/anon.d.ts +1 -1
  50. package/src/anon.js +3 -3
  51. package/src/anon.test.ts +3 -3
  52. package/src/core.test.ts +6 -6
  53. package/src/core.ts +11 -11
  54. package/src/events.ts +1 -1
  55. package/src/exception.ts +1 -1
  56. package/src/org.test.ts +16 -0
  57. package/src/org.ts +17 -1
  58. package/src/stack.ts +1 -1
  59. package/src/types.ts +3 -3
  60. package/src/uid.ts +2 -2
  61. package/src/version.ts +1 -1
  62. package/dist/core-CIhI2R7S.d.ts +0 -380
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/attribution.ts","../src/dsn.ts","../src/org.ts","../src/scrub.ts","../src/anon.js","../src/version.ts","../src/sentry.ts","../src/exception.ts","../src/storage.ts","../src/core.ts","../src/react.tsx"],"names":["truncate","normalizeError","PAGEVIEW","EXCEPTION","createContext","useEffect","createElement","useContext","useRef","Component"],"mappings":"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","file":"react.cjs","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","/**\n * Which org owns a host's telemetry.\n *\n * A surface should not have to LEARN its key. It already knows the domain it is\n * served from, and a domain belongs to exactly one brand, so the key is derivable\n * and asking a surface to carry one is asking it to restate something already\n * true. This module answers `orgOf(location.hostname)` and hands back that org's\n * publishable key, which is what lets a static export report correctly while\n * configuring nothing.\n *\n * This is the SAME question `hanzo.id` answers at runtime for the identity hosts\n * (`pkgs/shared/src/ingest.ts`): one image serves every brand, so the key cannot\n * be a property of the build. It was, and the bill is on record — Lux's, Zoo's,\n * Osage's and Pars' visitors were all filed in HANZO's project, because one\n * build-time key was inlined for every brand. That is the white-label boundary\n * crossed in the direction that shows up latest. The marketing sites carry the\n * identical defect in its other form: each commits its OWN key literal, so the\n * fleet holds N copies of a value with one source, and a site added tomorrow\n * reports nothing until somebody remembers to paste one in.\n *\n * A `pk-` is PUBLISHABLE: it authorizes a write into one org and mints no reading\n * principal. It is readable in devtools on every deployed page that sends an\n * event, so stating it here exposes nothing that serving the page did not. What\n * it does buy is that correct attribution becomes the DEFAULT rather than\n * something each surface opts into.\n *\n * Keyed by ORG, never by host: a brand's facts repeat on every alias it owns\n * (`lux.id`, `id.lux.network`), and a key stated per host would have to be\n * repeated too — so the day someone adds an alias and forgets the key, that host\n * silently stops reporting. Stated once per org, a new alias inherits its brand's\n * key by naming its brand's domain, which is all an alias ever says.\n */\n\n/** One publishable key per org. */\nexport type Keyring = Readonly<Record<string, string>>\n\n/**\n * Each org's registrable domains. A host matches a domain when it IS that domain\n * or a subdomain of it, so `explore.lux.network` needs no entry of its own.\n *\n * An org absent from this table resolves to undefined, and that is deliberate:\n * `osage`, `pars` and `bootnode` have no project of their own yet, and reporting\n * NOTHING is the honest answer. Filing them under a brand that is not theirs is\n * the defect this module exists to prevent — it is silent, it reads as working,\n * and it is only visible later in someone else's warehouse.\n */\nexport const ORG_DOMAIN: Readonly<Record<string, readonly string[]>> = Object.freeze({\n hanzo: Object.freeze(['hanzo.ai', 'hanzo.app', 'hanzo.chat', 'hanzo.id', 'hanzo.bot', 'hanzo.sh']),\n lux: Object.freeze([\n 'lux.network',\n 'lux.exchange',\n 'lux.market',\n 'lux.finance',\n 'lux.financial',\n 'lux.credit',\n 'lux.fund',\n 'lux.id',\n ]),\n zoo: Object.freeze(['zoo.ngo', 'zoo.network', 'zoolabs.id']),\n})\n\n/**\n * Each org's publishable key — the same values `universe`'s `SPA_INGEST_KEYRING`\n * serves to the identity hosts, which are each brand's own insights team token.\n * Add an org here the day its project exists, never before.\n */\nexport const ORG_KEY: Keyring = Object.freeze({\n hanzo: 'pk-rM_CdaF2MQckGCrla113SrR1oH4zvqN8xh2I95Z9tY8',\n lux: 'pk-gUZp6ZVfhJzSwK-rb4oLbVkpCnMBx5uSCpxf_5yEhQk',\n zoo: 'pk-3TKpKnERV9AQSsBUERWkZejC1O1mUxc1jRzsP3MPbs4',\n})\n\n/** `pk-` is publishable; `sk-` is not, and there is no third thing. Checked at the\n * one point a key becomes something a page will send, so a mistyped entry fails\n * closed rather than putting a secret in every visitor's tab. */\nconst PUBLISHABLE = 'pk-'\n\n/** Strip the port and case a hostname the way a domain compares. */\nconst normalize = (host: string): string =>\n host.trim().toLowerCase().replace(/\\.$/, '').split(':')[0] ?? ''\n\n/**\n * The org that owns a host, or undefined when no brand claims it.\n *\n * Longest match wins, so a brand owning both a domain and a subdomain of another\n * brand's cannot be decided by table order. Pure and total.\n */\nexport function orgOf(host: string): string | undefined {\n const h = normalize(host)\n if (!h) return undefined\n let best: string | undefined\n let bestLen = 0\n for (const [org, domains] of Object.entries(ORG_DOMAIN)) {\n for (const d of domains) {\n if ((h === d || h.endsWith(`.${d}`)) && d.length > bestLen) {\n best = org\n bestLen = d.length\n }\n }\n }\n return best\n}\n\n/**\n * The publishable key for a host, or undefined when there is not exactly one to\n * give.\n *\n * Deliberately WITHOUT a fallback: returning Hanzo's key for an unrecognised host\n * is precisely the defect described above. Undefined is the honest answer and the\n * caller reports nothing.\n *\n * `keyring` is a parameter so the identity runtime — which receives its keyring\n * from `/config.json` because one image serves every brand — resolves through\n * this SAME function rather than a second copy of it.\n */\nexport function keyFor(host: string, keyring: Keyring = ORG_KEY): string | undefined {\n const org = orgOf(host)\n if (!org) return undefined\n const key = keyring[org]\n if (typeof key !== 'string') return undefined\n const trimmed = key.trim()\n return trimmed.startsWith(PUBLISHABLE) ? trimmed : undefined\n}\n\n/** The key for the page this code is running on; undefined off a browser. */\nexport function keyForPage(keyring: Keyring = ORG_KEY): string | undefined {\n if (typeof location === 'undefined') return undefined\n return keyFor(location.hostname, keyring)\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.\n *\n * It names what it is, not who ships it: this value is visible to anyone who opens\n * their own cookie jar, and a vendor's name has no business there. Identity is IAM's\n * concern whether or not the visitor has said who they are. */\nvar HZ_ANON_KEY = 'iam-anon-id'\n\n/** Keys an id may already be living under. READ, never written.\n *\n * Each was canonical once — `hz_anon_id` most recently, and `hz_id` before it, when a\n * no-build tag wrote a second identity space and one page could hold two people.\n * Adopting an id already in the wild is what makes this a rename rather than an\n * erasure: minting over one detaches a returning visitor from their own history.\n * They are never written, so they leave with the cookies that hold them. */\nvar HZ_ANON_ADOPT = ['hz_anon_id', '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 iam-anon-id · adopted keys · 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 */\n/**\n * hzAnonAdopted returns an id already living under a key that used to be canonical,\n * from the cookie jar first — that is the copy shared across subdomains, so a visitor\n * who arrived on one host is the same person on the next.\n */\nfunction hzAnonAdopted(s) {\n for (var i = 0; i < HZ_ANON_ADOPT.length; i++) {\n var id = hzAnonCookie(HZ_ANON_ADOPT[i]) || hzAnonItem(s, HZ_ANON_ADOPT[i])\n if (id) return id\n }\n return ''\n}\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 hzAnonAdopted(s) ||\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 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.35'\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 { keyForPage } from './org'\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 // 3. the org that owns the HOST this page is served from (`org.ts`).\n //\n // Step 3 fires only when a surface configured NOTHING, so it never overrides\n // the KMS chain above — it replaces going dark with reporting to the right\n // brand. That is what a static export needs: `output: export` inlines no env,\n // so before this the only way to report was to commit a key literal, and the\n // fleet grew one copy per site of a value with a single source.\n //\n // A surface no brand claims still has no key, and the door REFUSES an\n // unattributed event (401 `ingest_key_required`) — the reserved `$public`\n // tenant that once caught keyless beacons is retired, and anonymous ingest is\n // refused at every door on every brand host. So there is no quiet fallback to\n // rely on: an event lands in the org a credential names, or it does not land.\n ingestKey:\n config.ingestKey ?? readEnv('NEXT_PUBLIC_PUBLISHABLE_KEY') ?? keyForPage(),\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","// React bindings for @hanzo/event — a provider, an accessor hook, a route-change\n// pageview hook, and an error boundary. Framework-neutral: it takes the current\n// path as an argument (the Next app wires usePathname(); a Vite/router app passes\n// its own), so this file never imports next/*.\n//\n// 'use client'\n// import { AnalyticsProvider, useAnalytics, usePageview, ErrorBoundary } from '@hanzo/event/react'\n//\n// <AnalyticsProvider config={{ product: 'console' }}>…</AnalyticsProvider>\n// const a = useAnalytics(); usePageview(usePathname())\n\nimport {\n Component,\n createContext,\n createElement,\n useContext,\n useEffect,\n useRef,\n type ErrorInfo,\n type ReactNode,\n} from 'react'\nimport { Analytics, createAnalytics } from './core'\nimport type { AnalyticsConfig } from './types'\n\nconst Ctx = createContext<Analytics | null>(null)\n\nexport interface AnalyticsProviderProps {\n /** Provide a pre-built client, or a config to build one. */\n client?: Analytics\n config?: AnalyticsConfig\n /** Fire a pageview for the initial load (default true). */\n autoPageview?: boolean\n children: ReactNode\n}\n\nexport function AnalyticsProvider(props: AnalyticsProviderProps) {\n const { client, config, autoPageview = true, children } = props\n // No memo. createAnalytics returns the client for a stream, so asking on every\n // render hands back the same object — the identity a memo used to be here to\n // preserve. Memoizing construction is what made a config change unreachable\n // (deps held `client` alone) while adding `config` would have built a client\n // per render, since call sites pass an object literal.\n if (!client && !config) throw new Error('AnalyticsProvider requires `client` or `config`')\n const instance = client ?? createAnalytics(config as AnalyticsConfig)\n\n useEffect(() => {\n instance.init()\n if (autoPageview) instance.pageview()\n }, [instance, autoPageview])\n\n return createElement(Ctx.Provider, { value: instance }, children)\n}\n\n/** useAnalytics returns the client. Outside a provider it returns a no-op-safe\n * null-guarded proxy so calls never throw during SSR/tests. */\nexport function useAnalytics(): Analytics {\n const a = useContext(Ctx)\n if (!a) return noop\n return a\n}\n\n/** usePageview fires a pageview on every route CHANGE (not the initial mount —\n * the provider's autoPageview covers that, so pages are counted exactly once). */\nexport function usePageview(path: string | null | undefined): void {\n const a = useContext(Ctx)\n const first = useRef(true)\n useEffect(() => {\n if (first.current) {\n first.current = false\n return\n }\n if (a && path) a.pageview(path)\n }, [a, path])\n}\n\n// A shared no-op client for use outside a provider — keeps call sites total.\nconst noop = new Analytics({ product: 'unknown', enabled: false })\n\nexport interface ErrorBoundaryProps {\n children: ReactNode\n /** Rendered when a child throws. A function receives the error + a reset. */\n fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode)\n /** Explicit client; defaults to the one from AnalyticsProvider. */\n client?: Analytics\n}\n\ninterface ErrorBoundaryState {\n error: Error | null\n}\n\n/** ErrorBoundary reports React render errors to the client as error events —\n * React swallows these before window.onerror sees them, so a boundary is the\n * ONLY way to capture them. This is the React half of the @sentry replacement.\n * Pair it with AnalyticsProvider (it reads the client from context), or pass an\n * explicit `client`. */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = Ctx\n declare context: React.ContextType<typeof Ctx>\n state: ErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n const client = this.props.client ?? this.context ?? undefined\n client?.captureError(error, {\n handled: false,\n properties: { componentStack: info.componentStack, react: true },\n })\n }\n\n private reset = () => this.setState({ error: null })\n\n render(): ReactNode {\n const { error } = this.state\n if (error === null) return this.props.children\n const { fallback } = this.props\n if (typeof fallback === 'function') return fallback(error, this.reset)\n return fallback ?? null\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/attribution.ts","../src/dsn.ts","../src/org.ts","../src/scrub.ts","../src/anon.js","../src/version.ts","../src/sentry.ts","../src/exception.ts","../src/storage.ts","../src/core.ts","../src/react.tsx"],"names":["truncate","normalizeError","PAGEVIEW","EXCEPTION","createContext","useEffect","createElement","useContext","useRef","Component"],"mappings":"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","file":"react.cjs","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","/**\n * Which org owns a host's telemetry.\n *\n * A surface should not have to LEARN its key. It already knows the domain it is\n * served from, and a domain belongs to exactly one brand, so the key is derivable\n * and asking a surface to carry one is asking it to restate something already\n * true. This module answers `orgOf(location.hostname)` and hands back that org's\n * publishable key, which is what lets a static export report correctly while\n * configuring nothing.\n *\n * This is the SAME question `hanzo.id` answers at runtime for the identity hosts\n * (`pkgs/shared/src/ingest.ts`): one image serves every brand, so the key cannot\n * be a property of the build. It was, and the bill is on record — Lux's, Zoo's,\n * Osage's and Pars' visitors were all filed in HANZO's project, because one\n * build-time key was inlined for every brand. That is the white-label boundary\n * crossed in the direction that shows up latest. The marketing sites carry the\n * identical defect in its other form: each commits its OWN key literal, so the\n * fleet holds N copies of a value with one source, and a site added tomorrow\n * reports nothing until somebody remembers to paste one in.\n *\n * A `pk-` is PUBLISHABLE: it authorizes a write into one org and mints no reading\n * principal. It is readable in devtools on every deployed page that sends an\n * event, so stating it here exposes nothing that serving the page did not. What\n * it does buy is that correct attribution becomes the DEFAULT rather than\n * something each surface opts into.\n *\n * Keyed by ORG, never by host: a brand's facts repeat on every alias it owns\n * (`lux.id`, `id.lux.network`), and a key stated per host would have to be\n * repeated too — so the day someone adds an alias and forgets the key, that host\n * silently stops reporting. Stated once per org, a new alias inherits its brand's\n * key by naming its brand's domain, which is all an alias ever says.\n */\n\n/** One publishable key per org. */\nexport type Keyring = Readonly<Record<string, string>>\n\n/**\n * Each org's registrable domains. A host matches a domain when it IS that domain\n * or a subdomain of it, so `explore.lux.network` needs no entry of its own.\n *\n * An org absent from this table resolves to undefined, and that is deliberate:\n * `osage`, `pars` and `bootnode` have no project of their own yet, and reporting\n * NOTHING is the honest answer. Filing them under a brand that is not theirs is\n * the defect this module exists to prevent — it is silent, it reads as working,\n * and it is only visible later in someone else's warehouse.\n */\nexport const ORG_DOMAIN: Readonly<Record<string, readonly string[]>> = Object.freeze({\n // A brand's domains are not a pattern — `hanzoskills.com` is Hanzo's and does\n // not end in `hanzo.ai`, while `hanzo.works` is a registrable domain of its own\n // rather than a subdomain of anything here. Each is stated because each is a\n // separate fact, which is the whole reason this is a table.\n hanzo: Object.freeze([\n 'hanzo.ai',\n 'hanzo.app',\n 'hanzo.bot',\n 'hanzo.chat',\n 'hanzo.codes',\n 'hanzo.id',\n 'hanzo.sh',\n 'hanzo.team',\n 'hanzo.ventures',\n 'hanzo.works',\n 'hanzoskills.com',\n ]),\n lux: Object.freeze([\n 'lux.network',\n 'lux.exchange',\n 'lux.market',\n 'lux.finance',\n 'lux.financial',\n 'lux.credit',\n 'lux.fund',\n 'lux.id',\n ]),\n zoo: Object.freeze(['zoo.ngo', 'zoo.network', 'zoolabs.id']),\n})\n\n/**\n * Each org's publishable key — the same values `universe`'s `SPA_INGEST_KEYRING`\n * serves to the identity hosts, which are each brand's own insights team token.\n * Add an org here the day its project exists, never before.\n */\nexport const ORG_KEY: Keyring = Object.freeze({\n hanzo: 'pk-rM_CdaF2MQckGCrla113SrR1oH4zvqN8xh2I95Z9tY8',\n lux: 'pk-gUZp6ZVfhJzSwK-rb4oLbVkpCnMBx5uSCpxf_5yEhQk',\n zoo: 'pk-3TKpKnERV9AQSsBUERWkZejC1O1mUxc1jRzsP3MPbs4',\n})\n\n/** `pk-` is publishable; `sk-` is not, and there is no third thing. Checked at the\n * one point a key becomes something a page will send, so a mistyped entry fails\n * closed rather than putting a secret in every visitor's tab. */\nconst PUBLISHABLE = 'pk-'\n\n/** Strip the port and case a hostname the way a domain compares. */\nconst normalize = (host: string): string =>\n host.trim().toLowerCase().replace(/\\.$/, '').split(':')[0] ?? ''\n\n/**\n * The org that owns a host, or undefined when no brand claims it.\n *\n * Longest match wins, so a brand owning both a domain and a subdomain of another\n * brand's cannot be decided by table order. Pure and total.\n */\nexport function orgOf(host: string): string | undefined {\n const h = normalize(host)\n if (!h) return undefined\n let best: string | undefined\n let bestLen = 0\n for (const [org, domains] of Object.entries(ORG_DOMAIN)) {\n for (const d of domains) {\n if ((h === d || h.endsWith(`.${d}`)) && d.length > bestLen) {\n best = org\n bestLen = d.length\n }\n }\n }\n return best\n}\n\n/**\n * The publishable key for a host, or undefined when there is not exactly one to\n * give.\n *\n * Deliberately WITHOUT a fallback: returning Hanzo's key for an unrecognised host\n * is precisely the defect described above. Undefined is the honest answer and the\n * caller reports nothing.\n *\n * `keyring` is a parameter so the identity runtime — which receives its keyring\n * from `/config.json` because one image serves every brand — resolves through\n * this SAME function rather than a second copy of it.\n */\nexport function keyFor(host: string, keyring: Keyring = ORG_KEY): string | undefined {\n const org = orgOf(host)\n if (!org) return undefined\n const key = keyring[org]\n if (typeof key !== 'string') return undefined\n const trimmed = key.trim()\n return trimmed.startsWith(PUBLISHABLE) ? trimmed : undefined\n}\n\n/** The key for the page this code is running on; undefined off a browser. */\nexport function keyForPage(keyring: Keyring = ORG_KEY): string | undefined {\n if (typeof location === 'undefined') return undefined\n return keyFor(location.hostname, keyring)\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 served at\n * /v1/event.js; vendors this file and its tag.go serves the marked region\n * with the tag as one asset, so cloud 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 that copy:\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.\n *\n * It names what it is, not who ships it: this value is visible to anyone who opens\n * their own cookie jar, and a vendor's name has no business there. Identity is IAM's\n * concern whether or not the visitor has said who they are. */\nvar HZ_ANON_KEY = 'iam-anon-id'\n\n/** Keys an id may already be living under. READ, never written.\n *\n * Each was canonical once — `hz_anon_id` most recently, and `hz_id` before it, when a\n * no-build tag wrote a second identity space and one page could hold two people.\n * Adopting an id already in the wild is what makes this a rename rather than an\n * erasure: minting over one detaches a returning visitor from their own history.\n * They are never written, so they leave with the cookies that hold them. */\nvar HZ_ANON_ADOPT = ['hz_anon_id', '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 iam-anon-id · adopted keys · 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 */\n/**\n * hzAnonAdopted returns an id already living under a key that used to be canonical,\n * from the cookie jar first — that is the copy shared across subdomains, so a visitor\n * who arrived on one host is the same person on the next.\n */\nfunction hzAnonAdopted(s) {\n for (var i = 0; i < HZ_ANON_ADOPT.length; i++) {\n var id = hzAnonCookie(HZ_ANON_ADOPT[i]) || hzAnonItem(s, HZ_ANON_ADOPT[i])\n if (id) return id\n }\n return ''\n}\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 hzAnonAdopted(s) ||\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 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.37'\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 ingest endpoint 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 entry point:\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 entry point 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 endpoint, 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 endpoint 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 { keyForPage } from './org'\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 entry point\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 endpoint 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 // 3. the org that owns the HOST this page is served from (`org.ts`).\n //\n // Step 3 fires only when a surface configured NOTHING, so it never overrides\n // the KMS chain above — it replaces going dark with reporting to the right\n // brand. That is what a static export needs: `output: export` inlines no env,\n // so before this the only way to report was to commit a key literal, and the\n // fleet grew one copy per site of a value with a single source.\n //\n // A surface no brand claims still has no key, and the edge REFUSES an\n // unattributed event (401 `ingest_key_required`) — the reserved `$public`\n // tenant that once caught keyless beacons is retired, and anonymous ingest is\n // refused at every edge on every brand host. So there is no quiet fallback to\n // rely on: an event lands in the org a credential names, or it does not land.\n ingestKey:\n config.ingestKey ?? readEnv('NEXT_PUBLIC_PUBLISHABLE_KEY') ?? keyForPage(),\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 * endpoint 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 credentials, 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 edge — 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","// React bindings for @hanzo/event — a provider, an accessor hook, a route-change\n// pageview hook, and an error boundary. Framework-neutral: it takes the current\n// path as an argument (the Next app wires usePathname(); a Vite/router app passes\n// its own), so this file never imports next/*.\n//\n// 'use client'\n// import { AnalyticsProvider, useAnalytics, usePageview, ErrorBoundary } from '@hanzo/event/react'\n//\n// <AnalyticsProvider config={{ product: 'console' }}>…</AnalyticsProvider>\n// const a = useAnalytics(); usePageview(usePathname())\n\nimport {\n Component,\n createContext,\n createElement,\n useContext,\n useEffect,\n useRef,\n type ErrorInfo,\n type ReactNode,\n} from 'react'\nimport { Analytics, createAnalytics } from './core'\nimport type { AnalyticsConfig } from './types'\n\nconst Ctx = createContext<Analytics | null>(null)\n\nexport interface AnalyticsProviderProps {\n /** Provide a pre-built client, or a config to build one. */\n client?: Analytics\n config?: AnalyticsConfig\n /** Fire a pageview for the initial load (default true). */\n autoPageview?: boolean\n children: ReactNode\n}\n\nexport function AnalyticsProvider(props: AnalyticsProviderProps) {\n const { client, config, autoPageview = true, children } = props\n // No memo. createAnalytics returns the client for a stream, so asking on every\n // render hands back the same object — the identity a memo used to be here to\n // preserve. Memoizing construction is what made a config change unreachable\n // (deps held `client` alone) while adding `config` would have built a client\n // per render, since call sites pass an object literal.\n if (!client && !config) throw new Error('AnalyticsProvider requires `client` or `config`')\n const instance = client ?? createAnalytics(config as AnalyticsConfig)\n\n useEffect(() => {\n instance.init()\n if (autoPageview) instance.pageview()\n }, [instance, autoPageview])\n\n return createElement(Ctx.Provider, { value: instance }, children)\n}\n\n/** useAnalytics returns the client. Outside a provider it returns a no-op-safe\n * null-guarded proxy so calls never throw during SSR/tests. */\nexport function useAnalytics(): Analytics {\n const a = useContext(Ctx)\n if (!a) return noop\n return a\n}\n\n/** usePageview fires a pageview on every route CHANGE (not the initial mount —\n * the provider's autoPageview covers that, so pages are counted exactly once). */\nexport function usePageview(path: string | null | undefined): void {\n const a = useContext(Ctx)\n const first = useRef(true)\n useEffect(() => {\n if (first.current) {\n first.current = false\n return\n }\n if (a && path) a.pageview(path)\n }, [a, path])\n}\n\n// A shared no-op client for use outside a provider — keeps call sites total.\nconst noop = new Analytics({ product: 'unknown', enabled: false })\n\nexport interface ErrorBoundaryProps {\n children: ReactNode\n /** Rendered when a child throws. A function receives the error + a reset. */\n fallback?: ReactNode | ((error: Error, reset: () => void) => ReactNode)\n /** Explicit client; defaults to the one from AnalyticsProvider. */\n client?: Analytics\n}\n\ninterface ErrorBoundaryState {\n error: Error | null\n}\n\n/** ErrorBoundary reports React render errors to the client as error events —\n * React swallows these before window.onerror sees them, so a boundary is the\n * ONLY way to capture them. This is the React half of the @sentry replacement.\n * Pair it with AnalyticsProvider (it reads the client from context), or pass an\n * explicit `client`. */\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n static contextType = Ctx\n declare context: React.ContextType<typeof Ctx>\n state: ErrorBoundaryState = { error: null }\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error }\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n const client = this.props.client ?? this.context ?? undefined\n client?.captureError(error, {\n handled: false,\n properties: { componentStack: info.componentStack, react: true },\n })\n }\n\n private reset = () => this.setState({ error: null })\n\n render(): ReactNode {\n const { error } = this.state\n if (error === null) return this.props.children\n const { fallback } = this.props\n if (typeof fallback === 'function') return fallback(error, this.reset)\n return fallback ?? null\n }\n}\n"]}