@aglyn/plugins-marketing 1.0.0-beta.222 → 1.0.0-beta.224

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/package.json +15 -15
  2. package/src/lib/components/campaign-detail-card.js +17 -3
  3. package/src/lib/components/campaign-detail-card.js.map +1 -1
  4. package/src/lib/components/campaign-edit-drawer.d.ts +6 -0
  5. package/src/lib/components/campaign-edit-drawer.js +13 -2
  6. package/src/lib/components/campaign-edit-drawer.js.map +1 -1
  7. package/src/lib/components/campaign-queries.d.ts +5 -0
  8. package/src/lib/components/campaign-queries.js +7 -0
  9. package/src/lib/components/campaign-queries.js.map +1 -1
  10. package/src/lib/components/campaign-reach-sections.d.ts +28 -0
  11. package/src/lib/components/campaign-reach-sections.js +95 -4
  12. package/src/lib/components/campaign-reach-sections.js.map +1 -1
  13. package/src/lib/components/conversion-attribution.component.d.ts +18 -0
  14. package/src/lib/components/conversion-attribution.component.js +177 -39
  15. package/src/lib/components/conversion-attribution.component.js.map +1 -1
  16. package/src/lib/components/record-attribution-widget.d.ts +5 -0
  17. package/src/lib/components/record-attribution-widget.js +6 -3
  18. package/src/lib/components/record-attribution-widget.js.map +1 -1
  19. package/src/lib/components/site-runtime.d.ts +5 -0
  20. package/src/lib/components/site-runtime.js +101 -2
  21. package/src/lib/components/site-runtime.js.map +1 -1
  22. package/src/lib/declarations.server.js +17 -1
  23. package/src/lib/declarations.server.js.map +1 -1
  24. package/src/lib/model/campaign-container.d.ts +28 -0
  25. package/src/lib/model/campaign-container.js +34 -0
  26. package/src/lib/model/campaign-container.js.map +1 -1
  27. package/src/lib/model/campaign-conversions.d.ts +47 -3
  28. package/src/lib/model/campaign-conversions.js +49 -4
  29. package/src/lib/model/campaign-conversions.js.map +1 -1
  30. package/src/lib/model/campaign-visits.d.ts +74 -0
  31. package/src/lib/model/campaign-visits.js +65 -0
  32. package/src/lib/model/campaign-visits.js.map +1 -0
  33. package/src/lib/server/campaign-conversion-attribution.d.ts +34 -3
  34. package/src/lib/server/campaign-conversion-attribution.js +126 -24
  35. package/src/lib/server/campaign-conversion-attribution.js.map +1 -1
  36. package/src/lib/server/campaign-touch-targets.d.ts +61 -0
  37. package/src/lib/server/campaign-touch-targets.js +162 -0
  38. package/src/lib/server/campaign-touch-targets.js.map +1 -0
  39. package/src/lib/server/campaign-visit-beacon.d.ts +44 -0
  40. package/src/lib/server/campaign-visit-beacon.js +125 -0
  41. package/src/lib/server/campaign-visit-beacon.js.map +1 -0
  42. package/src/lib/server/conversion-creditor.js +109 -2
  43. package/src/lib/server/conversion-creditor.js.map +1 -1
  44. package/src/lib/server/email-events.js +24 -25
  45. package/src/lib/server/email-events.js.map +1 -1
  46. package/src/lib/server/site-page-enricher.js +18 -2
  47. package/src/lib/server/site-page-enricher.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/marketing/src/lib/components/site-runtime.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { sendAnalyticsBeacon } from '@aglyn/aglyn/app-utils/analytics-beacon'\nimport {\n trackAuthoredEvent,\n trackEvent,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport { utmTouchField } from '@aglyn/aglyn/app-utils/utm-touch'\nimport { type CSSProperties, useEffect, useRef, useState } from 'react'\nimport type { SiteRuntimeProps } from '@aglyn/aglyn'\nimport * as MarketingModel from '../model'\nimport type {\n AnnouncementBarData,\n ClientAutomation,\n PopupData,\n ScreenExperiment,\n} from '../model/site-contract'\n\n/**\n * Overlay metrics beacon (AGL-200): fire-and-forget, never blocks UX.\n * With an `overlayId` (marketing-hub docs, AGL-271) the collector also\n * increments that overlay's own stats counters.\n */\nfunction sendOverlayBeacon(\n hostId: string | undefined,\n overlay: string,\n overlayId?: string,\n) {\n if (!hostId) return\n // Best-effort, and refused outright from a non-production build or a browser\n // marked ours — the same gate the pageview beacon passes. The GA mirror\n // below is NOT gated here: `trackEvent` carries the taxonomy's own\n // environment check and stamps `traffic_type` rather than dropping the hit.\n sendAnalyticsBeacon({\n hostId,\n overlay,\n ...(overlayId ? { overlayId } : {}),\n })\n // GA mirror (wave v8): sites with Analytics configured see overlay\n // engagement in their own property; no-op without gtag.\n //\n // Through the taxonomy since AGL-1591 rather than raw gtag. `trackEvent`\n // already swallows everything and never throws, so the try/catch this used\n // to need is gone rather than kept as decoration.\n trackEvent('aglyn_overlay', {\n overlay_action: overlay,\n ...(overlayId ? { overlay_id: overlayId } : {}),\n })\n}\n\n/**\n * Site-wide announcement bar (AGL-195). Dismissal is per content-hash in\n * localStorage (no cookies): editing the text re-shows the bar for\n * everyone who hid the old one.\n */\n/**\n * Experiments runner (AGL-253): deterministic per-visitor assignment for\n * the screen's experiments. The first active experiment wins (one per\n * screen); its variant tree — composed server-side per variant version —\n * swaps in via canvas.setNodes on hydration. Exposures beacon on\n * assignment; the conversion listener matches the experiment's goal and\n * beacons once per pageview.\n */\nfunction ExperimentsRunner(props: {\n hostId?: string\n experiments: ScreenExperiment[]\n /** Host consent config (AGL-1498); decides where the visitor id may live. */\n consentHost?: Aglyn.VisitorConsentHost | null\n}) {\n const { hostId, experiments, consentHost } = props\n\n useEffect(() => {\n if (!hostId || !experiments.length) return undefined\n const experiment = experiments[0]\n // Visitor-id persistence honors the consent gate (AGL-1498): without an\n // analytics yes on a consent-gated site, the id lives in sessionStorage —\n // variants stay stable within the visit, and the indefinite identifier\n // is not kept. The id never leaves the browser either way (the beacons\n // below carry no visitor id), which is why this is a persistence\n // downgrade rather than a kill switch on experiments.\n const persistence = Aglyn.resolveVisitorIdPersistence(\n consentHost,\n Aglyn.readStoredVisitorConsent(hostId),\n )\n let visitorId: string\n try {\n const storage =\n persistence === 'local' ? localStorage : sessionStorage\n // Read across BOTH stores so the assignment survives a consent move:\n // a session id promoted to local (consent granted mid-visit) and a\n // legacy local id migrating down to session both keep their variant.\n visitorId =\n storage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n sessionStorage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n localStorage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n ''\n if (!visitorId) {\n visitorId = `v-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`\n }\n storage.setItem(Aglyn.VISITOR_ID_STORAGE_KEY, visitorId)\n // A pre-consent-tool id may still sit in localStorage from before the\n // gate existed; while un-consented it must not persist.\n if (persistence === 'session') {\n localStorage.removeItem(Aglyn.VISITOR_ID_STORAGE_KEY)\n }\n } catch {\n return undefined // No storage (privacy mode) — serve the default.\n }\n const variant = MarketingModel.assignExperimentVariant(\n // Wire-typed props (AGL-418); the plugin narrows its own enum.\n { status: experiment.status as never, variants: experiment.variants,\n ...(experiment.winnerVariantId\n ? { winnerVariantId: experiment.winnerVariantId }\n : {}),\n // End dates (AGL-273): past-end experiments serve the default.\n ...(experiment.endAtMs ? { endAtMs: experiment.endAtMs } : {}) },\n experiment.id,\n visitorId,\n )\n if (!variant) return undefined\n const payload = experiment.payloads[variant.id]\n if (payload) Aglyn.canvas.setNodes(payload as any)\n\n const beacon = (kind: 'exposure' | 'conversion') => {\n void fetch('/api/experiments/track', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n experimentId: experiment.id,\n variantId: variant.id,\n kind,\n }),\n keepalive: true,\n }).catch(() => undefined)\n // GA mirror (wave v8): exposure/conversion events land in the\n // site's own Analytics property when configured. Through the taxonomy\n // since AGL-1591 — which also reserves the name against an authored\n // `trackGaEvent` step, so nothing hand-written can add itself to the\n // counts that decide which variant wins.\n trackEvent('aglyn_experiment', {\n experiment_id: experiment.id,\n variant_id: variant.id,\n experiment_action: kind,\n })\n }\n // Finished experiments serve the winner without counting stats.\n if (experiment.status !== 'running') return undefined\n beacon('exposure')\n\n // Goal listener — client-observable goals only; server-side goals\n // (bookings etc.) count through their own pipelines in a follow-up.\n const cleanups: Array<() => void> = []\n let converted = false\n const convert = () => {\n if (converted) return\n converted = true\n beacon('conversion')\n }\n const goal = experiment.goal?.event ?? 'formSubmission'\n if (goal === 'formSubmission') {\n const onSubmit = () => convert()\n document.addEventListener('submit', onSubmit, true)\n cleanups.push(() => document.removeEventListener('submit', onSubmit, true))\n } else if (goal === 'elementClick') {\n const selector = experiment.goal?.filter?.trim() || 'a, button'\n const onClick = (event: MouseEvent) => {\n const target = event.target as Element | null\n if (target?.closest?.(selector)) convert()\n }\n document.addEventListener('click', onClick, true)\n cleanups.push(() => document.removeEventListener('click', onClick, true))\n } else if (goal === 'scrollDepth') {\n const onScroll = () => {\n const doc = document.documentElement\n const max = doc.scrollHeight - window.innerHeight\n if (max <= 0 || (window.scrollY / max) * 100 >= 50) {\n convert()\n window.removeEventListener('scroll', onScroll)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', onScroll))\n } else if (goal === 'timeOnPage') {\n const timer = setTimeout(convert, 30_000)\n cleanups.push(() => clearTimeout(timer))\n }\n return () => {\n for (const cleanup of cleanups) cleanup()\n }\n // Experiments are static per pageview (ISR props).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hostId, experiments.length && experiments[0]?.id])\n\n return null\n}\n\n/**\n * Site-event automations engine (AGL-256/257): arms the page's triggers\n * (scroll depth, element visibility/clicks, exit intent, dwell time),\n * runs each fired action's CLIENT steps in the browser, and dispatches\n * actions with server steps to /api/events/dispatch. Every trigger fires\n * at most once per pageview.\n */\nfunction AutomationsEngine(props: {\n hostId?: string\n automations: ClientAutomation[]\n /** Host routing map (screen id → slug) for rename-safe redirects. */\n screens?: Record<string, string>\n onShowOverlay: (overlayId: string) => void\n}) {\n const { hostId, automations, screens, onShowOverlay } = props\n const showOverlayRef = useRef(onShowOverlay)\n showOverlayRef.current = onShowOverlay\n\n useEffect(() => {\n if (!hostId || !automations.length) return undefined\n const fired = new Set<string>()\n const cleanups: Array<() => void> = []\n\n const showToast = (\n message: string,\n severity: 'info' | 'success' | 'warning' | 'error',\n ) => {\n const toast = document.createElement('div')\n toast.textContent = message\n toast.setAttribute('role', 'status')\n Object.assign(toast.style, {\n position: 'fixed',\n bottom: '16px',\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: '2147483000',\n padding: '10px 16px',\n borderRadius: '8px',\n fontSize: '14px',\n fontFamily: 'system-ui, sans-serif',\n color: '#fff',\n backgroundColor:\n severity === 'error'\n ? '#c62828'\n : severity === 'warning'\n ? '#e65100'\n : severity === 'success'\n ? '#2e7d32'\n : 'rgba(0, 0, 0, 0.85)',\n maxWidth: '90vw',\n })\n document.body.appendChild(toast)\n setTimeout(() => toast.remove(), 6000)\n }\n\n const runClientSteps = (automation: ClientAutomation) => {\n for (const step of automation.steps) {\n try {\n if (\n step.type === 'addClass' ||\n step.type === 'removeClass' ||\n step.type === 'toggleClass'\n ) {\n // Expand the raw-id selector to also match the layout-composed\n // live id (AGL-573); non-leaf selectors are unchanged.\n const targets = document.querySelectorAll(\n Aglyn.expandLeafSelector(step.selector),\n )\n targets.forEach((element) => {\n if (step.type === 'addClass') {\n element.classList.add(step.className)\n } else if (step.type === 'removeClass') {\n element.classList.remove(step.className)\n } else {\n element.classList.toggle(step.className)\n }\n })\n } else if (\n step.type === 'setAttribute' ||\n step.type === 'removeAttribute'\n ) {\n /*\n The semantics half of a hand-built disclosure (AGL-2546).\n\n Deliberately in THIS loop rather than behind a guard of its own:\n it then inherits exactly the gating the visibility steps have,\n including which surfaces mount the runtime at all. A separate\n path reaching `document.querySelector` directly is how this\n would come to run somewhere `showElement` does not.\n\n The name is re-checked here and not only in the editor. The\n editor is a convenience; a step can reach this runtime from a\n document written before the allowlist existed, or by any route\n that does not pass through the console UI.\n\n A rejected name is a NO-OP, not a throw — the `catch` around\n this loop would otherwise let one bad attribute name silently\n drop every step after it in the same automation.\n */\n if (Aglyn.isInteractionAttributeAllowed(step.name)) {\n const name = step.name.trim().toLowerCase()\n const targets = document.querySelectorAll(\n Aglyn.expandLeafSelector(step.selector),\n )\n targets.forEach((element) => {\n if (step.type === 'setAttribute') {\n element.setAttribute(name, step.value ?? '')\n } else {\n element.removeAttribute(name)\n }\n })\n }\n } else if (step.type === 'scrollTo') {\n // One target, the first one on screen (AGL-2867). A target that\n // is missing, deleted or hidden makes the step a no-op, and the\n // steps after it in this automation still run.\n Aglyn.runScrollToStep(Aglyn.expandLeafSelector(step.selector), {\n behavior: step.behavior,\n offsetPx: step.offsetPx,\n })\n } else if (step.type === 'playVideo') {\n // The Video element's own poster press, sent to the element: the\n // player loads only now, exactly as it would for a click on the\n // poster, and under the same consent rules.\n Aglyn.runPlayVideoStep(Aglyn.expandLeafSelector(step.selector))\n } else if (step.type === 'stickyNav') {\n const target = document.querySelector(\n Aglyn.expandLeafSelector(step.selector?.trim() || 'header, nav'),\n )\n if (target instanceof HTMLElement) {\n target.style.position = 'sticky'\n target.style.top = '0'\n target.style.zIndex = '1100'\n }\n } else if (step.type === 'showHtml') {\n const container = document.createElement('div')\n // Sanitize (AGL-504): unlike runJs, showHtml is NOT dropped by the\n // JS entitlement gate, so raw innerHTML would let any automations-\n // tier author execute event-handler attributes (<img onerror>).\n //\n // ONE policy for the surface (AGL-2486). AGL-1901 moved rich text\n // and Custom HTML onto `sanitizeAuthorHtml`; this call was the\n // last raw DOMPurify left on a published page, and two sanitizers\n // with different rules on one surface is worse than the weaker of\n // them — a reviewer reads the strict one and assumes it covers\n // both. It did not: DOMPurify filters NO CSS, so every `style`\n // attribute arriving here reached the visitor unexamined while\n // the Custom HTML block beside it went through `sanitizeAuthorCss`.\n //\n // Nothing this used to refuse is now allowed. `sanitizeAuthorHtml`\n // is a strict SUBSET of the DOMPurify config it replaces, and that\n // is measured rather than asserted: `rich-text-hydration.spec.tsx`\n // holds this exact former config as `referenceShowHtmlPurify` and\n // runs the shared corpus through both. So the change is only in\n // what it ADDITIONALLY refuses:\n //\n // - `style` now gets the CSS rule — `http:` and unknown-scheme\n // `url()` neutered to `about:invalid`, and `@import`,\n // `expression()`, `behavior:` and `-moz-binding` dropping the\n // declaration whole. Character references are decoded BEFORE\n // the scheme is judged, which the old config did not do: it\n // emitted `url(&#104;ttp://…)` as a literal `http://`.\n // - `<form>` stops being an element. The former FORBID_TAGS here\n // listed `script, iframe, object, embed, base` and omitted\n // `form` — alone among this repo's author-HTML configs, both of\n // which forbade it — so a password field on the owner's live\n // page was one paste away.\n //\n // What is deliberately NOT refused, on either side of the change:\n // a third-party `https:` `url()`, and `position:fixed` / `z-index`.\n // The first is AGL-1725's actor analysis (the site owner chooses\n // recipients for their own visitors); the second is a capability\n // the Styles panel already gives the same author as a first-class\n // field, so refusing it only here would move nothing.\n container.innerHTML = Aglyn.sanitizeAuthorHtml(step.html)\n document.body.appendChild(container)\n } else if (step.type === 'runJs') {\n // Business-gated server-side (dropped from props otherwise);\n // the site owner's own code running on their own page.\n // eslint-disable-next-line no-new-func\n new Function(step.code)()\n } else if (step.type === 'redirect') {\n // Screen targets resolve through the routing map (AGL-339) so\n // slug renames never break the interaction; url is the manual\n // fallback.\n const screenSlug =\n (step as any).screenId != null\n ? screens?.[(step as any).screenId]\n : undefined\n const destination =\n screenSlug != null\n ? Aglyn.screenRoutePathToUrl(screenSlug)\n : step.url\n if (destination) window.location.assign(destination)\n } else if (\n step.type === 'showElement' ||\n step.type === 'hideElement' ||\n step.type === 'toggleElement'\n ) {\n // Element choreography (AGL-562): class-based so \"show\"\n // reveals targets the author started hidden. The tenant page\n // ships the hidden-class rule in its SSR HTML; ensure is the\n // fallback for other embeddings. Grace delays + Escape/\n // outside-click dismissal ride the same step (AGL-589).\n Aglyn.ensureElementHiddenStyle()\n Aglyn.runElementVisibilityStep(\n step.type === 'showElement'\n ? 'show'\n : step.type === 'hideElement'\n ? 'hide'\n : 'toggle',\n // Expand so a show/hide/toggle authored against the raw\n // canvas id still reaches the layout-composed node (AGL-573).\n Aglyn.expandLeafSelector(step.selector),\n {\n delayMs: (step as { delayMs?: number }).delayMs,\n dismissOn: (\n step as { dismissOn?: Aglyn.ElementDismissOption[] }\n ).dismissOn,\n },\n )\n } else if (\n step.type === 'openDrawer' ||\n step.type === 'closeDrawer' ||\n step.type === 'toggleDrawer'\n ) {\n // Drawer commands (AGL-562) ride the window event bus; the\n // muiDrawer element answers (first drawer for broadcasts).\n Aglyn.dispatchDrawerCommand(\n step.type === 'openDrawer'\n ? 'open'\n : step.type === 'closeDrawer'\n ? 'close'\n : 'toggle',\n step.drawerNodeId || undefined,\n )\n } else if (\n step.type === 'openMenu' ||\n step.type === 'closeMenu' ||\n step.type === 'toggleMenu'\n ) {\n // Menu commands (AGL-568) ride their own event bus like\n // drawers; the nav-menu elements answer (first menu for\n // broadcasts). A hover-enter trigger stamps the hover flag\n // so a menu opened this way closes itself when the pointer\n // leaves the trigger + panel surface.\n Aglyn.dispatchMenuCommand(\n step.type === 'openMenu'\n ? 'open'\n : step.type === 'closeMenu'\n ? 'close'\n : 'toggle',\n step.menuNodeId || undefined,\n { hover: automation.event === 'elementHoverEnter' },\n )\n } else if (step.type === 'trackGaEvent') {\n // AGL-1587: the name and the params are AUTHORED, which makes\n // this the least trustworthy analytics input in the repo — a\n // param could carry a form field's value. It goes through the\n // shared sanitizer and the reserved-name refusal like everything\n // else, never raw gtag.\n trackAuthoredEvent(step.eventName, step.params)\n } else if (step.type === 'siteAlert') {\n showToast(\n String(step.message ?? '').slice(0, 300),\n step.severity ?? 'info',\n )\n } else if (step.type === 'showOverlay') {\n if (step.overlayId) showOverlayRef.current(step.overlayId)\n }\n } catch (error) {\n console.error('automation step failed', error)\n }\n }\n }\n\n const fire = (automation: ClientAutomation) => {\n // Repeatable UI choreography (AGL-562): everyTime automations skip\n // the once-per-pageview gate (explicit caps below still apply).\n if (!automation.everyTime) {\n if (fired.has(automation.id)) return\n fired.add(automation.id)\n }\n // Once per visitor (AGL-266): a persisted flag outlives the pageview.\n if (automation.oncePerVisitor) {\n const key = `aglyn:auto:${automation.id}`\n try {\n if (localStorage.getItem(key)) return\n localStorage.setItem(key, '1')\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n } else if (automation.oncePerSession) {\n // Once per session (AGL-274): survives navigation, not the tab.\n const key = `aglyn:auto:${automation.id}`\n try {\n if (sessionStorage.getItem(key)) return\n sessionStorage.setItem(key, '1')\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n } else if (automation.cooldownMinutes) {\n // Cooldown (AGL-274): a timestamp gates re-fires for the visitor.\n const key = `aglyn:auto:${automation.id}:at`\n try {\n const last = Number(localStorage.getItem(key) ?? 0)\n if (\n last &&\n Date.now() - last < automation.cooldownMinutes * 60_000\n ) {\n return\n }\n localStorage.setItem(key, String(Date.now()))\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n }\n runClientSteps(automation)\n if (automation.hasServerSteps) {\n void fetch('/api/events/dispatch', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n actionId: automation.id,\n event: automation.event,\n payload: { path: window.location.pathname },\n }),\n keepalive: true,\n }).catch(() => undefined)\n }\n }\n\n /**\n * Elements that arrive AFTER this effect binds (AGL-2512).\n *\n * `elementVisible` and `scrollToElement` are the only two triggers that\n * resolve their targets by querying the DOM — every other one listens on\n * `document` and so needs no element to exist yet. A single query at bind\n * time made them dead on the two pages where the tree lands late: a\n * deferred lazy panel patched back in on interaction (AGL-1285), and a\n * gated screen's tree swapped in once the visitor is past the gate\n * (AGL-2510).\n *\n * One MutationObserver for all of them, not one each, and it stops the\n * moment nothing is left watching — these triggers fire once per pageview\n * by construction, so a page whose targets have all been seen pays\n * nothing for the rest of the visit. A page with no such automation never\n * starts one at all.\n */\n const pendingObservers: Array<() => void> = []\n let domObserver: MutationObserver | null = null\n const rescan = () => {\n for (const attach of [...pendingObservers]) attach()\n if (!pendingObservers.length) {\n domObserver?.disconnect()\n domObserver = null\n }\n }\n const watchLateElements = (attach: () => void) => {\n pendingObservers.push(attach)\n if (domObserver || typeof MutationObserver === 'undefined') return\n domObserver = new MutationObserver(rescan)\n domObserver.observe(document.body, { childList: true, subtree: true })\n }\n const stopWatching = (attach: () => void) => {\n const index = pendingObservers.indexOf(attach)\n if (index >= 0) pendingObservers.splice(index, 1)\n if (!pendingObservers.length) {\n domObserver?.disconnect()\n domObserver = null\n }\n }\n cleanups.push(() => {\n pendingObservers.length = 0\n domObserver?.disconnect()\n domObserver = null\n })\n\n for (const automation of automations) {\n const { event, threshold } = automation\n // Composition namespaces a node's live `data-aglyn` id, but the\n // interaction builder records the RAW canvas id in the selector.\n // Expand it so the trigger still matches the live element — layouts\n // (AGL-573) and reusable-component grafts (AGL-1229), the latter being\n // why every interaction authored inside the Site nav bound to nothing.\n // Hand-typed CSS selectors pass through untouched.\n const selector = automation.selector\n ? Aglyn.expandLeafSelector(automation.selector)\n : automation.selector\n if (event === 'pageVisit') {\n fire(automation)\n } else if (event === 'timeOnPage') {\n const timer = setTimeout(\n () => fire(automation),\n Math.max(1, threshold ?? 5) * 1000,\n )\n cleanups.push(() => clearTimeout(timer))\n } else if (event === 'scrollDepth') {\n const onScroll = () => {\n const doc = document.documentElement\n const max = doc.scrollHeight - window.innerHeight\n const percent = max > 0 ? (window.scrollY / max) * 100 : 100\n if (percent >= Math.min(100, Math.max(1, threshold ?? 50))) {\n fire(automation)\n window.removeEventListener('scroll', onScroll)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', onScroll))\n } else if (event === 'elementVisible' || event === 'scrollToElement') {\n if (!selector) continue\n let fired = false\n const observer = new IntersectionObserver((entries) => {\n if (fired || !entries.some((entry) => entry.isIntersecting)) return\n fired = true\n fire(automation)\n observer.disconnect()\n stopWatching(attachTargets)\n })\n // Re-entrant: called again on every DOM change until the trigger\n // fires, and observing an element twice is a no-op, so a rescan costs\n // one `querySelectorAll` and nothing else.\n const attachTargets = () => {\n if (fired) return stopWatching(attachTargets)\n document\n .querySelectorAll(selector)\n .forEach((target) => observer.observe(target))\n }\n attachTargets()\n watchLateElements(attachTargets)\n cleanups.push(() => observer.disconnect())\n } else if (event === 'elementClick') {\n if (!selector) continue\n const onClick = (mouseEvent: MouseEvent) => {\n const target = mouseEvent.target as Element | null\n if (target?.closest?.(selector)) fire(automation)\n }\n document.addEventListener('click', onClick, true)\n cleanups.push(() =>\n document.removeEventListener('click', onClick, true),\n )\n } else if (\n event === 'elementHoverEnter' ||\n event === 'elementHoverLeave'\n ) {\n // Hover choreography (AGL-562): delegated mouseover/mouseout with\n // enter/leave semantics — moves WITHIN the matched element (its\n // own children) never re-fire.\n if (!selector) continue\n const onHover = (mouseEvent: MouseEvent) => {\n const target = mouseEvent.target as Element | null\n const match = target?.closest?.(selector)\n if (!match) return\n const related = mouseEvent.relatedTarget as Element | null\n if (related && match.contains(related)) return\n fire(automation)\n }\n const type = event === 'elementHoverEnter' ? 'mouseover' : 'mouseout'\n document.addEventListener(type, onHover, true)\n cleanups.push(() =>\n document.removeEventListener(type, onHover, true),\n )\n } else if (event === 'exitIntent') {\n const onLeave = (mouseEvent: MouseEvent) => {\n if (mouseEvent.clientY <= 0) fire(automation)\n }\n document.addEventListener('mouseleave', onLeave)\n cleanups.push(() => document.removeEventListener('mouseleave', onLeave))\n }\n }\n return () => {\n for (const cleanup of cleanups) cleanup()\n }\n // Automations are static per pageview (ISR props).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n hostId,\n screens,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(automations.map((automation) => automation.id)),\n ])\n\n return null\n}\n\nfunction AnnouncementBar(props: {\n bar: AnnouncementBarData\n hostId?: string\n}) {\n const { bar, hostId } = props\n const storageKey = `aglyn-abar-${bar.contentHash}`\n const [hidden, setHidden] = useState(true)\n useEffect(() => {\n try {\n setHidden(Boolean(window.localStorage.getItem(storageKey)))\n } catch {\n setHidden(false)\n }\n }, [storageKey])\n // Impression (AGL-271): once per pageview, only when actually shown.\n useEffect(() => {\n if (!hidden) sendOverlayBeacon(hostId, 'barImpression', bar.overlayId)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hidden])\n if (hidden) return null\n const style: CSSProperties = {\n position: 'relative',\n zIndex: 1300,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '8px 40px 8px 16px',\n fontSize: 14,\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n color: bar.textColor || '#fff',\n backgroundColor: bar.backgroundColor || '#111827',\n }\n const text = bar.href ? (\n <a\n href={bar.href}\n onClick={() => sendOverlayBeacon(hostId, 'barClick', bar.overlayId)}\n style={{ color: 'inherit', textDecoration: 'underline' }}\n >\n {bar.text}\n </a>\n ) : (\n <span>{bar.text}</span>\n )\n return (\n <div role=\"region\" aria-label=\"Announcement\" style={style}>\n {text}\n {bar.dismissible ? (\n <button\n type=\"button\"\n aria-label=\"Dismiss announcement\"\n onClick={() => {\n try {\n window.localStorage.setItem(storageKey, '1')\n } catch {\n // Storage may be unavailable (private mode); hide anyway.\n }\n sendOverlayBeacon(hostId, 'barDismiss', bar.overlayId)\n setHidden(true)\n }}\n style={{\n position: 'absolute',\n right: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n border: 'none',\n background: 'transparent',\n color: 'inherit',\n fontSize: 16,\n lineHeight: 1,\n cursor: 'pointer',\n padding: 6,\n }}\n >\n {'✕'}\n </button>\n ) : null}\n </div>\n )\n}\n\n/**\n * Promotional popup (AGL-196). Client owns: schedule-window re-check (the\n * page is ISR-cached), trigger timing (delay/scroll/exit), and frequency\n * capping via a per-content-hash localStorage stamp (no cookies). ESC and\n * backdrop close; reduced-motion preferences skip the entrance ease.\n */\nfunction PopupOverlay(props: {\n popup: PopupData\n hostId?: string\n}) {\n const { popup, hostId } = props\n const storageKey = `aglyn-popup-${popup.contentHash}`\n const [open, setOpen] = useState(false)\n // Email capture (AGL-200): submits into the forms pipeline (inbox +\n // contacts); success suppresses the popup for ~10 years.\n const [email, setEmail] = useState('')\n // The honeypot's value, held in state so whatever a bot typed into the\n // hidden input below is what gets POSTed (AGL-1665). This used to be a\n // hardcoded `website: ''` in the request body: the route drops a\n // submission only when the field is NON-empty, so a constant empty string\n // never failed the check — it removed it. There was no field on the page\n // to fill and no value a script could set, which made the popup the one\n // form surface on the site with no honeypot at all.\n const [website, setWebsite] = useState('')\n const [submitted, setSubmitted] = useState(false)\n\n useEffect(() => {\n if (open) sendOverlayBeacon(hostId, 'popupImpression', popup.overlayId)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open, hostId])\n\n useEffect(() => {\n const now = Date.now()\n if (popup.startAtMs && now < popup.startAtMs) return\n if (popup.endAtMs && now > popup.endAtMs) return\n try {\n // The decision itself is a pure function in the model (AGL-2174) —\n // which store to read is the whole feature, and it has to agree with\n // what `close` writes.\n const suppressed = MarketingModel.popupSuppressed(\n popup,\n MarketingModel.popupCapStore(popup) === 'session'\n ? { sessionFlag: window.sessionStorage.getItem(storageKey) }\n : { lastShownMs: Number(window.localStorage.getItem(storageKey) ?? 0) },\n now,\n )\n if (suppressed) return\n } catch {\n // Storage unavailable: show at most per-pageview.\n }\n let cleanup: (() => void) | undefined\n if (popup.trigger === 'scroll') {\n const threshold = Math.min(100, Math.max(0, popup.triggerValue)) / 100\n const onScroll = () => {\n const height =\n document.documentElement.scrollHeight - window.innerHeight\n if (height <= 0 || window.scrollY / height >= threshold) {\n setOpen(true)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanup = () => window.removeEventListener('scroll', onScroll)\n } else if (popup.trigger === 'exit') {\n const onLeave = (event: MouseEvent) => {\n if (event.clientY <= 0) setOpen(true)\n }\n document.addEventListener('mouseout', onLeave)\n cleanup = () => document.removeEventListener('mouseout', onLeave)\n } else {\n const timer = window.setTimeout(\n () => setOpen(true),\n Math.max(0, popup.triggerValue) * 1000,\n )\n cleanup = () => window.clearTimeout(timer)\n }\n return cleanup\n }, [popup, storageKey])\n\n const close = (kind: 'popupDismiss' | 'popupClick' = 'popupDismiss') => {\n try {\n // Written to whichever store the cap READS (AGL-2174). Stamping\n // `localStorage` for a session-capped popup would leave a timestamp\n // nothing reads, outliving the cap it was meant to record.\n if (MarketingModel.popupCapStore(popup) === 'session') {\n window.sessionStorage.setItem(storageKey, '1')\n } else {\n window.localStorage.setItem(storageKey, String(Date.now()))\n }\n } catch {\n // Private mode etc. — closing still works for this pageview.\n }\n sendOverlayBeacon(hostId, kind, popup.overlayId)\n setOpen(false)\n }\n\n const handleEmailSubmit = async () => {\n const value = email.trim()\n if (!value || submitted) return\n try {\n const response = await fetch('/api/forms/submit', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n // The door this capture comes through (AGL-3029): the popup is a\n // Marketing element, so a site that switched Forms off still\n // collects the address it shows the popup for.\n door: 'popup',\n formName: 'Popup',\n fields: { email: value },\n path: window.location.pathname,\n // Submitted AS-IS (AGL-1665) — the point of a honeypot is that the\n // client never judges it. `libs/plugins/mui/.../form.tsx` reads its\n // own hidden `website` input off the FormData and forwards it the\n // same way; `/api/forms/submit` is the single place that decides.\n website,\n // The campaign this visitor came from, when they came from one. A\n // popup capture is often a site's highest-converting door, so it\n // reports its campaign for the same reason it reports its lead.\n ...utmTouchField(),\n }),\n })\n // The popup's email capture is a lead, and it reported none: an\n // announcement popup is often a site's highest-converting capture, and\n // the merchant saw the impression and the dismiss (`aglyn_overlay`) with\n // nothing in between. The generic form block has sent `generate_lead`\n // since AGL-1561; this door was simply never wired to it.\n //\n // Gated on `response.ok`, unlike the visitor-facing thank-you below.\n // The two disagree deliberately: a spam-refused or rate-limited capture\n // is still shown the thank-you — telling a real visitor to try again\n // after a honeypot verdict would leak the honeypot — but it is NOT a\n // lead, and counting it would inflate the only number the merchant uses\n // to judge whether the popup is worth interrupting people with.\n //\n // `form_name` is the block's own name, matching the `formName` on the\n // wire; the address the visitor just typed never leaves this function.\n if (response.ok) {\n trackEvent('generate_lead', {\n form_name: 'Popup',\n form_location: window.location.pathname,\n })\n }\n } catch {\n // Best-effort — still thank the visitor.\n }\n setSubmitted(true)\n try {\n // Far-future stamp: a successful capture never re-prompts.\n window.localStorage.setItem(\n storageKey,\n String(Date.now() + 315360000000),\n )\n } catch {\n // Ignore.\n }\n }\n\n useEffect(() => {\n if (!open) return\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n if (!open) return null\n return (\n <div\n onClick={() => close()}\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 2147483200,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n padding: 16,\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={popup.headline || 'Announcement'}\n onClick={(event) => event.stopPropagation()}\n style={{\n maxWidth: 420,\n width: '100%',\n background: '#fff',\n color: '#111827',\n borderRadius: 12,\n overflow: 'hidden',\n boxShadow: '0 24px 64px rgba(0, 0, 0, 0.35)',\n fontFamily: 'system-ui, sans-serif',\n position: 'relative',\n }}\n >\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={() => close()}\n style={{\n position: 'absolute',\n top: 8,\n right: 8,\n border: 'none',\n background: 'rgba(255, 255, 255, 0.85)',\n borderRadius: '50%',\n width: 28,\n height: 28,\n cursor: 'pointer',\n fontSize: 14,\n lineHeight: 1,\n }}\n >\n {'✕'}\n </button>\n {/* The popup image is a free-text console field rendered verbatim —\n one of AGL-1725's raw author sinks. Scheme rule only, never a\n host check: `http:` and unknown schemes render nothing;\n https/relative (the media picker's forms) render as stored,\n except a library file's Storage URL, which the resolver routes\n through the site's CDN like every other image (AGL-3506). */}\n {popup.imageUrl && !Aglyn.isRefusedAuthorImageSrc(popup.imageUrl) ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={Aglyn.siteRelativeMediaSrc(popup.imageUrl, { hostId })}\n // AGL-1896. This was a hardcoded `alt=\"\"` with no field behind\n // it. Still empty when the author left it empty — a decorative\n // banner beside its own headline is the case `alt=\"\"` exists for\n // — but it is now their choice rather than ours, and picking the\n // image from the library fills it in from the asset.\n alt={popup.imageAlt ?? ''}\n style={{\n width: '100%',\n maxHeight: 200,\n objectFit: 'cover',\n display: 'block',\n }}\n />\n ) : null}\n <div style={{ padding: 24, textAlign: 'center' }}>\n {popup.headline ? (\n <h2 style={{ margin: '0 0 8px', fontSize: 20 }}>\n {popup.headline}\n </h2>\n ) : null}\n <p style={{ margin: 0, fontSize: 14, whiteSpace: 'pre-wrap' }}>\n {popup.body}\n </p>\n {popup.collectEmail ? (\n <div style={{ marginTop: 16 }}>\n {submitted ? (\n <p style={{ margin: 0, fontSize: 14, fontWeight: 600 }}>\n {'Thanks — you are on the list!'}\n </p>\n ) : (\n <form\n onSubmit={(event) => {\n event.preventDefault()\n void handleEmailSubmit()\n }}\n style={{ display: 'flex', gap: 8, justifyContent: 'center' }}\n >\n <input\n type=\"email\"\n required\n placeholder=\"you@example.com\"\n // Same nameless-input defect as the newsletter block\n // (AGL-2392). A popup is modal-ish and arrives unbidden,\n // so a screen-reader user meets this field with no\n // surrounding context at all.\n aria-label=\"Email address\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n style={{\n flex: 1,\n maxWidth: 240,\n padding: '8px 12px',\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n }}\n />\n {/* Honeypot: humans never see or fill this (AGL-1665).\n Off-screen rather than `display:none`/`hidden`, and\n named `website`, so the naive form-filling bots the\n route's check is aimed at treat it as an ordinary\n field — the same bait, presented the same way, as the\n site form's. Out of flow, so the flex row above is\n unchanged. */}\n <input\n type=\"text\"\n name=\"website\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={website}\n onChange={(event) => setWebsite(event.target.value)}\n style={{\n position: 'absolute',\n left: '-5000px',\n height: 0,\n width: 0,\n }}\n />\n <button\n type=\"submit\"\n style={{\n padding: '8px 16px',\n borderRadius: 8,\n border: 'none',\n background: '#111827',\n color: '#fff',\n fontSize: 14,\n cursor: 'pointer',\n }}\n >\n {'Sign up'}\n </button>\n </form>\n )}\n </div>\n ) : null}\n {popup.ctaHref && popup.ctaLabel ? (\n <a\n href={popup.ctaHref}\n onClick={() => close('popupClick')}\n style={{\n display: 'inline-block',\n marginTop: 16,\n padding: '10px 24px',\n borderRadius: 8,\n background: '#111827',\n color: '#fff',\n textDecoration: 'none',\n fontSize: 14,\n }}\n >\n {popup.ctaLabel}\n </a>\n ) : null}\n </div>\n </div>\n </div>\n )\n}\n\n\n/**\n * The marketing plugin's site runtime (AGL-419), relocated verbatim from\n * the tenant catch-all: announcement bar + popup rendering (AGL-195/200),\n * the experiments runner (AGL-253), the site-event automations engine\n * (AGL-256/257), and automation-triggered overlays. Reads back exactly the\n * page-props slices its server enricher wrote (site-contract shapes).\n */\nexport function MarketingSiteRuntime({ hostId, screens, page }: SiteRuntimeProps) {\n const [automationOverlay, setAutomationOverlay] = useState<any>(null)\n const announcementBar = page['announcementBar'] as AnnouncementBarData | null\n const popup = page['popup'] as PopupData | null\n const experiments = (page['experiments'] ?? []) as ScreenExperiment[]\n const clientAutomations = (page['clientAutomations'] ?? []) as ClientAutomation[]\n const automationOverlays = page['automationOverlays'] as Record<string, any> | null\n\n return (\n <>\n {announcementBar ? (\n <AnnouncementBar bar={announcementBar} hostId={hostId} />\n ) : null}\n {popup ? <PopupOverlay popup={popup} hostId={hostId} /> : null}\n {/* Screen/section experiments (AGL-253). */}\n {experiments.length ? (\n <ExperimentsRunner\n hostId={hostId}\n experiments={experiments}\n consentHost={page['data']?.host as Aglyn.VisitorConsentHost | null}\n />\n ) : null}\n {/* Site-event automations (AGL-256/257). */}\n {clientAutomations.length ? (\n <AutomationsEngine\n hostId={hostId}\n automations={clientAutomations}\n screens={screens}\n onShowOverlay={(overlayId) => {\n const overlay = automationOverlays?.[overlayId]\n if (overlay) setAutomationOverlay({ id: overlayId, ...overlay })\n }}\n />\n ) : null}\n {automationOverlay?.kind === 'bar' && automationOverlay.bar?.text ? (\n <AnnouncementBar\n bar={{\n ...automationOverlay.bar,\n text: String(automationOverlay.bar.text),\n dismissible: automationOverlay.bar.dismissible !== false,\n contentHash: `automation-${automationOverlay.id}`,\n }}\n hostId={hostId}\n />\n ) : null}\n {automationOverlay?.kind === 'popup' && automationOverlay.popup?.body ? (\n <PopupOverlay\n popup={{\n ...automationOverlay.popup,\n body: String(automationOverlay.popup.body),\n trigger: 'delay',\n triggerValue: 0,\n frequencyDays: Math.max(\n 1,\n Number(automationOverlay.popup.frequencyDays ?? 1),\n ),\n contentHash: `automation-${automationOverlay.id}`,\n }}\n hostId={hostId}\n />\n ) : null}\n </>\n )\n}\n"],"names":["Aglyn","sendAnalyticsBeacon","trackAuthoredEvent","trackEvent","utmTouchField","useEffect","useRef","useState","MarketingModel","sendOverlayBeacon","hostId","overlay","overlayId","overlay_action","overlay_id","ExperimentsRunner","props","experiments","consentHost","experiment","length","undefined","persistence","resolveVisitorIdPersistence","readStoredVisitorConsent","visitorId","storage","localStorage","sessionStorage","getItem","VISITOR_ID_STORAGE_KEY","Math","random","toString","slice","Date","now","setItem","removeItem","variant","assignExperimentVariant","status","variants","winnerVariantId","endAtMs","id","payload","payloads","canvas","setNodes","beacon","kind","fetch","method","headers","body","JSON","stringify","experimentId","variantId","keepalive","catch","experiment_id","variant_id","experiment_action","cleanups","converted","convert","goal","event","onSubmit","document","addEventListener","push","removeEventListener","selector","filter","trim","onClick","target","closest","onScroll","doc","documentElement","max","scrollHeight","window","innerHeight","scrollY","passive","timer","setTimeout","clearTimeout","cleanup","AutomationsEngine","automations","screens","onShowOverlay","showOverlayRef","current","fired","Set","showToast","message","severity","toast","createElement","textContent","setAttribute","Object","assign","style","position","bottom","left","transform","zIndex","padding","borderRadius","fontSize","fontFamily","color","backgroundColor","maxWidth","appendChild","remove","runClientSteps","automation","step","steps","type","targets","querySelectorAll","expandLeafSelector","forEach","element","classList","add","className","toggle","isInteractionAttributeAllowed","name","toLowerCase","value","removeAttribute","runScrollToStep","behavior","offsetPx","runPlayVideoStep","querySelector","HTMLElement","top","container","innerHTML","sanitizeAuthorHtml","html","Function","code","screenSlug","screenId","destination","screenRoutePathToUrl","url","location","ensureElementHiddenStyle","runElementVisibilityStep","delayMs","dismissOn","dispatchDrawerCommand","drawerNodeId","dispatchMenuCommand","menuNodeId","hover","eventName","params","String","error","console","fire","everyTime","has","oncePerVisitor","key","oncePerSession","cooldownMinutes","last","Number","hasServerSteps","actionId","path","pathname","pendingObservers","domObserver","rescan","attach","disconnect","watchLateElements","MutationObserver","observe","childList","subtree","stopWatching","index","indexOf","splice","threshold","percent","min","observer","IntersectionObserver","entries","some","entry","isIntersecting","attachTargets","mouseEvent","onHover","match","related","relatedTarget","contains","onLeave","clientY","map","AnnouncementBar","bar","storageKey","contentHash","hidden","setHidden","Boolean","display","alignItems","justifyContent","gap","textAlign","textColor","text","href","a","textDecoration","span","div","role","aria-label","dismissible","button","right","border","background","lineHeight","cursor","PopupOverlay","popup","open","setOpen","email","setEmail","website","setWebsite","submitted","setSubmitted","startAtMs","suppressed","popupSuppressed","popupCapStore","sessionFlag","lastShownMs","trigger","triggerValue","height","close","handleEmailSubmit","response","door","formName","fields","ok","form_name","form_location","onKey","inset","aria-modal","headline","stopPropagation","width","overflow","boxShadow","imageUrl","isRefusedAuthorImageSrc","img","src","siteRelativeMediaSrc","alt","imageAlt","maxHeight","objectFit","h2","margin","p","whiteSpace","collectEmail","marginTop","fontWeight","form","preventDefault","input","required","placeholder","onChange","flex","tabIndex","autoComplete","aria-hidden","ctaHref","ctaLabel","MarketingSiteRuntime","page","automationOverlay","setAutomationOverlay","announcementBar","clientAutomations","automationOverlays","host","frequencyDays"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/marketing/src/lib/components/site-runtime.tsx"],"sourcesContent":["/**\n * @license\n * Copyright 2022 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n'use client'\n\nimport * as Aglyn from '@aglyn/aglyn'\nimport { sendAnalyticsBeacon } from '@aglyn/aglyn/app-utils/analytics-beacon'\nimport {\n trackAuthoredEvent,\n trackEvent,\n} from '@aglyn/aglyn/app-utils/analytics-events'\nimport {\n claimFirstCampaignTouch,\n notePageCampaigns,\n utmTouchField,\n whenUtmTouchConsentSettles,\n} from '@aglyn/aglyn/app-utils/utm-touch'\nimport { type CSSProperties, useEffect, useRef, useState } from 'react'\nimport type { SiteRuntimeProps } from '@aglyn/aglyn'\nimport * as MarketingModel from '../model'\nimport type {\n AnnouncementBarData,\n ClientAutomation,\n PopupData,\n ScreenExperiment,\n} from '../model/site-contract'\n\n/**\n * Overlay metrics beacon (AGL-200): fire-and-forget, never blocks UX.\n * With an `overlayId` (marketing-hub docs, AGL-271) the collector also\n * increments that overlay's own stats counters.\n */\nfunction sendOverlayBeacon(\n hostId: string | undefined,\n overlay: string,\n overlayId?: string,\n) {\n if (!hostId) return\n // Best-effort, and refused outright from a non-production build or a browser\n // marked ours — the same gate the pageview beacon passes. The GA mirror\n // below is NOT gated here: `trackEvent` carries the taxonomy's own\n // environment check and stamps `traffic_type` rather than dropping the hit.\n sendAnalyticsBeacon({\n hostId,\n overlay,\n ...(overlayId ? { overlayId } : {}),\n })\n // GA mirror (wave v8): sites with Analytics configured see overlay\n // engagement in their own property; no-op without gtag.\n //\n // Through the taxonomy since AGL-1591 rather than raw gtag. `trackEvent`\n // already swallows everything and never throws, so the try/catch this used\n // to need is gone rather than kept as decoration.\n trackEvent('aglyn_overlay', {\n overlay_action: overlay,\n ...(overlayId ? { overlay_id: overlayId } : {}),\n })\n}\n\n/**\n * Site-wide announcement bar (AGL-195). Dismissal is per content-hash in\n * localStorage (no cookies): editing the text re-shows the bar for\n * everyone who hid the old one.\n */\n/**\n * Experiments runner (AGL-253): deterministic per-visitor assignment for\n * the screen's experiments. The first active experiment wins (one per\n * screen); its variant tree — composed server-side per variant version —\n * swaps in via canvas.setNodes on hydration. Exposures beacon on\n * assignment; the conversion listener matches the experiment's goal and\n * beacons once per pageview.\n */\nfunction ExperimentsRunner(props: {\n hostId?: string\n experiments: ScreenExperiment[]\n /** Host consent config (AGL-1498); decides where the visitor id may live. */\n consentHost?: Aglyn.VisitorConsentHost | null\n}) {\n const { hostId, experiments, consentHost } = props\n\n useEffect(() => {\n if (!hostId || !experiments.length) return undefined\n const experiment = experiments[0]\n // Visitor-id persistence honors the consent gate (AGL-1498): without an\n // analytics yes on a consent-gated site, the id lives in sessionStorage —\n // variants stay stable within the visit, and the indefinite identifier\n // is not kept. The id never leaves the browser either way (the beacons\n // below carry no visitor id), which is why this is a persistence\n // downgrade rather than a kill switch on experiments.\n const persistence = Aglyn.resolveVisitorIdPersistence(\n consentHost,\n Aglyn.readStoredVisitorConsent(hostId),\n )\n let visitorId: string\n try {\n const storage =\n persistence === 'local' ? localStorage : sessionStorage\n // Read across BOTH stores so the assignment survives a consent move:\n // a session id promoted to local (consent granted mid-visit) and a\n // legacy local id migrating down to session both keep their variant.\n visitorId =\n storage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n sessionStorage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n localStorage.getItem(Aglyn.VISITOR_ID_STORAGE_KEY) ??\n ''\n if (!visitorId) {\n visitorId = `v-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`\n }\n storage.setItem(Aglyn.VISITOR_ID_STORAGE_KEY, visitorId)\n // A pre-consent-tool id may still sit in localStorage from before the\n // gate existed; while un-consented it must not persist.\n if (persistence === 'session') {\n localStorage.removeItem(Aglyn.VISITOR_ID_STORAGE_KEY)\n }\n } catch {\n return undefined // No storage (privacy mode) — serve the default.\n }\n const variant = MarketingModel.assignExperimentVariant(\n // Wire-typed props (AGL-418); the plugin narrows its own enum.\n { status: experiment.status as never, variants: experiment.variants,\n ...(experiment.winnerVariantId\n ? { winnerVariantId: experiment.winnerVariantId }\n : {}),\n // End dates (AGL-273): past-end experiments serve the default.\n ...(experiment.endAtMs ? { endAtMs: experiment.endAtMs } : {}) },\n experiment.id,\n visitorId,\n )\n if (!variant) return undefined\n const payload = experiment.payloads[variant.id]\n if (payload) Aglyn.canvas.setNodes(payload as any)\n\n const beacon = (kind: 'exposure' | 'conversion') => {\n void fetch('/api/experiments/track', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n experimentId: experiment.id,\n variantId: variant.id,\n kind,\n }),\n keepalive: true,\n }).catch(() => undefined)\n // GA mirror (wave v8): exposure/conversion events land in the\n // site's own Analytics property when configured. Through the taxonomy\n // since AGL-1591 — which also reserves the name against an authored\n // `trackGaEvent` step, so nothing hand-written can add itself to the\n // counts that decide which variant wins.\n trackEvent('aglyn_experiment', {\n experiment_id: experiment.id,\n variant_id: variant.id,\n experiment_action: kind,\n })\n }\n // Finished experiments serve the winner without counting stats.\n if (experiment.status !== 'running') return undefined\n beacon('exposure')\n\n // Goal listener — client-observable goals only; server-side goals\n // (bookings etc.) count through their own pipelines in a follow-up.\n const cleanups: Array<() => void> = []\n let converted = false\n const convert = () => {\n if (converted) return\n converted = true\n beacon('conversion')\n }\n const goal = experiment.goal?.event ?? 'formSubmission'\n if (goal === 'formSubmission') {\n const onSubmit = () => convert()\n document.addEventListener('submit', onSubmit, true)\n cleanups.push(() => document.removeEventListener('submit', onSubmit, true))\n } else if (goal === 'elementClick') {\n const selector = experiment.goal?.filter?.trim() || 'a, button'\n const onClick = (event: MouseEvent) => {\n const target = event.target as Element | null\n if (target?.closest?.(selector)) convert()\n }\n document.addEventListener('click', onClick, true)\n cleanups.push(() => document.removeEventListener('click', onClick, true))\n } else if (goal === 'scrollDepth') {\n const onScroll = () => {\n const doc = document.documentElement\n const max = doc.scrollHeight - window.innerHeight\n if (max <= 0 || (window.scrollY / max) * 100 >= 50) {\n convert()\n window.removeEventListener('scroll', onScroll)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', onScroll))\n } else if (goal === 'timeOnPage') {\n const timer = setTimeout(convert, 30_000)\n cleanups.push(() => clearTimeout(timer))\n }\n return () => {\n for (const cleanup of cleanups) cleanup()\n }\n // Experiments are static per pageview (ISR props).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hostId, experiments.length && experiments[0]?.id])\n\n return null\n}\n\n/**\n * Site-event automations engine (AGL-256/257): arms the page's triggers\n * (scroll depth, element visibility/clicks, exit intent, dwell time),\n * runs each fired action's CLIENT steps in the browser, and dispatches\n * actions with server steps to /api/events/dispatch. Every trigger fires\n * at most once per pageview.\n */\nfunction AutomationsEngine(props: {\n hostId?: string\n automations: ClientAutomation[]\n /** Host routing map (screen id → slug) for rename-safe redirects. */\n screens?: Record<string, string>\n onShowOverlay: (overlayId: string) => void\n}) {\n const { hostId, automations, screens, onShowOverlay } = props\n const showOverlayRef = useRef(onShowOverlay)\n showOverlayRef.current = onShowOverlay\n\n useEffect(() => {\n if (!hostId || !automations.length) return undefined\n const fired = new Set<string>()\n const cleanups: Array<() => void> = []\n\n const showToast = (\n message: string,\n severity: 'info' | 'success' | 'warning' | 'error',\n ) => {\n const toast = document.createElement('div')\n toast.textContent = message\n toast.setAttribute('role', 'status')\n Object.assign(toast.style, {\n position: 'fixed',\n bottom: '16px',\n left: '50%',\n transform: 'translateX(-50%)',\n zIndex: '2147483000',\n padding: '10px 16px',\n borderRadius: '8px',\n fontSize: '14px',\n fontFamily: 'system-ui, sans-serif',\n color: '#fff',\n backgroundColor:\n severity === 'error'\n ? '#c62828'\n : severity === 'warning'\n ? '#e65100'\n : severity === 'success'\n ? '#2e7d32'\n : 'rgba(0, 0, 0, 0.85)',\n maxWidth: '90vw',\n })\n document.body.appendChild(toast)\n setTimeout(() => toast.remove(), 6000)\n }\n\n const runClientSteps = (automation: ClientAutomation) => {\n for (const step of automation.steps) {\n try {\n if (\n step.type === 'addClass' ||\n step.type === 'removeClass' ||\n step.type === 'toggleClass'\n ) {\n // Expand the raw-id selector to also match the layout-composed\n // live id (AGL-573); non-leaf selectors are unchanged.\n const targets = document.querySelectorAll(\n Aglyn.expandLeafSelector(step.selector),\n )\n targets.forEach((element) => {\n if (step.type === 'addClass') {\n element.classList.add(step.className)\n } else if (step.type === 'removeClass') {\n element.classList.remove(step.className)\n } else {\n element.classList.toggle(step.className)\n }\n })\n } else if (\n step.type === 'setAttribute' ||\n step.type === 'removeAttribute'\n ) {\n /*\n The semantics half of a hand-built disclosure (AGL-2546).\n\n Deliberately in THIS loop rather than behind a guard of its own:\n it then inherits exactly the gating the visibility steps have,\n including which surfaces mount the runtime at all. A separate\n path reaching `document.querySelector` directly is how this\n would come to run somewhere `showElement` does not.\n\n The name is re-checked here and not only in the editor. The\n editor is a convenience; a step can reach this runtime from a\n document written before the allowlist existed, or by any route\n that does not pass through the console UI.\n\n A rejected name is a NO-OP, not a throw — the `catch` around\n this loop would otherwise let one bad attribute name silently\n drop every step after it in the same automation.\n */\n if (Aglyn.isInteractionAttributeAllowed(step.name)) {\n const name = step.name.trim().toLowerCase()\n const targets = document.querySelectorAll(\n Aglyn.expandLeafSelector(step.selector),\n )\n targets.forEach((element) => {\n if (step.type === 'setAttribute') {\n element.setAttribute(name, step.value ?? '')\n } else {\n element.removeAttribute(name)\n }\n })\n }\n } else if (step.type === 'scrollTo') {\n // One target, the first one on screen (AGL-2867). A target that\n // is missing, deleted or hidden makes the step a no-op, and the\n // steps after it in this automation still run.\n Aglyn.runScrollToStep(Aglyn.expandLeafSelector(step.selector), {\n behavior: step.behavior,\n offsetPx: step.offsetPx,\n })\n } else if (step.type === 'playVideo') {\n // The Video element's own poster press, sent to the element: the\n // player loads only now, exactly as it would for a click on the\n // poster, and under the same consent rules.\n Aglyn.runPlayVideoStep(Aglyn.expandLeafSelector(step.selector))\n } else if (step.type === 'stickyNav') {\n const target = document.querySelector(\n Aglyn.expandLeafSelector(step.selector?.trim() || 'header, nav'),\n )\n if (target instanceof HTMLElement) {\n target.style.position = 'sticky'\n target.style.top = '0'\n target.style.zIndex = '1100'\n }\n } else if (step.type === 'showHtml') {\n const container = document.createElement('div')\n // Sanitize (AGL-504): unlike runJs, showHtml is NOT dropped by the\n // JS entitlement gate, so raw innerHTML would let any automations-\n // tier author execute event-handler attributes (<img onerror>).\n //\n // ONE policy for the surface (AGL-2486). AGL-1901 moved rich text\n // and Custom HTML onto `sanitizeAuthorHtml`; this call was the\n // last raw DOMPurify left on a published page, and two sanitizers\n // with different rules on one surface is worse than the weaker of\n // them — a reviewer reads the strict one and assumes it covers\n // both. It did not: DOMPurify filters NO CSS, so every `style`\n // attribute arriving here reached the visitor unexamined while\n // the Custom HTML block beside it went through `sanitizeAuthorCss`.\n //\n // Nothing this used to refuse is now allowed. `sanitizeAuthorHtml`\n // is a strict SUBSET of the DOMPurify config it replaces, and that\n // is measured rather than asserted: `rich-text-hydration.spec.tsx`\n // holds this exact former config as `referenceShowHtmlPurify` and\n // runs the shared corpus through both. So the change is only in\n // what it ADDITIONALLY refuses:\n //\n // - `style` now gets the CSS rule — `http:` and unknown-scheme\n // `url()` neutered to `about:invalid`, and `@import`,\n // `expression()`, `behavior:` and `-moz-binding` dropping the\n // declaration whole. Character references are decoded BEFORE\n // the scheme is judged, which the old config did not do: it\n // emitted `url(&#104;ttp://…)` as a literal `http://`.\n // - `<form>` stops being an element. The former FORBID_TAGS here\n // listed `script, iframe, object, embed, base` and omitted\n // `form` — alone among this repo's author-HTML configs, both of\n // which forbade it — so a password field on the owner's live\n // page was one paste away.\n //\n // What is deliberately NOT refused, on either side of the change:\n // a third-party `https:` `url()`, and `position:fixed` / `z-index`.\n // The first is AGL-1725's actor analysis (the site owner chooses\n // recipients for their own visitors); the second is a capability\n // the Styles panel already gives the same author as a first-class\n // field, so refusing it only here would move nothing.\n container.innerHTML = Aglyn.sanitizeAuthorHtml(step.html)\n document.body.appendChild(container)\n } else if (step.type === 'runJs') {\n // Business-gated server-side (dropped from props otherwise);\n // the site owner's own code running on their own page.\n // eslint-disable-next-line no-new-func\n new Function(step.code)()\n } else if (step.type === 'redirect') {\n // Screen targets resolve through the routing map (AGL-339) so\n // slug renames never break the interaction; url is the manual\n // fallback.\n const screenSlug =\n (step as any).screenId != null\n ? screens?.[(step as any).screenId]\n : undefined\n const destination =\n screenSlug != null\n ? Aglyn.screenRoutePathToUrl(screenSlug)\n : step.url\n if (destination) window.location.assign(destination)\n } else if (\n step.type === 'showElement' ||\n step.type === 'hideElement' ||\n step.type === 'toggleElement'\n ) {\n // Element choreography (AGL-562): class-based so \"show\"\n // reveals targets the author started hidden. The tenant page\n // ships the hidden-class rule in its SSR HTML; ensure is the\n // fallback for other embeddings. Grace delays + Escape/\n // outside-click dismissal ride the same step (AGL-589).\n Aglyn.ensureElementHiddenStyle()\n Aglyn.runElementVisibilityStep(\n step.type === 'showElement'\n ? 'show'\n : step.type === 'hideElement'\n ? 'hide'\n : 'toggle',\n // Expand so a show/hide/toggle authored against the raw\n // canvas id still reaches the layout-composed node (AGL-573).\n Aglyn.expandLeafSelector(step.selector),\n {\n delayMs: (step as { delayMs?: number }).delayMs,\n dismissOn: (\n step as { dismissOn?: Aglyn.ElementDismissOption[] }\n ).dismissOn,\n },\n )\n } else if (\n step.type === 'openDrawer' ||\n step.type === 'closeDrawer' ||\n step.type === 'toggleDrawer'\n ) {\n // Drawer commands (AGL-562) ride the window event bus; the\n // muiDrawer element answers (first drawer for broadcasts).\n Aglyn.dispatchDrawerCommand(\n step.type === 'openDrawer'\n ? 'open'\n : step.type === 'closeDrawer'\n ? 'close'\n : 'toggle',\n step.drawerNodeId || undefined,\n )\n } else if (\n step.type === 'openMenu' ||\n step.type === 'closeMenu' ||\n step.type === 'toggleMenu'\n ) {\n // Menu commands (AGL-568) ride their own event bus like\n // drawers; the nav-menu elements answer (first menu for\n // broadcasts). A hover-enter trigger stamps the hover flag\n // so a menu opened this way closes itself when the pointer\n // leaves the trigger + panel surface.\n Aglyn.dispatchMenuCommand(\n step.type === 'openMenu'\n ? 'open'\n : step.type === 'closeMenu'\n ? 'close'\n : 'toggle',\n step.menuNodeId || undefined,\n { hover: automation.event === 'elementHoverEnter' },\n )\n } else if (step.type === 'trackGaEvent') {\n // AGL-1587: the name and the params are AUTHORED, which makes\n // this the least trustworthy analytics input in the repo — a\n // param could carry a form field's value. It goes through the\n // shared sanitizer and the reserved-name refusal like everything\n // else, never raw gtag.\n trackAuthoredEvent(step.eventName, step.params)\n } else if (step.type === 'siteAlert') {\n showToast(\n String(step.message ?? '').slice(0, 300),\n step.severity ?? 'info',\n )\n } else if (step.type === 'showOverlay') {\n if (step.overlayId) showOverlayRef.current(step.overlayId)\n }\n } catch (error) {\n console.error('automation step failed', error)\n }\n }\n }\n\n const fire = (automation: ClientAutomation) => {\n // Repeatable UI choreography (AGL-562): everyTime automations skip\n // the once-per-pageview gate (explicit caps below still apply).\n if (!automation.everyTime) {\n if (fired.has(automation.id)) return\n fired.add(automation.id)\n }\n // Once per visitor (AGL-266): a persisted flag outlives the pageview.\n if (automation.oncePerVisitor) {\n const key = `aglyn:auto:${automation.id}`\n try {\n if (localStorage.getItem(key)) return\n localStorage.setItem(key, '1')\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n } else if (automation.oncePerSession) {\n // Once per session (AGL-274): survives navigation, not the tab.\n const key = `aglyn:auto:${automation.id}`\n try {\n if (sessionStorage.getItem(key)) return\n sessionStorage.setItem(key, '1')\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n } else if (automation.cooldownMinutes) {\n // Cooldown (AGL-274): a timestamp gates re-fires for the visitor.\n const key = `aglyn:auto:${automation.id}:at`\n try {\n const last = Number(localStorage.getItem(key) ?? 0)\n if (\n last &&\n Date.now() - last < automation.cooldownMinutes * 60_000\n ) {\n return\n }\n localStorage.setItem(key, String(Date.now()))\n } catch {\n // Storage unavailable — degrade to once per pageview.\n }\n }\n runClientSteps(automation)\n if (automation.hasServerSteps) {\n void fetch('/api/events/dispatch', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n actionId: automation.id,\n event: automation.event,\n payload: { path: window.location.pathname },\n }),\n keepalive: true,\n }).catch(() => undefined)\n }\n }\n\n /**\n * Elements that arrive AFTER this effect binds (AGL-2512).\n *\n * `elementVisible` and `scrollToElement` are the only two triggers that\n * resolve their targets by querying the DOM — every other one listens on\n * `document` and so needs no element to exist yet. A single query at bind\n * time made them dead on the two pages where the tree lands late: a\n * deferred lazy panel patched back in on interaction (AGL-1285), and a\n * gated screen's tree swapped in once the visitor is past the gate\n * (AGL-2510).\n *\n * One MutationObserver for all of them, not one each, and it stops the\n * moment nothing is left watching — these triggers fire once per pageview\n * by construction, so a page whose targets have all been seen pays\n * nothing for the rest of the visit. A page with no such automation never\n * starts one at all.\n */\n const pendingObservers: Array<() => void> = []\n let domObserver: MutationObserver | null = null\n const rescan = () => {\n for (const attach of [...pendingObservers]) attach()\n if (!pendingObservers.length) {\n domObserver?.disconnect()\n domObserver = null\n }\n }\n const watchLateElements = (attach: () => void) => {\n pendingObservers.push(attach)\n if (domObserver || typeof MutationObserver === 'undefined') return\n domObserver = new MutationObserver(rescan)\n domObserver.observe(document.body, { childList: true, subtree: true })\n }\n const stopWatching = (attach: () => void) => {\n const index = pendingObservers.indexOf(attach)\n if (index >= 0) pendingObservers.splice(index, 1)\n if (!pendingObservers.length) {\n domObserver?.disconnect()\n domObserver = null\n }\n }\n cleanups.push(() => {\n pendingObservers.length = 0\n domObserver?.disconnect()\n domObserver = null\n })\n\n for (const automation of automations) {\n const { event, threshold } = automation\n // Composition namespaces a node's live `data-aglyn` id, but the\n // interaction builder records the RAW canvas id in the selector.\n // Expand it so the trigger still matches the live element — layouts\n // (AGL-573) and reusable-component grafts (AGL-1229), the latter being\n // why every interaction authored inside the Site nav bound to nothing.\n // Hand-typed CSS selectors pass through untouched.\n const selector = automation.selector\n ? Aglyn.expandLeafSelector(automation.selector)\n : automation.selector\n if (event === 'pageVisit') {\n fire(automation)\n } else if (event === 'timeOnPage') {\n const timer = setTimeout(\n () => fire(automation),\n Math.max(1, threshold ?? 5) * 1000,\n )\n cleanups.push(() => clearTimeout(timer))\n } else if (event === 'scrollDepth') {\n const onScroll = () => {\n const doc = document.documentElement\n const max = doc.scrollHeight - window.innerHeight\n const percent = max > 0 ? (window.scrollY / max) * 100 : 100\n if (percent >= Math.min(100, Math.max(1, threshold ?? 50))) {\n fire(automation)\n window.removeEventListener('scroll', onScroll)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanups.push(() => window.removeEventListener('scroll', onScroll))\n } else if (event === 'elementVisible' || event === 'scrollToElement') {\n if (!selector) continue\n let fired = false\n const observer = new IntersectionObserver((entries) => {\n if (fired || !entries.some((entry) => entry.isIntersecting)) return\n fired = true\n fire(automation)\n observer.disconnect()\n stopWatching(attachTargets)\n })\n // Re-entrant: called again on every DOM change until the trigger\n // fires, and observing an element twice is a no-op, so a rescan costs\n // one `querySelectorAll` and nothing else.\n const attachTargets = () => {\n if (fired) return stopWatching(attachTargets)\n document\n .querySelectorAll(selector)\n .forEach((target) => observer.observe(target))\n }\n attachTargets()\n watchLateElements(attachTargets)\n cleanups.push(() => observer.disconnect())\n } else if (event === 'elementClick') {\n if (!selector) continue\n const onClick = (mouseEvent: MouseEvent) => {\n const target = mouseEvent.target as Element | null\n if (target?.closest?.(selector)) fire(automation)\n }\n document.addEventListener('click', onClick, true)\n cleanups.push(() =>\n document.removeEventListener('click', onClick, true),\n )\n } else if (\n event === 'elementHoverEnter' ||\n event === 'elementHoverLeave'\n ) {\n // Hover choreography (AGL-562): delegated mouseover/mouseout with\n // enter/leave semantics — moves WITHIN the matched element (its\n // own children) never re-fire.\n if (!selector) continue\n const onHover = (mouseEvent: MouseEvent) => {\n const target = mouseEvent.target as Element | null\n const match = target?.closest?.(selector)\n if (!match) return\n const related = mouseEvent.relatedTarget as Element | null\n if (related && match.contains(related)) return\n fire(automation)\n }\n const type = event === 'elementHoverEnter' ? 'mouseover' : 'mouseout'\n document.addEventListener(type, onHover, true)\n cleanups.push(() =>\n document.removeEventListener(type, onHover, true),\n )\n } else if (event === 'exitIntent') {\n const onLeave = (mouseEvent: MouseEvent) => {\n if (mouseEvent.clientY <= 0) fire(automation)\n }\n document.addEventListener('mouseleave', onLeave)\n cleanups.push(() => document.removeEventListener('mouseleave', onLeave))\n }\n }\n return () => {\n for (const cleanup of cleanups) cleanup()\n }\n // Automations are static per pageview (ISR props).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n hostId,\n screens,\n // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(automations.map((automation) => automation.id)),\n ])\n\n return null\n}\n\nfunction AnnouncementBar(props: {\n bar: AnnouncementBarData\n hostId?: string\n}) {\n const { bar, hostId } = props\n const storageKey = `aglyn-abar-${bar.contentHash}`\n const [hidden, setHidden] = useState(true)\n useEffect(() => {\n try {\n setHidden(Boolean(window.localStorage.getItem(storageKey)))\n } catch {\n setHidden(false)\n }\n }, [storageKey])\n // Impression (AGL-271): once per pageview, only when actually shown.\n useEffect(() => {\n if (!hidden) sendOverlayBeacon(hostId, 'barImpression', bar.overlayId)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hidden])\n if (hidden) return null\n const style: CSSProperties = {\n position: 'relative',\n zIndex: 1300,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: '8px 40px 8px 16px',\n fontSize: 14,\n fontFamily: 'system-ui, sans-serif',\n textAlign: 'center',\n color: bar.textColor || '#fff',\n backgroundColor: bar.backgroundColor || '#111827',\n }\n const text = bar.href ? (\n <a\n href={bar.href}\n onClick={() => sendOverlayBeacon(hostId, 'barClick', bar.overlayId)}\n style={{ color: 'inherit', textDecoration: 'underline' }}\n >\n {bar.text}\n </a>\n ) : (\n <span>{bar.text}</span>\n )\n return (\n <div role=\"region\" aria-label=\"Announcement\" style={style}>\n {text}\n {bar.dismissible ? (\n <button\n type=\"button\"\n aria-label=\"Dismiss announcement\"\n onClick={() => {\n try {\n window.localStorage.setItem(storageKey, '1')\n } catch {\n // Storage may be unavailable (private mode); hide anyway.\n }\n sendOverlayBeacon(hostId, 'barDismiss', bar.overlayId)\n setHidden(true)\n }}\n style={{\n position: 'absolute',\n right: 8,\n top: '50%',\n transform: 'translateY(-50%)',\n border: 'none',\n background: 'transparent',\n color: 'inherit',\n fontSize: 16,\n lineHeight: 1,\n cursor: 'pointer',\n padding: 6,\n }}\n >\n {'✕'}\n </button>\n ) : null}\n </div>\n )\n}\n\n/**\n * Promotional popup (AGL-196). Client owns: schedule-window re-check (the\n * page is ISR-cached), trigger timing (delay/scroll/exit), and frequency\n * capping via a per-content-hash localStorage stamp (no cookies). ESC and\n * backdrop close; reduced-motion preferences skip the entrance ease.\n */\nfunction PopupOverlay(props: {\n popup: PopupData\n hostId?: string\n}) {\n const { popup, hostId } = props\n const storageKey = `aglyn-popup-${popup.contentHash}`\n const [open, setOpen] = useState(false)\n // Email capture (AGL-200): submits into the forms pipeline (inbox +\n // contacts); success suppresses the popup for ~10 years.\n const [email, setEmail] = useState('')\n // The honeypot's value, held in state so whatever a bot typed into the\n // hidden input below is what gets POSTed (AGL-1665). This used to be a\n // hardcoded `website: ''` in the request body: the route drops a\n // submission only when the field is NON-empty, so a constant empty string\n // never failed the check — it removed it. There was no field on the page\n // to fill and no value a script could set, which made the popup the one\n // form surface on the site with no honeypot at all.\n const [website, setWebsite] = useState('')\n const [submitted, setSubmitted] = useState(false)\n\n useEffect(() => {\n if (open) sendOverlayBeacon(hostId, 'popupImpression', popup.overlayId)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open, hostId])\n\n useEffect(() => {\n const now = Date.now()\n if (popup.startAtMs && now < popup.startAtMs) return\n if (popup.endAtMs && now > popup.endAtMs) return\n try {\n // The decision itself is a pure function in the model (AGL-2174) —\n // which store to read is the whole feature, and it has to agree with\n // what `close` writes.\n const suppressed = MarketingModel.popupSuppressed(\n popup,\n MarketingModel.popupCapStore(popup) === 'session'\n ? { sessionFlag: window.sessionStorage.getItem(storageKey) }\n : { lastShownMs: Number(window.localStorage.getItem(storageKey) ?? 0) },\n now,\n )\n if (suppressed) return\n } catch {\n // Storage unavailable: show at most per-pageview.\n }\n let cleanup: (() => void) | undefined\n if (popup.trigger === 'scroll') {\n const threshold = Math.min(100, Math.max(0, popup.triggerValue)) / 100\n const onScroll = () => {\n const height =\n document.documentElement.scrollHeight - window.innerHeight\n if (height <= 0 || window.scrollY / height >= threshold) {\n setOpen(true)\n }\n }\n window.addEventListener('scroll', onScroll, { passive: true })\n cleanup = () => window.removeEventListener('scroll', onScroll)\n } else if (popup.trigger === 'exit') {\n const onLeave = (event: MouseEvent) => {\n if (event.clientY <= 0) setOpen(true)\n }\n document.addEventListener('mouseout', onLeave)\n cleanup = () => document.removeEventListener('mouseout', onLeave)\n } else {\n const timer = window.setTimeout(\n () => setOpen(true),\n Math.max(0, popup.triggerValue) * 1000,\n )\n cleanup = () => window.clearTimeout(timer)\n }\n return cleanup\n }, [popup, storageKey])\n\n const close = (kind: 'popupDismiss' | 'popupClick' = 'popupDismiss') => {\n try {\n // Written to whichever store the cap READS (AGL-2174). Stamping\n // `localStorage` for a session-capped popup would leave a timestamp\n // nothing reads, outliving the cap it was meant to record.\n if (MarketingModel.popupCapStore(popup) === 'session') {\n window.sessionStorage.setItem(storageKey, '1')\n } else {\n window.localStorage.setItem(storageKey, String(Date.now()))\n }\n } catch {\n // Private mode etc. — closing still works for this pageview.\n }\n sendOverlayBeacon(hostId, kind, popup.overlayId)\n setOpen(false)\n }\n\n const handleEmailSubmit = async () => {\n const value = email.trim()\n if (!value || submitted) return\n try {\n const response = await fetch('/api/forms/submit', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n hostId,\n // The door this capture comes through (AGL-3029): the popup is a\n // Marketing element, so a site that switched Forms off still\n // collects the address it shows the popup for.\n door: 'popup',\n formName: 'Popup',\n fields: { email: value },\n path: window.location.pathname,\n // Submitted AS-IS (AGL-1665) — the point of a honeypot is that the\n // client never judges it. `libs/plugins/mui/.../form.tsx` reads its\n // own hidden `website` input off the FormData and forwards it the\n // same way; `/api/forms/submit` is the single place that decides.\n website,\n // The campaign this visitor came from, when they came from one. A\n // popup capture is often a site's highest-converting door, so it\n // reports its campaign for the same reason it reports its lead.\n ...utmTouchField(),\n }),\n })\n // The popup's email capture is a lead, and it reported none: an\n // announcement popup is often a site's highest-converting capture, and\n // the merchant saw the impression and the dismiss (`aglyn_overlay`) with\n // nothing in between. The generic form block has sent `generate_lead`\n // since AGL-1561; this door was simply never wired to it.\n //\n // Gated on `response.ok`, unlike the visitor-facing thank-you below.\n // The two disagree deliberately: a spam-refused or rate-limited capture\n // is still shown the thank-you — telling a real visitor to try again\n // after a honeypot verdict would leak the honeypot — but it is NOT a\n // lead, and counting it would inflate the only number the merchant uses\n // to judge whether the popup is worth interrupting people with.\n //\n // `form_name` is the block's own name, matching the `formName` on the\n // wire; the address the visitor just typed never leaves this function.\n if (response.ok) {\n trackEvent('generate_lead', {\n form_name: 'Popup',\n form_location: window.location.pathname,\n })\n }\n } catch {\n // Best-effort — still thank the visitor.\n }\n setSubmitted(true)\n try {\n // Far-future stamp: a successful capture never re-prompts.\n window.localStorage.setItem(\n storageKey,\n String(Date.now() + 315360000000),\n )\n } catch {\n // Ignore.\n }\n }\n\n useEffect(() => {\n if (!open) return\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n if (!open) return null\n return (\n <div\n onClick={() => close()}\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 2147483200,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n padding: 16,\n }}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={popup.headline || 'Announcement'}\n onClick={(event) => event.stopPropagation()}\n style={{\n maxWidth: 420,\n width: '100%',\n background: '#fff',\n color: '#111827',\n borderRadius: 12,\n overflow: 'hidden',\n boxShadow: '0 24px 64px rgba(0, 0, 0, 0.35)',\n fontFamily: 'system-ui, sans-serif',\n position: 'relative',\n }}\n >\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={() => close()}\n style={{\n position: 'absolute',\n top: 8,\n right: 8,\n border: 'none',\n background: 'rgba(255, 255, 255, 0.85)',\n borderRadius: '50%',\n width: 28,\n height: 28,\n cursor: 'pointer',\n fontSize: 14,\n lineHeight: 1,\n }}\n >\n {'✕'}\n </button>\n {/* The popup image is a free-text console field rendered verbatim —\n one of AGL-1725's raw author sinks. Scheme rule only, never a\n host check: `http:` and unknown schemes render nothing;\n https/relative (the media picker's forms) render as stored,\n except a library file's Storage URL, which the resolver routes\n through the site's CDN like every other image (AGL-3506). */}\n {popup.imageUrl && !Aglyn.isRefusedAuthorImageSrc(popup.imageUrl) ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={Aglyn.siteRelativeMediaSrc(popup.imageUrl, { hostId })}\n // AGL-1896. This was a hardcoded `alt=\"\"` with no field behind\n // it. Still empty when the author left it empty — a decorative\n // banner beside its own headline is the case `alt=\"\"` exists for\n // — but it is now their choice rather than ours, and picking the\n // image from the library fills it in from the asset.\n alt={popup.imageAlt ?? ''}\n style={{\n width: '100%',\n maxHeight: 200,\n objectFit: 'cover',\n display: 'block',\n }}\n />\n ) : null}\n <div style={{ padding: 24, textAlign: 'center' }}>\n {popup.headline ? (\n <h2 style={{ margin: '0 0 8px', fontSize: 20 }}>\n {popup.headline}\n </h2>\n ) : null}\n <p style={{ margin: 0, fontSize: 14, whiteSpace: 'pre-wrap' }}>\n {popup.body}\n </p>\n {popup.collectEmail ? (\n <div style={{ marginTop: 16 }}>\n {submitted ? (\n <p style={{ margin: 0, fontSize: 14, fontWeight: 600 }}>\n {'Thanks — you are on the list!'}\n </p>\n ) : (\n <form\n onSubmit={(event) => {\n event.preventDefault()\n void handleEmailSubmit()\n }}\n style={{ display: 'flex', gap: 8, justifyContent: 'center' }}\n >\n <input\n type=\"email\"\n required\n placeholder=\"you@example.com\"\n // Same nameless-input defect as the newsletter block\n // (AGL-2392). A popup is modal-ish and arrives unbidden,\n // so a screen-reader user meets this field with no\n // surrounding context at all.\n aria-label=\"Email address\"\n value={email}\n onChange={(event) => setEmail(event.target.value)}\n style={{\n flex: 1,\n maxWidth: 240,\n padding: '8px 12px',\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n }}\n />\n {/* Honeypot: humans never see or fill this (AGL-1665).\n Off-screen rather than `display:none`/`hidden`, and\n named `website`, so the naive form-filling bots the\n route's check is aimed at treat it as an ordinary\n field — the same bait, presented the same way, as the\n site form's. Out of flow, so the flex row above is\n unchanged. */}\n <input\n type=\"text\"\n name=\"website\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={website}\n onChange={(event) => setWebsite(event.target.value)}\n style={{\n position: 'absolute',\n left: '-5000px',\n height: 0,\n width: 0,\n }}\n />\n <button\n type=\"submit\"\n style={{\n padding: '8px 16px',\n borderRadius: 8,\n border: 'none',\n background: '#111827',\n color: '#fff',\n fontSize: 14,\n cursor: 'pointer',\n }}\n >\n {'Sign up'}\n </button>\n </form>\n )}\n </div>\n ) : null}\n {popup.ctaHref && popup.ctaLabel ? (\n <a\n href={popup.ctaHref}\n onClick={() => close('popupClick')}\n style={{\n display: 'inline-block',\n marginTop: 16,\n padding: '10px 24px',\n borderRadius: 8,\n background: '#111827',\n color: '#fff',\n textDecoration: 'none',\n fontSize: 14,\n }}\n >\n {popup.ctaLabel}\n </a>\n ) : null}\n </div>\n </div>\n </div>\n )\n}\n\n\n/** The page-props slice the server enricher writes for a page filed under a campaign. */\nexport interface CampaignPageData {\n screenId: string\n campaignIds: string[]\n}\n\n/**\n * Pageviews already reported to their campaigns, keyed by host and address.\n * Module scope for the reason the pageview beacon's guard is: a page remounts\n * on its own, and a remount is not a second visit.\n */\nconst campaignVisitsReported = new Set<string>()\n\n/**\n * How long the visit report waits for the visitor's storage consent to\n * settle before it reports the view alone. Long enough for the region check\n * a consent posture runs on load; short enough that a stalled one still\n * counts the page view.\n */\nconst CAMPAIGN_VISIT_CONSENT_WAIT_MS = 10_000\n\n/**\n * A PAGE FILED UNDER A CAMPAIGN IS A CAMPAIGN TOUCH (AGL-3461).\n *\n * On every pageview this tells the core which campaigns the page is filed\n * under — the touch every conversion door on the page then reports, live and\n * with nothing written, and the one the device remembers under the visitor's\n * analytics grant (`utm-touch.ts`). A page filed under nothing clears the\n * live touch and keeps the remembered one.\n *\n * And it reports the visit to each campaign through the site collector's\n * `campaignVisit` beacon: a view of the campaign's page, and — when this is\n * the device's first campaign touch in the window — a first visit. A link\n * carrying a `utm_campaign` label is a touch too, credited as a first visit\n * to the campaign that declares it; the server answers which one. The\n * first-touch claim waits for consent to settle, because asked before it an\n * unresolved state would read as \"may not remember\", and the view would be\n * counted as nobody's first.\n *\n * Renders nothing.\n */\nfunction CampaignPageTouch(props: {\n hostId?: string\n campaignPage: CampaignPageData | null\n}) {\n const { hostId, campaignPage } = props\n const screenId = campaignPage?.screenId ?? ''\n const idsKey = (campaignPage?.campaignIds ?? []).join(',')\n\n useEffect(() => {\n if (typeof window === 'undefined') return undefined\n const ids = idsKey ? idsKey.split(',') : []\n notePageCampaigns(\n ids.length ? { screenId, containerIds: ids, path: window.location.pathname } : null,\n )\n if (!hostId) return undefined\n const label = (new URLSearchParams(window.location.search).get('utm_campaign') ?? '')\n .trim()\n .toLowerCase()\n .slice(0, 100)\n if (!ids.length && !label) return undefined\n const visitKey = `${hostId}\\x00${window.location.pathname}${window.location.search}`\n if (campaignVisitsReported.has(visitKey)) return undefined\n\n let done = false\n const report = (allowed: boolean) => {\n if (done) return\n done = true\n campaignVisitsReported.add(visitKey)\n const claimed = allowed\n ? claimFirstCampaignTouch([\n ...ids.map((id) => `c:${id}`),\n ...(label ? [`u:${label}`] : []),\n ])\n : []\n const first = claimed.filter((key) => key.startsWith('c:')).map((key) => key.slice(2))\n const firstLabel = Boolean(label) && claimed.includes(`u:${label}`)\n // A label arrival on a page filed under nothing is only a first visit;\n // with nothing first about it there is nothing to count.\n if (!ids.length && !firstLabel) return\n sendAnalyticsBeacon({\n hostId,\n campaignVisit: '1',\n ...(ids.length ? { screenId, campaignIds: ids } : {}),\n ...(first.length ? { first } : {}),\n ...(firstLabel ? { utmCampaign: label, firstLabel: true } : {}),\n })\n }\n const withdraw = whenUtmTouchConsentSettles(report)\n const timer = window.setTimeout(() => {\n withdraw()\n report(false)\n }, CAMPAIGN_VISIT_CONSENT_WAIT_MS)\n return () => {\n withdraw()\n window.clearTimeout(timer)\n }\n }, [hostId, screenId, idsKey])\n\n return null\n}\n\n/**\n * The marketing plugin's site runtime (AGL-419), relocated verbatim from\n * the tenant catch-all: announcement bar + popup rendering (AGL-195/200),\n * the experiments runner (AGL-253), the site-event automations engine\n * (AGL-256/257), and automation-triggered overlays. Reads back exactly the\n * page-props slices its server enricher wrote (site-contract shapes).\n */\nexport function MarketingSiteRuntime({ hostId, screens, page }: SiteRuntimeProps) {\n const [automationOverlay, setAutomationOverlay] = useState<any>(null)\n const announcementBar = page['announcementBar'] as AnnouncementBarData | null\n const popup = page['popup'] as PopupData | null\n const experiments = (page['experiments'] ?? []) as ScreenExperiment[]\n const clientAutomations = (page['clientAutomations'] ?? []) as ClientAutomation[]\n const automationOverlays = page['automationOverlays'] as Record<string, any> | null\n\n const campaignPage = (page['campaignPage'] ?? null) as CampaignPageData | null\n\n return (\n <>\n {/* A page filed under a campaign is a campaign touch (AGL-3461). */}\n <CampaignPageTouch hostId={hostId} campaignPage={campaignPage} />\n {announcementBar ? (\n <AnnouncementBar bar={announcementBar} hostId={hostId} />\n ) : null}\n {popup ? <PopupOverlay popup={popup} hostId={hostId} /> : null}\n {/* Screen/section experiments (AGL-253). */}\n {experiments.length ? (\n <ExperimentsRunner\n hostId={hostId}\n experiments={experiments}\n consentHost={page['data']?.host as Aglyn.VisitorConsentHost | null}\n />\n ) : null}\n {/* Site-event automations (AGL-256/257). */}\n {clientAutomations.length ? (\n <AutomationsEngine\n hostId={hostId}\n automations={clientAutomations}\n screens={screens}\n onShowOverlay={(overlayId) => {\n const overlay = automationOverlays?.[overlayId]\n if (overlay) setAutomationOverlay({ id: overlayId, ...overlay })\n }}\n />\n ) : null}\n {automationOverlay?.kind === 'bar' && automationOverlay.bar?.text ? (\n <AnnouncementBar\n bar={{\n ...automationOverlay.bar,\n text: String(automationOverlay.bar.text),\n dismissible: automationOverlay.bar.dismissible !== false,\n contentHash: `automation-${automationOverlay.id}`,\n }}\n hostId={hostId}\n />\n ) : null}\n {automationOverlay?.kind === 'popup' && automationOverlay.popup?.body ? (\n <PopupOverlay\n popup={{\n ...automationOverlay.popup,\n body: String(automationOverlay.popup.body),\n trigger: 'delay',\n triggerValue: 0,\n frequencyDays: Math.max(\n 1,\n Number(automationOverlay.popup.frequencyDays ?? 1),\n ),\n contentHash: `automation-${automationOverlay.id}`,\n }}\n hostId={hostId}\n />\n ) : null}\n </>\n )\n}\n"],"names":["Aglyn","sendAnalyticsBeacon","trackAuthoredEvent","trackEvent","claimFirstCampaignTouch","notePageCampaigns","utmTouchField","whenUtmTouchConsentSettles","useEffect","useRef","useState","MarketingModel","sendOverlayBeacon","hostId","overlay","overlayId","overlay_action","overlay_id","ExperimentsRunner","props","experiments","consentHost","experiment","length","undefined","persistence","resolveVisitorIdPersistence","readStoredVisitorConsent","visitorId","storage","localStorage","sessionStorage","getItem","VISITOR_ID_STORAGE_KEY","Math","random","toString","slice","Date","now","setItem","removeItem","variant","assignExperimentVariant","status","variants","winnerVariantId","endAtMs","id","payload","payloads","canvas","setNodes","beacon","kind","fetch","method","headers","body","JSON","stringify","experimentId","variantId","keepalive","catch","experiment_id","variant_id","experiment_action","cleanups","converted","convert","goal","event","onSubmit","document","addEventListener","push","removeEventListener","selector","filter","trim","onClick","target","closest","onScroll","doc","documentElement","max","scrollHeight","window","innerHeight","scrollY","passive","timer","setTimeout","clearTimeout","cleanup","AutomationsEngine","automations","screens","onShowOverlay","showOverlayRef","current","fired","Set","showToast","message","severity","toast","createElement","textContent","setAttribute","Object","assign","style","position","bottom","left","transform","zIndex","padding","borderRadius","fontSize","fontFamily","color","backgroundColor","maxWidth","appendChild","remove","runClientSteps","automation","step","steps","type","targets","querySelectorAll","expandLeafSelector","forEach","element","classList","add","className","toggle","isInteractionAttributeAllowed","name","toLowerCase","value","removeAttribute","runScrollToStep","behavior","offsetPx","runPlayVideoStep","querySelector","HTMLElement","top","container","innerHTML","sanitizeAuthorHtml","html","Function","code","screenSlug","screenId","destination","screenRoutePathToUrl","url","location","ensureElementHiddenStyle","runElementVisibilityStep","delayMs","dismissOn","dispatchDrawerCommand","drawerNodeId","dispatchMenuCommand","menuNodeId","hover","eventName","params","String","error","console","fire","everyTime","has","oncePerVisitor","key","oncePerSession","cooldownMinutes","last","Number","hasServerSteps","actionId","path","pathname","pendingObservers","domObserver","rescan","attach","disconnect","watchLateElements","MutationObserver","observe","childList","subtree","stopWatching","index","indexOf","splice","threshold","percent","min","observer","IntersectionObserver","entries","some","entry","isIntersecting","attachTargets","mouseEvent","onHover","match","related","relatedTarget","contains","onLeave","clientY","map","AnnouncementBar","bar","storageKey","contentHash","hidden","setHidden","Boolean","display","alignItems","justifyContent","gap","textAlign","textColor","text","href","a","textDecoration","span","div","role","aria-label","dismissible","button","right","border","background","lineHeight","cursor","PopupOverlay","popup","open","setOpen","email","setEmail","website","setWebsite","submitted","setSubmitted","startAtMs","suppressed","popupSuppressed","popupCapStore","sessionFlag","lastShownMs","trigger","triggerValue","height","close","handleEmailSubmit","response","door","formName","fields","ok","form_name","form_location","onKey","inset","aria-modal","headline","stopPropagation","width","overflow","boxShadow","imageUrl","isRefusedAuthorImageSrc","img","src","siteRelativeMediaSrc","alt","imageAlt","maxHeight","objectFit","h2","margin","p","whiteSpace","collectEmail","marginTop","fontWeight","form","preventDefault","input","required","placeholder","onChange","flex","tabIndex","autoComplete","aria-hidden","ctaHref","ctaLabel","campaignVisitsReported","CAMPAIGN_VISIT_CONSENT_WAIT_MS","CampaignPageTouch","campaignPage","idsKey","campaignIds","join","ids","split","containerIds","label","URLSearchParams","search","get","visitKey","done","report","allowed","claimed","first","startsWith","firstLabel","includes","campaignVisit","utmCampaign","withdraw","MarketingSiteRuntime","page","automationOverlay","setAutomationOverlay","announcementBar","clientAutomations","automationOverlays","host","frequencyDays"],"mappings":"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"}
@@ -71,6 +71,17 @@ import { MARKETING_OPERATOR_ALERTS } from "./constants/operator-alerts.js";
71
71
  }, {
72
72
  pluginId: BUNDLE_ID
73
73
  });
