@huloglobal/vendure-plugin-visitor-analytics 0.6.0 → 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.
Files changed (54) hide show
  1. package/CHANGELOG.md +83 -15
  2. package/dist/abandoned-cart.controller.d.ts +78 -0
  3. package/dist/abandoned-cart.controller.d.ts.map +1 -0
  4. package/dist/abandoned-cart.controller.js +251 -0
  5. package/dist/abandoned-cart.controller.js.map +1 -0
  6. package/dist/abandoned-cart.entity.d.ts +61 -0
  7. package/dist/abandoned-cart.entity.d.ts.map +1 -0
  8. package/dist/abandoned-cart.entity.js +143 -0
  9. package/dist/abandoned-cart.entity.js.map +1 -0
  10. package/dist/abandoned-cart.scanner.d.ts +34 -0
  11. package/dist/abandoned-cart.scanner.d.ts.map +1 -0
  12. package/dist/abandoned-cart.scanner.js +85 -0
  13. package/dist/abandoned-cart.scanner.js.map +1 -0
  14. package/dist/abandoned-cart.service.d.ts +92 -0
  15. package/dist/abandoned-cart.service.d.ts.map +1 -0
  16. package/dist/abandoned-cart.service.js +276 -0
  17. package/dist/abandoned-cart.service.js.map +1 -0
  18. package/dist/index.d.ts +6 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +13 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/journey-buffs.controller.d.ts +43 -0
  23. package/dist/journey-buffs.controller.d.ts.map +1 -0
  24. package/dist/journey-buffs.controller.js +79 -0
  25. package/dist/journey-buffs.controller.js.map +1 -0
  26. package/dist/journey-buffs.service.d.ts +53 -0
  27. package/dist/journey-buffs.service.d.ts.map +1 -0
  28. package/dist/journey-buffs.service.js +141 -0
  29. package/dist/journey-buffs.service.js.map +1 -0
  30. package/dist/plugin.d.ts +5 -0
  31. package/dist/plugin.d.ts.map +1 -1
  32. package/dist/plugin.js +35 -3
  33. package/dist/plugin.js.map +1 -1
  34. package/dist/product-co-view.entity.d.ts +19 -0
  35. package/dist/product-co-view.entity.d.ts.map +1 -0
  36. package/dist/product-co-view.entity.js +52 -0
  37. package/dist/product-co-view.entity.js.map +1 -0
  38. package/dist/recommendations.controller.d.ts +72 -0
  39. package/dist/recommendations.controller.d.ts.map +1 -0
  40. package/dist/recommendations.controller.js +123 -0
  41. package/dist/recommendations.controller.js.map +1 -0
  42. package/dist/recommendations.service.d.ts +62 -0
  43. package/dist/recommendations.service.d.ts.map +1 -0
  44. package/dist/recommendations.service.js +167 -0
  45. package/dist/recommendations.service.js.map +1 -0
  46. package/dist/search-analytics.controller.d.ts +36 -0
  47. package/dist/search-analytics.controller.d.ts.map +1 -0
  48. package/dist/search-analytics.controller.js +86 -0
  49. package/dist/search-analytics.controller.js.map +1 -0
  50. package/dist/search-analytics.service.d.ts +36 -0
  51. package/dist/search-analytics.service.d.ts.map +1 -0
  52. package/dist/search-analytics.service.js +105 -0
  53. package/dist/search-analytics.service.js.map +1 -0
  54. package/package.json +3 -3
