@tekibo/feedpulse-sdk 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,11 +22,6 @@ The SDK automatically tracks:
22
22
  - `feedback`: explicit rating/message submissions from widget or manual API
23
23
 
24
24
 
25
-
26
-
27
-
28
- ## Quick start (Nuxt)
29
-
30
25
  Import from `@tekibo/feedpulse-sdk/nuxt` and wrap your app:
31
26
 
32
27
  ```vue
@@ -36,12 +31,16 @@ import { FeedPulseProvider, FeedPulseWidget } from "@tekibo/feedpulse-sdk/nuxt";
36
31
 
37
32
  <template>
38
33
  <FeedPulseProvider api-key="fp_live_your_project_key">
39
- <NuxtPage />
34
+ <FeedPulseProvider
35
+ api-key="fp_live_your_project_key"
36
+ endpoint="https://feed-pulse.vercel.app/api/ingest"
37
+ >
40
38
  <FeedPulseWidget id="global-feedback" position="bottom-right" />
41
39
  </FeedPulseProvider>
42
40
  </template>
43
41
  ```
44
42
 
43
+
45
44
  Tag any interactive element with `data-fp-id`:
46
45
 
47
46
  ```vue
@@ -88,7 +87,10 @@ function SaveButton() {
88
87
 
89
88
  export default function App() {
90
89
  return (
91
- <FeedPulseProvider apiKey="fp_live_your_project_key">
90
+ <FeedPulseProvider
91
+ apiKey="fp_live_your_project_key"
92
+ endpoint="https://feed-pulse.vercel.app/api/ingest"
93
+ >
92
94
  <button data-fp-id="hero-cta">Get Started</button>
93
95
  <SaveButton />
94
96
  <FeedPulseWidget id="global-feedback" position="bottom-right" />
@@ -108,7 +110,7 @@ import { FeedPulseTracker } from "@tekibo/feedpulse-sdk";
108
110
  `FeedPulseTracker` configuration:
109
111
 
110
112
  - `apiKey: string` required
111
- - `endpoint?: string` optional, defaults to `https://feedpulse.dev/api/ingest`
113
+ - `endpoint?: string` optional, defaults to `https://feed-pulse.vercel.app/api/ingest`
112
114
  - `batchInterval?: number` optional, defaults to `5000` ms
113
115
 
114
116
  Key methods:
@@ -126,7 +128,6 @@ Nuxt and React widgets support:
126
128
  - `placeholder?: string` prompt text
127
129
  - `position?: "bottom-right" | "bottom-left" | "inline"` default is `"bottom-right"`
128
130
 
129
-
130
131
  ## Integration checklist for your app
131
132
 
132
133
  1. Create a project in FeedPulse dashboard and copy the project API key
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://feedpulse.dev/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.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;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  class o {
2
2
  constructor(e) {
3
3
  this.queue = [], this.flushInterval = null, this.observer = null, this.intersectionObserver = null, this.seenInView = /* @__PURE__ */ new Set(), this.config = {
4
- endpoint: "https://feedpulse.dev/api/ingest",
4
+ endpoint: "https://feed-pulse.vercel.app/api/ingest",
5
5
  batchInterval: 5e3,
6
6
  ...e
7
7
  }, this.visitorId = this.getOrCreateVisitorId(), this.sessionId = this.generateSessionId();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekibo/feedpulse-sdk",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Embeddable analytics and feedback SDK for FeedPulse",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",