74
+ // A visitor reaching a campaign — a page filed under it, or a link carrying
75
+ // a label it declares — counted under the campaign (AGL-3461).
76
+ registerPluginSiteBeacon({
77
+ field: 'campaignVisit',
78
+ async count (request) {
79
+ const { countCampaignVisitBeacon } = await import("./server/campaign-visit-beacon.js");
80
+ await countCampaignVisitBeacon(request);
81
+ }
82
+ }, {
83
+ pluginId: BUNDLE_ID
84
+ });
74
85
  registerPluginConversionCreditor(lazyConversionCreditor(), {
75
86
  pluginId: BUNDLE_ID
76
87
  });
@@ -102,7 +113,12 @@ import { MARKETING_OPERATOR_ALERTS } from "./constants/operator-alerts.js";
102
113
  reverseOrder: async (request)=>(await load()).reverseOrder(request),
103
114
  recordClick: async (click)=>(await load()).recordClick(click),
104
115
  creditOutcome: async (request)=>(await load()).creditOutcome(request),
105
- erasePerson: async (key)=>(await load()).erasePerson(key)
116
+ erasePerson: async (key)=>(await load()).erasePerson(key),
117
+ describeConversion: async (request)=>{
118
+ var _ref;
119
+ var _describeConversion, _this;
120
+ return (_ref = (_describeConversion = (_this = await load()).describeConversion) == null ? void 0 : _describeConversion.call(_this, request)) != null ? _ref : null;
121
+ }
106
122
  };
