@kryptonhq/analytics 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,136 +1,77 @@
1
1
  # @kryptonhq/analytics
2
2
 
3
- Krypton Analytics JavaScript SDK.
4
-
5
- ## Install (npm)
6
-
7
- ```bash
8
- npm install @kryptonhq/analytics
9
- ```
10
-
11
- ```ts
12
- import { Krypton } from "@kryptonhq/analytics";
13
-
14
- const krypton = new Krypton({
15
- apiKey: "kapi_xxx",
16
- endpoint: "https://ingest.yourdomain.com",
17
- autoPageview: true,
18
- heatmap: true,
19
- consentRequired: true,
20
- showConsentBanner: true,
21
- });
22
-
23
- krypton.track("signup_clicked", { plan: "pro" });
24
- ```
3
+ Krypton Analytics JavaScript SDK — privacy-first analytics tracking.
25
4
 
26
5
  ## Install (CDN, script tag)
27
6
 
28
- Use jsDelivr:
29
-
30
7
  ```html
31
8
  <script defer src="https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js"></script>
32
9
  <script>
33
- window.addEventListener("DOMContentLoaded", function () {
34
- var krypton = window.KryptonAnalytics.init({
10
+ window.addEventListener("load", function () {
11
+ window.krypton = window.KryptonAnalytics.init({
35
12
  apiKey: "kapi_xxx",
36
13
  endpoint: "https://ingest.yourdomain.com",
37
14
  autoPageview: true,
38
15
  heatmap: true,
39
16
  consentRequired: true,
40
17
  showConsentBanner: true
41
- });
42
-
43
- krypton.track("page_loaded");
44
- });
18
+ })
19
+ })
45
20
  </script>
46
21
  ```
47
22
 
48
23
  The CDN build exposes a global: `window.KryptonAnalytics`.
49
24
 
50
- ## Consent (default deny + categories)
51
-
52
- The SDK supports category-level consent:
53
-
54
- - `analytics`
55
- - `heatmaps`
56
- - `geo` (browser geolocation, if granted by user)
25
+ ## Install (npm)
57
26
 
58
- Example:
27
+ ```bash
28
+ npm install @kryptonhq/analytics
29
+ ```
59
30
 
60
31
  ```ts
61
- import { Krypton } from "@kryptonhq/analytics";
32
+ import { createKrypton } from "@kryptonhq/analytics";
62
33
 
63
- const krypton = new Krypton({
34
+ const krypton = createKrypton({
64
35
  apiKey: "kapi_xxx",
65
36
  endpoint: "https://ingest.yourdomain.com",
37
+ autoPageview: true,
66
38
  heatmap: true,
67
- consentRequired: true, // default deny
68
- showConsentBanner: true, // built-in popup
39
+ consentRequired: true,
40
+ showConsentBanner: true,
69
41
  });
70
42
 
71
- // Optional manual control
72
- krypton.setConsent({
73
- analytics: true,
74
- heatmaps: false,
75
- geo: false,
76
- });
43
+ krypton.track("signup", { plan: "pro" });
77
44
  ```
78
45
 
79
- ### GA-style bootstrap snippet (single paste)
46
+ ## Consent (default deny + categories)
80
47
 
81
- ```html
82
- <script>
83
- (function (w, d, s, u, n) {
84
- w[n] = w[n] || function () { (w[n].q = w[n].q || []).push(arguments); };
85
- w[n].l = +new Date();
86
- var js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
87
- js.async = 1;
88
- js.src = u;
89
- js.onload = function () {
90
- var cfg = w[n].cfg;
91
- w[n].client = w.KryptonAnalytics.init(cfg);
92
- var q = w[n].q || [];
93
- for (var i = 0; i < q.length; i++) {
94
- var args = q[i];
95
- if (args[0] === "track") w[n].client.track(args[1], args[2]);
96
- }
97
- };
98
- fjs.parentNode.insertBefore(js, fjs);
99
- })(window, document, "script", "https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js", "krypton");
100
-
101
- krypton.cfg = {
102
- apiKey: "kapi_xxx",
103
- endpoint: "https://ingest.yourdomain.com",
104
- autoPageview: true,
105
- heatmap: true
106
- };
107
-
108
- krypton("track", "landing_view");
109
- </script>
110
- ```
48
+ The SDK supports category-level consent:
111
49
 
112
- ## Publish to npm
50
+ - `analytics` pageviews and custom events
51
+ - `heatmaps` — click and scroll interaction maps
113
52
 
114
- This repository includes a GitHub Actions workflow at:
53
+ When `consentRequired: true` and `showConsentBanner: true`, a built-in consent popup is shown automatically. No data is collected until the user grants consent.
115
54
 
116
- - `.github/workflows/publish-sdk.yml`
55
+ Geolocation is resolved server-side from the request IP (no browser Geolocation API needed).
117
56
 
118
- It triggers on:
57
+ ### Manual consent control
119
58
 
120
- - Manual run (`workflow_dispatch`)
121
- - Tag push matching `sdk-v*` (example: `sdk-v0.1.1`)
59
+ ```ts
60
+ krypton.setConsent({ analytics: true, heatmaps: false });
122
61
 
123
- Required GitHub secret:
62
+ krypton.grantConsent(); // grant all
63
+ krypton.revokeConsent(); // revoke all
124
64
 
125
- - None, when using npm Trusted Publishing (recommended)
65
+ krypton.showConsentBanner(); // re-show the popup
66
+ ```
126
67
 
127
- Publish flow:
68
+ ## API
128
69
 
