@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 +45 -107
- package/dist/index.js +1 -1
- package/dist/index.mjs +7 -12
- package/dist/nuxt.js +1 -1
- package/dist/nuxt.mjs +38 -40
- package/dist/react.js +2 -2
- package/dist/react.mjs +124 -125
- package/package.json +3 -2
- package/templates/nextjs-proxy.ts +33 -0
- package/templates/nuxt-proxy.ts +44 -0
package/README.md
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
# @tekibo/feedpulse-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
FeedPulse analytics and feedback SDK for Nuxt and React.
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
7
|
+
### 1) Create a proxy route in your own app
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
12
|
+
### 2) Set server-only environment variables
|
|
18
13
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
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
|
-
|
|
19
|
+
Never use `NUXT_PUBLIC_` or `NEXT_PUBLIC_` for the FeedPulse API key.
|
|
25
20
|
|
|
26
|
-
|
|
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
|
|
29
|
+
<FeedPulseProvider :debug="true">
|
|
35
30
|
<NuxtPage />
|
|
36
|
-
<FeedPulseWidget
|
|
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
|
|
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
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
56
|
+
## Provider props
|
|
121
57
|
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
58
|
+
- `proxyEndpoint?: string` default `/api/fp-proxy`
|
|
59
|
+
- `debug?: boolean`
|
|
60
|
+
- `consentRequired?: boolean` default `true`
|
|
125
61
|
|
|
126
|
-
##
|
|
62
|
+
## Tracker config
|
|
127
63
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
64
|
+
```ts
|
|
65
|
+
type FeedPulseConfig = {
|
|
66
|
+
proxyEndpoint?: string
|
|
67
|
+
batchInterval?: number
|
|
68
|
+
debug?: boolean
|
|
69
|
+
}
|
|
70
|
+
```
|
|
132
71
|
|
|
133
|
-
##
|
|
72
|
+
## What is tracked
|
|
134
73
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
74
|
+
- `click`
|
|
75
|
+
- `hover`
|
|
76
|
+
- `scroll_into_view`
|
|
77
|
+
- `feedback`
|
|
78
|
+
- `consent`
|
|
140
79
|
|
|
141
|
-
##
|
|
80
|
+
## Templates included in package
|
|
142
81
|
|
|
143
|
-
-
|
|
144
|
-
-
|
|
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
|
|
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("="),
|
|
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(
|
|
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
|
-
},
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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"),
|
|
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
|
|
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
|
|
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
|
-
},
|
|
10
|
+
}, q = { style: { "max-width": "900px", margin: "0 auto" } }, W = {
|
|
11
11
|
key: 0,
|
|
12
12
|
style: { "margin-bottom": "12px", "font-size": "13px" }
|
|
13
|
-
},
|
|
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(
|
|
17
|
-
const o =
|
|
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
|
-
|
|
22
|
-
const
|
|
23
|
-
i.value = !
|
|
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
|
|
37
|
+
return D(() => {
|
|
38
38
|
typeof window < "u" && (window.removeEventListener("feedpulse:open-consent", v), window.removeEventListener("feedpulse:withdraw-consent", w));
|
|
39
|
-
}), (
|
|
40
|
-
i.value ? (l(), u("div",
|
|
41
|
-
n("div",
|
|
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",
|
|
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",
|
|
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",
|
|
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
|
-
])) :
|
|
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
|
-
])) :
|
|
92
|
+
])) : y("", !0)
|
|
93
93
|
]));
|
|
94
94
|
}
|
|
95
95
|
}), te = /* @__PURE__ */ _({
|
|
96
96
|
__name: "FeedPulseProvider",
|
|
97
97
|
props: {
|
|
98
|
-
|
|
99
|
-
endpoint: {},
|
|
98
|
+
proxyEndpoint: { default: "/api/fp-proxy" },
|
|
100
99
|
debug: { type: Boolean },
|
|
101
100
|
consentRequired: { type: Boolean, default: !0 }
|
|
102
101
|
},
|
|
103
|
-
setup(
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
122
|
+
return z(() => {
|
|
125
123
|
const e = o.getConsent();
|
|
126
|
-
|
|
127
|
-
}),
|
|
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
|
-
|
|
127
|
+
r.consentRequired !== !1 ? (l(), P(Y, {
|
|
130
128
|
key: 0,
|
|
131
129
|
onConsent: i
|
|
132
|
-
})) :
|
|
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(
|
|
149
|
-
const
|
|
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(
|
|
155
|
-
t.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:
|
|
158
|
+
style: E(r.position !== "inline" ? `position:fixed; ${r.position === "bottom-right" ? "right:24px" : "left:24px"}; bottom:24px; z-index:9999;` : "")
|
|
161
159
|
}, [
|
|
162
|
-
|
|
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
|
-
}, " 💬 ")) :
|
|
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, $(
|
|
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:
|
|
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
|
-
])) :
|
|
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"),
|
|
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,
|
|
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
|
|
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"),
|
|
9
|
-
function
|
|
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 (
|
|
12
|
-
|
|
13
|
-
for (var
|
|
14
|
-
|
|
15
|
-
} else
|
|
16
|
-
return
|
|
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:
|
|
18
|
+
type: g,
|
|
19
19
|
key: p,
|
|
20
|
-
ref:
|
|
21
|
-
props:
|
|
20
|
+
ref: a !== void 0 ? a : null,
|
|
21
|
+
props: i
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
return
|
|
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 ===
|
|
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
|
|
73
|
+
function x(e) {
|
|
74
74
|
return "" + e;
|
|
75
75
|
}
|
|
76
|
-
function
|
|
76
|
+
function n(e) {
|
|
77
77
|
try {
|
|
78
|
-
|
|
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
|
|
86
|
-
return
|
|
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
|
-
),
|
|
90
|
+
), x(e);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
function
|
|
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
|
|
104
|
+
function a() {
|
|
105
105
|
var e = A.A;
|
|
106
106
|
return e === null ? null : e.getOwner();
|
|
107
107
|
}
|
|
108
|
-
function
|
|
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
|
|
119
|
-
function
|
|
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
|
-
|
|
126
|
-
get:
|
|
125
|
+
s.isReactWarning = !0, Object.defineProperty(e, "key", {
|
|
126
|
+
get: s,
|
|
127
127
|
configurable: !0
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
-
function
|
|
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
|
|
137
|
-
var c =
|
|
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:
|
|
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:
|
|
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
|
|
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 (
|
|
173
|
+
if (oe(c)) {
|
|
174
174
|
for (l = 0; l < c.length; l++)
|
|
175
|
-
|
|
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
|
|
181
|
+
else b(c);
|
|
182
182
|
if (D.call(r, "key")) {
|
|
183
183
|
c = u(e);
|
|
184
|
-
var
|
|
184
|
+
var _ = Object.keys(r).filter(function(se) {
|
|
185
185
|
return se !== "key";
|
|
186
186
|
});
|
|
187
|
-
l = 0 <
|
|
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
|
-
|
|
196
|
+
_,
|
|
197
197
|
c
|
|
198
198
|
), Y[c + l] = !0);
|
|
199
199
|
}
|
|
200
|
-
if (c = null,
|
|
201
|
-
|
|
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" && (
|
|
204
|
-
} else
|
|
205
|
-
return c &&
|
|
206
|
-
|
|
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
|
-
),
|
|
208
|
+
), o(
|
|
209
209
|
e,
|
|
210
210
|
c,
|
|
211
|
-
|
|
212
|
-
|
|
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
|
|
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
|
-
|
|
226
|
+
d = {
|
|
227
227
|
react_stack_bottom_frame: function(e) {
|
|
228
228
|
return e();
|
|
229
229
|
}
|
|
230
230
|
};
|
|
231
|
-
var F, I = {}, z =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
)(), W = C(
|
|
235
|
-
R.Fragment = T, R.jsx = function(e, r,
|
|
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
|
|
237
|
+
return f(
|
|
238
238
|
e,
|
|
239
239
|
r,
|
|
240
|
-
|
|
240
|
+
s,
|
|
241
241
|
!1,
|
|
242
242
|
l ? Error("react-stack-top-frame") : z,
|
|
243
|
-
l ? C(
|
|
243
|
+
l ? C(g(e)) : W
|
|
244
244
|
);
|
|
245
|
-
}, R.jsxs = function(e, r,
|
|
245
|
+
}, R.jsxs = function(e, r, s) {
|
|
246
246
|
var l = 1e4 > A.recentlyCreatedOwnerStacks++;
|
|
247
|
-
return
|
|
247
|
+
return f(
|
|
248
248
|
e,
|
|
249
249
|
r,
|
|
250
|
-
|
|
250
|
+
s,
|
|
251
251
|
!0,
|
|
252
252
|
l ? Error("react-stack-top-frame") : z,
|
|
253
|
-
l ? C(
|
|
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 [
|
|
265
|
+
const [x, n] = y(!1), [g, a] = y(!1), [i, p] = y(!1), [m, k] = y(!1);
|
|
266
266
|
N(() => {
|
|
267
|
-
const
|
|
268
|
-
|
|
267
|
+
const d = V.getConsent();
|
|
268
|
+
n(!d || V.isConsentExpired()), d && (p(d.analytics), k(d.marketing));
|
|
269
269
|
}, []);
|
|
270
|
-
const
|
|
271
|
-
u({ analytics: !0, marketing: !0, action: "accept_all" }),
|
|
272
|
-
},
|
|
273
|
-
u({ analytics: !1, marketing: !1, action: "reject_all" }),
|
|
274
|
-
},
|
|
275
|
-
u({ analytics:
|
|
276
|
-
},
|
|
277
|
-
u({ analytics: !1, marketing: !1, action: "withdraw" }), p(!1),
|
|
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
|
|
281
|
-
|
|
280
|
+
const d = () => {
|
|
281
|
+
n(!0), a(!0);
|
|
282
282
|
};
|
|
283
|
-
return window.addEventListener("feedpulse:open-consent",
|
|
284
|
-
window.removeEventListener("feedpulse:open-consent",
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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: () =>
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
children: i
|
|
315
|
+
proxyEndpoint: u = "/api/fp-proxy",
|
|
316
|
+
debug: x,
|
|
317
|
+
consentRequired: n = !0,
|
|
318
|
+
children: g
|
|
320
319
|
}) {
|
|
321
|
-
const
|
|
322
|
-
const
|
|
323
|
-
analytics:
|
|
324
|
-
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
|
-
|
|
328
|
-
analytics:
|
|
329
|
-
marketing:
|
|
330
|
-
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
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
return
|
|
340
|
-
|
|
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,
|
|
343
|
-
|
|
344
|
-
|
|
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
|
|
351
|
-
const { tracker:
|
|
352
|
-
!p && !
|
|
353
|
-
|
|
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
|
-
},
|
|
356
|
-
return /* @__PURE__ */ t.jsxs("div", { style:
|
|
357
|
-
|
|
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: () =>
|
|
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
|
-
|
|
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:
|
|
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: () =>
|
|
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:
|
|
383
|
-
onChange: (v) =>
|
|
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:
|
|
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
|
-
|
|
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.
|
|
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
|
+
});
|