@tekibo/feedpulse-sdk 2.1.1 → 2.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/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class n{constructor(e){this.queue=[],this.flushInterval=null,this.observer=null,this.intersectionObserver=null,this.seenInView=new Set,this.config={endpoint:"https://feed-pulse.vercel.app/api/ingest",batchInterval:5e3,...e},this.visitorId=this.getOrCreateVisitorId(),this.sessionId=this.generateSessionId()}init(){this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM()}attachGlobalListeners(){document.addEventListener("click",i=>{const s=i.target.closest("[data-fp-id]");s&&this.track("click",s.getAttribute("data-fp-id"),{x:i.clientX,y:i.clientY})},{passive:!0});let e=0,t=null;document.addEventListener("mouseover",i=>{const s=i.target.closest("[data-fp-id]");s&&(e=Date.now(),t=s.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",i=>{if(!i.target.closest("[data-fp-id]")||!t)return;const r=Date.now()-e;r>500&&this.track("hover",t,{hoverDuration:r}),t=null},{passive:!0})}observeDOM(){this.intersectionObserver=new IntersectionObserver(t=>{for(const i of t){const s=i.target.dataset.fpId;!s||!i.isIntersecting||this.seenInView.has(s)||(this.seenInView.add(s),this.track("scroll_into_view",s,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))}},{threshold:.5});const e=()=>{document.querySelectorAll("[data-fp-id]").forEach(t=>{this.intersectionObserver?.observe(t)})};e(),this.observer=new MutationObserver(()=>e()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,t,i){this.queue.push({projectApiKey:this.config.apiKey,elementId:t,eventType:e,sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:i,timestamp:new Date().toISOString()})}trackFeedback(e,t,i){!t&&!i||this.sendImmediate([{projectApiKey:this.config.apiKey,elementId:e??"__page__",eventType:"feedback",sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:t,message:i},timestamp:new Date().toISOString()}])}async flush(){if(this.queue.length===0)return;const e=[...this.queue];this.queue=[],await this.sendImmediate(e)}async sendImmediate(e){try{await fetch(this.config.endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0})}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),window.addEventListener("beforeunload",()=>this.flush()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.flush()})}getOrCreateVisitorId(){const e="__fp_vid";let t=localStorage.getItem(e);return t||(t=crypto.randomUUID(),localStorage.setItem(e,t)),t}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).slice(2)}`}getDeviceType(){const e=navigator.userAgent;return/Mobi|Android/i.test(e)?"mobile":/Tablet|iPad/i.test(e)?"tablet":"desktop"}getBrowser(){const e=navigator.userAgent;return e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Firefox")?"Firefox":e.includes("Safari")?"Safari":"Other"}getOS(){const e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":/iPhone|iOS/.test(e)?"iOS":"Other"}destroy(){this.flushInterval&&clearInterval(this.flushInterval),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.flush()}}exports.FeedPulseTracker=n;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class n{constructor(e){this.queue=[],this.flushInterval=null,this.observer=null,this.intersectionObserver=null,this.seenInView=new Set,this.config={endpoint:"https://feed-pulse.vercel.app/api/ingest",batchInterval:5e3,...e},this.visitorId="",this.sessionId=""}init(){this.isBrowser()&&(this.visitorId=this.getOrCreateVisitorId(),this.sessionId=this.generateSessionId(),this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM())}attachGlobalListeners(){document.addEventListener("click",t=>{const r=t.target.closest("[data-fp-id]");r&&this.track("click",r.getAttribute("data-fp-id"),{x:t.clientX,y:t.clientY})},{passive:!0});let e=0,i=null;document.addEventListener("mouseover",t=>{const r=t.target.closest("[data-fp-id]");r&&(e=Date.now(),i=r.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",t=>{if(!t.target.closest("[data-fp-id]")||!i)return;const s=Date.now()-e;s>500&&this.track("hover",i,{hoverDuration:s}),i=null},{passive:!0})}observeDOM(){this.intersectionObserver=new IntersectionObserver(i=>{for(const t of i){const r=t.target.dataset.fpId;!r||!t.isIntersecting||this.seenInView.has(r)||(this.seenInView.add(r),this.track("scroll_into_view",r,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))}},{threshold:.5});const e=()=>{document.querySelectorAll("[data-fp-id]").forEach(i=>{this.intersectionObserver?.observe(i)})};e(),this.observer=new MutationObserver(()=>e()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,i,t){this.isBrowser()&&this.queue.push({projectApiKey:this.config.apiKey,elementId:i,eventType:e,sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:t,timestamp:new Date().toISOString()})}trackFeedback(e,i,t){this.isBrowser()&&(!i&&!t||this.sendImmediate([{projectApiKey:this.config.apiKey,elementId:e??"__page__",eventType:"feedback",sessionId:this.sessionId,visitorId:this.visitorId,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:i,message:t},timestamp:new Date().toISOString()}]))}async flush(){if(this.queue.length===0)return;const e=[...this.queue];this.queue=[],await this.sendImmediate(e)}async sendImmediate(e){try{await fetch(this.config.endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0})}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),window.addEventListener("beforeunload",()=>this.flush()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&this.flush()})}getOrCreateVisitorId(){const e="__fp_vid",i=this.generateId();try{let t=localStorage.getItem(e);return t||(t=i,localStorage.setItem(e,t)),t}catch{return i}}generateId(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}isBrowser(){return typeof window<"u"&&typeof document<"u"}generateSessionId(){return`${Date.now()}-${Math.random().toString(36).slice(2)}`}getDeviceType(){const e=navigator.userAgent;return/Mobi|Android/i.test(e)?"mobile":/Tablet|iPad/i.test(e)?"tablet":"desktop"}getBrowser(){const e=navigator.userAgent;return e.includes("Edg")?"Edge":e.includes("Chrome")?"Chrome":e.includes("Firefox")?"Firefox":e.includes("Safari")?"Safari":"Other"}getOS(){const e=navigator.userAgent;return e.includes("Windows")?"Windows":e.includes("Mac")?"macOS":e.includes("Linux")?"Linux":e.includes("Android")?"Android":/iPhone|iOS/.test(e)?"iOS":"Other"}destroy(){this.flushInterval&&clearInterval(this.flushInterval),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.flush()}}exports.FeedPulseTracker=n;
package/dist/index.mjs CHANGED
@@ -4,50 +4,50 @@ class o {
4
4
  endpoint: "https://feed-pulse.vercel.app/api/ingest",
5
5
  batchInterval: 5e3,
6
6
  ...e
7
- }, this.visitorId = this.getOrCreateVisitorId(), this.sessionId = this.generateSessionId();
7
+ }, this.visitorId = "", this.sessionId = "";
8
8
  }
9
9
  init() {
10
- this.startFlushInterval(), this.attachGlobalListeners(), this.observeDOM();
10
+ this.isBrowser() && (this.visitorId = this.getOrCreateVisitorId(), this.sessionId = this.generateSessionId(), this.startFlushInterval(), this.attachGlobalListeners(), this.observeDOM());
11
11
  }
12
12
  attachGlobalListeners() {
13
- document.addEventListener("click", (i) => {
14
- const s = i.target.closest("[data-fp-id]");
15
- s && this.track("click", s.getAttribute("data-fp-id"), {
16
- x: i.clientX,
17
- y: i.clientY
13
+ document.addEventListener("click", (t) => {
14
+ const r = t.target.closest("[data-fp-id]");
15
+ r && this.track("click", r.getAttribute("data-fp-id"), {
16
+ x: t.clientX,
17
+ y: t.clientY
18
18
  });
19
19
  }, { passive: !0 });
20
- let e = 0, t = null;
21
- document.addEventListener("mouseover", (i) => {
22
- const s = i.target.closest("[data-fp-id]");
23
- s && (e = Date.now(), t = s.getAttribute("data-fp-id"));
24
- }, { passive: !0 }), document.addEventListener("mouseout", (i) => {
25
- if (!i.target.closest("[data-fp-id]") || !t)
20
+ let e = 0, i = null;
21
+ document.addEventListener("mouseover", (t) => {
22
+ const r = t.target.closest("[data-fp-id]");
23
+ r && (e = Date.now(), i = r.getAttribute("data-fp-id"));
24
+ }, { passive: !0 }), document.addEventListener("mouseout", (t) => {
25
+ if (!t.target.closest("[data-fp-id]") || !i)
26
26
  return;
27
- const r = Date.now() - e;
28
- r > 500 && this.track("hover", t, { hoverDuration: r }), t = null;
27
+ const s = Date.now() - e;
28
+ s > 500 && this.track("hover", i, { hoverDuration: s }), i = null;
29
29
  }, { passive: !0 });
30
30
  }
31
31
  observeDOM() {
32
- this.intersectionObserver = new IntersectionObserver((t) => {
33
- for (const i of t) {
34
- const s = i.target.dataset.fpId;
35
- !s || !i.isIntersecting || this.seenInView.has(s) || (this.seenInView.add(s), this.track("scroll_into_view", s, {
32
+ this.intersectionObserver = new IntersectionObserver((i) => {
33
+ for (const t of i) {
34
+ const r = t.target.dataset.fpId;
35
+ !r || !t.isIntersecting || this.seenInView.has(r) || (this.seenInView.add(r), this.track("scroll_into_view", r, {
36
36
  scrollDepth: Math.round(window.scrollY / Math.max(1, document.body.scrollHeight) * 100)
37
37
  }));
38
38
  }
39
39
  }, { threshold: 0.5 });
40
40
  const e = () => {
41
- document.querySelectorAll("[data-fp-id]").forEach((t) => {
42
- this.intersectionObserver?.observe(t);
41
+ document.querySelectorAll("[data-fp-id]").forEach((i) => {
42
+ this.intersectionObserver?.observe(i);
43
43
  });
44
44
  };
45
45
  e(), this.observer = new MutationObserver(() => e()), this.observer.observe(document.body, { childList: !0, subtree: !0 });
46
46
  }
47
- track(e, t, i) {
48
- this.queue.push({
47
+ track(e, i, t) {
48
+ this.isBrowser() && this.queue.push({
49
49
  projectApiKey: this.config.apiKey,
50
- elementId: t,
50
+ elementId: i,
51
51
  eventType: e,
52
52
  sessionId: this.sessionId,
53
53
  visitorId: this.visitorId,
@@ -56,12 +56,12 @@ class o {
56
56
  device: this.getDeviceType(),
57
57
  browser: this.getBrowser(),
58
58
  os: this.getOS(),
59
- metadata: i,
59
+ metadata: t,
60
60
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
61
61
  });
62
62
  }
63
- trackFeedback(e, t, i) {
64
- !t && !i || this.sendImmediate([{
63
+ trackFeedback(e, i, t) {
64
+ this.isBrowser() && (!i && !t || this.sendImmediate([{
65
65
  projectApiKey: this.config.apiKey,
66
66
  elementId: e ?? "__page__",
67
67
  eventType: "feedback",
@@ -69,9 +69,9 @@ class o {
69
69
  visitorId: this.visitorId,
70
70
  page: window.location.pathname,
71
71
  device: this.getDeviceType(),
72
- metadata: { rating: t, message: i },
72
+ metadata: { rating: i, message: t },
73
73
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
74
- }]);
74
+ }]));
75
75
  }
76
76
  async flush() {
77
77
  if (this.queue.length === 0)
@@ -96,9 +96,19 @@ class o {
96
96
  });
97
97
  }
98
98
  getOrCreateVisitorId() {
99
- const e = "__fp_vid";
100
- let t = localStorage.getItem(e);
101
- return t || (t = crypto.randomUUID(), localStorage.setItem(e, t)), t;
99
+ const e = "__fp_vid", i = this.generateId();
100
+ try {
101
+ let t = localStorage.getItem(e);
102
+ return t || (t = i, localStorage.setItem(e, t)), t;
103
+ } catch {
104
+ return i;
105
+ }
106
+ }
107
+ generateId() {
108
+ return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
109
+ }
110
+ isBrowser() {
111
+ return typeof window < "u" && typeof document < "u";
102
112
  }
103
113
  generateSessionId() {
104
114
  return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekibo/feedpulse-sdk",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Embeddable analytics and feedback SDK for FeedPulse",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",