@tekibo/feedpulse-sdk 0.7.1 → 0.7.3

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.
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync } from "node:fs";
4
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
5
+ import { join, relative } from "node:path";
6
+
7
+ const CWD = process.cwd();
8
+ const PAGES_DIR = join(CWD, "pages");
9
+ const OUTPUT_DIR = join(CWD, "feedpulse", "page-maps");
10
+
11
+ async function findBotPages(dir) {
12
+ const results = [];
13
+ for (const entry of await readdir(dir, { withFileTypes: true })) {
14
+ const filePath = join(dir, entry.name);
15
+ if (entry.isDirectory()) {
16
+ results.push(...await findBotPages(filePath));
17
+ }
18
+ else if (entry.isFile() && /\.(vue|tsx)$/.test(entry.name)) {
19
+ const content = await readFile(filePath, "utf8");
20
+ if (content.includes("FeedPulseBot")) {
21
+ const route = `/${relative(PAGES_DIR, filePath)
22
+ .replace(/\.(vue|tsx)$/, "")
23
+ .replace(/\/index$/, "")
24
+ .replace(/\\/g, "/")}`;
25
+ results.push({ path: filePath, content, route });
26
+ }
27
+ }
28
+ }
29
+ return results;
30
+ }
31
+
32
+ function extractBotProps(content) {
33
+ const botMatch = content.match(/<FeedPulseBot([^/]*?)(?:\/?>|\n\s*>)/s);
34
+ if (!botMatch)
35
+ return {};
36
+ const propsStr = botMatch[1];
37
+ const get = (name) => {
38
+ const match = propsStr.match(new RegExp(`:?${name}="([^"]*)"`, "i"));
39
+ if (!match)
40
+ return undefined;
41
+ try {
42
+ return JSON.parse(match[1].replace(/'/g, "\""));
43
+ }
44
+ catch {
45
+ return match[1];
46
+ }
47
+ };
48
+ return {
49
+ pageContext: get("page-context") ?? get("pageContext"),
50
+ systemPrompt: get("system-prompt") ?? get("systemPrompt"),
51
+ position: get("position"),
52
+ };
53
+ }
54
+
55
+ function extractInteractiveElements(content) {
56
+ const elements = [];
57
+ const patterns = [
58
+ [/data-fp-id="([^"]+)"/g, "tracked"],
59
+ [/<button[^>]*>([^<]*)<\/button>/gi, "button"],
60
+ [/<a\s[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>/gi, "link"],
61
+ [/<input[^>]*(?:placeholder|id)="([^"]*)"/gi, "input"],
62
+ ];
63
+ for (const [pattern, type] of patterns) {
64
+ let match;
65
+ while ((match = pattern.exec(content)) !== null)
66
+ elements.push({ type, value: match[1] ?? match[0] });
67
+ }
68
+ return elements;
69
+ }
70
+
71
+ function buildPageMap(route, props, elements, rawContent) {
72
+ return {
73
+ route,
74
+ generatedAt: new Date().toISOString(),
75
+ botConfig: props,
76
+ interactiveElements: elements,
77
+ templateSummary: rawContent
78
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
79
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
80
+ .replace(/<!--[\s\S]*?-->/g, "")
81
+ .replace(/\s+/g, " ")
82
+ .trim()
83
+ .slice(0, 3000),
84
+ injectionProtection: { enabled: true },
85
+ };
86
+ }
87
+
88
+ async function run() {
89
+ if (!existsSync(PAGES_DIR)) {
90
+ console.error("No pages/ dir found.");
91
+ process.exit(1);
92
+ }
93
+
94
+ await mkdir(OUTPUT_DIR, { recursive: true });
95
+ const pages = await findBotPages(PAGES_DIR);
96
+ console.log(`FeedPulse Bot Build — found ${pages.length} page(s) with FeedPulseBot`);
97
+
98
+ for (const page of pages) {
99
+ const map = buildPageMap(
100
+ page.route,
101
+ extractBotProps(page.content),
102
+ extractInteractiveElements(page.content),
103
+ page.content,
104
+ );
105
+ const filename = page.route.replace(/\//g, "_").replace(/^_/, "") || "index";
106
+ await writeFile(join(OUTPUT_DIR, `${filename}.json`), JSON.stringify(map, null, 2));
107
+ console.log(`${page.route} -> feedpulse/page-maps/${filename}.json`);
108
+ }
109
+
110
+ await writeFile(join(OUTPUT_DIR, "_index.json"), JSON.stringify({
111
+ generatedAt: new Date().toISOString(),
112
+ pages: pages.map(page => ({ route: page.route })),
113
+ }, null, 2));
114
+
115
+ console.log("Done. Page maps in feedpulse/page-maps/");
116
+ }
117
+
118
+ run().catch((error) => {
119
+ console.error(error);
120
+ process.exit(1);
121
+ });
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,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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function p(o){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var s in i)o[s]=i[s]}return o}var y={read:function(o){return o[0]==='"'&&(o=o.slice(1,-1)),o.replace(/(%[\dA-F]{2})+/gi,decodeURIComponent)},write:function(o){return encodeURIComponent(o).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,decodeURIComponent)}};function m(o,e){function i(t,n,r){if(!(typeof document>"u")){r=p({},e,r),typeof r.expires=="number"&&(r.expires=new Date(Date.now()+r.expires*864e5)),r.expires&&(r.expires=r.expires.toUTCString()),t=encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var a="";for(var l in r)r[l]&&(a+="; "+l,r[l]!==!0&&(a+="="+r[l].split(";")[0]));return document.cookie=t+"="+o.write(n,t)+a}}function s(t){if(!(typeof document>"u"||arguments.length&&!t)){for(var n=document.cookie?document.cookie.split("; "):[],r={},a=0;a<n.length;a++){var l=n[a].split("="),d=l.slice(1).join("=");try{var h=decodeURIComponent(l[0]);if(r[h]=o.read(d,h),t===h)break}catch{}}return t?r[t]:r}}return Object.create({set:i,get:s,remove:function(t,n){i(t,"",p({},n,{expires:-1}))},withAttributes:function(t){return m(this.converter,p({},this.attributes,t))},withConverter:function(t){return m(p({},this.converter,t),this.attributes)}},{attributes:{value:Object.freeze(e)},converter:{value:Object.freeze(o)}})}var u=m(y,{path:"/"});const c={USER_ID:"__fp_uid",SESSION_ID:"__fp_sid",SESSION_START:"__fp_ss",CONSENT:"__fp_consent",UTM:"__fp_utm"},g=1/48,I=365,b=365,k=30;function S(){return typeof window<"u"}function v(o){if(!o)return null;try{return JSON.parse(o)}catch{return null}}class w{initSession(){const e=!!u.get(c.USER_ID);let i=u.get(c.SESSION_ID)??null,s=Number(u.get(c.SESSION_START)||Date.now());return i||(i=crypto.randomUUID(),s=Date.now()),u.set(c.SESSION_ID,i,{expires:g}),u.set(c.SESSION_START,String(s),{expires:g}),{sessionId:i,sessionStart:s,isReturningUser:e}}initUser(){let e=u.get(c.USER_ID)??null;return e||(e=crypto.randomUUID(),u.set(c.USER_ID,e,{expires:b})),e}getConsent(){return v(u.get(c.CONSENT))}setConsent(e){const i={necessary:!0,analytics:e.analytics,marketing:e.marketing,version:e.version,timestamp:Date.now()};return u.set(c.CONSENT,JSON.stringify(i),{expires:I}),i}clearAnalyticsCookies(){u.remove(c.USER_ID)}isConsentExpired(){const e=this.getConsent();if(!e)return!0;const i=365*24*60*60*1e3;return Date.now()-e.timestamp>i}captureUTM(){if(!S())return null;const e=new URLSearchParams(window.location.search),i={};for(const s of["utm_source","utm_medium","utm_campaign","utm_term","utm_content"]){const t=e.get(s);t&&(i[s]=t)}return Object.keys(i).length===0?v(u.get(c.UTM)):(u.set(c.UTM,JSON.stringify(i),{expires:k}),i)}getAllData(e){const{sessionId:i,sessionStart:s,isReturningUser:t}=this.initSession();return{userId:e?this.initUser():null,sessionId:i,sessionStart:s,consent:this.getConsent(),utm:this.captureUTM(),isReturningUser:e?t:!1}}}class _{constructor(){this.cursorEl=null}createCursor(){if(this.cursorEl)return this.cursorEl;const e=document.createElement("div");return e.id="__fp_bot_cursor",e.innerHTML='<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 3l14 9-7 1-4 7L5 3z" fill="#6366f1" stroke="white" stroke-width="1.5"/></svg>',Object.assign(e.style,{position:"fixed",zIndex:"999999",pointerEvents:"none",transition:"left 0.6s ease, top 0.6s ease",transform:"translate(-4px,-4px)",left:"50%",top:"50%",opacity:"0"}),document.body.appendChild(e),this.cursorEl=e,e}async moveTo(e,i){const s=this.createCursor();s.style.left=`${e}px`,s.style.top=`${i}px`,await new Promise(t=>setTimeout(t,700))}async clickAnimation(e,i){if(!document.getElementById("__fp_cursor_styles")){const t=document.createElement("style");t.id="__fp_cursor_styles",t.textContent="@keyframes fp-ripple{from{transform:scale(0);opacity:1}to{transform:scale(2);opacity:0}}",document.head.appendChild(t)}const s=document.createElement("div");Object.assign(s.style,{position:"fixed",left:`${e-16}px`,top:`${i-16}px`,width:"32px",height:"32px",borderRadius:"50%",background:"rgba(99,102,241,0.4)",zIndex:"999998",pointerEvents:"none",animation:"fp-ripple 0.4s ease-out forwards"}),document.body.appendChild(s),await new Promise(t=>setTimeout(t,400)),s.remove()}async typeText(e,i){e.focus(),(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&(e.value="");for(const s of i)await new Promise(t=>setTimeout(t,60+Math.random()*40)),(e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement)&&(e.value+=s,e.dispatchEvent(new Event("input",{bubbles:!0})))}async perform(e){try{const i=this.createCursor();if(i.style.opacity="1",e.type==="navigate"&&e.value)return await this.moveTo(window.innerWidth/2,window.innerHeight/2),await new Promise(d=>setTimeout(d,300)),this.destroy(),window.location.href=e.value,{success:!0,message:`Navigating to ${e.value}...`};if(!e.selector)return{success:!1,message:"No target element specified."};const t=!/[#.\[\]\s>:+~]/.test(e.selector)?`[data-fp-id="${e.selector}"], #${e.selector}, [name="${e.selector}"]`:e.selector,n=document.querySelector(t);if(!n)return{success:!1,message:`Could not find "${e.label}" on the page.`};const r=n.getBoundingClientRect(),a=r.left+r.width/2,l=r.top+r.height/2;if(await this.moveTo(a,l),e.type==="click"&&(await this.clickAnimation(a,l),n.click(),n.dispatchEvent(new MouseEvent("click",{bubbles:!0,cancelable:!0}))),e.type==="scroll"){n.scrollIntoView({behavior:"smooth",block:"center"});const d=n.style.outline,h=n.style.outlineOffset;n.style.outline="2px solid #6366f1",n.style.outlineOffset="3px",await new Promise(f=>setTimeout(f,1500)),n.style.outline=d,n.style.outlineOffset=h}if(e.type==="fill"&&e.value&&await this.typeText(n,e.value),e.type==="highlight"){n.scrollIntoView({behavior:"smooth",block:"center"});const d=n.style.outline,h=n.style.outlineOffset;n.style.outline="2px solid #6366f1",n.style.outlineOffset="3px",await new Promise(f=>setTimeout(f,1500)),n.style.outline=d,n.style.outlineOffset=h}return await new Promise(d=>setTimeout(d,400)),this.destroy(),{success:!0,message:`Done! I ${e.type}ed "${e.label}".`}}catch{return this.destroy(),{success:!1,message:"Something went wrong performing that action."}}}destroy(){this.cursorEl?.remove(),this.cursorEl=null}}class D{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 w,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 t=s.target.closest("[data-fp-id]");t&&this.track("click",t.getAttribute("data-fp-id"),{x:s.clientX,y:s.clientY})},{passive:!0});let e=0,i=null;document.addEventListener("mouseover",s=>{const t=s.target.closest("[data-fp-id]");t&&(e=Date.now(),i=t.getAttribute("data-fp-id"))},{passive:!0}),document.addEventListener("mouseout",s=>{if(!s.target.closest("[data-fp-id]")||!i)return;const n=Date.now()-e;n>500&&this.track("hover",i,{hoverDuration:n}),i=null},{passive:!0})}observeDOM(){const e=t=>{this.seenInView.has(t)||(this.seenInView.add(t),this.track("scroll_into_view",t,{scrollDepth:Math.round(window.scrollY/Math.max(1,document.body.scrollHeight)*100)}))};this.intersectionObserver=new IntersectionObserver(t=>{for(const n of t){const r=n.target.dataset.fpId;!r||!n.isIntersecting||e(r)}},{threshold:.1});const i=()=>{document.querySelectorAll("[data-fp-id]").forEach(t=>{this.intersectionObserver?.observe(t)})},s=()=>{const t=window.innerHeight*.1,n=window.innerHeight*.9;document.querySelectorAll("[data-fp-id]").forEach(r=>{const a=r.dataset.fpId;if(!a||this.seenInView.has(a))return;const l=r.getBoundingClientRect();l.bottom>=t&&l.top<=n&&e(a)})};i(),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(()=>i()),this.observer.observe(document.body,{childList:!0,subtree:!0})}track(e,i,s){this.isBrowser()&&(this.refreshCookieData(),this.queue.push({elementId:i,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,i,s){this.isBrowser()&&(!i&&!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:i,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 i=await fetch(this.config.proxyEndpoint,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({events:e}),keepalive:!0});if(this.config.debug&&i.ok){const s=await i.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=c;exports.CookieManager=w;exports.CursorActor=_;exports.FeedPulseTracker=D;
package/dist/index.mjs CHANGED
@@ -1,150 +1,227 @@
1
- function d(r) {
1
+ function p(o) {
2
2
  for (var e = 1; e < arguments.length; e++) {
3
- var t = arguments[e];
4
- for (var s in t)
5
- r[s] = t[s];
3
+ var i = arguments[e];
4
+ for (var s in i)
5
+ o[s] = i[s];
6
6
  }
7
- return r;
7
+ return o;
8
8
  }
9
- var v = {
10
- read: function(r) {
11
- return r[0] === '"' && (r = r.slice(1, -1)), r.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
9
+ var w = {
10
+ read: function(o) {
11
+ return o[0] === '"' && (o = o.slice(1, -1)), o.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
12
12
  },
13
- write: function(r) {
14
- return encodeURIComponent(r).replace(
13
+ write: function(o) {
14
+ return encodeURIComponent(o).replace(
15
15
  /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
16
16
  decodeURIComponent
17
17
  );
18
18
  }
19
19
  };
20
- function f(r, e) {
21
- function t(i, o, n) {
20
+ function m(o, e) {
21
+ function i(t, n, r) {
22
22
  if (!(typeof document > "u")) {
23
- 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);
24
- var u = "";
25
- for (var l in n)
26
- n[l] && (u += "; " + l, n[l] !== !0 && (u += "=" + n[l].split(";")[0]));
27
- return document.cookie = i + "=" + r.write(o, i) + u;
23
+ r = p({}, e, r), typeof r.expires == "number" && (r.expires = new Date(Date.now() + r.expires * 864e5)), r.expires && (r.expires = r.expires.toUTCString()), t = encodeURIComponent(t).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
24
+ var a = "";
25
+ for (var l in r)
26
+ r[l] && (a += "; " + l, r[l] !== !0 && (a += "=" + r[l].split(";")[0]));
27
+ return document.cookie = t + "=" + o.write(n, t) + a;
28
28
  }
29
29
  }
30
- function s(i) {
31
- if (!(typeof document > "u" || arguments.length && !i)) {
32
- for (var o = document.cookie ? document.cookie.split("; ") : [], n = {}, u = 0; u < o.length; u++) {
33
- var l = o[u].split("="), m = l.slice(1).join("=");
30
+ function s(t) {
31
+ if (!(typeof document > "u" || arguments.length && !t)) {
32
+ for (var n = document.cookie ? document.cookie.split("; ") : [], r = {}, a = 0; a < n.length; a++) {
33
+ var l = n[a].split("="), d = l.slice(1).join("=");
34
34
  try {
35
35
  var h = decodeURIComponent(l[0]);
36
- if (n[h] = r.read(m, h), i === h)
36
+ if (r[h] = o.read(d, h), t === h)
37
37
  break;
38
38
  } catch {
39
39
  }
40
40
  }
41
- return i ? n[i] : n;
41
+ return t ? r[t] : r;
42
42
  }
43
43
  }
44
44
  return Object.create(
45
45
  {
46
- set: t,
46
+ set: i,
47
47
  get: s,
48
- remove: function(i, o) {
49
- t(
50
- i,
48
+ remove: function(t, n) {
49
+ i(
50
+ t,
51
51
  "",
52
- d({}, o, {
52
+ p({}, n, {
53
53
  expires: -1
54
54
  })
55
55
  );
56
56
  },
57
- withAttributes: function(i) {
58
- return f(this.converter, d({}, this.attributes, i));
57
+ withAttributes: function(t) {
58
+ return m(this.converter, p({}, this.attributes, t));
59
59
  },
60
- withConverter: function(i) {
61
- return f(d({}, this.converter, i), this.attributes);
60
+ withConverter: function(t) {
61
+ return m(p({}, this.converter, t), this.attributes);
62
62
  }
63
63
  },
64
64
  {
65
65
  attributes: { value: Object.freeze(e) },
66
- converter: { value: Object.freeze(r) }
66
+ converter: { value: Object.freeze(o) }
67
67
  }
68
68
  );
69
69
  }
70
- var a = f(v, { path: "/" });
71
- const c = {
70
+ var c = m(w, { path: "/" });
71
+ const u = {
72
72
  USER_ID: "__fp_uid",
73
73
  SESSION_ID: "__fp_sid",
74
74
  SESSION_START: "__fp_ss",
75
75
  CONSENT: "__fp_consent",
76
76
  UTM: "__fp_utm"
77
- }, p = 1 / 48, I = 365, S = 365, w = 30;
77
+ }, g = 1 / 48, y = 365, I = 365, b = 30;
78
78
  function k() {
79
79
  return typeof window < "u";
80
80
  }
81
- function g(r) {
82
- if (!r)
81
+ function v(o) {
82
+ if (!o)
83
83
  return null;
84
84
  try {
85
- return JSON.parse(r);
85
+ return JSON.parse(o);
86
86
  } catch {
87
87
  return null;
88
88
  }
89
89
  }
90
- class D {
90
+ class S {
91
91
  initSession() {
92
- const e = !!a.get(c.USER_ID);
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: p }), a.set(c.SESSION_START, String(s), { expires: p }), { sessionId: t, sessionStart: s, isReturningUser: e };
92
+ const e = !!c.get(u.USER_ID);
93
+ let i = c.get(u.SESSION_ID) ?? null, s = Number(c.get(u.SESSION_START) || Date.now());
94
+ return i || (i = crypto.randomUUID(), s = Date.now()), c.set(u.SESSION_ID, i, { expires: g }), c.set(u.SESSION_START, String(s), { expires: g }), { sessionId: i, sessionStart: s, isReturningUser: e };
95
95
  }
96
96
  initUser() {
97
- let e = a.get(c.USER_ID) ?? null;
98
- return e || (e = crypto.randomUUID(), a.set(c.USER_ID, e, { expires: S })), e;
97
+ let e = c.get(u.USER_ID) ?? null;
98
+ return e || (e = crypto.randomUUID(), c.set(u.USER_ID, e, { expires: I })), e;
99
99
  }
100
100
  getConsent() {
101
- return g(a.get(c.CONSENT));
101
+ return v(c.get(u.CONSENT));
102
102
  }
103
103
  setConsent(e) {
104
- const t = {
104
+ const i = {
105
105
  necessary: !0,
106
106
  analytics: e.analytics,
107
107
  marketing: e.marketing,
108
108
  version: e.version,
109
109
  timestamp: Date.now()
110
110
  };
111
- return a.set(c.CONSENT, JSON.stringify(t), { expires: I }), t;
111
+ return c.set(u.CONSENT, JSON.stringify(i), { expires: y }), i;
112
112
  }
113
113
  clearAnalyticsCookies() {
114
- a.remove(c.USER_ID);
114
+ c.remove(u.USER_ID);
115
115
  }
116
116
  isConsentExpired() {
117
117
  const e = this.getConsent();
118
118
  if (!e)
119
119
  return !0;
120
- const t = 365 * 24 * 60 * 60 * 1e3;
121
- return Date.now() - e.timestamp > t;
120
+ const i = 365 * 24 * 60 * 60 * 1e3;
121
+ return Date.now() - e.timestamp > i;
122
122
  }
123
123
  captureUTM() {
124
124
  if (!k())
125
125
  return null;
126
- const e = new URLSearchParams(window.location.search), t = {};
126
+ const e = new URLSearchParams(window.location.search), i = {};
127
127
  for (const s of ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]) {
128
- const i = e.get(s);
129
- i && (t[s] = i);
128
+ const t = e.get(s);
129
+ t && (i[s] = t);
130
130
  }
131
- return Object.keys(t).length === 0 ? g(a.get(c.UTM)) : (a.set(c.UTM, JSON.stringify(t), { expires: w }), t);
131
+ return Object.keys(i).length === 0 ? v(c.get(u.UTM)) : (c.set(u.UTM, JSON.stringify(i), { expires: b }), i);
132
132
  }
133
133
  getAllData(e) {
134
- const { sessionId: t, sessionStart: s, isReturningUser: i } = this.initSession();
134
+ const { sessionId: i, sessionStart: s, isReturningUser: t } = this.initSession();
135
135
  return {
136
136
  userId: e ? this.initUser() : null,
137
- sessionId: t,
137
+ sessionId: i,
138
138
  sessionStart: s,
139
139
  consent: this.getConsent(),
140
140
  utm: this.captureUTM(),
141
- isReturningUser: e ? i : !1
141
+ isReturningUser: e ? t : !1
142
142
  };
143
143
  }
144
144
  }
145
+ class D {
146
+ constructor() {
147
+ this.cursorEl = null;
148
+ }
149
+ createCursor() {
150
+ if (this.cursorEl)
151
+ return this.cursorEl;
152
+ const e = document.createElement("div");
153
+ return e.id = "__fp_bot_cursor", e.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M5 3l14 9-7 1-4 7L5 3z" fill="#6366f1" stroke="white" stroke-width="1.5"/></svg>', Object.assign(e.style, {
154
+ position: "fixed",
155
+ zIndex: "999999",
156
+ pointerEvents: "none",
157
+ transition: "left 0.6s ease, top 0.6s ease",
158
+ transform: "translate(-4px,-4px)",
159
+ left: "50%",
160
+ top: "50%",
161
+ opacity: "0"
162
+ }), document.body.appendChild(e), this.cursorEl = e, e;
163
+ }
164
+ async moveTo(e, i) {
165
+ const s = this.createCursor();
166
+ s.style.left = `${e}px`, s.style.top = `${i}px`, await new Promise((t) => setTimeout(t, 700));
167
+ }
168
+ async clickAnimation(e, i) {
169
+ if (!document.getElementById("__fp_cursor_styles")) {
170
+ const t = document.createElement("style");
171
+ t.id = "__fp_cursor_styles", t.textContent = "@keyframes fp-ripple{from{transform:scale(0);opacity:1}to{transform:scale(2);opacity:0}}", document.head.appendChild(t);
172
+ }
173
+ const s = document.createElement("div");
174
+ Object.assign(s.style, {
175
+ position: "fixed",
176
+ left: `${e - 16}px`,
177
+ top: `${i - 16}px`,
178
+ width: "32px",
179
+ height: "32px",
180
+ borderRadius: "50%",
181
+ background: "rgba(99,102,241,0.4)",
182
+ zIndex: "999998",
183
+ pointerEvents: "none",
184
+ animation: "fp-ripple 0.4s ease-out forwards"
185
+ }), document.body.appendChild(s), await new Promise((t) => setTimeout(t, 400)), s.remove();
186
+ }
187
+ async typeText(e, i) {
188
+ e.focus(), (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && (e.value = "");
189
+ for (const s of i)
190
+ await new Promise((t) => setTimeout(t, 60 + Math.random() * 40)), (e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement) && (e.value += s, e.dispatchEvent(new Event("input", { bubbles: !0 })));
191
+ }
192
+ async perform(e) {
193
+ try {
194
+ const i = this.createCursor();
195
+ if (i.style.opacity = "1", e.type === "navigate" && e.value)
196
+ return await this.moveTo(window.innerWidth / 2, window.innerHeight / 2), await new Promise((d) => setTimeout(d, 300)), this.destroy(), window.location.href = e.value, { success: !0, message: `Navigating to ${e.value}...` };
197
+ if (!e.selector)
198
+ return { success: !1, message: "No target element specified." };
199
+ const t = !/[#.\[\]\s>:+~]/.test(e.selector) ? `[data-fp-id="${e.selector}"], #${e.selector}, [name="${e.selector}"]` : e.selector, n = document.querySelector(t);
200
+ if (!n)
201
+ return { success: !1, message: `Could not find "${e.label}" on the page.` };
202
+ const r = n.getBoundingClientRect(), a = r.left + r.width / 2, l = r.top + r.height / 2;
203
+ if (await this.moveTo(a, l), e.type === "click" && (await this.clickAnimation(a, l), n.click(), n.dispatchEvent(new MouseEvent("click", { bubbles: !0, cancelable: !0 }))), e.type === "scroll") {
204
+ n.scrollIntoView({ behavior: "smooth", block: "center" });
205
+ const d = n.style.outline, h = n.style.outlineOffset;
206
+ n.style.outline = "2px solid #6366f1", n.style.outlineOffset = "3px", await new Promise((f) => setTimeout(f, 1500)), n.style.outline = d, n.style.outlineOffset = h;
207
+ }
208
+ if (e.type === "fill" && e.value && await this.typeText(n, e.value), e.type === "highlight") {
209
+ n.scrollIntoView({ behavior: "smooth", block: "center" });
210
+ const d = n.style.outline, h = n.style.outlineOffset;
211
+ n.style.outline = "2px solid #6366f1", n.style.outlineOffset = "3px", await new Promise((f) => setTimeout(f, 1500)), n.style.outline = d, n.style.outlineOffset = h;
212
+ }
213
+ return await new Promise((d) => setTimeout(d, 400)), this.destroy(), { success: !0, message: `Done! I ${e.type}ed "${e.label}".` };
214
+ } catch {
215
+ return this.destroy(), { success: !1, message: "Something went wrong performing that action." };
216
+ }
217
+ }
218
+ destroy() {
219
+ this.cursorEl?.remove(), this.cursorEl = null;
220
+ }
221
+ }
145
222
  class _ {
146
223
  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, this.config = {
224
+ 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 S(), this.cookieData = null, this.analyticsConsented = !1, this.isInitialized = !1, this.beforeUnloadListener = null, this.visibilityListener = null, this.config = {
148
225
  proxyEndpoint: e.proxyEndpoint ?? "/api/fp-proxy",
149
226
  batchInterval: e.batchInterval ?? 5e3,
150
227
  debug: e.debug ?? !1
@@ -155,54 +232,54 @@ class _ {
155
232
  }
156
233
  attachGlobalListeners() {
157
234
  document.addEventListener("click", (s) => {
158
- const i = s.target.closest("[data-fp-id]");
159
- i && this.track("click", i.getAttribute("data-fp-id"), {
235
+ const t = s.target.closest("[data-fp-id]");
236
+ t && this.track("click", t.getAttribute("data-fp-id"), {
160
237
  x: s.clientX,
161
238
  y: s.clientY
162
239
  });
163
240
  }, { passive: !0 });
164
- let e = 0, t = null;
241
+ let e = 0, i = null;
165
242
  document.addEventListener("mouseover", (s) => {
166
- const i = s.target.closest("[data-fp-id]");
167
- i && (e = Date.now(), t = i.getAttribute("data-fp-id"));
243
+ const t = s.target.closest("[data-fp-id]");
244
+ t && (e = Date.now(), i = t.getAttribute("data-fp-id"));
168
245
  }, { passive: !0 }), document.addEventListener("mouseout", (s) => {
169
- if (!s.target.closest("[data-fp-id]") || !t)
246
+ if (!s.target.closest("[data-fp-id]") || !i)
170
247
  return;
171
- const o = Date.now() - e;
172
- o > 500 && this.track("hover", t, { hoverDuration: o }), t = null;
248
+ const n = Date.now() - e;
249
+ n > 500 && this.track("hover", i, { hoverDuration: n }), i = null;
173
250
  }, { passive: !0 });
174
251
  }
175
252
  observeDOM() {
176
- const e = (i) => {
177
- this.seenInView.has(i) || (this.seenInView.add(i), this.track("scroll_into_view", i, {
253
+ const e = (t) => {
254
+ this.seenInView.has(t) || (this.seenInView.add(t), this.track("scroll_into_view", t, {
178
255
  scrollDepth: Math.round(window.scrollY / Math.max(1, document.body.scrollHeight) * 100)
179
256
  }));
180
257
  };
181
- this.intersectionObserver = new IntersectionObserver((i) => {
182
- for (const o of i) {
183
- const n = o.target.dataset.fpId;
184
- !n || !o.isIntersecting || e(n);
258
+ this.intersectionObserver = new IntersectionObserver((t) => {
259
+ for (const n of t) {
260
+ const r = n.target.dataset.fpId;
261
+ !r || !n.isIntersecting || e(r);
185
262
  }
186
263
  }, { threshold: 0.1 });
187
- const t = () => {
188
- document.querySelectorAll("[data-fp-id]").forEach((i) => {
189
- this.intersectionObserver?.observe(i);
264
+ const i = () => {
265
+ document.querySelectorAll("[data-fp-id]").forEach((t) => {
266
+ this.intersectionObserver?.observe(t);
190
267
  });
191
268
  }, s = () => {
192
- const i = window.innerHeight * 0.1, o = window.innerHeight * 0.9;
193
- document.querySelectorAll("[data-fp-id]").forEach((n) => {
194
- const u = n.dataset.fpId;
195
- if (!u || this.seenInView.has(u))
269
+ const t = window.innerHeight * 0.1, n = window.innerHeight * 0.9;
270
+ document.querySelectorAll("[data-fp-id]").forEach((r) => {
271
+ const a = r.dataset.fpId;
272
+ if (!a || this.seenInView.has(a))
196
273
  return;
197
- const l = n.getBoundingClientRect();
198
- l.bottom >= i && l.top <= o && e(u);
274
+ const l = r.getBoundingClientRect();
275
+ l.bottom >= t && l.top <= n && e(a);
199
276
  });
200
277
  };
201
- 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 });
278
+ i(), 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(() => i()), this.observer.observe(document.body, { childList: !0, subtree: !0 });
202
279
  }
203
- track(e, t, s) {
280
+ track(e, i, s) {
204
281
  this.isBrowser() && (this.refreshCookieData(), this.queue.push({
205
- elementId: t,
282
+ elementId: i,
206
283
  eventType: e,
207
284
  sessionId: this.cookieData?.sessionId ?? this.sessionId,
208
285
  visitorId: this.cookieData?.userId ?? null,
@@ -223,8 +300,8 @@ class _ {
223
300
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
224
301
  }));
225
302
  }
226
- trackFeedback(e, t, s) {
227
- this.isBrowser() && (!t && !s || (this.refreshCookieData(), this.sendImmediate([{
303
+ trackFeedback(e, i, s) {
304
+ this.isBrowser() && (!i && !s || (this.refreshCookieData(), this.sendImmediate([{
228
305
  elementId: e ?? "__page__",
229
306
  eventType: "feedback",
230
307
  sessionId: this.cookieData?.sessionId ?? this.sessionId,
@@ -239,7 +316,7 @@ class _ {
239
316
  consentAnalytics: this.cookieData?.consent?.analytics ?? !1,
240
317
  page: window.location.pathname,
241
318
  device: this.getDeviceType(),
242
- metadata: { rating: t, message: s },
319
+ metadata: { rating: i, message: s },
243
320
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
244
321
  }])));
245
322
  }
@@ -251,14 +328,14 @@ class _ {
251
328
  }
252
329
  async sendImmediate(e) {
253
330
  try {
254
- const t = await fetch(this.config.proxyEndpoint, {
331
+ const i = await fetch(this.config.proxyEndpoint, {
255
332
  method: "POST",
256
333
  headers: { "content-type": "application/json" },
257
334
  body: JSON.stringify({ events: e }),
258
335
  keepalive: !0
259
336
  });
260
- if (this.config.debug && t.ok) {
261
- const s = await t.json().catch(() => null);
337
+ if (this.config.debug && i.ok) {
338
+ const s = await i.json().catch(() => null);
262
339
  s?.ingested !== void 0 && s?.pipeline && globalThis.console.debug(`[FeedPulse] ${s.ingested} events via ${s.pipeline} pipeline`);
263
340
  }
264
341
  } catch {
@@ -296,7 +373,8 @@ class _ {
296
373
  }
297
374
  }
298
375
  export {
299
- c as COOKIE_KEYS,
300
- D as CookieManager,
376
+ u as COOKIE_KEYS,
377
+ S as CookieManager,
378
+ D as CursorActor,
301
379
  _ as FeedPulseTracker
302
380
  };