@tekibo/feedpulse-sdk 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,29 +1,24 @@
1
1
  # @tekibo/feedpulse-sdk
2
2
 
3
- Developer-first embeddable behavior analytics and feedback SDK for Nuxt and React.
3
+ FeedPulse analytics and feedback SDK for Nuxt and React.
4
4
 
5
- - Tracks user interactions from elements tagged with `data-fp-id`
6
- - Sends event batches to your FeedPulse ingest endpoint
7
- - Includes ready-to-use feedback widgets for Nuxt and React
5
+ ## Setup
8
6
 
9
- ## Install
7
+ ### 1) Create a proxy route in your own app
10
8
 
11
- ```bash
12
- pnpm add @tekibo/feedpulse-sdk
13
- ```
14
-
15
- ## What this SDK tracks
9
+ - Nuxt: copy `templates/nuxt-proxy.ts` to `server/api/fp-proxy.post.ts`
10
+ - Next.js App Router: copy `templates/nextjs-proxy.ts` to `app/api/fp-proxy/route.ts`
16
11
 
17
- The SDK automatically tracks:
12
+ ### 2) Set server-only environment variables
18
13
 
19
- - `click`: when users click an element that has `data-fp-id`
20
- - `hover`: when users hover an element for more than 500ms
21
- - `scroll_into_view`: when tagged elements enter viewport
22
- - `feedback`: explicit rating/message submissions from widget or manual API
14
+ ```env
15
+ FEEDPULSE_API_KEY=fp_live_your_key
16
+ FEEDPULSE_WORKER_URL=https://feedpulse-workers.tekibohelp.workers.dev/ingest
17
+ ```
23
18
 
24
- ## Quick start (Nuxt)
19
+ Never use `NUXT_PUBLIC_` or `NEXT_PUBLIC_` for the FeedPulse API key.
25
20
 
26
- Import from `@tekibo/feedpulse-sdk/nuxt` and wrap your app:
21
+ ### 3) Use SDK without exposing key in client
27
22
 
28
23
  ```vue
29
24
  <script setup lang="ts">
@@ -31,115 +26,58 @@ import { FeedPulseProvider, FeedPulseWidget } from "@tekibo/feedpulse-sdk/nuxt";
31
26
  </script>
32
27
 
33
28
  <template>
34
- <FeedPulseProvider api-key="fp_live_your_project_key">
29
+ <FeedPulseProvider :debug="true">
35
30
  <NuxtPage />
36
- <FeedPulseWidget id="global-feedback" position="bottom-right" />
31
+ <FeedPulseWidget position="bottom-right" />
37
32
  </FeedPulseProvider>
38
33
  </template>
39
34
  ```
40
35
 
41
- The SDK uses `https://feed-pulse.vercel.app/api/ingest` by default, so only `api-key` is required.
42
- Tag any interactive element with `data-fp-id`:
43
-
44
- ```vue
45
- <template>
46
- <UButton data-fp-id="hero-cta">
47
- Start free trial
48
- </UButton>
49
- </template>
50
- ```
51
-
52
- Use the composable for manual feedback/event calls:
53
-
54
- ```vue
55
- <script setup lang="ts">
56
- import { useFeedPulse } from "@tekibo/feedpulse-sdk/nuxt";
57
-
58
- const tracker = useFeedPulse();
59
-
60
- function sendNps() {
61
- tracker?.trackFeedback("nps-card", 5, "Great onboarding flow");
62
- }
63
- </script>
64
- ```
65
-
66
- ## Quick start (React)
67
-
68
- Import from `@tekibo/feedpulse-sdk/react`:
69
-
70
36
  ```tsx
71
- import { FeedPulseProvider, FeedPulseWidget, useFeedPulse } from "@tekibo/feedpulse-sdk/react";
72
-
73
- function SaveButton() {
74
- const { tracker } = useFeedPulse();
37
+ import { FeedPulseProvider, FeedPulseWidget } from "@tekibo/feedpulse-sdk/react";
75
38
 
39
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
76
40
  return (
77
- <button
78
- data-fp-id="settings-save"
79
- onClick={() => tracker?.trackFeedback("settings-save", 5, "Saved successfully")}
80
- >
81
- Save
82
- </button>
83
- );
84
- }
85
-
86
- export default function App() {
87
- return (
88
- <FeedPulseProvider apiKey="fp_live_your_project_key">
89
- <button data-fp-id="hero-cta">Get Started</button>
90
- <SaveButton />
91
- <FeedPulseWidget id="global-feedback" position="bottom-right" />
41
+ <FeedPulseProvider debug>
42
+ {children}
43
+ <FeedPulseWidget position="bottom-right" />
92
44
  </FeedPulseProvider>
93
45
  );
94
46
  }
95
47
  ```
96
48
 
97
- ## Core API
98
-
99
- Import from `@tekibo/feedpulse-sdk`:
100
-
101
- ```ts
102
- import { FeedPulseTracker } from "@tekibo/feedpulse-sdk";
103
- ```
104
-
105
- `FeedPulseTracker` configuration:
106
-
107
- - `apiKey: string` required
108
- - `endpoint?: string` optional, defaults to `https://feed-pulse.vercel.app/api/ingest`
109
- - `batchInterval?: number` optional, defaults to `5000` ms
110
-
111
- Key methods:
112
-
113
- - `init()` start listeners and batching
114
- - `track(eventType, elementId, metadata?)` enqueue an event
115
- - `trackFeedback(elementId, rating, message)` send feedback immediately
116
- - `destroy()` stop listeners and flush queue
49
+ ## How it works
117
50
 
118
- ## Widget props
51
+ - Browser sends events to `/api/fp-proxy` by default
52
+ - Your server route injects `FEEDPULSE_API_KEY`
53
+ - Server forwards to FeedPulse worker ingest endpoint
54
+ - API key never appears in browser source or client payload
119
55
 
120
- Nuxt and React widgets support:
56
+ ## Provider props
121
57
 
122
- - `id?: string` element id used in feedback event
123
- - `placeholder?: string` prompt text
124
- - `position?: "bottom-right" | "bottom-left" | "inline"` default is `"bottom-right"`
58
+ - `proxyEndpoint?: string` default `/api/fp-proxy`
59
+ - `debug?: boolean`
60
+ - `consentRequired?: boolean` default `true`
125
61
 
126
- ## Optional endpoint override
62
+ ## Tracker config
127
63
 
128
- You can override the default endpoint when needed:
129
-
130
- - Nuxt: `<FeedPulseProvider api-key="..." endpoint="https://your-domain.com/api/ingest">`
131
- - React: `<FeedPulseProvider apiKey="..." endpoint="https://your-domain.com/api/ingest">`
64
+ ```ts
65
+ type FeedPulseConfig = {
66
+ proxyEndpoint?: string
67
+ batchInterval?: number
68
+ debug?: boolean
69
+ }
70
+ ```
132
71
 
133
- ## Integration checklist for your app
72
+ ## What is tracked
134
73
 
135
- 1. Create a project in FeedPulse dashboard and copy the project API key
136
- 2. Install package and add provider at root layout/app level
137
- 3. Add `data-fp-id` to primary buttons, links, forms, and sections
138
- 4. Optionally mount `FeedPulseWidget` for direct user feedback
139
- 5. Verify data appears in FeedPulse dashboard analytics and feedback pages
74
+ - `click`
75
+ - `hover`
76
+ - `scroll_into_view`
77
+ - `feedback`
78
+ - `consent`
140
79
 
141
- ## Package exports
80
+ ## Templates included in package
142
81
 