@@ -0,0 +1,105 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SearchAnalyticsService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const core_1 = require("@vendure/core");
15
+ /**
16
+ * Zero-schema-cost search analytics: reads back over the existing
17
+ * `visitor_event` table where the storefront has posted `type='event'`,
18
+ * `eventType='search'` custom events, and aggregates them per query
19
+ * string.
20
+ *
21
+ * The storefront just needs to fire:
22
+ * hulo.search('rgb keyboard', 42) // (query, resultsCount)
23
+ *
24
+ * Everything else lives in the read side.
25
+ */
26
+ let SearchAnalyticsService = class SearchAnalyticsService {
27
+ constructor(connection) {
28
+ this.connection = connection;
29
+ }
30
+ /** Top search queries in the window, by volume. */
31
+ async topQueries(sinceDays = 7, channelId = 1, limit = 50) {
32
+ const since = new Date(Date.now() - sinceDays * 86400000);
33
+ const rows = await this.connection.rawConnection.query(`SELECT
34
+ LOWER(TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(meta, '"query":"', -1), '"', 1))) AS query,
35
+ COUNT(*) AS searches,
36
+ AVG(CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(meta, '"resultsCount":', -1), ',', 1) AS UNSIGNED)) AS avgResults
37
+ FROM visitor_event
38
+ WHERE type = 'event'
39
+ AND meta LIKE '%"eventType":"search"%'
40
+ AND channelId = ?
41
+ AND createdAt >= ?
42
+ GROUP BY query
43
+ HAVING query <> ''
44
+ ORDER BY searches DESC
45
+ LIMIT ?`, [channelId, since, Math.min(Math.max(1, limit), 500)]);
46
+ return rows.map(r => ({
47
+ query: String(r.query || ''),
48
+ searches: Number(r.searches),
49
+ avgResults: Math.round(Number(r.avgResults || 0) * 10) / 10,
50
+ }));
51
+ }
52
+ /** Zero-result queries — catalogue-gap intel. */
53
+ async zeroResultQueries(sinceDays = 7, channelId = 1, limit = 50) {
54
+ const since = new Date(Date.now() - sinceDays * 86400000);
55
+ const rows = await this.connection.rawConnection.query(`SELECT
56
+ LOWER(TRIM(BOTH '"' FROM SUBSTRING_INDEX(SUBSTRING_INDEX(meta, '"query":"', -1), '"', 1))) AS query,
57
+ COUNT(*) AS searches
58
+ FROM visitor_event
59
+ WHERE type = 'event'
60
+ AND meta LIKE '%"eventType":"search"%'
61
+ AND meta LIKE '%"resultsCount":0%'
62
+ AND channelId = ?
63
+ AND createdAt >= ?
64
+ GROUP BY query
65
+ HAVING query <> ''
66
+ ORDER BY searches DESC
67
+ LIMIT ?`, [channelId, since, Math.min(Math.max(1, limit), 500)]);
68
+ return rows.map(r => ({ query: String(r.query || ''), searches: Number(r.searches) }));
69
+ }
70
+ /** Search-to-cart-add conversion — of sessions that searched, what
71
+ * fraction went on to fire an add_to_cart. Coarse, but the direction
72
+ * of movement is what matters for catalogue tuning. */
73
+ async searchToAddRate(sinceDays = 7, channelId = 1) {
74
+ const since = new Date(Date.now() - sinceDays * 86400000);
75
+ const rows = await this.connection.rawConnection.query(`SELECT
76
+ COUNT(DISTINCT ve.sessionId) AS sessionsSearched,
77
+ COUNT(DISTINCT CASE WHEN adds.sessionId IS NOT NULL THEN ve.sessionId END) AS sessionsAdded
78
+ FROM visitor_event ve
79
+ LEFT JOIN (
80
+ SELECT DISTINCT sessionId FROM visitor_event
81
+ WHERE type = 'event'
82
+ AND meta LIKE '%"eventType":"add_to_cart"%'
83
+ AND channelId = ?
84
+ AND createdAt >= ?
85
+ ) adds ON adds.sessionId = ve.sessionId
86
+ WHERE ve.type = 'event'
87
+ AND ve.meta LIKE '%"eventType":"search"%'
88
+ AND ve.channelId = ?
89
+ AND ve.createdAt >= ?`, [channelId, since, channelId, since]);
90
+ const r = (rows === null || rows === void 0 ? void 0 : rows[0]) || {};
91
+ const searched = Number(r.sessionsSearched || 0);
92
+ const added = Number(r.sessionsAdded || 0);
93
+ return {
94
+ sessionsSearched: searched,
95
+ sessionsAdded: added,
96
+ conversion: searched ? Math.round((added / searched) * 1000) / 10 : 0,
97
+ };
98
+ }
99
+ };
100
+ exports.SearchAnalyticsService = SearchAnalyticsService;
101
+ exports.SearchAnalyticsService = SearchAnalyticsService = __decorate([
102
+ (0, common_1.Injectable)(),
103
+ __metadata("design:paramtypes", [core_1.TransactionalConnection])
104
+ ], SearchAnalyticsService);
105
+ //# sourceMappingURL=search-analytics.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-analytics.service.js","sourceRoot":"","sources":["../src/search-analytics.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huloglobal/vendure-plugin-visitor-analytics",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
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>",
@@ -23,14 +23,14 @@
23
23
  "prepublishOnly": "yarn build"
24
24
  },
25
25
  "dependencies": {
26
- "@huloglobal/vendure-licence-sdk": "^0.4.0",
26
+ "@huloglobal/vendure-licence-sdk": "^0.6.0",
27
27
  "ua-parser-js": "^1.0.37",
28
28
  "geolite2-redist": "^3.1.0",
29
29
  "@maxmind/geoip2-node": "^5.0.0",
30
30
  "graphql-tag": "^2.12.7"
31
31
  },
32
32
  "peerDependencies": {
33
- "@vendure/core": ">=3.0.0",
33
+ "@vendure/core": ">=3.5.0 <4.0.0",
34
34
  "@nestjs/common": ">=10.0.0",
35
35
  "typeorm": ">=0.3.0"
36
36
  },