@seneris/nosework 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +535 -0
- package/dist/client/errors.d.ts +49 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +173 -0
- package/dist/client/errors.js.map +1 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +29 -0
- package/dist/client.js.map +1 -0
- package/dist/error.d.ts +40 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +248 -0
- package/dist/error.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/query.d.ts +48 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +471 -0
- package/dist/query.js.map +1 -0
- package/dist/track.d.ts +4 -0
- package/dist/track.d.ts.map +1 -0
- package/dist/track.js +74 -0
- package/dist/track.js.map +1 -0
- package/dist/types.d.ts +157 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ua.d.ts +3 -0
- package/dist/ua.d.ts.map +1 -0
- package/dist/ua.js +40 -0
- package/dist/ua.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +112 -0
- package/dist/utils.js.map +1 -0
- package/package.json +54 -0
- package/prisma/schema.prisma +145 -0
package/dist/query.js
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { getClient } from "./client.js";
|
|
2
|
+
function buildWhere(options) {
|
|
3
|
+
return {
|
|
4
|
+
siteId: options.siteId,
|
|
5
|
+
timestamp: {
|
|
6
|
+
gte: options.startDate,
|
|
7
|
+
lte: options.endDate,
|
|
8
|
+
},
|
|
9
|
+
isBot: false, // Exclude bots by default
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export async function getStats(options) {
|
|
13
|
+
const db = getClient();
|
|
14
|
+
const where = buildWhere(options);
|
|
15
|
+
// Get page views count
|
|
16
|
+
const pageViews = await db.pageView.count({ where });
|
|
17
|
+
// Get unique visitors
|
|
18
|
+
const visitorsResult = await db.pageView.groupBy({
|
|
19
|
+
by: ["visitorHash"],
|
|
20
|
+
where,
|
|
21
|
+
});
|
|
22
|
+
const visitors = visitorsResult.length;
|
|
23
|
+
// Get unique sessions
|
|
24
|
+
const sessionsResult = await db.pageView.groupBy({
|
|
25
|
+
by: ["sessionId"],
|
|
26
|
+
where,
|
|
27
|
+
});
|
|
28
|
+
const sessions = sessionsResult.length;
|
|
29
|
+
// Calculate bounce rate (sessions with only 1 page view)
|
|
30
|
+
const sessionPageCounts = await db.pageView.groupBy({
|
|
31
|
+
by: ["sessionId"],
|
|
32
|
+
where,
|
|
33
|
+
_count: { id: true },
|
|
34
|
+
});
|
|
35
|
+
const bouncedSessions = sessionPageCounts.filter((s) => s._count.id === 1).length;
|
|
36
|
+
const bounceRate = sessions > 0 ? (bouncedSessions / sessions) * 100 : 0;
|
|
37
|
+
return {
|
|
38
|
+
pageViews,
|
|
39
|
+
visitors,
|
|
40
|
+
sessions,
|
|
41
|
+
bounceRate: Math.round(bounceRate * 100) / 100,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export async function getTopPages(options) {
|
|
45
|
+
const db = getClient();
|
|
46
|
+
const where = buildWhere(options);
|
|
47
|
+
const limit = options.limit ?? 10;
|
|
48
|
+
// Group by pathname and count
|
|
49
|
+
const results = await db.pageView.groupBy({
|
|
50
|
+
by: ["pathname"],
|
|
51
|
+
where,
|
|
52
|
+
_count: { id: true },
|
|
53
|
+
});
|
|
54
|
+
// Get unique visitors per page (need separate query)
|
|
55
|
+
const pageVisitors = await Promise.all(results.map(async (r) => {
|
|
56
|
+
const uniqueVisitors = await db.pageView.groupBy({
|
|
57
|
+
by: ["visitorHash"],
|
|
58
|
+
where: { ...where, pathname: r.pathname },
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
pathname: r.pathname,
|
|
62
|
+
pageViews: r._count.id,
|
|
63
|
+
visitors: uniqueVisitors.length,
|
|
64
|
+
};
|
|
65
|
+
}));
|
|
66
|
+
// Sort by page views and limit
|
|
67
|
+
return pageVisitors
|
|
68
|
+
.sort((a, b) => b.pageViews - a.pageViews)
|
|
69
|
+
.slice(0, limit);
|
|
70
|
+
}
|
|
71
|
+
export async function getLocations(options) {
|
|
72
|
+
const db = getClient();
|
|
73
|
+
const where = buildWhere(options);
|
|
74
|
+
const limit = options.limit ?? 20;
|
|
75
|
+
// Group by country and city
|
|
76
|
+
const results = await db.pageView.groupBy({
|
|
77
|
+
by: ["country", "countryCode", "city"],
|
|
78
|
+
where,
|
|
79
|
+
_count: { id: true },
|
|
80
|
+
});
|
|
81
|
+
// Get unique visitors per location
|
|
82
|
+
const locationData = await Promise.all(results.map(async (r) => {
|
|
83
|
+
const uniqueVisitors = await db.pageView.groupBy({
|
|
84
|
+
by: ["visitorHash"],
|
|
85
|
+
where: {
|
|
86
|
+
...where,
|
|
87
|
+
country: r.country,
|
|
88
|
+
city: r.city,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
country: r.country,
|
|
93
|
+
countryCode: r.countryCode,
|
|
94
|
+
city: r.city,
|
|
95
|
+
pageViews: r._count.id,
|
|
96
|
+
visitors: uniqueVisitors.length,
|
|
97
|
+
};
|
|
98
|
+
}));
|
|
99
|
+
// Sort by page views and limit
|
|
100
|
+
return locationData
|
|
101
|
+
.sort((a, b) => b.pageViews - a.pageViews)
|
|
102
|
+
.slice(0, limit);
|
|
103
|
+
}
|
|
104
|
+
export async function getReferrers(options) {
|
|
105
|
+
const db = getClient();
|
|
106
|
+
const where = buildWhere(options);
|
|
107
|
+
const limit = options.limit ?? 10;
|
|
108
|
+
// Group by referrer
|
|
109
|
+
const results = await db.pageView.groupBy({
|
|
110
|
+
by: ["referrer"],
|
|
111
|
+
where,
|
|
112
|
+
_count: { id: true },
|
|
113
|
+
});
|
|
114
|
+
// Get unique visitors per referrer
|
|
115
|
+
const referrerData = await Promise.all(results.map(async (r) => {
|
|
116
|
+
const uniqueVisitors = await db.pageView.groupBy({
|
|
117
|
+
by: ["visitorHash"],
|
|
118
|
+
where: { ...where, referrer: r.referrer },
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
referrer: r.referrer,
|
|
122
|
+
pageViews: r._count.id,
|
|
123
|
+
visitors: uniqueVisitors.length,
|
|
124
|
+
};
|
|
125
|
+
}));
|
|
126
|
+
// Sort by page views and limit
|
|
127
|
+
return referrerData
|
|
128
|
+
.sort((a, b) => b.pageViews - a.pageViews)
|
|
129
|
+
.slice(0, limit);
|
|
130
|
+
}
|
|
131
|
+
export async function getDevices(options) {
|
|
132
|
+
const db = getClient();
|
|
133
|
+
const where = buildWhere(options);
|
|
134
|
+
const limit = options.limit ?? 10;
|
|
135
|
+
// Group by device, browser, os
|
|
136
|
+
const results = await db.pageView.groupBy({
|
|
137
|
+
by: ["device", "browser", "os"],
|
|
138
|
+
where,
|
|
139
|
+
_count: { id: true },
|
|
140
|
+
});
|
|
141
|
+
// Get unique visitors per device combo
|
|
142
|
+
const deviceData = await Promise.all(results.map(async (r) => {
|
|
143
|
+
const uniqueVisitors = await db.pageView.groupBy({
|
|
144
|
+
by: ["visitorHash"],
|
|
145
|
+
where: {
|
|
146
|
+
...where,
|
|
147
|
+
device: r.device,
|
|
148
|
+
browser: r.browser,
|
|
149
|
+
os: r.os,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
device: r.device,
|
|
154
|
+
browser: r.browser,
|
|
155
|
+
os: r.os,
|
|
156
|
+
pageViews: r._count.id,
|
|
157
|
+
visitors: uniqueVisitors.length,
|
|
158
|
+
};
|
|
159
|
+
}));
|
|
160
|
+
// Sort by page views and limit
|
|
161
|
+
return deviceData
|
|
162
|
+
.sort((a, b) => b.pageViews - a.pageViews)
|
|
163
|
+
.slice(0, limit);
|
|
164
|
+
}
|
|
165
|
+
export async function getTimeSeries(options) {
|
|
166
|
+
const db = getClient();
|
|
167
|
+
const where = buildWhere(options);
|
|
168
|
+
const interval = options.interval ?? "day";
|
|
169
|
+
// Get all page views in range
|
|
170
|
+
const pageViews = await db.pageView.findMany({
|
|
171
|
+
where,
|
|
172
|
+
select: { timestamp: true, visitorHash: true },
|
|
173
|
+
orderBy: { timestamp: "asc" },
|
|
174
|
+
});
|
|
175
|
+
// Group by interval
|
|
176
|
+
const groups = new Map();
|
|
177
|
+
for (const pv of pageViews) {
|
|
178
|
+
const key = formatDateKey(pv.timestamp, interval);
|
|
179
|
+
const group = groups.get(key) ?? { views: 0, visitors: new Set() };
|
|
180
|
+
group.views++;
|
|
181
|
+
group.visitors.add(pv.visitorHash);
|
|
182
|
+
groups.set(key, group);
|
|
183
|
+
}
|
|
184
|
+
// Convert to array
|
|
185
|
+
return Array.from(groups.entries()).map(([date, data]) => ({
|
|
186
|
+
date,
|
|
187
|
+
pageViews: data.views,
|
|
188
|
+
visitors: data.visitors.size,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
function formatDateKey(date, interval) {
|
|
192
|
+
const d = new Date(date);
|
|
193
|
+
switch (interval) {
|
|
194
|
+
case "hour":
|
|
195
|
+
return d.toISOString().slice(0, 13) + ":00";
|
|
196
|
+
case "day":
|
|
197
|
+
return d.toISOString().slice(0, 10);
|
|
198
|
+
case "week": {
|
|
199
|
+
// Get start of week (Sunday)
|
|
200
|
+
const day = d.getDay();
|
|
201
|
+
d.setDate(d.getDate() - day);
|
|
202
|
+
return d.toISOString().slice(0, 10);
|
|
203
|
+
}
|
|
204
|
+
case "month":
|
|
205
|
+
return d.toISOString().slice(0, 7);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// ============================================
|
|
209
|
+
// Session Analytics Functions
|
|
210
|
+
// ============================================
|
|
211
|
+
/**
|
|
212
|
+
* Get aggregate session statistics
|
|
213
|
+
*/
|
|
214
|
+
export async function getSessionStats(options) {
|
|
215
|
+
const db = getClient();
|
|
216
|
+
const where = buildWhere(options);
|
|
217
|
+
// Get all page views grouped by session
|
|
218
|
+
const pageViews = await db.pageView.findMany({
|
|
219
|
+
where,
|
|
220
|
+
select: { sessionId: true, timestamp: true },
|
|
221
|
+
orderBy: { timestamp: "asc" },
|
|
222
|
+
});
|
|
223
|
+
// Group page views by session
|
|
224
|
+
const sessions = new Map();
|
|
225
|
+
for (const pv of pageViews) {
|
|
226
|
+
const timestamps = sessions.get(pv.sessionId) ?? [];
|
|
227
|
+
timestamps.push(pv.timestamp);
|
|
228
|
+
sessions.set(pv.sessionId, timestamps);
|
|
229
|
+
}
|
|
230
|
+
const totalSessions = sessions.size;
|
|
231
|
+
if (totalSessions === 0) {
|
|
232
|
+
return {
|
|
233
|
+
totalSessions: 0,
|
|
234
|
+
avgDuration: 0,
|
|
235
|
+
avgPagesPerSession: 0,
|
|
236
|
+
bounceRate: 0,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
let totalDuration = 0;
|
|
240
|
+
let totalPageCount = 0;
|
|
241
|
+
let bounceCount = 0;
|
|
242
|
+
for (const timestamps of sessions.values()) {
|
|
243
|
+
const pageCount = timestamps.length;
|
|
244
|
+
totalPageCount += pageCount;
|
|
245
|
+
if (pageCount === 1) {
|
|
246
|
+
bounceCount++;
|
|
247
|
+
// Single page view = 0 duration
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Duration = last timestamp - first timestamp
|
|
251
|
+
const sorted = timestamps.sort((a, b) => a.getTime() - b.getTime());
|
|
252
|
+
const firstTimestamp = sorted[0];
|
|
253
|
+
const lastTimestamp = sorted[sorted.length - 1];
|
|
254
|
+
if (firstTimestamp && lastTimestamp) {
|
|
255
|
+
const duration = (lastTimestamp.getTime() - firstTimestamp.getTime()) / 1000;
|
|
256
|
+
totalDuration += duration;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
totalSessions,
|
|
262
|
+
avgDuration: Math.round(totalDuration / totalSessions),
|
|
263
|
+
avgPagesPerSession: Math.round((totalPageCount / totalSessions) * 100) / 100,
|
|
264
|
+
bounceRate: Math.round((bounceCount / totalSessions) * 100 * 100) / 100,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get entry pages (first page of each session)
|
|
269
|
+
*/
|
|
270
|
+
export async function getEntryPages(options) {
|
|
271
|
+
const db = getClient();
|
|
272
|
+
const where = buildWhere(options);
|
|
273
|
+
const limit = options.limit ?? 10;
|
|
274
|
+
// Get all page views with session info
|
|
275
|
+
const pageViews = await db.pageView.findMany({
|
|
276
|
+
where,
|
|
277
|
+
select: { sessionId: true, pathname: true, timestamp: true },
|
|
278
|
+
orderBy: { timestamp: "asc" },
|
|
279
|
+
});
|
|
280
|
+
// Find first page view per session
|
|
281
|
+
const sessionFirstPages = new Map();
|
|
282
|
+
for (const pv of pageViews) {
|
|
283
|
+
if (!sessionFirstPages.has(pv.sessionId)) {
|
|
284
|
+
sessionFirstPages.set(pv.sessionId, pv.pathname);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Count entry pages
|
|
288
|
+
const entryPageCounts = new Map();
|
|
289
|
+
for (const pathname of sessionFirstPages.values()) {
|
|
290
|
+
entryPageCounts.set(pathname, (entryPageCounts.get(pathname) ?? 0) + 1);
|
|
291
|
+
}
|
|
292
|
+
const totalSessions = sessionFirstPages.size;
|
|
293
|
+
// Convert to array and sort
|
|
294
|
+
return Array.from(entryPageCounts.entries())
|
|
295
|
+
.map(([pathname, count]) => ({
|
|
296
|
+
pathname,
|
|
297
|
+
count,
|
|
298
|
+
percentage: Math.round((count / totalSessions) * 100 * 100) / 100,
|
|
299
|
+
}))
|
|
300
|
+
.sort((a, b) => b.count - a.count)
|
|
301
|
+
.slice(0, limit);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Get exit pages (last page of each session)
|
|
305
|
+
*/
|
|
306
|
+
export async function getExitPages(options) {
|
|
307
|
+
const db = getClient();
|
|
308
|
+
const where = buildWhere(options);
|
|
309
|
+
const limit = options.limit ?? 10;
|
|
310
|
+
// Get all page views with session info
|
|
311
|
+
const pageViews = await db.pageView.findMany({
|
|
312
|
+
where,
|
|
313
|
+
select: { sessionId: true, pathname: true, timestamp: true },
|
|
314
|
+
orderBy: { timestamp: "desc" }, // Descending to get last pages first
|
|
315
|
+
});
|
|
316
|
+
// Find last page view per session
|
|
317
|
+
const sessionLastPages = new Map();
|
|
318
|
+
for (const pv of pageViews) {
|
|
319
|
+
if (!sessionLastPages.has(pv.sessionId)) {
|
|
320
|
+
sessionLastPages.set(pv.sessionId, pv.pathname);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Count exit pages
|
|
324
|
+
const exitPageCounts = new Map();
|
|
325
|
+
for (const pathname of sessionLastPages.values()) {
|
|
326
|
+
exitPageCounts.set(pathname, (exitPageCounts.get(pathname) ?? 0) + 1);
|
|
327
|
+
}
|
|
328
|
+
const totalSessions = sessionLastPages.size;
|
|
329
|
+
// Convert to array and sort
|
|
330
|
+
return Array.from(exitPageCounts.entries())
|
|
331
|
+
.map(([pathname, count]) => ({
|
|
332
|
+
pathname,
|
|
333
|
+
count,
|
|
334
|
+
percentage: Math.round((count / totalSessions) * 100 * 100) / 100,
|
|
335
|
+
}))
|
|
336
|
+
.sort((a, b) => b.count - a.count)
|
|
337
|
+
.slice(0, limit);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get common page flow paths (sequence of pages in sessions)
|
|
341
|
+
*/
|
|
342
|
+
export async function getPageFlows(options) {
|
|
343
|
+
const db = getClient();
|
|
344
|
+
const where = buildWhere(options);
|
|
345
|
+
const limit = options.limit ?? 10;
|
|
346
|
+
const maxPathLength = options.maxPathLength ?? 5;
|
|
347
|
+
// Get all page views with session info
|
|
348
|
+
const pageViews = await db.pageView.findMany({
|
|
349
|
+
where,
|
|
350
|
+
select: { sessionId: true, pathname: true, timestamp: true },
|
|
351
|
+
orderBy: { timestamp: "asc" },
|
|
352
|
+
});
|
|
353
|
+
// Build paths per session
|
|
354
|
+
const sessionPaths = new Map();
|
|
355
|
+
for (const pv of pageViews) {
|
|
356
|
+
const path = sessionPaths.get(pv.sessionId) ?? [];
|
|
357
|
+
// Only add if different from last (avoid duplicates from refreshes)
|
|
358
|
+
if (path.length === 0 || path[path.length - 1] !== pv.pathname) {
|
|
359
|
+
path.push(pv.pathname);
|
|
360
|
+
}
|
|
361
|
+
sessionPaths.set(pv.sessionId, path);
|
|
362
|
+
}
|
|
363
|
+
// Truncate paths and count
|
|
364
|
+
const pathCounts = new Map();
|
|
365
|
+
for (const path of sessionPaths.values()) {
|
|
366
|
+
const truncated = path.slice(0, maxPathLength);
|
|
367
|
+
const key = JSON.stringify(truncated);
|
|
368
|
+
pathCounts.set(key, (pathCounts.get(key) ?? 0) + 1);
|
|
369
|
+
}
|
|
370
|
+
const totalSessions = sessionPaths.size;
|
|
371
|
+
// Convert to array and sort
|
|
372
|
+
return Array.from(pathCounts.entries())
|
|
373
|
+
.map(([key, count]) => ({
|
|
374
|
+
path: JSON.parse(key),
|
|
375
|
+
count,
|
|
376
|
+
percentage: Math.round((count / totalSessions) * 100 * 100) / 100,
|
|
377
|
+
}))
|
|
378
|
+
.sort((a, b) => b.count - a.count)
|
|
379
|
+
.slice(0, limit);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Get individual session data (for debugging/analysis)
|
|
383
|
+
*/
|
|
384
|
+
export async function getSessions(options) {
|
|
385
|
+
const db = getClient();
|
|
386
|
+
const where = buildWhere(options);
|
|
387
|
+
const limit = options.limit ?? 50;
|
|
388
|
+
const offset = options.offset ?? 0;
|
|
389
|
+
// Get all page views
|
|
390
|
+
const pageViews = await db.pageView.findMany({
|
|
391
|
+
where,
|
|
392
|
+
select: {
|
|
393
|
+
sessionId: true,
|
|
394
|
+
visitorHash: true,
|
|
395
|
+
pathname: true,
|
|
396
|
+
timestamp: true,
|
|
397
|
+
country: true,
|
|
398
|
+
device: true,
|
|
399
|
+
browser: true,
|
|
400
|
+
},
|
|
401
|
+
orderBy: { timestamp: "asc" },
|
|
402
|
+
});
|
|
403
|
+
// Group by session
|
|
404
|
+
const sessionMap = new Map();
|
|
405
|
+
for (const pv of pageViews) {
|
|
406
|
+
const existing = sessionMap.get(pv.sessionId);
|
|
407
|
+
if (existing) {
|
|
408
|
+
existing.pages.push({ pathname: pv.pathname, timestamp: pv.timestamp });
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
sessionMap.set(pv.sessionId, {
|
|
412
|
+
visitorHash: pv.visitorHash,
|
|
413
|
+
pages: [{ pathname: pv.pathname, timestamp: pv.timestamp }],
|
|
414
|
+
country: pv.country,
|
|
415
|
+
device: pv.device,
|
|
416
|
+
browser: pv.browser,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// Convert to SessionData array
|
|
421
|
+
const sessions = [];
|
|
422
|
+
for (const [sessionId, data] of sessionMap.entries()) {
|
|
423
|
+
const sortedPages = data.pages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
424
|
+
const firstPage = sortedPages[0];
|
|
425
|
+
const lastPage = sortedPages[sortedPages.length - 1];
|
|
426
|
+
// Skip if somehow we have no pages (shouldn't happen)
|
|
427
|
+
if (!firstPage || !lastPage)
|
|
428
|
+
continue;
|
|
429
|
+
const startTime = firstPage.timestamp;
|
|
430
|
+
const endTime = lastPage.timestamp;
|
|
431
|
+
const duration = Math.round((endTime.getTime() - startTime.getTime()) / 1000);
|
|
432
|
+
sessions.push({
|
|
433
|
+
sessionId,
|
|
434
|
+
visitorHash: data.visitorHash,
|
|
435
|
+
startTime,
|
|
436
|
+
endTime,
|
|
437
|
+
duration,
|
|
438
|
+
pageCount: sortedPages.length,
|
|
439
|
+
entryPage: firstPage.pathname,
|
|
440
|
+
exitPage: lastPage.pathname,
|
|
441
|
+
isBounce: sortedPages.length === 1,
|
|
442
|
+
country: data.country,
|
|
443
|
+
device: data.device,
|
|
444
|
+
browser: data.browser,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
// Sort by startTime descending (most recent first) and paginate
|
|
448
|
+
return sessions
|
|
449
|
+
.sort((a, b) => b.startTime.getTime() - a.startTime.getTime())
|
|
450
|
+
.slice(offset, offset + limit);
|
|
451
|
+
}
|
|
452
|
+
// Get or create a site
|
|
453
|
+
export async function getOrCreateSite(domain, name) {
|
|
454
|
+
const db = getClient();
|
|
455
|
+
let site = await db.site.findUnique({ where: { domain } });
|
|
456
|
+
if (!site) {
|
|
457
|
+
site = await db.site.create({
|
|
458
|
+
data: {
|
|
459
|
+
domain,
|
|
460
|
+
name: name ?? domain,
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
return site;
|
|
465
|
+
}
|
|
466
|
+
// List all sites
|
|
467
|
+
export async function listSites() {
|
|
468
|
+
const db = getClient();
|
|
469
|
+
return db.site.findMany({ orderBy: { name: "asc" } });
|
|
470
|
+
}
|
|
471
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
package/dist/track.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TrackPageViewOptions, TrackEventOptions } from "./types.js";
|
|
2
|
+
export declare function trackPageView(options: TrackPageViewOptions): Promise<void>;
|
|
3
|
+
export declare function trackEvent(options: TrackEventOptions): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=track.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAkEf;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB1E"}
|
package/dist/track.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { getClient } from "./client.js";
|
|
2
|
+
import { parseUserAgent } from "./ua.js";
|
|
3
|
+
import { isBot, getVisitorInfo, extractPathname } from "./utils.js";
|
|
4
|
+
export async function trackPageView(options) {
|
|
5
|
+
const { siteId, url, referrer, ip, userAgent, userId,
|
|
6
|
+
// Geo data passed directly (e.g., from Vercel headers)
|
|
7
|
+
country, countryCode, region, city, } = options;
|
|
8
|
+
// Normalize undefined to null
|
|
9
|
+
const ipNorm = ip ?? null;
|
|
10
|
+
const uaNorm = userAgent ?? null;
|
|
11
|
+
// Get visitor info (hashes for privacy)
|
|
12
|
+
const { visitorHash, sessionId } = await getVisitorInfo(ipNorm, uaNorm);
|
|
13
|
+
// Parse user agent
|
|
14
|
+
const ua = parseUserAgent(uaNorm);
|
|
15
|
+
// Detect bots
|
|
16
|
+
const isBotRequest = isBot(uaNorm);
|
|
17
|
+
// Extract pathname from URL
|
|
18
|
+
const pathname = extractPathname(url);
|
|
19
|
+
// Clean referrer (remove query params for privacy)
|
|
20
|
+
let cleanReferrer = referrer ?? null;
|
|
21
|
+
if (cleanReferrer) {
|
|
22
|
+
try {
|
|
23
|
+
const refUrl = new URL(cleanReferrer);
|
|
24
|
+
// Only keep the domain for external referrers
|
|
25
|
+
cleanReferrer = refUrl.origin + refUrl.pathname;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// Keep as-is if not a valid URL
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const db = getClient();
|
|
32
|
+
await db.pageView.create({
|
|
33
|
+
data: {
|
|
34
|
+
siteId,
|
|
35
|
+
url,
|
|
36
|
+
pathname,
|
|
37
|
+
referrer: cleanReferrer,
|
|
38
|
+
visitorHash,
|
|
39
|
+
sessionId,
|
|
40
|
+
country: country ?? null,
|
|
41
|
+
countryCode: countryCode ?? null,
|
|
42
|
+
region: region ?? null,
|
|
43
|
+
city: city ?? null,
|
|
44
|
+
browser: ua.browser,
|
|
45
|
+
browserVer: ua.browserVer,
|
|
46
|
+
os: ua.os,
|
|
47
|
+
osVer: ua.osVer,
|
|
48
|
+
device: ua.device,
|
|
49
|
+
userId,
|
|
50
|
+
isBot: isBotRequest,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function trackEvent(options) {
|
|
55
|
+
const { siteId, name, properties, url, ip, userAgent, userId } = options;
|
|
56
|
+
// Normalize undefined to null
|
|
57
|
+
const ipNorm = ip ?? null;
|
|
58
|
+
const uaNorm = userAgent ?? null;
|
|
59
|
+
// Get visitor info (hashes for privacy)
|
|
60
|
+
const { visitorHash, sessionId } = await getVisitorInfo(ipNorm, uaNorm);
|
|
61
|
+
const db = getClient();
|
|
62
|
+
await db.event.create({
|
|
63
|
+
data: {
|
|
64
|
+
siteId,
|
|
65
|
+
name,
|
|
66
|
+
properties: properties,
|
|
67
|
+
url,
|
|
68
|
+
visitorHash,
|
|
69
|
+
sessionId,
|
|
70
|
+
userId,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track.js","sourceRoot":"","sources":["../src/track.ts"],"names":[],"mappings":"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"}
|