143
- - `@tekibo/feedpulse-sdk` → core types + tracker
144
- - `@tekibo/feedpulse-sdk/nuxt` → `FeedPulseProvider`, `FeedPulseWidget`, `useFeedPulse`
145
- - `@tekibo/feedpulse-sdk/react` → `FeedPulseProvider`, `FeedPulseWidget`, `useFeedPulse`
82
+ - `templates/nuxt-proxy.ts`
83
+ - `templates/nextjs-proxy.ts`
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function d(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var s in t)r[s]=t[s]}return r}var S={read:function(r){return r[0]==='"'&&(r=r.slice(1,-1)),r.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(r){return encodeURIComponent(r).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}};function f(r,e){function t(i,o,n){if(!(typeof document>"u")){n=d({},e,n),typeof n.expires=="number"&&(n.expires=new Date(Date.now()+n.expires*864e5)),n.expires&&(n.expires=n.expires.toUTCString()),i=encodeURIComponent(i).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var u="";for(var l in n)n[l]&&(u+="; "+l,n[l]!==!0&&(u+="="+n[l].split(";")[0]));return document.cookie=i+"="+r.write(o,i)+u}}function s(i){if(!(typeof document>"u"||arguments.length&&!i)){for(var o=document.cookie?document.cookie.split("; "):[],n={},u=0;u<o.length;u++){var l=o[u].split("="),m=l.slice(1).join("=");try{var h=decodeURIComponent(l[0]);if(n[h]=r.read(m,h),i===h)break}catch{}}return i?n[i]:n}}return Object.create({set:t,get:s,remove:function(i,o){t(i,"",d({},o,{expires:-1}))},withAttributes:function(i){return f(this.converter,d({},this.attributes,i))},withConverter:function(i){return f(d({},this.converter,i),this.attributes)}},{attributes:{value:Object.freeze(e)},converter:{value:Object.freeze(r)}})}var c=f(S,{path:"/"});const a={USER_ID:"__fp_uid",SESSION_ID:"__fp_sid",SESSION_START:"__fp_ss",CONSENT:"__fp_consent",UTM:"__fp_utm"},p=1/48,I=365,w=365,k=30;function D(){return typeof window<"u"}function g(r){if(!r)return null;try{return JSON.parse(r)}catch{return null}}class v{initSession(){const e=!!c.get(a.USER_ID);let t=c.get(a.SESSION_ID)??null,s=Number(c.get(a.SESSION_START)||Date.now());return t||(t=crypto.randomUUID(),s=Date.now()),c.set(a.SESSION_ID,t,{expires:p}),c.set(a.SESSION_START,String(s),{expires:p}),{sessionId:t,sessionStart:s,isReturningUser:e}}initUser(){let e=c.get(a.USER_ID)??null;return e||(e=crypto.randomUUID(),c.set(a.USER_ID,e,{expires:w})),e}getConsent(){return g(c.get(a.CONSENT))}setConsent(e){const t={necessary:!0,analytics:e.analytics,marketing:e.marketing,version:e.version,timestamp:Date.now()};return c.set(a.CONSENT,JSON.stringify(t),{expires:I}),t}clearAnalyticsCookies(){c.remove(a.USER_ID)}isConsentExpired(){const e=this.getConsent();if(!e)return!0;const t=365*24*60*60*1e3;return Date.now()-e.timestamp>t}captureUTM(){if(!D())return null;const e=new URLSearchParams(window.location.search),t={};for(const s of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){const i=e.get(s);i&&(t[s]=i)}return Object.keys(t).length===0?g(c.get(a.UTM)):(c.set(a.UTM,JSON.stringify(t),{expires:k}),t)}getAllData(e){const{sessionId:t,sessionStart:s,isReturningUser:i}=this.initSession();return{userId:e?this.initUser():null,sessionId:t,sessionStart:s,consent:this.getConsent(),utm:this.captureUTM(),isReturningUser:e?i:!1}}}class b{constructor(e){this.queue=[],this.flushInterval=null,this.sessionId="",this.observer=null,this.intersectionObserver=null,this.scrollFallbackListener=null,this.resizeFallbackListener=null,this.seenInView=new Set,this.cookieManager=new v,this.cookieData=null,this.analyticsConsented=!1,this.isInitialized=!1,this.beforeUnloadListener=null,this.visibilityListener=null;const t="https://feedpulse-workers.tekibohelp.workers.dev/ingest";this.config={apiKey:e.apiKey,endpoint:e.endpoint??t,batchInterval:e.batchInterval??5e3,debug:e.debug??!1}}init(){!this.isBrowser()||this.isInitialized||(this.isInitialized=!0,this.refreshCookieData(),this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM())}attachGlobalListeners(){document.addEventListener("click",s=>{const i=s.target.closest("[data-fp-id]");i&&this.track("click",i.getAttribute("data-fp-id"),{x:s.clientX,y:s.clientY})},{passive:!0});let e=0,t=null;document.addEventListener("mouseover",s=>{const i=s.target.closest("[data-fp-id]");i&&(e=Date.now(),t=i.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",s=>{if(!s.target.closest("[data-fp-id]")||!t)return;const o=Date.now()-e;o>500&&this.track("hover",t,{hoverDuration:o}),t=null},{passive:!0})}observeDOM(){const e=i=>{this.seenInView.has(i)||(this.seenInView.add(i),this.track("scroll_into_view",i,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))};this.intersectionObserver=new IntersectionObserver(i=>{for(const o of i){const n=o.target.dataset.fpId;!n||!o.isIntersecting||e(n)}},{threshold:.1});const t=()=>{document.querySelectorAll("[data-fp-id]").forEach(i=>{this.intersectionObserver?.observe(i)})},s=()=>{const i=window.innerHeight*.1,o=window.innerHeight*.9;document.querySelectorAll("[data-fp-id]").forEach(n=>{const u=n.dataset.fpId;if(!u||this.seenInView.has(u))return;const l=n.getBoundingClientRect();l.bottom>=i&&l.top<=o&&e(u)})};t(),s(),this.scrollFallbackListener=()=>s(),this.resizeFallbackListener=()=>s(),window.addEventListener("scroll",this.scrollFallbackListener,{passive:!0}),window.addEventListener("resize",this.resizeFallbackListener,{passive:!0}),this.observer=new MutationObserver(()=>t()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,t,s){this.isBrowser()&&(this.refreshCookieData(),this.queue.push({projectApiKey:this.config.apiKey,elementId:t,eventType:e,sessionId:this.cookieData?.sessionId??this.sessionId,visitorId:this.cookieData?.userId??null,isReturningUser:this.cookieData?.isReturningUser??!1,sessionStart:this.cookieData?.sessionStart?new Date(this.cookieData.sessionStart).toISOString():null,utmSource:this.cookieData?.utm?.utm_source??null,utmMedium:this.cookieData?.utm?.utm_medium??null,utmCampaign:this.cookieData?.utm?.utm_campaign??null,utmTerm:this.cookieData?.utm?.utm_term??null,utmContent:this.cookieData?.utm?.utm_content??null,consentAnalytics:this.cookieData?.consent?.analytics??!1,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:s,timestamp:new Date().toISOString()}))}trackFeedback(e,t,s){this.isBrowser()&&(!t&&!s||(this.refreshCookieData(),this.sendImmediate([{projectApiKey:this.config.apiKey,elementId:e??"__page__",eventType:"feedback",sessionId:this.cookieData?.sessionId??this.sessionId,visitorId:this.cookieData?.userId??null,isReturningUser:this.cookieData?.isReturningUser??!1,sessionStart:this.cookieData?.sessionStart?new Date(this.cookieData.sessionStart).toISOString():null,utmSource:this.cookieData?.utm?.utm_source??null,utmMedium:this.cookieData?.utm?.utm_medium??null,utmCampaign:this.cookieData?.utm?.utm_campaign??null,utmTerm:this.cookieData?.utm?.utm_term??null,utmContent:this.cookieData?.utm?.utm_content??null,consentAnalytics:this.cookieData?.consent?.analytics??!1,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:t,message:s},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{const t=await fetch(this.config.endpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(this.config.debug&&t.ok){const s=await t.json().catch(()=>null);s?.ingested!==void 0&&s?.pipeline&&globalThis.console.debug(`[FeedPulse] ${s.ingested} events via ${s.pipeline} pipeline`)}}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),this.beforeUnloadListener=()=>this.flush(),this.visibilityListener=()=>{document.visibilityState==="hidden"&&this.flush()},window.addEventListener("beforeunload",this.beforeUnloadListener),document.addEventListener("visibilitychange",this.visibilityListener)}updateCookieData(e){this.cookieData=e,this.sessionId=e.sessionId,this.analyticsConsented=!!e.consent?.analytics}refreshCookieData(){const e=this.cookieManager.getAllData(this.analyticsConsented);this.cookieData=e,this.sessionId=e.sessionId}isBrowser(){return typeof window<"u"&&typeof document<"u"}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.beforeUnloadListener&&window.removeEventListener("beforeunload",this.beforeUnloadListener),this.visibilityListener&&document.removeEventListener("visibilitychange",this.visibilityListener),this.scrollFallbackListener&&window.removeEventListener("scroll",this.scrollFallbackListener),this.resizeFallbackListener&&window.removeEventListener("resize",this.resizeFallbackListener),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.isInitialized=!1,this.flush()}}exports.COOKIE_KEYS=a;exports.CookieManager=v;exports.FeedPulseTracker=b;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function d(r){for(var e=1;e<arguments.length;e++){var t=arguments[e];for(var s in t)r[s]=t[s]}return r}var S={read:function(r){return r[0]==='"'&&(r=r.slice(1,-1)),r.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(r){return encodeURIComponent(r).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}};function f(r,e){function t(i,o,n){if(!(typeof document>"u")){n=d({},e,n),typeof n.expires=="number"&&(n.expires=new Date(Date.now()+n.expires*864e5)),n.expires&&(n.expires=n.expires.toUTCString()),i=encodeURIComponent(i).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var u="";for(var l in n)n[l]&&(u+="; "+l,n[l]!==!0&&(u+="="+n[l].split(";")[0]));return document.cookie=i+"="+r.write(o,i)+u}}function s(i){if(!(typeof document>"u"||arguments.length&&!i)){for(var o=document.cookie?document.cookie.split("; "):[],n={},u=0;u<o.length;u++){var l=o[u].split("="),m=l.slice(1).join("=");try{var h=decodeURIComponent(l[0]);if(n[h]=r.read(m,h),i===h)break}catch{}}return i?n[i]:n}}return Object.create({set:t,get:s,remove:function(i,o){t(i,"",d({},o,{expires:-1}))},withAttributes:function(i){return f(this.converter,d({},this.attributes,i))},withConverter:function(i){return f(d({},this.converter,i),this.attributes)}},{attributes:{value:Object.freeze(e)},converter:{value:Object.freeze(r)}})}var c=f(S,{path:"/"});const a={USER_ID:"__fp_uid",SESSION_ID:"__fp_sid",SESSION_START:"__fp_ss",CONSENT:"__fp_consent",UTM:"__fp_utm"},p=1/48,I=365,w=365,k=30;function D(){return typeof window<"u"}function g(r){if(!r)return null;try{return JSON.parse(r)}catch{return null}}class v{initSession(){const e=!!c.get(a.USER_ID);let t=c.get(a.SESSION_ID)??null,s=Number(c.get(a.SESSION_START)||Date.now());return t||(t=crypto.randomUUID(),s=Date.now()),c.set(a.SESSION_ID,t,{expires:p}),c.set(a.SESSION_START,String(s),{expires:p}),{sessionId:t,sessionStart:s,isReturningUser:e}}initUser(){let e=c.get(a.USER_ID)??null;return e||(e=crypto.randomUUID(),c.set(a.USER_ID,e,{expires:w})),e}getConsent(){return g(c.get(a.CONSENT))}setConsent(e){const t={necessary:!0,analytics:e.analytics,marketing:e.marketing,version:e.version,timestamp:Date.now()};return c.set(a.CONSENT,JSON.stringify(t),{expires:I}),t}clearAnalyticsCookies(){c.remove(a.USER_ID)}isConsentExpired(){const e=this.getConsent();if(!e)return!0;const t=365*24*60*60*1e3;return Date.now()-e.timestamp>t}captureUTM(){if(!D())return null;const e=new URLSearchParams(window.location.search),t={};for(const s of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){const i=e.get(s);i&&(t[s]=i)}return Object.keys(t).length===0?g(c.get(a.UTM)):(c.set(a.UTM,JSON.stringify(t),{expires:k}),t)}getAllData(e){const{sessionId:t,sessionStart:s,isReturningUser:i}=this.initSession();return{userId:e?this.initUser():null,sessionId:t,sessionStart:s,consent:this.getConsent(),utm:this.captureUTM(),isReturningUser:e?i:!1}}}class b{constructor(e){this.queue=[],this.flushInterval=null,this.sessionId="",this.observer=null,this.intersectionObserver=null,this.scrollFallbackListener=null,this.resizeFallbackListener=null,this.seenInView=new Set,this.cookieManager=new v,this.cookieData=null,this.analyticsConsented=!1,this.isInitialized=!1,this.beforeUnloadListener=null,this.visibilityListener=null,this.config={proxyEndpoint:e.proxyEndpoint??"/api/fp-proxy",batchInterval:e.batchInterval??5e3,debug:e.debug??!1}}init(){!this.isBrowser()||this.isInitialized||(this.isInitialized=!0,this.refreshCookieData(),this.startFlushInterval(),this.attachGlobalListeners(),this.observeDOM())}attachGlobalListeners(){document.addEventListener("click",s=>{const i=s.target.closest("[data-fp-id]");i&&this.track("click",i.getAttribute("data-fp-id"),{x:s.clientX,y:s.clientY})},{passive:!0});let e=0,t=null;document.addEventListener("mouseover",s=>{const i=s.target.closest("[data-fp-id]");i&&(e=Date.now(),t=i.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",s=>{if(!s.target.closest("[data-fp-id]")||!t)return;const o=Date.now()-e;o>500&&this.track("hover",t,{hoverDuration:o}),t=null},{passive:!0})}observeDOM(){const e=i=>{this.seenInView.has(i)||(this.seenInView.add(i),this.track("scroll_into_view",i,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))};this.intersectionObserver=new IntersectionObserver(i=>{for(const o of i){const n=o.target.dataset.fpId;!n||!o.isIntersecting||e(n)}},{threshold:.1});const t=()=>{document.querySelectorAll("[data-fp-id]").forEach(i=>{this.intersectionObserver?.observe(i)})},s=()=>{const i=window.innerHeight*.1,o=window.innerHeight*.9;document.querySelectorAll("[data-fp-id]").forEach(n=>{const u=n.dataset.fpId;if(!u||this.seenInView.has(u))return;const l=n.getBoundingClientRect();l.bottom>=i&&l.top<=o&&e(u)})};t(),s(),this.scrollFallbackListener=()=>s(),this.resizeFallbackListener=()=>s(),window.addEventListener("scroll",this.scrollFallbackListener,{passive:!0}),window.addEventListener("resize",this.resizeFallbackListener,{passive:!0}),this.observer=new MutationObserver(()=>t()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,t,s){this.isBrowser()&&(this.refreshCookieData(),this.queue.push({elementId:t,eventType:e,sessionId:this.cookieData?.sessionId??this.sessionId,visitorId:this.cookieData?.userId??null,isReturningUser:this.cookieData?.isReturningUser??!1,sessionStart:this.cookieData?.sessionStart?new Date(this.cookieData.sessionStart).toISOString():null,utmSource:this.cookieData?.utm?.utm_source??null,utmMedium:this.cookieData?.utm?.utm_medium??null,utmCampaign:this.cookieData?.utm?.utm_campaign??null,utmTerm:this.cookieData?.utm?.utm_term??null,utmContent:this.cookieData?.utm?.utm_content??null,consentAnalytics:this.cookieData?.consent?.analytics??!1,page:window.location.pathname,referrer:document.referrer,device:this.getDeviceType(),browser:this.getBrowser(),os:this.getOS(),metadata:s,timestamp:new Date().toISOString()}))}trackFeedback(e,t,s){this.isBrowser()&&(!t&&!s||(this.refreshCookieData(),this.sendImmediate([{elementId:e??"__page__",eventType:"feedback",sessionId:this.cookieData?.sessionId??this.sessionId,visitorId:this.cookieData?.userId??null,isReturningUser:this.cookieData?.isReturningUser??!1,sessionStart:this.cookieData?.sessionStart?new Date(this.cookieData.sessionStart).toISOString():null,utmSource:this.cookieData?.utm?.utm_source??null,utmMedium:this.cookieData?.utm?.utm_medium??null,utmCampaign:this.cookieData?.utm?.utm_campaign??null,utmTerm:this.cookieData?.utm?.utm_term??null,utmContent:this.cookieData?.utm?.utm_content??null,consentAnalytics:this.cookieData?.consent?.analytics??!1,page:window.location.pathname,device:this.getDeviceType(),metadata:{rating:t,message:s},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{const t=await fetch(this.config.proxyEndpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(this.config.debug&&t.ok){const s=await t.json().catch(()=>null);s?.ingested!==void 0&&s?.pipeline&&globalThis.console.debug(`[FeedPulse] ${s.ingested} events via ${s.pipeline} pipeline`)}}catch{}}startFlushInterval(){this.flushInterval=setInterval(()=>this.flush(),this.config.batchInterval),this.beforeUnloadListener=()=>this.flush(),this.visibilityListener=()=>{document.visibilityState==="hidden"&&this.flush()},window.addEventListener("beforeunload",this.beforeUnloadListener),document.addEventListener("visibilitychange",this.visibilityListener)}updateCookieData(e){this.cookieData=e,this.sessionId=e.sessionId,this.analyticsConsented=!!e.consent?.analytics}refreshCookieData(){const e=this.cookieManager.getAllData(this.analyticsConsented);this.cookieData=e,this.sessionId=e.sessionId}isBrowser(){return typeof window<"u"&&typeof document<"u"}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.beforeUnloadListener&&window.removeEventListener("beforeunload",this.beforeUnloadListener),this.visibilityListener&&document.removeEventListener("visibilitychange",this.visibilityListener),this.scrollFallbackListener&&window.removeEventListener("scroll",this.scrollFallbackListener),this.resizeFallbackListener&&window.removeEventListener("resize",this.resizeFallbackListener),this.observer?.disconnect(),this.intersectionObserver?.disconnect(),this.isInitialized=!1,this.flush()}}exports.COOKIE_KEYS=a;exports.CookieManager=v;exports.FeedPulseTracker=b;
package/dist/index.mjs CHANGED
@@ -30,10 +30,10 @@ function f(r, e) {
30
30
  function s(i) {
31
31
  if (!(typeof document > "u" || arguments.length && !i)) {
32
32
  for (var o = document.cookie ? document.cookie.split("; ") : [], n = {}, u = 0; u < o.length; u++) {
33
- var l = o[u].split("="), p = l.slice(1).join("=");
33
+ var l = o[u].split("="), m = l.slice(1).join("=");
34
34
  try {
35
35
  var h = decodeURIComponent(l[0]);
36
- if (n[h] = r.read(p, h), i === h)
36
+ if (n[h] = r.read(m, h), i === h)
37
37
  break;
38
38
  } catch {
39
39
  }
@@ -74,7 +74,7 @@ const c = {
74
74
  SESSION_START: "__fp_ss",
75
75
  CONSENT: "__fp_consent",
76
76
  UTM: "__fp_utm"
77
- }, m = 1 / 48, I = 365, S = 365, w = 30;
77
+ }, p = 1 / 48, I = 365, S = 365, w = 30;
78
78
  function k() {
79
79
  return typeof window < "u";
80
80
  }
@@ -91,7 +91,7 @@ class D {
91
91
  initSession() {
92
92
  const e = !!a.get(c.USER_ID);
93
93
  let t = a.get(c.SESSION_ID) ?? null, s = Number(a.get(c.SESSION_START) || Date.now());
94
- return t || (t = crypto.randomUUID(), s = Date.now()), a.set(c.SESSION_ID, t, { expires: m }), a.set(c.SESSION_START, String(s), { expires: m }), { sessionId: t, sessionStart: s, isReturningUser: e };
94
+ return t || (t = crypto.randomUUID(), s = Date.now()), a.set(c.SESSION_ID, t, { expires: p }), a.set(c.SESSION_START, String(s), { expires: p }), { sessionId: t, sessionStart: s, isReturningUser: e };
95
95
  }
96
96
  initUser() {
97
97
  let e = a.get(c.USER_ID) ?? null;
@@ -144,11 +144,8 @@ class D {
144
144
  }
145
145
  class _ {
146
146
  constructor(e) {
147
- this.queue = [], this.flushInterval = null, this.sessionId = "", this.observer = null, this.intersectionObserver = null, this.scrollFallbackListener = null, this.resizeFallbackListener = null, this.seenInView = /* @__PURE__ */ new Set(), this.cookieManager = new D(), this.cookieData = null, this.analyticsConsented = !1, this.isInitialized = !1, this.beforeUnloadListener = null, this.visibilityListener = null;
148
- const t = "https://feedpulse-workers.tekibohelp.workers.dev/ingest";
149
- this.config = {
150
- apiKey: e.apiKey,
151
- endpoint: e.endpoint ?? t,
147
+ this.queue = [], this.flushInterval = null, this.sessionId = "", this.observer = null, this.intersectionObserver = null, this.scrollFallbackListener = null, this.resizeFallbackListener = null, this.seenInView = /* @__PURE__ */ new Set(), this.cookieManager = new D(), this.cookieData = null, this.analyticsConsented = !1, this.isInitialized = !1, this.beforeUnloadListener = null, this.visibilityListener = null, this.config = {
148
+ proxyEndpoint: e.proxyEndpoint ?? "/api/fp-proxy",
152
149
  batchInterval: e.batchInterval ?? 5e3,
153
150
  debug: e.debug ?? !1
154
151
  };
@@ -205,7 +202,6 @@ class _ {
205
202
  }
206
203
  track(e, t, s) {
207
204
  this.isBrowser() && (this.refreshCookieData(), this.queue.push({
208
- projectApiKey: this.config.apiKey,
209
205
  elementId: t,
210
206
  eventType: e,
211
207
  sessionId: this.cookieData?.sessionId ?? this.sessionId,
@@ -229,7 +225,6 @@ class _ {
229
225
  }
230
226
  trackFeedback(e, t, s) {
231
227
  this.isBrowser() && (!t && !s || (this.refreshCookieData(), this.sendImmediate([{
232
- projectApiKey: this.config.apiKey,
233
228
  elementId: e ?? "__page__",
234
229
  eventType: "feedback",
235
230
  sessionId: this.cookieData?.sessionId ?? this.sessionId,
@@ -256,7 +251,7 @@ class _ {
256
251
  }
257
252
  async sendImmediate(e) {
258
253
  try {
259
- const t = await fetch(this.config.endpoint, {
254
+ const t = await fetch(this.config.proxyEndpoint, {
260
255
  method: "POST",
261
256
  headers: { "content-type": "application/json" },
262
257
  body: JSON.stringify({ events: e }),
package/dist/nuxt.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),y=require("./index.js"),x=Symbol("feedpulse");function v(){return e.inject(x,null)}const w={key:0,style:{position:"fixed",bottom:"0",left:"0",right:"0","z-index":"99999",background:"#1a1a1a",color:"#fff",padding:"20px 24px","border-top":"1px solid #333","font-family":"sans-serif"}},C={style:{"max-width":"900px",margin:"0 auto"}},E={key:0,style:{"margin-bottom":"12px","font-size":"13px"}},h={style:{display:"flex","align-items":"center",gap:"8px","margin-bottom":"6px"}},V={style:{display:"flex","align-items":"center",gap:"8px"}},N={style:{display:"flex",gap:"8px","flex-wrap":"wrap","align-items":"center"}},b=e.defineComponent({__name:"consent-banner",emits:["consent"],setup(s,{emit:r}){const o=r,n=new y.CookieManager,a=e.ref(!1),t=e.ref(!1),i=e.ref(!1),c=e.ref(!1);function f(){a.value=!0,t.value=!0}e.onMounted(()=>{const p=n.getConsent();a.value=!p||n.isConsentExpired(),p&&(i.value=p.analytics,c.value=p.marketing),typeof window<"u"&&(window.addEventListener("feedpulse:open-consent",f),window.addEventListener("feedpulse:withdraw-consent",k))});function m(){n.setConsent({analytics:!0,marketing:!0,version:"1.0"}),o("consent",{analytics:!0,marketing:!0,action:"accept_all"}),a.value=!1}function d(){n.setConsent({analytics:!1,marketing:!1,version:"1.0"}),n.clearAnalyticsCookies(),o("consent",{analytics:!1,marketing:!1,action:"reject_all"}),a.value=!1}function u(){n.setConsent({analytics:i.value,marketing:c.value,version:"1.0"}),i.value||n.clearAnalyticsCookies(),o("consent",{analytics:i.value,marketing:c.value,action:"custom"}),a.value=!1}function k(){n.setConsent({analytics:!1,marketing:!1,version:"1.0"}),n.clearAnalyticsCookies(),i.value=!1,c.value=!1,o("consent",{analytics:!1,marketing:!1,action:"withdraw"}),a.value=!0}return e.onBeforeUnmount(()=>{typeof window<"u"&&(window.removeEventListener("feedpulse:open-consent",f),window.removeEventListener("feedpulse:withdraw-consent",k))}),(p,l)=>(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[a.value?(e.openBlock(),e.createElementBlock("div",w,[e.createElementVNode("div",C,[l[6]||(l[6]=e.createElementVNode("p",{style:{margin:"0 0 12px","font-size":"14px","line-height":"1.5"}},[e.createTextVNode(" We use cookies to improve reliability and understand usage. "),e.createElementVNode("a",{href:"/privacy",style:{color:"#818cf8"}},"Privacy Policy")],-1)),t.value?(e.openBlock(),e.createElementBlock("div",E,[l[5]||(l[5]=e.createElementVNode("label",{style:{display:"flex","align-items":"center",gap:"8px","margin-bottom":"6px",opacity:"0.75"}},[e.createElementVNode("input",{type:"checkbox",checked:"",disabled:""}),e.createTextVNode(" Necessary (always on) ")],-1)),e.createElementVNode("label",h,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":l[0]||(l[0]=g=>i.value=g),type:"checkbox"},null,512),[[e.vModelCheckbox,i.value]]),l[3]||(l[3]=e.createTextVNode(" Analytics ",-1))]),e.createElementVNode("label",V,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":l[1]||(l[1]=g=>c.value=g),type:"checkbox"},null,512),[[e.vModelCheckbox,c.value]]),l[4]||(l[4]=e.createTextVNode(" Marketing ",-1))])])):e.createCommentVNode("",!0),e.createElementVNode("div",N,[e.createElementVNode("button",{style:{width:"130px",padding:"9px 12px",background:"#4f46e5",color:"#fff",border:"1px solid #4f46e5","border-radius":"6px","font-size":"13px","font-weight":"600",cursor:"pointer"},onClick:m}," Accept All "),e.createElementVNode("button",{style:{width:"130px",padding:"9px 12px",background:"transparent",color:"#fff",border:"1px solid #555","border-radius":"6px","font-size":"13px","font-weight":"600",cursor:"pointer"},onClick:d}," Reject All "),e.createElementVNode("button",{style:{padding:"9px 16px",background:"transparent",color:"#aaa",border:"1px solid #333","border-radius":"6px","font-size":"13px",cursor:"pointer"},onClick:l[2]||(l[2]=g=>t.value?u():t.value=!0)},e.toDisplayString(t.value?"Save Preferences":"Customize"),1)])])])):e.createCommentVNode("",!0)]))}}),B=e.defineComponent({__name:"FeedPulseProvider",props:{apiKey:{},endpoint:{},debug:{type:Boolean},consentRequired:{type:Boolean,default:!0}},setup(s){const r=s,o=new y.CookieManager,n=new y.FeedPulseTracker({apiKey:r.apiKey,endpoint:r.endpoint,debug:r.debug});e.provide(x,n);function a(t){const i=o.setConsent({analytics:t.analytics,marketing:t.marketing,version:"1.0"});t.analytics||o.clearAnalyticsCookies(),n.updateCookieData(o.getAllData(t.analytics)),n.track("consent","__consent__",{analytics:t.analytics,marketing:t.marketing,action:t.action,userAgent:navigator.userAgent,version:i.version})}return e.onMounted(()=>{const t=o.getConsent();r.consentRequired===!1?(o.setConsent({analytics:!0,marketing:!0,version:"1.0"}),n.updateCookieData(o.getAllData(!0))):t&&!o.isConsentExpired()?n.updateCookieData(o.getAllData(t.analytics)):n.updateCookieData(o.getAllData(!1)),n.init()}),e.onBeforeUnmount(()=>n.destroy()),(t,i)=>(e.openBlock(),e.createElementBlock(e.Fragment,null,[e.renderSlot(t.$slots,"default"),s.consentRequired!==!1?(e.openBlock(),e.createBlock(b,{key:0,onConsent:a})):e.createCommentVNode("",!0)],64))}}),_={key:1,style:{background:"#fff",border:"1px solid #e5e7eb","border-radius":"12px",padding:"16px",width:"280px","box-shadow":"0 10px 25px rgba(0,0,0,0.15)"}},A={style:{margin:"0 0 12px","font-weight":"600",color:"#111"}},z={style:{display:"flex",gap:"6px","margin-bottom":"12px"}},D=["onClick"],P={key:1,style:{"text-align":"center",padding:"16px",color:"#111"}},F=e.defineComponent({__name:"FeedPulseWidget",props:{id:{},placeholder:{},position:{default:"bottom-right"}},setup(s){const r=s,o=v(),n=e.ref(r.position==="inline"),a=e.ref(null),t=e.ref(""),i=e.ref(!1);function c(m){a.value=m}function f(){!a.value&&!t.value.trim()||(o?.trackFeedback(r.id??null,a.value,t.value||null),i.value=!0,setTimeout(()=>{n.value=r.position==="inline",i.value=!1,a.value=null,t.value=""},2e3))}return(m,d)=>(e.openBlock(),e.createElementBlock("div",{class:"feedpulse-widget",style:e.normalizeStyle(s.position!=="inline"?`position:fixed; ${s.position==="bottom-right"?"right:24px":"left:24px"}; bottom:24px; z-index:9999;`:"")},[s.position!=="inline"?(e.openBlock(),e.createElementBlock("button",{key:0,style:{background:"#6366f1",color:"#fff",border:"none","border-radius":"50%",width:"48px",height:"48px","font-size":"20px",cursor:"pointer"},onClick:d[0]||(d[0]=u=>n.value=!n.value)}," 💬 ")):e.createCommentVNode("",!0),n.value?(e.openBlock(),e.createElementBlock("div",_,[i.value?(e.openBlock(),e.createElementBlock("div",P,[...d[2]||(d[2]=[e.createElementVNode("p",{style:{"font-size":"28px",margin:"0"}}," 🎉 ",-1),e.createElementVNode("p",{style:{margin:"8px 0 0","font-weight":"600"}}," Thanks for your feedback! ",-1)])])):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createElementVNode("p",A,e.toDisplayString(s.placeholder??"How was your experience?"),1),e.createElementVNode("div",z,[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(5,u=>e.createElementVNode("button",{key:u,style:e.normalizeStyle({background:"none",border:"none",cursor:"pointer",fontSize:"24px",opacity:a.value!==null&&u<=a.value?1:.3}),onClick:k=>c(u)}," ⭐ ",12,D)),64))]),e.withDirectives(e.createElementVNode("textarea",{"onUpdate:modelValue":d[1]||(d[1]=u=>t.value=u),placeholder:"Tell us more (optional)...",rows:"3",style:{width:"100%",padding:"8px",border:"1px solid #d1d5db","border-radius":"8px",resize:"none","font-size":"14px"}},null,512),[[e.vModelText,t.value]]),e.createElementVNode("button",{style:{"margin-top":"10px",width:"100%",background:"#6366f1",color:"#fff",border:"none","border-radius":"8px",padding:"10px","font-weight":"600",cursor:"pointer"},onClick:f}," Submit Feedback ")],64))])):e.createCommentVNode("",!0)],4))}});exports.ConsentBanner=b;exports.FeedPulseProvider=B;exports.FeedPulseWidget=F;exports.useFeedPulse=v;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),y=require("./index.js"),k=Symbol("feedpulse");function v(){return e.inject(k,null)}const w={key:0,style:{position:"fixed",bottom:"0",left:"0",right:"0","z-index":"99999",background:"#1a1a1a",color:"#fff",padding:"20px 24px","border-top":"1px solid #333","font-family":"sans-serif"}},C={style:{"max-width":"900px",margin:"0 auto"}},E={key:0,style:{"margin-bottom":"12px","font-size":"13px"}},h={style:{display:"flex","align-items":"center",gap:"8px","margin-bottom":"6px"}},V={style:{display:"flex","align-items":"center",gap:"8px"}},N={style:{display:"flex",gap:"8px","flex-wrap":"wrap","align-items":"center"}},b=e.defineComponent({__name:"consent-banner",emits:["consent"],setup(r,{emit:s}){const o=s,n=new y.CookieManager,a=e.ref(!1),t=e.ref(!1),l=e.ref(!1),d=e.ref(!1);function f(){a.value=!0,t.value=!0}e.onMounted(()=>{const p=n.getConsent();a.value=!p||n.isConsentExpired(),p&&(l.value=p.analytics,d.value=p.marketing),typeof window<"u"&&(window.addEventListener("feedpulse:open-consent",f),window.addEventListener("feedpulse:withdraw-consent",x))});function m(){n.setConsent({analytics:!0,marketing:!0,version:"1.0"}),o("consent",{analytics:!0,marketing:!0,action:"accept_all"}),a.value=!1}function c(){n.setConsent({analytics:!1,marketing:!1,version:"1.0"}),n.clearAnalyticsCookies(),o("consent",{analytics:!1,marketing:!1,action:"reject_all"}),a.value=!1}function u(){n.setConsent({analytics:l.value,marketing:d.value,version:"1.0"}),l.value||n.clearAnalyticsCookies(),o("consent",{analytics:l.value,marketing:d.value,action:"custom"}),a.value=!1}function x(){n.setConsent({analytics:!1,marketing:!1,version:"1.0"}),n.clearAnalyticsCookies(),l.value=!1,d.value=!1,o("consent",{analytics:!1,marketing:!1,action:"withdraw"}),a.value=!0}return e.onBeforeUnmount(()=>{typeof window<"u"&&(window.removeEventListener("feedpulse:open-consent",f),window.removeEventListener("feedpulse:withdraw-consent",x))}),(p,i)=>(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[a.value?(e.openBlock(),e.createElementBlock("div",w,[e.createElementVNode("div",C,[i[6]||(i[6]=e.createElementVNode("p",{style:{margin:"0 0 12px","font-size":"14px","line-height":"1.5"}},[e.createTextVNode(" We use cookies to improve reliability and understand usage. "),e.createElementVNode("a",{href:"/privacy",style:{color:"#818cf8"}},"Privacy Policy")],-1)),t.value?(e.openBlock(),e.createElementBlock("div",E,[i[5]||(i[5]=e.createElementVNode("label",{style:{display:"flex","align-items":"center",gap:"8px","margin-bottom":"6px",opacity:"0.75"}},[e.createElementVNode("input",{type:"checkbox",checked:"",disabled:""}),e.createTextVNode(" Necessary (always on) ")],-1)),e.createElementVNode("label",h,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":i[0]||(i[0]=g=>l.value=g),type:"checkbox"},null,512),[[e.vModelCheckbox,l.value]]),i[3]||(i[3]=e.createTextVNode(" Analytics ",-1))]),e.createElementVNode("label",V,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":i[1]||(i[1]=g=>d.value=g),type:"checkbox"},null,512),[[e.vModelCheckbox,d.value]]),i[4]||(i[4]=e.createTextVNode(" Marketing ",-1))])])):e.createCommentVNode("",!0),e.createElementVNode("div",N,[e.createElementVNode("button",{style:{width:"130px",padding:"9px 12px",background:"#4f46e5",color:"#fff",border:"1px solid #4f46e5","border-radius":"6px","font-size":"13px","font-weight":"600",cursor:"pointer"},onClick:m}," Accept All "),e.createElementVNode("button",{style:{width:"130px",padding:"9px 12px",background:"transparent",color:"#fff",border:"1px solid #555","border-radius":"6px","font-size":"13px","font-weight":"600",cursor:"pointer"},onClick:c}," Reject All "),e.createElementVNode("button",{style:{padding:"9px 16px",background:"transparent",color:"#aaa",border:"1px solid #333","border-radius":"6px","font-size":"13px",cursor:"pointer"},onClick:i[2]||(i[2]=g=>t.value?u():t.value=!0)},e.toDisplayString(t.value?"Save Preferences":"Customize"),1)])])])):e.createCommentVNode("",!0)]))}}),B=e.defineComponent({__name:"FeedPulseProvider",props:{proxyEndpoint:{default:"/api/fp-proxy"},debug:{type:Boolean},consentRequired:{type:Boolean,default:!0}},setup(r){const s=r,o=new y.CookieManager,n=new y.FeedPulseTracker({proxyEndpoint:s.proxyEndpoint,debug:s.debug});e.provide(k,n);function a(t){const l=o.setConsent({analytics:t.analytics,marketing:t.marketing,version:"1.0"});t.analytics||o.clearAnalyticsCookies(),n.updateCookieData(o.getAllData(t.analytics)),n.track("consent","__consent__",{analytics:t.analytics,marketing:t.marketing,action:t.action,userAgent:navigator.userAgent,version:l.version})}return e.onMounted(()=>{const t=o.getConsent();s.consentRequired===!1?(o.setConsent({analytics:!0,marketing:!0,version:"1.0"}),n.updateCookieData(o.getAllData(!0))):t&&!o.isConsentExpired()?n.updateCookieData(o.getAllData(t.analytics)):n.updateCookieData(o.getAllData(!1)),n.init()}),e.onBeforeUnmount(()=>n.destroy()),(t,l)=>(e.openBlock(),e.createElementBlock(e.Fragment,null,[e.renderSlot(t.$slots,"default"),r.consentRequired!==!1?(e.openBlock(),e.createBlock(b,{key:0,onConsent:a})):e.createCommentVNode("",!0)],64))}}),_={key:1,style:{background:"#fff",border:"1px solid #e5e7eb","border-radius":"12px",padding:"16px",width:"280px","box-shadow":"0 10px 25px rgba(0,0,0,0.15)"}},A={style:{margin:"0 0 12px","font-weight":"600",color:"#111"}},z={style:{display:"flex",gap:"6px","margin-bottom":"12px"}},D=["onClick"],P={key:1,style:{"text-align":"center",padding:"16px",color:"#111"}},F=e.defineComponent({__name:"FeedPulseWidget",props:{id:{},placeholder:{},position:{default:"bottom-right"}},setup(r){const s=r,o=v(),n=e.ref(s.position==="inline"),a=e.ref(null),t=e.ref(""),l=e.ref(!1);function d(m){a.value=m}function f(){!a.value&&!t.value.trim()||(o?.trackFeedback(s.id??null,a.value,t.value||null),l.value=!0,setTimeout(()=>{n.value=s.position==="inline",l.value=!1,a.value=null,t.value=""},2e3))}return(m,c)=>(e.openBlock(),e.createElementBlock("div",{class:"feedpulse-widget",style:e.normalizeStyle(r.position!=="inline"?`position:fixed; ${r.position==="bottom-right"?"right:24px":"left:24px"}; bottom:24px; z-index:9999;`:"")},[r.position!=="inline"?(e.openBlock(),e.createElementBlock("button",{key:0,style:{background:"#6366f1",color:"#fff",border:"none","border-radius":"50%",width:"48px",height:"48px","font-size":"20px",cursor:"pointer"},onClick:c[0]||(c[0]=u=>n.value=!n.value)}," 💬 ")):e.createCommentVNode("",!0),n.value?(e.openBlock(),e.createElementBlock("div",_,[l.value?(e.openBlock(),e.createElementBlock("div",P,[...c[2]||(c[2]=[e.createElementVNode("p",{style:{"font-size":"28px",margin:"0"}}," 🎉 ",-1),e.createElementVNode("p",{style:{margin:"8px 0 0","font-weight":"600"}}," Thanks for your feedback! ",-1)])])):(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[e.createElementVNode("p",A,e.toDisplayString(r.placeholder??"How was your experience?"),1),e.createElementVNode("div",z,[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(5,u=>e.createElementVNode("button",{key:u,style:e.normalizeStyle({background:"none",border:"none",cursor:"pointer",fontSize:"24px",opacity:a.value!==null&&u<=a.value?1:.3}),onClick:x=>d(u)}," ⭐ ",12,D)),64))]),e.withDirectives(e.createElementVNode("textarea",{"onUpdate:modelValue":c[1]||(c[1]=u=>t.value=u),placeholder:"Tell us more (optional)...",rows:"3",style:{width:"100%",padding:"8px",border:"1px solid #d1d5db","border-radius":"8px",resize:"none","font-size":"14px"}},null,512),[[e.vModelText,t.value]]),e.createElementVNode("button",{style:{"margin-top":"10px",width:"100%",background:"#6366f1",color:"#fff",border:"none","border-radius":"8px",padding:"10px","font-weight":"600",cursor:"pointer"},onClick:f}," Submit Feedback ")],64))])):e.createCommentVNode("",!0)],4))}});exports.ConsentBanner=b;exports.FeedPulseProvider=B;exports.FeedPulseWidget=F;exports.useFeedPulse=v;
package/dist/nuxt.mjs CHANGED
@@ -1,26 +1,26 @@
1
- import { inject as B, defineComponent as _, ref as g, onMounted as D, onBeforeUnmount as E, createBlock as P, openBlock as l, Teleport as M, createElementBlock as u, createCommentVNode as x, createElementVNode as n, createTextVNode as b, withDirectives as C, vModelCheckbox as A, toDisplayString as $, provide as T, Fragment as h, renderSlot as L, normalizeStyle as z, renderList as V, vModelText as R } from "vue";
1
+ import { inject as B, defineComponent as _, ref as g, onMounted as z, onBeforeUnmount as D, createBlock as P, openBlock as l, Teleport as M, createElementBlock as u, createCommentVNode as y, createElementVNode as n, createTextVNode as b, withDirectives as C, vModelCheckbox as A, toDisplayString as $, provide as T, Fragment as h, renderSlot as L, normalizeStyle as E, renderList as V, vModelText as R } from "vue";
2
2
  import { CookieManager as F, FeedPulseTracker as U } from "./index.mjs";
3
3
  const S = /* @__PURE__ */ Symbol("feedpulse");
4
4
  function j() {
5
5
  return B(S, null);
6
6
  }
7
- const K = {
7
+ const N = {
8
8
  key: 0,
9
9
  style: { position: "fixed", bottom: "0", left: "0", right: "0", "z-index": "99999", background: "#1a1a1a", color: "#fff", padding: "20px 24px", "border-top": "1px solid #333", "font-family": "sans-serif" }
10
- }, N = { style: { "max-width": "900px", margin: "0 auto" } }, q = {
10
+ }, q = { style: { "max-width": "900px", margin: "0 auto" } }, W = {
11
11
  key: 0,
12
12
  style: { "margin-bottom": "12px", "font-size": "13px" }
13
- }, W = { style: { display: "flex", "align-items": "center", gap: "8px", "margin-bottom": "6px" } }, H = { style: { display: "flex", "align-items": "center", gap: "8px" } }, O = { style: { display: "flex", gap: "8px", "flex-wrap": "wrap", "align-items": "center" } }, Y = /* @__PURE__ */ _({
13
+ }, H = { style: { display: "flex", "align-items": "center", gap: "8px", "margin-bottom": "6px" } }, K = { style: { display: "flex", "align-items": "center", gap: "8px" } }, O = { style: { display: "flex", gap: "8px", "flex-wrap": "wrap", "align-items": "center" } }, Y = /* @__PURE__ */ _({
14
14
  __name: "consent-banner",
15
15
  emits: ["consent"],
16
- setup(d, { emit: r }) {
17
- const o = r, t = new F(), i = g(!1), e = g(!1), a = g(!1), p = g(!1);
16
+ setup(r, { emit: d }) {
17
+ const o = d, t = new F(), i = g(!1), e = g(!1), a = g(!1), p = g(!1);
18
18
  function v() {
19
19
  i.value = !0, e.value = !0;
20
20
  }
21
- D(() => {
22
- const y = t.getConsent();
23
- i.value = !y || t.isConsentExpired(), y && (a.value = y.analytics, p.value = y.marketing), typeof window < "u" && (window.addEventListener("feedpulse:open-consent", v), window.addEventListener("feedpulse:withdraw-consent", w));
21
+ z(() => {
22
+ const x = t.getConsent();
23
+ i.value = !x || t.isConsentExpired(), x && (a.value = x.analytics, p.value = x.marketing), typeof window < "u" && (window.addEventListener("feedpulse:open-consent", v), window.addEventListener("feedpulse:withdraw-consent", w));
24
24
  });
25
25
  function m() {
26
26
  t.setConsent({ analytics: !0, marketing: !0, version: "1.0" }), o("consent", { analytics: !0, marketing: !0, action: "accept_all" }), i.value = !1;
@@ -34,11 +34,11 @@ const K = {
34
34
  function w() {
35
35
  t.setConsent({ analytics: !1, marketing: !1, version: "1.0" }), t.clearAnalyticsCookies(), a.value = !1, p.value = !1, o("consent", { analytics: !1, marketing: !1, action: "withdraw" }), i.value = !0;
36
36
  }
37
- return E(() => {
37
+ return D(() => {
38
38
  typeof window < "u" && (window.removeEventListener("feedpulse:open-consent", v), window.removeEventListener("feedpulse:withdraw-consent", w));
39
- }), (y, s) => (l(), P(M, { to: "body" }, [
40
- i.value ? (l(), u("div", K, [
41
- n("div", N, [
39
+ }), (x, s) => (l(), P(M, { to: "body" }, [
40
+ i.value ? (l(), u("div", N, [
41
+ n("div", q, [
42
42
  s[6] || (s[6] = n("p", { style: { margin: "0 0 12px", "font-size": "14px", "line-height": "1.5" } }, [
43
43
  b(" We use cookies to improve reliability and understand usage. "),
44
44
  n("a", {
@@ -46,7 +46,7 @@ const K = {
46
46
  style: { color: "#818cf8" }
47
47
  }, "Privacy Policy")
48
48
  ], -1)),
49
- e.value ? (l(), u("div", q, [
49
+ e.value ? (l(), u("div", W, [
50
50
  s[5] || (s[5] = n("label", { style: { display: "flex", "align-items": "center", gap: "8px", "margin-bottom": "6px", opacity: "0.75" } }, [
51
51
  n("input", {
52
52
  type: "checkbox",
@@ -55,7 +55,7 @@ const K = {
55
55
  }),
56
56
  b(" Necessary (always on) ")
57
57
  ], -1)),
58
- n("label", W, [
58
+ n("label", H, [
59
59
  C(n("input", {
60
60
  "onUpdate:modelValue": s[0] || (s[0] = (k) => a.value = k),
61
61
  type: "checkbox"
@@ -64,7 +64,7 @@ const K = {
64
64
  ]),
65
65
  s[3] || (s[3] = b(" Analytics ", -1))
66
66
  ]),
67
- n("label", H, [
67
+ n("label", K, [
68
68
  C(n("input", {
69
69
  "onUpdate:modelValue": s[1] || (s[1] = (k) => p.value = k),
70
70
  type: "checkbox"
@@ -73,7 +73,7 @@ const K = {
73
73
  ]),
74
74
  s[4] || (s[4] = b(" Marketing ", -1))
75
75
  ])
76
- ])) : x("", !0),
76
+ ])) : y("", !0),
77
77
  n("div", O, [
78
78
  n("button", {
79
79
  style: { width: "130px", padding: "9px 12px", background: "#4f46e5", color: "#fff", border: "1px solid #4f46e5", "border-radius": "6px", "font-size": "13px", "font-weight": "600", cursor: "pointer" },
@@ -89,22 +89,20 @@ const K = {
89
89
  }, $(e.value ? "Save Preferences" : "Customize"), 1)
90
90
  ])
91
91
  ])
92
- ])) : x("", !0)
92
+ ])) : y("", !0)
93
93
  ]));
94
94
  }
95
95
  }), te = /* @__PURE__ */ _({
96
96
  __name: "FeedPulseProvider",
97
97
  props: {
98
- apiKey: {},
99
- endpoint: {},
98
+ proxyEndpoint: { default: "/api/fp-proxy" },
100
99
  debug: { type: Boolean },
101
100
  consentRequired: { type: Boolean, default: !0 }
102
101
  },
103
- setup(d) {
104
- const r = d, o = new F(), t = new U({
105
- apiKey: r.apiKey,
106
- endpoint: r.endpoint,
107
- debug: r.debug
102
+ setup(r) {
103
+ const d = r, o = new F(), t = new U({
104
+ proxyEndpoint: d.proxyEndpoint,
105
+ debug: d.debug
108
106
  });
109
107
  T(S, t);
110
108
  function i(e) {
@@ -121,15 +119,15 @@ const K = {
121
119
  version: a.version
122
120
  });
123
121
  }
124
- return D(() => {
122
+ return z(() => {
125
123
  const e = o.getConsent();
126
- r.consentRequired === !1 ? (o.setConsent({ analytics: !0, marketing: !0, version: "1.0" }), t.updateCookieData(o.getAllData(!0))) : e && !o.isConsentExpired() ? t.updateCookieData(o.getAllData(e.analytics)) : t.updateCookieData(o.getAllData(!1)), t.init();
127
- }), E(() => t.destroy()), (e, a) => (l(), u(h, null, [
124
+ d.consentRequired === !1 ? (o.setConsent({ analytics: !0, marketing: !0, version: "1.0" }), t.updateCookieData(o.getAllData(!0))) : e && !o.isConsentExpired() ? t.updateCookieData(o.getAllData(e.analytics)) : t.updateCookieData(o.getAllData(!1)), t.init();
125
+ }), D(() => t.destroy()), (e, a) => (l(), u(h, null, [
128
126
  L(e.$slots, "default"),
129
- d.consentRequired !== !1 ? (l(), P(Y, {
127
+ r.consentRequired !== !1 ? (l(), P(Y, {
130
128
  key: 0,
131
129
  onConsent: i
132
- })) : x("", !0)
130
+ })) : y("", !0)
133
131
  ], 64));
134
132
  }
135
133
  }), G = {
@@ -145,35 +143,35 @@ const K = {
145
143
  placeholder: {},
146
144
  position: { default: "bottom-right" }
147
145
  },
148
- setup(d) {
149
- const r = d, o = j(), t = g(r.position === "inline"), i = g(null), e = g(""), a = g(!1);
146
+ setup(r) {
147
+ const d = r, o = j(), t = g(d.position === "inline"), i = g(null), e = g(""), a = g(!1);
150
148
  function p(m) {
151
149
  i.value = m;
152
150
  }
153
151
  function v() {
154
- !i.value && !e.value.trim() || (o?.trackFeedback(r.id ?? null, i.value, e.value || null), a.value = !0, setTimeout(() => {
155
- t.value = r.position === "inline", a.value = !1, i.value = null, e.value = "";
152
+ !i.value && !e.value.trim() || (o?.trackFeedback(d.id ?? null, i.value, e.value || null), a.value = !0, setTimeout(() => {
153
+ t.value = d.position === "inline", a.value = !1, i.value = null, e.value = "";
156
154
  }, 2e3));
157
155
  }
158
156
  return (m, c) => (l(), u("div", {
159
157
  class: "feedpulse-widget",
160
- style: z(d.position !== "inline" ? `position:fixed; ${d.position === "bottom-right" ? "right:24px" : "left:24px"}; bottom:24px; z-index:9999;` : "")
158
+ style: E(r.position !== "inline" ? `position:fixed; ${r.position === "bottom-right" ? "right:24px" : "left:24px"}; bottom:24px; z-index:9999;` : "")
161
159
  }, [
162
- d.position !== "inline" ? (l(), u("button", {
160
+ r.position !== "inline" ? (l(), u("button", {
163
161
  key: 0,
164
162
  style: { background: "#6366f1", color: "#fff", border: "none", "border-radius": "50%", width: "48px", height: "48px", "font-size": "20px", cursor: "pointer" },
165
163
  onClick: c[0] || (c[0] = (f) => t.value = !t.value)
166
- }, " 💬 ")) : x("", !0),
164
+ }, " 💬 ")) : y("", !0),
167
165
  t.value ? (l(), u("div", G, [
168
166
  a.value ? (l(), u("div", X, [...c[2] || (c[2] = [
169
167
  n("p", { style: { "font-size": "28px", margin: "0" } }, " 🎉 ", -1),
170
168
  n("p", { style: { margin: "8px 0 0", "font-weight": "600" } }, " Thanks for your feedback! ", -1)
171
169
  ])])) : (l(), u(h, { key: 0 }, [
172
- n("p", I, $(d.placeholder ?? "How was your experience?"), 1),
170
+ n("p", I, $(r.placeholder ?? "How was your experience?"), 1),
173
171
  n("div", J, [
174
172
  (l(), u(h, null, V(5, (f) => n("button", {
175
173
  key: f,
176
- style: z({ background: "none", border: "none", cursor: "pointer", fontSize: "24px", opacity: i.value !== null && f <= i.value ? 1 : 0.3 }),
174
+ style: E({ background: "none", border: "none", cursor: "pointer", fontSize: "24px", opacity: i.value !== null && f <= i.value ? 1 : 0.3 }),
177
175
  onClick: (w) => p(f)
178
176
  }, " ⭐ ", 12, Q)), 64))
179
177
  ]),
@@ -190,7 +188,7 @@ const K = {
190
188
  onClick: v
191
189
  }, " Submit Feedback ")
192
190
  ], 64))
193
- ])) : x("", !0)
191
+ ])) : y("", !0)
194
192
  ], 4));
195
193
  }
196
194
  });
package/dist/react.js CHANGED
@@ -1,6 +1,6 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react"),N=require("./index.js");var j={exports:{}},_={};var Y;function se(){if(Y)return _;Y=1;var d=Symbol.for("react.transitional.element"),y=Symbol.for("react.fragment");function o(g,i,s){var m=null;if(s!==void 0&&(m=""+s),i.key!==void 0&&(m=""+i.key),"key"in i){s={};for(var b in i)b!=="key"&&(s[b]=i[b])}else s=i;return i=s.ref,{$$typeof:d,type:g,key:m,ref:i!==void 0?i:null,props:s}}return _.Fragment=y,_.jsx=o,_.jsxs=o,_}var R={};var $;function ie(){return $||($=1,process.env.NODE_ENV!=="production"&&(function(){function d(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ne?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case S:return"Fragment";case X:return"Profiler";case G:return"StrictMode";case K:return"Suspense";case ee:return"SuspenseList";case re:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case J:return"Portal";case Z:return e.displayName||"Context";case H:return(e._context.displayName||"Context")+".Consumer";case Q:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return t=e.displayName||null,t!==null?t:d(e.type)||"Memo";case T:t=e._payload,e=e._init;try{return d(e(t))}catch{}}return null}function y(e){return""+e}function o(e){try{y(e);var t=!1}catch{t=!0}if(t){t=console;var a=t.error,l=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return a.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",l),y(e)}}function g(e){if(e===S)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===T)return"<...>";try{var t=d(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function i(){var e=A.A;return e===null?null:e.getOwner()}function s(){return Error("react-stack-top-frame")}function m(e){if(F.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function b(e,t){function a(){D||(D=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}a.isReactWarning=!0,Object.defineProperty(e,"key",{get:a,configurable:!0})}function x(){var e=d(this.type);return I[e]||(I[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function h(e,t,a,l,w,C){var c=a.ref;return e={$$typeof:v,type:e,key:t,props:a,_owner:l},(c!==void 0?c:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:x}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:w}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:C}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function n(e,t,a,l,w,C){var c=t.children;if(c!==void 0)if(l)if(ae(c)){for(l=0;l<c.length;l++)f(c[l]);Object.freeze&&Object.freeze(c)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else f(c);if(F.call(t,"key")){c=d(e);var E=Object.keys(t).filter(function(oe){return oe!=="key"});l=0<E.length?"{key: someKey, "+E.join(": ..., ")+": ...}":"{key: someKey}",z[c+l]||(E=0<E.length?"{"+E.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react"),N=require("./index.js");var j={exports:{}},_={};var Y;function se(){if(Y)return _;Y=1;var d=Symbol.for("react.transitional.element"),x=Symbol.for("react.fragment");function n(b,a,i){var m=null;if(i!==void 0&&(m=""+i),a.key!==void 0&&(m=""+a.key),"key"in a){i={};for(var g in a)g!=="key"&&(i[g]=a[g])}else i=a;return a=i.ref,{$$typeof:d,type:b,key:m,ref:a!==void 0?a:null,props:i}}return _.Fragment=x,_.jsx=n,_.jsxs=n,_}var R={};var $;function ie(){return $||($=1,process.env.NODE_ENV!=="production"&&(function(){function d(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ne?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case S:return"Fragment";case X:return"Profiler";case G:return"StrictMode";case K:return"Suspense";case ee:return"SuspenseList";case re:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case J:return"Portal";case Z:return e.displayName||"Context";case H:return(e._context.displayName||"Context")+".Consumer";case Q:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case te:return t=e.displayName||null,t!==null?t:d(e.type)||"Memo";case T:t=e._payload,e=e._init;try{return d(e(t))}catch{}}return null}function x(e){return""+e}function n(e){try{x(e);var t=!1}catch{t=!0}if(t){t=console;var s=t.error,l=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return s.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",l),x(e)}}function b(e){if(e===S)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===T)return"<...>";try{var t=d(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function a(){var e=A.A;return e===null?null:e.getOwner()}function i(){return Error("react-stack-top-frame")}function m(e){if(F.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function g(e,t){function s(){D||(D=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}s.isReactWarning=!0,Object.defineProperty(e,"key",{get:s,configurable:!0})}function y(){var e=d(this.type);return I[e]||(I[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function o(e,t,s,l,w,C){var c=s.ref;return e={$$typeof:v,type:e,key:t,props:s,_owner:l},(c!==void 0?c:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:y}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:w}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:C}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function p(e,t,s,l,w,C){var c=t.children;if(c!==void 0)if(l)if(ae(c)){for(l=0;l<c.length;l++)k(c[l]);Object.freeze&&Object.freeze(c)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else k(c);if(F.call(t,"key")){c=d(e);var E=Object.keys(t).filter(function(oe){return oe!=="key"});l=0<E.length?"{key: someKey, "+E.join(": ..., ")+": ...}":"{key: someKey}",z[c+l]||(E=0<E.length?"{"+E.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
2
  let props = %s;
3
3
  <%s {...props} />
4
4
  React keys must be passed directly to JSX without using spread:
5
5
  let props = %s;
6
- <%s key={someKey} {...props} />`,l,c,E,c),z[c+l]=!0)}if(c=null,a!==void 0&&(o(a),c=""+a),m(t)&&(o(t.key),c=""+t.key),"key"in t){a={};for(var O in t)O!=="key"&&(a[O]=t[O])}else a=t;return c&&b(a,typeof e=="function"?e.displayName||e.name||"Unknown":e),h(e,c,a,i(),w,C)}function f(e){k(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===T&&(e._payload.status==="fulfilled"?k(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function k(e){return typeof e=="object"&&e!==null&&e.$$typeof===v}var p=u,v=Symbol.for("react.transitional.element"),J=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),G=Symbol.for("react.strict_mode"),X=Symbol.for("react.profiler"),H=Symbol.for("react.consumer"),Z=Symbol.for("react.context"),Q=Symbol.for("react.forward_ref"),K=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),T=Symbol.for("react.lazy"),re=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),A=p.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,F=Object.prototype.hasOwnProperty,ae=Array.isArray,P=console.createTask?console.createTask:function(){return null};p={react_stack_bottom_frame:function(e){return e()}};var D,I={},M=p.react_stack_bottom_frame.bind(p,s)(),W=P(g(s)),z={};R.Fragment=S,R.jsx=function(e,t,a){var l=1e4>A.recentlyCreatedOwnerStacks++;return n(e,t,a,!1,l?Error("react-stack-top-frame"):M,l?P(g(e)):W)},R.jsxs=function(e,t,a){var l=1e4>A.recentlyCreatedOwnerStacks++;return n(e,t,a,!0,l?Error("react-stack-top-frame"):M,l?P(g(e)):W)}})()),R}var L;function le(){return L||(L=1,process.env.NODE_ENV==="production"?j.exports=se():j.exports=ie()),j.exports}var r=le();const U=new N.CookieManager;function V({onConsent:d}){const[y,o]=u.useState(!1),[g,i]=u.useState(!1),[s,m]=u.useState(!1),[b,x]=u.useState(!1);u.useEffect(()=>{const p=U.getConsent();o(!p||U.isConsentExpired()),p&&(m(p.analytics),x(p.marketing))},[]);const h=()=>{d({analytics:!0,marketing:!0,action:"accept_all"}),o(!1)},n=()=>{d({analytics:!1,marketing:!1,action:"reject_all"}),o(!1)},f=()=>{d({analytics:s,marketing:b,action:"custom"}),o(!1)},k=u.useCallback(()=>{d({analytics:!1,marketing:!1,action:"withdraw"}),m(!1),x(!1),o(!0)},[d]);return u.useEffect(()=>{const p=()=>{o(!0),i(!0)};return window.addEventListener("feedpulse:open-consent",p),window.addEventListener("feedpulse:withdraw-consent",k),()=>{window.removeEventListener("feedpulse:open-consent",p),window.removeEventListener("feedpulse:withdraw-consent",k)}},[k]),y?r.jsx("div",{style:{position:"fixed",bottom:0,left:0,right:0,zIndex:99999,background:"#1a1a1a",color:"#fff",padding:"20px 24px",borderTop:"1px solid #333",fontFamily:"sans-serif"},children:r.jsxs("div",{style:{maxWidth:900,margin:"0 auto"},children:[r.jsxs("p",{style:{margin:"0 0 12px",fontSize:14,lineHeight:1.5},children:["We use cookies to improve reliability and understand usage."," ",r.jsx("a",{href:"/privacy",style:{color:"#818cf8"},children:"Privacy Policy"})]}),g&&r.jsxs("div",{style:{marginBottom:12,fontSize:13},children:[r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:6,opacity:.75},children:[r.jsx("input",{type:"checkbox",checked:!0,disabled:!0}),"Necessary (always on)"]}),r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:6},children:[r.jsx("input",{type:"checkbox",checked:s,onChange:p=>m(p.target.checked)}),"Analytics"]}),r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8},children:[r.jsx("input",{type:"checkbox",checked:b,onChange:p=>x(p.target.checked)}),"Marketing"]})]}),r.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"center"},children:[r.jsx("button",{type:"button",style:{width:130,padding:"9px 12px",background:"#4f46e5",color:"#fff",border:"1px solid #4f46e5",borderRadius:6,fontSize:13,fontWeight:600,cursor:"pointer"},onClick:h,children:"Accept All"}),r.jsx("button",{type:"button",style:{width:130,padding:"9px 12px",background:"transparent",color:"#fff",border:"1px solid #555",borderRadius:6,fontSize:13,fontWeight:600,cursor:"pointer"},onClick:n,children:"Reject All"}),r.jsx("button",{type:"button",style:{padding:"9px 16px",background:"transparent",color:"#aaa",border:"1px solid #333",borderRadius:6,fontSize:13,cursor:"pointer"},onClick:()=>g?f():i(!0),children:g?"Save Preferences":"Customize"})]})]})}):null}const q=u.createContext({tracker:null});function ce({apiKey:d,endpoint:y,debug:o,consentRequired:g=!0,children:i}){const s=u.useRef(null),m=u.useRef(new N.CookieManager),[b,x]=u.useState(null),h=u.useCallback(n=>{const f=m.current,k=f.setConsent({analytics:n.analytics,marketing:n.marketing,version:"1.0"});n.analytics||f.clearAnalyticsCookies(),s.current?.updateCookieData(f.getAllData(n.analytics)),s.current?.track("consent","__consent__",{analytics:n.analytics,marketing:n.marketing,action:n.action,userAgent:navigator.userAgent,version:k.version})},[]);return u.useEffect(()=>{const n=new N.FeedPulseTracker({apiKey:d,endpoint:y,debug:o});s.current=n,x(n);const f=m.current,k=f.getConsent();return g?k&&!f.isConsentExpired()?n.updateCookieData(f.getAllData(k.analytics)):n.updateCookieData(f.getAllData(!1)):(f.setConsent({analytics:!0,marketing:!0,version:"1.0"}),n.updateCookieData(f.getAllData(!0))),n.init(),()=>{n.destroy(),s.current=null,x(null)}},[d,y,o,g]),r.jsxs(q.Provider,{value:{tracker:b},children:[i,g&&r.jsx(V,{onConsent:h})]})}function B(){return u.useContext(q)}function ue({id:d,placeholder:y,position:o="bottom-right"}){const{tracker:g}=B(),[i,s]=u.useState(o==="inline"),[m,b]=u.useState(null),[x,h]=u.useState(""),[n,f]=u.useState(!1),k=()=>{!m&&!x.trim()||(g?.trackFeedback(d??null,m,x||null),f(!0),setTimeout(()=>{s(o==="inline"),f(!1),b(null),h("")},2e3))},p=o!=="inline"?{position:"fixed",bottom:24,[o==="bottom-right"?"right":"left"]:24,zIndex:9999}:{};return r.jsxs("div",{style:p,children:[o!=="inline"&&r.jsx("button",{onClick:()=>s(!i),style:{background:"#6366f1",color:"#fff",border:"none",borderRadius:"50%",width:48,height:48,fontSize:20,cursor:"pointer"},children:"💬"}),i&&r.jsx("div",{style:{background:"#fff",border:"1px solid #e5e7eb",borderRadius:12,padding:16,width:280,boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:n?r.jsxs("div",{style:{textAlign:"center",padding:16},children:[r.jsx("p",{style:{fontSize:28,margin:0},children:"🎉"}),r.jsx("p",{style:{margin:"8px 0 0",fontWeight:600},children:"Thanks for your feedback!"})]}):r.jsxs(r.Fragment,{children:[r.jsx("p",{style:{margin:"0 0 12px",fontWeight:600},children:y??"How was your experience?"}),r.jsx("div",{style:{display:"flex",gap:6,marginBottom:12},children:[1,2,3,4,5].map(v=>r.jsx("button",{onClick:()=>b(v),style:{background:"none",border:"none",cursor:"pointer",fontSize:24,opacity:m!==null&&v<=m?1:.3},children:"⭐"},v))}),r.jsx("textarea",{value:x,onChange:v=>h(v.target.value),placeholder:"Tell us more (optional)...",rows:3,style:{width:"100%",padding:8,border:"1px solid #d1d5db",borderRadius:8,resize:"none",fontSize:14}}),r.jsx("button",{onClick:k,style:{marginTop:10,width:"100%",background:"#6366f1",color:"#fff",border:"none",borderRadius:8,padding:10,fontWeight:600,cursor:"pointer"},children:"Submit Feedback"})]})})]})}exports.ConsentBanner=V;exports.FeedPulseProvider=ce;exports.FeedPulseWidget=ue;exports.useFeedPulse=B;
6
+ <%s key={someKey} {...props} />`,l,c,E,c),z[c+l]=!0)}if(c=null,s!==void 0&&(n(s),c=""+s),m(t)&&(n(t.key),c=""+t.key),"key"in t){s={};for(var O in t)O!=="key"&&(s[O]=t[O])}else s=t;return c&&g(s,typeof e=="function"?e.displayName||e.name||"Unknown":e),o(e,c,s,a(),w,C)}function k(e){h(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===T&&(e._payload.status==="fulfilled"?h(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function h(e){return typeof e=="object"&&e!==null&&e.$$typeof===v}var f=u,v=Symbol.for("react.transitional.element"),J=Symbol.for("react.portal"),S=Symbol.for("react.fragment"),G=Symbol.for("react.strict_mode"),X=Symbol.for("react.profiler"),H=Symbol.for("react.consumer"),Z=Symbol.for("react.context"),Q=Symbol.for("react.forward_ref"),K=Symbol.for("react.suspense"),ee=Symbol.for("react.suspense_list"),te=Symbol.for("react.memo"),T=Symbol.for("react.lazy"),re=Symbol.for("react.activity"),ne=Symbol.for("react.client.reference"),A=f.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,F=Object.prototype.hasOwnProperty,ae=Array.isArray,P=console.createTask?console.createTask:function(){return null};f={react_stack_bottom_frame:function(e){return e()}};var D,I={},M=f.react_stack_bottom_frame.bind(f,i)(),W=P(b(i)),z={};R.Fragment=S,R.jsx=function(e,t,s){var l=1e4>A.recentlyCreatedOwnerStacks++;return p(e,t,s,!1,l?Error("react-stack-top-frame"):M,l?P(b(e)):W)},R.jsxs=function(e,t,s){var l=1e4>A.recentlyCreatedOwnerStacks++;return p(e,t,s,!0,l?Error("react-stack-top-frame"):M,l?P(b(e)):W)}})()),R}var L;function le(){return L||(L=1,process.env.NODE_ENV==="production"?j.exports=se():j.exports=ie()),j.exports}var r=le();const U=new N.CookieManager;function V({onConsent:d}){const[x,n]=u.useState(!1),[b,a]=u.useState(!1),[i,m]=u.useState(!1),[g,y]=u.useState(!1);u.useEffect(()=>{const f=U.getConsent();n(!f||U.isConsentExpired()),f&&(m(f.analytics),y(f.marketing))},[]);const o=()=>{d({analytics:!0,marketing:!0,action:"accept_all"}),n(!1)},p=()=>{d({analytics:!1,marketing:!1,action:"reject_all"}),n(!1)},k=()=>{d({analytics:i,marketing:g,action:"custom"}),n(!1)},h=u.useCallback(()=>{d({analytics:!1,marketing:!1,action:"withdraw"}),m(!1),y(!1),n(!0)},[d]);return u.useEffect(()=>{const f=()=>{n(!0),a(!0)};return window.addEventListener("feedpulse:open-consent",f),window.addEventListener("feedpulse:withdraw-consent",h),()=>{window.removeEventListener("feedpulse:open-consent",f),window.removeEventListener("feedpulse:withdraw-consent",h)}},[h]),x?r.jsx("div",{style:{position:"fixed",bottom:0,left:0,right:0,zIndex:99999,background:"#1a1a1a",color:"#fff",padding:"20px 24px",borderTop:"1px solid #333",fontFamily:"sans-serif"},children:r.jsxs("div",{style:{maxWidth:900,margin:"0 auto"},children:[r.jsxs("p",{style:{margin:"0 0 12px",fontSize:14,lineHeight:1.5},children:["We use cookies to improve reliability and understand usage."," ",r.jsx("a",{href:"/privacy",style:{color:"#818cf8"},children:"Privacy Policy"})]}),b&&r.jsxs("div",{style:{marginBottom:12,fontSize:13},children:[r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:6,opacity:.75},children:[r.jsx("input",{type:"checkbox",checked:!0,disabled:!0}),"Necessary (always on)"]}),r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:6},children:[r.jsx("input",{type:"checkbox",checked:i,onChange:f=>m(f.target.checked)}),"Analytics"]}),r.jsxs("label",{style:{display:"flex",alignItems:"center",gap:8},children:[r.jsx("input",{type:"checkbox",checked:g,onChange:f=>y(f.target.checked)}),"Marketing"]})]}),r.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"center"},children:[r.jsx("button",{type:"button",style:{width:130,padding:"9px 12px",background:"#4f46e5",color:"#fff",border:"1px solid #4f46e5",borderRadius:6,fontSize:13,fontWeight:600,cursor:"pointer"},onClick:o,children:"Accept All"}),r.jsx("button",{type:"button",style:{width:130,padding:"9px 12px",background:"transparent",color:"#fff",border:"1px solid #555",borderRadius:6,fontSize:13,fontWeight:600,cursor:"pointer"},onClick:p,children:"Reject All"}),r.jsx("button",{type:"button",style:{padding:"9px 16px",background:"transparent",color:"#aaa",border:"1px solid #333",borderRadius:6,fontSize:13,cursor:"pointer"},onClick:()=>b?k():a(!0),children:b?"Save Preferences":"Customize"})]})]})}):null}const q=u.createContext({tracker:null});function ce({proxyEndpoint:d="/api/fp-proxy",debug:x,consentRequired:n=!0,children:b}){const a=u.useRef(null),i=u.useRef(new N.CookieManager),[m,g]=u.useState(null),y=u.useCallback(o=>{const p=i.current,k=p.setConsent({analytics:o.analytics,marketing:o.marketing,version:"1.0"});o.analytics||p.clearAnalyticsCookies(),a.current?.updateCookieData(p.getAllData(o.analytics)),a.current?.track("consent","__consent__",{analytics:o.analytics,marketing:o.marketing,action:o.action,userAgent:navigator.userAgent,version:k.version})},[]);return u.useEffect(()=>{const o=new N.FeedPulseTracker({proxyEndpoint:d,debug:x});a.current=o,g(o);const p=i.current,k=p.getConsent();return n?k&&!p.isConsentExpired()?o.updateCookieData(p.getAllData(k.analytics)):o.updateCookieData(p.getAllData(!1)):(p.setConsent({analytics:!0,marketing:!0,version:"1.0"}),o.updateCookieData(p.getAllData(!0))),o.init(),()=>{o.destroy(),a.current=null,g(null)}},[d,x,n]),r.jsxs(q.Provider,{value:{tracker:m},children:[b,n&&r.jsx(V,{onConsent:y})]})}function B(){return u.useContext(q)}function ue({id:d,placeholder:x,position:n="bottom-right"}){const{tracker:b}=B(),[a,i]=u.useState(n==="inline"),[m,g]=u.useState(null),[y,o]=u.useState(""),[p,k]=u.useState(!1),h=()=>{!m&&!y.trim()||(b?.trackFeedback(d??null,m,y||null),k(!0),setTimeout(()=>{i(n==="inline"),k(!1),g(null),o("")},2e3))},f=n!=="inline"?{position:"fixed",bottom:24,[n==="bottom-right"?"right":"left"]:24,zIndex:9999}:{};return r.jsxs("div",{style:f,children:[n!=="inline"&&r.jsx("button",{onClick:()=>i(!a),style:{background:"#6366f1",color:"#fff",border:"none",borderRadius:"50%",width:48,height:48,fontSize:20,cursor:"pointer"},children:"💬"}),a&&r.jsx("div",{style:{background:"#fff",border:"1px solid #e5e7eb",borderRadius:12,padding:16,width:280,boxShadow:"0 10px 25px rgba(0,0,0,0.15)"},children:p?r.jsxs("div",{style:{textAlign:"center",padding:16},children:[r.jsx("p",{style:{fontSize:28,margin:0},children:"🎉"}),r.jsx("p",{style:{margin:"8px 0 0",fontWeight:600},children:"Thanks for your feedback!"})]}):r.jsxs(r.Fragment,{children:[r.jsx("p",{style:{margin:"0 0 12px",fontWeight:600},children:x??"How was your experience?"}),r.jsx("div",{style:{display:"flex",gap:6,marginBottom:12},children:[1,2,3,4,5].map(v=>r.jsx("button",{onClick:()=>g(v),style:{background:"none",border:"none",cursor:"pointer",fontSize:24,opacity:m!==null&&v<=m?1:.3},children:"⭐"},v))}),r.jsx("textarea",{value:y,onChange:v=>o(v.target.value),placeholder:"Tell us more (optional)...",rows:3,style:{width:"100%",padding:8,border:"1px solid #d1d5db",borderRadius:8,resize:"none",fontSize:14}}),r.jsx("button",{onClick:h,style:{marginTop:10,width:"100%",background:"#6366f1",color:"#fff",border:"none",borderRadius:8,padding:10,fontWeight:600,cursor:"pointer"},children:"Submit Feedback"})]})})]})}exports.ConsentBanner=V;exports.FeedPulseProvider=ce;exports.FeedPulseWidget=ue;exports.useFeedPulse=B;
package/dist/react.mjs CHANGED
@@ -1,27 +1,27 @@
1
- import ie, { useState as h, useEffect as N, useCallback as J, createContext as le, useRef as M, useContext as ce } from "react";
1
+ import ie, { useState as y, useEffect as N, useCallback as J, createContext as le, useRef as M, useContext as ce } from "react";
2
2
  import { CookieManager as B, FeedPulseTracker as ue } from "./index.mjs";
3
- var j = { exports: {} }, _ = {};
3
+ var j = { exports: {} }, E = {};
4
4
  var $;
5
5
  function de() {
6
- if ($) return _;
6
+ if ($) return E;
7
7
  $ = 1;
8
- var u = /* @__PURE__ */ Symbol.for("react.transitional.element"), k = /* @__PURE__ */ Symbol.for("react.fragment");
9
- function a(m, i, s) {
8
+ var u = /* @__PURE__ */ Symbol.for("react.transitional.element"), x = /* @__PURE__ */ Symbol.for("react.fragment");
9
+ function n(g, a, i) {
10
10
  var p = null;
11
- if (s !== void 0 && (p = "" + s), i.key !== void 0 && (p = "" + i.key), "key" in i) {
12
- s = {};
13
- for (var g in i)
14
- g !== "key" && (s[g] = i[g]);
15
- } else s = i;
16
- return i = s.ref, {
11
+ if (i !== void 0 && (p = "" + i), a.key !== void 0 && (p = "" + a.key), "key" in a) {
12
+ i = {};
13
+ for (var m in a)
14
+ m !== "key" && (i[m] = a[m]);
15
+ } else i = a;
16
+ return a = i.ref, {
17
17
  $$typeof: u,
18
- type: m,
18
+ type: g,
19
19
  key: p,
20
- ref: i !== void 0 ? i : null,
21
- props: s
20
+ ref: a !== void 0 ? a : null,
21
+ props: i
22
22
  };
23
23
  }
24
- return _.Fragment = k, _.jsx = a, _.jsxs = a, _;
24
+ return E.Fragment = x, E.jsx = n, E.jsxs = n, E;
25
25
  }
26
26
  var R = {};
27
27
  var L;
@@ -30,7 +30,7 @@ function fe() {
30
30
  function u(e) {
31
31
  if (e == null) return null;
32
32
  if (typeof e == "function")
33
- return e.$$typeof === oe ? null : e.displayName || e.name || null;
33
+ return e.$$typeof === ae ? null : e.displayName || e.name || null;
34
34
  if (typeof e == "string") return e;
35
35
  switch (e) {
36
36
  case T:
@@ -70,27 +70,27 @@ function fe() {
70
70
  }
71
71
  return null;
72
72
  }
73
- function k(e) {
73
+ function x(e) {
74
74
  return "" + e;
75
75
  }
76
- function a(e) {
76
+ function n(e) {
77
77
  try {
78
- k(e);
78
+ x(e);
79
79
  var r = !1;
80
80
  } catch {
81
81
  r = !0;
82
82
  }
83
83
  if (r) {
84
84
  r = console;
85
- var o = r.error, l = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
86
- return o.call(
85
+ var s = r.error, l = typeof Symbol == "function" && Symbol.toStringTag && e[Symbol.toStringTag] || e.constructor.name || "Object";
86
+ return s.call(
87
87
  r,
88
88
  "The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",
89
89
  l
90
- ), k(e);
90
+ ), x(e);
91
91
  }
92
92
  }
93
- function m(e) {
93
+ function g(e) {
94
94
  if (e === T) return "<>";
95
95
  if (typeof e == "object" && e !== null && e.$$typeof === S)
96
96
  return "<...>";
@@ -101,11 +101,11 @@ function fe() {
101
101
  return "<...>";
102
102
  }
103
103
  }
104
- function i() {
104
+ function a() {
105
105
  var e = A.A;
106
106
  return e === null ? null : e.getOwner();
107
107
  }
108
- function s() {
108
+ function i() {
109
109
  return Error("react-stack-top-frame");
110
110
  }
111
111
  function p(e) {
@@ -115,35 +115,35 @@ function fe() {
115
115
  }
116
116
  return e.key !== void 0;
117
117
  }
118
- function g(e, r) {
119
- function o() {
118
+ function m(e, r) {
119
+ function s() {
120
120
  F || (F = !0, console.error(
121
121
  "%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",
122
122
  r
123
123
  ));
124
124
  }
125
- o.isReactWarning = !0, Object.defineProperty(e, "key", {
126
- get: o,
125
+ s.isReactWarning = !0, Object.defineProperty(e, "key", {
126
+ get: s,
127
127
  configurable: !0
128
128
  });
129
129
  }
130
- function x() {
130
+ function k() {
131
131
  var e = u(this.type);
132
132
  return I[e] || (I[e] = !0, console.error(
133
133
  "Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release."
134
134
  )), e = this.props.ref, e !== void 0 ? e : null;
135
135
  }
136
- function y(e, r, o, l, w, P) {
137
- var c = o.ref;
136
+ function o(e, r, s, l, w, P) {
137
+ var c = s.ref;
138
138
  return e = {
139
139
  $$typeof: v,
140
140
  type: e,
141
141
  key: r,
142
- props: o,
142
+ props: s,
143
143
  _owner: l
144
144
  }, (c !== void 0 ? c : null) !== null ? Object.defineProperty(e, "ref", {
145
145
  enumerable: !1,
146
- get: x
146
+ get: k
147
147
  }) : Object.defineProperty(e, "ref", { enumerable: !1, value: null }), e._store = {}, Object.defineProperty(e._store, "validated", {
148
148
  configurable: !1,
149
149
  enumerable: !1,
@@ -166,25 +166,25 @@ function fe() {
166
166
  value: P
167
167
  }), Object.freeze && (Object.freeze(e.props), Object.freeze(e)), e;
168
168
  }
169
- function n(e, r, o, l, w, P) {
169
+ function f(e, r, s, l, w, P) {
170
170
  var c = r.children;
171
171
  if (c !== void 0)
172
172
  if (l)
173
- if (ae(c)) {
173
+ if (oe(c)) {
174
174
  for (l = 0; l < c.length; l++)
175
- d(c[l]);
175
+ b(c[l]);
176
176
  Object.freeze && Object.freeze(c);
177
177
  } else
178
178
  console.error(
179
179
  "React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead."
180
180
  );
181
- else d(c);
181
+ else b(c);
182
182
  if (D.call(r, "key")) {
183
183
  c = u(e);
184
- var E = Object.keys(r).filter(function(se) {
184
+ var _ = Object.keys(r).filter(function(se) {
185
185
  return se !== "key";
186
186
  });
187
- l = 0 < E.length ? "{key: someKey, " + E.join(": ..., ") + ": ...}" : "{key: someKey}", Y[c + l] || (E = 0 < E.length ? "{" + E.join(": ..., ") + ": ...}" : "{}", console.error(
187
+ l = 0 < _.length ? "{key: someKey, " + _.join(": ..., ") + ": ...}" : "{key: someKey}", Y[c + l] || (_ = 0 < _.length ? "{" + _.join(": ..., ") + ": ...}" : "{}", console.error(
188
188
  `A props object containing a "key" prop is being spread into JSX:
189
189
  let props = %s;
190
190
  <%s {...props} />
@@ -193,64 +193,64 @@ React keys must be passed directly to JSX without using spread:
193
193
  <%s key={someKey} {...props} />`,
194
194
  l,
195
195
  c,
196
- E,
196
+ _,
197
197
  c
198
198
  ), Y[c + l] = !0);
199
199
  }
200
- if (c = null, o !== void 0 && (a(o), c = "" + o), p(r) && (a(r.key), c = "" + r.key), "key" in r) {
201
- o = {};
200
+ if (c = null, s !== void 0 && (n(s), c = "" + s), p(r) && (n(r.key), c = "" + r.key), "key" in r) {
201
+ s = {};
202
202
  for (var O in r)
203
- O !== "key" && (o[O] = r[O]);
204
- } else o = r;
205
- return c && g(
206
- o,
203
+ O !== "key" && (s[O] = r[O]);
204
+ } else s = r;
205
+ return c && m(
206
+ s,
207
207
  typeof e == "function" ? e.displayName || e.name || "Unknown" : e
208
- ), y(
208
+ ), o(
209
209
  e,
210
210
  c,
211
- o,
212
- i(),
211
+ s,
212
+ a(),
213
213
  w,
214
214
  P
215
215
  );
216
216
  }
217
- function d(e) {
218
- b(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === S && (e._payload.status === "fulfilled" ? b(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
219
- }
220
217
  function b(e) {
218
+ h(e) ? e._store && (e._store.validated = 1) : typeof e == "object" && e !== null && e.$$typeof === S && (e._payload.status === "fulfilled" ? h(e._payload.value) && e._payload.value._store && (e._payload.value._store.validated = 1) : e._store && (e._store.validated = 1));
219
+ }
220
+ function h(e) {
221
221
  return typeof e == "object" && e !== null && e.$$typeof === v;
222
222
  }
223
- var f = ie, v = /* @__PURE__ */ Symbol.for("react.transitional.element"), G = /* @__PURE__ */ Symbol.for("react.portal"), T = /* @__PURE__ */ Symbol.for("react.fragment"), X = /* @__PURE__ */ Symbol.for("react.strict_mode"), H = /* @__PURE__ */ Symbol.for("react.profiler"), Z = /* @__PURE__ */ Symbol.for("react.consumer"), Q = /* @__PURE__ */ Symbol.for("react.context"), K = /* @__PURE__ */ Symbol.for("react.forward_ref"), ee = /* @__PURE__ */ Symbol.for("react.suspense"), re = /* @__PURE__ */ Symbol.for("react.suspense_list"), te = /* @__PURE__ */ Symbol.for("react.memo"), S = /* @__PURE__ */ Symbol.for("react.lazy"), ne = /* @__PURE__ */ Symbol.for("react.activity"), oe = /* @__PURE__ */ Symbol.for("react.client.reference"), A = f.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, D = Object.prototype.hasOwnProperty, ae = Array.isArray, C = console.createTask ? console.createTask : function() {
223
+ var d = ie, v = /* @__PURE__ */ Symbol.for("react.transitional.element"), G = /* @__PURE__ */ Symbol.for("react.portal"), T = /* @__PURE__ */ Symbol.for("react.fragment"), X = /* @__PURE__ */ Symbol.for("react.strict_mode"), H = /* @__PURE__ */ Symbol.for("react.profiler"), Z = /* @__PURE__ */ Symbol.for("react.consumer"), Q = /* @__PURE__ */ Symbol.for("react.context"), K = /* @__PURE__ */ Symbol.for("react.forward_ref"), ee = /* @__PURE__ */ Symbol.for("react.suspense"), re = /* @__PURE__ */ Symbol.for("react.suspense_list"), te = /* @__PURE__ */ Symbol.for("react.memo"), S = /* @__PURE__ */ Symbol.for("react.lazy"), ne = /* @__PURE__ */ Symbol.for("react.activity"), ae = /* @__PURE__ */ Symbol.for("react.client.reference"), A = d.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, D = Object.prototype.hasOwnProperty, oe = Array.isArray, C = console.createTask ? console.createTask : function() {
224
224
  return null;
225
225
  };
226
- f = {
226
+ d = {
227
227
  react_stack_bottom_frame: function(e) {
228
228
  return e();
229
229
  }
230
230
  };
231
- var F, I = {}, z = f.react_stack_bottom_frame.bind(
232
- f,
233
- s
234
- )(), W = C(m(s)), Y = {};
235
- R.Fragment = T, R.jsx = function(e, r, o) {
231
+ var F, I = {}, z = d.react_stack_bottom_frame.bind(
232
+ d,
233
+ i
234
+ )(), W = C(g(i)), Y = {};
235
+ R.Fragment = T, R.jsx = function(e, r, s) {
236
236
  var l = 1e4 > A.recentlyCreatedOwnerStacks++;
237
- return n(
237
+ return f(
238
238
  e,
239
239
  r,
240
- o,
240
+ s,
241
241
  !1,
242
242
  l ? Error("react-stack-top-frame") : z,
243
- l ? C(m(e)) : W
243
+ l ? C(g(e)) : W
244
244
  );
245
- }, R.jsxs = function(e, r, o) {
245
+ }, R.jsxs = function(e, r, s) {
246
246
  var l = 1e4 > A.recentlyCreatedOwnerStacks++;
247
- return n(
247
+ return f(
248
248
  e,
249
249
  r,
250
- o,
250
+ s,
251
251
  !0,
252
252
  l ? Error("react-stack-top-frame") : z,
253
- l ? C(m(e)) : W
253
+ l ? C(g(e)) : W
254
254
  );
255
255
  };
256
256
  })()), R;
@@ -262,115 +262,114 @@ function pe() {
262
262
  var t = pe();
263
263
  const V = new B();
264
264
  function me({ onConsent: u }) {
265
- const [k, a] = h(!1), [m, i] = h(!1), [s, p] = h(!1), [g, x] = h(!1);
265
+ const [x, n] = y(!1), [g, a] = y(!1), [i, p] = y(!1), [m, k] = y(!1);
266
266
  N(() => {
267
- const f = V.getConsent();
268
- a(!f || V.isConsentExpired()), f && (p(f.analytics), x(f.marketing));
267
+ const d = V.getConsent();
268
+ n(!d || V.isConsentExpired()), d && (p(d.analytics), k(d.marketing));
269
269
  }, []);
270
- const y = () => {
271
- u({ analytics: !0, marketing: !0, action: "accept_all" }), a(!1);
272
- }, n = () => {
273
- u({ analytics: !1, marketing: !1, action: "reject_all" }), a(!1);
274
- }, d = () => {
275
- u({ analytics: s, marketing: g, action: "custom" }), a(!1);
276
- }, b = J(() => {
277
- u({ analytics: !1, marketing: !1, action: "withdraw" }), p(!1), x(!1), a(!0);
270
+ const o = () => {
271
+ u({ analytics: !0, marketing: !0, action: "accept_all" }), n(!1);
272
+ }, f = () => {
273
+ u({ analytics: !1, marketing: !1, action: "reject_all" }), n(!1);
274
+ }, b = () => {
275
+ u({ analytics: i, marketing: m, action: "custom" }), n(!1);
276
+ }, h = J(() => {
277
+ u({ analytics: !1, marketing: !1, action: "withdraw" }), p(!1), k(!1), n(!0);
278
278
  }, [u]);
279
279
  return N(() => {
280
- const f = () => {
281
- a(!0), i(!0);
280
+ const d = () => {
281
+ n(!0), a(!0);
282
282
  };
283
- return window.addEventListener("feedpulse:open-consent", f), window.addEventListener("feedpulse:withdraw-consent", b), () => {
284
- window.removeEventListener("feedpulse:open-consent", f), window.removeEventListener("feedpulse:withdraw-consent", b);
283
+ return window.addEventListener("feedpulse:open-consent", d), window.addEventListener("feedpulse:withdraw-consent", h), () => {
284
+ window.removeEventListener("feedpulse:open-consent", d), window.removeEventListener("feedpulse:withdraw-consent", h);
285
285
  };
286
- }, [b]), k ? /* @__PURE__ */ t.jsx("div", { style: { position: "fixed", bottom: 0, left: 0, right: 0, zIndex: 99999, background: "#1a1a1a", color: "#fff", padding: "20px 24px", borderTop: "1px solid #333", fontFamily: "sans-serif" }, children: /* @__PURE__ */ t.jsxs("div", { style: { maxWidth: 900, margin: "0 auto" }, children: [
286
+ }, [h]), x ? /* @__PURE__ */ t.jsx("div", { style: { position: "fixed", bottom: 0, left: 0, right: 0, zIndex: 99999, background: "#1a1a1a", color: "#fff", padding: "20px 24px", borderTop: "1px solid #333", fontFamily: "sans-serif" }, children: /* @__PURE__ */ t.jsxs("div", { style: { maxWidth: 900, margin: "0 auto" }, children: [
287
287
  /* @__PURE__ */ t.jsxs("p", { style: { margin: "0 0 12px", fontSize: 14, lineHeight: 1.5 }, children: [
288
288
  "We use cookies to improve reliability and understand usage.",
289
289
  " ",
290
290
  /* @__PURE__ */ t.jsx("a", { href: "/privacy", style: { color: "#818cf8" }, children: "Privacy Policy" })
291
291
  ] }),
292
- m && /* @__PURE__ */ t.jsxs("div", { style: { marginBottom: 12, fontSize: 13 }, children: [
292
+ g && /* @__PURE__ */ t.jsxs("div", { style: { marginBottom: 12, fontSize: 13 }, children: [
293
293
  /* @__PURE__ */ t.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6, opacity: 0.75 }, children: [
294
294
  /* @__PURE__ */ t.jsx("input", { type: "checkbox", checked: !0, disabled: !0 }),
295
295
  "Necessary (always on)"
296
296
  ] }),
297
297
  /* @__PURE__ */ t.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 }, children: [
298
- /* @__PURE__ */ t.jsx("input", { type: "checkbox", checked: s, onChange: (f) => p(f.target.checked) }),
298
+ /* @__PURE__ */ t.jsx("input", { type: "checkbox", checked: i, onChange: (d) => p(d.target.checked) }),
299
299
  "Analytics"
300
300
  ] }),
301
301
  /* @__PURE__ */ t.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
302
- /* @__PURE__ */ t.jsx("input", { type: "checkbox", checked: g, onChange: (f) => x(f.target.checked) }),
302
+ /* @__PURE__ */ t.jsx("input", { type: "checkbox", checked: m, onChange: (d) => k(d.target.checked) }),
303
303
  "Marketing"
304
304
  ] })
305
305
  ] }),
306
306
  /* @__PURE__ */ t.jsxs("div", { style: { display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center" }, children: [
307
- /* @__PURE__ */ t.jsx("button", { type: "button", style: { width: 130, padding: "9px 12px", background: "#4f46e5", color: "#fff", border: "1px solid #4f46e5", borderRadius: 6, fontSize: 13, fontWeight: 600, cursor: "pointer" }, onClick: y, children: "Accept All" }),
308
- /* @__PURE__ */ t.jsx("button", { type: "button", style: { width: 130, padding: "9px 12px", background: "transparent", color: "#fff", border: "1px solid #555", borderRadius: 6, fontSize: 13, fontWeight: 600, cursor: "pointer" }, onClick: n, children: "Reject All" }),
309
- /* @__PURE__ */ t.jsx("button", { type: "button", style: { padding: "9px 16px", background: "transparent", color: "#aaa", border: "1px solid #333", borderRadius: 6, fontSize: 13, cursor: "pointer" }, onClick: () => m ? d() : i(!0), children: m ? "Save Preferences" : "Customize" })
307
+ /* @__PURE__ */ t.jsx("button", { type: "button", style: { width: 130, padding: "9px 12px", background: "#4f46e5", color: "#fff", border: "1px solid #4f46e5", borderRadius: 6, fontSize: 13, fontWeight: 600, cursor: "pointer" }, onClick: o, children: "Accept All" }),
308
+ /* @__PURE__ */ t.jsx("button", { type: "button", style: { width: 130, padding: "9px 12px", background: "transparent", color: "#fff", border: "1px solid #555", borderRadius: 6, fontSize: 13, fontWeight: 600, cursor: "pointer" }, onClick: f, children: "Reject All" }),
309
+ /* @__PURE__ */ t.jsx("button", { type: "button", style: { padding: "9px 16px", background: "transparent", color: "#aaa", border: "1px solid #333", borderRadius: 6, fontSize: 13, cursor: "pointer" }, onClick: () => g ? b() : a(!0), children: g ? "Save Preferences" : "Customize" })
310
310
  ] })
311
311
  ] }) }) : null;
312
312
  }
313
313
  const q = le({ tracker: null });
314
314
  function ke({
315
- apiKey: u,
316
- endpoint: k,
317
- debug: a,
318
- consentRequired: m = !0,
319
- children: i
315
+ proxyEndpoint: u = "/api/fp-proxy",
316
+ debug: x,
317
+ consentRequired: n = !0,
318
+ children: g
320
319
  }) {
321
- const s = M(null), p = M(new B()), [g, x] = h(null), y = J((n) => {
322
- const d = p.current, b = d.setConsent({
323
- analytics: n.analytics,
324
- marketing: n.marketing,
320
+ const a = M(null), i = M(new B()), [p, m] = y(null), k = J((o) => {
321
+ const f = i.current, b = f.setConsent({
322
+ analytics: o.analytics,
323
+ marketing: o.marketing,
325
324
  version: "1.0"
326
325
  });
327
- n.analytics || d.clearAnalyticsCookies(), s.current?.updateCookieData(d.getAllData(n.analytics)), s.current?.track("consent", "__consent__", {
328
- analytics: n.analytics,
329
- marketing: n.marketing,
330
- action: n.action,
326
+ o.analytics || f.clearAnalyticsCookies(), a.current?.updateCookieData(f.getAllData(o.analytics)), a.current?.track("consent", "__consent__", {
327
+ analytics: o.analytics,
328
+ marketing: o.marketing,
329
+ action: o.action,
331
330
  userAgent: navigator.userAgent,
332
331
  version: b.version
333
332
  });
334
333
  }, []);
335
334
  return N(() => {
336
- const n = new ue({ apiKey: u, endpoint: k, debug: a });
337
- s.current = n, x(n);
338
- const d = p.current, b = d.getConsent();
339
- return m ? b && !d.isConsentExpired() ? n.updateCookieData(d.getAllData(b.analytics)) : n.updateCookieData(d.getAllData(!1)) : (d.setConsent({ analytics: !0, marketing: !0, version: "1.0" }), n.updateCookieData(d.getAllData(!0))), n.init(), () => {
340
- n.destroy(), s.current = null, x(null);
335
+ const o = new ue({ proxyEndpoint: u, debug: x });
336
+ a.current = o, m(o);
337
+ const f = i.current, b = f.getConsent();
338
+ return n ? b && !f.isConsentExpired() ? o.updateCookieData(f.getAllData(b.analytics)) : o.updateCookieData(f.getAllData(!1)) : (f.setConsent({ analytics: !0, marketing: !0, version: "1.0" }), o.updateCookieData(f.getAllData(!0))), o.init(), () => {
339
+ o.destroy(), a.current = null, m(null);
341
340
  };
342
- }, [u, k, a, m]), /* @__PURE__ */ t.jsxs(q.Provider, { value: { tracker: g }, children: [
343
- i,
344
- m && /* @__PURE__ */ t.jsx(me, { onConsent: y })
341
+ }, [u, x, n]), /* @__PURE__ */ t.jsxs(q.Provider, { value: { tracker: p }, children: [
342
+ g,
343
+ n && /* @__PURE__ */ t.jsx(me, { onConsent: k })
345
344
  ] });
346
345
  }
347
346
  function ge() {
348
347
  return ce(q);
349
348
  }
350
- function he({ id: u, placeholder: k, position: a = "bottom-right" }) {
351
- const { tracker: m } = ge(), [i, s] = h(a === "inline"), [p, g] = h(null), [x, y] = h(""), [n, d] = h(!1), b = () => {
352
- !p && !x.trim() || (m?.trackFeedback(u ?? null, p, x || null), d(!0), setTimeout(() => {
353
- s(a === "inline"), d(!1), g(null), y("");
349
+ function ye({ id: u, placeholder: x, position: n = "bottom-right" }) {
350
+ const { tracker: g } = ge(), [a, i] = y(n === "inline"), [p, m] = y(null), [k, o] = y(""), [f, b] = y(!1), h = () => {
351
+ !p && !k.trim() || (g?.trackFeedback(u ?? null, p, k || null), b(!0), setTimeout(() => {
352
+ i(n === "inline"), b(!1), m(null), o("");
354
353
  }, 2e3));
355
- }, f = a !== "inline" ? { position: "fixed", bottom: 24, [a === "bottom-right" ? "right" : "left"]: 24, zIndex: 9999 } : {};
356
- return /* @__PURE__ */ t.jsxs("div", { style: f, children: [
357
- a !== "inline" && /* @__PURE__ */ t.jsx(
354
+ }, d = n !== "inline" ? { position: "fixed", bottom: 24, [n === "bottom-right" ? "right" : "left"]: 24, zIndex: 9999 } : {};
355
+ return /* @__PURE__ */ t.jsxs("div", { style: d, children: [
356
+ n !== "inline" && /* @__PURE__ */ t.jsx(
358
357
  "button",
359
358
  {
360
- onClick: () => s(!i),
359
+ onClick: () => i(!a),
361
360
  style: { background: "#6366f1", color: "#fff", border: "none", borderRadius: "50%", width: 48, height: 48, fontSize: 20, cursor: "pointer" },
362
361
  children: "💬"
363
362
  }
364
363
  ),
365
- i && /* @__PURE__ */ t.jsx("div", { style: { background: "#fff", border: "1px solid #e5e7eb", borderRadius: 12, padding: 16, width: 280, boxShadow: "0 10px 25px rgba(0,0,0,0.15)" }, children: n ? /* @__PURE__ */ t.jsxs("div", { style: { textAlign: "center", padding: 16 }, children: [
364
+ a && /* @__PURE__ */ t.jsx("div", { style: { background: "#fff", border: "1px solid #e5e7eb", borderRadius: 12, padding: 16, width: 280, boxShadow: "0 10px 25px rgba(0,0,0,0.15)" }, children: f ? /* @__PURE__ */ t.jsxs("div", { style: { textAlign: "center", padding: 16 }, children: [
366
365
  /* @__PURE__ */ t.jsx("p", { style: { fontSize: 28, margin: 0 }, children: "🎉" }),
367
366
  /* @__PURE__ */ t.jsx("p", { style: { margin: "8px 0 0", fontWeight: 600 }, children: "Thanks for your feedback!" })
368
367
  ] }) : /* @__PURE__ */ t.jsxs(t.Fragment, { children: [
369
- /* @__PURE__ */ t.jsx("p", { style: { margin: "0 0 12px", fontWeight: 600 }, children: k ?? "How was your experience?" }),
368
+ /* @__PURE__ */ t.jsx("p", { style: { margin: "0 0 12px", fontWeight: 600 }, children: x ?? "How was your experience?" }),
370
369
  /* @__PURE__ */ t.jsx("div", { style: { display: "flex", gap: 6, marginBottom: 12 }, children: [1, 2, 3, 4, 5].map((v) => /* @__PURE__ */ t.jsx(
371
370
  "button",
372
371
  {
373
- onClick: () => g(v),
372
+ onClick: () => m(v),
374
373
  style: { background: "none", border: "none", cursor: "pointer", fontSize: 24, opacity: p !== null && v <= p ? 1 : 0.3 },
375
374
  children: "⭐"
376
375
  },
@@ -379,8 +378,8 @@ function he({ id: u, placeholder: k, position: a = "bottom-right" }) {
379
378
  /* @__PURE__ */ t.jsx(
380
379
  "textarea",
381
380
  {
382
- value: x,
383
- onChange: (v) => y(v.target.value),
381
+ value: k,
382
+ onChange: (v) => o(v.target.value),
384
383
  placeholder: "Tell us more (optional)...",
385
384
  rows: 3,
386
385
  style: { width: "100%", padding: 8, border: "1px solid #d1d5db", borderRadius: 8, resize: "none", fontSize: 14 }
@@ -389,7 +388,7 @@ function he({ id: u, placeholder: k, position: a = "bottom-right" }) {
389
388
  /* @__PURE__ */ t.jsx(
390
389
  "button",
391
390
  {
392
- onClick: b,
391
+ onClick: h,
393
392
  style: { marginTop: 10, width: "100%", background: "#6366f1", color: "#fff", border: "none", borderRadius: 8, padding: 10, fontWeight: 600, cursor: "pointer" },
394
393
  children: "Submit Feedback"
395
394
  }
@@ -400,6 +399,6 @@ function he({ id: u, placeholder: k, position: a = "bottom-right" }) {
400
399
  export {
401
400
  me as ConsentBanner,
402
401
  ke as FeedPulseProvider,
403
- he as FeedPulseWidget,
402
+ ye as FeedPulseWidget,
404
403
  ge as useFeedPulse
405
404
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekibo/feedpulse-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Embeddable analytics and feedback SDK for FeedPulse",
5
5
  "exports": {
6
6
  ".": {
@@ -20,7 +20,8 @@
20
20
  "module": "./dist/index.mjs",
21
21
  "types": "./dist/index.d.ts",
22
22
  "files": [
23
- "dist"
23
+ "dist",
24
+ "templates"
24
25
  ],
25
26
  "scripts": {
26
27
  "build": "vite build",
@@ -0,0 +1,33 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+
3
+ export async function POST(request: NextRequest) {
4
+ const apiKey = process.env.FEEDPULSE_API_KEY;
5
+ const workerUrl = process.env.FEEDPULSE_WORKER_URL || "https://feedpulse-workers.tekibohelp.workers.dev/ingest";
6
+
7
+ if (!apiKey) {
8
+ return NextResponse.json(
9
+ { error: "FEEDPULSE_API_KEY is not configured" },
10
+ { status: 500 },
11
+ );
12
+ }
13
+
14
+ const body = await request.json().catch(() => null);
15
+ const events = Array.isArray(body?.events) ? body.events : [];
16
+ if (events.length === 0)
17
+ return NextResponse.json({ error: "No events" }, { status: 400 });
18
+
19
+ const enriched = events.map((item: unknown) => {
20
+ if (!item || typeof item !== "object")
21
+ return { projectApiKey: apiKey };
22
+ return { ...item, projectApiKey: apiKey };
23
+ });
24
+
25
+ const response = await fetch(workerUrl, {
26
+ method: "POST",
27
+ headers: { "content-type": "application/json" },
28
+ body: JSON.stringify({ events: enriched }),
29
+ });
30
+
31
+ const payload = await response.json().catch(() => ({ ok: false, error: "Invalid worker response" }));
32
+ return NextResponse.json(payload, { status: response.status });
33
+ }
@@ -0,0 +1,44 @@
1
+ export default defineEventHandler(async (event) => {
2
+ const config = useRuntimeConfig(event);
3
+ const apiKey = config.feedpulseApiKey;
4
+ const workerUrl = config.feedpulseWorkerUrl || "https://feedpulse-workers.tekibohelp.workers.dev/ingest";
5
+
6
+ if (!apiKey) {
7
+ throw createError({
8
+ statusCode: 500,
9
+ statusMessage: "FEEDPULSE_API_KEY is not configured",
10
+ });
11
+ }
12
+
13
+ const body = await readBody<{ events?: unknown }>(event);
14
+ const events = Array.isArray(body?.events) ? body.events : [];
15
+ if (events.length === 0) {
16
+ throw createError({
17
+ statusCode: 400,
18
+ statusMessage: "No events",
19
+ });
20
+ }
21
+
22
+ const enriched = events.map((item) => {
23
+ if (!item || typeof item !== "object")
24
+ return { projectApiKey: apiKey };
25
+ return { ...item, projectApiKey: apiKey };
26
+ });
27
+
28
+ const response = await fetch(workerUrl, {
29
+ method: "POST",
30
+ headers: { "content-type": "application/json" },
31
+ body: JSON.stringify({ events: enriched }),
32
+ });
33
+
34
+ const payload = await response.json().catch(() => ({ ok: false, error: "Invalid worker response" }));
35
+ if (!response.ok) {
36
+ throw createError({
37
+ statusCode: response.status,
38
+ statusMessage: typeof payload?.error === "string" ? payload.error : "FeedPulse worker request failed",
39
+ data: payload,
40
+ });
41
+ }
42
+
43
+ return payload;
44
+ });