@tekibo/feedpulse-sdk 0.7.1 → 0.8.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 +83 -83
- package/dist/core/cookies.d.ts +37 -0
- package/dist/core/struggle-detector.d.ts +33 -0
- package/dist/core/tracker.d.ts +38 -0
- package/dist/core/types.d.ts +59 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +129 -100
- package/dist/nuxt/BotPanel.vue.d.ts +17 -0
- package/dist/nuxt/FeedPulseBot.vue.d.ts +24 -0
- package/dist/nuxt/FeedPulseProvider.vue.d.ts +21 -0
- package/dist/nuxt/FeedPulseWidget.vue.d.ts +10 -0
- package/dist/nuxt/composables.d.ts +4 -0
- package/dist/nuxt/consent-banner.vue.d.ts +16 -0
- package/dist/nuxt/index.d.ts +5 -0
- package/dist/nuxt.d.ts +2 -0
- package/dist/nuxt.js +1 -1
- package/dist/nuxt.mjs +2 -2
- package/dist/react/FeedPulseBot.d.ts +21 -0
- package/dist/react/FeedPulseProvider.d.ts +13 -0
- package/dist/react/FeedPulseWidget.d.ts +8 -0
- package/dist/react/consent-banner.d.ts +11 -0
- package/dist/react/hooks.d.ts +1 -0
- package/dist/react/index.d.ts +4 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +1 -1
- package/dist/react.mjs +1 -1
- package/dist/struggle-detector-CT3YShuG.js +1 -0
- package/dist/{struggle-detector-BqTHgw95.mjs → struggle-detector-Cwe3PD9s.mjs} +40 -25
- package/package.json +3 -1
- package/templates/nextjs-proxy.ts +36 -36
- package/templates/nuxt-bot-proxy.ts +60 -56
- package/templates/nuxt-proxy.ts +44 -44
- package/dist/struggle-detector-DV52qDLp.js +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
function
|
|
1
|
+
function h(r) {
|
|
2
2
|
for (var e = 1; e < arguments.length; e++) {
|
|
3
|
-
var
|
|
4
|
-
for (var
|
|
5
|
-
r[
|
|
3
|
+
var i = arguments[e];
|
|
4
|
+
for (var t in i)
|
|
5
|
+
t !== "__proto__" && (r[t] = i[t]);
|
|
6
6
|
}
|
|
7
7
|
return r;
|
|
8
8
|
}
|
|
9
|
-
var
|
|
9
|
+
var g = {
|
|
10
10
|
read: function(r) {
|
|
11
11
|
return r[0] === '"' && (r = r.slice(1, -1)), r.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
|
|
12
12
|
},
|
|
@@ -18,47 +18,47 @@ var v = {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
function f(r, e) {
|
|
21
|
-
function
|
|
21
|
+
function i(n, a, s) {
|
|
22
22
|
if (!(typeof document > "u")) {
|
|
23
|
-
|
|
24
|
-
var
|
|
25
|
-
for (var
|
|
26
|
-
|
|
27
|
-
return document.cookie =
|
|
23
|
+
s = h({}, e, s), typeof s.expires == "number" && (s.expires = new Date(Date.now() + s.expires * 864e5)), s.expires && (s.expires = s.expires.toUTCString()), n = encodeURIComponent(n).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
|
|
24
|
+
var l = "";
|
|
25
|
+
for (var u in s)
|
|
26
|
+
s[u] && (l += "; " + u, s[u] !== !0 && (l += "=" + s[u].split(";")[0]));
|
|
27
|
+
return document.cookie = n + "=" + r.write(a, n) + l;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
if (!(typeof document > "u" || arguments.length && !
|
|
32
|
-
for (var
|
|
33
|
-
var
|
|
30
|
+
function t(n) {
|
|
31
|
+
if (!(typeof document > "u" || arguments.length && !n)) {
|
|
32
|
+
for (var a = document.cookie ? document.cookie.split("; ") : [], s = {}, l = 0; l < a.length; l++) {
|
|
33
|
+
var u = a[l].split("="), m = u.slice(1).join("=");
|
|
34
34
|
try {
|
|
35
|
-
var
|
|
36
|
-
if (
|
|
35
|
+
var d = decodeURIComponent(u[0]);
|
|
36
|
+
if (d in s || (s[d] = r.read(m, d)), n === d)
|
|
37
37
|
break;
|
|
38
38
|
} catch {
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
return
|
|
41
|
+
return n ? s[n] : s;
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
return Object.create(
|
|
45
45
|
{
|
|
46
|
-
set:
|
|
47
|
-
get:
|
|
48
|
-
remove: function(
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
set: i,
|
|
47
|
+
get: t,
|
|
48
|
+
remove: function(n, a) {
|
|
49
|
+
i(
|
|
50
|
+
n,
|
|
51
51
|
"",
|
|
52
|
-
|
|
52
|
+
h({}, a, {
|
|
53
53
|
expires: -1
|
|
54
54
|
})
|
|
55
55
|
);
|
|
56
56
|
},
|
|
57
|
-
withAttributes: function(
|
|
58
|
-
return f(this.converter,
|
|
57
|
+
withAttributes: function(n) {
|
|
58
|
+
return f(this.converter, h({}, this.attributes, n));
|
|
59
59
|
},
|
|
60
|
-
withConverter: function(
|
|
61
|
-
return f(
|
|
60
|
+
withConverter: function(n) {
|
|
61
|
+
return f(h({}, this.converter, n), this.attributes);
|
|
62
62
|
}
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -67,18 +67,18 @@ function f(r, e) {
|
|
|
67
67
|
}
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
|
-
var
|
|
71
|
-
const
|
|
70
|
+
var c = f(g, { path: "/" });
|
|
71
|
+
const o = {
|
|
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,
|
|
78
|
-
function
|
|
77
|
+
}, p = 1 / 48, S = 365, I = 365, k = 30;
|
|
78
|
+
function w() {
|
|
79
79
|
return typeof window < "u";
|
|
80
80
|
}
|
|
81
|
-
function
|
|
81
|
+
function v(r) {
|
|
82
82
|
if (!r)
|
|
83
83
|
return null;
|
|
84
84
|
try {
|
|
@@ -88,63 +88,92 @@ function g(r) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
class D {
|
|
91
|
+
transientSession = null;
|
|
91
92
|
initSession() {
|
|
92
|
-
const e = !!
|
|
93
|
-
let
|
|
94
|
-
return
|
|
93
|
+
const e = !!c.get(o.USER_ID);
|
|
94
|
+
let i = c.get(o.SESSION_ID) ?? null, t = Number(c.get(o.SESSION_START) || Date.now());
|
|
95
|
+
return i || (i = crypto.randomUUID(), t = Date.now()), c.set(o.SESSION_ID, i, { expires: p }), c.set(o.SESSION_START, String(t), { expires: p }), { sessionId: i, sessionStart: t, isReturningUser: e };
|
|
95
96
|
}
|
|
96
97
|
initUser() {
|
|
97
|
-
let e =
|
|
98
|
-
return e || (e = crypto.randomUUID(),
|
|
98
|
+
let e = c.get(o.USER_ID) ?? null;
|
|
99
|
+
return e || (e = crypto.randomUUID(), c.set(o.USER_ID, e, { expires: I })), e;
|
|
99
100
|
}
|
|
100
101
|
getConsent() {
|
|
101
|
-
return
|
|
102
|
+
return v(c.get(o.CONSENT));
|
|
102
103
|
}
|
|
103
104
|
setConsent(e) {
|
|
104
|
-
const
|
|
105
|
+
const i = {
|
|
105
106
|
necessary: !0,
|
|
106
107
|
analytics: e.analytics,
|
|
107
108
|
marketing: e.marketing,
|
|
108
109
|
version: e.version,
|
|
109
110
|
timestamp: Date.now()
|
|
110
111
|
};
|
|
111
|
-
return
|
|
112
|
+
return c.set(o.CONSENT, JSON.stringify(i), { expires: S }), i;
|
|
112
113
|
}
|
|
113
114
|
clearAnalyticsCookies() {
|
|
114
|
-
|
|
115
|
+
for (const e of [o.USER_ID, o.SESSION_ID, o.SESSION_START, o.UTM])
|
|
116
|
+
c.remove(e);
|
|
117
|
+
this.transientSession = null;
|
|
115
118
|
}
|
|
116
119
|
isConsentExpired() {
|
|
117
120
|
const e = this.getConsent();
|
|
118
121
|
if (!e)
|
|
119
122
|
return !0;
|
|
120
|
-
const
|
|
121
|
-
return Date.now() - e.timestamp >
|
|
123
|
+
const i = 365 * 24 * 60 * 60 * 1e3;
|
|
124
|
+
return Date.now() - e.timestamp > i;
|
|
122
125
|
}
|
|
123
126
|
captureUTM() {
|
|
124
|
-
if (!
|
|
127
|
+
if (!w())
|
|
125
128
|
return null;
|
|
126
|
-
const e = new URLSearchParams(window.location.search),
|
|
127
|
-
for (const
|
|
128
|
-
const
|
|
129
|
-
|
|
129
|
+
const e = new URLSearchParams(window.location.search), i = {};
|
|
130
|
+
for (const t of ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"]) {
|
|
131
|
+
const n = e.get(t);
|
|
132
|
+
n && (i[t] = n);
|
|
130
133
|
}
|
|
131
|
-
return Object.keys(
|
|
134
|
+
return Object.keys(i).length === 0 ? v(c.get(o.UTM)) : (c.set(o.UTM, JSON.stringify(i), { expires: k }), i);
|
|
132
135
|
}
|
|
133
136
|
getAllData(e) {
|
|
134
|
-
|
|
137
|
+
if (!e)
|
|
138
|
+
return this.transientSession === null && (this.transientSession = { sessionId: crypto.randomUUID(), sessionStart: Date.now() }), {
|
|
139
|
+
userId: null,
|
|
140
|
+
...this.transientSession,
|
|
141
|
+
consent: this.getConsent(),
|
|
142
|
+
utm: null,
|
|
143
|
+
isReturningUser: !1
|
|
144
|
+
};
|
|
145
|
+
const { sessionId: i, sessionStart: t, isReturningUser: n } = this.initSession();
|
|
135
146
|
return {
|
|
136
147
|
userId: e ? this.initUser() : null,
|
|
137
|
-
sessionId:
|
|
138
|
-
sessionStart:
|
|
148
|
+
sessionId: i,
|
|
149
|
+
sessionStart: t,
|
|
139
150
|
consent: this.getConsent(),
|
|
140
151
|
utm: this.captureUTM(),
|
|
141
|
-
isReturningUser: e ?
|
|
152
|
+
isReturningUser: e ? n : !1
|
|
142
153
|
};
|
|
143
154
|
}
|
|
144
155
|
}
|
|
145
156
|
class _ {
|
|
157
|
+
config;
|
|
158
|
+
queue = [];
|
|
159
|
+
flushInterval = null;
|
|
160
|
+
sessionId = "";
|
|
161
|
+
observer = null;
|
|
162
|
+
intersectionObserver = null;
|
|
163
|
+
scrollFallbackListener = null;
|
|
164
|
+
resizeFallbackListener = null;
|
|
165
|
+
seenInView = /* @__PURE__ */ new Set();
|
|
166
|
+
cookieManager = new D();
|
|
167
|
+
cookieData = null;
|
|
168
|
+
analyticsConsented = !1;
|
|
169
|
+
isInitialized = !1;
|
|
170
|
+
beforeUnloadListener = null;
|
|
171
|
+
visibilityListener = null;
|
|
172
|
+
clickListener = null;
|
|
173
|
+
hoverStartListener = null;
|
|
174
|
+
hoverEndListener = null;
|
|
146
175
|
constructor(e) {
|
|
147
|
-
this.
|
|
176
|
+
this.config = {
|
|
148
177
|
proxyEndpoint: e.proxyEndpoint ?? "/api/fp-proxy",
|
|
149
178
|
batchInterval: e.batchInterval ?? 5e3,
|
|
150
179
|
debug: e.debug ?? !1
|
|
@@ -154,55 +183,55 @@ class _ {
|
|
|
154
183
|
!this.isBrowser() || this.isInitialized || (this.isInitialized = !0, this.refreshCookieData(), this.startFlushInterval(), this.attachGlobalListeners(), this.observeDOM());
|
|
155
184
|
}
|
|
156
185
|
attachGlobalListeners() {
|
|
157
|
-
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
x:
|
|
161
|
-
y:
|
|
186
|
+
this.clickListener = (t) => {
|
|
187
|
+
const n = t.target instanceof Element ? t.target.closest("[data-fp-id]") : null;
|
|
188
|
+
n && this.track("click", n.getAttribute("data-fp-id"), {
|
|
189
|
+
x: t.clientX,
|
|
190
|
+
y: t.clientY
|
|
162
191
|
});
|
|
163
|
-
}, { passive: !0 });
|
|
164
|
-
let e = 0,
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
}, { passive: !0 }),
|
|
169
|
-
if (!
|
|
192
|
+
}, document.addEventListener("click", this.clickListener, { passive: !0 });
|
|
193
|
+
let e = 0, i = null;
|
|
194
|
+
this.hoverStartListener = (t) => {
|
|
195
|
+
const n = t.target instanceof Element ? t.target.closest("[data-fp-id]") : null;
|
|
196
|
+
n && (e = Date.now(), i = n.getAttribute("data-fp-id"));
|
|
197
|
+
}, document.addEventListener("mouseover", this.hoverStartListener, { passive: !0 }), this.hoverEndListener = (t) => {
|
|
198
|
+
if (!(t.target instanceof Element ? t.target.closest("[data-fp-id]") : null) || !i)
|
|
170
199
|
return;
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
}, { passive: !0 });
|
|
200
|
+
const a = Date.now() - e;
|
|
201
|
+
a > 500 && this.track("hover", i, { hoverDuration: a }), i = null;
|
|
202
|
+
}, document.addEventListener("mouseout", this.hoverEndListener, { passive: !0 });
|
|
174
203
|
}
|
|
175
204
|
observeDOM() {
|
|
176
|
-
const e = (
|
|
177
|
-
this.seenInView.has(
|
|
205
|
+
const e = (n) => {
|
|
206
|
+
this.seenInView.has(n) || (this.seenInView.add(n), this.track("scroll_into_view", n, {
|
|
178
207
|
scrollDepth: Math.round(window.scrollY / Math.max(1, document.body.scrollHeight) * 100)
|
|
179
208
|
}));
|
|
180
209
|
};
|
|
181
|
-
this.intersectionObserver = new IntersectionObserver((
|
|
182
|
-
for (const
|
|
183
|
-
const
|
|
184
|
-
!
|
|
210
|
+
this.intersectionObserver = new IntersectionObserver((n) => {
|
|
211
|
+
for (const a of n) {
|
|
212
|
+
const s = a.target.dataset.fpId;
|
|
213
|
+
!s || !a.isIntersecting || e(s);
|
|
185
214
|
}
|
|
186
215
|
}, { threshold: 0.1 });
|
|
187
|
-
const
|
|
188
|
-
document.querySelectorAll("[data-fp-id]").forEach((i) => {
|
|
189
|
-
this.intersectionObserver?.observe(i);
|
|
190
|
-
});
|
|
191
|
-
}, s = () => {
|
|
192
|
-
const i = window.innerHeight * 0.1, o = window.innerHeight * 0.9;
|
|
216
|
+
const i = () => {
|
|
193
217
|
document.querySelectorAll("[data-fp-id]").forEach((n) => {
|
|
194
|
-
|
|
195
|
-
|
|
218
|
+
this.intersectionObserver?.observe(n);
|
|
219
|
+
});
|
|
220
|
+
}, t = () => {
|
|
221
|
+
const n = window.innerHeight * 0.1, a = window.innerHeight * 0.9;
|
|
222
|
+
document.querySelectorAll("[data-fp-id]").forEach((s) => {
|
|
223
|
+
const l = s.dataset.fpId;
|
|
224
|
+
if (!l || this.seenInView.has(l))
|
|
196
225
|
return;
|
|
197
|
-
const
|
|
198
|
-
|
|
226
|
+
const u = s.getBoundingClientRect();
|
|
227
|
+
u.bottom >= n && u.top <= a && e(l);
|
|
199
228
|
});
|
|
200
229
|
};
|
|
201
|
-
|
|
230
|
+
i(), t(), this.scrollFallbackListener = () => t(), this.resizeFallbackListener = () => t(), 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
231
|
}
|
|
203
|
-
track(e,
|
|
204
|
-
this.isBrowser()
|
|
205
|
-
elementId:
|
|
232
|
+
track(e, i, t) {
|
|
233
|
+
!this.isBrowser() || !this.analyticsConsented || (this.refreshCookieData(), this.queue.push({
|
|
234
|
+
elementId: i,
|
|
206
235
|
eventType: e,
|
|
207
236
|
sessionId: this.cookieData?.sessionId ?? this.sessionId,
|
|
208
237
|
visitorId: this.cookieData?.userId ?? null,
|
|
@@ -219,12 +248,12 @@ class _ {
|
|
|
219
248
|
device: this.getDeviceType(),
|
|
220
249
|
browser: this.getBrowser(),
|
|
221
250
|
os: this.getOS(),
|
|
222
|
-
metadata:
|
|
251
|
+
metadata: t,
|
|
223
252
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
224
253
|
}));
|
|
225
254
|
}
|
|
226
|
-
trackFeedback(e,
|
|
227
|
-
this.isBrowser() && (!
|
|
255
|
+
trackFeedback(e, i, t) {
|
|
256
|
+
this.isBrowser() && (!i && !t || (this.refreshCookieData(), this.sendImmediate([{
|
|
228
257
|
elementId: e ?? "__page__",
|
|
229
258
|
eventType: "feedback",
|
|
230
259
|
sessionId: this.cookieData?.sessionId ?? this.sessionId,
|
|
@@ -239,7 +268,7 @@ class _ {
|
|
|
239
268
|
consentAnalytics: this.cookieData?.consent?.analytics ?? !1,
|
|
240
269
|
page: window.location.pathname,
|
|
241
270
|
device: this.getDeviceType(),
|
|
242
|
-
metadata: { rating:
|
|
271
|
+
metadata: { rating: i, message: t },
|
|
243
272
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
244
273
|
}])));
|
|
245
274
|
}
|
|
@@ -251,15 +280,15 @@ class _ {
|
|
|
251
280
|
}
|
|
252
281
|
async sendImmediate(e) {
|
|
253
282
|
try {
|
|
254
|
-
const
|
|
283
|
+
const i = await fetch(this.config.proxyEndpoint, {
|
|
255
284
|
method: "POST",
|
|
256
285
|
headers: { "content-type": "application/json" },
|
|
257
286
|
body: JSON.stringify({ events: e }),
|
|
258
287
|
keepalive: !0
|
|
259
288
|
});
|
|
260
|
-
if (this.config.debug &&
|
|
261
|
-
const
|
|
262
|
-
|
|
289
|
+
if (this.config.debug && i.ok) {
|
|
290
|
+
const t = await i.json().catch(() => null);
|
|
291
|
+
t?.ingested !== void 0 && t?.pipeline && globalThis.console.debug(`[FeedPulse] ${t.ingested} events via ${t.pipeline} pipeline`);
|
|
263
292
|
}
|
|
264
293
|
} catch {
|
|
265
294
|
}
|
|
@@ -292,11 +321,11 @@ class _ {
|
|
|
292
321
|
return e.includes("Windows") ? "Windows" : e.includes("Mac") ? "macOS" : e.includes("Linux") ? "Linux" : e.includes("Android") ? "Android" : /iPhone|iOS/.test(e) ? "iOS" : "Other";
|
|
293
322
|
}
|
|
294
323
|
destroy() {
|
|
295
|
-
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();
|
|
324
|
+
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.clickListener && document.removeEventListener("click", this.clickListener), this.hoverStartListener && document.removeEventListener("mouseover", this.hoverStartListener), this.hoverEndListener && document.removeEventListener("mouseout", this.hoverEndListener), this.observer?.disconnect(), this.intersectionObserver?.disconnect(), this.isInitialized = !1, this.flush();
|
|
296
325
|
}
|
|
297
326
|
}
|
|
298
327
|
export {
|
|
299
|
-
|
|
328
|
+
o as COOKIE_KEYS,
|
|
300
329
|
D as CookieManager,
|
|
301
330
|
_ as FeedPulseTracker
|
|
302
331
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BotConfig } from '../core/types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
botSessionId: string;
|
|
4
|
+
config: BotConfig;
|
|
5
|
+
unavailable?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
8
|
+
close: () => any;
|
|
9
|
+
helpful: (value: boolean) => any;
|
|
10
|
+
escalated: () => any;
|
|
11
|
+
}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onClose?: (() => any) | undefined;
|
|
13
|
+
onHelpful?: ((value: boolean) => any) | undefined;
|
|
14
|
+
onEscalated?: (() => any) | undefined;
|
|
15
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BotConfig, BotFaqItem, BotFeature, BotFormField, BotNavigableElement } from '../core/types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
faq?: BotFaqItem[];
|
|
4
|
+
pageContext?: string;
|
|
5
|
+
systemPrompt?: string;
|
|
6
|
+
canNavigate?: boolean;
|
|
7
|
+
navigableElements?: BotNavigableElement[];
|
|
8
|
+
canHelpForms?: boolean;
|
|
9
|
+
formGuide?: BotFormField[];
|
|
10
|
+
features?: BotFeature[];
|
|
11
|
+
escalateTo?: {
|
|
12
|
+
label: string;
|
|
13
|
+
url: string;
|
|
14
|
+
};
|
|
15
|
+
initialMessage?: string;
|
|
16
|
+
position?: "bottom-right" | "bottom-left";
|
|
17
|
+
config?: BotConfig;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
20
|
+
initialMessage: string;
|
|
21
|
+
position: "bottom-right" | "bottom-left";
|
|
22
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
proxyEndpoint?: string;
|
|
3
|
+
debug?: boolean;
|
|
4
|
+
consentRequired?: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare var __VLS_1: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_1) => any;
|
|
9
|
+
};
|
|
10
|
+
declare const __VLS_base: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
11
|
+
proxyEndpoint: string;
|
|
12
|
+
consentRequired: boolean;
|
|
13
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
17
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
18
|
+
new (): {
|
|
19
|
+
$slots: S;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
id?: string;
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
position?: "bottom-right" | "bottom-left" | "inline";
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
7
|
+
position: "bottom-right" | "bottom-left" | "inline";
|
|
8
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ConsentAction = "accept_all" | "reject_all" | "custom" | "withdraw";
|
|
2
|
+
declare const __VLS_export: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
3
|
+
consent: (state: {
|
|
4
|
+
analytics: boolean;
|
|
5
|
+
marketing: boolean;
|
|
6
|
+
action: ConsentAction;
|
|
7
|
+
}) => any;
|
|
8
|
+
}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{
|
|
9
|
+
onConsent?: ((state: {
|
|
10
|
+
analytics: boolean;
|
|
11
|
+
marketing: boolean;
|
|
12
|
+
action: ConsentAction;
|
|
13
|
+
}) => any) | undefined;
|
|
14
|
+
}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
|
|
15
|
+
declare const _default: typeof __VLS_export;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { useFeedPulse } from './composables';
|
|
2
|
+
export { default as FeedPulseBot } from './FeedPulseBot.vue';
|
|
3
|
+
export { default as ConsentBanner } from './consent-banner.vue';
|
|
4
|
+
export { default as FeedPulseProvider } from './FeedPulseProvider.vue';
|
|
5
|
+
export { default as FeedPulseWidget } from './FeedPulseWidget.vue';
|
package/dist/nuxt.d.ts
ADDED
package/dist/nuxt.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),N=require("./index.js"),T=require("./struggle-detector-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),N=require("./index.js"),T=require("./struggle-detector-CT3YShuG.js"),S=Symbol("feedpulse");function B(){return e.inject(S,null)}const P={style:{width:"360px",height:"520px",background:"#111827",color:"#e5e7eb",borderRadius:"16px",border:"1px solid #374151",boxShadow:"0 20px 40px rgba(0,0,0,0.35)",display:"flex",flexDirection:"column",overflow:"hidden",animation:"fp-panel-open 300ms ease-out"}},D={style:{display:"flex",justifyContent:"space-between",alignItems:"center",padding:"12px 14px",borderBottom:"1px solid #374151",background:"#0f172a"}},$={style:{flex:1,overflowY:"auto",padding:"12px",display:"grid",gap:"10px"}},M={key:0,style:{display:"flex",gap:"8px"}},A=["onClick"],I=["onClick"],F={key:0,style:{display:"flex",alignItems:"center",gap:"5px",padding:"4px 0"}},_={key:1,style:{border:"1px solid #f59e0b",background:"#451a03",color:"#fde68a",borderRadius:"10px",padding:"10px",fontSize:"12px"}},R={style:{display:"flex",gap:"8px"}},q=["disabled"],Y=["disabled"],j=["href"],L=e.defineComponent({__name:"BotPanel",props:{botSessionId:{},config:{},unavailable:{type:Boolean}},emits:["close","helpful","escalated"],setup(s,{emit:a}){const r=s,o=a,l=e.ref({}),t=e.ref([]),n=e.ref(""),d=e.ref(!1),m=e.ref(!1),g=e.computed(()=>n.value.trim().length>0&&!d.value&&!r.unavailable&&!m.value);function x(){return t.value.map(i=>({role:i.role,content:i.content}))}async function f(i){if(i.preventDefault(),!g.value)return;const c=n.value.trim();n.value="",t.value.push({id:`user-${Date.now()}`,role:"user",content:c});const p=`assistant-${Date.now()}`;t.value.push({id:p,role:"assistant",content:""}),d.value=!0,m.value=!1;try{const b=await fetch("/api/bot/chat-proxy",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({botSessionId:r.botSessionId,config:JSON.parse(JSON.stringify(r.config)),messages:x()})});if(b.status===402){m.value=!0;const v=t.value.find(w=>w.id===p);v&&(v.content="Service temporarily unavailable.");return}if(!b.ok)throw new Error("Chat request failed");const E=b.body?.getReader();if(!E)throw new Error("Missing stream");const y=new TextDecoder;let u=!1;for(;!u;){const v=await E.read();if(u=v.done,v.value){const w=y.decode(v.value,{stream:!u}),C=t.value.find(z=>z.id===p);C&&(C.content+=w)}}}catch{const b=t.value.find(E=>E.id===p);b&&!b.content&&(b.content="Sorry, I couldn't process that. Please try again.")}finally{d.value=!1}}function k(i,c){l.value[i]=c,o("helpful",c)}function h(){o("escalated")}return e.watch(()=>r.botSessionId,()=>{l.value={},t.value=[],n.value="",m.value=!1}),(i,c)=>(e.openBlock(),e.createElementBlock("div",P,[e.createElementVNode("div",D,[c[2]||(c[2]=e.createElementVNode("div",{style:{display:"grid",gap:"2px"}},[e.createElementVNode("strong",{style:{fontSize:"14px",color:"#fff"}},"Pulse Bot"),e.createElementVNode("span",{style:{fontSize:"11px",color:"#94a3b8"}},"Powered by FeedPulse AI")],-1)),e.createElementVNode("button",{style:{border:"none",background:"transparent",color:"#cbd5e1",cursor:"pointer",fontSize:"18px",lineHeight:"1"},onClick:c[0]||(c[0]=p=>o("close"))}," × ")]),e.createElementVNode("div",$,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.value,p=>(e.openBlock(),e.createElementBlock("div",{key:p.id,style:e.normalizeStyle({display:"grid",justifyItems:p.role==="user"?"end":"start",gap:"6px"})},[e.createElementVNode("div",{style:e.normalizeStyle({maxWidth:"85%",padding:"9px 11px",borderRadius:p.role==="user"?"14px 14px 2px 14px":"14px 14px 14px 2px",background:p.role==="user"?"#4f46e5":"#1f2937",color:"#fff",fontSize:"13px",lineHeight:"1.4",whiteSpace:"pre-wrap"})},e.toDisplayString(p.content),5),p.role==="assistant"?(e.openBlock(),e.createElementBlock("div",M,[e.createElementVNode("button",{style:e.normalizeStyle({border:"1px solid #334155",background:l.value[p.id]===!0?"#16a34a":"#0f172a",color:"#e2e8f0",borderRadius:"8px",fontSize:"12px",padding:"4px 8px",cursor:"pointer"}),onClick:b=>k(p.id,!0)}," 👍 ",12,A),e.createElementVNode("button",{style:e.normalizeStyle({border:"1px solid #334155",background:l.value[p.id]===!1?"#dc2626":"#0f172a",color:"#e2e8f0",borderRadius:"8px",fontSize:"12px",padding:"4px 8px",cursor:"pointer"}),onClick:b=>k(p.id,!1)}," 👎 ",12,I)])):e.createCommentVNode("",!0)],4))),128)),d.value?(e.openBlock(),e.createElementBlock("div",F,[...c[3]||(c[3]=[e.createElementVNode("span",{style:{width:"8px",height:"8px",borderRadius:"999px",background:"#94a3b8",animation:"fp-dot 1s infinite 0ms"}},null,-1),e.createElementVNode("span",{style:{width:"8px",height:"8px",borderRadius:"999px",background:"#94a3b8",animation:"fp-dot 1s infinite 160ms"}},null,-1),e.createElementVNode("span",{style:{width:"8px",height:"8px",borderRadius:"999px",background:"#94a3b8",animation:"fp-dot 1s infinite 320ms"}},null,-1)])])):e.createCommentVNode("",!0),s.unavailable||m.value?(e.openBlock(),e.createElementBlock("div",_," Service temporarily unavailable. ")):e.createCommentVNode("",!0)]),e.createElementVNode("form",{style:{padding:"10px",borderTop:"1px solid #374151",display:"grid",gap:"8px"},onSubmit:f},[e.createElementVNode("div",R,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":c[1]||(c[1]=p=>n.value=p),disabled:d.value||s.unavailable,style:{flex:1,borderRadius:"10px",border:"1px solid #475569",background:"#0f172a",color:"#fff",fontSize:"13px",padding:"8px 10px",outline:"none"},placeholder:"Ask a question..."},null,8,q),[[e.vModelText,n.value]]),e.createElementVNode("button",{type:"submit",disabled:!g.value,style:e.normalizeStyle({border:"none",borderRadius:"10px",background:g.value?"#6366f1":"#334155",color:"#fff",fontWeight:"600",fontSize:"12px",padding:"0 14px",cursor:g.value?"pointer":"not-allowed"})}," Send ",12,Y)]),s.config.escalateTo?(e.openBlock(),e.createElementBlock("a",{key:0,href:s.config.escalateTo.url,style:{color:"#c4b5fd",fontSize:"12px",textDecoration:"none"},onClick:h},e.toDisplayString(s.config.escalateTo.label),9,j)):e.createCommentVNode("",!0)],32)]))}}),O=e.defineComponent({__name:"FeedPulseBot",props:{faq:{},pageContext:{},systemPrompt:{},canNavigate:{type:Boolean},navigableElements:{},canHelpForms:{type:Boolean},formGuide:{},features:{},escalateTo:{},initialMessage:{default:"👋 Need help?"},position:{default:"bottom-right"},config:{}},setup(s){const a=s,r=new N.CookieManager,o=e.ref(!1),l=e.ref(!1),t=e.ref(!1),n=e.ref(!1),d=e.ref(""),m=e.ref(null),g=e.ref(!1);let x=null,f=null;const k=e.computed(()=>a.config??{pageContext:a.pageContext,systemPrompt:a.systemPrompt,faq:a.faq,canNavigate:a.canNavigate,navigableElements:a.navigableElements,canHelpForms:a.canHelpForms,formGuide:a.formGuide,features:a.features,escalateTo:a.escalateTo,initialMessage:a.initialMessage}),h=e.computed(()=>({position:"fixed",bottom:"24px",zIndex:"10000",...a.position==="bottom-left"?{left:"24px"}:{right:"24px"}}));function i(){if(typeof document>"u"||document.getElementById("fp-bot-animations"))return;const y=document.createElement("style");y.id="fp-bot-animations",y.textContent=`
|
|
2
2
|
@keyframes fp-bubble-in {
|
|
3
3
|
0% { opacity: 0; transform: scale(0.8) translateY(6px); }
|
|
4
4
|
100% { opacity: 1; transform: scale(1) translateY(0); }
|
package/dist/nuxt.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { inject as V, defineComponent as D, ref as x, computed as B, watch as U,
|
|
1
|
+
import { inject as V, defineComponent as D, ref as x, computed as B, watch as U, openBlock as r, createElementBlock as g, createElementVNode as t, Fragment as _, renderList as L, normalizeStyle as T, toDisplayString as I, createCommentVNode as w, withDirectives as R, vModelText as O, onMounted as M, onBeforeUnmount as F, createTextVNode as A, createStaticVNode as W, createBlock as N, Teleport as J, vModelCheckbox as j, provide as G, renderSlot as K } from "vue";
|
|
2
2
|
import { CookieManager as Y, FeedPulseTracker as Q } from "./index.mjs";
|
|
3
|
-
import { S as X } from "./struggle-detector-
|
|
3
|
+
import { S as X } from "./struggle-detector-Cwe3PD9s.mjs";
|
|
4
4
|
const q = /* @__PURE__ */ Symbol("feedpulse");
|
|
5
5
|
function Z() {
|
|
6
6
|
return V(q, null);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
type BotConfig = {
|
|
3
|
+
faq?: Array<{
|
|
4
|
+
q: string;
|
|
5
|
+
a: string;
|
|
6
|
+
}>;
|
|
7
|
+
pageContext?: string;
|
|
8
|
+
systemPrompt?: string;
|
|
9
|
+
canNavigate?: boolean;
|
|
10
|
+
canHelpForms?: boolean;
|
|
11
|
+
escalateTo?: {
|
|
12
|
+
label: string;
|
|
13
|
+
url: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
type Props = BotConfig & {
|
|
17
|
+
initialMessage?: string;
|
|
18
|
+
position?: "bottom-right" | "bottom-left";
|
|
19
|
+
};
|
|
20
|
+
export declare function FeedPulseBot({ faq, pageContext, systemPrompt, canNavigate, canHelpForms, escalateTo, initialMessage, position, }: Props): React.JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { FeedPulseTracker } from '../core/tracker';
|
|
3
|
+
type FeedPulseContextValue = {
|
|
4
|
+
tracker: FeedPulseTracker | null;
|
|
5
|
+
};
|
|
6
|
+
export declare function FeedPulseProvider({ proxyEndpoint, debug, consentRequired, children, }: {
|
|
7
|
+
proxyEndpoint?: string;
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
consentRequired?: boolean;
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
export declare function useFeedPulse(): FeedPulseContextValue;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
type FeedPulseWidgetProps = {
|
|
3
|
+
id?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
position?: "bottom-right" | "bottom-left" | "inline";
|
|
6
|
+
};
|
|
7
|
+
export declare function FeedPulseWidget({ id, placeholder, position }: FeedPulseWidgetProps): React.JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type ConsentAction = "accept_all" | "reject_all" | "custom" | "withdraw";
|
|
3
|
+
type ConsentBannerProps = {
|
|
4
|
+
onConsent: (state: {
|
|
5
|
+
analytics: boolean;
|
|
6
|
+
marketing: boolean;
|
|
7
|
+
action: ConsentAction;
|
|
8
|
+
}) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function ConsentBanner({ onConsent }: ConsentBannerProps): React.JSX.Element | null;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useFeedPulse } from './FeedPulseProvider';
|
package/dist/react.d.ts
ADDED