@kryptonhq/analytics 0.1.0 → 0.1.2
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 +34 -1
- package/dist/browser.global.js +21 -1
- package/dist/index.d.mts +31 -6
- package/dist/index.d.ts +31 -6
- package/dist/index.js +287 -64
- package/dist/index.mjs +287 -64
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ const krypton = new Krypton({
|
|
|
16
16
|
endpoint: "https://ingest.yourdomain.com",
|
|
17
17
|
autoPageview: true,
|
|
18
18
|
heatmap: true,
|
|
19
|
+
consentRequired: true,
|
|
20
|
+
showConsentBanner: true,
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
krypton.track("signup_clicked", { plan: "pro" });
|
|
@@ -33,7 +35,9 @@ Use jsDelivr:
|
|
|
33
35
|
apiKey: "kapi_xxx",
|
|
34
36
|
endpoint: "https://ingest.yourdomain.com",
|
|
35
37
|
autoPageview: true,
|
|
36
|
-
heatmap: true
|
|
38
|
+
heatmap: true,
|
|
39
|
+
consentRequired: true,
|
|
40
|
+
showConsentBanner: true
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
krypton.track("page_loaded");
|
|
@@ -43,6 +47,35 @@ Use jsDelivr:
|
|
|
43
47
|
|
|
44
48
|
The CDN build exposes a global: `window.KryptonAnalytics`.
|
|
45
49
|
|
|
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)
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { Krypton } from "@kryptonhq/analytics";
|
|
62
|
+
|
|
63
|
+
const krypton = new Krypton({
|
|
64
|
+
apiKey: "kapi_xxx",
|
|
65
|
+
endpoint: "https://ingest.yourdomain.com",
|
|
66
|
+
heatmap: true,
|
|
67
|
+
consentRequired: true, // default deny
|
|
68
|
+
showConsentBanner: true, // built-in popup
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Optional manual control
|
|
72
|
+
krypton.setConsent({
|
|
73
|
+
analytics: true,
|
|
74
|
+
heatmaps: false,
|
|
75
|
+
geo: false,
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
46
79
|
### GA-style bootstrap snippet (single paste)
|
|
47
80
|
|
|
48
81
|
```html
|
package/dist/browser.global.js
CHANGED
|
@@ -1 +1,21 @@
|
|
|
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})},Ie=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Se(t))!be.call(e,n)&&n!==r&&Z(e,n,{get:()=>t[n],enumerable:!(i=ke(t,n))||i.enumerable});return e};var Te=e=>Ie(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>K,default:()=>nt,init:()=>ye});var g;(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"})(g||(g={}));function xe(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(Ne).join("")):null}catch{return null}}function Ne(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 Re=(function(){function e(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}return e.prototype.getId=function(t){var r;if(!t)return-1;var i=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return i??-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,i=this.getId(t);this.idNodeMap.delete(i),t.childNodes&&t.childNodes.forEach(function(n){return r.removeNodeFromMap(n)})},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 i=r.id;this.idNodeMap.set(i,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var i=this.getNode(t);if(i){var n=this.nodeMetaMap.get(i);n&&this.nodeMetaMap.set(r,n)}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,i=e.type,n=e.value,a=e.maskInputFn,c=n||"";return(t[r.toLowerCase()]||t[i])&&(a?c=a(c):c="*".repeat(c.length)),c}var ue="__rrweb_original__";function Me(e){var t=e.getContext("2d");if(!t)return!0;for(var r=50,i=0;i<e.width;i+=r)for(var n=0;n<e.height;n+=r){var a=t.getImageData,c=ue in a?a[ue]:a,l=new Uint32Array(c.call(t,i,n,Math.min(r,e.width-i),Math.min(r,e.height-n)).data.buffer);if(l.some(function(o){return o!==0}))return!1}return!0}var De=1,Ae=new RegExp("[^a-z0-9-_:]"),le=-2;function Fe(){return De++}function Pe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return Ae.test(t)?"div":t}function Ue(e){return e.cssRules?Array.from(e.cssRules).map(function(t){return t.cssText||""}).join(""):""}function He(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,Ge=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,ze=/^(data:)([^,]*),(.*)/i;function $(e,t){return(e||"").replace(We,function(r,i,n,a,c,l){var o=n||c||l,f=i||a||"";if(!o)return r;if(!Ge.test(o)||ze.test(o))return"url(".concat(f).concat(o).concat(f,")");if(o[0]==="/")return"url(".concat(f).concat(He(t)+o).concat(f,")");var u=t.split("/"),p=o.split("/");u.pop();for(var b=0,w=p;b<w.length;b++){var k=w[b];k!=="."&&(k===".."?u.pop():u.push(k))}return"url(".concat(f).concat(u.join("/")).concat(f,")")})}var je=/^[^ \t\n\r\u000c]+/,Ke=/^[, \t\n\r\u000c]+/;function Be(e,t){if(t.trim()==="")return t;var r=0;function i(f){var u,p=f.exec(t.substring(r));return p?(u=p[0],r+=u.length,u):""}for(var n=[];i(Ke),!(r>=t.length);){var a=i(je);if(a.slice(-1)===",")a=j(e,a.substring(0,a.length-1)),n.push(a);else{var c="";a=j(e,a);for(var l=!1;;){var o=t.charAt(r);if(o===""){n.push((a+c).trim());break}else if(l)o===")"&&(l=!1);else if(o===","){r+=1,n.push((a+c).trim());break}else o==="("&&(l=!0);c+=o,r+=1}}}return n.join(", ")}function j(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function Qe(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ie(){var e=document.createElement("a");return e.href="",e.href}function $e(e,t,r,i){return r==="src"||r==="href"&&i&&!(t==="use"&&i[0]==="#")||r==="xlink:href"&&i&&i[0]!=="#"||r==="background"&&i&&(t==="table"||t==="td"||t==="th")?j(e,i):r==="srcset"&&i?Be(e,i):r==="style"&&i?$(i,ie()):t==="object"&&r==="data"&&i?j(e,i):i}function qe(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var i=e.classList.length;i--;){var n=e.classList[i];if(t.test(n))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 i=e.classList.length;i--;){var n=e.classList[i];if(t.test(n))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var i=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(i===null)return!1;if(typeof t=="string"){if(i.classList.contains(t)||i.closest(".".concat(t)))return!0}else if(re(i,t,!0))return!0;return!!(r&&(i.matches(r)||i.closest(r)))}function Ye(e,t,r){var i=e.contentWindow;if(i){var n=!1,a;try{a=i.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(c),n=!0,t()});return}var l="about:blank";if(i.location.href!==l||e.src===l||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}}function Ve(e,t,r){var i=!1,n;try{n=e.sheet}catch{return}if(!n){var a=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(a),i=!0,t()})}}function Xe(e,t){var r=t.doc,i=t.mirror,n=t.blockClass,a=t.blockSelector,c=t.maskTextClass,l=t.maskTextSelector,o=t.inlineStylesheet,f=t.maskInputOptions,u=f===void 0?{}:f,p=t.maskTextFn,b=t.maskInputFn,w=t.dataURLOptions,k=w===void 0?{}:w,I=t.inlineImages,T=t.recordCanvas,x=t.keepIframeSrcFn,h=t.newlyAddedElement,s=h===void 0?!1:h,y=Ze(r,i);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:g.Document,childNodes:[],compatMode:e.compatMode}:{type:g.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:g.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return tt(e,{doc:r,blockClass:n,blockSelector:a,inlineStylesheet:o,maskInputOptions:u,maskInputFn:b,dataURLOptions:k,inlineImages:I,recordCanvas:T,keepIframeSrcFn:x,newlyAddedElement:s,rootId:y});case e.TEXT_NODE:return et(e,{maskTextClass:c,maskTextSelector:l,maskTextFn:p,rootId:y});case e.CDATA_SECTION_NODE:return{type:g.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:g.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,i=t.maskTextClass,n=t.maskTextSelector,a=t.maskTextFn,c=t.rootId,l=e.parentNode&&e.parentNode.tagName,o=e.textContent,f=l==="STYLE"?!0:void 0,u=l==="SCRIPT"?!0:void 0;if(f&&o){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(o=Ue(e.parentNode.sheet))}catch(p){console.warn("Cannot get CSS styles from text's parentNode. Error: ".concat(p),e)}o=$(o,ie())}return u&&(o="SCRIPT_PLACEHOLDER"),!f&&!u&&o&&Je(e,i,n)&&(o=a?a(o):o.replace(/[\S]/g,"*")),{type:g.Text,textContent:o||"",isStyle:f,rootId:c}}function tt(e,t){for(var r=t.doc,i=t.blockClass,n=t.blockSelector,a=t.inlineStylesheet,c=t.maskInputOptions,l=c===void 0?{}:c,o=t.maskInputFn,f=t.dataURLOptions,u=f===void 0?{}:f,p=t.inlineImages,b=t.recordCanvas,w=t.keepIframeSrcFn,k=t.newlyAddedElement,I=k===void 0?!1:k,T=t.rootId,x=qe(e,i,n),h=Pe(e),s={},y=e.attributes.length,M=0;M<y;M++){var E=e.attributes[M];s[E.name]=$e(r,h,E.name,E.value)}if(h==="link"&&a){var C=Array.from(r.styleSheets).find(function(N){return N.href===e.href}),m=null;C&&(m=te(C)),m&&(delete s.rel,delete s.href,s._cssText=$(m,C.href))}if(h==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=$(m,ie()))}if(h==="input"||h==="textarea"||h==="select"){var P=e.value,_=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&P?s.value=Oe({type:s.type,tagName:h,value:P,maskInputOptions:l,maskInputFn:o}):_&&(s.checked=_)}if(h==="option"&&(e.selected&&!l.select?s.selected=!0:delete s.selected),h==="canvas"&&b){if(e.__context==="2d")Me(e)||(s.rr_dataURL=e.toDataURL(u.type,u.quality));else if(!("__context"in e)){var L=e.toDataURL(u.type,u.quality),D=document.createElement("canvas");D.width=e.width,D.height=e.height;var A=D.toDataURL(u.type,u.quality);L!==A&&(s.rr_dataURL=L)}}if(h==="img"&&p){z||(z=r.createElement("canvas"),fe=z.getContext("2d"));var S=e,R=S.crossOrigin;S.crossOrigin="anonymous";var F=function(){try{z.width=S.naturalWidth,z.height=S.naturalHeight,fe.drawImage(S,0,0),s.rr_dataURL=z.toDataURL(u.type,u.quality)}catch(N){console.warn("Cannot inline img src=".concat(S.currentSrc,"! Error: ").concat(N))}R?s.crossOrigin=R:S.removeAttribute("crossorigin")};S.complete&&S.naturalWidth!==0?F():S.onload=F}if((h==="audio"||h==="video")&&(s.rr_mediaState=e.paused?"paused":"played",s.rr_mediaCurrentTime=e.currentTime),I||(e.scrollLeft&&(s.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(s.rr_scrollTop=e.scrollTop)),x){var U=e.getBoundingClientRect(),H=U.width,O=U.height;s={class:s.class,rr_width:"".concat(H,"px"),rr_height:"".concat(O,"px")}}return h==="iframe"&&!w(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:g.Element,tagName:h,attributes:s,childNodes:[],isSVG:Qe(e)||void 0,needBlock:x,rootId:T}}function d(e){return e===void 0?"":e.toLowerCase()}function rt(e,t){if(t.comment&&e.type===g.Comment)return!0;if(e.type===g.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,i=t.mirror,n=t.blockClass,a=t.blockSelector,c=t.maskTextClass,l=t.maskTextSelector,o=t.skipChild,f=o===void 0?!1:o,u=t.inlineStylesheet,p=u===void 0?!0:u,b=t.maskInputOptions,w=b===void 0?{}:b,k=t.maskTextFn,I=t.maskInputFn,T=t.slimDOMOptions,x=t.dataURLOptions,h=x===void 0?{}:x,s=t.inlineImages,y=s===void 0?!1:s,M=t.recordCanvas,E=M===void 0?!1:M,C=t.onSerialize,m=t.onIframeLoad,P=t.iframeLoadTimeout,_=P===void 0?5e3:P,L=t.onStylesheetLoad,D=t.stylesheetLoadTimeout,A=D===void 0?5e3:D,S=t.keepIframeSrcFn,R=S===void 0?function(){return!1}:S,F=t.newlyAddedElement,U=F===void 0?!1:F,H=t.preserveWhiteSpace,O=H===void 0?!0:H,N=Xe(e,{doc:r,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:l,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,keepIframeSrcFn:R,newlyAddedElement:U});if(!N)return console.warn(e,"not serialized"),null;var B;i.hasNode(e)?B=i.getId(e):rt(N,T)||!O&&N.type===g.Text&&!N.isStyle&&!N.textContent.replace(/^\s+|\s+$/gm,"").length?B=le:B=Fe();var v=Object.assign(N,{id:B});if(i.add(e,v),B===le)return null;C&&C(e);var J=!f;if(v.type===g.Element){J=J&&!v.needBlock,delete v.needBlock;var ne=e.shadowRoot;ne&&ee(ne)&&(v.isShadowHost=!0)}if((v.type===g.Document||v.type===g.Element)&&J){T.headWhitespace&&v.type===g.Element&&v.tagName==="head"&&(O=!1);for(var ae={doc:r,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:l,skipChild:f,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:I,slimDOMOptions:T,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:A,keepIframeSrcFn:R},Y=0,oe=Array.from(e.childNodes);Y<oe.length;Y++){var V=oe[Y],W=Q(V,ae);W&&v.childNodes.push(W)}if(xe(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var V=se[X],W=Q(V,ae);W&&(ee(e.shadowRoot)&&(W.isShadow=!0),v.childNodes.push(W))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(v.isShadow=!0),v.type===g.Element&&v.tagName==="iframe"&&Ye(e,function(){var G=e.contentDocument;if(G&&m){var ce=Q(G,{doc:G,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:l,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:I,slimDOMOptions:T,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:A,keepIframeSrcFn:R});ce&&m(e,ce)}},_),v.type===g.Element&&v.tagName==="link"&&v.attributes.rel==="stylesheet"&&Ve(e,function(){if(L){var G=Q(e,{doc:r,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:l,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:I,slimDOMOptions:T,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:A,keepIframeSrcFn:R});G&&L(e,G)}},A),v}function de(e,t){var r=t||{},i=r.mirror,n=i===void 0?new Re:i,a=r.blockClass,c=a===void 0?"rr-block":a,l=r.blockSelector,o=l===void 0?null:l,f=r.maskTextClass,u=f===void 0?"rr-mask":f,p=r.maskTextSelector,b=p===void 0?null:p,w=r.inlineStylesheet,k=w===void 0?!0:w,I=r.inlineImages,T=I===void 0?!1:I,x=r.recordCanvas,h=x===void 0?!1:x,s=r.maskAllInputs,y=s===void 0?!1:s,M=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,P=r.dataURLOptions,_=r.preserveWhiteSpace,L=r.onSerialize,D=r.onIframeLoad,A=r.iframeLoadTimeout,S=r.onStylesheetLoad,R=r.stylesheetLoadTimeout,F=r.keepIframeSrcFn,U=F===void 0?function(){return!1}:F,H=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 Q(e,{doc:e,mirror:n,blockClass:c,blockSelector:o,maskTextClass:u,maskTextSelector:b,skipChild:!1,inlineStylesheet:k,maskInputOptions:H,maskTextFn:M,maskInputFn:E,slimDOMOptions:O,dataURLOptions:P,inlineImages:T,recordCanvas:h,preserveWhiteSpace:_,onSerialize:L,onIframeLoad:D,iframeLoadTimeout:A,onStylesheetLoad:S,stylesheetLoadTimeout:R,keepIframeSrcFn:U,newlyAddedElement:!1})}var it=/([^\\]):hover/,st=new RegExp(it.source,"g");function q(){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";if(typeof sessionStorage<"u"){let t=sessionStorage.getItem(e);return t||(t=q(),sessionStorage.setItem(e,t)),t}return q()}function pe(){let e="_krypton_did";if(typeof localStorage<"u"){let t=localStorage.getItem(e);return t||(t=q(),localStorage.setItem(e,t)),t}return q()}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 i=e.get(r);i&&(t[r]=i)}return t}function ve(){if(typeof window>"u")return"unknown";let e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function ge(e){if(e.id)return`#${e.id}`;let t=[],r=e;for(;r&&r!==document.body;){let i=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let n=r.className.trim().split(/\s+/).slice(0,2).join(".");n&&(i+=`.${n}`)}t.unshift(i),r=r.parentElement}return t.join(" > ")}var K=class{constructor(t){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.consentGiven=!1;this.initialized=!1;this.lastSnapshotUrl=null;this.serverConfig=null;this.configFetched=!1;this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,flushInterval:5e3,batchSize:20,...t},this.distinctId=pe(),this.sessionId=he(),this.config.consentRequired||(this.consentGiven=!0),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().then(()=>this.setupTracking()))}async fetchConfig(){if(typeof window>"u")return;let t=`_krypton_config_${this.config.apiKey}`,r=sessionStorage.getItem(t);if(r)try{let i=JSON.parse(r);if(i._ts&&Date.now()-i._ts<300*1e3){this.serverConfig=i,this.configFetched=!0;return}}catch{}try{let i=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`);if(i.ok){let n=await i.json();this.serverConfig=n,this.configFetched=!0,sessionStorage.setItem(t,JSON.stringify({...n,_ts:Date.now()}))}}catch{}}setupTracking(){if(this.flushTimer=setInterval(()=>this.flush(),this.config.flushInterval),typeof window<"u"){window.addEventListener("beforeunload",()=>this.flush()),this.config.autoPageview&&this.consentGiven&&this.trackPageview();let t=this.config.heatmap&&(!this.configFetched||this.serverConfig?.heatmaps_enabled),r=history.pushState;history.pushState=(...i)=>{r.apply(history,i),this.config.autoPageview&&this.consentGiven&&setTimeout(()=>this.trackPageview(),0),t&&this.consentGiven&&setTimeout(()=>this.captureSnapshot(),0)},window.addEventListener("popstate",()=>{this.config.autoPageview&&this.consentGiven&&setTimeout(()=>this.trackPageview(),0),t&&this.consentGiven&&setTimeout(()=>this.captureSnapshot(),0)}),t&&this.consentGiven&&this.setupHeatmap()}}grantConsent(){this.consentGiven=!0,this.config.autoPageview&&this.trackPageview(),this.config.heatmap&&(!this.configFetched||this.serverConfig?.heatmaps_enabled)&&this.setupHeatmap()}revokeConsent(){this.consentGiven=!1,this.eventQueue=[],this.heatmapQueue=[]}identify(t){this.distinctId=t,typeof localStorage<"u"&&localStorage.setItem("_krypton_did",t)}trackPageview(t){this.consentGiven&&this.track("$pageview",{...t})}track(t,r){if(!this.consentGiven)return;let i=me(),n={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:t,timestamp:new Date().toISOString(),properties:r,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:i.utm_source||"",utm_medium:i.utm_medium||"",utm_campaign:i.utm_campaign||"",utm_term:i.utm_term||"",utm_content:i.utm_content||"",device_type:ve(),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(n),this.eventQueue.length>=this.config.batchSize&&this.flush()}async flush(){await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}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};try{await fetch(`${this.config.endpoint}/api/v1/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}catch{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};try{await fetch(`${this.config.endpoint}/api/v1/heatmap`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}catch{this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...t)}}captureSnapshot(){if(typeof window>"u"||typeof document>"u")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 i=JSON.stringify(r),n={api_key:this.config.apiKey,page_url:t,snapshot:i,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,timestamp:new Date().toISOString()};fetch(`${this.config.endpoint}/api/v1/snapshot`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),keepalive:!0}).catch(()=>{})}catch{}},1e3))}setupHeatmap(){if(typeof window>"u")return;this.captureSnapshot(),document.addEventListener("click",i=>{if(!this.consentGiven)return;let n=i.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:i.clientX+window.scrollX,y:i.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:ge(n)})});let t=0,r=null;window.addEventListener("scroll",()=>{if(!this.consentGiven)return;let i=window.scrollY||document.documentElement.scrollTop,n=document.documentElement.scrollHeight-window.innerHeight,a=n>0?i/n*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)})}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 K(e)}var we={Krypton:K,init:ye};typeof window<"u"&&(window.KryptonAnalytics=we);var nt=we;return Te(at);})();
|
|
1
|
+
"use strict";var KryptonAnalytics=(()=>{var Z=Object.defineProperty;var we=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,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Se(t))!be.call(e,n)&&n!==r&&Z(e,n,{get:()=>t[n],enumerable:!(i=we(t,n))||i.enumerable});return e};var Ie=e=>xe(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>q,default:()=>nt,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 i=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return i??-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,i=this.getId(t);this.idNodeMap.delete(i),t.childNodes&&t.childNodes.forEach(function(n){return r.removeNodeFromMap(n)})},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 i=r.id;this.idNodeMap.set(i,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var i=this.getNode(t);if(i){var n=this.nodeMetaMap.get(i);n&&this.nodeMetaMap.set(r,n)}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,i=e.type,n=e.value,a=e.maskInputFn,c=n||"";return(t[r.toLowerCase()]||t[i])&&(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,i=0;i<e.width;i+=r)for(var n=0;n<e.height;n+=r){var a=t.getImageData,c=le in a?a[le]:a,u=new Uint32Array(c.call(t,i,n,Math.min(r,e.width-i),Math.min(r,e.height-n)).data.buffer);if(u.some(function(o){return o!==0}))return!1}return!0}var Ae=1,De=new RegExp("[^a-z0-9-_:]"),ue=-2;function Fe(){return Ae++}function Pe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return De.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,Ke=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,Be=/^(data:)([^,]*),(.*)/i;function $(e,t){return(e||"").replace(We,function(r,i,n,a,c,u){var o=n||c||u,f=i||a||"";if(!o)return r;if(!Ke.test(o)||Be.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,k=h;b<k.length;b++){var w=k[b];w!=="."&&(w===".."?l.pop():l.push(w))}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 i(f){var l,h=f.exec(t.substring(r));return h?(l=h[0],r+=l.length,l):""}for(var n=[];i(je),!(r>=t.length);){var a=i(ze);if(a.slice(-1)===",")a=j(e,a.substring(0,a.length-1)),n.push(a);else{var c="";a=j(e,a);for(var u=!1;;){var o=t.charAt(r);if(o===""){n.push((a+c).trim());break}else if(u)o===")"&&(u=!1);else if(o===","){r+=1,n.push((a+c).trim());break}else o==="("&&(u=!0);c+=o,r+=1}}}return n.join(", ")}function j(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function Ge(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ie(){var e=document.createElement("a");return e.href="",e.href}function Qe(e,t,r,i){return r==="src"||r==="href"&&i&&!(t==="use"&&i[0]==="#")||r==="xlink:href"&&i&&i[0]!=="#"||r==="background"&&i&&(t==="table"||t==="td"||t==="th")?j(e,i):r==="srcset"&&i?qe(e,i):r==="style"&&i?$(i,ie()):t==="object"&&r==="data"&&i?j(e,i):i}function $e(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var i=e.classList.length;i--;){var n=e.classList[i];if(t.test(n))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 i=e.classList.length;i--;){var n=e.classList[i];if(t.test(n))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var i=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(i===null)return!1;if(typeof t=="string"){if(i.classList.contains(t)||i.closest(".".concat(t)))return!0}else if(re(i,t,!0))return!0;return!!(r&&(i.matches(r)||i.closest(r)))}function Ve(e,t,r){var i=e.contentWindow;if(i){var n=!1,a;try{a=i.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(c),n=!0,t()});return}var u="about:blank";if(i.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 i=!1,n;try{n=e.sheet}catch{return}if(!n){var a=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(a),i=!0,t()})}}function Xe(e,t){var r=t.doc,i=t.mirror,n=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,k=t.dataURLOptions,w=k===void 0?{}:k,x=t.inlineImages,I=t.recordCanvas,T=t.keepIframeSrcFn,p=t.newlyAddedElement,s=p===void 0?!1:p,y=Ze(r,i);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:n,blockSelector:a,inlineStylesheet:o,maskInputOptions:l,maskInputFn:b,dataURLOptions:w,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,i=t.maskTextClass,n=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=$(o,ie())}return l&&(o="SCRIPT_PLACEHOLDER"),!f&&!l&&o&&Je(e,i,n)&&(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,i=t.blockClass,n=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,k=t.keepIframeSrcFn,w=t.newlyAddedElement,x=w===void 0?!1:w,I=t.rootId,T=$e(e,i,n),p=Pe(e),s={},y=e.attributes.length,M=0;M<y;M++){var E=e.attributes[M];s[E.name]=Qe(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=$(m,C.href))}if(p==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=$(m,ie()))}if(p==="input"||p==="textarea"||p==="select"){var P=e.value,_=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&P?s.value=Oe({type:s.type,tagName:p,value:P,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")Me(e)||(s.rr_dataURL=e.toDataURL(l.type,l.quality));else if(!("__context"in e)){var L=e.toDataURL(l.type,l.quality),A=document.createElement("canvas");A.width=e.width,A.height=e.height;var D=A.toDataURL(l.type,l.quality);L!==D&&(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 F=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?F():S.onload=F}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"&&!k(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:v.Element,tagName:p,attributes:s,childNodes:[],isSVG:Ge(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,i=t.mirror,n=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,k=b===void 0?{}:b,w=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,M=t.recordCanvas,E=M===void 0?!1:M,C=t.onSerialize,m=t.onIframeLoad,P=t.iframeLoadTimeout,_=P===void 0?5e3:P,L=t.onStylesheetLoad,A=t.stylesheetLoadTimeout,D=A===void 0?5e3:A,S=t.keepIframeSrcFn,N=S===void 0?function(){return!1}:S,F=t.newlyAddedElement,U=F===void 0?!1:F,W=t.preserveWhiteSpace,O=W===void 0?!0:W,R=Xe(e,{doc:r,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:u,inlineStylesheet:h,maskInputOptions:k,maskTextFn:w,maskInputFn:x,dataURLOptions:p,inlineImages:y,recordCanvas:E,keepIframeSrcFn:N,newlyAddedElement:U});if(!R)return console.warn(e,"not serialized"),null;var G;i.hasNode(e)?G=i.getId(e):rt(R,I)||!O&&R.type===v.Text&&!R.isStyle&&!R.textContent.replace(/^\s+|\s+$/gm,"").length?G=ue:G=Fe();var g=Object.assign(R,{id:G});if(i.add(e,g),G===ue)return null;C&&C(e);var J=!f;if(g.type===v.Element){J=J&&!g.needBlock,delete g.needBlock;var ne=e.shadowRoot;ne&&ee(ne)&&(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:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:f,inlineStylesheet:h,maskInputOptions:k,maskTextFn:w,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:D,keepIframeSrcFn:N},V=0,oe=Array.from(e.childNodes);V<oe.length;V++){var Y=oe[V],K=Q(Y,ae);K&&g.childNodes.push(K)}if(Te(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var Y=se[X],K=Q(Y,ae);K&&(ee(e.shadowRoot)&&(K.isShadow=!0),g.childNodes.push(K))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(g.isShadow=!0),g.type===v.Element&&g.tagName==="iframe"&&Ve(e,function(){var B=e.contentDocument;if(B&&m){var ce=Q(B,{doc:B,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:h,maskInputOptions:k,maskTextFn:w,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:D,keepIframeSrcFn:N});ce&&m(e,ce)}},_),g.type===v.Element&&g.tagName==="link"&&g.attributes.rel==="stylesheet"&&Ye(e,function(){if(L){var B=Q(e,{doc:r,mirror:i,blockClass:n,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:h,maskInputOptions:k,maskTextFn:w,maskInputFn:x,slimDOMOptions:I,dataURLOptions:p,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:D,keepIframeSrcFn:N});B&&L(e,B)}},D),g}function de(e,t){var r=t||{},i=r.mirror,n=i===void 0?new Ne:i,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,k=r.inlineStylesheet,w=k===void 0?!0:k,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,M=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,P=r.dataURLOptions,_=r.preserveWhiteSpace,L=r.onSerialize,A=r.onIframeLoad,D=r.iframeLoadTimeout,S=r.onStylesheetLoad,N=r.stylesheetLoadTimeout,F=r.keepIframeSrcFn,U=F===void 0?function(){return!1}:F,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 Q(e,{doc:e,mirror:n,blockClass:c,blockSelector:o,maskTextClass:l,maskTextSelector:b,skipChild:!1,inlineStylesheet:w,maskInputOptions:W,maskTextFn:M,maskInputFn:E,slimDOMOptions:O,dataURLOptions:P,inlineImages:I,recordCanvas:p,preserveWhiteSpace:_,onSerialize:L,onIframeLoad:A,iframeLoadTimeout:D,onStylesheetLoad:S,stylesheetLoadTimeout:N,keepIframeSrcFn:U,newlyAddedElement:!1})}var it=/([^\\]):hover/,st=new RegExp(it.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 i=e.get(r);i&&(t[r]=i)}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 i=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let n=r.className.trim().split(/\s+/).slice(0,2).join(".");n&&(i+=`.${n}`)}t.unshift(i),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.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().then(()=>{this.setupTracking(),this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()&&this.showConsentBanner()}))}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 i=JSON.parse(r);if(i._ts&&Date.now()-i._ts<300*1e3){this.serverConfig=i,this.configFetched=!0;return}}catch{}try{let i=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`);if(i.ok){let n=await i.json();this.serverConfig=n,this.configFetched=!0;try{sessionStorage.setItem(t,JSON.stringify({...n,_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=(...i)=>{t.apply(history,i),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)};let r=history.replaceState;history.replaceState=(...i)=>{r.apply(history,i),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)},window.addEventListener("popstate",()=>{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}),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=`
|
|
2
|
+
<div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
|
|
3
|
+
<div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
|
|
4
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
5
|
+
<input type="checkbox" id="krypton-consent-analytics" ${r(this.consent.analytics)} />
|
|
6
|
+
<span><strong>Analytics</strong> (pageviews and custom events)</span>
|
|
7
|
+
</label>
|
|
8
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
9
|
+
<input type="checkbox" id="krypton-consent-heatmaps" ${r(this.consent.heatmaps)} />
|
|
10
|
+
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
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">
|
|
17
|
+
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
18
|
+
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
19
|
+
<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
|
+
</div>
|
|
21
|
+
`;let i=()=>{t.remove()},n=a=>!!document.getElementById(a)?.checked;t.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{this.setConsent({analytics:n("krypton-consent-analytics"),heatmaps:n("krypton-consent-heatmaps"),geo:n("krypton-consent-geo")}),i()}),t.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{this.setConsent({analytics:!0,heatmaps:!0,geo:!0}),i()}),t.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{this.setConsent({analytics:!1,heatmaps:!1,geo:!1}),i()}),document.body.appendChild(t)}setConsent(t,r=!0){let i={...this.consent};this.consent={analytics:t.analytics??i.analytics,heatmaps:t.heatmaps??i.heatmaps,geo:t.geo??i.geo},r&&this.persistConsent(),!i.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),i.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!i.heatmaps&&this.isHeatmapFeatureEnabled()&&(this.setupHeatmap(),this.captureSnapshot()),i.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[]),!i.geo&&this.consent.geo&&this.captureGeoOnce()}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){if(this.distinctId=t,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",t)}catch{}}trackPageview(t){this.canTrackAnalytics()&&this.track("$pageview",{...t})}track(t,r){if(!this.canTrackAnalytics())return;let i=me(),n={...r||{}};this.consent.geo&&this.geoContext&&(n.geo=this.geoContext);let a={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:t,timestamp:new Date().toISOString(),properties:n,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:i.utm_source||"",utm_medium:i.utm_medium||"",utm_campaign:i.utm_campaign||"",utm_term:i.utm_term||"",utm_content:i.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()}async flush(){await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}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=(i,n=3)=>Number(i.toFixed(n));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};try{await fetch(`${this.config.endpoint}/api/v1/ingest/batch`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}catch{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};try{await fetch(`${this.config.endpoint}/api/v1/heatmap`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),keepalive:!0})}catch{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 i=JSON.stringify(r),n={api_key:this.config.apiKey,page_url:t,snapshot:i,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,timestamp:new Date().toISOString()};fetch(`${this.config.endpoint}/api/v1/snapshot`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),keepalive:!0}).catch(()=>{})}catch{}},1e3))}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,this.captureSnapshot(),document.addEventListener("click",i=>{if(!this.isHeatmapFeatureEnabled())return;let n=i.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:i.clientX+window.scrollX,y:i.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:ve(n)})});let t=0,r=null;window.addEventListener("scroll",()=>{if(!this.isHeatmapFeatureEnabled())return;let i=window.scrollY||document.documentElement.scrollTop,n=document.documentElement.scrollHeight-window.innerHeight,a=n>0?i/n*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)})}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 ke={Krypton:q,init:ye};typeof window<"u"&&(window.KryptonAnalytics=ke);var nt=ke;return Ie(at);})();
|
package/dist/index.d.mts
CHANGED
|
@@ -9,11 +9,21 @@ interface KryptonConfig {
|
|
|
9
9
|
heatmap?: boolean;
|
|
10
10
|
/** Require consent before tracking (default: false) */
|
|
11
11
|
consentRequired?: boolean;
|
|
12
|
+
/** Show a built-in consent popup (default: false) */
|
|
13
|
+
showConsentBanner?: boolean;
|
|
14
|
+
/** Optional initial consent values (default deny when consentRequired=true) */
|
|
15
|
+
consentCategories?: Partial<ConsentPreferences>;
|
|
12
16
|
/** Flush interval in milliseconds (default: 5000) */
|
|
13
17
|
flushInterval?: number;
|
|
14
18
|
/** Max events per batch (default: 20) */
|
|
15
19
|
batchSize?: number;
|
|
16
20
|
}
|
|
21
|
+
type ConsentCategory = "analytics" | "heatmaps" | "geo";
|
|
22
|
+
interface ConsentPreferences {
|
|
23
|
+
analytics: boolean;
|
|
24
|
+
heatmaps: boolean;
|
|
25
|
+
geo: boolean;
|
|
26
|
+
}
|
|
17
27
|
interface EventPayload {
|
|
18
28
|
project_id: string;
|
|
19
29
|
distinct_id: string;
|
|
@@ -61,18 +71,34 @@ declare class Krypton {
|
|
|
61
71
|
private eventQueue;
|
|
62
72
|
private heatmapQueue;
|
|
63
73
|
private flushTimer;
|
|
64
|
-
private consentGiven;
|
|
65
74
|
private initialized;
|
|
66
75
|
private lastSnapshotUrl;
|
|
76
|
+
private heatmapSetup;
|
|
77
|
+
private geoRequested;
|
|
78
|
+
private geoContext;
|
|
79
|
+
private consent;
|
|
67
80
|
private serverConfig;
|
|
68
81
|
private configFetched;
|
|
69
82
|
constructor(config: KryptonConfig);
|
|
70
83
|
private init;
|
|
84
|
+
private resolveInitialConsent;
|
|
85
|
+
private consentStorageKey;
|
|
86
|
+
private hasStoredConsent;
|
|
87
|
+
private loadStoredConsent;
|
|
88
|
+
private persistConsent;
|
|
89
|
+
private promotePersistentIds;
|
|
90
|
+
private canTrackAnalytics;
|
|
91
|
+
private isHeatmapFeatureEnabled;
|
|
71
92
|
private fetchConfig;
|
|
72
93
|
private setupTracking;
|
|
73
|
-
/**
|
|
94
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
|
|
95
|
+
showConsentBanner(): void;
|
|
96
|
+
/** Set one or more consent categories and apply changes immediately. */
|
|
97
|
+
setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
|
|
98
|
+
getConsent(): ConsentPreferences;
|
|
99
|
+
/** Backward-compatible: grant all categories. */
|
|
74
100
|
grantConsent(): void;
|
|
75
|
-
/**
|
|
101
|
+
/** Backward-compatible: revoke all categories and clear queues. */
|
|
76
102
|
revokeConsent(): void;
|
|
77
103
|
/** Identify a user with a custom distinct ID */
|
|
78
104
|
identify(distinctId: string): void;
|
|
@@ -80,10 +106,9 @@ declare class Krypton {
|
|
|
80
106
|
trackPageview(properties?: Record<string, unknown>): void;
|
|
81
107
|
/** Track a custom event */
|
|
82
108
|
track(eventName: string, properties?: Record<string, unknown>): void;
|
|
83
|
-
/** Flush all queued events to the server */
|
|
84
109
|
flush(): Promise<void>;
|
|
85
|
-
/** Shutdown the SDK */
|
|
86
110
|
shutdown(): void;
|
|
111
|
+
private captureGeoOnce;
|
|
87
112
|
private flushEvents;
|
|
88
113
|
private flushHeatmapEvents;
|
|
89
114
|
private captureSnapshot;
|
|
@@ -92,4 +117,4 @@ declare class Krypton {
|
|
|
92
117
|
}
|
|
93
118
|
declare function createKrypton(config: KryptonConfig): Krypton;
|
|
94
119
|
|
|
95
|
-
export { type EventPayload, type HeatmapEventPayload, Krypton, type KryptonConfig, createKrypton };
|
|
120
|
+
export { type ConsentCategory, type ConsentPreferences, type EventPayload, type HeatmapEventPayload, Krypton, type KryptonConfig, createKrypton };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,11 +9,21 @@ interface KryptonConfig {
|
|
|
9
9
|
heatmap?: boolean;
|
|
10
10
|
/** Require consent before tracking (default: false) */
|
|
11
11
|
consentRequired?: boolean;
|
|
12
|
+
/** Show a built-in consent popup (default: false) */
|
|
13
|
+
showConsentBanner?: boolean;
|
|
14
|
+
/** Optional initial consent values (default deny when consentRequired=true) */
|
|
15
|
+
consentCategories?: Partial<ConsentPreferences>;
|
|
12
16
|
/** Flush interval in milliseconds (default: 5000) */
|
|
13
17
|
flushInterval?: number;
|
|
14
18
|
/** Max events per batch (default: 20) */
|
|
15
19
|
batchSize?: number;
|
|
16
20
|
}
|
|
21
|
+
type ConsentCategory = "analytics" | "heatmaps" | "geo";
|
|
22
|
+
interface ConsentPreferences {
|
|
23
|
+
analytics: boolean;
|
|
24
|
+
heatmaps: boolean;
|
|
25
|
+
geo: boolean;
|
|
26
|
+
}
|
|
17
27
|
interface EventPayload {
|
|
18
28
|
project_id: string;
|
|
19
29
|
distinct_id: string;
|
|
@@ -61,18 +71,34 @@ declare class Krypton {
|
|
|
61
71
|
private eventQueue;
|
|
62
72
|
private heatmapQueue;
|
|
63
73
|
private flushTimer;
|
|
64
|
-
private consentGiven;
|
|
65
74
|
private initialized;
|
|
66
75
|
private lastSnapshotUrl;
|
|
76
|
+
private heatmapSetup;
|
|
77
|
+
private geoRequested;
|
|
78
|
+
private geoContext;
|
|
79
|
+
private consent;
|
|
67
80
|
private serverConfig;
|
|
68
81
|
private configFetched;
|
|
69
82
|
constructor(config: KryptonConfig);
|
|
70
83
|
private init;
|
|
84
|
+
private resolveInitialConsent;
|
|
85
|
+
private consentStorageKey;
|
|
86
|
+
private hasStoredConsent;
|
|
87
|
+
private loadStoredConsent;
|
|
88
|
+
private persistConsent;
|
|
89
|
+
private promotePersistentIds;
|
|
90
|
+
private canTrackAnalytics;
|
|
91
|
+
private isHeatmapFeatureEnabled;
|
|
71
92
|
private fetchConfig;
|
|
72
93
|
private setupTracking;
|
|
73
|
-
/**
|
|
94
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
|
|
95
|
+
showConsentBanner(): void;
|
|
96
|
+
/** Set one or more consent categories and apply changes immediately. */
|
|
97
|
+
setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
|
|
98
|
+
getConsent(): ConsentPreferences;
|
|
99
|
+
/** Backward-compatible: grant all categories. */
|
|
74
100
|
grantConsent(): void;
|
|
75
|
-
/**
|
|
101
|
+
/** Backward-compatible: revoke all categories and clear queues. */
|
|
76
102
|
revokeConsent(): void;
|
|
77
103
|
/** Identify a user with a custom distinct ID */
|
|
78
104
|
identify(distinctId: string): void;
|
|
@@ -80,10 +106,9 @@ declare class Krypton {
|
|
|
80
106
|
trackPageview(properties?: Record<string, unknown>): void;
|
|
81
107
|
/** Track a custom event */
|
|
82
108
|
track(eventName: string, properties?: Record<string, unknown>): void;
|
|
83
|
-
/** Flush all queued events to the server */
|
|
84
109
|
flush(): Promise<void>;
|
|
85
|
-
/** Shutdown the SDK */
|
|
86
110
|
shutdown(): void;
|
|
111
|
+
private captureGeoOnce;
|
|
87
112
|
private flushEvents;
|
|
88
113
|
private flushHeatmapEvents;
|
|
89
114
|
private captureSnapshot;
|
|
@@ -92,4 +117,4 @@ declare class Krypton {
|
|
|
92
117
|
}
|
|
93
118
|
declare function createKrypton(config: KryptonConfig): Krypton;
|
|
94
119
|
|
|
95
|
-
export { type EventPayload, type HeatmapEventPayload, Krypton, type KryptonConfig, createKrypton };
|
|
120
|
+
export { type ConsentCategory, type ConsentPreferences, type EventPayload, type HeatmapEventPayload, Krypton, type KryptonConfig, createKrypton };
|
package/dist/index.js
CHANGED
|
@@ -39,25 +39,31 @@ function generateId() {
|
|
|
39
39
|
}
|
|
40
40
|
function getSessionId() {
|
|
41
41
|
const key = "_krypton_sid";
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
try {
|
|
43
|
+
if (typeof sessionStorage !== "undefined") {
|
|
44
|
+
let sid = sessionStorage.getItem(key);
|
|
45
|
+
if (!sid) {
|
|
46
|
+
sid = generateId();
|
|
47
|
+
sessionStorage.setItem(key, sid);
|
|
48
|
+
}
|
|
49
|
+
return sid;
|
|
47
50
|
}
|
|
48
|
-
|
|
51
|
+
} catch {
|
|
49
52
|
}
|
|
50
53
|
return generateId();
|
|
51
54
|
}
|
|
52
55
|
function getDistinctId() {
|
|
53
56
|
const key = "_krypton_did";
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
try {
|
|
58
|
+
if (typeof localStorage !== "undefined") {
|
|
59
|
+
let did = localStorage.getItem(key);
|
|
60
|
+
if (!did) {
|
|
61
|
+
did = generateId();
|
|
62
|
+
localStorage.setItem(key, did);
|
|
63
|
+
}
|
|
64
|
+
return did;
|
|
59
65
|
}
|
|
60
|
-
|
|
66
|
+
} catch {
|
|
61
67
|
}
|
|
62
68
|
return generateId();
|
|
63
69
|
}
|
|
@@ -104,35 +110,108 @@ var Krypton = class {
|
|
|
104
110
|
this.eventQueue = [];
|
|
105
111
|
this.heatmapQueue = [];
|
|
106
112
|
this.flushTimer = null;
|
|
107
|
-
this.consentGiven = false;
|
|
108
113
|
this.initialized = false;
|
|
109
114
|
this.lastSnapshotUrl = null;
|
|
115
|
+
this.heatmapSetup = false;
|
|
116
|
+
this.geoRequested = false;
|
|
117
|
+
this.geoContext = null;
|
|
110
118
|
this.serverConfig = null;
|
|
111
119
|
this.configFetched = false;
|
|
112
120
|
this.config = {
|
|
113
121
|
autoPageview: true,
|
|
114
122
|
heatmap: false,
|
|
115
123
|
consentRequired: false,
|
|
124
|
+
showConsentBanner: false,
|
|
125
|
+
consentCategories: {},
|
|
116
126
|
flushInterval: 5e3,
|
|
117
127
|
batchSize: 20,
|
|
118
128
|
...config
|
|
119
129
|
};
|
|
120
|
-
this.distinctId =
|
|
121
|
-
this.sessionId =
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
this.distinctId = generateId();
|
|
131
|
+
this.sessionId = generateId();
|
|
132
|
+
this.consent = this.resolveInitialConsent();
|
|
133
|
+
if (this.canTrackAnalytics()) {
|
|
134
|
+
this.promotePersistentIds();
|
|
124
135
|
}
|
|
125
136
|
this.init();
|
|
126
137
|
}
|
|
127
138
|
init() {
|
|
128
139
|
if (this.initialized) return;
|
|
129
140
|
this.initialized = true;
|
|
130
|
-
this.fetchConfig().then(() =>
|
|
141
|
+
this.fetchConfig().then(() => {
|
|
142
|
+
this.setupTracking();
|
|
143
|
+
if (this.config.consentRequired && this.config.showConsentBanner && !this.hasStoredConsent()) {
|
|
144
|
+
this.showConsentBanner();
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
resolveInitialConsent() {
|
|
149
|
+
const stored = this.loadStoredConsent();
|
|
150
|
+
if (stored) return stored;
|
|
151
|
+
const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
|
|
152
|
+
analytics: true,
|
|
153
|
+
heatmaps: !!this.config.heatmap,
|
|
154
|
+
geo: false
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
...base,
|
|
158
|
+
...this.config.consentCategories
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
consentStorageKey() {
|
|
162
|
+
return `_krypton_consent_${this.config.apiKey}`;
|
|
163
|
+
}
|
|
164
|
+
hasStoredConsent() {
|
|
165
|
+
try {
|
|
166
|
+
if (typeof localStorage === "undefined") return false;
|
|
167
|
+
return !!localStorage.getItem(this.consentStorageKey());
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
loadStoredConsent() {
|
|
173
|
+
try {
|
|
174
|
+
if (typeof localStorage === "undefined") return null;
|
|
175
|
+
const raw = localStorage.getItem(this.consentStorageKey());
|
|
176
|
+
if (!raw) return null;
|
|
177
|
+
const parsed = JSON.parse(raw);
|
|
178
|
+
return {
|
|
179
|
+
analytics: !!parsed.analytics,
|
|
180
|
+
heatmaps: !!parsed.heatmaps,
|
|
181
|
+
geo: !!parsed.geo
|
|
182
|
+
};
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
persistConsent() {
|
|
188
|
+
try {
|
|
189
|
+
if (typeof localStorage === "undefined") return;
|
|
190
|
+
localStorage.setItem(this.consentStorageKey(), JSON.stringify(this.consent));
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
promotePersistentIds() {
|
|
195
|
+
this.distinctId = getDistinctId();
|
|
196
|
+
this.sessionId = getSessionId();
|
|
197
|
+
}
|
|
198
|
+
canTrackAnalytics() {
|
|
199
|
+
return !!this.consent.analytics;
|
|
200
|
+
}
|
|
201
|
+
isHeatmapFeatureEnabled() {
|
|
202
|
+
if (!this.config.heatmap) return false;
|
|
203
|
+
if (this.configFetched && !this.serverConfig?.heatmaps_enabled) return false;
|
|
204
|
+
return !!this.consent.heatmaps;
|
|
131
205
|
}
|
|
132
206
|
async fetchConfig() {
|
|
133
207
|
if (typeof window === "undefined") return;
|
|
134
208
|
const cacheKey = `_krypton_config_${this.config.apiKey}`;
|
|
135
|
-
|
|
209
|
+
let cached = null;
|
|
210
|
+
try {
|
|
211
|
+
cached = sessionStorage.getItem(cacheKey);
|
|
212
|
+
} catch {
|
|
213
|
+
cached = null;
|
|
214
|
+
}
|
|
136
215
|
if (cached) {
|
|
137
216
|
try {
|
|
138
217
|
const parsed = JSON.parse(cached);
|
|
@@ -152,83 +231,203 @@ var Krypton = class {
|
|
|
152
231
|
const data = await res.json();
|
|
153
232
|
this.serverConfig = data;
|
|
154
233
|
this.configFetched = true;
|
|
155
|
-
|
|
234
|
+
try {
|
|
235
|
+
sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
|
|
236
|
+
} catch {
|
|
237
|
+
}
|
|
156
238
|
}
|
|
157
239
|
} catch {
|
|
158
240
|
}
|
|
159
241
|
}
|
|
160
242
|
setupTracking() {
|
|
161
243
|
this.flushTimer = setInterval(() => this.flush(), this.config.flushInterval);
|
|
162
|
-
if (typeof window
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
244
|
+
if (typeof window === "undefined") return;
|
|
245
|
+
window.addEventListener("beforeunload", () => this.flush());
|
|
246
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
247
|
+
this.trackPageview();
|
|
248
|
+
}
|
|
249
|
+
const originalPushState = history.pushState;
|
|
250
|
+
history.pushState = (...args) => {
|
|
251
|
+
originalPushState.apply(history, args);
|
|
252
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
253
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
166
254
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
window.addEventListener("popstate", () => {
|
|
179
|
-
if (this.config.autoPageview && this.consentGiven) {
|
|
180
|
-
setTimeout(() => this.trackPageview(), 0);
|
|
181
|
-
}
|
|
182
|
-
if (heatmapEnabled && this.consentGiven) {
|
|
183
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
if (heatmapEnabled && this.consentGiven) {
|
|
187
|
-
this.setupHeatmap();
|
|
255
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
256
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const originalReplaceState = history.replaceState;
|
|
260
|
+
history.replaceState = (...args) => {
|
|
261
|
+
originalReplaceState.apply(history, args);
|
|
262
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
263
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
188
264
|
}
|
|
265
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
266
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
window.addEventListener("popstate", () => {
|
|
270
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
271
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
272
|
+
}
|
|
273
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
274
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
278
|
+
this.setupHeatmap();
|
|
279
|
+
}
|
|
280
|
+
if (this.consent.geo) {
|
|
281
|
+
this.captureGeoOnce();
|
|
189
282
|
}
|
|
190
283
|
}
|
|
191
|
-
/**
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
|
|
284
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
|
|
285
|
+
showConsentBanner() {
|
|
286
|
+
if (typeof document === "undefined") return;
|
|
287
|
+
if (document.getElementById("krypton-consent-banner")) return;
|
|
288
|
+
const banner = document.createElement("div");
|
|
289
|
+
banner.id = "krypton-consent-banner";
|
|
290
|
+
banner.style.cssText = [
|
|
291
|
+
"position:fixed",
|
|
292
|
+
"left:16px",
|
|
293
|
+
"right:16px",
|
|
294
|
+
"bottom:16px",
|
|
295
|
+
"z-index:2147483647",
|
|
296
|
+
"max-width:720px",
|
|
297
|
+
"margin:0 auto",
|
|
298
|
+
"background:#111827",
|
|
299
|
+
"color:#f9fafb",
|
|
300
|
+
"border-radius:12px",
|
|
301
|
+
"padding:16px",
|
|
302
|
+
"box-shadow:0 12px 30px rgba(0,0,0,0.35)",
|
|
303
|
+
"font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif",
|
|
304
|
+
"font-size:14px",
|
|
305
|
+
"line-height:1.4"
|
|
306
|
+
].join(";");
|
|
307
|
+
const checked = (value) => value ? "checked" : "";
|
|
308
|
+
banner.innerHTML = `
|
|
309
|
+
<div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
|
|
310
|
+
<div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
|
|
311
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
312
|
+
<input type="checkbox" id="krypton-consent-analytics" ${checked(this.consent.analytics)} />
|
|
313
|
+
<span><strong>Analytics</strong> (pageviews and custom events)</span>
|
|
314
|
+
</label>
|
|
315
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
316
|
+
<input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
|
|
317
|
+
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
318
|
+
</label>
|
|
319
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
|
|
320
|
+
<input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
|
|
321
|
+
<span><strong>Geo location</strong> (browser geolocation if available)</span>
|
|
322
|
+
</label>
|
|
323
|
+
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
324
|
+
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
325
|
+
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
326
|
+
<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>
|
|
327
|
+
</div>
|
|
328
|
+
`;
|
|
329
|
+
const remove = () => {
|
|
330
|
+
banner.remove();
|
|
331
|
+
};
|
|
332
|
+
const readValue = (id) => {
|
|
333
|
+
const el = document.getElementById(id);
|
|
334
|
+
return !!el?.checked;
|
|
335
|
+
};
|
|
336
|
+
banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
|
|
337
|
+
this.setConsent({
|
|
338
|
+
analytics: readValue("krypton-consent-analytics"),
|
|
339
|
+
heatmaps: readValue("krypton-consent-heatmaps"),
|
|
340
|
+
geo: readValue("krypton-consent-geo")
|
|
341
|
+
});
|
|
342
|
+
remove();
|
|
343
|
+
});
|
|
344
|
+
banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
|
|
345
|
+
this.setConsent({ analytics: true, heatmaps: true, geo: true });
|
|
346
|
+
remove();
|
|
347
|
+
});
|
|
348
|
+
banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
|
|
349
|
+
this.setConsent({ analytics: false, heatmaps: false, geo: false });
|
|
350
|
+
remove();
|
|
351
|
+
});
|
|
352
|
+
document.body.appendChild(banner);
|
|
353
|
+
}
|
|
354
|
+
/** Set one or more consent categories and apply changes immediately. */
|
|
355
|
+
setConsent(next, persist = true) {
|
|
356
|
+
const prev = { ...this.consent };
|
|
357
|
+
this.consent = {
|
|
358
|
+
analytics: next.analytics ?? prev.analytics,
|
|
359
|
+
heatmaps: next.heatmaps ?? prev.heatmaps,
|
|
360
|
+
geo: next.geo ?? prev.geo
|
|
361
|
+
};
|
|
362
|
+
if (persist) {
|
|
363
|
+
this.persistConsent();
|
|
364
|
+
}
|
|
365
|
+
if (!prev.analytics && this.consent.analytics) {
|
|
366
|
+
this.promotePersistentIds();
|
|
367
|
+
if (this.config.autoPageview) {
|
|
368
|
+
this.trackPageview();
|
|
369
|
+
}
|
|
196
370
|
}
|
|
197
|
-
|
|
198
|
-
|
|
371
|
+
if (prev.analytics && !this.consent.analytics) {
|
|
372
|
+
this.eventQueue = [];
|
|
373
|
+
}
|
|
374
|
+
if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
|
|
199
375
|
this.setupHeatmap();
|
|
376
|
+
this.captureSnapshot();
|
|
377
|
+
}
|
|
378
|
+
if (prev.heatmaps && !this.consent.heatmaps) {
|
|
379
|
+
this.heatmapQueue = [];
|
|
380
|
+
}
|
|
381
|
+
if (!prev.geo && this.consent.geo) {
|
|
382
|
+
this.captureGeoOnce();
|
|
200
383
|
}
|
|
201
384
|
}
|
|
202
|
-
|
|
385
|
+
getConsent() {
|
|
386
|
+
return { ...this.consent };
|
|
387
|
+
}
|
|
388
|
+
/** Backward-compatible: grant all categories. */
|
|
389
|
+
grantConsent() {
|
|
390
|
+
this.setConsent({ analytics: true, heatmaps: true, geo: true });
|
|
391
|
+
}
|
|
392
|
+
/** Backward-compatible: revoke all categories and clear queues. */
|
|
203
393
|
revokeConsent() {
|
|
204
|
-
this.
|
|
394
|
+
this.setConsent({ analytics: false, heatmaps: false, geo: false });
|
|
205
395
|
this.eventQueue = [];
|
|
206
396
|
this.heatmapQueue = [];
|
|
207
397
|
}
|
|
208
398
|
/** Identify a user with a custom distinct ID */
|
|
209
399
|
identify(distinctId) {
|
|
210
400
|
this.distinctId = distinctId;
|
|
211
|
-
if (
|
|
212
|
-
|
|
401
|
+
if (this.canTrackAnalytics()) {
|
|
402
|
+
try {
|
|
403
|
+
if (typeof localStorage !== "undefined") {
|
|
404
|
+
localStorage.setItem("_krypton_did", distinctId);
|
|
405
|
+
}
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
213
408
|
}
|
|
214
409
|
}
|
|
215
410
|
/** Track a pageview */
|
|
216
411
|
trackPageview(properties) {
|
|
217
|
-
if (!this.
|
|
412
|
+
if (!this.canTrackAnalytics()) return;
|
|
218
413
|
this.track("$pageview", {
|
|
219
414
|
...properties
|
|
220
415
|
});
|
|
221
416
|
}
|
|
222
417
|
/** Track a custom event */
|
|
223
418
|
track(eventName, properties) {
|
|
224
|
-
if (!this.
|
|
419
|
+
if (!this.canTrackAnalytics()) return;
|
|
225
420
|
const utm = getUTMParams();
|
|
421
|
+
const mergedProperties = { ...properties || {} };
|
|
422
|
+
if (this.consent.geo && this.geoContext) {
|
|
423
|
+
mergedProperties.geo = this.geoContext;
|
|
424
|
+
}
|
|
226
425
|
const event = {
|
|
227
426
|
project_id: this.config.apiKey,
|
|
228
427
|
distinct_id: this.distinctId,
|
|
229
428
|
event_name: eventName,
|
|
230
429
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
231
|
-
properties,
|
|
430
|
+
properties: mergedProperties,
|
|
232
431
|
page_url: typeof window !== "undefined" ? window.location.href : "",
|
|
233
432
|
page_title: typeof document !== "undefined" ? document.title : "",
|
|
234
433
|
referrer: typeof document !== "undefined" ? document.referrer : "",
|
|
@@ -248,11 +447,9 @@ var Krypton = class {
|
|
|
248
447
|
this.flush();
|
|
249
448
|
}
|
|
250
449
|
}
|
|
251
|
-
/** Flush all queued events to the server */
|
|
252
450
|
async flush() {
|
|
253
451
|
await Promise.all([this.flushEvents(), this.flushHeatmapEvents()]);
|
|
254
452
|
}
|
|
255
|
-
/** Shutdown the SDK */
|
|
256
453
|
shutdown() {
|
|
257
454
|
if (this.flushTimer) {
|
|
258
455
|
clearInterval(this.flushTimer);
|
|
@@ -260,7 +457,30 @@ var Krypton = class {
|
|
|
260
457
|
}
|
|
261
458
|
this.flush();
|
|
262
459
|
}
|
|
263
|
-
|
|
460
|
+
captureGeoOnce() {
|
|
461
|
+
if (this.geoRequested) return;
|
|
462
|
+
if (!this.consent.geo) return;
|
|
463
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) return;
|
|
464
|
+
this.geoRequested = true;
|
|
465
|
+
navigator.geolocation.getCurrentPosition(
|
|
466
|
+
(pos) => {
|
|
467
|
+
const round = (value, precision = 3) => Number(value.toFixed(precision));
|
|
468
|
+
this.geoContext = {
|
|
469
|
+
lat: round(pos.coords.latitude),
|
|
470
|
+
lon: round(pos.coords.longitude),
|
|
471
|
+
accuracy_m: Math.round(pos.coords.accuracy),
|
|
472
|
+
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
473
|
+
};
|
|
474
|
+
},
|
|
475
|
+
() => {
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
enableHighAccuracy: false,
|
|
479
|
+
maximumAge: 10 * 60 * 1e3,
|
|
480
|
+
timeout: 5e3
|
|
481
|
+
}
|
|
482
|
+
);
|
|
483
|
+
}
|
|
264
484
|
async flushEvents() {
|
|
265
485
|
if (this.eventQueue.length === 0) return;
|
|
266
486
|
const events = this.eventQueue.splice(0, this.eventQueue.length);
|
|
@@ -303,6 +523,7 @@ var Krypton = class {
|
|
|
303
523
|
}
|
|
304
524
|
captureSnapshot() {
|
|
305
525
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
526
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
306
527
|
const currentUrl = window.location.href;
|
|
307
528
|
if (this.lastSnapshotUrl === currentUrl) return;
|
|
308
529
|
this.lastSnapshotUrl = currentUrl;
|
|
@@ -338,9 +559,11 @@ var Krypton = class {
|
|
|
338
559
|
}
|
|
339
560
|
setupHeatmap() {
|
|
340
561
|
if (typeof window === "undefined") return;
|
|
562
|
+
if (this.heatmapSetup) return;
|
|
563
|
+
this.heatmapSetup = true;
|
|
341
564
|
this.captureSnapshot();
|
|
342
565
|
document.addEventListener("click", (e) => {
|
|
343
|
-
if (!this.
|
|
566
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
344
567
|
const target = e.target;
|
|
345
568
|
this.heatmapQueue.push({
|
|
346
569
|
project_id: this.config.apiKey,
|
|
@@ -361,7 +584,7 @@ var Krypton = class {
|
|
|
361
584
|
let maxScrollDepth = 0;
|
|
362
585
|
let scrollTimeout = null;
|
|
363
586
|
window.addEventListener("scroll", () => {
|
|
364
|
-
if (!this.
|
|
587
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
365
588
|
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
366
589
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
367
590
|
const depth = docHeight > 0 ? scrollTop / docHeight * 100 : 0;
|
package/dist/index.mjs
CHANGED
|
@@ -14,25 +14,31 @@ function generateId() {
|
|
|
14
14
|
}
|
|
15
15
|
function getSessionId() {
|
|
16
16
|
const key = "_krypton_sid";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
try {
|
|
18
|
+
if (typeof sessionStorage !== "undefined") {
|
|
19
|
+
let sid = sessionStorage.getItem(key);
|
|
20
|
+
if (!sid) {
|
|
21
|
+
sid = generateId();
|
|
22
|
+
sessionStorage.setItem(key, sid);
|
|
23
|
+
}
|
|
24
|
+
return sid;
|
|
22
25
|
}
|
|
23
|
-
|
|
26
|
+
} catch {
|
|
24
27
|
}
|
|
25
28
|
return generateId();
|
|
26
29
|
}
|
|
27
30
|
function getDistinctId() {
|
|
28
31
|
const key = "_krypton_did";
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
try {
|
|
33
|
+
if (typeof localStorage !== "undefined") {
|
|
34
|
+
let did = localStorage.getItem(key);
|
|
35
|
+
if (!did) {
|
|
36
|
+
did = generateId();
|
|
37
|
+
localStorage.setItem(key, did);
|
|
38
|
+
}
|
|
39
|
+
return did;
|
|
34
40
|
}
|
|
35
|
-
|
|
41
|
+
} catch {
|
|
36
42
|
}
|
|
37
43
|
return generateId();
|
|
38
44
|
}
|
|
@@ -79,35 +85,108 @@ var Krypton = class {
|
|
|
79
85
|
this.eventQueue = [];
|
|
80
86
|
this.heatmapQueue = [];
|
|
81
87
|
this.flushTimer = null;
|
|
82
|
-
this.consentGiven = false;
|
|
83
88
|
this.initialized = false;
|
|
84
89
|
this.lastSnapshotUrl = null;
|
|
90
|
+
this.heatmapSetup = false;
|
|
91
|
+
this.geoRequested = false;
|
|
92
|
+
this.geoContext = null;
|
|
85
93
|
this.serverConfig = null;
|
|
86
94
|
this.configFetched = false;
|
|
87
95
|
this.config = {
|
|
88
96
|
autoPageview: true,
|
|
89
97
|
heatmap: false,
|
|
90
98
|
consentRequired: false,
|
|
99
|
+
showConsentBanner: false,
|
|
100
|
+
consentCategories: {},
|
|
91
101
|
flushInterval: 5e3,
|
|
92
102
|
batchSize: 20,
|
|
93
103
|
...config
|
|
94
104
|
};
|
|
95
|
-
this.distinctId =
|
|
96
|
-
this.sessionId =
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
this.distinctId = generateId();
|
|
106
|
+
this.sessionId = generateId();
|
|
107
|
+
this.consent = this.resolveInitialConsent();
|
|
108
|
+
if (this.canTrackAnalytics()) {
|
|
109
|
+
this.promotePersistentIds();
|
|
99
110
|
}
|
|
100
111
|
this.init();
|
|
101
112
|
}
|
|
102
113
|
init() {
|
|
103
114
|
if (this.initialized) return;
|
|
104
115
|
this.initialized = true;
|
|
105
|
-
this.fetchConfig().then(() =>
|
|
116
|
+
this.fetchConfig().then(() => {
|
|
117
|
+
this.setupTracking();
|
|
118
|
+
if (this.config.consentRequired && this.config.showConsentBanner && !this.hasStoredConsent()) {
|
|
119
|
+
this.showConsentBanner();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
resolveInitialConsent() {
|
|
124
|
+
const stored = this.loadStoredConsent();
|
|
125
|
+
if (stored) return stored;
|
|
126
|
+
const base = this.config.consentRequired ? { analytics: false, heatmaps: false, geo: false } : {
|
|
127
|
+
analytics: true,
|
|
128
|
+
heatmaps: !!this.config.heatmap,
|
|
129
|
+
geo: false
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
...this.config.consentCategories
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
consentStorageKey() {
|
|
137
|
+
return `_krypton_consent_${this.config.apiKey}`;
|
|
138
|
+
}
|
|
139
|
+
hasStoredConsent() {
|
|
140
|
+
try {
|
|
141
|
+
if (typeof localStorage === "undefined") return false;
|
|
142
|
+
return !!localStorage.getItem(this.consentStorageKey());
|
|
143
|
+
} catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
loadStoredConsent() {
|
|
148
|
+
try {
|
|
149
|
+
if (typeof localStorage === "undefined") return null;
|
|
150
|
+
const raw = localStorage.getItem(this.consentStorageKey());
|
|
151
|
+
if (!raw) return null;
|
|
152
|
+
const parsed = JSON.parse(raw);
|
|
153
|
+
return {
|
|
154
|
+
analytics: !!parsed.analytics,
|
|
155
|
+
heatmaps: !!parsed.heatmaps,
|
|
156
|
+
geo: !!parsed.geo
|
|
157
|
+
};
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
persistConsent() {
|
|
163
|
+
try {
|
|
164
|
+
if (typeof localStorage === "undefined") return;
|
|
165
|
+
localStorage.setItem(this.consentStorageKey(), JSON.stringify(this.consent));
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
promotePersistentIds() {
|
|
170
|
+
this.distinctId = getDistinctId();
|
|
171
|
+
this.sessionId = getSessionId();
|
|
172
|
+
}
|
|
173
|
+
canTrackAnalytics() {
|
|
174
|
+
return !!this.consent.analytics;
|
|
175
|
+
}
|
|
176
|
+
isHeatmapFeatureEnabled() {
|
|
177
|
+
if (!this.config.heatmap) return false;
|
|
178
|
+
if (this.configFetched && !this.serverConfig?.heatmaps_enabled) return false;
|
|
179
|
+
return !!this.consent.heatmaps;
|
|
106
180
|
}
|
|
107
181
|
async fetchConfig() {
|
|
108
182
|
if (typeof window === "undefined") return;
|
|
109
183
|
const cacheKey = `_krypton_config_${this.config.apiKey}`;
|
|
110
|
-
|
|
184
|
+
let cached = null;
|
|
185
|
+
try {
|
|
186
|
+
cached = sessionStorage.getItem(cacheKey);
|
|
187
|
+
} catch {
|
|
188
|
+
cached = null;
|
|
189
|
+
}
|
|
111
190
|
if (cached) {
|
|
112
191
|
try {
|
|
113
192
|
const parsed = JSON.parse(cached);
|
|
@@ -127,83 +206,203 @@ var Krypton = class {
|
|
|
127
206
|
const data = await res.json();
|
|
128
207
|
this.serverConfig = data;
|
|
129
208
|
this.configFetched = true;
|
|
130
|
-
|
|
209
|
+
try {
|
|
210
|
+
sessionStorage.setItem(cacheKey, JSON.stringify({ ...data, _ts: Date.now() }));
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
131
213
|
}
|
|
132
214
|
} catch {
|
|
133
215
|
}
|
|
134
216
|
}
|
|
135
217
|
setupTracking() {
|
|
136
218
|
this.flushTimer = setInterval(() => this.flush(), this.config.flushInterval);
|
|
137
|
-
if (typeof window
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
219
|
+
if (typeof window === "undefined") return;
|
|
220
|
+
window.addEventListener("beforeunload", () => this.flush());
|
|
221
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
222
|
+
this.trackPageview();
|
|
223
|
+
}
|
|
224
|
+
const originalPushState = history.pushState;
|
|
225
|
+
history.pushState = (...args) => {
|
|
226
|
+
originalPushState.apply(history, args);
|
|
227
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
228
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
141
229
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
window.addEventListener("popstate", () => {
|
|
154
|
-
if (this.config.autoPageview && this.consentGiven) {
|
|
155
|
-
setTimeout(() => this.trackPageview(), 0);
|
|
156
|
-
}
|
|
157
|
-
if (heatmapEnabled && this.consentGiven) {
|
|
158
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
if (heatmapEnabled && this.consentGiven) {
|
|
162
|
-
this.setupHeatmap();
|
|
230
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
231
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const originalReplaceState = history.replaceState;
|
|
235
|
+
history.replaceState = (...args) => {
|
|
236
|
+
originalReplaceState.apply(history, args);
|
|
237
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
238
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
163
239
|
}
|
|
240
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
241
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
window.addEventListener("popstate", () => {
|
|
245
|
+
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
246
|
+
setTimeout(() => this.trackPageview(), 0);
|
|
247
|
+
}
|
|
248
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
249
|
+
setTimeout(() => this.captureSnapshot(), 0);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
if (this.isHeatmapFeatureEnabled()) {
|
|
253
|
+
this.setupHeatmap();
|
|
254
|
+
}
|
|
255
|
+
if (this.consent.geo) {
|
|
256
|
+
this.captureGeoOnce();
|
|
164
257
|
}
|
|
165
258
|
}
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
|
|
259
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps, geo). */
|
|
260
|
+
showConsentBanner() {
|
|
261
|
+
if (typeof document === "undefined") return;
|
|
262
|
+
if (document.getElementById("krypton-consent-banner")) return;
|
|
263
|
+
const banner = document.createElement("div");
|
|
264
|
+
banner.id = "krypton-consent-banner";
|
|
265
|
+
banner.style.cssText = [
|
|
266
|
+
"position:fixed",
|
|
267
|
+
"left:16px",
|
|
268
|
+
"right:16px",
|
|
269
|
+
"bottom:16px",
|
|
270
|
+
"z-index:2147483647",
|
|
271
|
+
"max-width:720px",
|
|
272
|
+
"margin:0 auto",
|
|
273
|
+
"background:#111827",
|
|
274
|
+
"color:#f9fafb",
|
|
275
|
+
"border-radius:12px",
|
|
276
|
+
"padding:16px",
|
|
277
|
+
"box-shadow:0 12px 30px rgba(0,0,0,0.35)",
|
|
278
|
+
"font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif",
|
|
279
|
+
"font-size:14px",
|
|
280
|
+
"line-height:1.4"
|
|
281
|
+
].join(";");
|
|
282
|
+
const checked = (value) => value ? "checked" : "";
|
|
283
|
+
banner.innerHTML = `
|
|
284
|
+
<div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
|
|
285
|
+
<div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
|
|
286
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
287
|
+
<input type="checkbox" id="krypton-consent-analytics" ${checked(this.consent.analytics)} />
|
|
288
|
+
<span><strong>Analytics</strong> (pageviews and custom events)</span>
|
|
289
|
+
</label>
|
|
290
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
291
|
+
<input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
|
|
292
|
+
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
293
|
+
</label>
|
|
294
|
+
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0 12px 0">
|
|
295
|
+
<input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
|
|
296
|
+
<span><strong>Geo location</strong> (browser geolocation if available)</span>
|
|
297
|
+
</label>
|
|
298
|
+
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
299
|
+
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
300
|
+
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
301
|
+
<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>
|
|
302
|
+
</div>
|
|
303
|
+
`;
|
|
304
|
+
const remove = () => {
|
|
305
|
+
banner.remove();
|
|
306
|
+
};
|
|
307
|
+
const readValue = (id) => {
|
|
308
|
+
const el = document.getElementById(id);
|
|
309
|
+
return !!el?.checked;
|
|
310
|
+
};
|
|
311
|
+
banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
|
|
312
|
+
this.setConsent({
|
|
313
|
+
analytics: readValue("krypton-consent-analytics"),
|
|
314
|
+
heatmaps: readValue("krypton-consent-heatmaps"),
|
|
315
|
+
geo: readValue("krypton-consent-geo")
|
|
316
|
+
});
|
|
317
|
+
remove();
|
|
318
|
+
});
|
|
319
|
+
banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
|
|
320
|
+
this.setConsent({ analytics: true, heatmaps: true, geo: true });
|
|
321
|
+
remove();
|
|
322
|
+
});
|
|
323
|
+
banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
|
|
324
|
+
this.setConsent({ analytics: false, heatmaps: false, geo: false });
|
|
325
|
+
remove();
|
|
326
|
+
});
|
|
327
|
+
document.body.appendChild(banner);
|
|
328
|
+
}
|
|
329
|
+
/** Set one or more consent categories and apply changes immediately. */
|
|
330
|
+
setConsent(next, persist = true) {
|
|
331
|
+
const prev = { ...this.consent };
|
|
332
|
+
this.consent = {
|
|
333
|
+
analytics: next.analytics ?? prev.analytics,
|
|
334
|
+
heatmaps: next.heatmaps ?? prev.heatmaps,
|
|
335
|
+
geo: next.geo ?? prev.geo
|
|
336
|
+
};
|
|
337
|
+
if (persist) {
|
|
338
|
+
this.persistConsent();
|
|
339
|
+
}
|
|
340
|
+
if (!prev.analytics && this.consent.analytics) {
|
|
341
|
+
this.promotePersistentIds();
|
|
342
|
+
if (this.config.autoPageview) {
|
|
343
|
+
this.trackPageview();
|
|
344
|
+
}
|
|
171
345
|
}
|
|
172
|
-
|
|
173
|
-
|
|
346
|
+
if (prev.analytics && !this.consent.analytics) {
|
|
347
|
+
this.eventQueue = [];
|
|
348
|
+
}
|
|
349
|
+
if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
|
|
174
350
|
this.setupHeatmap();
|
|
351
|
+
this.captureSnapshot();
|
|
352
|
+
}
|
|
353
|
+
if (prev.heatmaps && !this.consent.heatmaps) {
|
|
354
|
+
this.heatmapQueue = [];
|
|
355
|
+
}
|
|
356
|
+
if (!prev.geo && this.consent.geo) {
|
|
357
|
+
this.captureGeoOnce();
|
|
175
358
|
}
|
|
176
359
|
}
|
|
177
|
-
|
|
360
|
+
getConsent() {
|
|
361
|
+
return { ...this.consent };
|
|
362
|
+
}
|
|
363
|
+
/** Backward-compatible: grant all categories. */
|
|
364
|
+
grantConsent() {
|
|
365
|
+
this.setConsent({ analytics: true, heatmaps: true, geo: true });
|
|
366
|
+
}
|
|
367
|
+
/** Backward-compatible: revoke all categories and clear queues. */
|
|
178
368
|
revokeConsent() {
|
|
179
|
-
this.
|
|
369
|
+
this.setConsent({ analytics: false, heatmaps: false, geo: false });
|
|
180
370
|
this.eventQueue = [];
|
|
181
371
|
this.heatmapQueue = [];
|
|
182
372
|
}
|
|
183
373
|
/** Identify a user with a custom distinct ID */
|
|
184
374
|
identify(distinctId) {
|
|
185
375
|
this.distinctId = distinctId;
|
|
186
|
-
if (
|
|
187
|
-
|
|
376
|
+
if (this.canTrackAnalytics()) {
|
|
377
|
+
try {
|
|
378
|
+
if (typeof localStorage !== "undefined") {
|
|
379
|
+
localStorage.setItem("_krypton_did", distinctId);
|
|
380
|
+
}
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
188
383
|
}
|
|
189
384
|
}
|
|
190
385
|
/** Track a pageview */
|
|
191
386
|
trackPageview(properties) {
|
|
192
|
-
if (!this.
|
|
387
|
+
if (!this.canTrackAnalytics()) return;
|
|
193
388
|
this.track("$pageview", {
|
|
194
389
|
...properties
|
|
195
390
|
});
|
|
196
391
|
}
|
|
197
392
|
/** Track a custom event */
|
|
198
393
|
track(eventName, properties) {
|
|
199
|
-
if (!this.
|
|
394
|
+
if (!this.canTrackAnalytics()) return;
|
|
200
395
|
const utm = getUTMParams();
|
|
396
|
+
const mergedProperties = { ...properties || {} };
|
|
397
|
+
if (this.consent.geo && this.geoContext) {
|
|
398
|
+
mergedProperties.geo = this.geoContext;
|
|
399
|
+
}
|
|
201
400
|
const event = {
|
|
202
401
|
project_id: this.config.apiKey,
|
|
203
402
|
distinct_id: this.distinctId,
|
|
204
403
|
event_name: eventName,
|
|
205
404
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206
|
-
properties,
|
|
405
|
+
properties: mergedProperties,
|
|
207
406
|
page_url: typeof window !== "undefined" ? window.location.href : "",
|
|
208
407
|
page_title: typeof document !== "undefined" ? document.title : "",
|
|
209
408
|
referrer: typeof document !== "undefined" ? document.referrer : "",
|
|
@@ -223,11 +422,9 @@ var Krypton = class {
|
|
|
223
422
|
this.flush();
|
|
224
423
|
}
|
|
225
424
|
}
|
|
226
|
-
/** Flush all queued events to the server */
|
|
227
425
|
async flush() {
|
|
228
426
|
await Promise.all([this.flushEvents(), this.flushHeatmapEvents()]);
|
|
229
427
|
}
|
|
230
|
-
/** Shutdown the SDK */
|
|
231
428
|
shutdown() {
|
|
232
429
|
if (this.flushTimer) {
|
|
233
430
|
clearInterval(this.flushTimer);
|
|
@@ -235,7 +432,30 @@ var Krypton = class {
|
|
|
235
432
|
}
|
|
236
433
|
this.flush();
|
|
237
434
|
}
|
|
238
|
-
|
|
435
|
+
captureGeoOnce() {
|
|
436
|
+
if (this.geoRequested) return;
|
|
437
|
+
if (!this.consent.geo) return;
|
|
438
|
+
if (typeof navigator === "undefined" || !navigator.geolocation) return;
|
|
439
|
+
this.geoRequested = true;
|
|
440
|
+
navigator.geolocation.getCurrentPosition(
|
|
441
|
+
(pos) => {
|
|
442
|
+
const round = (value, precision = 3) => Number(value.toFixed(precision));
|
|
443
|
+
this.geoContext = {
|
|
444
|
+
lat: round(pos.coords.latitude),
|
|
445
|
+
lon: round(pos.coords.longitude),
|
|
446
|
+
accuracy_m: Math.round(pos.coords.accuracy),
|
|
447
|
+
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
448
|
+
};
|
|
449
|
+
},
|
|
450
|
+
() => {
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
enableHighAccuracy: false,
|
|
454
|
+
maximumAge: 10 * 60 * 1e3,
|
|
455
|
+
timeout: 5e3
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
}
|
|
239
459
|
async flushEvents() {
|
|
240
460
|
if (this.eventQueue.length === 0) return;
|
|
241
461
|
const events = this.eventQueue.splice(0, this.eventQueue.length);
|
|
@@ -278,6 +498,7 @@ var Krypton = class {
|
|
|
278
498
|
}
|
|
279
499
|
captureSnapshot() {
|
|
280
500
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
501
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
281
502
|
const currentUrl = window.location.href;
|
|
282
503
|
if (this.lastSnapshotUrl === currentUrl) return;
|
|
283
504
|
this.lastSnapshotUrl = currentUrl;
|
|
@@ -313,9 +534,11 @@ var Krypton = class {
|
|
|
313
534
|
}
|
|
314
535
|
setupHeatmap() {
|
|
315
536
|
if (typeof window === "undefined") return;
|
|
537
|
+
if (this.heatmapSetup) return;
|
|
538
|
+
this.heatmapSetup = true;
|
|
316
539
|
this.captureSnapshot();
|
|
317
540
|
document.addEventListener("click", (e) => {
|
|
318
|
-
if (!this.
|
|
541
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
319
542
|
const target = e.target;
|
|
320
543
|
this.heatmapQueue.push({
|
|
321
544
|
project_id: this.config.apiKey,
|
|
@@ -336,7 +559,7 @@ var Krypton = class {
|
|
|
336
559
|
let maxScrollDepth = 0;
|
|
337
560
|
let scrollTimeout = null;
|
|
338
561
|
window.addEventListener("scroll", () => {
|
|
339
|
-
if (!this.
|
|
562
|
+
if (!this.isHeatmapFeatureEnabled()) return;
|
|
340
563
|
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
341
564
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
342
565
|
const depth = docHeight > 0 ? scrollTop / docHeight * 100 : 0;
|