107
123
  }
108
124
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/plugins/marketing/src/lib/declarations.server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// The seam from its own module, not the plugin-manager barrel: boot needs the\n// registry and nothing else, and the barrel reaches the client contexts.\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport {\n registerPluginConversionCreditor,\n type PluginConversionCreditor,\n} from '@aglyn/aglyn/plugin-manager/plugin-conversion-credit'\nimport { registerPluginSendTally } from '@aglyn/aglyn/plugin-manager/plugin-send-tallies'\nimport { registerPluginRecordIndex } from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { registerPluginSiteBeacon } from '@aglyn/aglyn/plugin-manager/plugin-site-beacons'\nimport { registerPluginTransferResource } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport {\n CAMPAIGN_PACKAGE_RULES,\n CAMPAIGNS_TRANSFER_KEY,\n campaignDependencies,\n campaignPackageContent,\n remapCampaignIds,\n} from './transfer/campaigns-package'\n\n/** The campaigns package's server half (AGL-3535), loaded when an import or export first asks. */\nconst campaignsPackage = async () => (await import('./transfer/campaigns-package.server')).createCampaignsPackage()\nimport { MARKETING_OPERATOR_ALERTS } from './constants/operator-alerts'\n\n/**\n * The marketing plugin's server declarations: the light registrations core\n * reads at boot, before any surface loads — its operator alerts (AGL-3377),\n * so Staff → Operator alerts lists them before the first one is raised, and\n * its overlay beacons, which the site collector hands it on any published\n * page. The counting code and the Admin SDK load with the first beacon.\n *\n * And the conversion creditor (`plugin-conversion-credit`): every door that\n * produces an outcome — a form, a booking, a sign-up, an order, a sequence's\n * mail — asks it which campaign to credit, in any process, before any of\n * this plugin's surfaces has loaded. The joins load with the first credit.\n * Beside it, the tally the site's unsubscribe page tells when a recipient\n * leaves from a campaign send's mail (`plugin-send-tallies`), and the\n * `emailSend` record index another plugin names a send by — a person's\n * timeline listing the campaign mail they were sent (`plugin-record-index`).\n */\nexport function registerMarketingServerDeclarations(): void {\n // Campaigns in a workspace package (AGL-3535).\n registerPluginTransferResource(\n CAMPAIGNS_TRANSFER_KEY,\n {\n items: async (ctx) => (await campaignsPackage()).items(ctx),\n dependencies: (item) => campaignDependencies(campaignPackageContent(item)),\n remapIds: (item, idMap) => remapCampaignIds(campaignPackageContent(item), idMap),\n readItems: async (ctx, ids) => (await campaignsPackage()).readItems(ctx, ids),\n writeItems: async (ctx, items, writer) => (await campaignsPackage()).writeItems(ctx, items as never, writer),\n revertItems: async (ctx, steps) => (await campaignsPackage()).revertItems(ctx, steps as never),\n problems: async (ctx, write) => (await campaignsPackage()).problems(ctx, write as never),\n referenceTargets: async (ctx, kinds) => (await campaignsPackage()).referenceTargets(ctx, kinds),\n rules: CAMPAIGN_PACKAGE_RULES,\n },\n { pluginId: BUNDLE_ID },\n )\n registerOperatorAlerts(MARKETING_OPERATOR_ALERTS, { pluginId: BUNDLE_ID })\n registerPluginSiteBeacon(\n {\n field: 'overlay',\n // The plugin's own module, which brings the Admin SDK with it: a lazy\n // import of the data layer from here would make every static import of\n // it in this plugin, and in each app that loads these declarations, a\n // static import of a library loaded lazily.\n async count(request) {\n const { countOverlayBeaconOnPlatform } = await import('./server/overlay-beacon')\n await countOverlayBeaconOnPlatform(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginConversionCreditor(lazyConversionCreditor(), { pluginId: BUNDLE_ID })\n registerPluginSendTally(\n {\n async unsubscribed(request) {\n const { countCampaignSendUnsubscribe } = await import('./server/send-tally')\n return countCampaignSendUnsubscribe(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginRecordIndex(\n 'emailSend',\n {\n list: async (request) => (await import('./server/email-send-record-index')).emailSendRecordIndex.list(request),\n get: async (request) => (await import('./server/email-send-record-index')).emailSendRecordIndex.get(request),\n },\n { pluginId: BUNDLE_ID },\n )\n}\n\n/**\n * The creditor, its module loaded on the first call: the plugin's own module,\n * which brings the data layer with it, for the reason the beacon's counter\n * is loaded that way.\n */\nfunction lazyConversionCreditor(): PluginConversionCreditor {\n const load = async () => (await import('./server/conversion-creditor')).marketingConversionCreditor\n return {\n resolveTouch: async (request) => (await load()).resolveTouch(request),\n creditConversion: async (request) => (await load()).creditConversion(request),\n creditOrder: async (request) => (await load()).creditOrder(request),\n reverseOrder: async (request) => (await load()).reverseOrder(request),\n recordClick: async (click) => (await load()).recordClick(click),\n creditOutcome: async (request) => (await load()).creditOutcome(request),\n erasePerson: async (key) => (await load()).erasePerson(key),\n }\n}\n"],"names":["registerOperatorAlerts","registerPluginConversionCreditor","registerPluginSendTally","registerPluginRecordIndex","registerPluginSiteBeacon","registerPluginTransferResource","BUNDLE_ID","CAMPAIGN_PACKAGE_RULES","CAMPAIGNS_TRANSFER_KEY","campaignDependencies","campaignPackageContent","remapCampaignIds","campaignsPackage","createCampaignsPackage","MARKETING_OPERATOR_ALERTS","registerMarketingServerDeclarations","items","ctx","dependencies","item","remapIds","idMap","readItems","ids","writeItems","writer","revertItems","steps","problems","write","referenceTargets","kinds","rules","pluginId","field","count","request","countOverlayBeaconOnPlatform","lazyConversionCreditor","unsubscribed","countCampaignSendUnsubscribe","list","emailSendRecordIndex","get","load","marketingConversionCreditor","resolveTouch","creditConversion","creditOrder","reverseOrder","recordClick","click","creditOutcome","erasePerson","key"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/plugins/marketing/src/lib/declarations.server.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n// The seam from its own module, not the plugin-manager barrel: boot needs the\n// registry and nothing else, and the barrel reaches the client contexts.\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport {\n registerPluginConversionCreditor,\n type PluginConversionCreditor,\n} from '@aglyn/aglyn/plugin-manager/plugin-conversion-credit'\nimport { registerPluginSendTally } from '@aglyn/aglyn/plugin-manager/plugin-send-tallies'\nimport { registerPluginRecordIndex } from '@aglyn/aglyn/plugin-manager/plugin-record-index'\nimport { registerPluginSiteBeacon } from '@aglyn/aglyn/plugin-manager/plugin-site-beacons'\nimport { registerPluginTransferResource } from '@aglyn/aglyn/plugin-manager/plugin-transfer-resources'\nimport { BUNDLE_ID } from './constants/bundle-common'\nimport {\n CAMPAIGN_PACKAGE_RULES,\n CAMPAIGNS_TRANSFER_KEY,\n campaignDependencies,\n campaignPackageContent,\n remapCampaignIds,\n} from './transfer/campaigns-package'\n\n/** The campaigns package's server half (AGL-3535), loaded when an import or export first asks. */\nconst campaignsPackage = async () => (await import('./transfer/campaigns-package.server')).createCampaignsPackage()\nimport { MARKETING_OPERATOR_ALERTS } from './constants/operator-alerts'\n\n/**\n * The marketing plugin's server declarations: the light registrations core\n * reads at boot, before any surface loads — its operator alerts (AGL-3377),\n * so Staff → Operator alerts lists them before the first one is raised, and\n * its overlay beacons, which the site collector hands it on any published\n * page. The counting code and the Admin SDK load with the first beacon.\n *\n * And the conversion creditor (`plugin-conversion-credit`): every door that\n * produces an outcome — a form, a booking, a sign-up, an order, a sequence's\n * mail — asks it which campaign to credit, in any process, before any of\n * this plugin's surfaces has loaded. The joins load with the first credit.\n * Beside it, the tally the site's unsubscribe page tells when a recipient\n * leaves from a campaign send's mail (`plugin-send-tallies`), and the\n * `emailSend` record index another plugin names a send by — a person's\n * timeline listing the campaign mail they were sent (`plugin-record-index`).\n */\nexport function registerMarketingServerDeclarations(): void {\n // Campaigns in a workspace package (AGL-3535).\n registerPluginTransferResource(\n CAMPAIGNS_TRANSFER_KEY,\n {\n items: async (ctx) => (await campaignsPackage()).items(ctx),\n dependencies: (item) => campaignDependencies(campaignPackageContent(item)),\n remapIds: (item, idMap) => remapCampaignIds(campaignPackageContent(item), idMap),\n readItems: async (ctx, ids) => (await campaignsPackage()).readItems(ctx, ids),\n writeItems: async (ctx, items, writer) => (await campaignsPackage()).writeItems(ctx, items as never, writer),\n revertItems: async (ctx, steps) => (await campaignsPackage()).revertItems(ctx, steps as never),\n problems: async (ctx, write) => (await campaignsPackage()).problems(ctx, write as never),\n referenceTargets: async (ctx, kinds) => (await campaignsPackage()).referenceTargets(ctx, kinds),\n rules: CAMPAIGN_PACKAGE_RULES,\n },\n { pluginId: BUNDLE_ID },\n )\n registerOperatorAlerts(MARKETING_OPERATOR_ALERTS, { pluginId: BUNDLE_ID })\n registerPluginSiteBeacon(\n {\n field: 'overlay',\n // The plugin's own module, which brings the Admin SDK with it: a lazy\n // import of the data layer from here would make every static import of\n // it in this plugin, and in each app that loads these declarations, a\n // static import of a library loaded lazily.\n async count(request) {\n const { countOverlayBeaconOnPlatform } = await import('./server/overlay-beacon')\n await countOverlayBeaconOnPlatform(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n // A visitor reaching a campaign — a page filed under it, or a link carrying\n // a label it declares — counted under the campaign (AGL-3461).\n registerPluginSiteBeacon(\n {\n field: 'campaignVisit',\n async count(request) {\n const { countCampaignVisitBeacon } = await import('./server/campaign-visit-beacon')\n await countCampaignVisitBeacon(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginConversionCreditor(lazyConversionCreditor(), { pluginId: BUNDLE_ID })\n registerPluginSendTally(\n {\n async unsubscribed(request) {\n const { countCampaignSendUnsubscribe } = await import('./server/send-tally')\n return countCampaignSendUnsubscribe(request)\n },\n },\n { pluginId: BUNDLE_ID },\n )\n registerPluginRecordIndex(\n 'emailSend',\n {\n list: async (request) => (await import('./server/email-send-record-index')).emailSendRecordIndex.list(request),\n get: async (request) => (await import('./server/email-send-record-index')).emailSendRecordIndex.get(request),\n },\n { pluginId: BUNDLE_ID },\n )\n}\n\n/**\n * The creditor, its module loaded on the first call: the plugin's own module,\n * which brings the data layer with it, for the reason the beacon's counter\n * is loaded that way.\n */\nfunction lazyConversionCreditor(): PluginConversionCreditor {\n const load = async () => (await import('./server/conversion-creditor')).marketingConversionCreditor\n return {\n resolveTouch: async (request) => (await load()).resolveTouch(request),\n creditConversion: async (request) => (await load()).creditConversion(request),\n creditOrder: async (request) => (await load()).creditOrder(request),\n reverseOrder: async (request) => (await load()).reverseOrder(request),\n recordClick: async (click) => (await load()).recordClick(click),\n creditOutcome: async (request) => (await load()).creditOutcome(request),\n erasePerson: async (key) => (await load()).erasePerson(key),\n describeConversion: async (request) =>\n (await load()).describeConversion?.(request) ?? null,\n }\n}\n"],"names":["registerOperatorAlerts","registerPluginConversionCreditor","registerPluginSendTally","registerPluginRecordIndex","registerPluginSiteBeacon","registerPluginTransferResource","BUNDLE_ID","CAMPAIGN_PACKAGE_RULES","CAMPAIGNS_TRANSFER_KEY","campaignDependencies","campaignPackageContent","remapCampaignIds","campaignsPackage","createCampaignsPackage","MARKETING_OPERATOR_ALERTS","registerMarketingServerDeclarations","items","ctx","dependencies","item","remapIds","idMap","readItems","ids","writeItems","writer","revertItems","steps","problems","write","referenceTargets","kinds","rules","pluginId","field","count","request","countOverlayBeaconOnPlatform","countCampaignVisitBeacon","lazyConversionCreditor","unsubscribed","countCampaignSendUnsubscribe","list","emailSendRecordIndex","get","load","marketingConversionCreditor","resolveTouch","creditConversion","creditOrder","reverseOrder","recordClick","click","creditOutcome","erasePerson","key","describeConversion"],"mappings":"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"}
@@ -169,10 +169,38 @@ export interface EmailCampaign {
169
169
  * in every email either way.
170
170
  */
171
171
  listUnsubscribe?: boolean;
172
+ /**
173
+ * The `utm_campaign` labels that mean this campaign (AGL-3461), stored as
174
+ * {@link campaignUtmLabels} normalizes them. A visitor who arrives on a
175
+ * link carrying one is credited to this campaign, as a visitor who reads a
176
+ * page filed under it is. Read it through {@link campaignUtmLabels}.
177
+ */
178
+ utmCampaigns?: string[];
172
179
  createdAtMs?: number;
173
180
  createdBy?: string;
174
181
  deletedAt?: unknown;
175
182
  }
