@stacksee/analytics 0.9.7 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/client/browser-analytics.d.ts +9 -1
- package/dist/adapters/server/server-analytics.d.ts +9 -1
- package/dist/client.js +145 -100
- package/dist/core/events/types.d.ts +63 -1
- package/dist/providers/client.js +7 -5
- package/dist/providers/server.d.ts +1 -1
- package/dist/providers/server.js +160 -119
- package/dist/server.js +143 -101
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
1
|
+
var h = Object.defineProperty;
|
|
2
|
+
var f = (a, r, e) => r in a ? h(a, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : a[r] = e;
|
|
3
|
+
var o = (a, r, e) => f(a, typeof r != "symbol" ? r + "" : r, e);
|
|
4
4
|
import { P as w } from "./server-DjEk1fUD.js";
|
|
5
|
-
import { B as
|
|
5
|
+
import { B as x } from "./base.provider-AfFL5W_P.js";
|
|
6
6
|
class v {
|
|
7
7
|
/**
|
|
8
8
|
* Creates a new ServerAnalytics instance for server-side event tracking.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* The server analytics instance is designed for Node.js environments including
|
|
11
11
|
* long-running servers, serverless functions, and edge computing environments.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* @param config Analytics configuration including providers and default context
|
|
14
14
|
* @param config.providers Array of analytics provider instances (e.g., PostHogServerProvider)
|
|
15
15
|
* @param config.defaultContext Optional default context to include with all events
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```typescript
|
|
19
19
|
* import { ServerAnalytics } from '@stacksee/analytics/server';
|
|
20
20
|
* import { PostHogServerProvider } from '@stacksee/analytics/providers/posthog';
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* const analytics = new ServerAnalytics({
|
|
23
23
|
* providers: [
|
|
24
24
|
* new PostHogServerProvider({
|
|
@@ -30,75 +30,117 @@ class v {
|
|
|
30
30
|
* app: { version: '1.0.0', environment: 'production' }
|
|
31
31
|
* }
|
|
32
32
|
* });
|
|
33
|
-
*
|
|
33
|
+
*
|
|
34
34
|
* analytics.initialize();
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
constructor(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.config =
|
|
37
|
+
constructor(r) {
|
|
38
|
+
o(this, "providerConfigs", []);
|
|
39
|
+
o(this, "config");
|
|
40
|
+
o(this, "initialized", !1);
|
|
41
|
+
this.config = r, this.providerConfigs = this.normalizeProviders(r.providers);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalizes provider configurations into a consistent internal format
|
|
45
|
+
*/
|
|
46
|
+
normalizeProviders(r) {
|
|
47
|
+
const e = [
|
|
48
|
+
"initialize",
|
|
49
|
+
"identify",
|
|
50
|
+
"track",
|
|
51
|
+
"pageView",
|
|
52
|
+
"pageLeave",
|
|
53
|
+
"reset"
|
|
54
|
+
];
|
|
55
|
+
return r.map((i) => {
|
|
56
|
+
if ("initialize" in i && "track" in i)
|
|
57
|
+
return {
|
|
58
|
+
provider: i,
|
|
59
|
+
enabledMethods: new Set(e)
|
|
60
|
+
};
|
|
61
|
+
const t = i;
|
|
62
|
+
t.methods && t.exclude && console.warn(
|
|
63
|
+
`[Analytics] Provider ${t.provider.name} has both 'methods' and 'exclude' specified. Using 'methods' and ignoring 'exclude'.`
|
|
64
|
+
);
|
|
65
|
+
let n;
|
|
66
|
+
return t.methods ? n = new Set(t.methods) : t.exclude ? n = new Set(
|
|
67
|
+
e.filter(
|
|
68
|
+
(l) => {
|
|
69
|
+
var d;
|
|
70
|
+
return !((d = t.exclude) != null && d.includes(l));
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
) : n = new Set(e), {
|
|
74
|
+
provider: t.provider,
|
|
75
|
+
enabledMethods: n
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Checks if a method should be called on a provider based on routing configuration
|
|
81
|
+
*/
|
|
82
|
+
shouldCallMethod(r, e) {
|
|
83
|
+
return r.enabledMethods.has(e);
|
|
42
84
|
}
|
|
43
85
|
/**
|
|
44
86
|
* Initializes all analytics providers.
|
|
45
|
-
*
|
|
87
|
+
*
|
|
46
88
|
* This method must be called before tracking events. It initializes all configured
|
|
47
89
|
* providers synchronously. Unlike the browser version, server initialization is
|
|
48
90
|
* typically synchronous as providers don't need to load external scripts.
|
|
49
|
-
*
|
|
91
|
+
*
|
|
50
92
|
* The method is safe to call multiple times and will not re-initialize if already done.
|
|
51
|
-
*
|
|
93
|
+
*
|
|
52
94
|
* @example
|
|
53
95
|
* ```typescript
|
|
54
96
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
55
|
-
*
|
|
97
|
+
*
|
|
56
98
|
* // Initialize before tracking events
|
|
57
99
|
* analytics.initialize();
|
|
58
|
-
*
|
|
100
|
+
*
|
|
59
101
|
* // Now ready to track events
|
|
60
102
|
* await analytics.track('api_request', { endpoint: '/users' });
|
|
61
103
|
* ```
|
|
62
|
-
*
|
|
104
|
+
*
|
|
63
105
|
* @example
|
|
64
106
|
* ```typescript
|
|
65
107
|
* // In a serverless function
|
|
66
108
|
* export async function handler(req, res) {
|
|
67
109
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
68
110
|
* analytics.initialize(); // Quick synchronous initialization
|
|
69
|
-
*
|
|
111
|
+
*
|
|
70
112
|
* await analytics.track('function_invoked', {
|
|
71
113
|
* path: req.path,
|
|
72
114
|
* method: req.method
|
|
73
115
|
* });
|
|
74
|
-
*
|
|
116
|
+
*
|
|
75
117
|
* await analytics.shutdown(); // Important for serverless
|
|
76
118
|
* }
|
|
77
119
|
* ```
|
|
78
120
|
*/
|
|
79
121
|
initialize() {
|
|
80
122
|
if (!this.initialized) {
|
|
81
|
-
for (const
|
|
82
|
-
|
|
123
|
+
for (const r of this.providerConfigs)
|
|
124
|
+
r.provider.initialize();
|
|
83
125
|
this.initialized = !0;
|
|
84
126
|
}
|
|
85
127
|
}
|
|
86
128
|
/**
|
|
87
129
|
* Identifies a user with optional traits.
|
|
88
|
-
*
|
|
130
|
+
*
|
|
89
131
|
* Associates subsequent events with the specified user ID and optionally
|
|
90
132
|
* sets user properties. This method is typically called when processing
|
|
91
133
|
* authentication or when you have user context available on the server.
|
|
92
|
-
*
|
|
134
|
+
*
|
|
93
135
|
* @param userId Unique identifier for the user (e.g., database ID, email)
|
|
94
136
|
* @param traits Optional user properties and characteristics
|
|
95
|
-
*
|
|
137
|
+
*
|
|
96
138
|
* @example
|
|
97
139
|
* ```typescript
|
|
98
140
|
* // Basic user identification
|
|
99
141
|
* analytics.identify('user-123');
|
|
100
142
|
* ```
|
|
101
|
-
*
|
|
143
|
+
*
|
|
102
144
|
* @example
|
|
103
145
|
* ```typescript
|
|
104
146
|
* // Identify with user traits from database
|
|
@@ -111,27 +153,27 @@ class v {
|
|
|
111
153
|
* lastSeenAt: new Date().toISOString()
|
|
112
154
|
* });
|
|
113
155
|
* ```
|
|
114
|
-
*
|
|
156
|
+
*
|
|
115
157
|
* @example
|
|
116
158
|
* ```typescript
|
|
117
159
|
* // In an API authentication middleware
|
|
118
160
|
* async function authMiddleware(req, res, next) {
|
|
119
161
|
* const user = await getUserFromToken(req.headers.authorization);
|
|
120
|
-
*
|
|
162
|
+
*
|
|
121
163
|
* analytics.identify(user.id, {
|
|
122
164
|
* email: user.email,
|
|
123
165
|
* role: user.role,
|
|
124
166
|
* organization: user.organization
|
|
125
167
|
* });
|
|
126
|
-
*
|
|
168
|
+
*
|
|
127
169
|
* req.user = user;
|
|
128
170
|
* next();
|
|
129
171
|
* }
|
|
130
172
|
* ```
|
|
131
173
|
*/
|
|
132
|
-
identify(
|
|
133
|
-
for (const
|
|
134
|
-
|
|
174
|
+
identify(r, e) {
|
|
175
|
+
for (const i of this.providerConfigs)
|
|
176
|
+
this.shouldCallMethod(i, "identify") && i.provider.identify(r, e);
|
|
135
177
|
}
|
|
136
178
|
/**
|
|
137
179
|
* Tracks a custom event with properties and optional context.
|
|
@@ -254,30 +296,30 @@ class v {
|
|
|
254
296
|
* }
|
|
255
297
|
* ```
|
|
256
298
|
*/
|
|
257
|
-
async track(
|
|
258
|
-
var
|
|
299
|
+
async track(r, e, i) {
|
|
300
|
+
var d;
|
|
259
301
|
if (!this.initialized) {
|
|
260
302
|
console.warn("[Analytics] Not initialized. Call initialize() first.");
|
|
261
303
|
return;
|
|
262
304
|
}
|
|
263
|
-
const
|
|
264
|
-
action:
|
|
265
|
-
category: this.getCategoryFromEventName(
|
|
266
|
-
properties:
|
|
305
|
+
const t = {
|
|
306
|
+
action: r,
|
|
307
|
+
category: this.getCategoryFromEventName(r),
|
|
308
|
+
properties: e,
|
|
267
309
|
timestamp: Date.now(),
|
|
268
|
-
userId:
|
|
269
|
-
sessionId:
|
|
270
|
-
},
|
|
310
|
+
userId: i == null ? void 0 : i.userId,
|
|
311
|
+
sessionId: i == null ? void 0 : i.sessionId
|
|
312
|
+
}, n = {
|
|
271
313
|
...this.config.defaultContext,
|
|
272
|
-
...
|
|
273
|
-
user: (
|
|
274
|
-
}, l = this.
|
|
314
|
+
...i == null ? void 0 : i.context,
|
|
315
|
+
user: (i == null ? void 0 : i.user) || ((d = i == null ? void 0 : i.context) == null ? void 0 : d.user)
|
|
316
|
+
}, l = this.providerConfigs.filter((s) => this.shouldCallMethod(s, "track")).map(async (s) => {
|
|
275
317
|
try {
|
|
276
|
-
await
|
|
277
|
-
} catch (
|
|
318
|
+
await s.provider.track(t, n);
|
|
319
|
+
} catch (c) {
|
|
278
320
|
console.error(
|
|
279
|
-
`[Analytics] Provider ${
|
|
280
|
-
|
|
321
|
+
`[Analytics] Provider ${s.provider.name} failed to track event:`,
|
|
322
|
+
c
|
|
281
323
|
);
|
|
282
324
|
}
|
|
283
325
|
});
|
|
@@ -285,21 +327,21 @@ class v {
|
|
|
285
327
|
}
|
|
286
328
|
/**
|
|
287
329
|
* Tracks a page view event from the server side.
|
|
288
|
-
*
|
|
330
|
+
*
|
|
289
331
|
* Server-side page view tracking is useful for server-rendered applications,
|
|
290
332
|
* SSR frameworks, or when you want to ensure page views are tracked even
|
|
291
333
|
* if client-side JavaScript fails.
|
|
292
|
-
*
|
|
334
|
+
*
|
|
293
335
|
* @param properties Optional properties to include with the page view
|
|
294
336
|
* @param options Optional configuration including context
|
|
295
337
|
* @param options.context Additional context for this page view
|
|
296
|
-
*
|
|
338
|
+
*
|
|
297
339
|
* @example
|
|
298
340
|
* ```typescript
|
|
299
341
|
* // Basic server-side page view
|
|
300
342
|
* analytics.pageView();
|
|
301
343
|
* ```
|
|
302
|
-
*
|
|
344
|
+
*
|
|
303
345
|
* @example
|
|
304
346
|
* ```typescript
|
|
305
347
|
* // Page view with server context
|
|
@@ -323,7 +365,7 @@ class v {
|
|
|
323
365
|
* }
|
|
324
366
|
* });
|
|
325
367
|
* ```
|
|
326
|
-
*
|
|
368
|
+
*
|
|
327
369
|
* @example
|
|
328
370
|
* ```typescript
|
|
329
371
|
* // In a Next.js API route or middleware
|
|
@@ -343,35 +385,35 @@ class v {
|
|
|
343
385
|
* }
|
|
344
386
|
* ```
|
|
345
387
|
*/
|
|
346
|
-
pageView(
|
|
388
|
+
pageView(r, e) {
|
|
347
389
|
if (!this.initialized) return;
|
|
348
|
-
const
|
|
390
|
+
const i = {
|
|
349
391
|
...this.config.defaultContext,
|
|
350
|
-
...
|
|
392
|
+
...e == null ? void 0 : e.context
|
|
351
393
|
};
|
|
352
|
-
for (const
|
|
353
|
-
|
|
394
|
+
for (const t of this.providerConfigs)
|
|
395
|
+
this.shouldCallMethod(t, "pageView") && t.provider.pageView(r, i);
|
|
354
396
|
}
|
|
355
397
|
/**
|
|
356
398
|
* Tracks when a user leaves a page from the server side.
|
|
357
|
-
*
|
|
399
|
+
*
|
|
358
400
|
* Server-side page leave tracking is less common than client-side but can be
|
|
359
401
|
* useful in certain scenarios like tracking session timeouts, or when combined
|
|
360
402
|
* with server-side session management.
|
|
361
|
-
*
|
|
403
|
+
*
|
|
362
404
|
* Note: Not all analytics providers support page leave events. The method
|
|
363
405
|
* will only call providers that implement the pageLeave method.
|
|
364
|
-
*
|
|
406
|
+
*
|
|
365
407
|
* @param properties Optional properties to include with the page leave event
|
|
366
408
|
* @param options Optional configuration including context
|
|
367
409
|
* @param options.context Additional context for this page leave
|
|
368
|
-
*
|
|
410
|
+
*
|
|
369
411
|
* @example
|
|
370
412
|
* ```typescript
|
|
371
413
|
* // Basic page leave tracking
|
|
372
414
|
* analytics.pageLeave();
|
|
373
415
|
* ```
|
|
374
|
-
*
|
|
416
|
+
*
|
|
375
417
|
* @example
|
|
376
418
|
* ```typescript
|
|
377
419
|
* // Page leave with session context
|
|
@@ -392,63 +434,63 @@ class v {
|
|
|
392
434
|
* }
|
|
393
435
|
* });
|
|
394
436
|
* ```
|
|
395
|
-
*
|
|
437
|
+
*
|
|
396
438
|
* @example
|
|
397
439
|
* ```typescript
|
|
398
440
|
* // In a session cleanup job
|
|
399
441
|
* async function cleanupExpiredSessions() {
|
|
400
442
|
* const expiredSessions = await getExpiredSessions();
|
|
401
|
-
*
|
|
443
|
+
*
|
|
402
444
|
* for (const session of expiredSessions) {
|
|
403
445
|
* analytics.pageLeave({
|
|
404
446
|
* sessionId: session.id,
|
|
405
447
|
* duration: session.duration,
|
|
406
448
|
* reason: 'expired'
|
|
407
449
|
* });
|
|
408
|
-
*
|
|
450
|
+
*
|
|
409
451
|
* await removeSession(session.id);
|
|
410
452
|
* }
|
|
411
453
|
* }
|
|
412
454
|
* ```
|
|
413
455
|
*/
|
|
414
|
-
pageLeave(
|
|
456
|
+
pageLeave(r, e) {
|
|
415
457
|
if (!this.initialized) return;
|
|
416
|
-
const
|
|
458
|
+
const i = {
|
|
417
459
|
...this.config.defaultContext,
|
|
418
|
-
...
|
|
460
|
+
...e == null ? void 0 : e.context
|
|
419
461
|
};
|
|
420
|
-
for (const
|
|
421
|
-
|
|
462
|
+
for (const t of this.providerConfigs)
|
|
463
|
+
this.shouldCallMethod(t, "pageLeave") && t.provider.pageLeave && t.provider.pageLeave(r, i);
|
|
422
464
|
}
|
|
423
465
|
/**
|
|
424
466
|
* Shuts down all analytics providers and flushes pending events.
|
|
425
|
-
*
|
|
467
|
+
*
|
|
426
468
|
* This method is crucial for server environments, especially serverless functions,
|
|
427
469
|
* as it ensures all events are sent before the process terminates. Some providers
|
|
428
470
|
* batch events and need an explicit flush to send them.
|
|
429
|
-
*
|
|
471
|
+
*
|
|
430
472
|
* Always call this method before your server shuts down or before a serverless
|
|
431
473
|
* function completes execution.
|
|
432
|
-
*
|
|
474
|
+
*
|
|
433
475
|
* @returns Promise that resolves when all providers have been shut down
|
|
434
|
-
*
|
|
476
|
+
*
|
|
435
477
|
* @example
|
|
436
478
|
* ```typescript
|
|
437
479
|
* // Basic shutdown
|
|
438
480
|
* await analytics.shutdown();
|
|
439
481
|
* ```
|
|
440
|
-
*
|
|
482
|
+
*
|
|
441
483
|
* @example
|
|
442
484
|
* ```typescript
|
|
443
485
|
* // In a serverless function
|
|
444
486
|
* export async function handler(event, context) {
|
|
445
487
|
* const analytics = new ServerAnalytics({ providers: [] });
|
|
446
488
|
* analytics.initialize();
|
|
447
|
-
*
|
|
489
|
+
*
|
|
448
490
|
* try {
|
|
449
491
|
* // Process the event
|
|
450
492
|
* await processEvent(event);
|
|
451
|
-
*
|
|
493
|
+
*
|
|
452
494
|
* // Track completion
|
|
453
495
|
* await analytics.track('function_completed', {
|
|
454
496
|
* duration: Date.now() - startTime,
|
|
@@ -463,20 +505,20 @@ class v {
|
|
|
463
505
|
* // Always shutdown to flush events
|
|
464
506
|
* await analytics.shutdown();
|
|
465
507
|
* }
|
|
466
|
-
*
|
|
508
|
+
*
|
|
467
509
|
* return { statusCode: 200 };
|
|
468
510
|
* }
|
|
469
511
|
* ```
|
|
470
|
-
*
|
|
512
|
+
*
|
|
471
513
|
* @example
|
|
472
514
|
* ```typescript
|
|
473
515
|
* // In an Express.js server
|
|
474
516
|
* const server = app.listen(3000);
|
|
475
|
-
*
|
|
517
|
+
*
|
|
476
518
|
* // Graceful shutdown
|
|
477
519
|
* process.on('SIGTERM', async () => {
|
|
478
520
|
* console.log('Shutting down gracefully...');
|
|
479
|
-
*
|
|
521
|
+
*
|
|
480
522
|
* server.close(async () => {
|
|
481
523
|
* // Flush analytics events before exit
|
|
482
524
|
* await analytics.shutdown();
|
|
@@ -484,45 +526,45 @@ class v {
|
|
|
484
526
|
* });
|
|
485
527
|
* });
|
|
486
528
|
* ```
|
|
487
|
-
*
|
|
529
|
+
*
|
|
488
530
|
* @example
|
|
489
531
|
* ```typescript
|
|
490
532
|
* // With Vercel's waitUntil
|
|
491
533
|
* import { waitUntil } from '@vercel/functions';
|
|
492
|
-
*
|
|
534
|
+
*
|
|
493
535
|
* export default async function handler(req, res) {
|
|
494
536
|
* // Process request
|
|
495
537
|
* const result = await processRequest(req);
|
|
496
|
-
*
|
|
538
|
+
*
|
|
497
539
|
* // Track in background without blocking response
|
|
498
540
|
* waitUntil(
|
|
499
541
|
* analytics.track('api_request', { endpoint: req.url })
|
|
500
542
|
* .then(() => analytics.shutdown())
|
|
501
543
|
* );
|
|
502
|
-
*
|
|
544
|
+
*
|
|
503
545
|
* return res.json(result);
|
|
504
546
|
* }
|
|
505
547
|
* ```
|
|
506
548
|
*/
|
|
507
549
|
async shutdown() {
|
|
508
|
-
const
|
|
509
|
-
await Promise.all(
|
|
550
|
+
const r = this.providerConfigs.map((e) => "shutdown" in e.provider && typeof e.provider.shutdown == "function" ? e.provider.shutdown() : Promise.resolve());
|
|
551
|
+
await Promise.all(r);
|
|
510
552
|
}
|
|
511
|
-
getCategoryFromEventName(
|
|
512
|
-
const
|
|
513
|
-
return
|
|
553
|
+
getCategoryFromEventName(r) {
|
|
554
|
+
const e = r.split("_");
|
|
555
|
+
return e.length > 1 && e[0] ? e[0] : "engagement";
|
|
514
556
|
}
|
|
515
557
|
}
|
|
516
|
-
function g(
|
|
517
|
-
const
|
|
518
|
-
providers:
|
|
519
|
-
debug:
|
|
520
|
-
enabled:
|
|
521
|
-
},
|
|
522
|
-
return
|
|
558
|
+
function g(a) {
|
|
559
|
+
const r = {
|
|
560
|
+
providers: a.providers || [],
|
|
561
|
+
debug: a.debug,
|
|
562
|
+
enabled: a.enabled
|
|
563
|
+
}, e = new v(r);
|
|
564
|
+
return e.initialize(), e;
|
|
523
565
|
}
|
|
524
566
|
export {
|
|
525
|
-
|
|
567
|
+
x as BaseAnalyticsProvider,
|
|
526
568
|
w as PostHogServerProvider,
|
|
527
569
|
v as ServerAnalytics,
|
|
528
570
|
g as createServerAnalytics
|