@hanzo/event 0.3.16 → 0.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TAXONOMY.md +1 -1
- package/dist/{core-BZraSvcr.d.cts → core-D4PaPlOB.d.cts} +3 -3
- package/dist/{core-BZraSvcr.d.ts → core-D4PaPlOB.d.ts} +3 -3
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/dist/react.cjs +5 -5
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +5 -5
- package/dist/react.mjs.map +1 -1
- package/hz.js +5 -3
- package/package.json +1 -1
- package/src/core.test.ts +8 -8
- package/src/core.ts +4 -4
- package/src/hz.test.ts +3 -3
- package/src/types.ts +3 -3
- package/src/version.ts +1 -1
package/dist/react.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/attribution.ts","../src/dsn.ts","../src/events.ts","../src/scrub.ts","../src/anon.js","../src/version.ts","../src/sentry.ts","../src/storage.ts","../src/core.ts","../src/react.tsx"],"names":["normalizeError"],"mappings":"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","file":"react.mjs","sourcesContent":["// Pure attribution helpers: parse first-touch UTM/referrer/refCode from a URL,\n// derive the acquisition channel, and compute the ISO week for the signup cohort.\n// No I/O, no globals — trivially testable.\n\nimport type { Attribution } from './types'\n\nconst SOCIAL_HOSTS = [\n 'facebook.', 'instagram.', 'twitter.', 'x.com', 't.co', 'linkedin.',\n 'reddit.', 'youtube.', 'tiktok.', 'pinterest.', 'news.ycombinator.com',\n]\nconst SEARCH_HOSTS = ['google.', 'bing.', 'duckduckgo.', 'yahoo.', 'baidu.', 'ecosia.']\n\n/** parseAttribution reads UTM params + ref/refCode from a query string and pairs\n * them with the referrer. `search` is a location.search value (\"?utm_source=…\"). */\nexport function parseAttribution(search: string, referrer: string): Attribution {\n const q = new URLSearchParams(search || '')\n const get = (k: string) => {\n const v = q.get(k)\n return v ? v.trim() : undefined\n }\n const a: Attribution = {\n utm: {\n source: get('utm_source'),\n medium: get('utm_medium'),\n campaign: get('utm_campaign'),\n term: get('utm_term'),\n content: get('utm_content'),\n },\n referrer: referrer ? referrer.trim() : undefined,\n refCode: get('ref') || get('refCode') || get('ref_code') || undefined,\n }\n a.channel = deriveChannel(a)\n return a\n}\n\n/** deriveChannel classifies the visit: paid | referral | social | organic | direct. */\nexport function deriveChannel(a: Attribution): string {\n const medium = (a.utm.medium || '').toLowerCase()\n if (/(cpc|ppc|paid|paidsearch|display|cpm)/.test(medium)) return 'paid'\n if (a.utm.source || a.utm.campaign) return 'campaign'\n if (a.refCode) return 'referral'\n const host = hostOf(a.referrer)\n if (!host) return 'direct'\n if (SOCIAL_HOSTS.some((h) => host.includes(h))) return 'social'\n if (SEARCH_HOSTS.some((h) => host.includes(h))) return 'organic'\n return 'referral'\n}\n\n/** hostOf extracts a bare lowercase host from a URL; \"\" when unparseable. */\nexport function hostOf(raw?: string): string {\n if (!raw) return ''\n let s = raw.trim()\n const scheme = s.indexOf('://')\n if (scheme >= 0) s = s.slice(scheme + 3)\n const cut = s.search(/[/?#]/)\n if (cut >= 0) s = s.slice(0, cut)\n const at = s.indexOf('@')\n if (at >= 0) s = s.slice(at + 1)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s.toLowerCase().trim()\n}\n\n/** hasAttribution reports whether anything was captured (so we don't persist an\n * empty first-touch that would shadow a later real one). */\nexport function hasAttribution(a: Attribution): boolean {\n return Boolean(\n a.utm.source || a.utm.medium || a.utm.campaign || a.utm.term ||\n a.utm.content || a.refCode || (a.referrer && hostOf(a.referrer)),\n )\n}\n\n/** isoWeek returns the ISO-8601 week label, e.g. \"2026-W28\". */\nexport function isoWeek(d: Date): string {\n // Copy to UTC midnight; ISO week: Thursday-anchored.\n const date = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()))\n const day = date.getUTCDay() || 7\n date.setUTCDate(date.getUTCDate() + 4 - day)\n const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1))\n const week = Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7)\n return `${date.getUTCFullYear()}-W${String(week).padStart(2, '0')}`\n}\n","/**\n * The product → Sentry 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 Sentry 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/sentry/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_DSN maps a `product` to the DSN its errors are submitted to. */\nexport const PRODUCT_DSN: Readonly<Record<string, string>> = Object.freeze({\n // hanzo-console — console.hanzo.ai (also served embedded by the cloud binary)\n console:\n 'https://1:0c8054dbde157f4f420c56b58660052b2ad782293c4de1d606ef8fbc46a0bf34@api.hanzo.ai/v1/sentry/019fa40b-94ae-7f1d-8f7b-e92f123fad42',\n // hanzo-app — hanzo.app\n app: 'https://1:b3e1173125568c80f91ef4b1fabbbd2d7e22341de02b33ce7e22ef4fc16a196e@api.hanzo.ai/v1/sentry/019f9b1e-57eb-7171-9d92-72c0b85e4b4b',\n // hanzo-ai — hanzo.ai (the marketing site; `site` is the product name it declares)\n site: 'https://1:d9cbfb844958bd7ef2a455600f00fbf237fbd71b75c1504f137773096d6aa53f@api.hanzo.ai/v1/sentry/019f9b1e-5785-7359-ad0b-f75db8e58c99',\n})\n\n/** dsnForProduct resolves the registered DSN for a product, or undefined when the\n * product has no project yet — which leaves the error plane inert rather than\n * guessing a destination and silently posting a surface's errors into the wrong\n * project. */\nexport function dsnForProduct(product: string | undefined): string | undefined {\n if (!product) return undefined\n return PRODUCT_DSN[product]\n}\n","// The ONE product-analytics vocabulary. Every Hanzo surface emits these exact\n// names so funnels, goals, and cohorts line up across console/chat/app/site/admin.\n// Pageviews use the reserved \"$pageview\" name (emitted by analytics.pageview()),\n// matching the server read lens.\n//\n// Naming is a closed convention, not a style preference (see TAXONOMY.md):\n// • snake_case, `<object>_<verb-in-past-tense>` — signup_completed, plan_clicked.\n// • Names are CONSTANTS, never interpolated. A dimension (framework, model,\n// plan, source) is a PROPERTY, never part of the name. `deploy_succeeded`\n// with {framework:'static'} — never `deploy_static_succeeded`.\n// • One name per user-visible moment, shared by every surface. The surface is\n// already on the wire as `product`, so a name is never product-prefixed.\n\nexport const EVENTS = {\n // Signup funnel: view -> submit -> verify -> completed -> first action.\n SIGNUP_VIEWED: 'signup_viewed',\n SIGNUP_SUBMITTED: 'signup_submitted',\n SIGNUP_VERIFIED: 'signup_verified',\n SIGNUP_COMPLETED: 'signup_completed',\n /** A RETURNING user authenticated — the non-signup half of the IAM callback.\n * Keeping it distinct is what stops returning logins from inflating signups. */\n LOGIN_COMPLETED: 'login_completed',\n /** Activation: the first moment of real value. ONE event for every product —\n * the product-specific moment is the `action` property (api_call, app_live,\n * chat_reply), never a new event name. */\n FIRST_ACTION: 'first_action',\n\n // Waitlist + referral.\n WAITLIST_JOINED: 'waitlist_joined',\n WAITLIST_SHARED: 'waitlist_shared',\n REFERRAL_USED: 'referral_used',\n REFERRAL_CLAIMED: 'referral_claimed',\n\n // Upgrade-intent + purchase.\n PRICING_VIEWED: 'pricing_viewed',\n PLAN_CLICKED: 'plan_clicked',\n CHECKOUT_STARTED: 'checkout_started',\n ORDER_COMPLETED: 'order_completed',\n\n // Feature usage — generic + the common key surfaces across products.\n FEATURE_USED: 'feature_used',\n API_KEY_CREATED: 'api_key_created',\n APP_CREATED: 'app_created',\n PROJECT_CREATED: 'project_created',\n AGENT_CREATED: 'agent_created',\n CHAT_STARTED: 'chat_started',\n CHAT_MESSAGE_SENT: 'chat_message_sent',\n /** The user switched model/endpoint — the single strongest quality signal a\n * chat surface emits (a switch usually follows a bad answer). */\n MODEL_SWITCHED: 'model_switched',\n TASK_STARTED: 'task_started',\n TASK_COMPLETED: 'task_completed',\n\n // Build → ship. `build_*` is a MODEL producing an artifact; `deploy_*` is that\n // artifact going live. Intent (build_started) is never the same event as the\n // artifact existing (app_created) — conflating them makes the funnel lie.\n BUILD_STARTED: 'build_started',\n /** A model finished producing an artifact (an app build, a chat reply, an agent\n * run). Carries `durationMs` — the outcome event owns its own duration, so no\n * paired start event is needed. */\n GENERATION_COMPLETED: 'generation_completed',\n GENERATION_FAILED: 'generation_failed',\n DEPLOY_STARTED: 'deploy_started',\n DEPLOY_SUCCEEDED: 'deploy_succeeded',\n DEPLOY_FAILED: 'deploy_failed',\n} as const\n\nexport type EventName = (typeof EVENTS)[keyof typeof EVENTS]\n\n/** The reserved event name a pageview is stored under (server + read lens). */\nexport const PAGEVIEW = '$pageview'\n","// Client-side redaction for error text — a faithful port of the server's\n// errortracking scrub (o11y pkg/modules/errortracking/implerrortracking/scrub.go),\n// applied BEFORE anything leaves the browser. Two layers, default-secure:\n//\n// - Secret shapes are ALWAYS redacted (sk-… keys, bearer/JWT tokens, DB DSNs,\n// PANs, cloud keys). There is no mode that ships a secret off-device.\n// - PII (email/IP) is scrubbed UNLESS capturePII is explicitly enabled.\n//\n// The server scrubs again — this is defense in depth, not a substitute — but the\n// point is that a Hanzo browser never emits a raw secret/email/IP in the first\n// place. Pure, no I/O.\n\nconst REDACTED = '[redacted]'\nconst EMAIL_MARK = '[email]'\nconst IP_MARK = '[ip]'\n\n// Secret patterns mirror scrub.go's secretPatterns. Order matters (broad DSN/PAN\n// rules run last). All are applied unconditionally.\nconst SECRET_PATTERNS: RegExp[] = [\n /-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,\n /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}/g, // JWT\n /\\bbearer\\s+[A-Za-z0-9._~+/-]{12,}=*/gi, // bearer token\n /\\b(?:sk|pk|rk)-[A-Za-z0-9]{2,}-?[A-Za-z0-9]{12,}/g, // openai-style\n /\\b(?:sk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, // stripe\n /\\bhk-[A-Za-z0-9]{16,}/g, // hanzo key\n /\\bAKIA[0-9A-Z]{16}\\b/g, // aws access key id\n /\\bASIA[0-9A-Z]{16}\\b/g, // aws sts key id\n /\\bAIza[0-9A-Za-z_-]{20,}/g, // google api key\n /\\bgh[posru]_[A-Za-z0-9]{20,}/g, // github token\n /\\bxox[baprs]-[A-Za-z0-9-]{10,}/g, // slack token\n // Creds in a URL/DSN. The repetition is BOUNDED on purpose: the unbounded form\n // ([^\\s:@/]+:[^\\s@/]+@) backtracks quadratically on colon-rich text with no\n // terminating '@' — an HTML error page pasted into an error message took 4.9s\n // at 32KB and >60s at 128KB, freezing the main thread from inside captureError.\n // Real userinfo is far below these caps, so bounding costs nothing.\n /[a-zA-Z][a-zA-Z0-9+.-]{0,32}:\\/\\/[^\\s:@/]{1,256}:[^\\s@/]{1,256}@/g,\n]\n\n/** Candidate card numbers. Gated by Luhn below — the bare digit-run pattern is a\n * false-positive cannon that redacts every millisecond epoch, order id and\n * phone number it sees (\"request 1753468800000 timed out\" became\n * \"request [redacted]timed out\"), which destroys the readability of the very\n * error messages this client exists to deliver. */\nconst RE_PAN = /\\b(?:\\d[ -]?){13,19}\\b/g\n\n/** luhn reports whether a digit string satisfies the Luhn checksum. Every real\n * card number does, so gating redaction on it removes the false positives\n * WITHOUT introducing a false negative — the safe direction for a redactor. */\nfunction luhn(digits: string): boolean {\n let sum = 0\n let alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) {\n d *= 2\n if (d > 9) d -= 9\n }\n sum += d\n alt = !alt\n }\n return sum % 10 === 0\n}\n\n/** redactPAN removes digit runs that actually check out as card numbers. */\nfunction redactPAN(s: string): string {\n return s.replace(RE_PAN, (m) => {\n const digits = m.replace(/[ -]/g, '')\n if (digits.length < 13 || digits.length > 19) return m\n return luhn(digits) ? REDACTED : m\n })\n}\n\n// Bounded to the RFC 5321 maxima (local-part 64, domain 255) for the same reason\n// as the creds-in-URL rule: the unbounded form backtracks quadratically across a\n// long run of local-part-legal characters that never reaches an '@' — measured at\n// 20ms on an 8KB worst case, on the main thread, per captured error. No real\n// address is excluded by these caps.\nconst RE_EMAIL = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\\.[A-Za-z]{2,24}/g\nconst RE_IPV4 = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g\nconst RE_IPV6 = /\\b(?:[0-9A-Fa-f]{1,4}:){2,7}[0-9A-Fa-f]{1,4}\\b/g\n\n// A CREDENTIAL IN A QUERY PARAM HAS NO SHAPE TO MATCH.\n//\n// Every pattern above recognises a secret by what it LOOKS like — a JWT's three\n// dots, `sk-`, `AKIA`, `ghp_`. An OAuth `code`, a `state`, a password-reset\n// nonce and an invite token are opaque random strings, indistinguishable from a\n// page id, so none of them match and all of them survive.\n//\n// That matters because the client stamps `url: window.location.href` on EVERY\n// event, not just pageviews. So one visit to `/callback?code=…&state=…` puts a\n// live authorization code on the wire, once per event, in cleartext — and the\n// code is exchangeable until it is redeemed.\n//\n// The fix is to redact by the NAME the value is filed under rather than by the\n// value's shape, which is the only signal available for an opaque token. The\n// name half is bounded (`{1,32}`) and the value half stops at the first\n// separator, so neither half can backtrack across a long string — the same\n// discipline the creds-in-URL pattern above documents.\nconst CREDENTIAL_PARAMS = [\n 'code', 'state', 'token', 'access_token', 'id_token', 'refresh_token',\n 'auth', 'authorization', 'secret', 'client_secret', 'password', 'passwd', 'pwd',\n 'api_key', 'apikey', 'key', 'session', 'session_id', 'sid',\n 'sig', 'signature', 'nonce', 'otp', 'invite', 'invitation',\n 'reset_token', 'confirmation_token', 'magic', 'ticket', 'assertion',\n]\nconst RE_CREDENTIAL_PARAM = new RegExp(\n '([?&#;](?:' + CREDENTIAL_PARAMS.join('|') + ')=)[^&#;\\\\s]{1,4096}',\n 'gi',\n)\n\n/** redactCredentialParams removes the VALUE of any query parameter whose NAME\n * says it carries a credential, leaving the name so the URL still reads. */\nexport function redactCredentialParams(s: string): string {\n return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix: string) => prefix + REDACTED)\n}\n\n/** redactSecrets removes known secret shapes. Always applied. */\nexport function redactSecrets(s: string): string {\n s = redactCredentialParams(s)\n for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED)\n return redactPAN(s)\n}\n\n/** scrubPII masks emails and IPs. Applied unless PII capture is enabled. */\nexport function scrubPII(s: string): string {\n s = s.replace(RE_EMAIL, EMAIL_MARK)\n s = s.replace(RE_IPV6, IP_MARK)\n s = s.replace(RE_IPV4, IP_MARK)\n return s\n}\n\n/** Longest free-text field this module will scrub. Every pattern here is a regex\n * run synchronously on the main thread, and the input is attacker-influenced —\n * `throw new Error(await res.text())` against an HTML error page is a one-line\n * way to hand us 128KB. Bounding the INPUT bounds the work regardless of which\n * pattern is pathological. 8KB is far beyond any real error message. */\nexport const MAX_SCRUB_LEN = 8192\n\n/** truncate caps a string at MAX_SCRUB_LEN, marking that it was cut so a reader\n * never mistakes a truncated message for the whole one. */\nexport function truncate(s: string, max = MAX_SCRUB_LEN): string {\n return s.length > max ? s.slice(0, max) + '… [truncated]' : s\n}\n\n/** scrubText applies the redaction policy to a free-text field. Input is capped\n * first: unbounded text is a denial-of-service surface, not just a size problem. */\nexport function scrubText(s: string | undefined, capturePII = false): string {\n if (!s) return s ?? ''\n s = truncate(s)\n s = redactSecrets(s)\n if (!capturePII) s = scrubPII(s)\n return s\n}\n","/*! anon.js — THE anonymous-identity chain. ONE implementation, three distributions.\n *\n * One browser is ONE person on every Hanzo surface, whichever client a page\n * happens to have loaded. There were three implementations writing TWO keys —\n * `hz_anon_id` (the npm client, the hosted tag) and `hz_id` (hz.js) — so the same\n * visitor was several people depending on which snippet the surface shipped.\n *\n * The three call sites:\n * 1. src/storage.ts — the bundled npm client; IMPORTS this file.\n * 2. hz.js — the no-build script tag; INLINES the marked region.\n * 3. hanzoai/cloud apps/analytics/tag.js — the tag the door hosts at\n * /v1/event.js; vendors this file and its tag.go serves the marked region\n * with the tag as one asset, so the door holds no second copy either.\n *\n * (2) and (3) have no bundler and cannot import anything, which is why the chain\n * lives in a file that is plain ES5 rather than in a .ts: the region between the\n * BEGIN and END markers is COPIED VERBATIM, and src/anon.test.ts fails if hz.js's\n * copy is so much as a byte different. Keep the region ES5, dependency-free,\n * `hz`-prefixed (it is spliced into other people's scopes) and unformatted — a\n * reformat of one copy is a diff against the other.\n */\n\n/* ── BEGIN hz anon chain — copied VERBATIM into hz.js and hanzoai/cloud ────── */\n\n/** The ONE anonymous-id key, on every surface and in every distribution. */\nvar HZ_ANON_KEY = 'hz_anon_id'\n\n/** hz.js used to write `hz_id` — a SECOND identity space, so the one-paste tag\n * and the npm client were two different people on one page. It is READ and never\n * written: an id already in the wild is ADOPTED into the shared identity, because\n * minting over one detaches a returning visitor from their own history. */\nvar HZ_ANON_LEGACY_KEY = 'hz_id'\n\n/** The registrable domain the cookie is scoped to, so docs, cloud, console,\n * studio, pay, id and www all read the ONE id. localStorage cannot do this: it is\n * ORIGIN-scoped, which is what made one journey arrive as several strangers. */\nvar HZ_ANON_DOMAIN = 'hanzo.ai'\n\n/** Two years, rewritten on every read, so the cookie rolls forward with the\n * visitor instead of expiring two years after first touch. Safari caps a\n * SCRIPT-written cookie at 7 days no matter what this says, so the rewrite is\n * what keeps a returning Safari visitor: each read re-arms the 7-day window. */\nvar HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60\n\n/** Last resort for a browser that refuses cookies AND localStorage: without it\n * every event in a page load would mint an id of its own. */\nvar hzAnonMemo\n\n/**\n * hzUuidv7 mints a time-ordered UUIDv7 (RFC 9562 §5.7) for `now` in epoch ms.\n *\n * It has to be v7, and this is the only minter any distribution may use. The\n * session rollups on the event plane derive a session's start instant FROM THE ID\n * and admit only ids whose version nibble is 7, so a crypto.randomUUID() (v4) id\n * is not merely unordered there — it is DISCARDED, silently, and the rollup stays\n * empty. Without crypto only the ENTROPY degrades; the shape is always a valid v7.\n */\nfunction hzUuidv7(now) {\n var b = new Uint8Array(16)\n var i\n var c = typeof crypto !== 'undefined' ? crypto : undefined\n if (c && typeof c.getRandomValues === 'function') c.getRandomValues(b)\n else for (i = 0; i < 16; i++) b[i] = (Math.random() * 256) | 0\n var t = Math.floor(now === undefined ? Date.now() : now)\n for (i = 5; i >= 0; i--) {\n b[i] = t % 256\n t = Math.floor(t / 256)\n }\n b[6] = 0x70 | (b[6] & 0x0f) // version 7\n b[8] = 0x80 | (b[8] & 0x3f) // variant 0b10\n var h = ''\n for (i = 0; i < 16; i++) {\n h += (b[i] + 0x100).toString(16).slice(1)\n if (i === 3 || i === 5 || i === 7 || i === 9) h += '-'\n }\n return h\n}\n\n/** The cookie jar, or null wherever there is no document to read one from. */\nfunction hzAnonJar() {\n try {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null\n return document\n } catch (e) {\n return null // sandboxed frame with an opaque origin\n }\n}\n\n/** localStorage, or null when the browser refuses it (Safari private mode). */\nfunction hzAnonStore() {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null\n return window.localStorage\n } catch (e) {\n return null\n }\n}\n\n/** One stored value, or '' — a jar can read as well as refuse to. */\nfunction hzAnonItem(store, name) {\n try {\n return (store && store.getItem(name)) || ''\n } catch (e) {\n return ''\n }\n}\n\n/** The value of cookie `name`, or ''. */\nfunction hzAnonCookie(name) {\n var d = hzAnonJar()\n if (!d) return ''\n var parts = d.cookie.split(';')\n for (var i = 0; i < parts.length; i++) {\n var eq = parts[i].indexOf('=')\n if (eq < 0 || parts[i].slice(0, eq).trim() !== name) continue\n var v = parts[i].slice(eq + 1).trim()\n if (!v) continue\n try {\n return decodeURIComponent(v)\n } catch (e) {\n return v // not percent-encoded — take it as written\n }\n }\n return ''\n}\n\n/** Writes `name` on the registrable domain, for as long as the browser allows. */\nfunction hzAnonWrite(name, value) {\n var d = hzAnonJar()\n if (!d) return\n var host = ''\n var secure = false\n try {\n if (typeof window !== 'undefined' && window.location) {\n host = window.location.hostname || ''\n // A Secure cookie is refused outright by a non-secure origin, which would\n // strand http://localhost dev on the localStorage path.\n secure = window.location.protocol === 'https:'\n }\n } catch (e) {\n /* location unreachable — write a host-only, non-secure cookie */\n }\n // encodeURIComponent leaves a UUID byte-identical while making any value that is\n // not one unable to forge a `;` and inject an attribute.\n var c = name + '=' + encodeURIComponent(value)\n c += '; Path=/; Max-Age=' + HZ_ANON_MAX_AGE + '; SameSite=Lax'\n // Off hanzo.ai (localhost, previews, other registrable domains) the attribute\n // would be rejected and the whole cookie dropped, so it stays host-only there.\n // Prefixing both sides with '.' matches the domain itself and its subdomains\n // while refusing a suffix that merely ends in the same letters (evilhanzo.ai).\n if (('.' + host).slice(-(HZ_ANON_DOMAIN.length + 1)) === '.' + HZ_ANON_DOMAIN) {\n c += '; Domain=' + HZ_ANON_DOMAIN\n }\n if (secure) c += '; Secure'\n try {\n d.cookie = c\n } catch (e) {\n /* cookies refused — localStorage still carries the id */\n }\n}\n\n/**\n * hzAnonId returns the stable anonymous id for this browser, '' during SSR.\n *\n * Resolution is strictly ADDITIVE — every id that already exists is ADOPTED, and\n * only a browser holding none of them is given a new one:\n *\n * cookie · localStorage hz_anon_id · localStorage hz_id · in-memory · mint\n *\n * Minting over an id resets a returning visitor and detaches them from their own\n * history, so the order is the migration: the cookie is the shared home, the two\n * localStorage keys are what the three implementations wrote before it existed,\n * and each is read until nothing is left to adopt.\n *\n * localStorage keeps being written, so a rollback finds everyone where it left\n * them, and a browser that refuses cookies still holds one id per origin.\n */\nfunction hzAnonId() {\n if (typeof window === 'undefined') return '' // SSR / prerender: no browser to identify\n var s = hzAnonStore()\n var id =\n hzAnonCookie(HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_LEGACY_KEY) ||\n hzAnonMemo ||\n hzUuidv7()\n hzAnonMemo = id\n hzAnonWrite(HZ_ANON_KEY, id)\n try {\n if (s && s.getItem(HZ_ANON_KEY) !== id) s.setItem(HZ_ANON_KEY, id)\n } catch (e) {\n /* quota exhausted, or a private-mode jar that reads but refuses writes */\n }\n return id\n}\n\n/* ── END hz anon chain ─────────────────────────────────────────────────────── */\n\nexport { hzAnonId, hzUuidv7 }\n","// The 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.16'\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/sentry 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/sentry/<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 const ingestUrl =\n `${origin}/v1/sentry/${encodeURIComponent(projectId)}/envelope/` +\n `?sentry_key=${encodeURIComponent(publicKey)}`\n return { publicKey, origin, projectId, 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.origin}/v1/sentry/${dsn.projectId}`,\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","// SSR-safe browser storage for stable identifiers and first-touch state. Every\n// accessor no-ops (returns undefined) when there is no window/localStorage, so the\n// client imports cleanly in a Next.js server component.\n//\n// The anonymous id is the one value that must outlive an ORIGIN, and it is also\n// the one value the OTHER two distributions must agree with, so its chain lives in\n// ./anon.js and this file only calls it. Everything else here stays origin-local.\n\nimport { hzAnonId } from './anon.js'\nimport type { Attribution, Cohort } from './types'\nimport { uuidv7 } from './uid'\n\nconst KEY = {\n session: 'hz_session',\n firstTouch: 'hz_first_touch',\n cohort: 'hz_cohort',\n} as const\n\n/** 30-minute inactivity window defines a session (PostHog/GA convention). */\nconst SESSION_TTL_MS = 30 * 60 * 1000\n\nfunction ls(): Storage | undefined {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return undefined\n return window.localStorage\n } catch {\n return undefined // Safari private mode / blocked storage\n }\n}\n\n/**\n * Stable anonymous id, shared by every *.hanzo.ai surface AND by every Hanzo\n * client on the page — the npm client, hz.js and the hosted tag all run the one\n * chain in ./anon.js, so which snippet a surface loaded no longer decides who the\n * visitor is.\n *\n * It lives in a first-party cookie on the registrable domain because localStorage\n * is ORIGIN-scoped: docs, cloud and console each minted their own id for the same\n * person, so one marketing → docs → signup → checkout journey arrived as several\n * strangers — 463 anonymous identities carried 545 events in a week, about 1.2\n * events each.\n */\nexport function anonId(): string | undefined {\n return hzAnonId() || undefined // '' during SSR / prerender\n}\n\ninterface SessionState {\n id: string\n last: number\n}\n\n/**\n * Current session id, rotated after SESSION_TTL_MS of inactivity.\n *\n * Minted at `now`, so the v7 timestamp the id carries IS the session's start\n * instant — which is what the session rollups partition and order on. Passing the\n * caller's clock rather than reading Date.now() again keeps the id's embedded time\n * and the recorded `last` from disagreeing.\n */\nexport function sessionId(now = Date.now()): string | undefined {\n const s = ls()\n if (!s) return undefined\n let state: SessionState | null = null\n try {\n state = JSON.parse(s.getItem(KEY.session) || 'null')\n } catch {\n state = null\n }\n if (!state || now - state.last > SESSION_TTL_MS) {\n state = { id: uuidv7(now), last: now }\n } else {\n state.last = now\n }\n s.setItem(KEY.session, JSON.stringify(state))\n return state.id\n}\n\n/** Read the persisted first-touch attribution. */\nexport function getFirstTouch(): Attribution | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.firstTouch)\n return v ? (JSON.parse(v) as Attribution) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Persist first-touch attribution ONCE — never overwrite an existing record. */\nexport function setFirstTouchOnce(a: Attribution): Attribution {\n const s = ls()\n const existing = getFirstTouch()\n if (existing) return existing\n if (s) s.setItem(KEY.firstTouch, JSON.stringify(a))\n return a\n}\n\n/** Read persisted cohort dimensions. */\nexport function getCohort(): Cohort | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.cohort)\n return v ? (JSON.parse(v) as Cohort) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Merge + persist cohort dimensions (signupWeek set once). */\nexport function mergeCohort(patch: Cohort): Cohort {\n const s = ls()\n const cur = getCohort() || {}\n const next: Cohort = {\n signupWeek: cur.signupWeek || patch.signupWeek,\n channel: patch.channel || cur.channel,\n refCode: cur.refCode || patch.refCode,\n }\n if (s) s.setItem(KEY.cohort, JSON.stringify(next))\n return next\n}\n","// The framework-agnostic event client. ONE API surface over TWO orthogonal\n// planes, sharing one session and one identity:\n//\n// 1. EVENT STREAM — buffered pageview/event/identify/group, flushed as ONE\n// batch to the Hanzo Cloud front door:\n// POST {host}/v1/event body: { batch: [Event, …] } -> { accepted, dropped }\n// Cloud resolves the tenant server-side (validated session, or the signed\n// publishable key) and stamps it; the client NEVER sends the org.\n//\n// 2. ERROR PLANE — every captured exception is ALSO framed as a real Sentry\n// envelope and POSTed to the error host named by the DSN:\n// POST {dsn.origin}/v1/sentry/{projectId}/envelope/?sentry_key=…\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_…') — Authorization: Bearer pk_… on\n// fetch, ?ingest_key=pk_… on a headerless page-unload beacon. Write-only and\n// safe to ship in a bundle; the door HMAC-verifies it to an org server-side.\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 { PAGEVIEW } from './events'\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\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 a headerless sendBeacon (?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 headerless page-unload beacons. A bearer (a JWT or a\n * publishable pk_ key) rides Authorization on fetch; on a beacon — which cannot\n * set headers — a publishable key rides the ?ingest_key query instead. */\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 const contentType = opts.contentType ?? 'application/json'\n if (opts.beacon && isBrowser() && typeof navigator.sendBeacon === 'function') {\n const beaconUrl = opts.ingestKey ? appendQuery(url, 'ingest_key', opts.ingestKey) : url\n try {\n navigator.sendBeacon(beaconUrl, new Blob([body], { type: contentType }))\n return\n } catch {\n /* fall through to fetch */\n }\n }\n if (typeof fetch !== 'function') return\n const headers: Record<string, string> = { 'Content-Type': contentType }\n const bearer = opts.ingestKey ?? opts.token\n if (bearer) headers.Authorization = `Bearer ${bearer}`\n void fetch(url, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n credentials: '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 /** 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 the SAME way the DSN below does: an explicit\n // config wins, else the inlined build-time env.\n //\n // NEXT_PUBLIC_EVENT_INGEST_KEY is that env, and it is the name the fleet\n // ALREADY carries end to end — KMS holds deploy/EVENT_INGEST_KEY, each\n // Dockerfile takes it as the EVENT_INGEST_KEY build-arg and re-exports it\n // with the NEXT_PUBLIC_ prefix Next needs to inline it. Reading anything\n // else here would add a fourth spelling of one value.\n //\n // Without this the key was the one piece of wiring a surface could not\n // declare the way it declares every other piece, so a surface that shipped\n // without passing it in code sent its beacons unattributed — and an\n // unattributed write is refused (401 ingest_key_required), which is silent\n // in the page and invisible until you read the warehouse and find the host\n // missing entirely.\n ingestKey: config.ingestKey ?? readEnv('NEXT_PUBLIC_EVENT_INGEST_KEY'),\n }\n this.transport = config.transport ?? new DefaultTransport()\n // Error plane, most specific source first: an explicit DSN wins, then the\n // inlined build-time env (a per-deploy override), then the product registry\n // — so declaring `product` is enough to report errors and no surface needs\n // build-argument plumbing. Malformed or absent => null => inert, never\n // throwing into the host app.\n this.dsn = parseDsn(config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product))\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. */\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 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 /** track is an alias of capture (Segment familiarity). */\n track = this.capture.bind(this)\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 ex = normalizeError(err)\n ex.handled = context?.handled ?? true\n this.enqueue('error', ex.message, { error: ex, properties: context?.properties })\n this.flush()\n } catch {\n /* nor the reverse */\n }\n } finally {\n this.reentrant = false\n }\n }\n\n /** captureException — @sentry-familiar alias of captureError. */\n captureException = this.captureError.bind(this)\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 Authorization: Bearer pk_… (fetch) or\n * ?ingest_key=pk_… (beacon), so unload beacons work anonymously.\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 headerful bearer JWT blocks the beacon: sendBeacon cannot set an\n // Authorization 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/** createAnalytics builds a client instance. Most apps use one shared instance. */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n return new Analytics(config)\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 useMemo,\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 const instance = useMemo<Analytics>(() => {\n if (client) return client\n if (config) return createAnalytics(config)\n throw new Error('AnalyticsProvider requires `client` or `config`')\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client])\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/events.ts","../src/scrub.ts","../src/anon.js","../src/version.ts","../src/sentry.ts","../src/storage.ts","../src/core.ts","../src/react.tsx"],"names":["normalizeError"],"mappings":"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","file":"react.mjs","sourcesContent":["// Pure attribution helpers: parse first-touch UTM/referrer/refCode from a URL,\n// derive the acquisition channel, and compute the ISO week for the signup cohort.\n// No I/O, no globals — trivially testable.\n\nimport type { Attribution } from './types'\n\nconst SOCIAL_HOSTS = [\n 'facebook.', 'instagram.', 'twitter.', 'x.com', 't.co', 'linkedin.',\n 'reddit.', 'youtube.', 'tiktok.', 'pinterest.', 'news.ycombinator.com',\n]\nconst SEARCH_HOSTS = ['google.', 'bing.', 'duckduckgo.', 'yahoo.', 'baidu.', 'ecosia.']\n\n/** parseAttribution reads UTM params + ref/refCode from a query string and pairs\n * them with the referrer. `search` is a location.search value (\"?utm_source=…\"). */\nexport function parseAttribution(search: string, referrer: string): Attribution {\n const q = new URLSearchParams(search || '')\n const get = (k: string) => {\n const v = q.get(k)\n return v ? v.trim() : undefined\n }\n const a: Attribution = {\n utm: {\n source: get('utm_source'),\n medium: get('utm_medium'),\n campaign: get('utm_campaign'),\n term: get('utm_term'),\n content: get('utm_content'),\n },\n referrer: referrer ? referrer.trim() : undefined,\n refCode: get('ref') || get('refCode') || get('ref_code') || undefined,\n }\n a.channel = deriveChannel(a)\n return a\n}\n\n/** deriveChannel classifies the visit: paid | referral | social | organic | direct. */\nexport function deriveChannel(a: Attribution): string {\n const medium = (a.utm.medium || '').toLowerCase()\n if (/(cpc|ppc|paid|paidsearch|display|cpm)/.test(medium)) return 'paid'\n if (a.utm.source || a.utm.campaign) return 'campaign'\n if (a.refCode) return 'referral'\n const host = hostOf(a.referrer)\n if (!host) return 'direct'\n if (SOCIAL_HOSTS.some((h) => host.includes(h))) return 'social'\n if (SEARCH_HOSTS.some((h) => host.includes(h))) return 'organic'\n return 'referral'\n}\n\n/** hostOf extracts a bare lowercase host from a URL; \"\" when unparseable. */\nexport function hostOf(raw?: string): string {\n if (!raw) return ''\n let s = raw.trim()\n const scheme = s.indexOf('://')\n if (scheme >= 0) s = s.slice(scheme + 3)\n const cut = s.search(/[/?#]/)\n if (cut >= 0) s = s.slice(0, cut)\n const at = s.indexOf('@')\n if (at >= 0) s = s.slice(at + 1)\n const colon = s.indexOf(':')\n if (colon >= 0) s = s.slice(0, colon)\n return s.toLowerCase().trim()\n}\n\n/** hasAttribution reports whether anything was captured (so we don't persist an\n * empty first-touch that would shadow a later real one). */\nexport function hasAttribution(a: Attribution): boolean {\n return Boolean(\n a.utm.source || a.utm.medium || a.utm.campaign || a.utm.term ||\n a.utm.content || a.refCode || (a.referrer && hostOf(a.referrer)),\n )\n}\n\n/** isoWeek returns the ISO-8601 week label, e.g. \"2026-W28\". */\nexport function isoWeek(d: Date): string {\n // Copy to UTC midnight; ISO week: Thursday-anchored.\n const date = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()))\n const day = date.getUTCDay() || 7\n date.setUTCDate(date.getUTCDate() + 4 - day)\n const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1))\n const week = Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7)\n return `${date.getUTCFullYear()}-W${String(week).padStart(2, '0')}`\n}\n","/**\n * The product → Sentry 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 Sentry 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/sentry/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_DSN maps a `product` to the DSN its errors are submitted to. */\nexport const PRODUCT_DSN: Readonly<Record<string, string>> = Object.freeze({\n // hanzo-console — console.hanzo.ai (also served embedded by the cloud binary)\n console:\n 'https://1:0c8054dbde157f4f420c56b58660052b2ad782293c4de1d606ef8fbc46a0bf34@api.hanzo.ai/v1/sentry/019fa40b-94ae-7f1d-8f7b-e92f123fad42',\n // hanzo-app — hanzo.app\n app: 'https://1:b3e1173125568c80f91ef4b1fabbbd2d7e22341de02b33ce7e22ef4fc16a196e@api.hanzo.ai/v1/sentry/019f9b1e-57eb-7171-9d92-72c0b85e4b4b',\n // hanzo-ai — hanzo.ai (the marketing site; `site` is the product name it declares)\n site: 'https://1:d9cbfb844958bd7ef2a455600f00fbf237fbd71b75c1504f137773096d6aa53f@api.hanzo.ai/v1/sentry/019f9b1e-5785-7359-ad0b-f75db8e58c99',\n})\n\n/** dsnForProduct resolves the registered DSN for a product, or undefined when the\n * product has no project yet — which leaves the error plane inert rather than\n * guessing a destination and silently posting a surface's errors into the wrong\n * project. */\nexport function dsnForProduct(product: string | undefined): string | undefined {\n if (!product) return undefined\n return PRODUCT_DSN[product]\n}\n","// The ONE product-analytics vocabulary. Every Hanzo surface emits these exact\n// names so funnels, goals, and cohorts line up across console/chat/app/site/admin.\n// Pageviews use the reserved \"$pageview\" name (emitted by analytics.pageview()),\n// matching the server read lens.\n//\n// Naming is a closed convention, not a style preference (see TAXONOMY.md):\n// • snake_case, `<object>_<verb-in-past-tense>` — signup_completed, plan_clicked.\n// • Names are CONSTANTS, never interpolated. A dimension (framework, model,\n// plan, source) is a PROPERTY, never part of the name. `deploy_succeeded`\n// with {framework:'static'} — never `deploy_static_succeeded`.\n// • One name per user-visible moment, shared by every surface. The surface is\n// already on the wire as `product`, so a name is never product-prefixed.\n\nexport const EVENTS = {\n // Signup funnel: view -> submit -> verify -> completed -> first action.\n SIGNUP_VIEWED: 'signup_viewed',\n SIGNUP_SUBMITTED: 'signup_submitted',\n SIGNUP_VERIFIED: 'signup_verified',\n SIGNUP_COMPLETED: 'signup_completed',\n /** A RETURNING user authenticated — the non-signup half of the IAM callback.\n * Keeping it distinct is what stops returning logins from inflating signups. */\n LOGIN_COMPLETED: 'login_completed',\n /** Activation: the first moment of real value. ONE event for every product —\n * the product-specific moment is the `action` property (api_call, app_live,\n * chat_reply), never a new event name. */\n FIRST_ACTION: 'first_action',\n\n // Waitlist + referral.\n WAITLIST_JOINED: 'waitlist_joined',\n WAITLIST_SHARED: 'waitlist_shared',\n REFERRAL_USED: 'referral_used',\n REFERRAL_CLAIMED: 'referral_claimed',\n\n // Upgrade-intent + purchase.\n PRICING_VIEWED: 'pricing_viewed',\n PLAN_CLICKED: 'plan_clicked',\n CHECKOUT_STARTED: 'checkout_started',\n ORDER_COMPLETED: 'order_completed',\n\n // Feature usage — generic + the common key surfaces across products.\n FEATURE_USED: 'feature_used',\n API_KEY_CREATED: 'api_key_created',\n APP_CREATED: 'app_created',\n PROJECT_CREATED: 'project_created',\n AGENT_CREATED: 'agent_created',\n CHAT_STARTED: 'chat_started',\n CHAT_MESSAGE_SENT: 'chat_message_sent',\n /** The user switched model/endpoint — the single strongest quality signal a\n * chat surface emits (a switch usually follows a bad answer). */\n MODEL_SWITCHED: 'model_switched',\n TASK_STARTED: 'task_started',\n TASK_COMPLETED: 'task_completed',\n\n // Build → ship. `build_*` is a MODEL producing an artifact; `deploy_*` is that\n // artifact going live. Intent (build_started) is never the same event as the\n // artifact existing (app_created) — conflating them makes the funnel lie.\n BUILD_STARTED: 'build_started',\n /** A model finished producing an artifact (an app build, a chat reply, an agent\n * run). Carries `durationMs` — the outcome event owns its own duration, so no\n * paired start event is needed. */\n GENERATION_COMPLETED: 'generation_completed',\n GENERATION_FAILED: 'generation_failed',\n DEPLOY_STARTED: 'deploy_started',\n DEPLOY_SUCCEEDED: 'deploy_succeeded',\n DEPLOY_FAILED: 'deploy_failed',\n} as const\n\nexport type EventName = (typeof EVENTS)[keyof typeof EVENTS]\n\n/** The reserved event name a pageview is stored under (server + read lens). */\nexport const PAGEVIEW = '$pageview'\n","// Client-side redaction for error text — a faithful port of the server's\n// errortracking scrub (o11y pkg/modules/errortracking/implerrortracking/scrub.go),\n// applied BEFORE anything leaves the browser. Two layers, default-secure:\n//\n// - Secret shapes are ALWAYS redacted (sk-… keys, bearer/JWT tokens, DB DSNs,\n// PANs, cloud keys). There is no mode that ships a secret off-device.\n// - PII (email/IP) is scrubbed UNLESS capturePII is explicitly enabled.\n//\n// The server scrubs again — this is defense in depth, not a substitute — but the\n// point is that a Hanzo browser never emits a raw secret/email/IP in the first\n// place. Pure, no I/O.\n\nconst REDACTED = '[redacted]'\nconst EMAIL_MARK = '[email]'\nconst IP_MARK = '[ip]'\n\n// Secret patterns mirror scrub.go's secretPatterns. Order matters (broad DSN/PAN\n// rules run last). All are applied unconditionally.\nconst SECRET_PATTERNS: RegExp[] = [\n /-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,\n /eyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{6,}/g, // JWT\n /\\bbearer\\s+[A-Za-z0-9._~+/-]{12,}=*/gi, // bearer token\n /\\b(?:sk|pk|rk)-[A-Za-z0-9]{2,}-?[A-Za-z0-9]{12,}/g, // openai-style\n /\\b(?:sk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g, // stripe\n /\\bhk-[A-Za-z0-9]{16,}/g, // hanzo key\n /\\bAKIA[0-9A-Z]{16}\\b/g, // aws access key id\n /\\bASIA[0-9A-Z]{16}\\b/g, // aws sts key id\n /\\bAIza[0-9A-Za-z_-]{20,}/g, // google api key\n /\\bgh[posru]_[A-Za-z0-9]{20,}/g, // github token\n /\\bxox[baprs]-[A-Za-z0-9-]{10,}/g, // slack token\n // Creds in a URL/DSN. The repetition is BOUNDED on purpose: the unbounded form\n // ([^\\s:@/]+:[^\\s@/]+@) backtracks quadratically on colon-rich text with no\n // terminating '@' — an HTML error page pasted into an error message took 4.9s\n // at 32KB and >60s at 128KB, freezing the main thread from inside captureError.\n // Real userinfo is far below these caps, so bounding costs nothing.\n /[a-zA-Z][a-zA-Z0-9+.-]{0,32}:\\/\\/[^\\s:@/]{1,256}:[^\\s@/]{1,256}@/g,\n]\n\n/** Candidate card numbers. Gated by Luhn below — the bare digit-run pattern is a\n * false-positive cannon that redacts every millisecond epoch, order id and\n * phone number it sees (\"request 1753468800000 timed out\" became\n * \"request [redacted]timed out\"), which destroys the readability of the very\n * error messages this client exists to deliver. */\nconst RE_PAN = /\\b(?:\\d[ -]?){13,19}\\b/g\n\n/** luhn reports whether a digit string satisfies the Luhn checksum. Every real\n * card number does, so gating redaction on it removes the false positives\n * WITHOUT introducing a false negative — the safe direction for a redactor. */\nfunction luhn(digits: string): boolean {\n let sum = 0\n let alt = false\n for (let i = digits.length - 1; i >= 0; i--) {\n let d = digits.charCodeAt(i) - 48\n if (alt) {\n d *= 2\n if (d > 9) d -= 9\n }\n sum += d\n alt = !alt\n }\n return sum % 10 === 0\n}\n\n/** redactPAN removes digit runs that actually check out as card numbers. */\nfunction redactPAN(s: string): string {\n return s.replace(RE_PAN, (m) => {\n const digits = m.replace(/[ -]/g, '')\n if (digits.length < 13 || digits.length > 19) return m\n return luhn(digits) ? REDACTED : m\n })\n}\n\n// Bounded to the RFC 5321 maxima (local-part 64, domain 255) for the same reason\n// as the creds-in-URL rule: the unbounded form backtracks quadratically across a\n// long run of local-part-legal characters that never reaches an '@' — measured at\n// 20ms on an 8KB worst case, on the main thread, per captured error. No real\n// address is excluded by these caps.\nconst RE_EMAIL = /[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{1,255}\\.[A-Za-z]{2,24}/g\nconst RE_IPV4 = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g\nconst RE_IPV6 = /\\b(?:[0-9A-Fa-f]{1,4}:){2,7}[0-9A-Fa-f]{1,4}\\b/g\n\n// A CREDENTIAL IN A QUERY PARAM HAS NO SHAPE TO MATCH.\n//\n// Every pattern above recognises a secret by what it LOOKS like — a JWT's three\n// dots, `sk-`, `AKIA`, `ghp_`. An OAuth `code`, a `state`, a password-reset\n// nonce and an invite token are opaque random strings, indistinguishable from a\n// page id, so none of them match and all of them survive.\n//\n// That matters because the client stamps `url: window.location.href` on EVERY\n// event, not just pageviews. So one visit to `/callback?code=…&state=…` puts a\n// live authorization code on the wire, once per event, in cleartext — and the\n// code is exchangeable until it is redeemed.\n//\n// The fix is to redact by the NAME the value is filed under rather than by the\n// value's shape, which is the only signal available for an opaque token. The\n// name half is bounded (`{1,32}`) and the value half stops at the first\n// separator, so neither half can backtrack across a long string — the same\n// discipline the creds-in-URL pattern above documents.\nconst CREDENTIAL_PARAMS = [\n 'code', 'state', 'token', 'access_token', 'id_token', 'refresh_token',\n 'auth', 'authorization', 'secret', 'client_secret', 'password', 'passwd', 'pwd',\n 'api_key', 'apikey', 'key', 'session', 'session_id', 'sid',\n 'sig', 'signature', 'nonce', 'otp', 'invite', 'invitation',\n 'reset_token', 'confirmation_token', 'magic', 'ticket', 'assertion',\n]\nconst RE_CREDENTIAL_PARAM = new RegExp(\n '([?&#;](?:' + CREDENTIAL_PARAMS.join('|') + ')=)[^&#;\\\\s]{1,4096}',\n 'gi',\n)\n\n/** redactCredentialParams removes the VALUE of any query parameter whose NAME\n * says it carries a credential, leaving the name so the URL still reads. */\nexport function redactCredentialParams(s: string): string {\n return s.replace(RE_CREDENTIAL_PARAM, (_m, prefix: string) => prefix + REDACTED)\n}\n\n/** redactSecrets removes known secret shapes. Always applied. */\nexport function redactSecrets(s: string): string {\n s = redactCredentialParams(s)\n for (const re of SECRET_PATTERNS) s = s.replace(re, REDACTED)\n return redactPAN(s)\n}\n\n/** scrubPII masks emails and IPs. Applied unless PII capture is enabled. */\nexport function scrubPII(s: string): string {\n s = s.replace(RE_EMAIL, EMAIL_MARK)\n s = s.replace(RE_IPV6, IP_MARK)\n s = s.replace(RE_IPV4, IP_MARK)\n return s\n}\n\n/** Longest free-text field this module will scrub. Every pattern here is a regex\n * run synchronously on the main thread, and the input is attacker-influenced —\n * `throw new Error(await res.text())` against an HTML error page is a one-line\n * way to hand us 128KB. Bounding the INPUT bounds the work regardless of which\n * pattern is pathological. 8KB is far beyond any real error message. */\nexport const MAX_SCRUB_LEN = 8192\n\n/** truncate caps a string at MAX_SCRUB_LEN, marking that it was cut so a reader\n * never mistakes a truncated message for the whole one. */\nexport function truncate(s: string, max = MAX_SCRUB_LEN): string {\n return s.length > max ? s.slice(0, max) + '… [truncated]' : s\n}\n\n/** scrubText applies the redaction policy to a free-text field. Input is capped\n * first: unbounded text is a denial-of-service surface, not just a size problem. */\nexport function scrubText(s: string | undefined, capturePII = false): string {\n if (!s) return s ?? ''\n s = truncate(s)\n s = redactSecrets(s)\n if (!capturePII) s = scrubPII(s)\n return s\n}\n","/*! anon.js — THE anonymous-identity chain. ONE implementation, three distributions.\n *\n * One browser is ONE person on every Hanzo surface, whichever client a page\n * happens to have loaded. There were three implementations writing TWO keys —\n * `hz_anon_id` (the npm client, the hosted tag) and `hz_id` (hz.js) — so the same\n * visitor was several people depending on which snippet the surface shipped.\n *\n * The three call sites:\n * 1. src/storage.ts — the bundled npm client; IMPORTS this file.\n * 2. hz.js — the no-build script tag; INLINES the marked region.\n * 3. hanzoai/cloud apps/analytics/tag.js — the tag the door hosts at\n * /v1/event.js; vendors this file and its tag.go serves the marked region\n * with the tag as one asset, so the door holds no second copy either.\n *\n * (2) and (3) have no bundler and cannot import anything, which is why the chain\n * lives in a file that is plain ES5 rather than in a .ts: the region between the\n * BEGIN and END markers is COPIED VERBATIM, and src/anon.test.ts fails if hz.js's\n * copy is so much as a byte different. Keep the region ES5, dependency-free,\n * `hz`-prefixed (it is spliced into other people's scopes) and unformatted — a\n * reformat of one copy is a diff against the other.\n */\n\n/* ── BEGIN hz anon chain — copied VERBATIM into hz.js and hanzoai/cloud ────── */\n\n/** The ONE anonymous-id key, on every surface and in every distribution. */\nvar HZ_ANON_KEY = 'hz_anon_id'\n\n/** hz.js used to write `hz_id` — a SECOND identity space, so the one-paste tag\n * and the npm client were two different people on one page. It is READ and never\n * written: an id already in the wild is ADOPTED into the shared identity, because\n * minting over one detaches a returning visitor from their own history. */\nvar HZ_ANON_LEGACY_KEY = 'hz_id'\n\n/** The registrable domain the cookie is scoped to, so docs, cloud, console,\n * studio, pay, id and www all read the ONE id. localStorage cannot do this: it is\n * ORIGIN-scoped, which is what made one journey arrive as several strangers. */\nvar HZ_ANON_DOMAIN = 'hanzo.ai'\n\n/** Two years, rewritten on every read, so the cookie rolls forward with the\n * visitor instead of expiring two years after first touch. Safari caps a\n * SCRIPT-written cookie at 7 days no matter what this says, so the rewrite is\n * what keeps a returning Safari visitor: each read re-arms the 7-day window. */\nvar HZ_ANON_MAX_AGE = 2 * 365 * 24 * 60 * 60\n\n/** Last resort for a browser that refuses cookies AND localStorage: without it\n * every event in a page load would mint an id of its own. */\nvar hzAnonMemo\n\n/**\n * hzUuidv7 mints a time-ordered UUIDv7 (RFC 9562 §5.7) for `now` in epoch ms.\n *\n * It has to be v7, and this is the only minter any distribution may use. The\n * session rollups on the event plane derive a session's start instant FROM THE ID\n * and admit only ids whose version nibble is 7, so a crypto.randomUUID() (v4) id\n * is not merely unordered there — it is DISCARDED, silently, and the rollup stays\n * empty. Without crypto only the ENTROPY degrades; the shape is always a valid v7.\n */\nfunction hzUuidv7(now) {\n var b = new Uint8Array(16)\n var i\n var c = typeof crypto !== 'undefined' ? crypto : undefined\n if (c && typeof c.getRandomValues === 'function') c.getRandomValues(b)\n else for (i = 0; i < 16; i++) b[i] = (Math.random() * 256) | 0\n var t = Math.floor(now === undefined ? Date.now() : now)\n for (i = 5; i >= 0; i--) {\n b[i] = t % 256\n t = Math.floor(t / 256)\n }\n b[6] = 0x70 | (b[6] & 0x0f) // version 7\n b[8] = 0x80 | (b[8] & 0x3f) // variant 0b10\n var h = ''\n for (i = 0; i < 16; i++) {\n h += (b[i] + 0x100).toString(16).slice(1)\n if (i === 3 || i === 5 || i === 7 || i === 9) h += '-'\n }\n return h\n}\n\n/** The cookie jar, or null wherever there is no document to read one from. */\nfunction hzAnonJar() {\n try {\n if (typeof document === 'undefined' || typeof document.cookie !== 'string') return null\n return document\n } catch (e) {\n return null // sandboxed frame with an opaque origin\n }\n}\n\n/** localStorage, or null when the browser refuses it (Safari private mode). */\nfunction hzAnonStore() {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return null\n return window.localStorage\n } catch (e) {\n return null\n }\n}\n\n/** One stored value, or '' — a jar can read as well as refuse to. */\nfunction hzAnonItem(store, name) {\n try {\n return (store && store.getItem(name)) || ''\n } catch (e) {\n return ''\n }\n}\n\n/** The value of cookie `name`, or ''. */\nfunction hzAnonCookie(name) {\n var d = hzAnonJar()\n if (!d) return ''\n var parts = d.cookie.split(';')\n for (var i = 0; i < parts.length; i++) {\n var eq = parts[i].indexOf('=')\n if (eq < 0 || parts[i].slice(0, eq).trim() !== name) continue\n var v = parts[i].slice(eq + 1).trim()\n if (!v) continue\n try {\n return decodeURIComponent(v)\n } catch (e) {\n return v // not percent-encoded — take it as written\n }\n }\n return ''\n}\n\n/** Writes `name` on the registrable domain, for as long as the browser allows. */\nfunction hzAnonWrite(name, value) {\n var d = hzAnonJar()\n if (!d) return\n var host = ''\n var secure = false\n try {\n if (typeof window !== 'undefined' && window.location) {\n host = window.location.hostname || ''\n // A Secure cookie is refused outright by a non-secure origin, which would\n // strand http://localhost dev on the localStorage path.\n secure = window.location.protocol === 'https:'\n }\n } catch (e) {\n /* location unreachable — write a host-only, non-secure cookie */\n }\n // encodeURIComponent leaves a UUID byte-identical while making any value that is\n // not one unable to forge a `;` and inject an attribute.\n var c = name + '=' + encodeURIComponent(value)\n c += '; Path=/; Max-Age=' + HZ_ANON_MAX_AGE + '; SameSite=Lax'\n // Off hanzo.ai (localhost, previews, other registrable domains) the attribute\n // would be rejected and the whole cookie dropped, so it stays host-only there.\n // Prefixing both sides with '.' matches the domain itself and its subdomains\n // while refusing a suffix that merely ends in the same letters (evilhanzo.ai).\n if (('.' + host).slice(-(HZ_ANON_DOMAIN.length + 1)) === '.' + HZ_ANON_DOMAIN) {\n c += '; Domain=' + HZ_ANON_DOMAIN\n }\n if (secure) c += '; Secure'\n try {\n d.cookie = c\n } catch (e) {\n /* cookies refused — localStorage still carries the id */\n }\n}\n\n/**\n * hzAnonId returns the stable anonymous id for this browser, '' during SSR.\n *\n * Resolution is strictly ADDITIVE — every id that already exists is ADOPTED, and\n * only a browser holding none of them is given a new one:\n *\n * cookie · localStorage hz_anon_id · localStorage hz_id · in-memory · mint\n *\n * Minting over an id resets a returning visitor and detaches them from their own\n * history, so the order is the migration: the cookie is the shared home, the two\n * localStorage keys are what the three implementations wrote before it existed,\n * and each is read until nothing is left to adopt.\n *\n * localStorage keeps being written, so a rollback finds everyone where it left\n * them, and a browser that refuses cookies still holds one id per origin.\n */\nfunction hzAnonId() {\n if (typeof window === 'undefined') return '' // SSR / prerender: no browser to identify\n var s = hzAnonStore()\n var id =\n hzAnonCookie(HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_KEY) ||\n hzAnonItem(s, HZ_ANON_LEGACY_KEY) ||\n hzAnonMemo ||\n hzUuidv7()\n hzAnonMemo = id\n hzAnonWrite(HZ_ANON_KEY, id)\n try {\n if (s && s.getItem(HZ_ANON_KEY) !== id) s.setItem(HZ_ANON_KEY, id)\n } catch (e) {\n /* quota exhausted, or a private-mode jar that reads but refuses writes */\n }\n return id\n}\n\n/* ── END hz anon chain ─────────────────────────────────────────────────────── */\n\nexport { hzAnonId, hzUuidv7 }\n","// The 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.17'\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/sentry 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/sentry/<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 const ingestUrl =\n `${origin}/v1/sentry/${encodeURIComponent(projectId)}/envelope/` +\n `?sentry_key=${encodeURIComponent(publicKey)}`\n return { publicKey, origin, projectId, 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.origin}/v1/sentry/${dsn.projectId}`,\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","// SSR-safe browser storage for stable identifiers and first-touch state. Every\n// accessor no-ops (returns undefined) when there is no window/localStorage, so the\n// client imports cleanly in a Next.js server component.\n//\n// The anonymous id is the one value that must outlive an ORIGIN, and it is also\n// the one value the OTHER two distributions must agree with, so its chain lives in\n// ./anon.js and this file only calls it. Everything else here stays origin-local.\n\nimport { hzAnonId } from './anon.js'\nimport type { Attribution, Cohort } from './types'\nimport { uuidv7 } from './uid'\n\nconst KEY = {\n session: 'hz_session',\n firstTouch: 'hz_first_touch',\n cohort: 'hz_cohort',\n} as const\n\n/** 30-minute inactivity window defines a session (PostHog/GA convention). */\nconst SESSION_TTL_MS = 30 * 60 * 1000\n\nfunction ls(): Storage | undefined {\n try {\n if (typeof window === 'undefined' || !window.localStorage) return undefined\n return window.localStorage\n } catch {\n return undefined // Safari private mode / blocked storage\n }\n}\n\n/**\n * Stable anonymous id, shared by every *.hanzo.ai surface AND by every Hanzo\n * client on the page — the npm client, hz.js and the hosted tag all run the one\n * chain in ./anon.js, so which snippet a surface loaded no longer decides who the\n * visitor is.\n *\n * It lives in a first-party cookie on the registrable domain because localStorage\n * is ORIGIN-scoped: docs, cloud and console each minted their own id for the same\n * person, so one marketing → docs → signup → checkout journey arrived as several\n * strangers — 463 anonymous identities carried 545 events in a week, about 1.2\n * events each.\n */\nexport function anonId(): string | undefined {\n return hzAnonId() || undefined // '' during SSR / prerender\n}\n\ninterface SessionState {\n id: string\n last: number\n}\n\n/**\n * Current session id, rotated after SESSION_TTL_MS of inactivity.\n *\n * Minted at `now`, so the v7 timestamp the id carries IS the session's start\n * instant — which is what the session rollups partition and order on. Passing the\n * caller's clock rather than reading Date.now() again keeps the id's embedded time\n * and the recorded `last` from disagreeing.\n */\nexport function sessionId(now = Date.now()): string | undefined {\n const s = ls()\n if (!s) return undefined\n let state: SessionState | null = null\n try {\n state = JSON.parse(s.getItem(KEY.session) || 'null')\n } catch {\n state = null\n }\n if (!state || now - state.last > SESSION_TTL_MS) {\n state = { id: uuidv7(now), last: now }\n } else {\n state.last = now\n }\n s.setItem(KEY.session, JSON.stringify(state))\n return state.id\n}\n\n/** Read the persisted first-touch attribution. */\nexport function getFirstTouch(): Attribution | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.firstTouch)\n return v ? (JSON.parse(v) as Attribution) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Persist first-touch attribution ONCE — never overwrite an existing record. */\nexport function setFirstTouchOnce(a: Attribution): Attribution {\n const s = ls()\n const existing = getFirstTouch()\n if (existing) return existing\n if (s) s.setItem(KEY.firstTouch, JSON.stringify(a))\n return a\n}\n\n/** Read persisted cohort dimensions. */\nexport function getCohort(): Cohort | undefined {\n const s = ls()\n if (!s) return undefined\n try {\n const v = s.getItem(KEY.cohort)\n return v ? (JSON.parse(v) as Cohort) : undefined\n } catch {\n return undefined\n }\n}\n\n/** Merge + persist cohort dimensions (signupWeek set once). */\nexport function mergeCohort(patch: Cohort): Cohort {\n const s = ls()\n const cur = getCohort() || {}\n const next: Cohort = {\n signupWeek: cur.signupWeek || patch.signupWeek,\n channel: patch.channel || cur.channel,\n refCode: cur.refCode || patch.refCode,\n }\n if (s) s.setItem(KEY.cohort, JSON.stringify(next))\n return next\n}\n","// The framework-agnostic event client. ONE API surface over TWO orthogonal\n// planes, sharing one session and one identity:\n//\n// 1. EVENT STREAM — buffered pageview/event/identify/group, flushed as ONE\n// batch to the Hanzo Cloud front door:\n// POST {host}/v1/event body: { batch: [Event, …] } -> { accepted, dropped }\n// Cloud resolves the tenant server-side (validated session, or the signed\n// publishable key) and stamps it; the client NEVER sends the org.\n//\n// 2. ERROR PLANE — every captured exception is ALSO framed as a real Sentry\n// envelope and POSTed to the error host named by the DSN:\n// POST {dsn.origin}/v1/sentry/{projectId}/envelope/?sentry_key=…\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_…') — Authorization: Bearer pk_… on\n// fetch, ?ingest_key=pk_… on a headerless page-unload beacon. Write-only and\n// safe to ship in a bundle; the door HMAC-verifies it to an org server-side.\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 { PAGEVIEW } from './events'\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\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 a headerless sendBeacon (?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 headerless page-unload beacons. A bearer (a JWT or a\n * publishable pk_ key) rides Authorization on fetch; on a beacon — which cannot\n * set headers — a publishable key rides the ?ingest_key query instead. */\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 const contentType = opts.contentType ?? 'application/json'\n if (opts.beacon && isBrowser() && typeof navigator.sendBeacon === 'function') {\n const beaconUrl = opts.ingestKey ? appendQuery(url, 'ingest_key', opts.ingestKey) : url\n try {\n navigator.sendBeacon(beaconUrl, new Blob([body], { type: contentType }))\n return\n } catch {\n /* fall through to fetch */\n }\n }\n if (typeof fetch !== 'function') return\n const headers: Record<string, string> = { 'Content-Type': contentType }\n const bearer = opts.ingestKey ?? opts.token\n if (bearer) headers.Authorization = `Bearer ${bearer}`\n void fetch(url, {\n method: 'POST',\n headers,\n body,\n keepalive: true,\n credentials: '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 /** 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 the SAME way the DSN below does: an explicit\n // config wins, else the inlined build-time env.\n //\n // NEXT_PUBLIC_PUBLISHABLE_KEY is that env, and it is the name the fleet\n // ALREADY carries end to end — KMS holds deploy/PUBLISHABLE_KEY, each\n // Dockerfile takes it as the PUBLISHABLE_KEY build-arg and re-exports it\n // with the NEXT_PUBLIC_ prefix Next needs to inline it. Reading anything\n // else here would add a fourth spelling of one value.\n //\n // Without this the key was the one piece of wiring a surface could not\n // declare the way it declares every other piece, so a surface that shipped\n // without passing it in code sent its beacons unattributed — and an\n // unattributed write is refused (401 ingest_key_required), which is silent\n // in the page and invisible until you read the warehouse and find the host\n // missing entirely.\n ingestKey: config.ingestKey ?? readEnv('NEXT_PUBLIC_PUBLISHABLE_KEY'),\n }\n this.transport = config.transport ?? new DefaultTransport()\n // Error plane, most specific source first: an explicit DSN wins, then the\n // inlined build-time env (a per-deploy override), then the product registry\n // — so declaring `product` is enough to report errors and no surface needs\n // build-argument plumbing. Malformed or absent => null => inert, never\n // throwing into the host app.\n this.dsn = parseDsn(config.dsn ?? readEnvDsn() ?? dsnForProduct(this.cfg.product))\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. */\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 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 /** track is an alias of capture (Segment familiarity). */\n track = this.capture.bind(this)\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 ex = normalizeError(err)\n ex.handled = context?.handled ?? true\n this.enqueue('error', ex.message, { error: ex, properties: context?.properties })\n this.flush()\n } catch {\n /* nor the reverse */\n }\n } finally {\n this.reentrant = false\n }\n }\n\n /** captureException — @sentry-familiar alias of captureError. */\n captureException = this.captureError.bind(this)\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 Authorization: Bearer pk_… (fetch) or\n * ?ingest_key=pk_… (beacon), so unload beacons work anonymously.\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 headerful bearer JWT blocks the beacon: sendBeacon cannot set an\n // Authorization 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/** createAnalytics builds a client instance. Most apps use one shared instance. */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n return new Analytics(config)\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 useMemo,\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 const instance = useMemo<Analytics>(() => {\n if (client) return client\n if (config) return createAnalytics(config)\n throw new Error('AnalyticsProvider requires `client` or `config`')\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client])\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"]}
|
package/hz.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* <script async src="https://unpkg.com/@hanzo/event/hz.js"
|
|
11
11
|
* data-product="hanzo.ai" // required: which surface this is
|
|
12
|
-
* data-
|
|
12
|
+
* data-publishable-key="pk-…" // required off api.hanzo.ai's own origin
|
|
13
13
|
* data-host="https://api.hanzo.ai" // optional: API host override
|
|
14
14
|
* data-ga="G-XXXX" data-fb="123" // optional: also fan out to GA4 / Meta
|
|
15
15
|
* data-capture="1"></script> // optional: autocapture off with "0"
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
var LIB = 'hz.js'
|
|
58
|
-
var VERSION = '0.3.
|
|
58
|
+
var VERSION = '0.3.17'
|
|
59
59
|
var host = (s.getAttribute('data-host') || 'https://api.hanzo.ai').replace(/\/+$/, '')
|
|
60
60
|
var product = s.getAttribute('data-product') || location.hostname
|
|
61
61
|
var capture = s.getAttribute('data-capture') !== '0'
|
|
@@ -67,7 +67,9 @@
|
|
|
67
67
|
// nothing here reads the response. Through 0.3.11 this file had no way to
|
|
68
68
|
// present a key at all, so every keyed static surface looked wired, measured
|
|
69
69
|
// fine in the browser, and filed nothing.
|
|
70
|
-
|
|
70
|
+
// data-publishable-key is the name; a static tag has no lockstep build to
|
|
71
|
+
// migrate it, so data-ingest-key stays readable as the retiring spelling.
|
|
72
|
+
var key = s.getAttribute('data-publishable-key') || s.getAttribute('data-ingest-key') || ''
|
|
71
73
|
|
|
72
74
|
// ── the shared anonymous-identity chain ───────────────────────────────────
|
|
73
75
|
// COPIED VERBATIM from @hanzo/event's src/anon.js, markers and all, for the same
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/event",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.17",
|
|
4
4
|
"description": "Hanzo Event — the ONE telemetry client. Emits pageview/event/identify/group to the Hanzo Cloud event stream (POST /v1/event), AND reports errors to Sentry as real Sentry envelopes — the error plane needs a DSN, without one nothing reaches Sentry. First-touch attribution, beacon-on-unload, auto error capture, client-side secret/PII scrubbing, a shared event + goal vocabulary. Subsumes @sentry.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|