183
+ /**
184
+ * How many `utm_campaign` labels one campaign may answer to. A ceiling on the
185
+ * field, so an `array-contains` lookup stays one cheap index entry per label.
186
+ */
187
+ export declare const CAMPAIGN_UTM_LABELS_MAX = 20;
188
+ /**
189
+ * One `utm_campaign` label as it is stored and looked up: trimmed, lowercase,
190
+ * at most 100 characters (the length the label parser keeps).
191
+ *
192
+ * Lowercase because the same push is routinely tagged `OneJob-AI` in one ad
193
+ * and `onejob-ai` in the next, and a match that told them apart would leave
194
+ * half a campaign's arrivals on a label nobody looks at. Empty for a value
195
+ * that is not a label at all.
196
+ */
197
+ export declare function normalizeCampaignUtmLabel(raw: unknown): string;
198
+ /**
199
+ * A campaign's `utm_campaign` labels as a clean list: normalized, deduped,
200
+ * capped. Accepts the stored array or a comma- or newline-separated string,
201
+ * which is how the edit drawer collects them.
202
+ */
203
+ export declare function campaignUtmLabels(raw: unknown): string[];
176
204
  /**
177
205
  * Whether a campaign's emails carry the mail-client unsubscribe button:
178
206
  * the shared reader sequences use, with a campaign's default of ON.
@@ -157,6 +157,40 @@ import { CAMPAIGN_SEQUENCE_REPORTS_COLLECTION } from "./campaign-report.js";
157
157
  * id — it is what `cid` carries and what the report route addresses — and one
158
158
  * word meaning both would be read into the other on the first edit.
159
159
  */ export const CAMPAIGN_SEND_CONTAINER_FIELD = 'emailCampaignId';
