@kryptonhq/analytics 0.1.6 → 0.1.9
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 +37 -96
- package/dist/browser.global.js +5 -9
- package/dist/index.d.mts +2 -8
- package/dist/index.d.ts +2 -8
- package/dist/index.js +13 -99
- package/dist/index.mjs +13 -101
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -1,136 +1,77 @@
|
|
|
1
1
|
# @kryptonhq/analytics
|
|
2
2
|
|
|
3
|
-
Krypton Analytics JavaScript SDK.
|
|
4
|
-
|
|
5
|
-
## Install (npm)
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @kryptonhq/analytics
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { Krypton } from "@kryptonhq/analytics";
|
|
13
|
-
|
|
14
|
-
const krypton = new Krypton({
|
|
15
|
-
apiKey: "kapi_xxx",
|
|
16
|
-
endpoint: "https://ingest.yourdomain.com",
|
|
17
|
-
autoPageview: true,
|
|
18
|
-
heatmap: true,
|
|
19
|
-
consentRequired: true,
|
|
20
|
-
showConsentBanner: true,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
krypton.track("signup_clicked", { plan: "pro" });
|
|
24
|
-
```
|
|
3
|
+
Krypton Analytics JavaScript SDK — privacy-first analytics tracking.
|
|
25
4
|
|
|
26
5
|
## Install (CDN, script tag)
|
|
27
6
|
|
|
28
|
-
Use jsDelivr:
|
|
29
|
-
|
|
30
7
|
```html
|
|
31
8
|
<script defer src="https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js"></script>
|
|
32
9
|
<script>
|
|
33
|
-
window.addEventListener("
|
|
34
|
-
|
|
10
|
+
window.addEventListener("load", function () {
|
|
11
|
+
window.krypton = window.KryptonAnalytics.init({
|
|
35
12
|
apiKey: "kapi_xxx",
|
|
36
13
|
endpoint: "https://ingest.yourdomain.com",
|
|
37
14
|
autoPageview: true,
|
|
38
15
|
heatmap: true,
|
|
39
16
|
consentRequired: true,
|
|
40
17
|
showConsentBanner: true
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
krypton.track("page_loaded");
|
|
44
|
-
});
|
|
18
|
+
})
|
|
19
|
+
})
|
|
45
20
|
</script>
|
|
46
21
|
```
|
|
47
22
|
|
|
48
23
|
The CDN build exposes a global: `window.KryptonAnalytics`.
|
|
49
24
|
|
|
50
|
-
##
|
|
51
|
-
|
|
52
|
-
The SDK supports category-level consent:
|
|
53
|
-
|
|
54
|
-
- `analytics`
|
|
55
|
-
- `heatmaps`
|
|
56
|
-
- `geo` (browser geolocation, if granted by user)
|
|
25
|
+
## Install (npm)
|
|
57
26
|
|
|
58
|
-
|
|
27
|
+
```bash
|
|
28
|
+
npm install @kryptonhq/analytics
|
|
29
|
+
```
|
|
59
30
|
|
|
60
31
|
```ts
|
|
61
|
-
import {
|
|
32
|
+
import { createKrypton } from "@kryptonhq/analytics";
|
|
62
33
|
|
|
63
|
-
const krypton =
|
|
34
|
+
const krypton = createKrypton({
|
|
64
35
|
apiKey: "kapi_xxx",
|
|
65
36
|
endpoint: "https://ingest.yourdomain.com",
|
|
37
|
+
autoPageview: true,
|
|
66
38
|
heatmap: true,
|
|
67
|
-
consentRequired: true,
|
|
68
|
-
showConsentBanner: true,
|
|
39
|
+
consentRequired: true,
|
|
40
|
+
showConsentBanner: true,
|
|
69
41
|
});
|
|
70
42
|
|
|
71
|
-
|
|
72
|
-
krypton.setConsent({
|
|
73
|
-
analytics: true,
|
|
74
|
-
heatmaps: false,
|
|
75
|
-
geo: false,
|
|
76
|
-
});
|
|
43
|
+
krypton.track("signup", { plan: "pro" });
|
|
77
44
|
```
|
|
78
45
|
|
|
79
|
-
|
|
46
|
+
## Consent (default deny + categories)
|
|
80
47
|
|
|
81
|
-
|
|
82
|
-
<script>
|
|
83
|
-
(function (w, d, s, u, n) {
|
|
84
|
-
w[n] = w[n] || function () { (w[n].q = w[n].q || []).push(arguments); };
|
|
85
|
-
w[n].l = +new Date();
|
|
86
|
-
var js = d.createElement(s), fjs = d.getElementsByTagName(s)[0];
|
|
87
|
-
js.async = 1;
|
|
88
|
-
js.src = u;
|
|
89
|
-
js.onload = function () {
|
|
90
|
-
var cfg = w[n].cfg;
|
|
91
|
-
w[n].client = w.KryptonAnalytics.init(cfg);
|
|
92
|
-
var q = w[n].q || [];
|
|
93
|
-
for (var i = 0; i < q.length; i++) {
|
|
94
|
-
var args = q[i];
|
|
95
|
-
if (args[0] === "track") w[n].client.track(args[1], args[2]);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
fjs.parentNode.insertBefore(js, fjs);
|
|
99
|
-
})(window, document, "script", "https://cdn.jsdelivr.net/npm/@kryptonhq/analytics@latest/dist/browser.global.js", "krypton");
|
|
100
|
-
|
|
101
|
-
krypton.cfg = {
|
|
102
|
-
apiKey: "kapi_xxx",
|
|
103
|
-
endpoint: "https://ingest.yourdomain.com",
|
|
104
|
-
autoPageview: true,
|
|
105
|
-
heatmap: true
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
krypton("track", "landing_view");
|
|
109
|
-
</script>
|
|
110
|
-
```
|
|
48
|
+
The SDK supports category-level consent:
|
|
111
49
|
|
|
112
|
-
|
|
50
|
+
- `analytics` — pageviews and custom events
|
|
51
|
+
- `heatmaps` — click and scroll interaction maps
|
|
113
52
|
|
|
114
|
-
|
|
53
|
+
When `consentRequired: true` and `showConsentBanner: true`, a built-in consent popup is shown automatically. No data is collected until the user grants consent.
|
|
115
54
|
|
|
116
|
-
-
|
|
55
|
+
Geolocation is resolved server-side from the request IP (no browser Geolocation API needed).
|
|
117
56
|
|
|
118
|
-
|
|
57
|
+
### Manual consent control
|
|
119
58
|
|
|
120
|
-
|
|
121
|
-
|
|
59
|
+
```ts
|
|
60
|
+
krypton.setConsent({ analytics: true, heatmaps: false });
|
|
122
61
|
|
|
123
|
-
|
|
62
|
+
krypton.grantConsent(); // grant all
|
|
63
|
+
krypton.revokeConsent(); // revoke all
|
|
124
64
|
|
|
125
|
-
|
|
65
|
+
krypton.showConsentBanner(); // re-show the popup
|
|
66
|
+
```
|
|
126
67
|
|
|
127
|
-
|
|
68
|
+
## API
|
|
128
69
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
70
|
+
```ts
|
|
71
|
+
krypton.track("event_name", { key: "value" });
|
|
72
|
+
krypton.trackPageview();
|
|
73
|
+
krypton.identify("user-123");
|
|
74
|
+
krypton.flush();
|
|
75
|
+
krypton.shutdown();
|
|
76
|
+
krypton.getConsent(); // { analytics: boolean, heatmaps: boolean }
|
|
77
|
+
```
|
package/dist/browser.global.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
"use strict";var KryptonAnalytics=(()=>{var Z=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var Se=Object.prototype.hasOwnProperty;var Ce=(e,t)=>{for(var r in t)Z(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of be(t))!Se.call(e,i)&&i!==r&&Z(e,i,{get:()=>t[i],enumerable:!(n=ke(t,i))||n.enumerable});return e};var Ie=e=>xe(Z({},"__esModule",{value:!0}),e);var at={};Ce(at,{Krypton:()=>$,default:()=>it,init:()=>ye});var v;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(v||(v={}));function Te(e){return e.nodeType===e.ELEMENT_NODE}function Ee(e){var t=e?.host;return t?.shadowRoot===e}function ee(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function Le(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function te(e){try{var t=e.rules||e.cssRules;return t?Le(Array.from(t).map(Re).join("")):null}catch{return null}}function Re(e){var t=e.cssText;if(_e(e))try{t=te(e.styleSheet)||t}catch{}return t}function _e(e){return"styleSheet"in e}var Ne=(function(){function e(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}return e.prototype.getId=function(t){var r;if(!t)return-1;var n=(r=this.getMeta(t))===null||r===void 0?void 0:r.id;return n??-1},e.prototype.getNode=function(t){return this.idNodeMap.get(t)||null},e.prototype.getIds=function(){return Array.from(this.idNodeMap.keys())},e.prototype.getMeta=function(t){return this.nodeMetaMap.get(t)||null},e.prototype.removeNodeFromMap=function(t){var r=this,n=this.getId(t);this.idNodeMap.delete(n),t.childNodes&&t.childNodes.forEach(function(i){return r.removeNodeFromMap(i)})},e.prototype.has=function(t){return this.idNodeMap.has(t)},e.prototype.hasNode=function(t){return this.nodeMetaMap.has(t)},e.prototype.add=function(t,r){var n=r.id;this.idNodeMap.set(n,t),this.nodeMetaMap.set(t,r)},e.prototype.replace=function(t,r){var n=this.getNode(t);if(n){var i=this.nodeMetaMap.get(n);i&&this.nodeMetaMap.set(r,i)}this.idNodeMap.set(t,r)},e.prototype.reset=function(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap},e})();function Oe(e){var t=e.maskInputOptions,r=e.tagName,n=e.type,i=e.value,a=e.maskInputFn,c=i||"";return(t[r.toLowerCase()]||t[n])&&(a?c=a(c):c="*".repeat(c.length)),c}var le="__rrweb_original__";function Ae(e){var t=e.getContext("2d");if(!t)return!0;for(var r=50,n=0;n<e.width;n+=r)for(var i=0;i<e.height;i+=r){var a=t.getImageData,c=le in a?a[le]:a,u=new Uint32Array(c.call(t,n,i,Math.min(r,e.width-n),Math.min(r,e.height-i)).data.buffer);if(u.some(function(o){return o!==0}))return!1}return!0}var Me=1,Pe=new RegExp("[^a-z0-9-_:]"),ue=-2;function De(){return Me++}function Fe(e){if(e instanceof HTMLFormElement)return"form";var t=e.tagName.toLowerCase().trim();return Pe.test(t)?"div":t}function He(e){return e.cssRules?Array.from(e.cssRules).map(function(t){return t.cssText||""}).join(""):""}function Ue(e){var t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}var q,fe,We=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Be=/^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/,Ke=/^(data:)([^,]*),(.*)/i;function Q(e,t){return(e||"").replace(We,function(r,n,i,a,c,u){var o=i||c||u,f=n||a||"";if(!o)return r;if(!Be.test(o)||Ke.test(o))return"url(".concat(f).concat(o).concat(f,")");if(o[0]==="/")return"url(".concat(f).concat(Ue(t)+o).concat(f,")");var l=t.split("/"),p=o.split("/");l.pop();for(var S=0,w=p;S<w.length;S++){var k=w[S];k!=="."&&(k===".."?l.pop():l.push(k))}return"url(".concat(f).concat(l.join("/")).concat(f,")")})}var qe=/^[^ \t\n\r\u000c]+/,ze=/^[, \t\n\r\u000c]+/;function $e(e,t){if(t.trim()==="")return t;var r=0;function n(f){var l,p=f.exec(t.substring(r));return p?(l=p[0],r+=l.length,l):""}for(var i=[];n(ze),!(r>=t.length);){var a=n(qe);if(a.slice(-1)===",")a=z(e,a.substring(0,a.length-1)),i.push(a);else{var c="";a=z(e,a);for(var u=!1;;){var o=t.charAt(r);if(o===""){i.push((a+c).trim());break}else if(u)o===")"&&(u=!1);else if(o===","){r+=1,i.push((a+c).trim());break}else o==="("&&(u=!0);c+=o,r+=1}}}return i.join(", ")}function z(e,t){if(!t||t.trim()==="")return t;var r=e.createElement("a");return r.href=t,r.href}function je(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function ne(){var e=document.createElement("a");return e.href="",e.href}function Ge(e,t,r,n){return r==="src"||r==="href"&&n&&!(t==="use"&&n[0]==="#")||r==="xlink:href"&&n&&n[0]!=="#"||r==="background"&&n&&(t==="table"||t==="td"||t==="th")?z(e,n):r==="srcset"&&n?$e(e,n):r==="style"&&n?Q(n,ne()):t==="object"&&r==="data"&&n?z(e,n):n}function Qe(e,t,r){if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?e.matches(r):!1}function re(e,t,r){if(!e)return!1;if(e.nodeType!==e.ELEMENT_NODE)return r?re(e.parentNode,t,r):!1;for(var n=e.classList.length;n--;){var i=e.classList[n];if(t.test(i))return!0}return r?re(e.parentNode,t,r):!1}function Je(e,t,r){var n=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(n===null)return!1;if(typeof t=="string"){if(n.classList.contains(t)||n.closest(".".concat(t)))return!0}else if(re(n,t,!0))return!0;return!!(r&&(n.matches(r)||n.closest(r)))}function Ve(e,t,r){var n=e.contentWindow;if(n){var i=!1,a;try{a=n.document.readyState}catch{return}if(a!=="complete"){var c=setTimeout(function(){i||(t(),i=!0)},r);e.addEventListener("load",function(){clearTimeout(c),i=!0,t()});return}var u="about:blank";if(n.location.href!==u||e.src===u||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}}function Ye(e,t,r){var n=!1,i;try{i=e.sheet}catch{return}if(!i){var a=setTimeout(function(){n||(t(),n=!0)},r);e.addEventListener("load",function(){clearTimeout(a),n=!0,t()})}}function Xe(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.inlineStylesheet,f=t.maskInputOptions,l=f===void 0?{}:f,p=t.maskTextFn,S=t.maskInputFn,w=t.dataURLOptions,k=w===void 0?{}:w,x=t.inlineImages,I=t.recordCanvas,T=t.keepIframeSrcFn,h=t.newlyAddedElement,s=h===void 0?!1:h,y=Ze(r,n);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:v.Document,childNodes:[],compatMode:e.compatMode}:{type:v.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:v.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:y};case e.ELEMENT_NODE:return tt(e,{doc:r,blockClass:i,blockSelector:a,inlineStylesheet:o,maskInputOptions:l,maskInputFn:S,dataURLOptions:k,inlineImages:x,recordCanvas:I,keepIframeSrcFn:T,newlyAddedElement:s,rootId:y});case e.TEXT_NODE:return et(e,{maskTextClass:c,maskTextSelector:u,maskTextFn:p,rootId:y});case e.CDATA_SECTION_NODE:return{type:v.CDATA,textContent:"",rootId:y};case e.COMMENT_NODE:return{type:v.Comment,textContent:e.textContent||"",rootId:y};default:return!1}}function Ze(e,t){if(t.hasNode(e)){var r=t.getId(e);return r===1?void 0:r}}function et(e,t){var r,n=t.maskTextClass,i=t.maskTextSelector,a=t.maskTextFn,c=t.rootId,u=e.parentNode&&e.parentNode.tagName,o=e.textContent,f=u==="STYLE"?!0:void 0,l=u==="SCRIPT"?!0:void 0;if(f&&o){try{e.nextSibling||e.previousSibling||!((r=e.parentNode.sheet)===null||r===void 0)&&r.cssRules&&(o=He(e.parentNode.sheet))}catch(p){console.warn("Cannot get CSS styles from text's parentNode. Error: ".concat(p),e)}o=Q(o,ne())}return l&&(o="SCRIPT_PLACEHOLDER"),!f&&!l&&o&&Je(e,n,i)&&(o=a?a(o):o.replace(/[\S]/g,"*")),{type:v.Text,textContent:o||"",isStyle:f,rootId:c}}function tt(e,t){for(var r=t.doc,n=t.blockClass,i=t.blockSelector,a=t.inlineStylesheet,c=t.maskInputOptions,u=c===void 0?{}:c,o=t.maskInputFn,f=t.dataURLOptions,l=f===void 0?{}:f,p=t.inlineImages,S=t.recordCanvas,w=t.keepIframeSrcFn,k=t.newlyAddedElement,x=k===void 0?!1:k,I=t.rootId,T=Qe(e,n,i),h=Fe(e),s={},y=e.attributes.length,A=0;A<y;A++){var E=e.attributes[A];s[E.name]=Ge(r,h,E.name,E.value)}if(h==="link"&&a){var C=Array.from(r.styleSheets).find(function(R){return R.href===e.href}),m=null;C&&(m=te(C)),m&&(delete s.rel,delete s.href,s._cssText=Q(m,C.href))}if(h==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){var m=te(e.sheet);m&&(s._cssText=Q(m,ne()))}if(h==="input"||h==="textarea"||h==="select"){var F=e.value,_=e.checked;s.type!=="radio"&&s.type!=="checkbox"&&s.type!=="submit"&&s.type!=="button"&&F?s.value=Oe({type:s.type,tagName:h,value:F,maskInputOptions:u,maskInputFn:o}):_&&(s.checked=_)}if(h==="option"&&(e.selected&&!u.select?s.selected=!0:delete s.selected),h==="canvas"&&S){if(e.__context==="2d")Ae(e)||(s.rr_dataURL=e.toDataURL(l.type,l.quality));else if(!("__context"in e)){var L=e.toDataURL(l.type,l.quality),M=document.createElement("canvas");M.width=e.width,M.height=e.height;var P=M.toDataURL(l.type,l.quality);L!==P&&(s.rr_dataURL=L)}}if(h==="img"&&p){q||(q=r.createElement("canvas"),fe=q.getContext("2d"));var b=e,N=b.crossOrigin;b.crossOrigin="anonymous";var D=function(){try{q.width=b.naturalWidth,q.height=b.naturalHeight,fe.drawImage(b,0,0),s.rr_dataURL=q.toDataURL(l.type,l.quality)}catch(R){console.warn("Cannot inline img src=".concat(b.currentSrc,"! Error: ").concat(R))}N?s.crossOrigin=N:b.removeAttribute("crossorigin")};b.complete&&b.naturalWidth!==0?D():b.onload=D}if((h==="audio"||h==="video")&&(s.rr_mediaState=e.paused?"paused":"played",s.rr_mediaCurrentTime=e.currentTime),x||(e.scrollLeft&&(s.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(s.rr_scrollTop=e.scrollTop)),T){var U=e.getBoundingClientRect(),W=U.width,O=U.height;s={class:s.class,rr_width:"".concat(W,"px"),rr_height:"".concat(O,"px")}}return h==="iframe"&&!w(s.src)&&(e.contentDocument||(s.rr_src=s.src),delete s.src),{type:v.Element,tagName:h,attributes:s,childNodes:[],isSVG:je(e)||void 0,needBlock:T,rootId:I}}function d(e){return e===void 0?"":e.toLowerCase()}function rt(e,t){if(t.comment&&e.type===v.Comment)return!0;if(e.type===v.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&e.attributes.rel==="preload"&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&e.attributes.href.endsWith(".js")))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(d(e.attributes.name).match(/^msapplication-tile(image|color)$/)||d(e.attributes.name)==="application-name"||d(e.attributes.rel)==="icon"||d(e.attributes.rel)==="apple-touch-icon"||d(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&d(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(d(e.attributes.property).match(/^(og|twitter|fb):/)||d(e.attributes.name).match(/^(og|twitter):/)||d(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(d(e.attributes.name)==="robots"||d(e.attributes.name)==="googlebot"||d(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(d(e.attributes.name)==="author"||d(e.attributes.name)==="generator"||d(e.attributes.name)==="framework"||d(e.attributes.name)==="publisher"||d(e.attributes.name)==="progid"||d(e.attributes.property).match(/^article:/)||d(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(d(e.attributes.name)==="google-site-verification"||d(e.attributes.name)==="yandex-verification"||d(e.attributes.name)==="csrf-token"||d(e.attributes.name)==="p:domain_verify"||d(e.attributes.name)==="verify-v1"||d(e.attributes.name)==="verification"||d(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function G(e,t){var r=t.doc,n=t.mirror,i=t.blockClass,a=t.blockSelector,c=t.maskTextClass,u=t.maskTextSelector,o=t.skipChild,f=o===void 0?!1:o,l=t.inlineStylesheet,p=l===void 0?!0:l,S=t.maskInputOptions,w=S===void 0?{}:S,k=t.maskTextFn,x=t.maskInputFn,I=t.slimDOMOptions,T=t.dataURLOptions,h=T===void 0?{}:T,s=t.inlineImages,y=s===void 0?!1:s,A=t.recordCanvas,E=A===void 0?!1:A,C=t.onSerialize,m=t.onIframeLoad,F=t.iframeLoadTimeout,_=F===void 0?5e3:F,L=t.onStylesheetLoad,M=t.stylesheetLoadTimeout,P=M===void 0?5e3:M,b=t.keepIframeSrcFn,N=b===void 0?function(){return!1}:b,D=t.newlyAddedElement,U=D===void 0?!1:D,W=t.preserveWhiteSpace,O=W===void 0?!0:W,R=Xe(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,dataURLOptions:h,inlineImages:y,recordCanvas:E,keepIframeSrcFn:N,newlyAddedElement:U});if(!R)return console.warn(e,"not serialized"),null;var j;n.hasNode(e)?j=n.getId(e):rt(R,I)||!O&&R.type===v.Text&&!R.isStyle&&!R.textContent.replace(/^\s+|\s+$/gm,"").length?j=ue:j=De();var g=Object.assign(R,{id:j});if(n.add(e,g),j===ue)return null;C&&C(e);var J=!f;if(g.type===v.Element){J=J&&!g.needBlock,delete g.needBlock;var ie=e.shadowRoot;ie&&ee(ie)&&(g.isShadowHost=!0)}if((g.type===v.Document||g.type===v.Element)&&J){I.headWhitespace&&g.type===v.Element&&g.tagName==="head"&&(O=!1);for(var ae={doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:f,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N},V=0,oe=Array.from(e.childNodes);V<oe.length;V++){var Y=oe[V],B=G(Y,ae);B&&g.childNodes.push(B)}if(Te(e)&&e.shadowRoot)for(var X=0,se=Array.from(e.shadowRoot.childNodes);X<se.length;X++){var Y=se[X],B=G(Y,ae);B&&(ee(e.shadowRoot)&&(B.isShadow=!0),g.childNodes.push(B))}}return e.parentNode&&Ee(e.parentNode)&&ee(e.parentNode)&&(g.isShadow=!0),g.type===v.Element&&g.tagName==="iframe"&&Ve(e,function(){var K=e.contentDocument;if(K&&m){var ce=G(K,{doc:K,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});ce&&m(e,ce)}},_),g.type===v.Element&&g.tagName==="link"&&g.attributes.rel==="stylesheet"&&Ye(e,function(){if(L){var K=G(e,{doc:r,mirror:n,blockClass:i,blockSelector:a,maskTextClass:c,maskTextSelector:u,skipChild:!1,inlineStylesheet:p,maskInputOptions:w,maskTextFn:k,maskInputFn:x,slimDOMOptions:I,dataURLOptions:h,inlineImages:y,recordCanvas:E,preserveWhiteSpace:O,onSerialize:C,onIframeLoad:m,iframeLoadTimeout:_,onStylesheetLoad:L,stylesheetLoadTimeout:P,keepIframeSrcFn:N});K&&L(e,K)}},P),g}function de(e,t){var r=t||{},n=r.mirror,i=n===void 0?new Ne:n,a=r.blockClass,c=a===void 0?"rr-block":a,u=r.blockSelector,o=u===void 0?null:u,f=r.maskTextClass,l=f===void 0?"rr-mask":f,p=r.maskTextSelector,S=p===void 0?null:p,w=r.inlineStylesheet,k=w===void 0?!0:w,x=r.inlineImages,I=x===void 0?!1:x,T=r.recordCanvas,h=T===void 0?!1:T,s=r.maskAllInputs,y=s===void 0?!1:s,A=r.maskTextFn,E=r.maskInputFn,C=r.slimDOM,m=C===void 0?!1:C,F=r.dataURLOptions,_=r.preserveWhiteSpace,L=r.onSerialize,M=r.onIframeLoad,P=r.iframeLoadTimeout,b=r.onStylesheetLoad,N=r.stylesheetLoadTimeout,D=r.keepIframeSrcFn,U=D===void 0?function(){return!1}:D,W=y===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,password:!0}:y===!1?{password:!0}:y,O=m===!0||m==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:m==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:m===!1?{}:m;return G(e,{doc:e,mirror:i,blockClass:c,blockSelector:o,maskTextClass:l,maskTextSelector:S,skipChild:!1,inlineStylesheet:k,maskInputOptions:W,maskTextFn:A,maskInputFn:E,slimDOMOptions:O,dataURLOptions:F,inlineImages:I,recordCanvas:h,preserveWhiteSpace:_,onSerialize:L,onIframeLoad:M,iframeLoadTimeout:P,onStylesheetLoad:b,stylesheetLoadTimeout:N,keepIframeSrcFn:U,newlyAddedElement:!1})}var nt=/([^\\]):hover/,st=new RegExp(nt.source,"g");function H(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function he(){let e="_krypton_sid";try{if(typeof sessionStorage<"u"){let t=sessionStorage.getItem(e);return t||(t=H(),sessionStorage.setItem(e,t)),t}}catch{}return H()}function pe(){let e="_krypton_did";try{if(typeof localStorage<"u"){let t=localStorage.getItem(e);return t||(t=H(),localStorage.setItem(e,t)),t}}catch{}return H()}function me(){if(typeof window>"u")return{};let e=new URLSearchParams(window.location.search),t={};for(let r of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let n=e.get(r);n&&(t[r]=n)}return t}function ge(){if(typeof window>"u")return"unknown";let e=window.innerWidth;return e<768?"mobile":e<1024?"tablet":"desktop"}function ve(e){if(e.id)return`#${e.id}`;let t=[],r=e;for(;r&&r!==document.body;){let n=r.tagName.toLowerCase();if(r.id){t.unshift(`#${r.id}`);break}if(r.className&&typeof r.className=="string"){let i=r.className.trim().split(/\s+/).slice(0,2).join(".");i&&(n+=`.${i}`)}t.unshift(n),r=r.parentElement}return t.join(" > ")}var $=class{constructor(t){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.lastSnapshotUrl=null;this.heatmapSetup=!1;this.geoRequested=!1;this.geoContext=null;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,debug:!1,disableConfigCache:!1,...t},this.distinctId=H(),this.sessionId=H(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(t){this.warn("setupTracking failed",t)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()?(this.debug("showing consent banner automatically",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner}),this.showConsentBannerWhenReady()):this.debug("skipping consent banner",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner,hasStoredConsent:this.hasStoredConsent()})}catch(t){this.warn("consent banner initialization failed",t)}}))}showConsentBannerWhenReady(t=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}t<=0||setTimeout(()=>this.showConsentBannerWhenReady(t-1),50)}}resolveInitialConsent(){let t=this.loadStoredConsent();return t||{...this.config.consentRequired?{analytics:!1,heatmaps:!1,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=pe(),this.sessionId=he()}canTrackAnalytics(){return!!this.consent.analytics}isHeatmapFeatureEnabled(){return!this.config.heatmap||this.configFetched&&!this.serverConfig?.heatmaps_enabled?!1:!!this.consent.heatmaps}async fetchConfig(){if(typeof window>"u")return;let t=`_krypton_config_${this.config.apiKey}`,r=null;if(!this.config.disableConfigCache)try{r=sessionStorage.getItem(t)}catch{r=null}if(r)try{let n=JSON.parse(r);if(n._ts&&Date.now()-n._ts<300*1e3){this.serverConfig=n,this.configFetched=!0,this.debug("config loaded from session cache",n);return}}catch{}try{let n=new AbortController,i=setTimeout(()=>n.abort(),5e3),a=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:n.signal});if(clearTimeout(i),a.ok){let c=await a.json();if(this.serverConfig=c,this.configFetched=!0,this.debug("config fetched from API",c),!this.config.disableConfigCache)try{sessionStorage.setItem(t,JSON.stringify({...c,_ts:Date.now()}))}catch{}}else this.warn(`Config fetch failed (${a.status})`,{endpoint:this.config.endpoint})}catch(n){this.warn("Config fetch failed",n)}}setupTracking(){if(this.flushTimer=setInterval(()=>{this.flush()},this.config.flushInterval),typeof window>"u")return;window.addEventListener("beforeunload",()=>{this.flush()}),this.config.autoPageview&&this.canTrackAnalytics()&&this.trackPageview();let t=history.pushState;history.pushState=(...n)=>{try{t.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("pushState hook failed",i)}};let r=history.replaceState;history.replaceState=(...n)=>{try{r.apply(history,n),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0),this.isHeatmapFeatureEnabled()&&setTimeout(()=>this.captureSnapshot(),0)}catch(n){this.warn("popstate hook failed",n)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap(),this.consent.geo&&this.captureGeoOnce()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let t=document.createElement("div");t.id="krypton-consent-banner",t.style.cssText=["position:fixed","left:16px","right:16px","bottom:16px","z-index:2147483647","max-width:720px","margin:0 auto","background:#111827","color:#f9fafb","border-radius:12px","padding:16px","box-shadow:0 12px 30px rgba(0,0,0,0.35)","font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif","font-size:14px","line-height:1.4"].join(";");let r=a=>a?"checked":"";t.innerHTML=`
|
|
1
|
+
"use strict";var KryptonAnalytics=(()=>{var l=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var x=(s,e)=>{for(var n in e)l(s,n,{get:e[n],enumerable:!0})},b=(s,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of w(e))!v.call(s,i)&&i!==n&&l(s,i,{get:()=>e[i],enumerable:!(t=y(e,i))||t.enumerable});return s};var k=s=>b(l({},"__esModule",{value:!0}),s);var S={};x(S,{Krypton:()=>r,default:()=>C,init:()=>g});function a(){return typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,s=>{let e=Math.random()*16|0;return(s==="x"?e:e&3|8).toString(16)})}function d(){let s="_krypton_sid";try{if(typeof sessionStorage<"u"){let e=sessionStorage.getItem(s);return e||(e=a(),sessionStorage.setItem(s,e)),e}}catch{}return a()}function h(){let s="_krypton_did";try{if(typeof localStorage<"u"){let e=localStorage.getItem(s);return e||(e=a(),localStorage.setItem(s,e)),e}}catch{}return a()}function u(){if(typeof window>"u")return{};let s=new URLSearchParams(window.location.search),e={};for(let n of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){let t=s.get(n);t&&(e[n]=t)}return e}function p(){if(typeof window>"u")return"unknown";let s=window.innerWidth;return s<768?"mobile":s<1024?"tablet":"desktop"}function f(s){if(s.id)return`#${s.id}`;let e=[],n=s;for(;n&&n!==document.body;){let t=n.tagName.toLowerCase();if(n.id){e.unshift(`#${n.id}`);break}if(n.className&&typeof n.className=="string"){let i=n.className.trim().split(/\s+/).slice(0,2).join(".");i&&(t+=`.${i}`)}e.unshift(t),n=n.parentElement}return e.join(" > ")}var r=class{constructor(e){this.eventQueue=[];this.heatmapQueue=[];this.flushTimer=null;this.initialized=!1;this.heatmapSetup=!1;this.serverConfig=null;this.configFetched=!1;this.logPrefix="[Krypton SDK]";this.config={autoPageview:!0,heatmap:!1,consentRequired:!1,showConsentBanner:!1,consentCategories:{},flushInterval:5e3,batchSize:20,debug:!1,disableConfigCache:!1,...e},this.distinctId=a(),this.sessionId=a(),this.consent=this.resolveInitialConsent(),this.canTrackAnalytics()&&this.promotePersistentIds(),this.init()}init(){this.initialized||(this.initialized=!0,this.fetchConfig().finally(()=>{try{this.setupTracking()}catch(e){this.warn("setupTracking failed",e)}try{this.config.consentRequired&&this.config.showConsentBanner&&!this.hasStoredConsent()?(this.debug("showing consent banner automatically",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner}),this.showConsentBannerWhenReady()):this.debug("skipping consent banner",{consentRequired:this.config.consentRequired,showConsentBanner:this.config.showConsentBanner,hasStoredConsent:this.hasStoredConsent()})}catch(e){this.warn("consent banner initialization failed",e)}}))}showConsentBannerWhenReady(e=12){if(!(typeof document>"u")&&!document.getElementById("krypton-consent-banner")){if(document.body){this.showConsentBanner();return}e<=0||setTimeout(()=>this.showConsentBannerWhenReady(e-1),50)}}resolveInitialConsent(){let e=this.loadStoredConsent();return e||{...this.config.consentRequired?{analytics:!1,heatmaps:!1}:{analytics:!0,heatmaps:!!this.config.heatmap},...this.config.consentCategories}}consentStorageKey(){return`_krypton_consent_${this.config.apiKey}`}hasStoredConsent(){try{return typeof localStorage>"u"?!1:!!localStorage.getItem(this.consentStorageKey())}catch{return!1}}loadStoredConsent(){try{if(typeof localStorage>"u")return null;let e=localStorage.getItem(this.consentStorageKey());if(!e)return null;let n=JSON.parse(e);return{analytics:!!n.analytics,heatmaps:!!n.heatmaps}}catch{return null}}persistConsent(){try{if(typeof localStorage>"u")return;localStorage.setItem(this.consentStorageKey(),JSON.stringify(this.consent))}catch{}}promotePersistentIds(){this.distinctId=h(),this.sessionId=d()}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 e=`_krypton_config_${this.config.apiKey}`,n=null;if(!this.config.disableConfigCache)try{n=sessionStorage.getItem(e)}catch{n=null}if(n)try{let t=JSON.parse(n);if(t._ts&&Date.now()-t._ts<300*1e3){this.serverConfig=t,this.configFetched=!0,this.debug("config loaded from session cache",t);return}}catch{}try{let t=new AbortController,i=setTimeout(()=>t.abort(),5e3),o=await fetch(`${this.config.endpoint}/api/v1/config?api_key=${encodeURIComponent(this.config.apiKey)}`,{signal:t.signal});if(clearTimeout(i),o.ok){let c=await o.json();if(this.serverConfig=c,this.configFetched=!0,this.debug("config fetched from API",c),!this.config.disableConfigCache)try{sessionStorage.setItem(e,JSON.stringify({...c,_ts:Date.now()}))}catch{}}else this.warn(`Config fetch failed (${o.status})`,{endpoint:this.config.endpoint})}catch(t){this.warn("Config fetch failed",t)}}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 e=history.pushState;history.pushState=(...t)=>{try{e.apply(history,t),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(i){this.warn("pushState hook failed",i)}};let n=history.replaceState;history.replaceState=(...t)=>{try{n.apply(history,t),this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(i){this.warn("replaceState hook failed",i)}},window.addEventListener("popstate",()=>{try{this.config.autoPageview&&this.canTrackAnalytics()&&setTimeout(()=>this.trackPageview(),0)}catch(t){this.warn("popstate hook failed",t)}}),this.isHeatmapFeatureEnabled()&&this.setupHeatmap()}showConsentBanner(){if(typeof document>"u"||document.getElementById("krypton-consent-banner"))return;let e=document.createElement("div");e.id="krypton-consent-banner",e.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 n=o=>o?"checked":"";e.innerHTML=`
|
|
2
2
|
<div style="font-weight:600;margin-bottom:6px">Privacy preferences</div>
|
|
3
3
|
<div style="opacity:0.9;margin-bottom:10px">Choose what data you allow us to collect.</div>
|
|
4
4
|
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
5
|
-
<input type="checkbox" id="krypton-consent-analytics" ${
|
|
5
|
+
<input type="checkbox" id="krypton-consent-analytics" ${n(this.consent.analytics)} />
|
|
6
6
|
<span><strong>Analytics</strong> (pageviews and custom events)</span>
|
|
7
7
|
</label>
|
|
8
8
|
<label style="display:flex;gap:8px;align-items:flex-start;margin:6px 0">
|
|
9
|
-
<input type="checkbox" id="krypton-consent-heatmaps" ${
|
|
9
|
+
<input type="checkbox" id="krypton-consent-heatmaps" ${n(this.consent.heatmaps)} />
|
|
10
10
|
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
11
11
|
</label>
|
|
12
|
-
<
|
|
13
|
-
<input type="checkbox" id="krypton-consent-geo" ${r(this.consent.geo)} />
|
|
14
|
-
<span><strong>Geo location</strong> (browser geolocation if available)</span>
|
|
15
|
-
</label>
|
|
16
|
-
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
12
|
+
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
|
|
17
13
|
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
18
14
|
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
19
15
|
<button id="krypton-consent-none" style="border:1px solid #4b5563;background:transparent;color:#f9fafb;padding:8px 12px;border-radius:8px;cursor:pointer">Reject all</button>
|
|
20
16
|
</div>
|
|
21
|
-
`;let
|
|
17
|
+
`;let t=()=>{e.remove();try{document.body&&(document.body.style.cursor=""),document.documentElement&&(document.documentElement.style.cursor="")}catch{}},i=o=>!!document.getElementById(o)?.checked;e.querySelector("#krypton-consent-save")?.addEventListener("click",()=>{let o={analytics:i("krypton-consent-analytics"),heatmaps:i("krypton-consent-heatmaps")};t(),setTimeout(()=>this.setConsent(o),0)}),e.querySelector("#krypton-consent-all")?.addEventListener("click",()=>{t(),setTimeout(()=>this.setConsent({analytics:!0,heatmaps:!0}),0)}),e.querySelector("#krypton-consent-none")?.addEventListener("click",()=>{t(),setTimeout(()=>this.setConsent({analytics:!1,heatmaps:!1}),0)}),document.body.appendChild(e)}setConsent(e,n=!0){try{let t={...this.consent};this.consent={analytics:e.analytics??t.analytics,heatmaps:e.heatmaps??t.heatmaps},n&&this.persistConsent(),!t.analytics&&this.consent.analytics&&(this.promotePersistentIds(),this.config.autoPageview&&this.trackPageview()),t.analytics&&!this.consent.analytics&&(this.eventQueue=[]),!t.heatmaps&&this.isHeatmapFeatureEnabled()&&this.setupHeatmap(),t.heatmaps&&!this.consent.heatmaps&&(this.heatmapQueue=[])}catch(t){this.warn("setConsent failed",t)}}getConsent(){return{...this.consent}}grantConsent(){this.setConsent({analytics:!0,heatmaps:!0})}revokeConsent(){this.setConsent({analytics:!1,heatmaps:!1}),this.eventQueue=[],this.heatmapQueue=[]}identify(e){try{if(this.distinctId=e,this.canTrackAnalytics())try{typeof localStorage<"u"&&localStorage.setItem("_krypton_did",e)}catch{}}catch(n){this.warn("identify failed",n)}}trackPageview(e){try{if(!this.canTrackAnalytics())return;this.track("$pageview",{...e})}catch(n){this.warn("trackPageview failed",n)}}track(e,n){try{if(!this.canTrackAnalytics())return;let t=u(),i={...n||{}},o={project_id:this.config.apiKey,distinct_id:this.distinctId,event_name:e,timestamp:new Date().toISOString(),properties:i,page_url:typeof window<"u"?window.location.href:"",page_title:typeof document<"u"?document.title:"",referrer:typeof document<"u"?document.referrer:"",utm_source:t.utm_source||"",utm_medium:t.utm_medium||"",utm_campaign:t.utm_campaign||"",utm_term:t.utm_term||"",utm_content:t.utm_content||"",device_type:p(),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(o),this.eventQueue.length>=this.config.batchSize&&this.flush()}catch(t){this.warn("track failed",t)}}async flush(){try{await Promise.all([this.flushEvents(),this.flushHeatmapEvents()])}catch(e){this.warn("flush failed",e)}}shutdown(){this.flushTimer&&(clearInterval(this.flushTimer),this.flushTimer=null),this.flush()}async flushEvents(){if(this.eventQueue.length===0)return;let e=this.eventQueue.splice(0,this.eventQueue.length),n={api_key:this.config.apiKey,events:e};await this.safePost(`${this.config.endpoint}/api/v1/ingest/batch`,n)||this.eventQueue.length<this.config.batchSize*5&&this.eventQueue.unshift(...e)}async flushHeatmapEvents(){if(this.heatmapQueue.length===0)return;let e=this.heatmapQueue.splice(0,this.heatmapQueue.length),n={api_key:this.config.apiKey,events:e};await this.safePost(`${this.config.endpoint}/api/v1/heatmap`,n)||this.heatmapQueue.length<this.config.batchSize*5&&this.heatmapQueue.unshift(...e)}setupHeatmap(){if(typeof window>"u"||this.heatmapSetup)return;this.heatmapSetup=!0,document.addEventListener("click",t=>{if(this.isHeatmapFeatureEnabled())try{let i=t.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:t.clientX+window.scrollX,y:t.clientY+window.scrollY,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight,selector:f(i)})}catch(i){this.warn("heatmap click capture failed",i)}});let e=0,n=null;window.addEventListener("scroll",()=>{if(this.isHeatmapFeatureEnabled())try{let t=window.scrollY||document.documentElement.scrollTop,i=document.documentElement.scrollHeight-window.innerHeight,o=i>0?t/i*100:0;o>e&&(e=o),n&&clearTimeout(n),n=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:e,viewport_width:window.innerWidth,viewport_height:window.innerHeight,page_width:document.documentElement.scrollWidth,page_height:document.documentElement.scrollHeight})},500)}catch(t){this.warn("heatmap scroll capture failed",t)}})}async safePost(e,n,t=!0){try{let i=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n),...t?{keepalive:!0}:{}});return i.ok?!0:(this.warn(`API request failed (${i.status})`,{url:e}),!1)}catch(i){return this.warn("API request failed",{url:e,err:i}),!1}}warn(e,n){try{console.warn(`${this.logPrefix} ${e}`,n??"")}catch{}}debug(e,n){if(this.config.debug)try{console.log(`${this.logPrefix} ${e}`,n??"")}catch{}}getBrowser(){if(typeof navigator>"u")return"unknown";let e=navigator.userAgent;return e.includes("Firefox")?"Firefox":e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Safari")?"Safari":"Other"}};function g(s){return new r(s)}var m={Krypton:r,init:g};typeof window<"u"&&(window.KryptonAnalytics=m);var C=m;return k(S);})();
|
package/dist/index.d.mts
CHANGED
|
@@ -22,11 +22,10 @@ interface KryptonConfig {
|
|
|
22
22
|
/** Disable SDK config cache and fetch project config on each init (default: false) */
|
|
23
23
|
disableConfigCache?: boolean;
|
|
24
24
|
}
|
|
25
|
-
type ConsentCategory = "analytics" | "heatmaps"
|
|
25
|
+
type ConsentCategory = "analytics" | "heatmaps";
|
|
26
26
|
interface ConsentPreferences {
|
|
27
27
|
analytics: boolean;
|
|
28
28
|
heatmaps: boolean;
|
|
29
|
-
geo: boolean;
|
|
30
29
|
}
|
|
31
30
|
interface EventPayload {
|
|
32
31
|
project_id: string;
|
|
@@ -76,10 +75,7 @@ declare class Krypton {
|
|
|
76
75
|
private heatmapQueue;
|
|
77
76
|
private flushTimer;
|
|
78
77
|
private initialized;
|
|
79
|
-
private lastSnapshotUrl;
|
|
80
78
|
private heatmapSetup;
|
|
81
|
-
private geoRequested;
|
|
82
|
-
private geoContext;
|
|
83
79
|
private consent;
|
|
84
80
|
private serverConfig;
|
|
85
81
|
private configFetched;
|
|
@@ -97,7 +93,7 @@ declare class Krypton {
|
|
|
97
93
|
private isHeatmapFeatureEnabled;
|
|
98
94
|
private fetchConfig;
|
|
99
95
|
private setupTracking;
|
|
100
|
-
/** Built-in consent popup with category toggles (analytics, heatmaps
|
|
96
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps). */
|
|
101
97
|
showConsentBanner(): void;
|
|
102
98
|
/** Set one or more consent categories and apply changes immediately. */
|
|
103
99
|
setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
|
|
@@ -114,10 +110,8 @@ declare class Krypton {
|
|
|
114
110
|
track(eventName: string, properties?: Record<string, unknown>): void;
|
|
115
111
|
flush(): Promise<void>;
|
|
116
112
|
shutdown(): void;
|
|
117
|
-
private captureGeoOnce;
|
|
118
113
|
private flushEvents;
|
|
119
114
|
private flushHeatmapEvents;
|
|
120
|
-
private captureSnapshot;
|
|
121
115
|
private setupHeatmap;
|
|
122
116
|
private safePost;
|
|
123
117
|
private warn;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,11 +22,10 @@ interface KryptonConfig {
|
|
|
22
22
|
/** Disable SDK config cache and fetch project config on each init (default: false) */
|
|
23
23
|
disableConfigCache?: boolean;
|
|
24
24
|
}
|
|
25
|
-
type ConsentCategory = "analytics" | "heatmaps"
|
|
25
|
+
type ConsentCategory = "analytics" | "heatmaps";
|
|
26
26
|
interface ConsentPreferences {
|
|
27
27
|
analytics: boolean;
|
|
28
28
|
heatmaps: boolean;
|
|
29
|
-
geo: boolean;
|
|
30
29
|
}
|
|
31
30
|
interface EventPayload {
|
|
32
31
|
project_id: string;
|
|
@@ -76,10 +75,7 @@ declare class Krypton {
|
|
|
76
75
|
private heatmapQueue;
|
|
77
76
|
private flushTimer;
|
|
78
77
|
private initialized;
|
|
79
|
-
private lastSnapshotUrl;
|
|
80
78
|
private heatmapSetup;
|
|
81
|
-
private geoRequested;
|
|
82
|
-
private geoContext;
|
|
83
79
|
private consent;
|
|
84
80
|
private serverConfig;
|
|
85
81
|
private configFetched;
|
|
@@ -97,7 +93,7 @@ declare class Krypton {
|
|
|
97
93
|
private isHeatmapFeatureEnabled;
|
|
98
94
|
private fetchConfig;
|
|
99
95
|
private setupTracking;
|
|
100
|
-
/** Built-in consent popup with category toggles (analytics, heatmaps
|
|
96
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps). */
|
|
101
97
|
showConsentBanner(): void;
|
|
102
98
|
/** Set one or more consent categories and apply changes immediately. */
|
|
103
99
|
setConsent(next: Partial<ConsentPreferences>, persist?: boolean): void;
|
|
@@ -114,10 +110,8 @@ declare class Krypton {
|
|
|
114
110
|
track(eventName: string, properties?: Record<string, unknown>): void;
|
|
115
111
|
flush(): Promise<void>;
|
|
116
112
|
shutdown(): void;
|
|
117
|
-
private captureGeoOnce;
|
|
118
113
|
private flushEvents;
|
|
119
114
|
private flushHeatmapEvents;
|
|
120
|
-
private captureSnapshot;
|
|
121
115
|
private setupHeatmap;
|
|
122
116
|
private safePost;
|
|
123
117
|
private warn;
|
package/dist/index.js
CHANGED
|
@@ -24,7 +24,6 @@ __export(index_exports, {
|
|
|
24
24
|
createKrypton: () => createKrypton
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
-
var import_rrweb_snapshot = require("rrweb-snapshot");
|
|
28
27
|
|
|
29
28
|
// src/utils.ts
|
|
30
29
|
function generateId() {
|
|
@@ -111,10 +110,7 @@ var Krypton = class {
|
|
|
111
110
|
this.heatmapQueue = [];
|
|
112
111
|
this.flushTimer = null;
|
|
113
112
|
this.initialized = false;
|
|
114
|
-
this.lastSnapshotUrl = null;
|
|
115
113
|
this.heatmapSetup = false;
|
|
116
|
-
this.geoRequested = false;
|
|
117
|
-
this.geoContext = null;
|
|
118
114
|
this.serverConfig = null;
|
|
119
115
|
this.configFetched = false;
|
|
120
116
|
this.logPrefix = "[Krypton SDK]";
|
|
@@ -179,10 +175,9 @@ var Krypton = class {
|
|
|
179
175
|
resolveInitialConsent() {
|
|
180
176
|
const stored = this.loadStoredConsent();
|
|
181
177
|
if (stored) return stored;
|
|
182
|
-
const base = this.config.consentRequired ? { analytics: false, heatmaps: false
|
|
178
|
+
const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
|
|
183
179
|
analytics: true,
|
|
184
|
-
heatmaps: !!this.config.heatmap
|
|
185
|
-
geo: false
|
|
180
|
+
heatmaps: !!this.config.heatmap
|
|
186
181
|
};
|
|
187
182
|
return {
|
|
188
183
|
...base,
|
|
@@ -208,8 +203,7 @@ var Krypton = class {
|
|
|
208
203
|
const parsed = JSON.parse(raw);
|
|
209
204
|
return {
|
|
210
205
|
analytics: !!parsed.analytics,
|
|
211
|
-
heatmaps: !!parsed.heatmaps
|
|
212
|
-
geo: !!parsed.geo
|
|
206
|
+
heatmaps: !!parsed.heatmaps
|
|
213
207
|
};
|
|
214
208
|
} catch {
|
|
215
209
|
return null;
|
|
@@ -301,9 +295,6 @@ var Krypton = class {
|
|
|
301
295
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
302
296
|
setTimeout(() => this.trackPageview(), 0);
|
|
303
297
|
}
|
|
304
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
305
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
306
|
-
}
|
|
307
298
|
} catch (err) {
|
|
308
299
|
this.warn("pushState hook failed", err);
|
|
309
300
|
}
|
|
@@ -315,9 +306,6 @@ var Krypton = class {
|
|
|
315
306
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
316
307
|
setTimeout(() => this.trackPageview(), 0);
|
|
317
308
|
}
|
|
318
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
319
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
320
|
-
}
|
|
321
309
|
} catch (err) {
|
|
322
310
|
this.warn("replaceState hook failed", err);
|
|
323
311
|
}
|
|
@@ -327,9 +315,6 @@ var Krypton = class {
|
|
|
327
315
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
328
316
|
setTimeout(() => this.trackPageview(), 0);
|
|
329
317
|
}
|
|
330
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
331
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
332
|
-
}
|
|
333
318
|
} catch (err) {
|
|
334
319
|
this.warn("popstate hook failed", err);
|
|
335
320
|
}
|
|
@@ -337,11 +322,8 @@ var Krypton = class {
|
|
|
337
322
|
if (this.isHeatmapFeatureEnabled()) {
|
|
338
323
|
this.setupHeatmap();
|
|
339
324
|
}
|
|
340
|
-
if (this.consent.geo) {
|
|
341
|
-
this.captureGeoOnce();
|
|
342
|
-
}
|
|
343
325
|
}
|
|
344
|
-
/** Built-in consent popup with category toggles (analytics, heatmaps
|
|
326
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps). */
|
|
345
327
|
showConsentBanner() {
|
|
346
328
|
if (typeof document === "undefined") return;
|
|
347
329
|
if (document.getElementById("krypton-consent-banner")) return;
|
|
@@ -376,11 +358,7 @@ var Krypton = class {
|
|
|
376
358
|
<input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
|
|
377
359
|
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
378
360
|
</label>
|
|
379
|
-
<
|
|
380
|
-
<input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
|
|
381
|
-
<span><strong>Geo location</strong> (browser geolocation if available)</span>
|
|
382
|
-
</label>
|
|
383
|
-
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
361
|
+
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
|
|
384
362
|
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
385
363
|
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
386
364
|
<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>
|
|
@@ -401,19 +379,18 @@ var Krypton = class {
|
|
|
401
379
|
banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
|
|
402
380
|
const next = {
|
|
403
381
|
analytics: readValue("krypton-consent-analytics"),
|
|
404
|
-
heatmaps: readValue("krypton-consent-heatmaps")
|
|
405
|
-
geo: readValue("krypton-consent-geo")
|
|
382
|
+
heatmaps: readValue("krypton-consent-heatmaps")
|
|
406
383
|
};
|
|
407
384
|
remove();
|
|
408
385
|
setTimeout(() => this.setConsent(next), 0);
|
|
409
386
|
});
|
|
410
387
|
banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
|
|
411
388
|
remove();
|
|
412
|
-
setTimeout(() => this.setConsent({ analytics: true, heatmaps: true
|
|
389
|
+
setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
|
|
413
390
|
});
|
|
414
391
|
banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
|
|
415
392
|
remove();
|
|
416
|
-
setTimeout(() => this.setConsent({ analytics: false, heatmaps: false
|
|
393
|
+
setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
|
|
417
394
|
});
|
|
418
395
|
document.body.appendChild(banner);
|
|
419
396
|
}
|
|
@@ -423,8 +400,7 @@ var Krypton = class {
|
|
|
423
400
|
const prev = { ...this.consent };
|
|
424
401
|
this.consent = {
|
|
425
402
|
analytics: next.analytics ?? prev.analytics,
|
|
426
|
-
heatmaps: next.heatmaps ?? prev.heatmaps
|
|
427
|
-
geo: next.geo ?? prev.geo
|
|
403
|
+
heatmaps: next.heatmaps ?? prev.heatmaps
|
|
428
404
|
};
|
|
429
405
|
if (persist) {
|
|
430
406
|
this.persistConsent();
|
|
@@ -440,14 +416,10 @@ var Krypton = class {
|
|
|
440
416
|
}
|
|
441
417
|
if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
|
|
442
418
|
this.setupHeatmap();
|
|
443
|
-
this.captureSnapshot();
|
|
444
419
|
}
|
|
445
420
|
if (prev.heatmaps && !this.consent.heatmaps) {
|
|
446
421
|
this.heatmapQueue = [];
|
|
447
422
|
}
|
|
448
|
-
if (!prev.geo && this.consent.geo) {
|
|
449
|
-
this.captureGeoOnce();
|
|
450
|
-
}
|
|
451
423
|
} catch (err) {
|
|
452
424
|
this.warn("setConsent failed", err);
|
|
453
425
|
}
|
|
@@ -457,11 +429,11 @@ var Krypton = class {
|
|
|
457
429
|
}
|
|
458
430
|
/** Backward-compatible: grant all categories. */
|
|
459
431
|
grantConsent() {
|
|
460
|
-
this.setConsent({ analytics: true, heatmaps: true
|
|
432
|
+
this.setConsent({ analytics: true, heatmaps: true });
|
|
461
433
|
}
|
|
462
434
|
/** Backward-compatible: revoke all categories and clear queues. */
|
|
463
435
|
revokeConsent() {
|
|
464
|
-
this.setConsent({ analytics: false, heatmaps: false
|
|
436
|
+
this.setConsent({ analytics: false, heatmaps: false });
|
|
465
437
|
this.eventQueue = [];
|
|
466
438
|
this.heatmapQueue = [];
|
|
467
439
|
}
|
|
@@ -498,9 +470,6 @@ var Krypton = class {
|
|
|
498
470
|
if (!this.canTrackAnalytics()) return;
|
|
499
471
|
const utm = getUTMParams();
|
|
500
472
|
const mergedProperties = { ...properties || {} };
|
|
501
|
-
if (this.consent.geo && this.geoContext) {
|
|
502
|
-
mergedProperties.geo = this.geoContext;
|
|
503
|
-
}
|
|
504
473
|
const event = {
|
|
505
474
|
project_id: this.config.apiKey,
|
|
506
475
|
distinct_id: this.distinctId,
|
|
@@ -543,30 +512,6 @@ var Krypton = class {
|
|
|
543
512
|
}
|
|
544
513
|
void this.flush();
|
|
545
514
|
}
|
|
546
|
-
captureGeoOnce() {
|
|
547
|
-
if (this.geoRequested) return;
|
|
548
|
-
if (!this.consent.geo) return;
|
|
549
|
-
if (typeof navigator === "undefined" || !navigator.geolocation) return;
|
|
550
|
-
this.geoRequested = true;
|
|
551
|
-
navigator.geolocation.getCurrentPosition(
|
|
552
|
-
(pos) => {
|
|
553
|
-
const round = (value, precision = 3) => Number(value.toFixed(precision));
|
|
554
|
-
this.geoContext = {
|
|
555
|
-
lat: round(pos.coords.latitude),
|
|
556
|
-
lon: round(pos.coords.longitude),
|
|
557
|
-
accuracy_m: Math.round(pos.coords.accuracy),
|
|
558
|
-
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
559
|
-
};
|
|
560
|
-
},
|
|
561
|
-
() => {
|
|
562
|
-
},
|
|
563
|
-
{
|
|
564
|
-
enableHighAccuracy: false,
|
|
565
|
-
maximumAge: 10 * 60 * 1e3,
|
|
566
|
-
timeout: 5e3
|
|
567
|
-
}
|
|
568
|
-
);
|
|
569
|
-
}
|
|
570
515
|
async flushEvents() {
|
|
571
516
|
if (this.eventQueue.length === 0) return;
|
|
572
517
|
const events = this.eventQueue.splice(0, this.eventQueue.length);
|
|
@@ -595,41 +540,10 @@ var Krypton = class {
|
|
|
595
540
|
}
|
|
596
541
|
}
|
|
597
542
|
}
|
|
598
|
-
captureSnapshot() {
|
|
599
|
-
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
600
|
-
if (!this.isHeatmapFeatureEnabled()) return;
|
|
601
|
-
const currentUrl = window.location.href;
|
|
602
|
-
if (this.lastSnapshotUrl === currentUrl) return;
|
|
603
|
-
this.lastSnapshotUrl = currentUrl;
|
|
604
|
-
setTimeout(() => {
|
|
605
|
-
try {
|
|
606
|
-
const node = (0, import_rrweb_snapshot.snapshot)(document, {
|
|
607
|
-
maskAllInputs: true,
|
|
608
|
-
blockSelector: "[data-krypton-block]",
|
|
609
|
-
inlineStylesheet: true
|
|
610
|
-
});
|
|
611
|
-
if (!node) return;
|
|
612
|
-
const snapshotJson = JSON.stringify(node);
|
|
613
|
-
const payload = {
|
|
614
|
-
api_key: this.config.apiKey,
|
|
615
|
-
page_url: currentUrl,
|
|
616
|
-
snapshot: snapshotJson,
|
|
617
|
-
viewport_width: window.innerWidth,
|
|
618
|
-
viewport_height: window.innerHeight,
|
|
619
|
-
page_width: document.documentElement.scrollWidth,
|
|
620
|
-
page_height: document.documentElement.scrollHeight,
|
|
621
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
622
|
-
};
|
|
623
|
-
void this.safePost(`${this.config.endpoint}/api/v1/snapshot`, payload);
|
|
624
|
-
} catch {
|
|
625
|
-
}
|
|
626
|
-
}, 1e3);
|
|
627
|
-
}
|
|
628
543
|
setupHeatmap() {
|
|
629
544
|
if (typeof window === "undefined") return;
|
|
630
545
|
if (this.heatmapSetup) return;
|
|
631
546
|
this.heatmapSetup = true;
|
|
632
|
-
this.captureSnapshot();
|
|
633
547
|
document.addEventListener("click", (e) => {
|
|
634
548
|
if (!this.isHeatmapFeatureEnabled()) return;
|
|
635
549
|
try {
|
|
@@ -685,13 +599,13 @@ var Krypton = class {
|
|
|
685
599
|
}
|
|
686
600
|
});
|
|
687
601
|
}
|
|
688
|
-
async safePost(url, payload) {
|
|
602
|
+
async safePost(url, payload, keepalive = true) {
|
|
689
603
|
try {
|
|
690
604
|
const res = await fetch(url, {
|
|
691
605
|
method: "POST",
|
|
692
606
|
headers: { "Content-Type": "application/json" },
|
|
693
607
|
body: JSON.stringify(payload),
|
|
694
|
-
keepalive: true
|
|
608
|
+
...keepalive ? { keepalive: true } : {}
|
|
695
609
|
});
|
|
696
610
|
if (!res.ok) {
|
|
697
611
|
this.warn(`API request failed (${res.status})`, { url });
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { snapshot as rrwebSnapshot } from "rrweb-snapshot";
|
|
3
|
-
|
|
4
1
|
// src/utils.ts
|
|
5
2
|
function generateId() {
|
|
6
3
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
@@ -86,10 +83,7 @@ var Krypton = class {
|
|
|
86
83
|
this.heatmapQueue = [];
|
|
87
84
|
this.flushTimer = null;
|
|
88
85
|
this.initialized = false;
|
|
89
|
-
this.lastSnapshotUrl = null;
|
|
90
86
|
this.heatmapSetup = false;
|
|
91
|
-
this.geoRequested = false;
|
|
92
|
-
this.geoContext = null;
|
|
93
87
|
this.serverConfig = null;
|
|
94
88
|
this.configFetched = false;
|
|
95
89
|
this.logPrefix = "[Krypton SDK]";
|
|
@@ -154,10 +148,9 @@ var Krypton = class {
|
|
|
154
148
|
resolveInitialConsent() {
|
|
155
149
|
const stored = this.loadStoredConsent();
|
|
156
150
|
if (stored) return stored;
|
|
157
|
-
const base = this.config.consentRequired ? { analytics: false, heatmaps: false
|
|
151
|
+
const base = this.config.consentRequired ? { analytics: false, heatmaps: false } : {
|
|
158
152
|
analytics: true,
|
|
159
|
-
heatmaps: !!this.config.heatmap
|
|
160
|
-
geo: false
|
|
153
|
+
heatmaps: !!this.config.heatmap
|
|
161
154
|
};
|
|
162
155
|
return {
|
|
163
156
|
...base,
|
|
@@ -183,8 +176,7 @@ var Krypton = class {
|
|
|
183
176
|
const parsed = JSON.parse(raw);
|
|
184
177
|
return {
|
|
185
178
|
analytics: !!parsed.analytics,
|
|
186
|
-
heatmaps: !!parsed.heatmaps
|
|
187
|
-
geo: !!parsed.geo
|
|
179
|
+
heatmaps: !!parsed.heatmaps
|
|
188
180
|
};
|
|
189
181
|
} catch {
|
|
190
182
|
return null;
|
|
@@ -276,9 +268,6 @@ var Krypton = class {
|
|
|
276
268
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
277
269
|
setTimeout(() => this.trackPageview(), 0);
|
|
278
270
|
}
|
|
279
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
280
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
281
|
-
}
|
|
282
271
|
} catch (err) {
|
|
283
272
|
this.warn("pushState hook failed", err);
|
|
284
273
|
}
|
|
@@ -290,9 +279,6 @@ var Krypton = class {
|
|
|
290
279
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
291
280
|
setTimeout(() => this.trackPageview(), 0);
|
|
292
281
|
}
|
|
293
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
294
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
295
|
-
}
|
|
296
282
|
} catch (err) {
|
|
297
283
|
this.warn("replaceState hook failed", err);
|
|
298
284
|
}
|
|
@@ -302,9 +288,6 @@ var Krypton = class {
|
|
|
302
288
|
if (this.config.autoPageview && this.canTrackAnalytics()) {
|
|
303
289
|
setTimeout(() => this.trackPageview(), 0);
|
|
304
290
|
}
|
|
305
|
-
if (this.isHeatmapFeatureEnabled()) {
|
|
306
|
-
setTimeout(() => this.captureSnapshot(), 0);
|
|
307
|
-
}
|
|
308
291
|
} catch (err) {
|
|
309
292
|
this.warn("popstate hook failed", err);
|
|
310
293
|
}
|
|
@@ -312,11 +295,8 @@ var Krypton = class {
|
|
|
312
295
|
if (this.isHeatmapFeatureEnabled()) {
|
|
313
296
|
this.setupHeatmap();
|
|
314
297
|
}
|
|
315
|
-
if (this.consent.geo) {
|
|
316
|
-
this.captureGeoOnce();
|
|
317
|
-
}
|
|
318
298
|
}
|
|
319
|
-
/** Built-in consent popup with category toggles (analytics, heatmaps
|
|
299
|
+
/** Built-in consent popup with category toggles (analytics, heatmaps). */
|
|
320
300
|
showConsentBanner() {
|
|
321
301
|
if (typeof document === "undefined") return;
|
|
322
302
|
if (document.getElementById("krypton-consent-banner")) return;
|
|
@@ -351,11 +331,7 @@ var Krypton = class {
|
|
|
351
331
|
<input type="checkbox" id="krypton-consent-heatmaps" ${checked(this.consent.heatmaps)} />
|
|
352
332
|
<span><strong>Heatmaps</strong> (click and scroll interaction maps)</span>
|
|
353
333
|
</label>
|
|
354
|
-
<
|
|
355
|
-
<input type="checkbox" id="krypton-consent-geo" ${checked(this.consent.geo)} />
|
|
356
|
-
<span><strong>Geo location</strong> (browser geolocation if available)</span>
|
|
357
|
-
</label>
|
|
358
|
-
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
|
334
|
+
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
|
|
359
335
|
<button id="krypton-consent-save" style="border:0;background:#2563eb;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept selected</button>
|
|
360
336
|
<button id="krypton-consent-all" style="border:0;background:#16a34a;color:#fff;padding:8px 12px;border-radius:8px;cursor:pointer">Accept all</button>
|
|
361
337
|
<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>
|
|
@@ -376,19 +352,18 @@ var Krypton = class {
|
|
|
376
352
|
banner.querySelector("#krypton-consent-save")?.addEventListener("click", () => {
|
|
377
353
|
const next = {
|
|
378
354
|
analytics: readValue("krypton-consent-analytics"),
|
|
379
|
-
heatmaps: readValue("krypton-consent-heatmaps")
|
|
380
|
-
geo: readValue("krypton-consent-geo")
|
|
355
|
+
heatmaps: readValue("krypton-consent-heatmaps")
|
|
381
356
|
};
|
|
382
357
|
remove();
|
|
383
358
|
setTimeout(() => this.setConsent(next), 0);
|
|
384
359
|
});
|
|
385
360
|
banner.querySelector("#krypton-consent-all")?.addEventListener("click", () => {
|
|
386
361
|
remove();
|
|
387
|
-
setTimeout(() => this.setConsent({ analytics: true, heatmaps: true
|
|
362
|
+
setTimeout(() => this.setConsent({ analytics: true, heatmaps: true }), 0);
|
|
388
363
|
});
|
|
389
364
|
banner.querySelector("#krypton-consent-none")?.addEventListener("click", () => {
|
|
390
365
|
remove();
|
|
391
|
-
setTimeout(() => this.setConsent({ analytics: false, heatmaps: false
|
|
366
|
+
setTimeout(() => this.setConsent({ analytics: false, heatmaps: false }), 0);
|
|
392
367
|
});
|
|
393
368
|
document.body.appendChild(banner);
|
|
394
369
|
}
|
|
@@ -398,8 +373,7 @@ var Krypton = class {
|
|
|
398
373
|
const prev = { ...this.consent };
|
|
399
374
|
this.consent = {
|
|
400
375
|
analytics: next.analytics ?? prev.analytics,
|
|
401
|
-
heatmaps: next.heatmaps ?? prev.heatmaps
|
|
402
|
-
geo: next.geo ?? prev.geo
|
|
376
|
+
heatmaps: next.heatmaps ?? prev.heatmaps
|
|
403
377
|
};
|
|
404
378
|
if (persist) {
|
|
405
379
|
this.persistConsent();
|
|
@@ -415,14 +389,10 @@ var Krypton = class {
|
|
|
415
389
|
}
|
|
416
390
|
if (!prev.heatmaps && this.isHeatmapFeatureEnabled()) {
|
|
417
391
|
this.setupHeatmap();
|
|
418
|
-
this.captureSnapshot();
|
|
419
392
|
}
|
|
420
393
|
if (prev.heatmaps && !this.consent.heatmaps) {
|
|
421
394
|
this.heatmapQueue = [];
|
|
422
395
|
}
|
|
423
|
-
if (!prev.geo && this.consent.geo) {
|
|
424
|
-
this.captureGeoOnce();
|
|
425
|
-
}
|
|
426
396
|
} catch (err) {
|
|
427
397
|
this.warn("setConsent failed", err);
|
|
428
398
|
}
|
|
@@ -432,11 +402,11 @@ var Krypton = class {
|
|
|
432
402
|
}
|
|
433
403
|
/** Backward-compatible: grant all categories. */
|
|
434
404
|
grantConsent() {
|
|
435
|
-
this.setConsent({ analytics: true, heatmaps: true
|
|
405
|
+
this.setConsent({ analytics: true, heatmaps: true });
|
|
436
406
|
}
|
|
437
407
|
/** Backward-compatible: revoke all categories and clear queues. */
|
|
438
408
|
revokeConsent() {
|
|
439
|
-
this.setConsent({ analytics: false, heatmaps: false
|
|
409
|
+
this.setConsent({ analytics: false, heatmaps: false });
|
|
440
410
|
this.eventQueue = [];
|
|
441
411
|
this.heatmapQueue = [];
|
|
442
412
|
}
|
|
@@ -473,9 +443,6 @@ var Krypton = class {
|
|
|
473
443
|
if (!this.canTrackAnalytics()) return;
|
|
474
444
|
const utm = getUTMParams();
|
|
475
445
|
const mergedProperties = { ...properties || {} };
|
|
476
|
-
if (this.consent.geo && this.geoContext) {
|
|
477
|
-
mergedProperties.geo = this.geoContext;
|
|
478
|
-
}
|
|
479
446
|
const event = {
|
|
480
447
|
project_id: this.config.apiKey,
|
|
481
448
|
distinct_id: this.distinctId,
|
|
@@ -518,30 +485,6 @@ var Krypton = class {
|
|
|
518
485
|
}
|
|
519
486
|
void this.flush();
|
|
520
487
|
}
|
|
521
|
-
captureGeoOnce() {
|
|
522
|
-
if (this.geoRequested) return;
|
|
523
|
-
if (!this.consent.geo) return;
|
|
524
|
-
if (typeof navigator === "undefined" || !navigator.geolocation) return;
|
|
525
|
-
this.geoRequested = true;
|
|
526
|
-
navigator.geolocation.getCurrentPosition(
|
|
527
|
-
(pos) => {
|
|
528
|
-
const round = (value, precision = 3) => Number(value.toFixed(precision));
|
|
529
|
-
this.geoContext = {
|
|
530
|
-
lat: round(pos.coords.latitude),
|
|
531
|
-
lon: round(pos.coords.longitude),
|
|
532
|
-
accuracy_m: Math.round(pos.coords.accuracy),
|
|
533
|
-
captured_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
534
|
-
};
|
|
535
|
-
},
|
|
536
|
-
() => {
|
|
537
|
-
},
|
|
538
|
-
{
|
|
539
|
-
enableHighAccuracy: false,
|
|
540
|
-
maximumAge: 10 * 60 * 1e3,
|
|
541
|
-
timeout: 5e3
|
|
542
|
-
}
|
|
543
|
-
);
|
|
544
|
-
}
|
|
545
488
|
async flushEvents() {
|
|
546
489
|
if (this.eventQueue.length === 0) return;
|
|
547
490
|
const events = this.eventQueue.splice(0, this.eventQueue.length);
|
|
@@ -570,41 +513,10 @@ var Krypton = class {
|
|
|
570
513
|
}
|
|
571
514
|
}
|
|
572
515
|
}
|
|
573
|
-
captureSnapshot() {
|
|
574
|
-
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
575
|
-
if (!this.isHeatmapFeatureEnabled()) return;
|
|
576
|
-
const currentUrl = window.location.href;
|
|
577
|
-
if (this.lastSnapshotUrl === currentUrl) return;
|
|
578
|
-
this.lastSnapshotUrl = currentUrl;
|
|
579
|
-
setTimeout(() => {
|
|
580
|
-
try {
|
|
581
|
-
const node = rrwebSnapshot(document, {
|
|
582
|
-
maskAllInputs: true,
|
|
583
|
-
blockSelector: "[data-krypton-block]",
|
|
584
|
-
inlineStylesheet: true
|
|
585
|
-
});
|
|
586
|
-
if (!node) return;
|
|
587
|
-
const snapshotJson = JSON.stringify(node);
|
|
588
|
-
const payload = {
|
|
589
|
-
api_key: this.config.apiKey,
|
|
590
|
-
page_url: currentUrl,
|
|
591
|
-
snapshot: snapshotJson,
|
|
592
|
-
viewport_width: window.innerWidth,
|
|
593
|
-
viewport_height: window.innerHeight,
|
|
594
|
-
page_width: document.documentElement.scrollWidth,
|
|
595
|
-
page_height: document.documentElement.scrollHeight,
|
|
596
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
597
|
-
};
|
|
598
|
-
void this.safePost(`${this.config.endpoint}/api/v1/snapshot`, payload);
|
|
599
|
-
} catch {
|
|
600
|
-
}
|
|
601
|
-
}, 1e3);
|
|
602
|
-
}
|
|
603
516
|
setupHeatmap() {
|
|
604
517
|
if (typeof window === "undefined") return;
|
|
605
518
|
if (this.heatmapSetup) return;
|
|
606
519
|
this.heatmapSetup = true;
|
|
607
|
-
this.captureSnapshot();
|
|
608
520
|
document.addEventListener("click", (e) => {
|
|
609
521
|
if (!this.isHeatmapFeatureEnabled()) return;
|
|
610
522
|
try {
|
|
@@ -660,13 +572,13 @@ var Krypton = class {
|
|
|
660
572
|
}
|
|
661
573
|
});
|
|
662
574
|
}
|
|
663
|
-
async safePost(url, payload) {
|
|
575
|
+
async safePost(url, payload, keepalive = true) {
|
|
664
576
|
try {
|
|
665
577
|
const res = await fetch(url, {
|
|
666
578
|
method: "POST",
|
|
667
579
|
headers: { "Content-Type": "application/json" },
|
|
668
580
|
body: JSON.stringify(payload),
|
|
669
|
-
keepalive: true
|
|
581
|
+
...keepalive ? { keepalive: true } : {}
|
|
670
582
|
});
|
|
671
583
|
if (!res.ok) {
|
|
672
584
|
this.warn(`API request failed (${res.status})`, { url });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kryptonhq/analytics",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Krypton Analytics JavaScript SDK — privacy-first analytics tracking",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -27,8 +27,5 @@
|
|
|
27
27
|
"tsup": "^8.0.0",
|
|
28
28
|
"typescript": "^5.4.0"
|
|
29
29
|
},
|
|
30
|
-
"license": "MIT"
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"rrweb-snapshot": "^2.0.0-alpha.4"
|
|
33
|
-
}
|
|
30
|
+
"license": "MIT"
|
|
34
31
|
}
|