@huloglobal/vendure-plugin-visitor-analytics 0.4.3 → 0.6.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/LICENSE +676 -25
- package/dist/admin-api.d.ts +12 -0
- package/dist/admin-api.d.ts.map +1 -0
- package/dist/admin-api.js +264 -0
- package/dist/admin-api.js.map +1 -0
- package/dist/plugin.d.ts +4 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +20 -2
- package/dist/plugin.js.map +1 -1
- package/dist/visitor-tracking.controller.d.ts +1 -1
- package/dist/visitor-tracking.controller.d.ts.map +1 -1
- package/dist/visitor-tracking.controller.js +47 -0
- package/dist/visitor-tracking.controller.js.map +1 -1
- package/package.json +50 -49
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RequestContext, TransactionalConnection } from '@vendure/core';
|
|
2
|
+
export declare const visitorAnalyticsAdminApiSchema: import("graphql").DocumentNode;
|
|
3
|
+
export declare class VisitorAnalyticsAdminResolver {
|
|
4
|
+
private connection;
|
|
5
|
+
constructor(connection: TransactionalConnection);
|
|
6
|
+
huloVisitorSummary(ctx: RequestContext, channelId?: number, daysInput?: number): Promise<any>;
|
|
7
|
+
huloVisitorSources(channelId?: number, daysInput?: number): Promise<any[]>;
|
|
8
|
+
huloVisitorTopPages(channelId?: number, daysInput?: number): Promise<any[]>;
|
|
9
|
+
huloVisitorFunnel(input: any): Promise<any>;
|
|
10
|
+
huloVisitorJourney(visitorId: string): Promise<any[]>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=admin-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-api.d.ts","sourceRoot":"","sources":["../src/admin-api.ts"],"names":[],"mappings":"AAYA,OAAO,EAA0B,cAAc,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAEhG,eAAO,MAAM,8BAA8B,gCAsE1C,CAAC;AAUF,qBAEa,6BAA6B;IAC1B,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,uBAAuB;IAIjD,kBAAkB,CACb,GAAG,EAAE,cAAc,EACP,SAAS,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,MAAM,GACjC,OAAO,CAAC,GAAG,CAAC;IAsCT,kBAAkB,CAAoB,SAAS,CAAC,EAAE,MAAM,EAAgB,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAqB3G,mBAAmB,CAAoB,SAAS,CAAC,EAAE,MAAM,EAAgB,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IA0B5G,iBAAiB,CAAgB,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IA8B1D,kBAAkB,CAAoB,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;CAajF"}
|
|
@@ -0,0 +1,264 @@
|
|
|
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.VisitorAnalyticsAdminResolver = exports.visitorAnalyticsAdminApiSchema = void 0;
|
|
16
|
+
/**
|
|
17
|
+
* Vendure Admin API extensions for HULO Visitor Analytics.
|
|
18
|
+
*
|
|
19
|
+
* Mirrors the operator queries from the REST controller — summary,
|
|
20
|
+
* sources, top-pages, funnel, journey — so any GraphQL client can
|
|
21
|
+
* drive the dashboards. The high-frequency public path POST /ees/track
|
|
22
|
+
* stays REST: it's an anonymous beacon, ingests potentially millions
|
|
23
|
+
* of events / day, and benefits from being outside the resolver stack.
|
|
24
|
+
*/
|
|
25
|
+
const common_1 = require("@nestjs/common");
|
|
26
|
+
const graphql_1 = require("@nestjs/graphql");
|
|
27
|
+
const graphql_tag_1 = require("graphql-tag");
|
|
28
|
+
const core_1 = require("@vendure/core");
|
|
29
|
+
exports.visitorAnalyticsAdminApiSchema = (0, graphql_tag_1.gql) `
|
|
30
|
+
type HuloVisitorSummary {
|
|
31
|
+
days: Int!
|
|
32
|
+
channelId: Int
|
|
33
|
+
visitors: Int!
|
|
34
|
+
sessions: Int!
|
|
35
|
+
pageViews: Int!
|
|
36
|
+
events: Int!
|
|
37
|
+
bounceRate: Float!
|
|
38
|
+
avgSessionSec: Float!
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type HuloVisitorSource {
|
|
42
|
+
source: String!
|
|
43
|
+
visitors: Int!
|
|
44
|
+
sessions: Int!
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type HuloVisitorPage {
|
|
48
|
+
url: String!
|
|
49
|
+
title: String
|
|
50
|
+
views: Int!
|
|
51
|
+
uniqueVisitors: Int!
|
|
52
|
+
avgTimeOnPageSec: Float!
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type HuloFunnelStep {
|
|
56
|
+
index: Int!
|
|
57
|
+
urlPattern: String!
|
|
58
|
+
label: String
|
|
59
|
+
users: Int!
|
|
60
|
+
dropOffPct: Float!
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type HuloVisitorFunnel {
|
|
64
|
+
days: Int!
|
|
65
|
+
steps: [HuloFunnelStep!]!
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type HuloVisitorEvent {
|
|
69
|
+
id: ID!
|
|
70
|
+
createdAt: DateTime!
|
|
71
|
+
type: String!
|
|
72
|
+
url: String
|
|
73
|
+
title: String
|
|
74
|
+
referrerDomain: String
|
|
75
|
+
country: String
|
|
76
|
+
region: String
|
|
77
|
+
city: String
|
|
78
|
+
browser: String
|
|
79
|
+
os: String
|
|
80
|
+
device: String
|
|
81
|
+
sessionId: String!
|
|
82
|
+
visitorId: String!
|
|
83
|
+
customerId: Int
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
input HuloVisitorFunnelInput {
|
|
87
|
+
channelId: Int
|
|
88
|
+
days: Int
|
|
89
|
+
steps: [String!]!
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
extend type Query {
|
|
93
|
+
huloVisitorSummary(channelId: Int, days: Int): HuloVisitorSummary!
|
|
94
|
+
huloVisitorSources(channelId: Int, days: Int): [HuloVisitorSource!]!
|
|
95
|
+
huloVisitorTopPages(channelId: Int, days: Int): [HuloVisitorPage!]!
|
|
96
|
+
huloVisitorFunnel(input: HuloVisitorFunnelInput!): HuloVisitorFunnel!
|
|
97
|
+
huloVisitorJourney(visitorId: String!): [HuloVisitorEvent!]!
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
function clampDays(input) {
|
|
101
|
+
return Math.min(Math.max(Number(input) || 7, 1), 365);
|
|
102
|
+
}
|
|
103
|
+
function channelFilter(channelId) {
|
|
104
|
+
if (channelId)
|
|
105
|
+
return { where: ' AND channelId = ?', params: [channelId] };
|
|
106
|
+
return { where: '', params: [] };
|
|
107
|
+
}
|
|
108
|
+
let VisitorAnalyticsAdminResolver = class VisitorAnalyticsAdminResolver {
|
|
109
|
+
constructor(connection) {
|
|
110
|
+
this.connection = connection;
|
|
111
|
+
}
|
|
112
|
+
async huloVisitorSummary(ctx, channelId, daysInput) {
|
|
113
|
+
const days = clampDays(daysInput);
|
|
114
|
+
const c = channelFilter(channelId);
|
|
115
|
+
const totals = await this.connection.rawConnection.query(`SELECT COUNT(DISTINCT visitorId) AS visitors,
|
|
116
|
+
COUNT(DISTINCT sessionId) AS sessions,
|
|
117
|
+
SUM(type = 'pageview') AS pageViews,
|
|
118
|
+
COUNT(*) AS events
|
|
119
|
+
FROM visitor_event
|
|
120
|
+
WHERE createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)${c.where}`, [days, ...c.params]);
|
|
121
|
+
const t = totals[0] || {};
|
|
122
|
+
const sessionRows = await this.connection.rawConnection.query(`SELECT sessionId,
|
|
123
|
+
TIMESTAMPDIFF(SECOND, MIN(createdAt), MAX(createdAt)) AS dur,
|
|
124
|
+
COUNT(*) AS n
|
|
125
|
+
FROM visitor_event
|
|
126
|
+
WHERE createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)${c.where}
|
|
127
|
+
GROUP BY sessionId`, [days, ...c.params]);
|
|
128
|
+
const ssRows = sessionRows;
|
|
129
|
+
const bounces = ssRows.filter((s) => Number(s.n) <= 1).length;
|
|
130
|
+
const avg = ssRows.length ? ssRows.reduce((a, s) => a + Number(s.dur || 0), 0) / ssRows.length : 0;
|
|
131
|
+
return {
|
|
132
|
+
days, channelId: channelId || null,
|
|
133
|
+
visitors: Number(t.visitors) || 0,
|
|
134
|
+
sessions: Number(t.sessions) || 0,
|
|
135
|
+
pageViews: Number(t.pageViews) || 0,
|
|
136
|
+
events: Number(t.events) || 0,
|
|
137
|
+
bounceRate: ssRows.length ? bounces / ssRows.length : 0,
|
|
138
|
+
avgSessionSec: avg,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async huloVisitorSources(channelId, daysInput) {
|
|
142
|
+
const days = clampDays(daysInput);
|
|
143
|
+
const c = channelFilter(channelId);
|
|
144
|
+
const rows = await this.connection.rawConnection.query(`SELECT COALESCE(NULLIF(referrerDomain, ''), '(direct)') AS source,
|
|
145
|
+
COUNT(DISTINCT visitorId) AS visitors,
|
|
146
|
+
COUNT(DISTINCT sessionId) AS sessions
|
|
147
|
+
FROM visitor_event
|
|
148
|
+
WHERE createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)${c.where}
|
|
149
|
+
GROUP BY source ORDER BY sessions DESC LIMIT 50`, [days, ...c.params]);
|
|
150
|
+
return rows.map((r) => ({
|
|
151
|
+
source: r.source,
|
|
152
|
+
visitors: Number(r.visitors) || 0,
|
|
153
|
+
sessions: Number(r.sessions) || 0,
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
async huloVisitorTopPages(channelId, daysInput) {
|
|
157
|
+
const days = clampDays(daysInput);
|
|
158
|
+
const c = channelFilter(channelId);
|
|
159
|
+
const rows = await this.connection.rawConnection.query(`SELECT url,
|
|
160
|
+
MAX(title) AS title,
|
|
161
|
+
COUNT(*) AS views,
|
|
162
|
+
COUNT(DISTINCT visitorId) AS uniqueVisitors,
|
|
163
|
+
AVG(COALESCE(timeOnPageMs, 0)) / 1000 AS avgTimeOnPageSec
|
|
164
|
+
FROM visitor_event
|
|
165
|
+
WHERE type = 'pageview'
|
|
166
|
+
AND createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)${c.where}
|
|
167
|
+
GROUP BY url ORDER BY views DESC LIMIT 50`, [days, ...c.params]);
|
|
168
|
+
return rows.map((r) => ({
|
|
169
|
+
url: r.url || '',
|
|
170
|
+
title: r.title || null,
|
|
171
|
+
views: Number(r.views) || 0,
|
|
172
|
+
uniqueVisitors: Number(r.uniqueVisitors) || 0,
|
|
173
|
+
avgTimeOnPageSec: Number(r.avgTimeOnPageSec) || 0,
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
async huloVisitorFunnel(input) {
|
|
177
|
+
var _a;
|
|
178
|
+
const days = clampDays(input === null || input === void 0 ? void 0 : input.days);
|
|
179
|
+
const c = channelFilter(input === null || input === void 0 ? void 0 : input.channelId);
|
|
180
|
+
const steps = Array.isArray(input === null || input === void 0 ? void 0 : input.steps) ? input.steps.map(String) : [];
|
|
181
|
+
if (!steps.length)
|
|
182
|
+
return { days, steps: [] };
|
|
183
|
+
// For each step, count distinct visitors who hit it. This is a
|
|
184
|
+
// pageview-funnel approximation; ordered funnel (visitor must
|
|
185
|
+
// have hit step i-1 before i) is a future enhancement.
|
|
186
|
+
const out = [];
|
|
187
|
+
let prevUsers = null;
|
|
188
|
+
for (let i = 0; i < steps.length; i++) {
|
|
189
|
+
const pattern = steps[i];
|
|
190
|
+
const rows = await this.connection.rawConnection.query(`SELECT COUNT(DISTINCT visitorId) AS n
|
|
191
|
+
FROM visitor_event
|
|
192
|
+
WHERE type = 'pageview'
|
|
193
|
+
AND url LIKE ?
|
|
194
|
+
AND createdAt >= DATE_SUB(NOW(), INTERVAL ? DAY)${c.where}`, [pattern.replace(/\*/g, '%'), days, ...c.params]);
|
|
195
|
+
const users = Number((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.n) || 0;
|
|
196
|
+
const dropOff = prevUsers && prevUsers > 0 ? 1 - (users / prevUsers) : 0;
|
|
197
|
+
out.push({ index: i, urlPattern: pattern, label: null, users, dropOffPct: dropOff });
|
|
198
|
+
prevUsers = users;
|
|
199
|
+
}
|
|
200
|
+
return { days, steps: out };
|
|
201
|
+
}
|
|
202
|
+
async huloVisitorJourney(visitorId) {
|
|
203
|
+
if (!visitorId)
|
|
204
|
+
return [];
|
|
205
|
+
const rows = await this.connection.rawConnection.query(`SELECT id, createdAt, type, url, title, referrerDomain,
|
|
206
|
+
country, region, city, browser, os, device,
|
|
207
|
+
sessionId, visitorId, customerId
|
|
208
|
+
FROM visitor_event
|
|
209
|
+
WHERE visitorId = ?
|
|
210
|
+
ORDER BY createdAt ASC LIMIT 1000`, [String(visitorId)]);
|
|
211
|
+
return rows;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
exports.VisitorAnalyticsAdminResolver = VisitorAnalyticsAdminResolver;
|
|
215
|
+
__decorate([
|
|
216
|
+
(0, graphql_1.Query)(),
|
|
217
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
218
|
+
__param(0, (0, core_1.Ctx)()),
|
|
219
|
+
__param(1, (0, graphql_1.Args)('channelId')),
|
|
220
|
+
__param(2, (0, graphql_1.Args)('days')),
|
|
221
|
+
__metadata("design:type", Function),
|
|
222
|
+
__metadata("design:paramtypes", [core_1.RequestContext, Number, Number]),
|
|
223
|
+
__metadata("design:returntype", Promise)
|
|
224
|
+
], VisitorAnalyticsAdminResolver.prototype, "huloVisitorSummary", null);
|
|
225
|
+
__decorate([
|
|
226
|
+
(0, graphql_1.Query)(),
|
|
227
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
228
|
+
__param(0, (0, graphql_1.Args)('channelId')),
|
|
229
|
+
__param(1, (0, graphql_1.Args)('days')),
|
|
230
|
+
__metadata("design:type", Function),
|
|
231
|
+
__metadata("design:paramtypes", [Number, Number]),
|
|
232
|
+
__metadata("design:returntype", Promise)
|
|
233
|
+
], VisitorAnalyticsAdminResolver.prototype, "huloVisitorSources", null);
|
|
234
|
+
__decorate([
|
|
235
|
+
(0, graphql_1.Query)(),
|
|
236
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
237
|
+
__param(0, (0, graphql_1.Args)('channelId')),
|
|
238
|
+
__param(1, (0, graphql_1.Args)('days')),
|
|
239
|
+
__metadata("design:type", Function),
|
|
240
|
+
__metadata("design:paramtypes", [Number, Number]),
|
|
241
|
+
__metadata("design:returntype", Promise)
|
|
242
|
+
], VisitorAnalyticsAdminResolver.prototype, "huloVisitorTopPages", null);
|
|
243
|
+
__decorate([
|
|
244
|
+
(0, graphql_1.Query)(),
|
|
245
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
246
|
+
__param(0, (0, graphql_1.Args)('input')),
|
|
247
|
+
__metadata("design:type", Function),
|
|
248
|
+
__metadata("design:paramtypes", [Object]),
|
|
249
|
+
__metadata("design:returntype", Promise)
|
|
250
|
+
], VisitorAnalyticsAdminResolver.prototype, "huloVisitorFunnel", null);
|
|
251
|
+
__decorate([
|
|
252
|
+
(0, graphql_1.Query)(),
|
|
253
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
254
|
+
__param(0, (0, graphql_1.Args)('visitorId')),
|
|
255
|
+
__metadata("design:type", Function),
|
|
256
|
+
__metadata("design:paramtypes", [String]),
|
|
257
|
+
__metadata("design:returntype", Promise)
|
|
258
|
+
], VisitorAnalyticsAdminResolver.prototype, "huloVisitorJourney", null);
|
|
259
|
+
exports.VisitorAnalyticsAdminResolver = VisitorAnalyticsAdminResolver = __decorate([
|
|
260
|
+
(0, graphql_1.Resolver)(),
|
|
261
|
+
(0, common_1.Injectable)(),
|
|
262
|
+
__metadata("design:paramtypes", [core_1.TransactionalConnection])
|
|
263
|
+
], VisitorAnalyticsAdminResolver);
|
|
264
|
+
//# sourceMappingURL=admin-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-api.js","sourceRoot":"","sources":["../src/admin-api.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Type } from '@vendure/core';
|
|
2
|
-
import { RetentionOptions, UpdateChecker } from '@huloglobal/vendure-licence-sdk';
|
|
2
|
+
import { LicenceStatus, RetentionOptions, UpdateChecker } from '@huloglobal/vendure-licence-sdk';
|
|
3
3
|
export interface VisitorAnalyticsPluginOptions {
|
|
4
4
|
/** Public host of the Vendure server. Used in licence host-match. */
|
|
5
5
|
publicBaseUrl: string;
|
|
@@ -56,9 +56,12 @@ export declare function getOptions(): typeof DEFAULT_OPTIONS & VisitorAnalyticsP
|
|
|
56
56
|
export declare class VisitorAnalyticsPlugin {
|
|
57
57
|
private static revocation;
|
|
58
58
|
private static updateChecker;
|
|
59
|
+
private static heartbeat;
|
|
60
|
+
private static licenceStatus;
|
|
59
61
|
static getUpdateChecker(): UpdateChecker | null;
|
|
60
62
|
static getPackageVersion(): string;
|
|
61
63
|
static getPackageName(): string;
|
|
64
|
+
static getLicenceStatus(): LicenceStatus | null;
|
|
62
65
|
static init(options: VisitorAnalyticsPluginOptions): Type<VisitorAnalyticsPlugin>;
|
|
63
66
|
static uiExtensions: {
|
|
64
67
|
extensionPath: string;
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -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,EAAE,gBAAgB,EAAqB,aAAa,EAAiB,MAAM,iCAAiC,CAAC;
|
|
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,EAAiB,MAAM,iCAAiC,CAAC;AAWpK,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;CAChC;AAgBD,QAAA,MAAM,eAAe,EAAE,6BAMtB,CAAC;AAGF,wBAAgB,UAAU,IAAI,OAAO,eAAe,GAAG,6BAA6B,CAEnF;AAED;;;;;;;;;;;GAWG;AACH,qBAWa,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;IA4CjF,MAAM,CAAC,YAAY;;;;;;;;MAUjB;CACL"}
|
package/dist/plugin.js
CHANGED
|
@@ -14,6 +14,7 @@ const vendure_licence_sdk_1 = require("@huloglobal/vendure-licence-sdk");
|
|
|
14
14
|
const conversion_goal_entity_1 = require("./conversion-goal.entity");
|
|
15
15
|
const visitor_event_entity_1 = require("./visitor-event.entity");
|
|
16
16
|
const visitor_tracking_service_1 = require("./visitor-tracking.service");
|
|
17
|
+
const admin_api_1 = require("./admin-api");
|
|
17
18
|
const visitor_tracking_controller_1 = require("./visitor-tracking.controller");
|
|
18
19
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
20
|
const PKG_VERSION = require('../package.json').version;
|
|
@@ -57,6 +58,7 @@ let VisitorAnalyticsPlugin = VisitorAnalyticsPlugin_1 = class VisitorAnalyticsPl
|
|
|
57
58
|
static getUpdateChecker() { return VisitorAnalyticsPlugin_1.updateChecker; }
|
|
58
59
|
static getPackageVersion() { return PKG_VERSION; }
|
|
59
60
|
static getPackageName() { return PKG_NAME; }
|
|
61
|
+
static getLicenceStatus() { return VisitorAnalyticsPlugin_1.licenceStatus; }
|
|
60
62
|
static init(options) {
|
|
61
63
|
cachedOptions = options;
|
|
62
64
|
if (!VisitorAnalyticsPlugin_1.revocation) {
|
|
@@ -76,10 +78,20 @@ let VisitorAnalyticsPlugin = VisitorAnalyticsPlugin_1 = class VisitorAnalyticsPl
|
|
|
76
78
|
publicKey: HULO_PUBLIC_KEY,
|
|
77
79
|
revokedIds: VisitorAnalyticsPlugin_1.revocation.getRevokedIds(),
|
|
78
80
|
});
|
|
81
|
+
VisitorAnalyticsPlugin_1.licenceStatus = status;
|
|
79
82
|
if (!status.valid) {
|
|
80
83
|
// eslint-disable-next-line no-console
|
|
81
84
|
console.warn(`[@huloglobal/vendure-plugin-visitor-analytics] ${status.message}` +
|
|
82
|
-
` — Running in
|
|
85
|
+
` — Running in FREE tier: 100 events/day cap, conversion goals disabled, live SSE feed disabled, CSV export disabled. Buy a licence at https://elite.charity/licence/buy/${PLUGIN_ID}`);
|
|
86
|
+
}
|
|
87
|
+
if (!VisitorAnalyticsPlugin_1.heartbeat) {
|
|
88
|
+
VisitorAnalyticsPlugin_1.heartbeat = new vendure_licence_sdk_1.Heartbeat({
|
|
89
|
+
packageName: PKG_NAME,
|
|
90
|
+
packageVersion: PKG_VERSION,
|
|
91
|
+
licenceKey: options.licenceKey,
|
|
92
|
+
publicKeyFingerprint: (0, vendure_licence_sdk_1.fingerprintPublicKey)(HULO_PUBLIC_KEY),
|
|
93
|
+
});
|
|
94
|
+
VisitorAnalyticsPlugin_1.heartbeat.start();
|
|
83
95
|
}
|
|
84
96
|
return VisitorAnalyticsPlugin_1;
|
|
85
97
|
}
|
|
@@ -87,6 +99,8 @@ let VisitorAnalyticsPlugin = VisitorAnalyticsPlugin_1 = class VisitorAnalyticsPl
|
|
|
87
99
|
exports.VisitorAnalyticsPlugin = VisitorAnalyticsPlugin;
|
|
88
100
|
VisitorAnalyticsPlugin.revocation = null;
|
|
89
101
|
VisitorAnalyticsPlugin.updateChecker = null;
|
|
102
|
+
VisitorAnalyticsPlugin.heartbeat = null;
|
|
103
|
+
VisitorAnalyticsPlugin.licenceStatus = null;
|
|
90
104
|
VisitorAnalyticsPlugin.uiExtensions = {
|
|
91
105
|
extensionPath: __dirname + '/../ui',
|
|
92
106
|
ngModules: [
|
|
@@ -101,10 +115,14 @@ VisitorAnalyticsPlugin.uiExtensions = {
|
|
|
101
115
|
exports.VisitorAnalyticsPlugin = VisitorAnalyticsPlugin = VisitorAnalyticsPlugin_1 = __decorate([
|
|
102
116
|
(0, core_1.VendurePlugin)({
|
|
103
117
|
imports: [core_1.PluginCommonModule],
|
|
104
|
-
providers: [visitor_tracking_service_1.VisitorTrackingService],
|
|
118
|
+
providers: [visitor_tracking_service_1.VisitorTrackingService, admin_api_1.VisitorAnalyticsAdminResolver],
|
|
105
119
|
controllers: [visitor_tracking_controller_1.VisitorTrackingController],
|
|
106
120
|
entities: [visitor_event_entity_1.VisitorEvent, conversion_goal_entity_1.ConversionGoal],
|
|
107
121
|
compatibility: '^3.0.0',
|
|
122
|
+
adminApiExtensions: {
|
|
123
|
+
schema: admin_api_1.visitorAnalyticsAdminApiSchema,
|
|
124
|
+
resolvers: [admin_api_1.VisitorAnalyticsAdminResolver],
|
|
125
|
+
},
|
|
108
126
|
})
|
|
109
127
|
], VisitorAnalyticsPlugin);
|
|
110
128
|
//# sourceMappingURL=plugin.js.map
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,7 +56,7 @@ export declare class VisitorTrackingController implements OnApplicationBootstrap
|
|
|
56
56
|
* Each event payload:
|
|
57
57
|
* data: { ts, activeCount, recent: [{ visitorId, url, country, secondsAgo }] }
|
|
58
58
|
*/
|
|
59
|
-
live(ctx: RequestContext, req: Request, res: Response): Promise<
|
|
59
|
+
live(ctx: RequestContext, req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
60
60
|
/** Journey timeline for one visitor — every event in order. */
|
|
61
61
|
journey(ctx: RequestContext, visitorId: string, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
62
62
|
/** Recent visitors — paginated via take + skip. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visitor-tracking.controller.d.ts","sourceRoot":"","sources":["../src/visitor-tracking.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,sBAAsB,EAAE,eAAe,EAA8B,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"visitor-tracking.controller.d.ts","sourceRoot":"","sources":["../src/visitor-tracking.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,35 @@ const COOKIE_VISITOR = 'ees_vid';
|
|
|
24
24
|
const COOKIE_SESSION = 'ees_sid';
|
|
25
25
|
const VISITOR_TTL_DAYS = 730; // ~2 years
|
|
26
26
|
const SESSION_IDLE_MIN = 30; // 30-minute idle session timeout
|
|
27
|
+
/** Free-tier daily event cap. 100 / UTC day across the whole install
|
|
28
|
+
* — enough to evaluate, not enough to run a real store on. The
|
|
29
|
+
* counter is in-memory only (acceptable: free-tier installs aren't
|
|
30
|
+
* multi-instance anyway, and resetting on restart works in the
|
|
31
|
+
* customer's favour). */
|
|
32
|
+
const FREE_TIER_DAILY_CAP = 100;
|
|
33
|
+
const freeTierBudget = (() => {
|
|
34
|
+
let day = '';
|
|
35
|
+
let used = 0;
|
|
36
|
+
return {
|
|
37
|
+
consume(n) {
|
|
38
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
39
|
+
if (today !== day) {
|
|
40
|
+
day = today;
|
|
41
|
+
used = 0;
|
|
42
|
+
}
|
|
43
|
+
if (used + n > FREE_TIER_DAILY_CAP)
|
|
44
|
+
return false;
|
|
45
|
+
used += n;
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
snapshot() {
|
|
49
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
50
|
+
if (today !== day)
|
|
51
|
+
return { day: today, used: 0, cap: FREE_TIER_DAILY_CAP };
|
|
52
|
+
return { day, used, cap: FREE_TIER_DAILY_CAP };
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
})();
|
|
27
56
|
function requireAdmin(ctx, res) {
|
|
28
57
|
if (!(ctx === null || ctx === void 0 ? void 0 : ctx.activeUserId)) {
|
|
29
58
|
res.status(401).json({ error: 'Authentication required' });
|
|
@@ -107,6 +136,15 @@ let VisitorTrackingController = class VisitorTrackingController {
|
|
|
107
136
|
return res.status(204).end();
|
|
108
137
|
if (this.rateLimited(req, res, 'track'))
|
|
109
138
|
return;
|
|
139
|
+
// Tier-gate: unlicensed installs are capped at 100 events / UTC day.
|
|
140
|
+
// Once the cap is hit, /track returns 200 with `skipped: 'free-tier-cap'`
|
|
141
|
+
// so the storefront's beacon doesn't surface errors to end users.
|
|
142
|
+
if (!(0, vendure_licence_sdk_1.isLicensed)(plugin_1.VisitorAnalyticsPlugin.getLicenceStatus())) {
|
|
143
|
+
const eventsLen = Array.isArray((body || {}).events) ? body.events.length : 1;
|
|
144
|
+
if (!freeTierBudget.consume(eventsLen)) {
|
|
145
|
+
return res.json({ stored: 0, skipped: 'free-tier-cap', cap: FREE_TIER_DAILY_CAP });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
110
148
|
const opts = (0, plugin_1.getOptions)();
|
|
111
149
|
// Privacy: honour Do-Not-Track when configured. We still return 200
|
|
112
150
|
// so the storefront can't tell the difference between "stored" and
|
|
@@ -397,6 +435,9 @@ let VisitorTrackingController = class VisitorTrackingController {
|
|
|
397
435
|
var _a;
|
|
398
436
|
if (!requireAdmin(ctx, res))
|
|
399
437
|
return;
|
|
438
|
+
if (!(0, vendure_licence_sdk_1.isLicensed)(plugin_1.VisitorAnalyticsPlugin.getLicenceStatus())) {
|
|
439
|
+
return res.status(402).json((0, vendure_licence_sdk_1.premiumFeatureError)('vendure-plugin-visitor-analytics'));
|
|
440
|
+
}
|
|
400
441
|
res.setHeader('Content-Type', 'text/event-stream');
|
|
401
442
|
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
402
443
|
res.setHeader('Connection', 'keep-alive');
|
|
@@ -656,6 +697,9 @@ let VisitorTrackingController = class VisitorTrackingController {
|
|
|
656
697
|
async createGoal(ctx, body, res) {
|
|
657
698
|
if (!requireAdmin(ctx, res))
|
|
658
699
|
return;
|
|
700
|
+
if (!(0, vendure_licence_sdk_1.isLicensed)(plugin_1.VisitorAnalyticsPlugin.getLicenceStatus())) {
|
|
701
|
+
return res.status(402).json((0, vendure_licence_sdk_1.premiumFeatureError)('vendure-plugin-visitor-analytics'));
|
|
702
|
+
}
|
|
659
703
|
const repo = this.connection.rawConnection.getRepository(conversion_goal_entity_1.ConversionGoal);
|
|
660
704
|
const row = repo.create({
|
|
661
705
|
channelId: Number(body === null || body === void 0 ? void 0 : body.channelId) || 1,
|
|
@@ -727,6 +771,9 @@ let VisitorTrackingController = class VisitorTrackingController {
|
|
|
727
771
|
async exportCsv(ctx, req, res) {
|
|
728
772
|
if (!requireAdmin(ctx, res))
|
|
729
773
|
return;
|
|
774
|
+
if (!(0, vendure_licence_sdk_1.isLicensed)(plugin_1.VisitorAnalyticsPlugin.getLicenceStatus())) {
|
|
775
|
+
return res.status(402).json((0, vendure_licence_sdk_1.premiumFeatureError)('vendure-plugin-visitor-analytics'));
|
|
776
|
+
}
|
|
730
777
|
const days = Math.min(Math.max(parseInt(String(req.query.days || '7'), 10) || 7, 1), 90);
|
|
731
778
|
const rows = await this.connection.rawConnection.query(`SELECT createdAt, visitorId, sessionId, customerId, channelId,
|
|
732
779
|
type, url, title, referrerDomain,
|