@huloglobal/vendure-plugin-visitor-analytics 0.8.0 → 0.8.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,87 @@ documented here. The format follows
5
5
  [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project
6
6
  adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.8.0] — 2026-07-04
9
+
10
+ ### Added
11
+
12
+ **Cart abandonment — end-to-end.**
13
+ - New `AbandonedCart` entity, keyed on session id. One row per
14
+ abandoned session, refreshed in place until it either converts
15
+ (order placed) or expires (recovery window elapses).
16
+ - `AbandonedCartService.scan()` — periodic sweep finds sessions with
17
+ `cart_snapshot` events but no `checkout_completed` in the
18
+ abandonment window (default 30 min). Auto-promotes previously
19
+ abandoned rows to `converted` when the customer later checks out.
20
+ - Ships with a boot-time timer (worker-only, 5-minute cadence).
21
+ Idempotent — safe to horizontally scale, only the worker runs it.
22
+ - Signed recovery links — `POST /ees/abandoned-carts/:id/recovery-link`
23
+ returns a time-bounded opaque token the storefront exchanges via
24
+ `GET /ees/recover-cart?t=…` to rebuild the exact cart. Storefront
25
+ never sees the underlying items until the token is presented.
26
+ - Slack notification for high-value abandonments — configurable
27
+ threshold and webhook via the `abandonment` plugin option.
28
+ - Admin API:
29
+ - `GET /ees/abandoned-carts` — paginated list with status,
30
+ value and email filters.
31
+ - `GET /ees/abandoned-carts/summary` — totals, recovery rate,
32
+ recovered vs. lost value in the window.
33
+ - `GET /ees/abandoned-carts/:id` — detail incl. parsed items.
34
+ - `POST /ees/abandoned-carts/:id/status` — mark recovered /
35
+ dismissed / re-open.
36
+ - `GET /ees/abandoned-carts/export.csv` — CSV export.
37
+
38
+ **Co-view product recommendations.**
39
+ - New `ProductCoView` aggregate table. Scanner walks recent
40
+ `product_view` events per session, extracts every ordered pair,
41
+ and increments a per-triple counter. Bounded to 20 events per
42
+ session so runaway bot sessions can't skew the table.
43
+ - Denormalised — both `(A, B)` and `(B, A)` stored — so read-side
44
+ lookups are one indexed scan.
45
+ - Runs every 6 hours on the worker; also exposed as
46
+ `GET /ees/recommendations/aggregate-now` for admins to kick a
47
+ fresh run after a data backfill.
48
+ - Public read endpoints (safe from the storefront):
49
+ - `GET /ees/recommendations/also-viewed?productId=…` — the
50
+ "customers who viewed X also viewed…" rail on a product page.
51
+ - `GET /ees/recommendations/personal?visitorId=…` — personalised
52
+ recs for a returning visitor, from their last 10 product views
53
+ over 30 days. Excludes seeds.
54
+ - `GET /ees/recommendations/trending?hours=24` — most-viewed
55
+ products in the window. Reflects real interest, not search-
56
+ console clicks.
57
+
58
+ **Site search analytics.**
59
+ - Reads back over `visitor_event` where the storefront has fired
60
+ `hulo.search(query, resultsCount)`. Zero new schema.
61
+ - `GET /ees/search-analytics/top` — top queries by volume with
62
+ average results count.
63
+ - `GET /ees/search-analytics/no-results` — top zero-result queries.
64
+ Direct catalogue-gap intel.
65
+ - `GET /ees/search-analytics/conversion` — of sessions that
66
+ searched, what fraction went on to fire `add_to_cart`.
67
+
68
+ **Journey drawer buffs.**
69
+ - Rage-click + dead-click aggregation, keyed on URL. Store-wide
70
+ hot-spot lists for pages where visitors are stuck or frustrated.
71
+ - Per-visitor session summary with a heuristic `intent` label
72
+ (`purchase` / `abandon` / `frustrate` / `consider` / `browse` /
73
+ `bounce`) computed from event history — one glance per session
74
+ in the Journey drawer instead of scrolling event rows.
75
+
76
+ **Storefront helper events (documented in the README).**
77
+ - `hulo.cartSnapshot({ currency, totalMinor, itemCount, items, email })`
78
+ - `hulo.productView(productId, productVariantId?)`
79
+ - `hulo.search(query, resultsCount)`
80
+ - `hulo.rageClick(url, selector?)` / `hulo.deadClick(url, selector)`
81
+ - `hulo.checkoutCompleted()`
82
+ - All flow into the existing `POST /ees/track` endpoint with a
83
+ standard shape, so admins can also fire them from any language.
84
+
85
+ ### Changed
86
+ - `checkout_completed` is now a first-class recognised event type
87
+ — the abandonment scanner uses it to auto-close matched rows.
88
+
8
89
  ## [0.7.0] — 2026-07-04
