@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/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- function d(r) {
1
+ function h(r) {
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 t in i)
5
+ t !== "__proto__" && (r[t] = i[t]);
6
6
  }
7
7
  return r;
8
8
  }
9
- var v = {
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 t(i, o, n) {
21
+ function i(n, a, s) {
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
+ 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 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 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 h = decodeURIComponent(l[0]);
36
- if (n[h] = r.read(m, h), i === h)
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 i ? n[i] : n;
41
+ return n ? s[n] : s;
42
42
  }
43
43
  }
44
44
  return Object.create(
45
45
  {
46
- set: t,
47
- get: s,
48
- remove: function(i, o) {
49
- t(
50
- i,
46
+ set: i,
47
+ get: t,
48
+ remove: function(n, a) {
49
+ i(
50
+ n,
51
51
  "",
52
- d({}, o, {
52
+ h({}, a, {
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(n) {
58
+ return f(this.converter, h({}, this.attributes, n));
59
59
  },
60
- withConverter: function(i) {
61
- return f(d({}, this.converter, i), this.attributes);
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 a = f(v, { path: "/" });
71
- const c = {
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, I = 365, S = 365, w = 30;
78
- function k() {
77
+ }, p = 1 / 48, S = 365, I = 365, k = 30;
78
+ function w() {
79
79
  return typeof window < "u";
80
80
  }
81
- function g(r) {
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 = !!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 };
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 = a.get(c.USER_ID) ?? null;
98
- return e || (e = crypto.randomUUID(), a.set(c.USER_ID, e, { expires: S })), e;
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 g(a.get(c.CONSENT));
102
+ return v(c.get(o.CONSENT));
102
103
  }
103
104
  setConsent(e) {
104
- const t = {
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 a.set(c.CONSENT, JSON.stringify(t), { expires: I }), t;
112
+ return c.set(o.CONSENT, JSON.stringify(i), { expires: S }), i;
112
113
  }
113
114
  clearAnalyticsCookies() {
114
- a.remove(c.USER_ID);
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 t = 365 * 24 * 60 * 60 * 1e3;
121
- return Date.now() - e.timestamp > t;
123
+ const i = 365 * 24 * 60 * 60 * 1e3;
124
+ return Date.now() - e.timestamp > i;
122
125
  }
123
126
  captureUTM() {
124
- if (!k())
127
+ if (!w())
125
128
  return null;
126
- const e = new URLSearchParams(window.location.search), t = {};
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);
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(t).length === 0 ? g(a.get(c.UTM)) : (a.set(c.UTM, JSON.stringify(t), { expires: w }), t);
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
- const { sessionId: t, sessionStart: s, isReturningUser: i } = this.initSession();
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: t,
138
- sessionStart: s,
148
+ sessionId: i,
149
+ sessionStart: t,
139
150
  consent: this.getConsent(),
140
151
  utm: this.captureUTM(),
141
- isReturningUser: e ? i : !1
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.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 = {
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
- document.addEventListener("click", (s) => {
158
- const i = s.target.closest("[data-fp-id]");
159
- i && this.track("click", i.getAttribute("data-fp-id"), {
160
- x: s.clientX,
161
- y: s.clientY
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, t = null;
165
- document.addEventListener("mouseover", (s) => {
166
- const i = s.target.closest("[data-fp-id]");
167
- i && (e = Date.now(), t = i.getAttribute("data-fp-id"));
168
- }, { passive: !0 }), document.addEventListener("mouseout", (s) => {
169
- if (!s.target.closest("[data-fp-id]") || !t)
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 o = Date.now() - e;
172
- o > 500 && this.track("hover", t, { hoverDuration: o }), t = null;
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 = (i) => {
177
- this.seenInView.has(i) || (this.seenInView.add(i), this.track("scroll_into_view", i, {
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((i) => {
182
- for (const o of i) {
183
- const n = o.target.dataset.fpId;
184
- !n || !o.isIntersecting || e(n);
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 t = () => {
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
- const u = n.dataset.fpId;
195
- if (!u || this.seenInView.has(u))
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 l = n.getBoundingClientRect();
198
- l.bottom >= i && l.top <= o && e(u);
226
+ const u = s.getBoundingClientRect();
227
+ u.bottom >= n && u.top <= a && e(l);
199
228
  });
200
229
  };
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 });
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, t, s) {
204
- this.isBrowser() && (this.refreshCookieData(), this.queue.push({
205
- elementId: t,
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: s,
251
+ metadata: t,
223
252
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
224
253
  }));
225
254
  }
226
- trackFeedback(e, t, s) {
227
- this.isBrowser() && (!t && !s || (this.refreshCookieData(), this.sendImmediate([{
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: t, message: s },
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 t = await fetch(this.config.proxyEndpoint, {
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 && t.ok) {
261
- const s = await t.json().catch(() => null);
262
- s?.ingested !== void 0 && s?.pipeline && globalThis.console.debug(`[FeedPulse] ${s.ingested} events via ${s.pipeline} pipeline`);
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
- c as COOKIE_KEYS,
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,4 @@
1
+ import { InjectionKey } from 'vue';
2
+ import { FeedPulseTracker } from '../core/tracker';
3
+ export declare const FEEDPULSE_KEY: InjectionKey<FeedPulseTracker>;
4
+ export declare function useFeedPulse(): FeedPulseTracker | null;
@@ -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
@@ -0,0 +1,2 @@
1
+ export * from './nuxt/index.js'
2
+ export {}
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-DV52qDLp.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=`
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, createElementBlock as g, openBlock as r, createElementVNode as t, createCommentVNode as w, Fragment as _, renderList as L, normalizeStyle as T, toDisplayString as I, withDirectives as R, vModelText as O, onMounted as M, onBeforeUnmount as F, createBlock as N, createTextVNode as A, createStaticVNode as W, Teleport as J, vModelCheckbox as j, provide as G, renderSlot as K } from "vue";
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-BqTHgw95.mjs";
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';
@@ -0,0 +1,4 @@
1
+ export { ConsentBanner } from './consent-banner';
2
+ export { FeedPulseBot } from './FeedPulseBot';
3
+ export { FeedPulseProvider, useFeedPulse } from './FeedPulseProvider';
4
+ export { FeedPulseWidget } from './FeedPulseWidget';
@@ -0,0 +1,2 @@
1
+ export * from './react/index.js'
2
+ export {}