160
+ /**
161
+ * How many `utm_campaign` labels one campaign may answer to. A ceiling on the
162
+ * field, so an `array-contains` lookup stays one cheap index entry per label.
163
+ */ export const CAMPAIGN_UTM_LABELS_MAX = 20;
164
+ /**
165
+ * One `utm_campaign` label as it is stored and looked up: trimmed, lowercase,
166
+ * at most 100 characters (the length the label parser keeps).
167
+ *
168
+ * Lowercase because the same push is routinely tagged `OneJob-AI` in one ad
169
+ * and `onejob-ai` in the next, and a match that told them apart would leave
170
+ * half a campaign's arrivals on a label nobody looks at. Empty for a value
171
+ * that is not a label at all.
172
+ */ export function normalizeCampaignUtmLabel(raw) {
173
+ if (typeof raw !== 'string') return '';
174
+ const label = raw.trim().toLowerCase().slice(0, 100);
175
+ // An address is never a campaign label — the label parser refuses one too.
176
+ if (!label || /[^\s@]+@[^\s@]+\.[^\s@]+/.test(label)) return '';
177
+ return label;
178
+ }
179
+ /**
180
+ * A campaign's `utm_campaign` labels as a clean list: normalized, deduped,
181
+ * capped. Accepts the stored array or a comma- or newline-separated string,
182
+ * which is how the edit drawer collects them.
183
+ */ export function campaignUtmLabels(raw) {
184
+ const parts = Array.isArray(raw) ? raw : typeof raw === 'string' ? raw.split(/[\n,]/) : [];
185
+ const labels = [];
186
+ for (const part of parts){
187
+ const label = normalizeCampaignUtmLabel(part);
188
+ if (!label || labels.includes(label)) continue;
189
+ labels.push(label);
190
+ if (labels.length >= CAMPAIGN_UTM_LABELS_MAX) break;
191
+ }
192
+ return labels;
193
+ }
160
194
  /**
161
195
  * Whether a campaign's emails carry the mail-client unsubscribe button:
162
196
  * the shared reader sequences use, with a campaign's default of ON.