9
90
 
10
91
  ### Added
@@ -149,6 +230,7 @@ adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
149
230
  - Licence verification via `@huloglobal/vendure-licence-sdk` with
150
231
  revocation polling.
151
232
 
233
+ [0.8.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.8.0
152
234
  [0.7.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.7.0
153
235
  [0.6.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.6.0
154
236
  [0.5.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.5.0
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The single-file storefront helper the plugin serves at /ees/hulo.js.
3
+ *
4
+ * Written as a string constant (not a bundled module) because:
5
+ * - It's tiny (< 6kB minified) — a bundler adds more than the code
6
+ * - It ships to the browser verbatim, no compile step
7
+ * - Customers can inspect / audit it without a source map
8
+ * - It has ZERO npm dependencies at runtime
9
+ *
10
+ * The controller wraps this in a small template that injects the
11
+ * public base URL and a default channel id, so a storefront paste
12
+ * of `<script src="https://backend/ees/hulo.js"></script>` Just Works
13
+ * with no config. Advanced users can call `hulo.configure({ ... })`
14
+ * to override.
15
+ */
16
+ export declare const HULO_STOREFRONT_JS: (backendBaseUrl: string, defaultChannelId?: number) => string;
17
+ //# sourceMappingURL=hulo-storefront.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hulo-storefront.d.ts","sourceRoot":"","sources":["../src/hulo-storefront.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB,GAAI,gBAAgB,MAAM,EAAE,yBAAoB,KAAG,MA4QjF,CAAC"}
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HULO_STOREFRONT_JS = void 0;
4
+ /**
5
+ * The single-file storefront helper the plugin serves at /ees/hulo.js.
6
+ *
7
+ * Written as a string constant (not a bundled module) because:
8
+ * - It's tiny (< 6kB minified) — a bundler adds more than the code
9
+ * - It ships to the browser verbatim, no compile step
10
+ * - Customers can inspect / audit it without a source map
11
+ * - It has ZERO npm dependencies at runtime
12
+ *
13
+ * The controller wraps this in a small template that injects the
14
+ * public base URL and a default channel id, so a storefront paste
15
+ * of `<script src="https://backend/ees/hulo.js"></script>` Just Works
16
+ * with no config. Advanced users can call `hulo.configure({ ... })`
17
+ * to override.
18
+ */
19
+ const HULO_STOREFRONT_JS = (backendBaseUrl, defaultChannelId = 1) => `
20
+ // hulo storefront helper — @huloglobal/vendure-plugin-visitor-analytics
21
+ // Public domain when served from your own store; do not resell.
22
+ (function (global) {
23
+ var CONFIG = {
24
+ endpoint: ${JSON.stringify(backendBaseUrl.replace(/\/$/, '') + '/ees/track')},
25
+ recoverEndpoint: ${JSON.stringify(backendBaseUrl.replace(/\/$/, '') + '/ees/recover-cart')},
26
+ channelId: ${defaultChannelId},
27
+ debug: false,
28
+ autoRageClick: true,
29
+ autoDeadClick: true,
30
+ autoScroll: false, // not implemented yet — flag reserved
31
+ };
32
+
33
+ // ── queue + batched send ─────────────────────────────────────────
34
+ // Every helper below pushes into a queue. Flush on requestIdleCallback
35
+ // or 2s max. Coalesces bursts of events into one HTTP roundtrip.
36
+ var QUEUE = [];
37
+ var FLUSH_TIMER = null;
38
+ function enqueue(event) {
39
+ event.url = event.url || location.href;
40
+ event.channelId = event.channelId || CONFIG.channelId;
41
+ QUEUE.push(event);
42
+ scheduleFlush();
43
+ if (CONFIG.debug) console.log('[hulo]', event);
44
+ }
45
+ function scheduleFlush() {
46
+ if (FLUSH_TIMER) return;
47
+ FLUSH_TIMER = setTimeout(flush, 1500);
48
+ }
49
+ function flush() {
50
+ FLUSH_TIMER = null;
51
+ if (!QUEUE.length) return;
52
+ var batch = QUEUE.splice(0, QUEUE.length);
53
+ var payload = JSON.stringify({ events: batch });
54
+ // Prefer sendBeacon on unload (survives page transitions) and
55
+ // fall back to fetch keepalive for normal calls.
56
+ try {
57
+ if (navigator.sendBeacon) {
58
+ var blob = new Blob([payload], { type: 'application/json' });
59
+ if (navigator.sendBeacon(CONFIG.endpoint, blob)) return;
60
+ }
61
+ } catch (_e) {}
62
+ try {
63
+ fetch(CONFIG.endpoint, {
64
+ method: 'POST', credentials: 'include', keepalive: true,
65
+ headers: { 'content-type': 'application/json' },
66
+ body: payload,
67
+ }).catch(function () { /* silent */ });
68
+ } catch (_e) {}
69
+ }
70
+ // Flush before the page dies.
71
+ window.addEventListener('pagehide', flush, { capture: true });
72
+ window.addEventListener('beforeunload', flush, { capture: true });
73
+
74
+ // ── public API ───────────────────────────────────────────────────
75
+ var hulo = {
76
+ configure: function (opts) { Object.assign(CONFIG, opts || {}); },
77
+ flush: flush,
78
+
79
+ /** Fire once per pageview. Optional — the ingest endpoint infers
80
+ * pageviews from the referrer / URL, but calling this explicitly
81
+ * captures the title too. */
82
+ pageview: function (extra) {
83
+ enqueue(Object.assign({ type: 'pageview', title: document.title }, extra || {}));
84
+ },
85
+
86
+ /** Product detail viewed. Store the product id you would use to
87
+ * fetch the product server-side (Vendure product.id). If your
88
+ * storefront uses variants primarily, pass variantId too. */
89
+ productView: function (productId, productVariantId) {
90
+ if (!productId && productId !== 0) return;
91
+ enqueue({
92
+ type: 'event',
93
+ meta: JSON.stringify({
94
+ eventType: 'product_view',
95
+ productId: Number(productId),
96
+ productVariantId: productVariantId != null ? Number(productVariantId) : undefined,
97
+ }),
98
+ });
99
+ },
100
+
101
+ /** Item added to cart. Fire on every add — not just the first. */
102
+ addToCart: function (variantId, qty, unitPriceMinor) {
103
+ enqueue({
104
+ type: 'event',
105
+ meta: JSON.stringify({
106
+ eventType: 'add_to_cart',
107
+ variantId: variantId != null ? Number(variantId) : undefined,
108
+ qty: qty != null ? Number(qty) : 1,
109
+ unitPriceMinor: unitPriceMinor != null ? Number(unitPriceMinor) : undefined,
110
+ }),
111
+ });
112
+ },
113
+
114
+ /** Cart snapshot — fire on every cart change (add / remove / qty).
115
+ * The abandonment scanner reads only this event, so fire it
116
+ * liberally. Payload shape:
117
+ * { currency, totalMinor, itemCount, items: [{ variantId, name, qty, unitPriceMinor }], email? } */
118
+ cartSnapshot: function (cart) {
119
+ if (!cart || !cart.items || !cart.items.length) return;
120
+ enqueue({
121
+ type: 'event',
122
+ meta: JSON.stringify({
123
+ eventType: 'cart_snapshot',
124
+ currency: (cart.currency || 'GBP').toUpperCase().slice(0, 3),
125
+ totalMinor: Number(cart.totalMinor || 0),
126
+ itemCount: Number(cart.itemCount || cart.items.length),
127
+ items: cart.items.map(function (i) {
128
+ return {
129
+ variantId: i.variantId != null ? Number(i.variantId) : undefined,
130
+ productId: i.productId != null ? Number(i.productId) : undefined,
131
+ name: i.name != null ? String(i.name).slice(0, 200) : undefined,
132
+ qty: Number(i.qty != null ? i.qty : (i.quantity != null ? i.quantity : 1)),
133
+ unitPriceMinor: Number(i.unitPriceMinor != null ? i.unitPriceMinor : (i.unitPrice != null ? i.unitPrice : 0)),
134
+ sku: i.sku != null ? String(i.sku).slice(0, 100) : undefined,
135
+ };
136
+ }).slice(0, 100),
137
+ email: cart.email || undefined,
138
+ countryCode: cart.countryCode || undefined,
139
+ }),
140
+ });
141
+ },
142
+
143
+ /** Storefront site search executed. Pass the raw query + the
144
+ * resulting hit count so no-result queries can be aggregated. */
145
+ search: function (query, resultsCount) {
146
+ var q = String(query || '').trim();
147
+ if (!q) return;
148
+ enqueue({
149
+ type: 'event',
150
+ meta: JSON.stringify({
151
+ eventType: 'search',
152
+ query: q.slice(0, 200),
153
+ resultsCount: Math.max(0, Number(resultsCount || 0)),
154
+ }),
155
+ });
156
+ },
157
+
158
+ /** Checkout finished — fires the counter that closes any open
159
+ * abandoned-cart row for this session. Call from your thank-you
160
+ * page. Optionally pass the order code + total. */
161
+ checkoutCompleted: function (orderCode, totalMinor) {
162
+ enqueue({
163
+ type: 'event',
164
+ meta: JSON.stringify({
165
+ eventType: 'checkout_completed',
166
+ orderCode: orderCode ? String(orderCode).slice(0, 64) : undefined,
167
+ totalMinor: totalMinor != null ? Number(totalMinor) : undefined,
168
+ }),
169
+ });
170
+ flush(); // don't wait — the visitor may close the tab immediately
171
+ },
172
+
173
+ /** Rage-click event — fire it yourself if you have a better signal
174
+ * than the built-in detector. */
175
+ rageClick: function (selector, extraMeta) {
176
+ enqueue({
177
+ type: 'event',
178
+ meta: JSON.stringify(Object.assign({
179
+ eventType: 'rage_click',
180
+ selector: selector ? String(selector).slice(0, 200) : undefined,
181
+ }, extraMeta || {})),
182
+ });
183
+ },
184
+
185
+ /** Click landed on a non-interactive element. */
186
+ deadClick: function (selector, extraMeta) {
187
+ enqueue({
188
+ type: 'event',
189
+ meta: JSON.stringify(Object.assign({
190
+ eventType: 'dead_click',
191
+ selector: selector ? String(selector).slice(0, 200) : undefined,
192
+ }, extraMeta || {})),
193
+ });
194
+ },
195
+
196
+ /**
197
+ * Restore a cart from a signed recovery token. Fetches the items
198
+ * from the backend and returns them. Your storefront is responsible
199
+ * for calling its own Vendure order API to actually re-add them,
200
+ * because different storefronts frame that call differently.
201
+ */
202
+ restoreCart: function (token) {
203
+ var t = String(token || '').trim();
204
+ if (!t) return Promise.reject(new Error('missing-token'));
205
+ return fetch(CONFIG.recoverEndpoint + '?t=' + encodeURIComponent(t), {
206
+ credentials: 'include',
207
+ }).then(function (r) { return r.json(); });
208
+ },
209
+ };
210
+
211
+ // ── auto rage-click detector ─────────────────────────────────────
212
+ // Any pointerdown ≥ 3 within 500ms in a 20x20px zone counts.
213
+ if (CONFIG.autoRageClick) {
214
+ var recent = [];
215
+ document.addEventListener('pointerdown', function (e) {
216
+ var now = Date.now();
217
+ recent = recent.filter(function (r) { return now - r.t < 500; });
218
+ recent.push({ t: now, x: e.clientX, y: e.clientY, target: e.target });
219
+ var close = recent.filter(function (r) {
220
+ return Math.abs(r.x - e.clientX) < 20 && Math.abs(r.y - e.clientY) < 20;
221
+ });
222
+ if (close.length >= 3) {
223
+ hulo.rageClick(cssPathOf(e.target));
224
+ recent = []; // reset so we don't fire again on the 4th, 5th, etc.
225
+ }
226
+ }, { capture: true, passive: true });
227
+ }
228
+
229
+ // ── auto dead-click detector ─────────────────────────────────────
230
+ // A click that lands on an element with no href / not a button /
231
+ // not a form control and doesn't produce a navigation within 400ms.
232
+ if (CONFIG.autoDeadClick) {
233
+ document.addEventListener('click', function (e) {
234
+ var target = e.target;
235
+ if (!target || target.nodeType !== 1) return;
236
+ if (isInteractive(target)) return;
237
+ var beforeUrl = location.href;
238
+ var beforeScroll = window.scrollY;
239
+ setTimeout(function () {
240
+ if (location.href !== beforeUrl) return;
241
+ if (Math.abs(window.scrollY - beforeScroll) > 50) return;
242
+ // Was there an ancestor with a click handler? Best-effort:
243
+ // walk up and check for onclick, role='button', tabindex.
244
+ var node = target;
245
+ for (var i = 0; i < 4 && node; i++) {
246
+ if (isInteractive(node) || node.onclick) return;
247
+ node = node.parentElement;
248
+ }
249
+ hulo.deadClick(cssPathOf(target));
250
+ }, 400);
251
+ }, { capture: true, passive: true });
252
+ }
253
+
254
+ function isInteractive(el) {
255
+ if (!el || !el.tagName) return false;
256
+ var tag = el.tagName.toLowerCase();
257
+ if (tag === 'a' || tag === 'button' || tag === 'input' || tag === 'select'
258
+ || tag === 'textarea' || tag === 'label' || tag === 'summary'
259
+ || tag === 'details') return true;
260
+ if (el.getAttribute && (el.getAttribute('role') === 'button'
261
+ || el.getAttribute('role') === 'link'
262
+ || el.hasAttribute('tabindex'))) return true;
263
+ return false;
264
+ }
265
+
266
+ function cssPathOf(el) {
267
+ if (!el || el.nodeType !== 1) return '';
268
+ var parts = [];
269
+ while (el && el.nodeType === 1 && parts.length < 5) {
270
+ var p = el.tagName.toLowerCase();
271
+ if (el.id) { p += '#' + el.id; parts.unshift(p); break; }
272
+ if (el.className && typeof el.className === 'string') {
273
+ var cls = el.className.trim().split(/\\s+/).slice(0, 2).join('.');
274
+ if (cls) p += '.' + cls;
275
+ }
276
+ parts.unshift(p);
277
+ el = el.parentElement;
278
+ }
279
+ return parts.join(' > ');
280
+ }
281
+
282
+ global.hulo = hulo;
283
+ // Auto pageview on load — most callers want it.
284
+ if (document.readyState === 'complete') hulo.pageview();
285
+ else window.addEventListener('load', function () { hulo.pageview(); });
286
+ })(window);
287
+ `;
288
+ exports.HULO_STOREFRONT_JS = HULO_STOREFRONT_JS;
289
+ //# sourceMappingURL=hulo-storefront.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hulo-storefront.js","sourceRoot":"","sources":["../src/hulo-storefront.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;GAcG;AACI,MAAM,kBAAkB,GAAG,CAAC,cAAsB,EAAE,gBAAgB,GAAG,CAAC,EAAU,EAAE,CAAC;;;;;gBAK5E,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,YAAY,CAAC;uBACzD,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,mBAAmB,CAAC;iBAC7E,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqQhC,CAAC;AA5QW,QAAA,kBAAkB,sBA4Q7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,IAAI,EAAiB,MAAM,eAAe,CAAC;AACxE,OAAO,EAAmC,aAAa,EAAE,gBAAgB,EAAqB,aAAa,EAA4C,MAAM,iCAAiC,CAAC;AAM/L,OAAO,EAAwB,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAgBpF,MAAM,WAAW,6BAA6B;IAC1C,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB;;;gDAG4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;6EACyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;yEAEqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;qEAEiE;IACjE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;6CAEyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,mDAAmD;IACnD,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD;;yEAEqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;2EAEuE;IACvE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAG9B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAG7B;;4DAEwD;IACxD,WAAW,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAgBD,QAAA,MAAM,eAAe,EAAE,6BAMtB,CAAC;AAGF,wBAAgB,UAAU,IAAI,OAAO,eAAe,GAAG,6BAA6B,CAEnF;AAED;;;;;;;;;;;GAWG;AACH,qBAyBa,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkC;IAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAA8B;IAC1D,OAAO,CAAC,MAAM,CAAC,SAAS,CAA0B;IAClD,OAAO,CAAC,MAAM,CAAC,aAAa,CAA8B;IAE1D,MAAM,CAAC,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAC/C,MAAM,CAAC,iBAAiB,IAAI,MAAM;IAClC,MAAM,CAAC,cAAc,IAAI,MAAM;IAC/B,MAAM,CAAC,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAE/C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAAC,sBAAsB,CAAC;IAoDjF,MAAM,CAAC,YAAY;;;;;;;;MAUjB;CACL"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,IAAI,EAAiB,MAAM,eAAe,CAAC;AACxE,OAAO,EAAmC,aAAa,EAAE,gBAAgB,EAAqB,aAAa,EAA4C,MAAM,iCAAiC,CAAC;AAM/L,OAAO,EAAwB,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAiBpF,MAAM,WAAW,6BAA6B;IAC1C,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB;;;gDAG4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;6EACyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;yEAEqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;qEAEiE;IACjE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;6CAEyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,mDAAmD;IACnD,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD;;yEAEqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;2EAEuE;IACvE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAG9B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAG7B;;4DAEwD;IACxD,WAAW,CAAC,EAAE,kBAAkB,CAAC;CACpC;AAgBD,QAAA,MAAM,eAAe,EAAE,6BAMtB,CAAC;AAGF,wBAAgB,UAAU,IAAI,OAAO,eAAe,GAAG,6BAA6B,CAEnF;AAED;;;;;;;;;;;GAWG;AACH,qBA0Ba,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAAC,UAAU,CAAkC;IAC3D,OAAO,CAAC,MAAM,CAAC,aAAa,CAA8B;IAC1D,OAAO,CAAC,MAAM,CAAC,SAAS,CAA0B;IAClD,OAAO,CAAC,MAAM,CAAC,aAAa,CAA8B;IAE1D,MAAM,CAAC,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAC/C,MAAM,CAAC,iBAAiB,IAAI,MAAM;IAClC,MAAM,CAAC,cAAc,IAAI,MAAM;IAC/B,MAAM,CAAC,gBAAgB,IAAI,aAAa,GAAG,IAAI;IAE/C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAAC,sBAAsB,CAAC;IAoDjF,MAAM,CAAC,YAAY;;;;;;;;MAUjB;CACL"}
package/dist/plugin.js CHANGED
@@ -27,6 +27,7 @@ const abandoned_cart_controller_1 = require("./abandoned-cart.controller");
27
27
  const recommendations_controller_1 = require("./recommendations.controller");
28
28
  const search_analytics_controller_1 = require("./search-analytics.controller");
29
29
  const journey_buffs_controller_1 = require("./journey-buffs.controller");
30
+ const storefront_helper_controller_1 = require("./storefront-helper.controller");
30
31
  // eslint-disable-next-line @typescript-eslint/no-var-requires
31
32
  const PKG_VERSION = require('../package.json').version;
32
33
  const PKG_NAME = '@huloglobal/vendure-plugin-visitor-analytics';
@@ -148,6 +149,7 @@ exports.VisitorAnalyticsPlugin = VisitorAnalyticsPlugin = VisitorAnalyticsPlugin
148
149
  recommendations_controller_1.RecommendationsController,
149
150
  search_analytics_controller_1.SearchAnalyticsController,
150
151
  journey_buffs_controller_1.JourneyBuffsController,
152
+ storefront_helper_controller_1.StorefrontHelperController,
151
153
  ],
152
154
  entities: [visitor_event_entity_1.VisitorEvent, conversion_goal_entity_1.ConversionGoal, abandoned_cart_entity_1.AbandonedCart, product_co_view_entity_1.ProductCoView],
153
155
  compatibility: '^3.0.0',
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;;;;;;;;;AA+FA,gCAEC;AAjGD,wCAAwE;AACxE,yEAA+L;AAC/L,qEAA0D;AAC1D,iEAAsD;AACtD,mEAAwD;AACxD,qEAAyD;AACzD,yEAAoE;AACpE,qEAAoF;AACpF,uEAAmE;AACnE,yEAAoE;AACpE,mEAA8D;AAC9D,qEAAgE;AAChE,2CAA4F;AAC5F,+EAA0E;AAC1E,2EAAsE;AACtE,6EAAyE;AACzE,+EAA0E;AAC1E,yEAAoE;AAEpE,8DAA8D;AAC9D,MAAM,WAAW,GAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC;AAC/D,MAAM,QAAQ,GAAG,8CAA8C,CAAC;AAmDhE,MAAM,eAAe,GAAG;;;;;;;;yBAQC,CAAC;AAE1B,MAAM,SAAS,GAAG,kCAAkC,CAAC;AACrD,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B;OACvD,4CAA4C,CAAC;AAEpD,MAAM,eAAe,GAAkC;IACnD,aAAa,EAAE,uBAAuB;IACtC,eAAe,EAAE,IAAI;IACrB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACvB,CAAC;AAEF,IAAI,aAAa,GAAkC,eAAsB,CAAC;AAC1E,SAAgB,UAAU;IACtB,OAAO,EAAE,GAAG,eAAe,EAAE,GAAG,aAAa,EAAS,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;GAWG;AA0BI,IAAM,sBAAsB,8BAA5B,MAAM,sBAAsB;IAM/B,MAAM,CAAC,gBAAgB,KAA2B,OAAO,wBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC;IAChG,MAAM,CAAC,iBAAiB,KAAa,OAAO,WAAW,CAAC,CAAC,CAAC;IAC1D,MAAM,CAAC,cAAc,KAAa,OAAO,QAAQ,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,gBAAgB,KAA2B,OAAO,wBAAsB,CAAC,aAAa,CAAC,CAAC,CAAC;IAEhG,MAAM,CAAC,IAAI,CAAC,OAAsC;QAC9C,aAAa,GAAG,OAAO,CAAC;QAExB,yDAAyD;QACzD,iDAAiD;QACjD,IAAA,+CAAyB,EAAC;YACtB,iBAAiB,EAAE,QAAQ;YAC3B,oBAAoB,EAAE,WAAW;YACjC,cAAc,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE;SACjD,CAAC,CAAC;QAEH,IAAI,CAAC,wBAAsB,CAAC,UAAU,EAAE,CAAC;YACrC,wBAAsB,CAAC,UAAU,GAAG,IAAI,uCAAiB,CAAC,cAAc,CAAC,CAAC;YAC1E,wBAAsB,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,wBAAsB,CAAC,aAAa,EAAE,CAAC;YACxC,wBAAsB,CAAC,aAAa,GAAG,IAAI,mCAAa,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAChF,wBAAsB,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QACjD,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;aACrC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAA,mCAAa,EAAC;YACzB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,QAAQ,EAAE,SAAS;YACnB,IAAI;YACJ,SAAS,EAAE,eAAe;YAC1B,UAAU,EAAE,wBAAsB,CAAC,UAAU,CAAC,aAAa,EAAE;SAChE,CAAC,CAAC;QACH,wBAAsB,CAAC,aAAa,GAAG,MAAM,CAAC;QAE9C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAChB,sCAAsC;YACtC,OAAO,CAAC,IAAI,CACR,kDAAkD,MAAM,CAAC,OAAO,EAAE;gBAClE,2KAA2K,SAAS,EAAE,CACzL,CAAC;QACN,CAAC;QAED,IAAI,CAAC,wBAAsB,CAAC,SAAS,EAAE,CAAC;YACpC,wBAAsB,CAAC,SAAS,GAAG,IAAI,+BAAS,CAAC;gBAC7C,WAAW,EAAE,QAAQ;gBACrB,cAAc,EAAE,WAAW;gBAC3B,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,oBAAoB,EAAE,IAAA,0CAAoB,EAAC,eAAe,CAAC;aAC9D,CAAC,CAAC;YACH,wBAAsB,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QAC7C,CAAC;QAED,OAAO,wBAAsB,CAAC;IAClC,CAAC;;AA7DQ,wDAAsB;AAChB,iCAAU,GAA6B,IAAI,AAAjC,CAAkC;AAC5C,oCAAa,GAAyB,IAAI,AAA7B,CAA8B;AAC3C,gCAAS,GAAqB,IAAI,AAAzB,CAA0B;AACnC,oCAAa,GAAyB,IAAI,AAA7B,CAA8B;AA2DnD,mCAAY,GAAG;IAClB,aAAa,EAAE,SAAS,GAAG,QAAQ;IACnC,SAAS,EAAE;QACP;YACI,IAAI,EAAE,MAAe;YACrB,KAAK,EAAE,UAAU;YACjB,gBAAgB,EAAE,oBAAoB;YACtC,YAAY,EAAE,gBAAgB;SACjC;KACJ;CACJ,AAVkB,CAUjB;iCAzEO,sBAAsB;IAzBlC,IAAA,oBAAa,EAAC;QACX,OAAO,EAAE,CAAC,yBAAkB,CAAC;QAC7B,SAAS,EAAE;YACP,iDAAsB;YACtB,yCAA6B;YAC7B,6CAAoB;YACpB,gDAAsB;YACtB,iDAAsB;YACtB,2CAAmB;YACnB,6CAAoB;SACvB;QACD,WAAW,EAAE;YACT,uDAAyB;YACzB,mDAAuB;YACvB,sDAAyB;YACzB,uDAAyB;YACzB,iDAAsB;SACzB;QACD,QAAQ,EAAE,CAAC,mCAAY,EAAE,uCAAc,EAAE,qCAAa,EAAE,sCAAa,CAAC;QACtE,aAAa,EAAE,QAAQ;QACvB,kBAAkB,EAAE;YAChB,MAAM,EAAE,0CAA8B;YACtC,SAAS,EAAE,CAAC,yCAA6B,CAAC;SAC7C;KACJ,CAAC;GACW,sBAAsB,CA0ElC"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Request, Response } from 'express';
2
+ /**
3
+ * Serves the storefront helper at `/ees/hulo.js`. Storefronts embed
4
+ * one script tag and every helper (cartSnapshot, productView, search,
5
+ * rageClick+deadClick auto-detectors, checkoutCompleted, restoreCart)
6
+ * is available on `window.hulo`.
7
+ *
8
+ * Cache: 10-minute browser TTL + 24-hour SWR. The file's content is
9
+ * a function of plugin options; storefronts don't need to bust the
10
+ * cache to see config changes because the URL stays stable and 10
11
+ * minutes is short enough that dashboard tweaks propagate promptly.
12
+ */
13
+ export declare class StorefrontHelperController {
14
+ hulo(req: Request, res: Response): void;
15
+ }
16
+ //# sourceMappingURL=storefront-helper.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storefront-helper.controller.d.ts","sourceRoot":"","sources":["../src/storefront-helper.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAI5C;;;;;;;;;;GAUG;AACH,qBACa,0BAA0B;IAEnC,IAAI,CAAQ,GAAG,EAAE,OAAO,EAAS,GAAG,EAAE,QAAQ;CAYjD"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.StorefrontHelperController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const hulo_storefront_1 = require("./hulo-storefront");
18
+ const plugin_1 = require("./plugin");
19
+ /**
20
+ * Serves the storefront helper at `/ees/hulo.js`. Storefronts embed
21
+ * one script tag and every helper (cartSnapshot, productView, search,
22
+ * rageClick+deadClick auto-detectors, checkoutCompleted, restoreCart)
23
+ * is available on `window.hulo`.
24
+ *
25
+ * Cache: 10-minute browser TTL + 24-hour SWR. The file's content is
26
+ * a function of plugin options; storefronts don't need to bust the
27
+ * cache to see config changes because the URL stays stable and 10
28
+ * minutes is short enough that dashboard tweaks propagate promptly.
29
+ */
30
+ let StorefrontHelperController = class StorefrontHelperController {
31
+ hulo(req, res) {
32
+ const opts = (0, plugin_1.getOptions)();
33
+ const base = opts.publicBaseUrl
34
+ || `https://${req.headers.host || 'localhost'}`;
35
+ const js = (0, hulo_storefront_1.HULO_STOREFRONT_JS)(base, 1);
36
+ res.setHeader('content-type', 'application/javascript; charset=utf-8');
37
+ res.setHeader('cache-control', 'public, max-age=600, stale-while-revalidate=86400');
38
+ // Storefront lives on a different origin from the backend —
39
+ // static-JS CORS is safe (no credentials) but be explicit.
40
+ res.setHeader('access-control-allow-origin', '*');
41
+ res.send(js);
42
+ }
43
+ };
44
+ exports.StorefrontHelperController = StorefrontHelperController;
45
+ __decorate([
46
+ (0, common_1.Get)('hulo.js'),
47
+ __param(0, (0, common_1.Req)()),
48
+ __param(1, (0, common_1.Res)()),
49
+ __metadata("design:type", Function),
50
+ __metadata("design:paramtypes", [Object, Object]),
51
+ __metadata("design:returntype", void 0)
52
+ ], StorefrontHelperController.prototype, "hulo", null);
53
+ exports.StorefrontHelperController = StorefrontHelperController = __decorate([
54
+ (0, common_1.Controller)('ees')
55
+ ], StorefrontHelperController);
56
+ //# sourceMappingURL=storefront-helper.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storefront-helper.controller.js","sourceRoot":"","sources":["../src/storefront-helper.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA2D;AAE3D,uDAAuD;AACvD,qCAAsC;AAEtC;;;;;;;;;;GAUG;AAEI,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IAEnC,IAAI,CAAQ,GAAY,EAAS,GAAa;QAC1C,MAAM,IAAI,GAAG,IAAA,mBAAU,GAAE,CAAC;QAC1B,MAAM,IAAI,GAAI,IAAY,CAAC,aAAa;eACjC,WAAW,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;QACpD,MAAM,EAAE,GAAG,IAAA,oCAAkB,EAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,uCAAuC,CAAC,CAAC;QACvE,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,mDAAmD,CAAC,CAAC;QACpF,4DAA4D;QAC5D,2DAA2D;QAC3D,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAClD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;CACJ,CAAA;AAdY,gEAA0B;AAEnC;IADC,IAAA,YAAG,EAAC,SAAS,CAAC;IACT,WAAA,IAAA,YAAG,GAAE,CAAA;IAAgB,WAAA,IAAA,YAAG,GAAE,CAAA;;;;sDAW/B;qCAbQ,0BAA0B;IADtC,IAAA,mBAAU,EAAC,KAAK,CAAC;GACL,0BAA0B,CActC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huloglobal/vendure-plugin-visitor-analytics",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Full-funnel visitor analytics for Vendure storefronts \u2014 pageviews, time-on-page, session journey, exit pages, funnel drop-off, and per-visitor profile drawer with parsed user-agent + MaxMind GeoLite2 enrichment. Auto-issues visitor + session cookies on first request; logs guest and signed-in events against the same visitor id so the journey survives login.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "author": "Wayne Garrison <wayne@garrison.me.uk>",