@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.
- package/bin/feedpulse-bot-build.mjs +121 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +171 -93
- package/dist/nuxt.js +2 -2
- package/dist/nuxt.mjs +336 -283
- package/dist/react.js +3 -3
- package/dist/react.mjs +315 -275
- package/dist/server.js +1 -0
- package/dist/server.mjs +18 -0
- package/package.json +11 -2
- package/templates/nuxt-bot-proxy.ts +39 -2
- package/templates/nuxt-config-id-route.ts +15 -0
|
@@ -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
|
|
1
|
+
function p(o) {
|
|
2
2
|
for (var e = 1; e < arguments.length; e++) {
|
|
3
|
-
var
|
|
4
|
-
for (var s in
|
|
5
|
-
|
|
3
|
+
var i = arguments[e];
|
|
4
|
+
for (var s in i)
|
|
5
|
+
o[s] = i[s];
|
|
6
6
|
}
|
|
7
|
-
return
|
|
7
|
+
return o;
|
|
8
8
|
}
|
|
9
|
-
var
|
|
10
|
-
read: function(
|
|
11
|
-
return
|
|
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(
|
|
14
|
-
return encodeURIComponent(
|
|
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
|
|
21
|
-
function t
|
|
20
|
+
function m(o, e) {
|
|
21
|
+
function i(t, n, r) {
|
|
22
22
|
if (!(typeof document > "u")) {
|
|
23
|
-
|
|
24
|
-
var
|
|
25
|
-
for (var l in
|
|
26
|
-
|
|
27
|
-
return document.cookie =
|
|
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(
|
|
31
|
-
if (!(typeof document > "u" || arguments.length && !
|
|
32
|
-
for (var
|
|
33
|
-
var l =
|
|
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 (
|
|
36
|
+
if (r[h] = o.read(d, h), t === h)
|
|
37
37
|
break;
|
|
38
38
|
} catch {
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
return
|
|
41
|
+
return t ? r[t] : r;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
return Object.create(
|
|
45
45
|
{
|
|
46
|
-
set:
|
|
46
|
+
set: i,
|
|
47
47
|
get: s,
|
|
48
|
-
remove: function(
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
remove: function(t, n) {
|
|
49
|
+
i(
|
|
50
|
+
t,
|
|
51
51
|
"",
|
|
52
|
-
|
|
52
|
+
p({}, n, {
|
|
53
53
|
expires: -1
|
|
54
54
|
})
|
|
55
55
|
);
|
|
56
56
|
},
|
|
57
|
-
withAttributes: function(
|
|
58
|
-
return
|
|
57
|
+
withAttributes: function(t) {
|
|
58
|
+
return m(this.converter, p({}, this.attributes, t));
|
|
59
59
|
},
|
|
60
|
-
withConverter: function(
|
|
61
|
-
return
|
|
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(
|
|
66
|
+
converter: { value: Object.freeze(o) }
|
|
67
67
|
}
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
|
-
var
|
|
71
|
-
const
|
|
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
|
-
},
|
|
77
|
+
}, g = 1 / 48, y = 365, I = 365, b = 30;
|
|
78
78
|
function k() {
|
|
79
79
|
return typeof window < "u";
|
|
80
80
|
}
|
|
81
|
-
function
|
|
82
|
-
if (!
|
|
81
|
+
function v(o) {
|
|
82
|
+
if (!o)
|
|
83
83
|
return null;
|
|
84
84
|
try {
|
|
85
|
-
return JSON.parse(
|
|
85
|
+
return JSON.parse(o);
|
|
86
86
|
} catch {
|
|
87
87
|
return null;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
class
|
|
90
|
+
class S {
|
|
91
91
|
initSession() {
|
|
92
|
-
const e = !!
|
|
93
|
-
let
|
|
94
|
-
return
|
|
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 =
|
|
98
|
-
return e || (e = crypto.randomUUID(),
|
|
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
|
|
101
|
+
return v(c.get(u.CONSENT));
|
|
102
102
|
}
|
|
103
103
|
setConsent(e) {
|
|
104
|
-
const
|
|
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
|
|
111
|
+
return c.set(u.CONSENT, JSON.stringify(i), { expires: y }), i;
|
|
112
112
|
}
|
|
113
113
|
clearAnalyticsCookies() {
|
|
114
|
-
|
|
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
|
|
121
|
-
return Date.now() - e.timestamp >
|
|
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),
|
|
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
|
|
129
|
-
|
|
128
|
+
const t = e.get(s);
|
|
129
|
+
t && (i[s] = t);
|
|
130
130
|
}
|
|
131
|
-
return Object.keys(
|
|
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:
|
|
134
|
+
const { sessionId: i, sessionStart: s, isReturningUser: t } = this.initSession();
|
|
135
135
|
return {
|
|
136
136
|
userId: e ? this.initUser() : null,
|
|
137
|
-
sessionId:
|
|
137
|
+
sessionId: i,
|
|
138
138
|
sessionStart: s,
|
|
139
139
|
consent: this.getConsent(),
|
|
140
140
|
utm: this.captureUTM(),
|
|
141
|
-
isReturningUser: e ?
|
|
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
|
|
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
|
|
159
|
-
|
|
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,
|
|
241
|
+
let e = 0, i = null;
|
|
165
242
|
document.addEventListener("mouseover", (s) => {
|
|
166
|
-
const
|
|
167
|
-
|
|
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]") || !
|
|
246
|
+
if (!s.target.closest("[data-fp-id]") || !i)
|
|
170
247
|
return;
|
|
171
|
-
const
|
|
172
|
-
|
|
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 = (
|
|
177
|
-
this.seenInView.has(
|
|
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((
|
|
182
|
-
for (const
|
|
183
|
-
const
|
|
184
|
-
!
|
|
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
|
|
188
|
-
document.querySelectorAll("[data-fp-id]").forEach((
|
|
189
|
-
this.intersectionObserver?.observe(
|
|
264
|
+
const i = () => {
|
|
265
|
+
document.querySelectorAll("[data-fp-id]").forEach((t) => {
|
|
266
|
+
this.intersectionObserver?.observe(t);
|
|
190
267
|
});
|
|
191
268
|
}, s = () => {
|
|
192
|
-
const
|
|
193
|
-
document.querySelectorAll("[data-fp-id]").forEach((
|
|
194
|
-
const
|
|
195
|
-
if (!
|
|
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 =
|
|
198
|
-
l.bottom >=
|
|
274
|
+
const l = r.getBoundingClientRect();
|
|
275
|
+
l.bottom >= t && l.top <= n && e(a);
|
|
199
276
|
});
|
|
200
277
|
};
|
|
201
|
-
|
|
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,
|
|
280
|
+
track(e, i, s) {
|
|
204
281
|
this.isBrowser() && (this.refreshCookieData(), this.queue.push({
|
|
205
|
-
elementId:
|
|
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,
|
|
227
|
-
this.isBrowser() && (!
|
|
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:
|
|
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
|
|
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 &&
|
|
261
|
-
const s = await
|
|
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
|
-
|
|
300
|
-
|
|
376
|
+
u as COOKIE_KEYS,
|
|
377
|
+
S as CookieManager,
|
|
378
|
+
D as CursorActor,
|
|
301
379
|
_ as FeedPulseTracker
|
|
302
380
|
};
|