ahoy_analytics 0.1.0
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +163 -0
- data/Rakefile +6 -0
- data/app/assets/ahoy_analytics/build/assets/Combination-BpSXUjp9.js +41 -0
- data/app/assets/ahoy_analytics/build/assets/analytics-5KyfCxh6.css +1 -0
- data/app/assets/ahoy_analytics/build/assets/analytics-dashboard-uOXx8zYZ.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/analytics-layout-ClAft5OU.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/analytics-tracker-B3f8P98z.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/analytics-ui-DMSkNqd6.js +90 -0
- data/app/assets/ahoy_analytics/build/assets/behaviors-panel-ChNGYbdH.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/button-JVCrlR4s.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/cable-DO-7y1-E.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/createLucideIcon-BGzacY2v.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/date-range-dialog-DWDp3cLG.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/details-button-NqKfSGEG.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/devices-panel-cXvlmNBY.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/dialog-path-BBPNlB4Z.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/dropdown-menu-Adj3O5fh.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/filter-dialog-BN-rf4lp.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/index-B1K1NTKT.js +3 -0
- data/app/assets/ahoy_analytics/build/assets/index-BcHeb-Rh.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/index-DzpzLoG4.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/index-vX97OY1J.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/input-e4v_v0kE.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/jsx-runtime-u17CrQMm.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/last-load-context-De5uA95L.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/list-table-ChHEzzF9.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/live-Cp2MHECh.js +2 -0
- data/app/assets/ahoy_analytics/build/assets/locations-panel-BaISRmaQ.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/mercator-BnxX5RzL.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/pages-panel-Bh25L8mP.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/panel-tabs-B2kvGFJx.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/query-context-B-PgE00D.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/remote-details-dialog-DDTcKaM5.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/show-CCRicksg.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/simple-tabs-D6G6Bs0k.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/site-context-BNteYRlR.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/sources-panel-DyB21hxD.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/top-bar-FSiLBjq6.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/top-stats-context-DU15P9jS.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/use-debounce-VBpXQRL8.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/user-context-DbYteluY.js +1 -0
- data/app/assets/ahoy_analytics/build/assets/visitor-globe-BWLDihid.js +4789 -0
- data/app/assets/ahoy_analytics/build/assets/visitor-graph-uKXjLvcu.js +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/brave.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/chrome.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/chromium.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/duckduckgo.svg +2151 -0
- data/app/assets/ahoy_analytics/images/icon/browser/edge.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/fallback.svg +5 -0
- data/app/assets/ahoy_analytics/images/icon/browser/firefox.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/opera.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/safari.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/browser/samsung-internet.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/uc.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/vivaldi.svg +1 -0
- data/app/assets/ahoy_analytics/images/icon/browser/yandex.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/android.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/chrome_os.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/fallback.svg +5 -0
- data/app/assets/ahoy_analytics/images/icon/os/fedora.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/freebsd.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/gnu_linux.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/ios.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/ipad_os.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/mac.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/ubuntu.png +0 -0
- data/app/assets/ahoy_analytics/images/icon/os/windows.png +0 -0
- data/app/assets/stylesheets/ahoy_analytics/application.css +15 -0
- data/app/channels/ahoy_analytics/analytics_channel.rb +9 -0
- data/app/controllers/ahoy_analytics/analytics_controller.rb +9 -0
- data/app/controllers/ahoy_analytics/application_controller.rb +8 -0
- data/app/controllers/ahoy_analytics/assets_controller.rb +46 -0
- data/app/controllers/ahoy_analytics/base_controller.rb +285 -0
- data/app/controllers/ahoy_analytics/behaviors_controller.rb +14 -0
- data/app/controllers/ahoy_analytics/devices_controller.rb +14 -0
- data/app/controllers/ahoy_analytics/export_controller.rb +12 -0
- data/app/controllers/ahoy_analytics/live_controller.rb +9 -0
- data/app/controllers/ahoy_analytics/locations_controller.rb +14 -0
- data/app/controllers/ahoy_analytics/main_graph_controller.rb +10 -0
- data/app/controllers/ahoy_analytics/pages_controller.rb +14 -0
- data/app/controllers/ahoy_analytics/referrers_controller.rb +34 -0
- data/app/controllers/ahoy_analytics/search_terms_controller.rb +47 -0
- data/app/controllers/ahoy_analytics/sources_controller.rb +14 -0
- data/app/controllers/ahoy_analytics/top_stats_controller.rb +13 -0
- data/app/controllers/concerns/ahoy_analytics/set_current_request.rb +17 -0
- data/app/frontend/components/analytics/hex-highlights.tsx +165 -0
- data/app/frontend/components/analytics/hex-land-layer.tsx +61 -0
- data/app/frontend/components/analytics/metric-card.tsx +138 -0
- data/app/frontend/components/analytics/sessions-by-location.tsx +62 -0
- data/app/frontend/components/analytics/visitor-globe.tsx +424 -0
- data/app/frontend/components/ui/accordion.tsx +64 -0
- data/app/frontend/components/ui/alert.tsx +66 -0
- data/app/frontend/components/ui/avatar.tsx +53 -0
- data/app/frontend/components/ui/badge.tsx +46 -0
- data/app/frontend/components/ui/button.tsx +62 -0
- data/app/frontend/components/ui/calendar.tsx +212 -0
- data/app/frontend/components/ui/card.tsx +91 -0
- data/app/frontend/components/ui/checkbox.tsx +32 -0
- data/app/frontend/components/ui/dropdown-menu.tsx +255 -0
- data/app/frontend/components/ui/input.tsx +21 -0
- data/app/frontend/components/ui/label.tsx +22 -0
- data/app/frontend/components/ui/popover.tsx +46 -0
- data/app/frontend/components/ui/select.tsx +183 -0
- data/app/frontend/components/ui/separator.tsx +26 -0
- data/app/frontend/components/ui/sheet.tsx +139 -0
- data/app/frontend/components/ui/sidebar.tsx +726 -0
- data/app/frontend/components/ui/skeleton.tsx +13 -0
- data/app/frontend/components/ui/sonner.tsx +33 -0
- data/app/frontend/components/ui/tooltip.tsx +59 -0
- data/app/frontend/data/countries-110m.json +1 -0
- data/app/frontend/data/globe-data.json +1 -0
- data/app/frontend/entrypoints/analytics-tracker.ts +680 -0
- data/app/frontend/entrypoints/analytics-ui.tsx +26 -0
- data/app/frontend/entrypoints/analytics.css +77 -0
- data/app/frontend/layouts/analytics-layout.tsx +28 -0
- data/app/frontend/lib/cable.ts +13 -0
- data/app/frontend/lib/geocode.ts +65 -0
- data/app/frontend/lib/utils.ts +6 -0
- data/app/frontend/pages/admin/analytics/api.ts +221 -0
- data/app/frontend/pages/admin/analytics/hooks/use-debounce.ts +36 -0
- data/app/frontend/pages/admin/analytics/last-load-context.tsx +29 -0
- data/app/frontend/pages/admin/analytics/lib/base-path.ts +28 -0
- data/app/frontend/pages/admin/analytics/lib/dialog-path.ts +242 -0
- data/app/frontend/pages/admin/analytics/lib/number-formatter.ts +100 -0
- data/app/frontend/pages/admin/analytics/live.tsx +608 -0
- data/app/frontend/pages/admin/analytics/query-context.tsx +61 -0
- data/app/frontend/pages/admin/analytics/show.tsx +40 -0
- data/app/frontend/pages/admin/analytics/site-context.tsx +22 -0
- data/app/frontend/pages/admin/analytics/top-stats-context.tsx +37 -0
- data/app/frontend/pages/admin/analytics/types.ts +161 -0
- data/app/frontend/pages/admin/analytics/ui/analytics-dashboard.tsx +60 -0
- data/app/frontend/pages/admin/analytics/ui/behaviors-panel.tsx +456 -0
- data/app/frontend/pages/admin/analytics/ui/date-range-dialog.tsx +173 -0
- data/app/frontend/pages/admin/analytics/ui/details-button.tsx +33 -0
- data/app/frontend/pages/admin/analytics/ui/devices-panel.tsx +474 -0
- data/app/frontend/pages/admin/analytics/ui/filter-dialog.tsx +558 -0
- data/app/frontend/pages/admin/analytics/ui/list-table.tsx +346 -0
- data/app/frontend/pages/admin/analytics/ui/locations-panel.tsx +566 -0
- data/app/frontend/pages/admin/analytics/ui/pages-panel.tsx +207 -0
- data/app/frontend/pages/admin/analytics/ui/panel-tabs.tsx +65 -0
- data/app/frontend/pages/admin/analytics/ui/remote-details-dialog.tsx +356 -0
- data/app/frontend/pages/admin/analytics/ui/simple-tabs.tsx +54 -0
- data/app/frontend/pages/admin/analytics/ui/sources-panel.tsx +771 -0
- data/app/frontend/pages/admin/analytics/ui/top-bar.tsx +793 -0
- data/app/frontend/pages/admin/analytics/ui/visitor-graph.tsx +891 -0
- data/app/frontend/pages/admin/analytics/user-context.tsx +22 -0
- data/app/frontend/styles/shared.css +156 -0
- data/app/helpers/ahoy_analytics/application_helper.rb +96 -0
- data/app/jobs/ahoy_analytics/application_job.rb +4 -0
- data/app/jobs/ahoy_analytics/update_job.rb +12 -0
- data/app/mailers/ahoy_analytics/application_mailer.rb +6 -0
- data/app/models/ahoy/event/filters.rb +7 -0
- data/app/models/ahoy/event.rb +9 -0
- data/app/models/ahoy/visit/cache_key.rb +15 -0
- data/app/models/ahoy/visit/constants.rb +11 -0
- data/app/models/ahoy/visit/devices.rb +144 -0
- data/app/models/ahoy/visit/export.rb +24 -0
- data/app/models/ahoy/visit/filters.rb +286 -0
- data/app/models/ahoy/visit/imports.rb +36 -0
- data/app/models/ahoy/visit/locations.rb +276 -0
- data/app/models/ahoy/visit/metrics.rb +473 -0
- data/app/models/ahoy/visit/ordering.rb +110 -0
- data/app/models/ahoy/visit/pages.rb +533 -0
- data/app/models/ahoy/visit/pagination.rb +17 -0
- data/app/models/ahoy/visit/ranges.rb +227 -0
- data/app/models/ahoy/visit/series.rb +177 -0
- data/app/models/ahoy/visit/sources.rb +418 -0
- data/app/models/ahoy/visit/url_labels.rb +32 -0
- data/app/models/ahoy/visit.rb +143 -0
- data/app/models/ahoy_analytics/application_record.rb +5 -0
- data/app/models/ahoy_analytics/current.rb +8 -0
- data/app/models/ahoy_analytics/funnel.rb +16 -0
- data/app/models/ahoy_analytics/imported_entry_page.rb +5 -0
- data/app/models/ahoy_analytics/imported_exit_page.rb +5 -0
- data/app/models/ahoy_analytics/imported_page.rb +5 -0
- data/app/models/ahoy_analytics/live_stats.rb +152 -0
- data/app/models/ahoy_analytics/setting.rb +19 -0
- data/app/models/analytics/source_catalog.rb +48 -0
- data/app/views/layouts/ahoy_analytics/application.html.erb +15 -0
- data/config/routes.rb +21 -0
- data/config/vite.json +22 -0
- data/db/migrate/20251006104056_create_ahoy_visits_and_events.rb +62 -0
- data/db/migrate/20251006105012_add_analytics_fields_to_ahoy_visits.rb +11 -0
- data/db/migrate/20251012090000_create_analytics_funnels_and_imports.rb +52 -0
- data/db/migrate/20251013021500_add_analytics_indexes.rb +14 -0
- data/lib/ahoy_analytics/ahoy_store.rb +429 -0
- data/lib/ahoy_analytics/asset_manifest.rb +56 -0
- data/lib/ahoy_analytics/device_bucket.rb +39 -0
- data/lib/ahoy_analytics/engine.rb +55 -0
- data/lib/ahoy_analytics/maxmind_geo.rb +77 -0
- data/lib/ahoy_analytics/version.rb +3 -0
- data/lib/ahoy_analytics.rb +52 -0
- data/lib/generators/ahoy_analytics/install/install_generator.rb +111 -0
- data/lib/generators/ahoy_analytics/install/templates/initializer.rb +28 -0
- data/lib/tasks/ahoy_analytics_tasks.rake +4 -0
- metadata +352 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as i}from"./jsx-runtime-u17CrQMm.js";import{r as s}from"./analytics-ui-DMSkNqd6.js";import{u as m}from"./query-context-B-PgE00D.js";import{TopStatsProvider as e}from"./top-stats-context-DU15P9jS.js";import l from"./top-bar-FSiLBjq6.js";import n from"./visitor-graph-uKXjLvcu.js";import p from"./sources-panel-DyB21hxD.js";import c from"./pages-panel-Bh25L8mP.js";import x from"./locations-panel-BaISRmaQ.js";import f from"./devices-panel-cXvlmNBY.js";import d from"./behaviors-panel-ChNGYbdH.js";import{useSiteContext as u}from"./site-context-BNteYRlR.js";/* empty css */import"./button-JVCrlR4s.js";import"./index-vX97OY1J.js";import"./dropdown-menu-Adj3O5fh.js";import"./Combination-BpSXUjp9.js";import"./createLucideIcon-BGzacY2v.js";import"./index-BcHeb-Rh.js";import"./index-DzpzLoG4.js";import"./filter-dialog-BN-rf4lp.js";import"./input-e4v_v0kE.js";import"./use-debounce-VBpXQRL8.js";import"./date-range-dialog-DWDp3cLG.js";import"./cable-DO-7y1-E.js";import"./index-B1K1NTKT.js";import"./last-load-context-De5uA95L.js";import"./list-table-ChHEzzF9.js";import"./remote-details-dialog-DDTcKaM5.js";import"./details-button-NqKfSGEG.js";import"./panel-tabs-B2kvGFJx.js";import"./dialog-path-BBPNlB4Z.js";import"./mercator-BnxX5RzL.js";function X(t){const{query:r}=m(),o=u(),a=s.useMemo(()=>r.period==="realtime",[r.period]);return i.jsx(e,{initial:t.initialTopStats,children:i.jsxs("div",{className:"flex flex-col gap-6 pb-16",children:[i.jsx(l,{showCurrentVisitors:!a}),i.jsx(n,{initialGraph:t.initialGraph}),i.jsxs("section",{className:"grid gap-6 lg:grid-cols-2",children:[i.jsx(p,{initialData:t.initialSources}),i.jsx(c,{initialData:t.initialPages})]}),i.jsxs("section",{className:"grid gap-6 lg:grid-cols-2",children:[i.jsx(x,{initialData:t.initialLocations}),i.jsx(f,{initialData:t.initialDevices})]}),o.hasGoals?i.jsx(d,{initialData:t.initialBehaviors}):null]})})}export{X as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as a}from"./jsx-runtime-u17CrQMm.js";import{c as o}from"./index-vX97OY1J.js";function n({children:s,fullBleed:x=!1,className:e}){return a.jsx("div",{className:o("min-h-dvh bg-background text-foreground",x&&"flex flex-col"),children:a.jsx("main",{className:o(x?"flex flex-1 flex-col min-h-dvh":"mx-auto w-full max-w-[1400px] px-4 py-6 lg:px-8",e),children:s})})}export{n as A};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class m{visitToken=null;visitExpiresAt=null;visitorToken=null;lastTrackedHref=null;lastTrackedPageKey=null;config;ensureVisitPromise=null;listeningOnEngagement=!1;currentEngagementIgnored=!1;currentEngagementURL=null;currentEngagementMaxScrollDepth=-1;runningEngagementStart=0;currentEngagementTime=0;currentDocumentHeight=0;maxScrollDepthPx=0;constructor(){this.config={eventsEndpoint:"/ahoy/events",visitsEndpoint:"/ahoy/visits",excludePaths:["/admin","/.well-known","/ahoy","/cable"],excludeAssets:[".png",".jpg",".jpeg",".gif",".svg",".webp",".ico",".woff",".woff2",".ttf",".eot",".otf",".pdf",".zip",".tar",".gz",".mp4",".webm",".mp3",".wav",".css",".js",".map",".json"],useCookies:!1,visitDurationMinutes:30,useBeaconForEvents:!0,trackVisits:!0,hashBasedRouting:!1,debug:!1}}init(){if(typeof window>"u")return;try{const i=window.analyticsConfig;i&&typeof i=="object"&&(this.config={...this.config,...i})}catch{}this.readScriptAttributes(),this.bootstrapIdentity(),this.config.trackVisits&&(this.ensureVisitPromise=this.ensureActiveVisit());const t=()=>{document.visibilityState==="visible"&&(document.removeEventListener("visibilitychange",t),this.trackPageview())},e=()=>{document.visibilityState==="visible"?this.trackPageview():document.addEventListener("visibilitychange",t)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e(),this.setupNavigationListener(),this.initEngagement(),this.initAutoCapture()}bootstrapIdentity(){const t=document.querySelector('meta[name="ahoy-visit"]'),e=document.querySelector('meta[name="ahoy-visitor"]');t?.content&&(this.visitToken=t.content),e?.content&&(this.visitorToken=e.content),this.visitorToken||(this.visitorToken=this.getOrCreateVisitorToken());const i=this.getStoredVisit();i&&(this.visitToken=i.token,this.visitExpiresAt=i.expiresAt),(!this.visitToken||this.isVisitExpired())&&this.createNewVisitToken()}setupNavigationListener(){const t=history.pushState,e=history.replaceState;t&&(history.pushState=(...i)=>{this.prePageview(),t.apply(history,i),this.config.debug&&console.debug("[analytics] pushState"),this.trackPageview()}),e&&(history.replaceState=(...i)=>{this.prePageview(),e.apply(history,i),this.config.debug&&console.debug("[analytics] replaceState"),this.trackPageview()}),window.addEventListener("popstate",()=>{this.prePageview(),this.config.debug&&console.debug("[analytics] popstate"),this.trackPageview()}),this.config.hashBasedRouting&&window.addEventListener("hashchange",()=>{this.prePageview(),this.config.debug&&console.debug("[analytics] hashchange"),this.trackPageview()})}async trackPageview(){if(typeof window>"u")return;try{if(window.top!==window.self)return}catch{return}const t=window.location.href,e=window.location.pathname,i=e+window.location.search,n=this.config.hashBasedRouting?i+window.location.hash:i;if(this.lastTrackedPageKey===n)return;if(this.lastTrackedPageKey=n,this.config.debug&&console.debug("[analytics] trackPageview pageKey=",n),this.shouldExclude(e)){this.lastTrackedHref=t;return}if(this.ensureVisitPromise)try{await this.ensureVisitPromise}catch{}const s=this.lastTrackedHref||document.referrer||"";this.sendEvent({name:"pageview",page:i,url:t,title:document.title,referrer:s,screenSize:`${window.innerWidth}x${window.innerHeight}`}),this.lastTrackedHref=t,this.postPageview({url:t,page:i})}shouldExclude(t){const e=t.toLowerCase();return!!(this.config.excludePaths.some(s=>e.startsWith(s))||this.config.excludeAssets.some(s=>e.endsWith(s))||["/favicon.ico","/robots.txt","/sitemap.xml","/manifest.json","/browserconfig.xml","/.well-known/appspecific/com.chrome.devtools.json"].includes(e)||e.includes("apple-touch-icon")||this.config.includePaths&&this.config.includePaths.length>0&&!this.config.includePaths.some(r=>this.pathMatches(r,e))||this.config.excludePaths&&this.config.excludePaths.length>0&&this.config.excludePaths.some(s=>this.pathMatches(s,e)))}sendEvent(t,e){if(typeof window>"u")return;const i={name:t.name,properties:{page:t.page,url:t.url,title:t.title,referrer:t.referrer,screen_size:t.screenSize,...e||{}},time:Date.now()/1e3};if(this.config.debug)try{console.debug("[analytics] sendEvent",{name:i.name,page:i.properties.page,url:i.properties.url})}catch{}if(this.config.useBeaconForEvents&&typeof navigator.sendBeacon=="function"){const o={};o.events_json=JSON.stringify([i]),this.visitToken&&(o.visit_token=this.visitToken),this.visitorToken&&(o.visitor_token=this.visitorToken);const a=this.getCSRFParam(),h=this.getCSRFToken();a&&h&&(o[a]=h);const g=new FormData;Object.entries(o).forEach(([u,d])=>g.append(u,d)),navigator.sendBeacon(this.config.eventsEndpoint,g);return}const s={"Content-Type":"application/json"},r=this.getCSRFToken();r&&(s["X-CSRF-Token"]=r);const c={visit_token:this.visitToken,visitor_token:this.visitorToken,events:[i]};fetch(this.config.eventsEndpoint,{method:"POST",headers:s,body:JSON.stringify(c),credentials:"same-origin",keepalive:!0}).catch(()=>{})}generateToken(){const t=typeof globalThis<"u"?globalThis.crypto:void 0;if(t?.randomUUID)return t.randomUUID().replace(/-/g,"");const e=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(e);else for(let i=0;i<e.length;i++)e[i]=Math.floor(Math.random()*256);return Array.from(e,i=>i.toString(16).padStart(2,"0")).join("")}getOrCreateVisitorToken(){if(this.config.useCookies){const t=this.getCookie("ahoy_visitor");if(t)return t;const e=this.generateToken();return this.setCookie("ahoy_visitor",e,1440*365*2),e}else{const t=localStorage.getItem("ahoy_visitor");if(t)return t;const e=this.generateToken();return localStorage.setItem("ahoy_visitor",e),e}}getCSRFToken(){return document.querySelector('meta[name="csrf-token"]')?.content||null}getCSRFParam(){return document.querySelector('meta[name="csrf-param"]')?.content||null}isVisitExpired(){return this.visitExpiresAt?Date.now()>this.visitExpiresAt:!0}createNewVisitToken(){this.visitToken=this.generateToken();const t=this.config.visitDurationMinutes*60*1e3;this.visitExpiresAt=Date.now()+t,this.storeVisit(this.visitToken,this.visitExpiresAt)}ensureActiveVisit(){(!this.visitToken||this.isVisitExpired())&&this.createNewVisitToken();const t={visit_token:this.visitToken,visitor_token:this.visitorToken,platform:"Web",landing_page:window.location.href,screen_width:window.innerWidth,screen_height:window.innerHeight,screen_size:`${window.innerWidth}x${window.innerHeight}`,js:!0};document.referrer&&(t.referrer=document.referrer);try{const n=new URLSearchParams(window.location.search),s=n.get("utm_source")||n.get("source")||n.get("ref"),r=n.get("utm_medium"),c=n.get("utm_campaign"),o=n.get("utm_content"),a=n.get("utm_term");s&&(t.utm_source=s),r&&(t.utm_medium=r),c&&(t.utm_campaign=c),o&&(t.utm_content=o),a&&(t.utm_term=a)}catch{}const e={"Content-Type":"application/json"},i=this.getCSRFToken();return i&&(e["X-CSRF-Token"]=i),fetch(this.config.visitsEndpoint,{method:"POST",headers:e,body:JSON.stringify(t),credentials:"same-origin",keepalive:!0}).then(()=>{}).catch(()=>{})}getStoredVisit(){if(this.config.useCookies){const t=this.getCookie("ahoy_visit"),e=this.getCookie("ahoy_visit_expires");return t&&e?{token:t,expiresAt:parseInt(e,10)}:null}else{const t=localStorage.getItem("ahoy_visit"),e=localStorage.getItem("ahoy_visit_expires");return t&&e?{token:t,expiresAt:parseInt(e,10)}:null}}storeVisit(t,e){this.config.useCookies?(this.setCookie("ahoy_visit",t,this.config.visitDurationMinutes),this.setCookie("ahoy_visit_expires",String(e),this.config.visitDurationMinutes)):(localStorage.setItem("ahoy_visit",t),localStorage.setItem("ahoy_visit_expires",String(e)))}setCookie(t,e,i){const n=new Date;n.setTime(n.getTime()+i*60*1e3),document.cookie=`${t}=${encodeURIComponent(e)}; expires=${n.toUTCString()}; path=/; samesite=lax`}getCookie(t){const e=document.cookie.match(new RegExp("(^|; )"+t.replace(/([.$?*|{}()\[\]\\/+^])/g,"\\$1")+"=([^;]*)"));return e?decodeURIComponent(e[2]):null}initEngagement(){this.currentDocumentHeight=this.getDocumentHeight(),this.maxScrollDepthPx=this.getCurrentScrollDepthPx(),window.addEventListener("load",()=>{this.currentDocumentHeight=this.getDocumentHeight();let t=0;const e=setInterval(()=>{this.currentDocumentHeight=this.getDocumentHeight(),++t===15&&clearInterval(e)},200)}),document.addEventListener("scroll",()=>{this.currentDocumentHeight=this.getDocumentHeight();const t=this.getCurrentScrollDepthPx();t>this.maxScrollDepthPx&&(this.maxScrollDepthPx=t)})}prePageview(){this.listeningOnEngagement&&(this.triggerEngagement(),this.currentDocumentHeight=this.getDocumentHeight(),this.maxScrollDepthPx=this.getCurrentScrollDepthPx())}postPageview(t){this.currentEngagementIgnored=!1,this.currentEngagementURL=t.url,this.currentEngagementMaxScrollDepth=-1,this.currentEngagementTime=0,this.runningEngagementStart=Date.now(),this.registerEngagementListeners()}onVisibilityChange=()=>{document.visibilityState==="visible"&&document.hasFocus()&&this.runningEngagementStart===0?this.runningEngagementStart=Date.now():(document.visibilityState==="hidden"||!document.hasFocus())&&(this.currentEngagementTime=this.getEngagementTime(),this.runningEngagementStart=0,this.triggerEngagement())};registerEngagementListeners(){this.listeningOnEngagement||(document.addEventListener("visibilitychange",this.onVisibilityChange),window.addEventListener("blur",this.onVisibilityChange),window.addEventListener("focus",this.onVisibilityChange),this.listeningOnEngagement=!0)}getEngagementTime(){return this.runningEngagementStart?this.currentEngagementTime+(Date.now()-this.runningEngagementStart):this.currentEngagementTime}triggerEngagement(){const t=this.getEngagementTime(),e=this.currentEngagementMaxScrollDepth<this.maxScrollDepthPx;if(!this.currentEngagementIgnored&&(e||t>=3e3||this.currentEngagementMaxScrollDepth===-1)){this.currentEngagementMaxScrollDepth=this.maxScrollDepthPx;const i=this.currentDocumentHeight>0?Math.round(this.maxScrollDepthPx/this.currentDocumentHeight*100):0,n=this.currentEngagementURL||window.location.href;this.sendEvent({name:"engagement",page:window.location.pathname+window.location.search,url:n,title:document.title,referrer:document.referrer||"",screenSize:`${window.innerWidth}x${window.innerHeight}`},{engaged_ms:t,scroll_depth:i}),this.runningEngagementStart=0,this.currentEngagementTime=0}}getDocumentHeight(){const t=document.body,e=document.documentElement,i=t||{},n=e||{};return Math.max(i.scrollHeight||0,i.offsetHeight||0,i.clientHeight||0,n.scrollHeight||0,n.offsetHeight||0,n.clientHeight||0)}getCurrentScrollDepthPx(){const t=document.body,e=document.documentElement,i=window.innerHeight||e&&e.clientHeight||0,n=window.scrollY||e&&e.scrollTop||t&&t.scrollTop||0;return this.currentDocumentHeight<=i?this.currentDocumentHeight:n+i}initAutoCapture(){const t=e=>{if(e.type==="auxclick"&&e.button!==1)return;const i=this.getLinkEl(e.target);if(!i||!i.href)return;try{if(new URL(i.href,window.location.origin).pathname.startsWith("/.well-known/"))return}catch{}const n=i.href.split("?")[0];if(this.isOutboundLink(i)){this.sendEvent({name:"Outbound Link: Click",page:window.location.pathname+window.location.search,url:i.href,title:document.title,referrer:document.referrer||"",screenSize:`${window.innerWidth}x${window.innerHeight}`});return}this.isDownloadToTrack(n)&&this.sendEvent({name:"File Download",page:window.location.pathname+window.location.search,url:n,title:document.title,referrer:document.referrer||"",screenSize:`${window.innerWidth}x${window.innerHeight}`})};document.addEventListener("click",t),document.addEventListener("auxclick",t)}readScriptAttributes(){try{const e=Array.from(document.getElementsByTagName("script")).reverse().find(s=>s.getAttribute("data-include")||s.getAttribute("data-exclude")||s.src&&s.src.includes("analytics"));if(!e)return;const i=e.getAttribute("data-include"),n=e.getAttribute("data-exclude");i&&(this.config.includePaths=i.split(",").map(s=>s.trim()).filter(Boolean)),n&&(this.config.excludePaths=[...this.config.excludePaths,...n.split(",").map(s=>s.trim()).filter(Boolean)])}catch{}}pathMatches(t,e){const n="^"+t.trim().replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/([^\\])\*/g,"$1[^\\s/]*")+"\\/?$";try{return new RegExp(n).test(e)}catch{return!1}}getLinkEl(t){let e=t,i=0;for(;e&&i<5;){if(e instanceof HTMLAnchorElement&&e.href)return e;e=e.parentElement,i++}return null}isOutboundLink(t){try{return!!t.host&&t.host!==window.location.host}catch{return!1}}isDownloadToTrack(t){if(!t)return!1;const e=["pdf","xlsx","docx","txt","rtf","csv","exe","key","pps","ppt","pptx","7z","pkg","rar","gz","zip","avi","mov","mp4","mpeg","wmv","midi","mp3","wav","wma","dmg"],i=t.split(".").pop()?.toLowerCase();return!!i&&e.includes(i)}}typeof window<"u"&&(window.__analyticsInitialized||(new m().init(),window.__analyticsInitialized=!0));
|