129
- 1. Configure npm Trusted Publishing for this package/repo in npm settings.
130
- 2. Bump version in `package.json`.
131
- 3. Commit and push.
132
- 4. Create and push tag:
133
- ```bash
134
- git tag sdk-v0.1.1
135
- git push origin sdk-v0.1.1
136
- ```
70
+ ```ts
71
+ krypton.track("event_name", { key: "value" });
72
+ krypton.trackPageview();
73
+ krypton.identify("user-123");
74
+ krypton.flush();
75
+ krypton.shutdown();
76
+ krypton.getConsent(); // { analytics: boolean, heatmaps: boolean }
77
+ ```
@@ -1,4 +1,4 @@
1
- "use strict";var KryptonAnalytics=(()=>{var Z=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var be=Object.prototype.hasOwnProperty;var Ce=(e,t)=>{for(var r in t)Z(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Se(t))!be.call(e,i)&&i!==r&&Z(e,i,{get:()=>t[i],enumerable:!(n=ke(t,i))||n.enumerable});return e};var Ie=e=>xe(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>q,default:()=>it,init:()=>ye});var v;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(v||(v={}));function Te(e){return e.nodeType===e.ELEMENT_NODE}function Ee(e){var t=e?.host;return t?.shadowRoot===e}function ee(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function Le(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function te(e){try{var t=e.rules||e.cssRules;return t?Le(Array.from(t).map(Re).join("")):null}catch{return null}}function Re(e){var t=e.cssText;if(_e(e))try{t=te(e.styleSheet)||t}catch{}return t}function _e(e){return"styleSheet"in e}var Ne=(function(){function e(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}return e.prototype.getId=function(t){var r;if(!t)return-1;var n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1},e.prototype.getNode=function(t){return this.idNodeMap.get(t)||null},e.prototype.getIds=function(){return Array.from(this.idNodeMap.keys())},e.prototype.getMeta=function(t){return this.nodeMetaMap.get(t)||null},e.prototype.removeNodeFromMap=function(t){var r=this,n=this.getId(t);this.idNodeMap.delete(n),t.childNodes&&t.childNodes.forEach(function(i){return r.removeNodeFromMap(i)})},e.prototype.has=function(t){return this.idNodeMap.has(t)},e.prototype.hasNode=function(t){return this.nodeMetaMap.has(t)},e.prototype.add=function(t,r){var n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var n=this.getNode(t);if(n){var i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)},e.prototype.reset=function(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap},e})();function Oe(e){var t=e.maskInputOptions,r=e.tagName,n=e.type,i=e.value,a=e.maskInputFn,c=i||"";return(t[r.toLowerCase()]||t[n])&&(a?c=a(c):c="*".repeat(c.length)),c}var le="__rrweb_original__";function Ae(e){var t=e.getContext("2d");if(!t)return!0;for(var r=50,n=0;n<e.width;n+=r)for(var i=0;i<e.height;i+=r){var a=t.getImageData,c=le in a?a[le]:a,u=new Uint32Array(c.call(t,n,i,Math.min(r,e.width-n),Math.min(r,e.height-i)).data.buffer);if(u.some(function(o){return o!==0}))return!1}return!0}var Me=1,Pe=new RegExp("[^a-z0-9-_:]"),ue=-2;function De(){return Me++}function Fe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return Pe.test(t)?"div":t}function He(e){return e.cssRules?Array.from(e.cssRules).map(function(t){return t.cssText||""}).join(""):""}function Ue(e){var t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}var z,fe,We=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Be=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,Ke=/^(data:)([^,]*),(.*)/i;function Q(e,t){return(e||"").replace(We,function(r,n,i,a,c,u){var o=i||c||u,f=n||a||"";if(!o)return r;if(!Be.test(o)||Ke.test(o))return"url(".concat(f).concat(o).concat(f,")");if(o[0]==="/")return"url(".concat(f).concat(Ue(t)+o).concat(f,")");var l=t.split("/"),h=o.split("/");l.pop();for(var b=0,w=h;b<w.length;b++){var k=w[b];k!=="."&&(k===".."?l.pop():l.push(k))}return"url(".concat(f).concat(l.join("/")).concat(f,")")})}var ze=/^[^ \t\n\r\u000c]+/,je=/^[, \t\n\r\u000c]+/;function qe(e,t){if(t.trim()==="")return t;var r=0;function n(f){var l,h=f.exec(t.substring(r));return h?(l=h[0],r+=l.length,l):""}for(var i=[];n(je),!(r>=t.length);){var a=n(ze);if(a.slice(-1)===",")a=j(e,a.substring(0,a.length-1)),i.push(a);else{var c="";a=j(e,a);for(var u=!1;;){var o=t.charAt(r);if(o===""){i.push((a+c).trim());break}else if(u)o===")"&&(u=!1);else if(o===","){r+=1,i.push((a+c).trim());break}else o==="("&&(u=!0);c+=o,r+=1}}}return i.join(", ")}function j(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function $e(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ne(){var e=document.createElement("a");return e.href="",e.href}function Ge(e,t,r,n){return r==="src"||r==="href"&&n&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n&&n[0]!=="#"||r==="background"&&n&&(t==="table"||t==="td"||t==="th")?j(e,n):r==="srcset"&&n?qe(e,n):r==="style"&&n?Q(n,ne()):t==="object"&&r==="data"&&n?j(e,n):n}function Qe(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?e.matches(r):!1}function re(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?re(e.parentNode,t,r):!1;for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var n=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(n===null)return!1;if(typeof t=="string"){if(n.classList.contains(t)||n.closest(".".concat(t)))return!0}else if(re(n,t,!0))return!0;return!!(r&&(n.matches(r)||n.closest(r)))}function Ve(e,t,r){var n=e.contentWindow;if(n){var i=!1,a;try{a=n.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(c),i=!0,t()});return}var u="about:blank";if(n.location.href!==u||e.src===u||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}}function Ye(e,t,r){var n=!1,i;try{i=e.sheet}catch{return}if(!i){var a=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(a),n=!0,t()})}}function Xe(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.inlineStylesheet,f=t.maskInputOptions,l=f===void 0?{}:f,h=t.maskTextFn,b=t.maskInputFn,w=t.dataURLOptions,k=w===void 0?{}:w,x=t.inlineImages,I=t.recordCanvas,T=t.keepIframeSrcFn,p=t.newlyAddedElement,s=p===void 0?!1:p,y=Ze(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:v.Document,childNodes:[],compatMode:e.compatMode}:{type:v.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:v.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return tt(e,{doc:r,blockClass:i,blockSelector:a,inlineStylesheet:o,maskInputOptions:l,maskInputFn:b,dataURLOptions:k,inlineImages:x,recordCanvas:I,keepIframeSrcFn:T,newlyAddedElement:s,rootId:y});case e.TEXT_NODE:return et(e,{maskTextClass:c,maskTextSelector:u,maskTextFn:h,rootId:y});case e.CDATA_SECTION_NODE:return{type:v.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:v.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function Ze(e,t){if(t.hasNode(e)){var r=t.getId(e);return r===1?void 0:r}}function et(e,t){var r,n=t.maskTextClass,i=t.maskTextSelector,a=t.maskTextFn,c=t.rootId,u=e.parentNode&&e.parentNode.tagName,o=e.textContent,f=u==="STYLE"?!0:void 0,l=u==="SCRIPT"?!0:void 0;if(f&&o){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(o=He(e.parentNode.sheet))}catch(h){console.warn("Cannot get CSS styles from text's parentNode. Error: ".concat(h),e)}o=Q(o,ne())}return l&&(o="SCRIPT_PLACEHOLDER"),!f&&!l&&o&&Je(e,n,i)&&(o=a?a(o):o.replace(/[\S]/g,"*")),{type:v.Text,textContent:o||"",isStyle:f,rootId:c}}function tt(e,t){for(var r=t.doc,n=t.blockClass,i=t.blockSelector,a=t.inlineStylesheet,c=t.maskInputOptions,u=c===void 0?{}:c,o=t.maskInputFn,f=t.dataURLOptions,l=f===void 0?{}:f,h=t.inlineImages,b=t.recordCanvas,w=t.keepIframeSrcFn,k=t.newlyAddedElement,x=k===void 0?!1:k,I=t.rootId,T=Qe(e,n,i),p=Fe(e),s={},y=e.attributes.length,A=0;A<y;A++){var E=e.attributes[A];s[E.name]=Ge(r,p,E.name,E.value)}if(p==="link"&&a){var C=Array.from(r.styleSheets).find(function(R){return R.href===e.href}),m=null;C&&(m=te(C)),m&&(delete s.rel,delete s.href,s._cssText=Q(m,C.href))}if(p==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=Q(m,ne()))}if(p==="input"||p==="textarea"||p==="select"){var F=e.value,_=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&F?s.value=Oe({type:s.type,tagName:p,value:F,maskInputOptions:u,maskInputFn:o}):_&&(s.checked=_)}if(p==="option"&&(e.selected&&!u.select?s.selected=!0:delete s.selected),p==="canvas"&&b){if(e.__context==="2d")Ae(e)||(s.rr_dataURL=e.toDataURL(l.type,l.quality));else if(!("__context"in e)){var L=e.toDataURL(l.type,l.quality),M=document.createElement("canvas");M.width=e.width,M.height=e.height;var P=M.toDataURL(l.type,l.quality);L!==P&&(s.rr_dataURL=L)}}if(p==="img"&&h){z||(z=r.createElement("canvas"),fe=z.getContext("2d"));var S=e,N=S.crossOrigin;S.crossOrigin="anonymous";var D=function(){try{z.width=S.naturalWidth,z.height=S.naturalHeight,fe.drawImage(S,0,0),s.rr_dataURL=z.toDataURL(l.type,l.quality)}catch(R){console.warn("Cannot inline img src=".concat(S.currentSrc,"! Error: ").concat(R))}N?s.crossOrigin=N:S.removeAttribute("crossorigin")};S.complete&&S.naturalWidth!==0?D():S.onload=D}if((p==="audio"||p==="video")&&(s.rr_mediaState=e.paused?"paused":"played",s.rr_mediaCurrentTime=e.currentTime),x||(e.scrollLeft&&(s.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(s.rr_scrollTop=e.scrollTop)),T){var U=e.getBoundingClientRect(),W=U.width,O=U.height;s={class:s.class,rr_width:"".concat(W,"px"),rr_height:"".concat(O,"px")}}return p==="iframe"&&!w(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:v.Element,tagName:p,attributes:s,childNodes:[],isSVG:$e(e)||void 0,needBlock:T,rootId:I}}function d(e){return e===void 0?"":e.toLowerCase()}function rt(e,t){if(t.comment&&e.type===v.Comment)return!0;if(e.type===v.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&e.attributes.rel==="preload"&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&e.attributes.href.endsWith(".js")))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(d(e.attributes.name).match(/^msapplication-tile(image|color)$/)||d(e.attributes.name)==="application-name"||d(e.attributes.rel)==="icon"||d(e.attributes.rel)==="apple-touch-icon"||d(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&d(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(d(e.attributes.property).match(/^(og|twitter|fb):/)||d(e.attributes.name).match(/^(og|twitter):/)||d(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(d(e.attributes.name)==="robots"||d(e.attributes.name)==="googlebot"||d(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(d(e.attributes.name)==="author"||d(e.attributes.name)==="generator"||d(e.attributes.name)==="framework"||d(e.attributes.name)==="publisher"||d(e.attributes.name)==="progid"||d(e.attributes.property).match(/^article:/)||d(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(d(e.attributes.name)==="google-site-verification"||d(e.attributes.name)==="yandex-verification"||d(e.attributes.name)==="csrf-token"||d(e.attributes.name)==="p:domain_verify"||d(e.attributes.name)==="verify-v1"||d(e.attributes.name)==="verification"||d(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function G(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.skipChild,f=o===void 0?!1:o,l=t.inlineStylesheet,h=l===void 0?!0:l,b=t.maskInputOptions,w=b===void 0?{}:b,k=t.maskTextFn,x=t.maskInputFn,I=t.slimDOMOptions,T=t.dataURLOptions,p=T===void 0?{}:T,s=t.inlineImages,y=s===void 0?!1:s,A=t.recordCanvas,E=A===void 0?!1:A,C=t.onSerialize,m=t.onIframeLoad,F=t.iframeLoadTimeout,_=F===void 0?5e3:F,L=t.onStylesheetLoad,M=t.stylesheetLoadTimeout,P=M===void 0?5e3:M,S=t.keepIframeSrcFn,N=S===void 0?function(){return!1}:S,D=t.newlyAddedElement,U=D===void 0?!1:D,W=t.preserveWhiteSpace,O=W===void 0?!0:W,R=Xe(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,inlineStylesheet:h,maskInputOptions:w,maskTextFn:k,maskInputFn:x,dataURLOptions:p,inlineImages:y,recordCanvas:E,keepIframeSrcFn:N,newlyAddedElement:U});if(!R)return console.warn(e,"not serialized"),null;var $;n.hasNode(e)?$=n.getId(e):rt(R,I)||!O&&R.type===v.Text&&!R.isStyle&&!R.textContent.replace(/^\s+|\s+$/gm,"").length?$=ue:$=De();var g=Object.assign(R,{id:$});if(n.add(e,g),$===ue)return null;C&&C(e);var J=!f;if(g.type===v.Element){J=J&&!g.needBlock,delete g.needBlock;var ie=e.shadowRoot;ie&&ee(ie)&&(g.isShadowHost=!0)}if((g.type===v.Document||g.type===v.Element)&&J){I.headWhitespace&&g.type===v.Element&&g.tagName==="head"&&(O=!1);for(var ae={doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:f,inlineStylesheet:h,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N},V=0,oe=Array.from(e.childNodes);V<oe.length;V++){var Y=oe[V],B=G(Y,ae);B&&g.childNodes.push(B)}if(Te(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var Y=se[X],B=G(Y,ae);B&&(ee(e.shadowRoot)&&(B.isShadow=!0),g.childNodes.push(B))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(g.isShadow=!0),g.type===v.Element&&g.tagName==="iframe"&&Ve(e,function(){var K=e.contentDocument;if(K&&m){var ce=G(K,{doc:K,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:h,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});ce&&m(e,ce)}},_),g.type===v.Element&&g.tagName==="link"&&g.attributes.rel==="stylesheet"&&Ye(e,function(){if(L){var K=G(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:h,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});K&&L(e,K)}},P),g}function de(e,t){var r=t||{},n=r.mirror,i=n===void 0?new Ne:n,a=r.blockClass,c=a===void 0?"rr-block":a,u=r.blockSelector,o=u===void 0?null:u,f=r.maskTextClass,l=f===void 0?"rr-mask":f,h=r.maskTextSelector,b=h===void 0?null:h,w=r.inlineStylesheet,k=w===void 0?!0:w,x=r.inlineImages,I=x===void 0?!1:x,T=r.recordCanvas,p=T===void 0?!1:T,s=r.maskAllInputs,y=s===void 0?!1:s,A=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,F=r.dataURLOptions,_=r.preserveWhiteSpace,L=r.onSerialize,M=r.onIframeLoad,P=r.iframeLoadTimeout,S=r.onStylesheetLoad,N=r.stylesheetLoadTimeout,D=r.keepIframeSrcFn,U=D===void 0?function(){return!1}:D,W=y===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:y===!1?{password:!0}:y,O=m===!0||m==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:m==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:m===!1?{}:m;return G(e,{doc:e,mirror:i,blockClass:c,blockSelector:o,maskTextClass:l,maskTextSelector:b,skipChild:!1,inlineStylesheet:k,maskInputOptions:W,maskTextFn:A,maskInputFn:E,slimDOMOptions:O,dataURLOptions:F,inlineImages:I,recordCanvas:p,preserveWhiteSpace:_,onSerialize:L,onIframeLoad:M,iframeLoadTimeout:P,onStylesheetLoad:S,stylesheetLoadTimeout:N,keepIframeSrcFn:U,newlyAddedElement:!1})}var nt=/([^\\]):hover/,st=new RegExp(nt.source,"g");function H(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function pe(){let e="_krypton_sid";try{if(typeof sessionStorage<"u"){let t=sessionStorage.getItem(e);return t||(t=H(),sessionStorage.setItem(e,t)),t}}catch{}return H()}function he(){let e="_krypton_did";try{if(typeof localStorage<"u"){let t=localStorage.getItem(e);return t||(t=H(),localStorage.setItem(e,t)),t}}catch{}return H()}function me(){if(typeof window>"u")return{};let e=new URLSearchParams(window.location.search),t={};for(let r of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let n=e.get(r);n&&(t[r]=n)}return t}function ge(){if(typeof window>"u")return"unknown";let e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function ve(e){if(e.id)return`#${e.id}`;let t=[],r=e;for(;r&&r!==document.body;){let n=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let i=r.className.trim().split(/\s+/).slice(0,2).join(".");i&&(n+=`.${i}`)}t.unshift(n),r=r.parentElement}return t.join(" > ")}var q=class{constructor(t){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.lastSnapshotUrl=null;this.heatmapSetup=!1;this.geoRequested=!1;this.geoContext=null;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,...t},this.distinctId=H(),this.sessionId=H(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(t){this.warn("setupTracking failed",t)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()&&this.showConsentBannerWhenReady()}catch(t){this.warn("consent banner initialization failed",t)}}))}showConsentBannerWhenReady(t=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}t<=0||setTimeout(()=>this.showConsentBannerWhenReady(t-1),50)}}resolveInitialConsent(){let t=this.loadStoredConsent();return t||{...this.config.consentRequired?{analytics:!1,heatmaps:!1,geo:!1}:{analytics:!0,heatmaps:!!this.config.heatmap,geo:!1},...this.config.consentCategories}}consentStorageKey(){return`_krypton_consent_${this.config.apiKey}`}hasStoredConsent(){try{return typeof localStorage>"u"?!1:!!localStorage.getItem(this.consentStorageKey())}catch{return!1}}loadStoredConsent(){try{if(typeof localStorage>"u")return null;let t=localStorage.getItem(this.consentStorageKey());if(!t)return null;let r=JSON.parse(t);return{analytics:!!r.analytics,heatmaps:!!r.heatmaps,geo:!!r.geo}}catch{return null}}persistConsent(){try{if(typeof localStorage>"u")return;localStorage.setItem(this.consentStorageKey(),JSON.stringify(this.consent))}catch{}}promotePersistentIds(){this.distinctId=he(),this.sessionId=pe()}canTrackAnalytics(){return!!this.consent.analytics}isHeatmapFeatureEnabled(){return!this.config.heatmap||this.configFetched&&!this.serverConfig?.heatmaps_enabled?!1:!!this.consent.heatmaps}async fetchConfig(){if(typeof window>"u")return;let t=`_krypton_config_${this.config.apiKey}`,r=null;try{r=sessionStorage.getItem(t)}catch{r=null}if(r)try{let n=JSON.parse(r);if(n._ts&&Date.now()-n._ts<300*1e3){this.serverConfig=n,this.configFetched=!0;return}}catch{}try{let n=new AbortController,i=setTimeout(()=>n.abort(),5e3),a=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:n.signal});if(clearTimeout(i),a.ok){let c=await a.json();this.serverConfig=c,this.configFetched=!0;try{sessionStorage.setItem(t,JSON.stringify({...c,_ts:Date.now()}))}catch{}}}catch{}}setupTracking(){if(this.flushTimer=setInterval(()=>{this.flush()},this.config.flushInterval),typeof window>"u")return;window.addEventListener("beforeunload",()=>{this.flush()}),this.config.autoPageview&&this.canTrackAnalytics()&&this.trackPageview();let t=history.pushState;history.pushState=(...n)=>{try{t.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("pushState hook failed",i)}};let r=history.replaceState;history.replaceState=(...n)=>{try{r.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(n){this.warn("popstate hook failed",n)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap(),this.consent.geo&&this.captureGeoOnce()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let t=document.createElement("div");t.id="krypton-consent-banner",t.style.cssText=["position:fixed","left:16px","right:16px","bottom:16px","z-index:2147483647","max-width:720px","margin:0 auto","background:#111827","color:#f9fafb","border-radius:12px","padding:16px","box-shadow:0 12px 30px rgba(0,0,0,0.35)","font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif","font-size:14px","line-height:1.4"].join(";");let r=a=>a?"checked":"";t.innerHTML=`
1
+ "use strict";var KryptonAnalytics=(()=>{var Z=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var be=Object.prototype.hasOwnProperty;var Ce=(e,t)=>{for(var r in t)Z(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Se(t))!be.call(e,i)&&i!==r&&Z(e,i,{get:()=>t[i],enumerable:!(n=ke(t,i))||n.enumerable});return e};var Ie=e=>xe(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>q,default:()=>it,init:()=>ye});var v;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(v||(v={}));function Te(e){return e.nodeType===e.ELEMENT_NODE}function Ee(e){var t=e?.host;return t?.shadowRoot===e}function ee(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function Le(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function te(e){try{var t=e.rules||e.cssRules;return t?Le(Array.from(t).map(Re).join("")):null}catch{return null}}function Re(e){var t=e.cssText;if(Ne(e))try{t=te(e.styleSheet)||t}catch{}return t}function Ne(e){return"styleSheet"in e}var _e=(function(){function e(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}return e.prototype.getId=function(t){var r;if(!t)return-1;var n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1},e.prototype.getNode=function(t){return this.idNodeMap.get(t)||null},e.prototype.getIds=function(){return Array.from(this.idNodeMap.keys())},e.prototype.getMeta=function(t){return this.nodeMetaMap.get(t)||null},e.prototype.removeNodeFromMap=function(t){var r=this,n=this.getId(t);this.idNodeMap.delete(n),t.childNodes&&t.childNodes.forEach(function(i){return r.removeNodeFromMap(i)})},e.prototype.has=function(t){return this.idNodeMap.has(t)},e.prototype.hasNode=function(t){return this.nodeMetaMap.has(t)},e.prototype.add=function(t,r){var n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var n=this.getNode(t);if(n){var i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)},e.prototype.reset=function(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap},e})();function Ae(e){var t=e.maskInputOptions,r=e.tagName,n=e.type,i=e.value,a=e.maskInputFn,c=i||"";return(t[r.toLowerCase()]||t[n])&&(a?c=a(c):c="*".repeat(c.length)),c}var le="__rrweb_original__";function Me(e){var t=e.getContext("2d");if(!t)return!0;for(var r=50,n=0;n<e.width;n+=r)for(var i=0;i<e.height;i+=r){var a=t.getImageData,c=le in a?a[le]:a,u=new Uint32Array(c.call(t,n,i,Math.min(r,e.width-n),Math.min(r,e.height-i)).data.buffer);if(u.some(function(o){return o!==0}))return!1}return!0}var Oe=1,Pe=new RegExp("[^a-z0-9-_:]"),ue=-2;function De(){return Oe++}function Fe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return Pe.test(t)?"div":t}function He(e){return e.cssRules?Array.from(e.cssRules).map(function(t){return t.cssText||""}).join(""):""}function Ue(e){var t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}var z,fe,We=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Be=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,Ke=/^(data:)([^,]*),(.*)/i;function G(e,t){return(e||"").replace(We,function(r,n,i,a,c,u){var o=i||c||u,f=n||a||"";if(!o)return r;if(!Be.test(o)||Ke.test(o))return"url(".concat(f).concat(o).concat(f,")");if(o[0]==="/")return"url(".concat(f).concat(Ue(t)+o).concat(f,")");var l=t.split("/"),p=o.split("/");l.pop();for(var b=0,w=p;b<w.length;b++){var k=w[b];k!=="."&&(k===".."?l.pop():l.push(k))}return"url(".concat(f).concat(l.join("/")).concat(f,")")})}var ze=/^[^ \t\n\r\u000c]+/,$e=/^[, \t\n\r\u000c]+/;function qe(e,t){if(t.trim()==="")return t;var r=0;function n(f){var l,p=f.exec(t.substring(r));return p?(l=p[0],r+=l.length,l):""}for(var i=[];n($e),!(r>=t.length);){var a=n(ze);if(a.slice(-1)===",")a=$(e,a.substring(0,a.length-1)),i.push(a);else{var c="";a=$(e,a);for(var u=!1;;){var o=t.charAt(r);if(o===""){i.push((a+c).trim());break}else if(u)o===")"&&(u=!1);else if(o===","){r+=1,i.push((a+c).trim());break}else o==="("&&(u=!0);c+=o,r+=1}}}return i.join(", ")}function $(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function je(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ne(){var e=document.createElement("a");return e.href="",e.href}function Qe(e,t,r,n){return r==="src"||r==="href"&&n&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n&&n[0]!=="#"||r==="background"&&n&&(t==="table"||t==="td"||t==="th")?$(e,n):r==="srcset"&&n?qe(e,n):r==="style"&&n?G(n,ne()):t==="object"&&r==="data"&&n?$(e,n):n}function Ge(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?e.matches(r):!1}function re(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?re(e.parentNode,t,r):!1;for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var n=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(n===null)return!1;if(typeof t=="string"){if(n.classList.contains(t)||n.closest(".".concat(t)))return!0}else if(re(n,t,!0))return!0;return!!(r&&(n.matches(r)||n.closest(r)))}function Ve(e,t,r){var n=e.contentWindow;if(n){var i=!1,a;try{a=n.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(c),i=!0,t()});return}var u="about:blank";if(n.location.href!==u||e.src===u||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}}function Ye(e,t,r){var n=!1,i;try{i=e.sheet}catch{return}if(!i){var a=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(a),n=!0,t()})}}function Xe(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.inlineStylesheet,f=t.maskInputOptions,l=f===void 0?{}:f,p=t.maskTextFn,b=t.maskInputFn,w=t.dataURLOptions,k=w===void 0?{}:w,x=t.inlineImages,I=t.recordCanvas,T=t.keepIframeSrcFn,h=t.newlyAddedElement,s=h===void 0?!1:h,y=Ze(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:v.Document,childNodes:[],compatMode:e.compatMode}:{type:v.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:v.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return tt(e,{doc:r,blockClass:i,blockSelector:a,inlineStylesheet:o,maskInputOptions:l,maskInputFn:b,dataURLOptions:k,inlineImages:x,recordCanvas:I,keepIframeSrcFn:T,newlyAddedElement:s,rootId:y});case e.TEXT_NODE:return et(e,{maskTextClass:c,maskTextSelector:u,maskTextFn:p,rootId:y});case e.CDATA_SECTION_NODE:return{type:v.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:v.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function Ze(e,t){if(t.hasNode(e)){var r=t.getId(e);return r===1?void 0:r}}function et(e,t){var r,n=t.maskTextClass,i=t.maskTextSelector,a=t.maskTextFn,c=t.rootId,u=e.parentNode&&e.parentNode.tagName,o=e.textContent,f=u==="STYLE"?!0:void 0,l=u==="SCRIPT"?!0:void 0;if(f&&o){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(o=He(e.parentNode.sheet))}catch(p){console.warn("Cannot get CSS styles from text's parentNode. Error: ".concat(p),e)}o=G(o,ne())}return l&&(o="SCRIPT_PLACEHOLDER"),!f&&!l&&o&&Je(e,n,i)&&(o=a?a(o):o.replace(/[\S]/g,"*")),{type:v.Text,textContent:o||"",isStyle:f,rootId:c}}function tt(e,t){for(var r=t.doc,n=t.blockClass,i=t.blockSelector,a=t.inlineStylesheet,c=t.maskInputOptions,u=c===void 0?{}:c,o=t.maskInputFn,f=t.dataURLOptions,l=f===void 0?{}:f,p=t.inlineImages,b=t.recordCanvas,w=t.keepIframeSrcFn,k=t.newlyAddedElement,x=k===void 0?!1:k,I=t.rootId,T=Ge(e,n,i),h=Fe(e),s={},y=e.attributes.length,M=0;M<y;M++){var E=e.attributes[M];s[E.name]=Qe(r,h,E.name,E.value)}if(h==="link"&&a){var C=Array.from(r.styleSheets).find(function(R){return R.href===e.href}),m=null;C&&(m=te(C)),m&&(delete s.rel,delete s.href,s._cssText=G(m,C.href))}if(h==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=G(m,ne()))}if(h==="input"||h==="textarea"||h==="select"){var F=e.value,N=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&F?s.value=Ae({type:s.type,tagName:h,value:F,maskInputOptions:u,maskInputFn:o}):N&&(s.checked=N)}if(h==="option"&&(e.selected&&!u.select?s.selected=!0:delete s.selected),h==="canvas"&&b){if(e.__context==="2d")Me(e)||(s.rr_dataURL=e.toDataURL(l.type,l.quality));else if(!("__context"in e)){var L=e.toDataURL(l.type,l.quality),O=document.createElement("canvas");O.width=e.width,O.height=e.height;var P=O.toDataURL(l.type,l.quality);L!==P&&(s.rr_dataURL=L)}}if(h==="img"&&p){z||(z=r.createElement("canvas"),fe=z.getContext("2d"));var S=e,_=S.crossOrigin;S.crossOrigin="anonymous";var D=function(){try{z.width=S.naturalWidth,z.height=S.naturalHeight,fe.drawImage(S,0,0),s.rr_dataURL=z.toDataURL(l.type,l.quality)}catch(R){console.warn("Cannot inline img src=".concat(S.currentSrc,"! Error: ").concat(R))}_?s.crossOrigin=_:S.removeAttribute("crossorigin")};S.complete&&S.naturalWidth!==0?D():S.onload=D}if((h==="audio"||h==="video")&&(s.rr_mediaState=e.paused?"paused":"played",s.rr_mediaCurrentTime=e.currentTime),x||(e.scrollLeft&&(s.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(s.rr_scrollTop=e.scrollTop)),T){var U=e.getBoundingClientRect(),W=U.width,A=U.height;s={class:s.class,rr_width:"".concat(W,"px"),rr_height:"".concat(A,"px")}}return h==="iframe"&&!w(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:v.Element,tagName:h,attributes:s,childNodes:[],isSVG:je(e)||void 0,needBlock:T,rootId:I}}function d(e){return e===void 0?"":e.toLowerCase()}function rt(e,t){if(t.comment&&e.type===v.Comment)return!0;if(e.type===v.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&e.attributes.rel==="preload"&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&e.attributes.href.endsWith(".js")))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(d(e.attributes.name).match(/^msapplication-tile(image|color)$/)||d(e.attributes.name)==="application-name"||d(e.attributes.rel)==="icon"||d(e.attributes.rel)==="apple-touch-icon"||d(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&d(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(d(e.attributes.property).match(/^(og|twitter|fb):/)||d(e.attributes.name).match(/^(og|twitter):/)||d(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(d(e.attributes.name)==="robots"||d(e.attributes.name)==="googlebot"||d(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(d(e.attributes.name)==="author"||d(e.attributes.name)==="generator"||d(e.attributes.name)==="framework"||d(e.attributes.name)==="publisher"||d(e.attributes.name)==="progid"||d(e.attributes.property).match(/^article:/)||d(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(d(e.attributes.name)==="google-site-verification"||d(e.attributes.name)==="yandex-verification"||d(e.attributes.name)==="csrf-token"||d(e.attributes.name)==="p:domain_verify"||d(e.attributes.name)==="verify-v1"||d(e.attributes.name)==="verification"||d(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function Q(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.skipChild,f=o===void 0?!1:o,l=t.inlineStylesheet,p=l===void 0?!0:l,b=t.maskInputOptions,w=b===void 0?{}:b,k=t.maskTextFn,x=t.maskInputFn,I=t.slimDOMOptions,T=t.dataURLOptions,h=T===void 0?{}:T,s=t.inlineImages,y=s===void 0?!1:s,M=t.recordCanvas,E=M===void 0?!1:M,C=t.onSerialize,m=t.onIframeLoad,F=t.iframeLoadTimeout,N=F===void 0?5e3:F,L=t.onStylesheetLoad,O=t.stylesheetLoadTimeout,P=O===void 0?5e3:O,S=t.keepIframeSrcFn,_=S===void 0?function(){return!1}:S,D=t.newlyAddedElement,U=D===void 0?!1:D,W=t.preserveWhiteSpace,A=W===void 0?!0:W,R=Xe(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,dataURLOptions:h,inlineImages:y,recordCanvas:E,keepIframeSrcFn:_,newlyAddedElement:U});if(!R)return console.warn(e,"not serialized"),null;var j;n.hasNode(e)?j=n.getId(e):rt(R,I)||!A&&R.type===v.Text&&!R.isStyle&&!R.textContent.replace(/^\s+|\s+$/gm,"").length?j=ue:j=De();var g=Object.assign(R,{id:j});if(n.add(e,g),j===ue)return null;C&&C(e);var J=!f;if(g.type===v.Element){J=J&&!g.needBlock,delete g.needBlock;var ie=e.shadowRoot;ie&&ee(ie)&&(g.isShadowHost=!0)}if((g.type===v.Document||g.type===v.Element)&&J){I.headWhitespace&&g.type===v.Element&&g.tagName==="head"&&(A=!1);for(var ae={doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:f,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:A,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:N,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:_},V=0,oe=Array.from(e.childNodes);V<oe.length;V++){var Y=oe[V],B=Q(Y,ae);B&&g.childNodes.push(B)}if(Te(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var Y=se[X],B=Q(Y,ae);B&&(ee(e.shadowRoot)&&(B.isShadow=!0),g.childNodes.push(B))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(g.isShadow=!0),g.type===v.Element&&g.tagName==="iframe"&&Ve(e,function(){var K=e.contentDocument;if(K&&m){var ce=Q(K,{doc:K,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:A,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:N,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:_});ce&&m(e,ce)}},N),g.type===v.Element&&g.tagName==="link"&&g.attributes.rel==="stylesheet"&&Ye(e,function(){if(L){var K=Q(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:A,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:N,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:_});K&&L(e,K)}},P),g}function de(e,t){var r=t||{},n=r.mirror,i=n===void 0?new _e:n,a=r.blockClass,c=a===void 0?"rr-block":a,u=r.blockSelector,o=u===void 0?null:u,f=r.maskTextClass,l=f===void 0?"rr-mask":f,p=r.maskTextSelector,b=p===void 0?null:p,w=r.inlineStylesheet,k=w===void 0?!0:w,x=r.inlineImages,I=x===void 0?!1:x,T=r.recordCanvas,h=T===void 0?!1:T,s=r.maskAllInputs,y=s===void 0?!1:s,M=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,F=r.dataURLOptions,N=r.preserveWhiteSpace,L=r.onSerialize,O=r.onIframeLoad,P=r.iframeLoadTimeout,S=r.onStylesheetLoad,_=r.stylesheetLoadTimeout,D=r.keepIframeSrcFn,U=D===void 0?function(){return!1}:D,W=y===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:y===!1?{password:!0}:y,A=m===!0||m==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:m==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:m===!1?{}:m;return Q(e,{doc:e,mirror:i,blockClass:c,blockSelector:o,maskTextClass:l,maskTextSelector:b,skipChild:!1,inlineStylesheet:k,maskInputOptions:W,maskTextFn:M,maskInputFn:E,slimDOMOptions:A,dataURLOptions:F,inlineImages:I,recordCanvas:h,preserveWhiteSpace:N,onSerialize:L,onIframeLoad:O,iframeLoadTimeout:P,onStylesheetLoad:S,stylesheetLoadTimeout:_,keepIframeSrcFn:U,newlyAddedElement:!1})}var nt=/([^\\]):hover/,st=new RegExp(nt.source,"g");function H(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function he(){let e="_krypton_sid";try{if(typeof sessionStorage<"u"){let t=sessionStorage.getItem(e);return t||(t=H(),sessionStorage.setItem(e,t)),t}}catch{}return H()}function pe(){let e="_krypton_did";try{if(typeof localStorage<"u"){let t=localStorage.getItem(e);return t||(t=H(),localStorage.setItem(e,t)),t}}catch{}return H()}function me(){if(typeof window>"u")return{};let e=new URLSearchParams(window.location.search),t={};for(let r of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let n=e.get(r);n&&(t[r]=n)}return t}function ge(){if(typeof window>"u")return"unknown";let e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function ve(e){if(e.id)return`#${e.id}`;let t=[],r=e;for(;r&&r!==document.body;){let n=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let i=r.className.trim().split(/\s+/).slice(0,2).join(".");i&&(n+=`.${i}`)}t.unshift(n),r=r.parentElement}return t.join(" > ")}var q=class{constructor(t){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.lastSnapshotUrl=null;this.heatmapSetup=!1;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,debug:!1,disableConfigCache:!1,...t},this.distinctId=H(),this.sessionId=H(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(t){this.warn("setupTracking failed",t)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()?(this.debug("showing consent banner automatically",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner}),this.showConsentBannerWhenReady()):this.debug("skipping consent banner",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner,hasStoredConsent:this.hasStoredConsent()})}catch(t){this.warn("consent banner initialization failed",t)}}))}showConsentBannerWhenReady(t=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}t<=0||setTimeout(()=>this.showConsentBannerWhenReady(t-1),50)}}resolveInitialConsent(){let t=this.loadStoredConsent();return t||{...this.config.consentRequired?{analytics:!1,heatmaps:!1}:{analytics:!0,heatmaps:!!this.config.heatmap},...this.config.consentCategories}}consentStorageKey(){return`_krypton_consent_${this.config.apiKey}`}hasStoredConsent(){try{return typeof localStorage>"u"?!1:!!localStorage.getItem(this.consentStorageKey())}catch{return!1}}loadStoredConsent(){try{if(typeof localStorage>"u")return null;let t=localStorage.getItem(this.consentStorageKey());if(!t)return null;let r=JSON.parse(t);return{analytics:!!r.analytics,heatmaps:!!r.heatmaps}}catch{return null}}persistConsent(){try{if(typeof localStorage>"u")return;localStorage.setItem(this.consentStorageKey(),JSON.stringify(this.consent))}catch{}}promotePersistentIds(){this.distinctId=pe(),this.sessionId=he()}canTrackAnalytics(){return!!this.consent.analytics}isHeatmapFeatureEnabled(){return!this.config.heatmap||this.configFetched&&!this.serverConfig?.heatmaps_enabled?!1:!!this.consent.heatmaps}async fetchConfig(){if(typeof window>"u")return;let t=`_krypton_config_${this.config.apiKey}`,r=null;if(!this.config.disableConfigCache)try{r=sessionStorage.getItem(t)}catch{r=null}if(r)try{let n=JSON.parse(r);if(n._ts&&Date.now()-n._ts<300*1e3){this.serverConfig=n,this.configFetched=!0,this.debug("config loaded from session cache",n);return}}catch{}try{let n=new AbortController,i=setTimeout(()=>n.abort(),5e3),a=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:n.signal});if(clearTimeout(i),a.ok){let c=await a.json();if(this.serverConfig=c,this.configFetched=!0,this.debug("config fetched from API",c),!this.config.disableConfigCache)try{sessionStorage.setItem(t,JSON.stringify({...c,_ts:Date.now()}))}catch{}}else this.warn(`Config fetch failed (${a.status})`,{endpoint:this.config.endpoint})}catch(n){this.warn("Config fetch failed",n)}}setupTracking(){if(this.flushTimer=setInterval(()=>{this.flush()},this.config.flushInterval),typeof window>"u")return;window.addEventListener("beforeunload",()=>{this.flush()}),this.config.autoPageview&&this.canTrackAnalytics()&&this.trackPageview();let t=history.pushState;history.pushState=(...n)=>{try{t.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("pushState hook failed",i)}};let r=history.replaceState;history.replaceState=(...n)=>{try{r.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(n){this.warn("popstate hook failed",n)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let t=document.createElement("div");t.id="krypton-consent-banner",t.style.cssText=["position:fixed","left:16px","right:16px","bottom:16px","z-index:2147483647","max-width:720px","margin:0 auto","background:#111827","color:#f9fafb","border-radius:12px","padding:16px","box-shadow:0 12px 30px rgba(0,0,0,0.35)","font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif","font-size:14px","line-height:1.4"].join(";");let r=a=>a?"checked":"";t.innerHTML=`
2
2
  <div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
3
3
  <div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
4
4
  <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
@@ -9,13 +9,9 @@
9
9
  <input type="checkbox" id="krypton-consent-heatmaps" ${r(this.consent.heatmaps)} />
10
10
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
11
11
  </label>
12
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
13
- <input type="checkbox" id="krypton-consent-geo" ${r(this.consent.geo)} />
14
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
15
- </label>
16
- <div style="display:flex;gap:8px;flex-wrap:wrap">
12
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
17
13
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
18
14
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
19
15
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
20
16
  </div>
21
- `;let n=()=>{t.remove();try{document.body&&(document.body.style.cursor=""),document.documentElement&&(document.documentElement.style.cursor="")}catch{}},i=a=>!!document.getElementById(a)?.checked;t.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{let a={analytics:i("krypton-consent-analytics"),heatmaps:i("krypton-consent-heatmaps"),geo:i("krypton-consent-geo")};n(),setTimeout(()=>this.setConsent(a),0)}),t.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!0,heatmaps:!0,geo:!0}),0)}),t.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!1,heatmaps:!1,geo:!1}),0)}),document.body.appendChild(t)}setConsent(t,r=!0){try{let n={...this.consent};this.consent={analytics:t.analytics??n.analytics,heatmaps:t.heatmaps??n.heatmaps,geo:t.geo??n.geo},r&&this.persistConsent(),!n.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),n.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!n.heatmaps&&this.isHeatmapFeatureEnabled()&&(this.setupHeatmap(),this.captureSnapshot()),n.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[]),!n.geo&&this.consent.geo&&this.captureGeoOnce()}catch(n){this.warn("setConsent failed",n)}}getConsent(){return{...this.consent}}grantConsent(){this.setConsent({analytics:!0,heatmaps:!0,geo:!0})}revokeConsent(){this.setConsent({analytics:!1,heatmaps:!1,geo:!1}),this.eventQueue=[],this.heatmapQueue=[]}identify(t){try{if(this.distinctId=t,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",t)}catch{}}catch(r){this.warn("identify failed",r)}}trackPageview(t){try{if(!this.canTrackAnalytics())return;this.track("$pageview",{...t})}catch(r){this.warn("trackPageview failed",r)}}track(t,r){try{if(!this.canTrackAnalytics())return;let n=me(),i={...r||{}};this.consent.geo&&this.geoContext&&(i.geo=this.geoContext);let a={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:t,timestamp:new Date().toISOString(),properties:i,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:n.utm_source||"",utm_medium:n.utm_medium||"",utm_campaign:n.utm_campaign||"",utm_term:n.utm_term||"",utm_content:n.utm_content||"",device_type:ge(),browser:this.getBrowser(),screen_width:typeof window<"u"?window.screen.width:0,screen_height:typeof window<"u"?window.screen.height:0,session_id:this.sessionId};this.eventQueue.push(a),this.eventQueue.length>=this.config.batchSize&&this.flush()}catch(n){this.warn("track failed",n)}}async flush(){try{await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}catch(t){this.warn("flush failed",t)}}shutdown(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush()}captureGeoOnce(){this.geoRequested||this.consent.geo&&(typeof navigator>"u"||!navigator.geolocation||(this.geoRequested=!0,navigator.geolocation.getCurrentPosition(t=>{let r=(n,i=3)=>Number(n.toFixed(i));this.geoContext={lat:r(t.coords.latitude),lon:r(t.coords.longitude),accuracy_m:Math.round(t.coords.accuracy),captured_at:new Date().toISOString()}},()=>{},{enableHighAccuracy:!1,maximumAge:600*1e3,timeout:5e3})))}async flushEvents(){if(this.eventQueue.length===0)return;let t=this.eventQueue.splice(0,this.eventQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/ingest/batch`,r)||this.eventQueue.length<this.config.batchSize*5&&this.eventQueue.unshift(...t)}async flushHeatmapEvents(){if(this.heatmapQueue.length===0)return;let t=this.heatmapQueue.splice(0,this.heatmapQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/heatmap`,r)||this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...t)}captureSnapshot(){if(typeof window>"u"||typeof document>"u"||!this.isHeatmapFeatureEnabled())return;let t=window.location.href;this.lastSnapshotUrl!==t&&(this.lastSnapshotUrl=t,setTimeout(()=>{try{let r=de(document,{maskAllInputs:!0,blockSelector:"[data-krypton-block]",inlineStylesheet:!0});if(!r)return;let n=JSON.stringify(r),i={api_key:this.config.apiKey,page_url:t,snapshot:n,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,timestamp:new Date().toISOString()};this.safePost(`${this.config.endpoint}/api/v1/snapshot`,i)}catch{}},1e3))}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,this.captureSnapshot(),document.addEventListener("click",n=>{if(this.isHeatmapFeatureEnabled())try{let i=n.target;this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"click",x:n.clientX+window.scrollX,y:n.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:ve(i)})}catch(i){this.warn("heatmap click capture failed",i)}});let t=0,r=null;window.addEventListener("scroll",()=>{if(this.isHeatmapFeatureEnabled())try{let n=window.scrollY||document.documentElement.scrollTop,i=document.documentElement.scrollHeight-window.innerHeight,a=i>0?n/i*100:0;a>t&&(t=a),r&&clearTimeout(r),r=setTimeout(()=>{this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"scroll",scroll_depth:t,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight})},500)}catch(n){this.warn("heatmap scroll capture failed",n)}})}async safePost(t,r){try{let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0});return n.ok?!0:(this.warn(`API request failed (${n.status})`,{url:t}),!1)}catch(n){return this.warn("API request failed",{url:t,err:n}),!1}}warn(t,r){try{console.warn(`${this.logPrefix} ${t}`,r??"")}catch{}}getBrowser(){if(typeof navigator>"u")return"unknown";let t=navigator.userAgent;return t.includes("Firefox")?"Firefox":t.includes("Edg")?"Edge":t.includes("Chrome")?"Chrome":t.includes("Safari")?"Safari":"Other"}};function ye(e){return new q(e)}var we={Krypton:q,init:ye};typeof window<"u"&&(window.KryptonAnalytics=we);var it=we;return Ie(at);})();
17
+ `;let n=()=>{t.remove();try{document.body&&(document.body.style.cursor=""),document.documentElement&&(document.documentElement.style.cursor="")}catch{}},i=a=>!!document.getElementById(a)?.checked;t.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{let a={analytics:i("krypton-consent-analytics"),heatmaps:i("krypton-consent-heatmaps")};n(),setTimeout(()=>this.setConsent(a),0)}),t.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!0,heatmaps:!0}),0)}),t.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{n(),setTimeout(()=>this.setConsent({analytics:!1,heatmaps:!1}),0)}),document.body.appendChild(t)}setConsent(t,r=!0){try{let n={...this.consent};this.consent={analytics:t.analytics??n.analytics,heatmaps:t.heatmaps??n.heatmaps},r&&this.persistConsent(),!n.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),n.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!n.heatmaps&&this.isHeatmapFeatureEnabled()&&(this.setupHeatmap(),this.captureSnapshot()),n.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[])}catch(n){this.warn("setConsent failed",n)}}getConsent(){return{...this.consent}}grantConsent(){this.setConsent({analytics:!0,heatmaps:!0})}revokeConsent(){this.setConsent({analytics:!1,heatmaps:!1}),this.eventQueue=[],this.heatmapQueue=[]}identify(t){try{if(this.distinctId=t,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",t)}catch{}}catch(r){this.warn("identify failed",r)}}trackPageview(t){try{if(!this.canTrackAnalytics())return;this.track("$pageview",{...t})}catch(r){this.warn("trackPageview failed",r)}}track(t,r){try{if(!this.canTrackAnalytics())return;let n=me(),i={...r||{}},a={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:t,timestamp:new Date().toISOString(),properties:i,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:n.utm_source||"",utm_medium:n.utm_medium||"",utm_campaign:n.utm_campaign||"",utm_term:n.utm_term||"",utm_content:n.utm_content||"",device_type:ge(),browser:this.getBrowser(),screen_width:typeof window<"u"?window.screen.width:0,screen_height:typeof window<"u"?window.screen.height:0,session_id:this.sessionId};this.eventQueue.push(a),this.eventQueue.length>=this.config.batchSize&&this.flush()}catch(n){this.warn("track failed",n)}}async flush(){try{await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}catch(t){this.warn("flush failed",t)}}shutdown(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush()}async flushEvents(){if(this.eventQueue.length===0)return;let t=this.eventQueue.splice(0,this.eventQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/ingest/batch`,r)||this.eventQueue.length<this.config.batchSize*5&&this.eventQueue.unshift(...t)}async flushHeatmapEvents(){if(this.heatmapQueue.length===0)return;let t=this.heatmapQueue.splice(0,this.heatmapQueue.length),r={api_key:this.config.apiKey,events:t};await this.safePost(`${this.config.endpoint}/api/v1/heatmap`,r)||this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...t)}captureSnapshot(){if(typeof window>"u"||typeof document>"u"||!this.isHeatmapFeatureEnabled())return;let t=window.location.href;this.lastSnapshotUrl!==t&&(this.lastSnapshotUrl=t,setTimeout(()=>{try{let r=de(document,{maskAllInputs:!0,blockSelector:"[data-krypton-block]",inlineStylesheet:!0});if(!r)return;let n=JSON.stringify(r),i={api_key:this.config.apiKey,page_url:t,snapshot:n,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,timestamp:new Date().toISOString()};this.safePost(`${this.config.endpoint}/api/v1/snapshot`,i)}catch{}},1e3))}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,this.captureSnapshot(),document.addEventListener("click",n=>{if(this.isHeatmapFeatureEnabled())try{let i=n.target;this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"click",x:n.clientX+window.scrollX,y:n.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:ve(i)})}catch(i){this.warn("heatmap click capture failed",i)}});let t=0,r=null;window.addEventListener("scroll",()=>{if(this.isHeatmapFeatureEnabled())try{let n=window.scrollY||document.documentElement.scrollTop,i=document.documentElement.scrollHeight-window.innerHeight,a=i>0?n/i*100:0;a>t&&(t=a),r&&clearTimeout(r),r=setTimeout(()=>{this.heatmapQueue.push({project_id:this.config.apiKey,distinct_id:this.distinctId,session_id:this.sessionId,timestamp:new Date().toISOString(),page_url:window.location.href,interaction_type:"scroll",scroll_depth:t,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight})},500)}catch(n){this.warn("heatmap scroll capture failed",n)}})}async safePost(t,r){try{let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0});return n.ok?!0:(this.warn(`API request failed (${n.status})`,{url:t}),!1)}catch(n){return this.warn("API request failed",{url:t,err:n}),!1}}warn(t,r){try{console.warn(`${this.logPrefix} ${t}`,r??"")}catch{}}debug(t,r){if(this.config.debug)try{console.log(`${this.logPrefix} ${t}`,r??"")}catch{}}getBrowser(){if(typeof navigator>"u")return"unknown";let t=navigator.userAgent;return t.includes("Firefox")?"Firefox":t.includes("Edg")?"Edge":t.includes("Chrome")?"Chrome":t.includes("Safari")?"Safari":"Other"}};function ye(e){return new q(e)}var we={Krypton:q,init:ye};typeof window<"u"&&(window.KryptonAnalytics=we);var it=we;return Ie(at);})();
package/dist/index.d.mts CHANGED
@@ -17,12 +17,15 @@ interface KryptonConfig {
17
17
  flushInterval?: number;
18
18
  /** Max events per batch (default: 20) */
19
19
  batchSize?: number;
20
+ /** Enable verbose SDK debug logs (default: false) */
21
+ debug?: boolean;
22
+ /** Disable SDK config cache and fetch project config on each init (default: false) */
23
+ disableConfigCache?: boolean;
20
24
  }
21
- type ConsentCategory = "analytics" | "heatmaps" | "geo";
25
+ type ConsentCategory = "analytics" | "heatmaps";
22
26
  interface ConsentPreferences {
23
27
  analytics: boolean;
24
28
  heatmaps: boolean;
25
- geo: boolean;
26
29
  }
27
30
  interface EventPayload {
28
31
  project_id: string;
@@ -74,8 +77,6 @@ declare class Krypton {
74
77
  private initialized;
75
78
  private lastSnapshotUrl;
76
79
  private heatmapSetup;
77
- private geoRequested;
78
- private geoContext;
79
80
  private consent;
80
81
  private serverConfig;
81
82
  private configFetched;
@@ -93,7 +94,7 @@ declare class Krypton {
93
94
  private isHeatmapFeatureEnabled;
94
95
  private fetchConfig;
95
96
  private setupTracking;
96
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
97
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
97
98
  showConsentBanner(): void;
98
99
  /** Set one or more consent categories and apply changes immediately. */
99
100
  setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
@@ -110,13 +111,13 @@ declare class Krypton {
110
111
  track(eventName: string, properties?: Record<string, unknown>): void;
111
112
  flush(): Promise<void>;
112
113
  shutdown(): void;
113
- private captureGeoOnce;
114
114
  private flushEvents;
115
115
  private flushHeatmapEvents;
116
116
  private captureSnapshot;
117
117
  private setupHeatmap;
118
118
  private safePost;
119
119
  private warn;
120
+ private debug;
120
121
  private getBrowser;
121
122
  }
122
123
  declare function createKrypton(config: KryptonConfig): Krypton;
package/dist/index.d.ts CHANGED
@@ -17,12 +17,15 @@ interface KryptonConfig {
17
17
  flushInterval?: number;
18
18
  /** Max events per batch (default: 20) */
19
19
  batchSize?: number;
20
+ /** Enable verbose SDK debug logs (default: false) */
21
+ debug?: boolean;
22
+ /** Disable SDK config cache and fetch project config on each init (default: false) */
23
+ disableConfigCache?: boolean;
20
24
  }
21
- type ConsentCategory = "analytics" | "heatmaps" | "geo";
25
+ type ConsentCategory = "analytics" | "heatmaps";
22
26
  interface ConsentPreferences {
23
27
  analytics: boolean;
24
28
  heatmaps: boolean;
25
- geo: boolean;
26
29
  }
27
30
  interface EventPayload {
28
31
  project_id: string;
@@ -74,8 +77,6 @@ declare class Krypton {
74
77
  private initialized;
75
78
  private lastSnapshotUrl;
76
79
  private heatmapSetup;
77
- private geoRequested;
78
- private geoContext;
79
80
  private consent;
80
81
  private serverConfig;
81
82
  private configFetched;
@@ -93,7 +94,7 @@ declare class Krypton {
93
94
  private isHeatmapFeatureEnabled;
94
95
  private fetchConfig;
95
96
  private setupTracking;
96
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
97
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
97
98
  showConsentBanner(): void;
98
99
  /** Set one or more consent categories and apply changes immediately. */
99
100
  setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
@@ -110,13 +111,13 @@ declare class Krypton {
110
111
  track(eventName: string, properties?: Record<string, unknown>): void;
111
112
  flush(): Promise<void>;
112
113
  shutdown(): void;
113
- private captureGeoOnce;
114
114
  private flushEvents;
115
115
  private flushHeatmapEvents;
116
116
  private captureSnapshot;
117
117
  private setupHeatmap;
118
118
  private safePost;
119
119
  private warn;
120
+ private debug;
120
121
  private getBrowser;
121
122
  }
122
123
  declare function createKrypton(config: KryptonConfig): Krypton;
package/dist/index.js CHANGED
@@ -113,8 +113,6 @@ var Krypton = class {
113
113
  this.initialized = false;
114
114
  this.lastSnapshotUrl = null;
115
115
  this.heatmapSetup = false;
116
- this.geoRequested = false;
117
- this.geoContext = null;
118
116
  this.serverConfig = null;
119
117
  this.configFetched = false;
120
118
  this.logPrefix = "[Krypton SDK]";
@@ -126,6 +124,8 @@ var Krypton = class {
126
124
  consentCategories: {},
127
125
  flushInterval: 5e3,
128
126
  batchSize: 20,
127
+ debug: false,
128
+ disableConfigCache: false,
129
129
  ...config
130
130
  };
131
131
  this.distinctId = generateId();
@@ -147,7 +147,17 @@ var Krypton = class {
147
147
  }
148
148
  try {
149
149
  if (this.config.consentRequired && this.config.showConsentBanner && !this.hasStoredConsent()) {
150
+ this.debug("showing consent banner automatically", {
151
+ consentRequired: this.config.consentRequired,
152
+ showConsentBanner: this.config.showConsentBanner
153
+ });
150
154
  this.showConsentBannerWhenReady();
155
+ } else {
156
+ this.debug("skipping consent banner", {
157
+ consentRequired: this.config.consentRequired,
158
+ showConsentBanner: this.config.showConsentBanner,
159
+ hasStoredConsent: this.hasStoredConsent()
160
+ });
151
161
  }
152
162
  } catch (err) {
153
163
  this.warn("consent banner initialization failed", err);
@@ -167,10 +177,9 @@ var Krypton = class {
167
177
  resolveInitialConsent() {
168
178
  const stored = this.loadStoredConsent();
169
179
  if (stored) return stored;
170
- const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
180
+ const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
171
181
  analytics: true,
172
- heatmaps: !!this.config.heatmap,
173
- geo: false
182
+ heatmaps: !!this.config.heatmap
174
183
  };
175
184
  return {
176
185
  ...base,
@@ -196,8 +205,7 @@ var Krypton = class {
196
205
  const parsed = JSON.parse(raw);
197
206
  return {
198
207
  analytics: !!parsed.analytics,
199
- heatmaps: !!parsed.heatmaps,
200
- geo: !!parsed.geo
208
+ heatmaps: !!parsed.heatmaps
201
209
  };
202
210
  } catch {
203
211
  return null;
@@ -226,10 +234,12 @@ var Krypton = class {
226
234
  if (typeof window === "undefined") return;
227
235
  const cacheKey = `_krypton_config_${this.config.apiKey}`;
228
236
  let cached = null;
229
- try {
230
- cached = sessionStorage.getItem(cacheKey);
231
- } catch {
232
- cached = null;
237
+ if (!this.config.disableConfigCache) {
238
+ try {
239
+ cached = sessionStorage.getItem(cacheKey);
240
+ } catch {
241
+ cached = null;
242
+ }
233
243
  }
234
244
  if (cached) {
235
245
  try {
@@ -237,6 +247,7 @@ var Krypton = class {
237
247
  if (parsed._ts && Date.now() - parsed._ts < 5 * 60 * 1e3) {
238
248
  this.serverConfig = parsed;
239
249
  this.configFetched = true;
250
+ this.debug("config loaded from session cache", parsed);
240
251
  return;
241
252
  }
242
253
  } catch {
@@ -254,12 +265,18 @@ var Krypton = class {
254
265
  const data = await res.json();
255
266
  this.serverConfig = data;
256
267
  this.configFetched = true;
257
- try {
258
- sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
259
- } catch {
268
+ this.debug("config fetched from API", data);
269
+ if (!this.config.disableConfigCache) {
270
+ try {
271
+ sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
272
+ } catch {
273
+ }
260
274
  }
275
+ } else {
276
+ this.warn(`Config fetch failed (${res.status})`, { endpoint: this.config.endpoint });
261
277
  }
262
- } catch {
278
+ } catch (err) {
279
+ this.warn("Config fetch failed", err);
263
280
  }
264
281
  }
265
282
  setupTracking() {
@@ -316,11 +333,8 @@ var Krypton = class {
316
333
  if (this.isHeatmapFeatureEnabled()) {
317
334
  this.setupHeatmap();
318
335
  }
319
- if (this.consent.geo) {
320
- this.captureGeoOnce();
321
- }
322
336
  }
323
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
337
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
324
338
  showConsentBanner() {
325
339
  if (typeof document === "undefined") return;
326
340
  if (document.getElementById("krypton-consent-banner")) return;
@@ -355,11 +369,7 @@ var Krypton = class {
355
369
  <input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
356
370
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
357
371
  </label>
358
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
359
- <input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
360
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
361
- </label>
362
- <div style="display:flex;gap:8px;flex-wrap:wrap">
372
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
363
373
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
364
374
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
365
375
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
@@ -380,19 +390,18 @@ var Krypton = class {
380
390
  banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
381
391
  const next = {
382
392
  analytics: readValue("krypton-consent-analytics"),
383
- heatmaps: readValue("krypton-consent-heatmaps"),
384
- geo: readValue("krypton-consent-geo")
393
+ heatmaps: readValue("krypton-consent-heatmaps")
385
394
  };
386
395
  remove();
387
396
  setTimeout(() => this.setConsent(next), 0);
388
397
  });
389
398
  banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
390
399
  remove();
391
- setTimeout(() => this.setConsent({ analytics: true, heatmaps: true, geo: true }), 0);
400
+ setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
392
401
  });
393
402
  banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
394
403
  remove();
395
- setTimeout(() => this.setConsent({ analytics: false, heatmaps: false, geo: false }), 0);
404
+ setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
396
405
  });
397
406
  document.body.appendChild(banner);
398
407
  }
@@ -402,8 +411,7 @@ var Krypton = class {
402
411
  const prev = { ...this.consent };
403
412
  this.consent = {
404
413
  analytics: next.analytics ?? prev.analytics,
405
- heatmaps: next.heatmaps ?? prev.heatmaps,
406
- geo: next.geo ?? prev.geo
414
+ heatmaps: next.heatmaps ?? prev.heatmaps
407
415
  };
408
416
  if (persist) {
409
417
  this.persistConsent();
@@ -424,9 +432,6 @@ var Krypton = class {
424
432
  if (prev.heatmaps && !this.consent.heatmaps) {
425
433
  this.heatmapQueue = [];
426
434
  }
427
- if (!prev.geo && this.consent.geo) {
428
- this.captureGeoOnce();
429
- }
430
435
  } catch (err) {
431
436
  this.warn("setConsent failed", err);
432
437
  }
@@ -436,11 +441,11 @@ var Krypton = class {
436
441
  }
437
442
  /** Backward-compatible: grant all categories. */
438
443
  grantConsent() {
439
- this.setConsent({ analytics: true, heatmaps: true, geo: true });
444
+ this.setConsent({ analytics: true, heatmaps: true });
440
445
  }
441
446
  /** Backward-compatible: revoke all categories and clear queues. */
442
447
  revokeConsent() {
443
- this.setConsent({ analytics: false, heatmaps: false, geo: false });
448
+ this.setConsent({ analytics: false, heatmaps: false });
444
449
  this.eventQueue = [];
445
450
  this.heatmapQueue = [];
446
451
  }
@@ -477,9 +482,6 @@ var Krypton = class {
477
482
  if (!this.canTrackAnalytics()) return;
478
483
  const utm = getUTMParams();
479
484
  const mergedProperties = { ...properties || {} };
480
- if (this.consent.geo && this.geoContext) {
481
- mergedProperties.geo = this.geoContext;
482
- }
483
485
  const event = {
484
486
  project_id: this.config.apiKey,
485
487
  distinct_id: this.distinctId,
@@ -522,30 +524,6 @@ var Krypton = class {
522
524
  }
523
525
  void this.flush();
524
526
  }
525
- captureGeoOnce() {
526
- if (this.geoRequested) return;
527
- if (!this.consent.geo) return;
528
- if (typeof navigator === "undefined" || !navigator.geolocation) return;
529
- this.geoRequested = true;
530
- navigator.geolocation.getCurrentPosition(
531
- (pos) => {
532
- const round = (value, precision = 3) => Number(value.toFixed(precision));
533
- this.geoContext = {
534
- lat: round(pos.coords.latitude),
535
- lon: round(pos.coords.longitude),
536
- accuracy_m: Math.round(pos.coords.accuracy),
537
- captured_at: (/* @__PURE__ */ new Date()).toISOString()
538
- };
539
- },
540
- () => {
541
- },
542
- {
543
- enableHighAccuracy: false,
544
- maximumAge: 10 * 60 * 1e3,
545
- timeout: 5e3
546
- }
547
- );
548
- }
549
527
  async flushEvents() {
550
528
  if (this.eventQueue.length === 0) return;
551
529
  const events = this.eventQueue.splice(0, this.eventQueue.length);
@@ -688,6 +666,13 @@ var Krypton = class {
688
666
  } catch {
689
667
  }
690
668
  }
669
+ debug(message, details) {
670
+ if (!this.config.debug) return;
671
+ try {
672
+ console.log(`${this.logPrefix} ${message}`, details ?? "");
673
+ } catch {
674
+ }
675
+ }
691
676
  getBrowser() {
692
677
  if (typeof navigator === "undefined") return "unknown";
693
678
  const ua = navigator.userAgent;
package/dist/index.mjs CHANGED
@@ -88,8 +88,6 @@ var Krypton = class {
88
88
  this.initialized = false;
89
89
  this.lastSnapshotUrl = null;
90
90
  this.heatmapSetup = false;
91
- this.geoRequested = false;
92
- this.geoContext = null;
93
91
  this.serverConfig = null;
94
92
  this.configFetched = false;
95
93
  this.logPrefix = "[Krypton SDK]";
@@ -101,6 +99,8 @@ var Krypton = class {
101
99
  consentCategories: {},
102
100
  flushInterval: 5e3,
103
101
  batchSize: 20,
102
+ debug: false,
103
+ disableConfigCache: false,
104
104
  ...config
105
105
  };
106
106
  this.distinctId = generateId();
@@ -122,7 +122,17 @@ var Krypton = class {
122
122
  }
123
123
  try {
124
124
  if (this.config.consentRequired && this.config.showConsentBanner && !this.hasStoredConsent()) {
125
+ this.debug("showing consent banner automatically", {
126
+ consentRequired: this.config.consentRequired,
127
+ showConsentBanner: this.config.showConsentBanner
128
+ });
125
129
  this.showConsentBannerWhenReady();
130
+ } else {
131
+ this.debug("skipping consent banner", {
132
+ consentRequired: this.config.consentRequired,
133
+ showConsentBanner: this.config.showConsentBanner,
134
+ hasStoredConsent: this.hasStoredConsent()
135
+ });
126
136
  }
127
137
  } catch (err) {
128
138
  this.warn("consent banner initialization failed", err);
@@ -142,10 +152,9 @@ var Krypton = class {
142
152
  resolveInitialConsent() {
143
153
  const stored = this.loadStoredConsent();
144
154
  if (stored) return stored;
145
- const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
155
+ const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
146
156
  analytics: true,
147
- heatmaps: !!this.config.heatmap,
148
- geo: false
157
+ heatmaps: !!this.config.heatmap
149
158
  };
150
159
  return {
151
160
  ...base,
@@ -171,8 +180,7 @@ var Krypton = class {
171
180
  const parsed = JSON.parse(raw);
172
181
  return {
173
182
  analytics: !!parsed.analytics,
174
- heatmaps: !!parsed.heatmaps,
175
- geo: !!parsed.geo
183
+ heatmaps: !!parsed.heatmaps
176
184
  };
177
185
  } catch {
178
186
  return null;
@@ -201,10 +209,12 @@ var Krypton = class {
201
209
  if (typeof window === "undefined") return;
202
210
  const cacheKey = `_krypton_config_${this.config.apiKey}`;
203
211
  let cached = null;
204
- try {
205
- cached = sessionStorage.getItem(cacheKey);
206
- } catch {
207
- cached = null;
212
+ if (!this.config.disableConfigCache) {
213
+ try {
214
+ cached = sessionStorage.getItem(cacheKey);
215
+ } catch {
216
+ cached = null;
217
+ }
208
218
  }
209
219
  if (cached) {
210
220
  try {
@@ -212,6 +222,7 @@ var Krypton = class {
212
222
  if (parsed._ts && Date.now() - parsed._ts < 5 * 60 * 1e3) {
213
223
  this.serverConfig = parsed;
214
224
  this.configFetched = true;
225
+ this.debug("config loaded from session cache", parsed);
215
226
  return;
216
227
  }
217
228
  } catch {
@@ -229,12 +240,18 @@ var Krypton = class {
229
240
  const data = await res.json();
230
241
  this.serverConfig = data;
231
242
  this.configFetched = true;
232
- try {
233
- sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
234
- } catch {
243
+ this.debug("config fetched from API", data);
244
+ if (!this.config.disableConfigCache) {
245
+ try {
246
+ sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
247
+ } catch {
248
+ }
235
249
  }
250
+ } else {
251
+ this.warn(`Config fetch failed (${res.status})`, { endpoint: this.config.endpoint });
236
252
  }
237
- } catch {
253
+ } catch (err) {
254
+ this.warn("Config fetch failed", err);
238
255
  }
239
256
  }
240
257
  setupTracking() {
@@ -291,11 +308,8 @@ var Krypton = class {
291
308
  if (this.isHeatmapFeatureEnabled()) {
292
309
  this.setupHeatmap();
293
310
  }
294
- if (this.consent.geo) {
295
- this.captureGeoOnce();
296
- }
297
311
  }
298
- /** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
312
+ /** Built-in consent popup with category toggles (analytics, heatmaps). */
299
313
  showConsentBanner() {
300
314
  if (typeof document === "undefined") return;
301
315
  if (document.getElementById("krypton-consent-banner")) return;
@@ -330,11 +344,7 @@ var Krypton = class {
330
344
  <input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
331
345
  <span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
332
346
  </label>
333
- <label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
334
- <input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
335
- <span><strong>Geo location</strong> (browser geolocation if available)</span>
336
- </label>
337
- <div style="display:flex;gap:8px;flex-wrap:wrap">
347
+ <div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
338
348
  <button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
339
349
  <button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
340
350
  <button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
@@ -355,19 +365,18 @@ var Krypton = class {
355
365
  banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
356
366
  const next = {
357
367
  analytics: readValue("krypton-consent-analytics"),
358
- heatmaps: readValue("krypton-consent-heatmaps"),
359
- geo: readValue("krypton-consent-geo")
368
+ heatmaps: readValue("krypton-consent-heatmaps")
360
369
  };
361
370
  remove();
362
371
  setTimeout(() => this.setConsent(next), 0);
363
372
  });
364
373
  banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
365
374
  remove();
366
- setTimeout(() => this.setConsent({ analytics: true, heatmaps: true, geo: true }), 0);
375
+ setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
367
376
  });
368
377
  banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
369
378
  remove();
370
- setTimeout(() => this.setConsent({ analytics: false, heatmaps: false, geo: false }), 0);
379
+ setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
371
380
  });
372
381
  document.body.appendChild(banner);
373
382
  }
@@ -377,8 +386,7 @@ var Krypton = class {
377
386
  const prev = { ...this.consent };
378
387
  this.consent = {
379
388
  analytics: next.analytics ?? prev.analytics,
380
- heatmaps: next.heatmaps ?? prev.heatmaps,
381
- geo: next.geo ?? prev.geo
389
+ heatmaps: next.heatmaps ?? prev.heatmaps
382
390
  };
383
391
  if (persist) {
384
392
  this.persistConsent();
@@ -399,9 +407,6 @@ var Krypton = class {
399
407
  if (prev.heatmaps && !this.consent.heatmaps) {
400
408
  this.heatmapQueue = [];
401
409
  }
402
- if (!prev.geo && this.consent.geo) {
403
- this.captureGeoOnce();
404
- }
405
410
  } catch (err) {
406
411
  this.warn("setConsent failed", err);
407
412
  }
@@ -411,11 +416,11 @@ var Krypton = class {
411
416
  }
412
417
  /** Backward-compatible: grant all categories. */
413
418
  grantConsent() {
414
- this.setConsent({ analytics: true, heatmaps: true, geo: true });
419
+ this.setConsent({ analytics: true, heatmaps: true });
415
420
  }
416
421
  /** Backward-compatible: revoke all categories and clear queues. */
417
422
  revokeConsent() {
418
- this.setConsent({ analytics: false, heatmaps: false, geo: false });
423
+ this.setConsent({ analytics: false, heatmaps: false });
419
424
  this.eventQueue = [];
420
425
  this.heatmapQueue = [];
421
426
  }
@@ -452,9 +457,6 @@ var Krypton = class {
452
457
  if (!this.canTrackAnalytics()) return;
453
458
  const utm = getUTMParams();
454
459
  const mergedProperties = { ...properties || {} };
455
- if (this.consent.geo && this.geoContext) {
456
- mergedProperties.geo = this.geoContext;
457
- }
458
460
  const event = {
459
461
  project_id: this.config.apiKey,
460
462
  distinct_id: this.distinctId,
@@ -497,30 +499,6 @@ var Krypton = class {
497
499
  }
498
500
  void this.flush();
499
501
  }
500
- captureGeoOnce() {
501
- if (this.geoRequested) return;
502
- if (!this.consent.geo) return;
503
- if (typeof navigator === "undefined" || !navigator.geolocation) return;
504
- this.geoRequested = true;
505
- navigator.geolocation.getCurrentPosition(
506
- (pos) => {
507
- const round = (value, precision = 3) => Number(value.toFixed(precision));
508
- this.geoContext = {
509
- lat: round(pos.coords.latitude),
510
- lon: round(pos.coords.longitude),
511
- accuracy_m: Math.round(pos.coords.accuracy),
512
- captured_at: (/* @__PURE__ */ new Date()).toISOString()
513
- };
514
- },
515
- () => {
516
- },
517
- {
518
- enableHighAccuracy: false,
519
- maximumAge: 10 * 60 * 1e3,
520
- timeout: 5e3
521
- }
522
- );
523
- }
524
502
  async flushEvents() {
525
503
  if (this.eventQueue.length === 0) return;
526
504
  const events = this.eventQueue.splice(0, this.eventQueue.length);
@@ -663,6 +641,13 @@ var Krypton = class {
663
641
  } catch {
664
642
  }
665
643
  }
644
+ debug(message, details) {
645
+ if (!this.config.debug) return;
646
+ try {
647
+ console.log(`${this.logPrefix} ${message}`, details ?? "");
648
+ } catch {
649
+ }
650
+ }
666
651
  getBrowser() {
667
652
  if (typeof navigator === "undefined") return "unknown";
668
653
  const ua = navigator.userAgent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kryptonhq/analytics",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Krypton Analytics JavaScript SDK — privacy-first analytics tracking",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",