@stacksee/analytics 0.13.1 → 0.13.2
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/server/server-analytics.d.ts +2 -2
- package/dist/providers/bento/server.d.ts +2 -2
- package/dist/providers/emitkit/server.d.ts +2 -2
- package/dist/providers/pirsch/server.d.ts +2 -2
- package/dist/providers/server.js +128 -124
- package/dist/server.js +41 -38
- package/package.json +5 -2
|
@@ -130,7 +130,7 @@ export declare class ServerAnalytics<TEventMap extends Record<string, Record<str
|
|
|
130
130
|
* }
|
|
131
131
|
* ```
|
|
132
132
|
*/
|
|
133
|
-
identify(userId: string, traits?: Record<string, unknown>): void
|
|
133
|
+
identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
|
|
134
134
|
/**
|
|
135
135
|
* Tracks a custom event with properties and optional context.
|
|
136
136
|
*
|
|
@@ -320,7 +320,7 @@ export declare class ServerAnalytics<TEventMap extends Record<string, Record<str
|
|
|
320
320
|
*/
|
|
321
321
|
pageView(properties?: Record<string, unknown>, options?: {
|
|
322
322
|
context?: EventContext<TUserTraits>;
|
|
323
|
-
}): void
|
|
323
|
+
}): Promise<void>;
|
|
324
324
|
/**
|
|
325
325
|
* Tracks when a user leaves a page from the server side.
|
|
326
326
|
*
|
|
@@ -50,9 +50,9 @@ export declare class BentoServerProvider extends BaseAnalyticsProvider {
|
|
|
50
50
|
private currentUserEmail?;
|
|
51
51
|
constructor(config: BentoServerConfig);
|
|
52
52
|
initialize(): Promise<void>;
|
|
53
|
-
identify(userId: string, traits?: Record<string, unknown>): void
|
|
53
|
+
identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
|
|
54
54
|
track(event: BaseEvent, context?: EventContext): Promise<void>;
|
|
55
|
-
pageView(properties?: Record<string, unknown>, context?: EventContext): void
|
|
55
|
+
pageView(properties?: Record<string, unknown>, context?: EventContext): Promise<void>;
|
|
56
56
|
reset(): Promise<void>;
|
|
57
57
|
shutdown(): Promise<void>;
|
|
58
58
|
}
|
|
@@ -66,9 +66,9 @@ export declare class EmitKitServerProvider extends BaseAnalyticsProvider {
|
|
|
66
66
|
private currentUserEmail?;
|
|
67
67
|
constructor(config: EmitKitServerConfig);
|
|
68
68
|
initialize(): Promise<void>;
|
|
69
|
-
identify(userId: string, traits?: Record<string, unknown>): void
|
|
69
|
+
identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
|
|
70
70
|
track(event: BaseEvent, context?: EventContext): Promise<void>;
|
|
71
|
-
pageView(properties?: Record<string, unknown>, context?: EventContext): void
|
|
71
|
+
pageView(properties?: Record<string, unknown>, context?: EventContext): Promise<void>;
|
|
72
72
|
reset(): Promise<void>;
|
|
73
73
|
shutdown(): Promise<void>;
|
|
74
74
|
/**
|
|
@@ -74,9 +74,9 @@ export declare class PirschServerProvider extends BaseAnalyticsProvider {
|
|
|
74
74
|
* Build a Pirsch hit from context
|
|
75
75
|
*/
|
|
76
76
|
private buildHit;
|
|
77
|
-
identify(userId: string, traits?: Record<string, unknown>): void
|
|
77
|
+
identify(userId: string, traits?: Record<string, unknown>): Promise<void>;
|
|
78
78
|
track(event: BaseEvent, context?: EventContext): Promise<void>;
|
|
79
|
-
pageView(properties?: Record<string, unknown>, context?: EventContext): void
|
|
79
|
+
pageView(properties?: Record<string, unknown>, context?: EventContext): Promise<void>;
|
|
80
80
|
reset(): Promise<void>;
|
|
81
81
|
shutdown(): Promise<void>;
|
|
82
82
|
}
|
package/dist/providers/server.js
CHANGED
|
@@ -23,8 +23,8 @@ class O extends y {
|
|
|
23
23
|
if (!((e = this.config.authentication) != null && e.secretKey) || typeof this.config.authentication.secretKey != "string")
|
|
24
24
|
throw new Error("Bento requires authentication.secretKey");
|
|
25
25
|
try {
|
|
26
|
-
const { Analytics: r } = await import("../bento-node-sdk.esm-CT4oS3Kp.js"), { debug: s, enabled:
|
|
27
|
-
this.client = new r(
|
|
26
|
+
const { Analytics: r } = await import("../bento-node-sdk.esm-CT4oS3Kp.js"), { debug: s, enabled: n, ...a } = this.config;
|
|
27
|
+
this.client = new r(a), this.initialized = !0, this.log("Initialized successfully", {
|
|
28
28
|
siteUuid: this.config.siteUuid
|
|
29
29
|
});
|
|
30
30
|
} catch (r) {
|
|
@@ -35,7 +35,7 @@ class O extends y {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
-
identify(i, e) {
|
|
38
|
+
async identify(i, e) {
|
|
39
39
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
40
40
|
const r = (e == null ? void 0 : e.email) || i;
|
|
41
41
|
if (!r || !r.includes("@")) {
|
|
@@ -47,17 +47,17 @@ class O extends y {
|
|
|
47
47
|
}
|
|
48
48
|
this.currentUserEmail = r;
|
|
49
49
|
const s = e ? { ...e } : {};
|
|
50
|
-
s.email = void 0
|
|
51
|
-
|
|
52
|
-
fields: s
|
|
53
|
-
}
|
|
54
|
-
console.error("[Bento-Server] Failed to identify user:",
|
|
55
|
-
}
|
|
50
|
+
s.email = void 0;
|
|
51
|
+
try {
|
|
52
|
+
await this.client.V1.addSubscriber({ email: r, fields: s }), this.log("Identified user", { userId: i, email: r, traits: e });
|
|
53
|
+
} catch (n) {
|
|
54
|
+
console.error("[Bento-Server] Failed to identify user:", n);
|
|
55
|
+
}
|
|
56
56
|
}
|
|
57
57
|
async track(i, e) {
|
|
58
|
-
var
|
|
58
|
+
var a, h, l, o;
|
|
59
59
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
60
|
-
const r = ((
|
|
60
|
+
const r = ((a = e == null ? void 0 : e.user) == null ? void 0 : a.email) || this.currentUserEmail || ((h = e == null ? void 0 : e.user) == null ? void 0 : h.userId) || i.userId;
|
|
61
61
|
if (!r || !r.includes("@")) {
|
|
62
62
|
console.warn(
|
|
63
63
|
"[Bento-Server] Skipping event - Bento requires an email address. Anonymous events are not currently supported by the Bento Node SDK. For now, use the Bento client provider for anonymous tracking. If you're using a proxy, use the hybrid pattern as described in the docs. For identified users, call identify() with a valid email before tracking events."
|
|
@@ -84,22 +84,22 @@ class O extends y {
|
|
|
84
84
|
...(e == null ? void 0 : e.utm) && { utm: e.utm },
|
|
85
85
|
site: this.config.siteUuid,
|
|
86
86
|
...((l = e == null ? void 0 : e.user) == null ? void 0 : l.userId) && { visitor: e.user.userId }
|
|
87
|
-
},
|
|
87
|
+
}, n = ((o = e == null ? void 0 : e.user) == null ? void 0 : o.traits) || {};
|
|
88
88
|
try {
|
|
89
89
|
await this.client.V1.track({
|
|
90
90
|
email: r,
|
|
91
91
|
type: `$${i.action}`,
|
|
92
92
|
details: s,
|
|
93
|
-
fields:
|
|
93
|
+
fields: n
|
|
94
94
|
}), this.log("Tracked event", { event: i, context: e });
|
|
95
|
-
} catch (
|
|
96
|
-
console.error("[Bento-Server] Failed to track event:",
|
|
95
|
+
} catch (t) {
|
|
96
|
+
console.error("[Bento-Server] Failed to track event:", t);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
pageView(i, e) {
|
|
100
|
-
var
|
|
99
|
+
async pageView(i, e) {
|
|
100
|
+
var a, h, l;
|
|
101
101
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
102
|
-
const r = ((
|
|
102
|
+
const r = ((a = e == null ? void 0 : e.user) == null ? void 0 : a.email) || this.currentUserEmail;
|
|
103
103
|
if (!r || !r.includes("@")) {
|
|
104
104
|
console.warn(
|
|
105
105
|
"[Bento-Server] Skipping pageView - Bento requires an email address. Anonymous events are not currently supported by the Bento Node SDK. For now, use the Bento client provider for anonymous tracking. If you're using a proxy, use the hybrid pattern as described in the docs. For identified users, call identify() with a valid email before tracking events."
|
|
@@ -122,15 +122,12 @@ class O extends y {
|
|
|
122
122
|
},
|
|
123
123
|
site: this.config.siteUuid,
|
|
124
124
|
...((h = e == null ? void 0 : e.user) == null ? void 0 : h.userId) && { visitor: e.user.userId }
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
email: r,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}).catch((n) => {
|
|
132
|
-
console.error("[Bento-Server] Failed to track page view:", n);
|
|
133
|
-
}), this.log("Tracked page view", { properties: i, context: e });
|
|
125
|
+
}, n = ((l = e == null ? void 0 : e.user) == null ? void 0 : l.traits) || {};
|
|
126
|
+
try {
|
|
127
|
+
await this.client.V1.track({ email: r, type: "$view", details: s, fields: n }), this.log("Tracked page view", { properties: i, context: e });
|
|
128
|
+
} catch (o) {
|
|
129
|
+
console.error("[Bento-Server] Failed to track page view:", o);
|
|
130
|
+
}
|
|
134
131
|
}
|
|
135
132
|
async reset() {
|
|
136
133
|
!this.isEnabled() || !this.initialized || !this.client || (this.currentUserEmail = void 0, this.log("Reset user session"));
|
|
@@ -171,14 +168,14 @@ class j extends y {
|
|
|
171
168
|
* Fetch with timeout using AbortController
|
|
172
169
|
*/
|
|
173
170
|
async fetchWithTimeout(i, e, r) {
|
|
174
|
-
const s = new AbortController(),
|
|
171
|
+
const s = new AbortController(), n = r ?? this.config.timeout ?? K, a = setTimeout(() => s.abort(), n);
|
|
175
172
|
try {
|
|
176
173
|
return await fetch(i, {
|
|
177
174
|
...e,
|
|
178
175
|
signal: s.signal
|
|
179
176
|
});
|
|
180
177
|
} finally {
|
|
181
|
-
clearTimeout(
|
|
178
|
+
clearTimeout(a);
|
|
182
179
|
}
|
|
183
180
|
}
|
|
184
181
|
/**
|
|
@@ -217,7 +214,7 @@ class j extends y {
|
|
|
217
214
|
async request(i, e, r = !0) {
|
|
218
215
|
const s = await this.ensureToken();
|
|
219
216
|
try {
|
|
220
|
-
const
|
|
217
|
+
const n = await this.fetchWithTimeout(
|
|
221
218
|
`${T}${i}`,
|
|
222
219
|
{
|
|
223
220
|
method: "POST",
|
|
@@ -228,16 +225,16 @@ class j extends y {
|
|
|
228
225
|
body: JSON.stringify(e)
|
|
229
226
|
}
|
|
230
227
|
);
|
|
231
|
-
if (
|
|
228
|
+
if (n.status === 401 && r && !this.isAccessKey)
|
|
232
229
|
return this.accessToken = "", this.tokenExpiresAt = null, this.request(i, e, !1);
|
|
233
|
-
if (!
|
|
234
|
-
const
|
|
235
|
-
throw new Error(`Pirsch API error: ${
|
|
230
|
+
if (!n.ok) {
|
|
231
|
+
const a = await n.text();
|
|
232
|
+
throw new Error(`Pirsch API error: ${n.status} ${a}`);
|
|
236
233
|
}
|
|
237
|
-
} catch (
|
|
238
|
-
throw
|
|
234
|
+
} catch (n) {
|
|
235
|
+
throw n instanceof Error && n.name === "AbortError" ? new Error(
|
|
239
236
|
`Pirsch request timeout after ${this.config.timeout ?? K}ms`
|
|
240
|
-
) :
|
|
237
|
+
) : n;
|
|
241
238
|
}
|
|
242
239
|
}
|
|
243
240
|
/**
|
|
@@ -265,10 +262,10 @@ class j extends y {
|
|
|
265
262
|
* Build a Pirsch hit from context
|
|
266
263
|
*/
|
|
267
264
|
buildHit(i) {
|
|
268
|
-
var
|
|
269
|
-
const e = i, r = ((
|
|
265
|
+
var a, h, l, o, t, p, g, f, m, v, w, b, k, E, _, S, I, A, z, P;
|
|
266
|
+
const e = i, r = ((a = e == null ? void 0 : e.device) == null ? void 0 : a.ip) || ((h = e == null ? void 0 : e.server) == null ? void 0 : h.ip), s = ((l = e == null ? void 0 : e.server) == null ? void 0 : l.userAgent) || ((o = e == null ? void 0 : e.device) == null ? void 0 : o.userAgent);
|
|
270
267
|
return !r || !s ? null : {
|
|
271
|
-
url: ((
|
|
268
|
+
url: ((t = i == null ? void 0 : i.page) == null ? void 0 : t.url) || ((p = i == null ? void 0 : i.page) != null && p.protocol && ((g = i == null ? void 0 : i.page) != null && g.host) && ((f = i == null ? void 0 : i.page) != null && f.path) ? `${i.page.protocol}://${i.page.host}${i.page.path}` : (m = i == null ? void 0 : i.page) != null && m.path ? `https://${this.config.hostname}${i.page.path}` : `https://${this.config.hostname}`),
|
|
272
269
|
ip: r,
|
|
273
270
|
user_agent: s,
|
|
274
271
|
...((v = i == null ? void 0 : i.page) == null ? void 0 : v.title) && { title: i.page.title },
|
|
@@ -292,7 +289,7 @@ class j extends y {
|
|
|
292
289
|
...this.config.disableBotFilter && { disable_bot_filter: !0 }
|
|
293
290
|
};
|
|
294
291
|
}
|
|
295
|
-
identify(i, e) {
|
|
292
|
+
async identify(i, e) {
|
|
296
293
|
if (!this.isEnabled() || !this.initialized) return;
|
|
297
294
|
const r = {
|
|
298
295
|
url: `https://${this.config.hostname}/identify`,
|
|
@@ -302,7 +299,7 @@ class j extends y {
|
|
|
302
299
|
}, s = this.toStringRecord({
|
|
303
300
|
userId: i,
|
|
304
301
|
...e
|
|
305
|
-
}),
|
|
302
|
+
}), n = {
|
|
306
303
|
...r,
|
|
307
304
|
event_name: "user_identified",
|
|
308
305
|
event_duration: 0,
|
|
@@ -310,12 +307,14 @@ class j extends y {
|
|
|
310
307
|
non_interactive: !0
|
|
311
308
|
// Synthetic event shouldn't affect bounce rate
|
|
312
309
|
};
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
310
|
+
try {
|
|
311
|
+
await this.request("/api/v1/event", n), this.log("Identified user via event", { userId: i, traits: e });
|
|
312
|
+
} catch (a) {
|
|
313
|
+
console.error("[Pirsch-Server] Failed to track identify event:", a);
|
|
314
|
+
}
|
|
316
315
|
}
|
|
317
316
|
async track(i, e) {
|
|
318
|
-
var h, l,
|
|
317
|
+
var h, l, o, t;
|
|
319
318
|
if (!this.isEnabled() || !this.initialized) return;
|
|
320
319
|
const r = this.buildHit(e);
|
|
321
320
|
if (!r) {
|
|
@@ -332,21 +331,21 @@ class j extends y {
|
|
|
332
331
|
...i.sessionId && { sessionId: i.sessionId },
|
|
333
332
|
...((h = e == null ? void 0 : e.user) == null ? void 0 : h.email) && { user_email: e.user.email },
|
|
334
333
|
...((l = e == null ? void 0 : e.device) == null ? void 0 : l.timezone) && { timezone: e.device.timezone },
|
|
335
|
-
...((
|
|
336
|
-
}),
|
|
334
|
+
...((o = e == null ? void 0 : e.device) == null ? void 0 : o.browser) && { browser: e.device.browser }
|
|
335
|
+
}), n = ((t = i.properties) == null ? void 0 : t.non_interactive) === !0, a = {
|
|
337
336
|
...r,
|
|
338
337
|
event_name: i.action,
|
|
339
338
|
event_duration: 0,
|
|
340
339
|
event_meta: s,
|
|
341
|
-
...
|
|
340
|
+
...n && { non_interactive: !0 }
|
|
342
341
|
};
|
|
343
342
|
try {
|
|
344
|
-
await this.request("/api/v1/event",
|
|
343
|
+
await this.request("/api/v1/event", a), this.log("Tracked event", { event: i.action });
|
|
345
344
|
} catch (p) {
|
|
346
345
|
console.error("[Pirsch-Server] Failed to track event:", p);
|
|
347
346
|
}
|
|
348
347
|
}
|
|
349
|
-
pageView(i, e) {
|
|
348
|
+
async pageView(i, e) {
|
|
350
349
|
var s;
|
|
351
350
|
if (!this.isEnabled() || !this.initialized) return;
|
|
352
351
|
const r = this.buildHit(e);
|
|
@@ -354,9 +353,12 @@ class j extends y {
|
|
|
354
353
|
this.log("Skipping pageView - missing required IP or user-agent");
|
|
355
354
|
return;
|
|
356
355
|
}
|
|
357
|
-
i && Object.keys(i).length > 0 && (r.tags = this.filterScalars(i))
|
|
358
|
-
|
|
359
|
-
|
|
356
|
+
i && Object.keys(i).length > 0 && (r.tags = this.filterScalars(i));
|
|
357
|
+
try {
|
|
358
|
+
await this.request("/api/v1/hit", r), this.log("Tracked page view", { path: (s = e == null ? void 0 : e.page) == null ? void 0 : s.path });
|
|
359
|
+
} catch (n) {
|
|
360
|
+
console.error("[Pirsch-Server] Failed to track page view:", n);
|
|
361
|
+
}
|
|
360
362
|
}
|
|
361
363
|
async reset() {
|
|
362
364
|
if (!this.isEnabled() || !this.initialized) return;
|
|
@@ -412,37 +414,39 @@ class N extends y {
|
|
|
412
414
|
}
|
|
413
415
|
}
|
|
414
416
|
}
|
|
415
|
-
identify(i, e) {
|
|
417
|
+
async identify(i, e) {
|
|
418
|
+
var n, a, h, l, o;
|
|
416
419
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
417
420
|
this.currentUserId = i;
|
|
418
421
|
const r = (e == null ? void 0 : e.email) || i;
|
|
419
422
|
r != null && r.includes("@") && (this.currentUserEmail = r);
|
|
420
423
|
const s = [];
|
|
421
|
-
i && s.push(i), r && r !== i && s.push(r), e != null && e.username && typeof e.username == "string" && s.push(e.username)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
424
|
+
i && s.push(i), r && r !== i && s.push(r), e != null && e.username && typeof e.username == "string" && s.push(e.username);
|
|
425
|
+
try {
|
|
426
|
+
const t = await this.client.identify({
|
|
427
|
+
user_id: i,
|
|
428
|
+
properties: e || {},
|
|
429
|
+
aliases: s.length > 0 ? s : void 0
|
|
430
|
+
});
|
|
427
431
|
this.log("Identified user", {
|
|
428
432
|
userId: i,
|
|
429
433
|
email: r,
|
|
430
|
-
identityId:
|
|
431
|
-
aliasesCreated: ((
|
|
432
|
-
aliasesFailed: ((
|
|
433
|
-
}), (o =
|
|
434
|
+
identityId: t.data.id,
|
|
435
|
+
aliasesCreated: ((a = (n = t.data.aliases) == null ? void 0 : n.created) == null ? void 0 : a.length) || 0,
|
|
436
|
+
aliasesFailed: ((l = (h = t.data.aliases) == null ? void 0 : h.failed) == null ? void 0 : l.length) || 0
|
|
437
|
+
}), (o = t.data.aliases) != null && o.failed && t.data.aliases.failed.length > 0 && console.warn(
|
|
434
438
|
"[EmitKit-Server] Some aliases failed to create:",
|
|
435
|
-
|
|
439
|
+
t.data.aliases.failed
|
|
436
440
|
);
|
|
437
|
-
}
|
|
438
|
-
console.error("[EmitKit-Server] Failed to identify user:",
|
|
439
|
-
}
|
|
441
|
+
} catch (t) {
|
|
442
|
+
console.error("[EmitKit-Server] Failed to identify user:", t);
|
|
443
|
+
}
|
|
440
444
|
}
|
|
441
445
|
async track(i, e) {
|
|
442
|
-
var
|
|
446
|
+
var t, p;
|
|
443
447
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
444
|
-
const r = ((
|
|
445
|
-
...
|
|
448
|
+
const r = ((t = e == null ? void 0 : e.user) == null ? void 0 : t.email) || ((p = e == null ? void 0 : e.user) == null ? void 0 : p.userId) || i.userId || this.currentUserEmail || this.currentUserId, s = this.formatEventTitle(i.action), { __emitkit_channel: n, ...a } = i.properties || {}, h = {
|
|
449
|
+
...a,
|
|
446
450
|
category: i.category,
|
|
447
451
|
timestamp: i.timestamp || Date.now(),
|
|
448
452
|
...i.sessionId && { sessionId: i.sessionId },
|
|
@@ -461,11 +465,11 @@ class N extends y {
|
|
|
461
465
|
...(e == null ? void 0 : e.utm) && { utm: e.utm },
|
|
462
466
|
...(e == null ? void 0 : e.server) && { server: e.server }
|
|
463
467
|
}, l = [];
|
|
464
|
-
i.category && l.push(i.category),
|
|
465
|
-
const
|
|
468
|
+
i.category && l.push(i.category), a != null && a.tags && Array.isArray(a.tags) && a.tags.every((g) => typeof g == "string") && l.push(...a.tags);
|
|
469
|
+
const o = this.resolveChannelName(i);
|
|
466
470
|
try {
|
|
467
471
|
const g = await this.client.events.create({
|
|
468
|
-
channelName:
|
|
472
|
+
channelName: o,
|
|
469
473
|
title: s,
|
|
470
474
|
description: this.getEventDescription(i, e),
|
|
471
475
|
icon: this.getEventIcon(i.category),
|
|
@@ -480,17 +484,17 @@ class N extends y {
|
|
|
480
484
|
eventId: g.data.id,
|
|
481
485
|
action: i.action,
|
|
482
486
|
userId: r,
|
|
483
|
-
channelName:
|
|
487
|
+
channelName: o
|
|
484
488
|
});
|
|
485
489
|
} catch (g) {
|
|
486
490
|
throw console.error("[EmitKit-Server] Failed to track event:", g), g;
|
|
487
491
|
}
|
|
488
492
|
}
|
|
489
|
-
pageView(i, e) {
|
|
490
|
-
var
|
|
493
|
+
async pageView(i, e) {
|
|
494
|
+
var o, t, p, g;
|
|
491
495
|
if (!this.isEnabled() || !this.initialized || !this.client) return;
|
|
492
|
-
const r = ((
|
|
493
|
-
...
|
|
496
|
+
const r = ((o = e == null ? void 0 : e.user) == null ? void 0 : o.email) || ((t = e == null ? void 0 : e.user) == null ? void 0 : t.userId) || this.currentUserEmail || this.currentUserId, { __emitkit_channel: s, ...n } = i || {}, a = {
|
|
497
|
+
...n,
|
|
494
498
|
date: (/* @__PURE__ */ new Date()).toISOString(),
|
|
495
499
|
...(e == null ? void 0 : e.page) && {
|
|
496
500
|
page: {
|
|
@@ -511,29 +515,29 @@ class N extends y {
|
|
|
511
515
|
category: "navigation",
|
|
512
516
|
properties: i || {}
|
|
513
517
|
}, l = this.resolveChannelName(h);
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
518
|
+
try {
|
|
519
|
+
const f = await this.client.events.create({
|
|
520
|
+
channelName: l,
|
|
521
|
+
title: "Page View",
|
|
522
|
+
description: ((p = e == null ? void 0 : e.page) == null ? void 0 : p.path) || "User viewed a page",
|
|
523
|
+
icon: "👁️",
|
|
524
|
+
tags: ["page_view", "navigation"],
|
|
525
|
+
metadata: a,
|
|
526
|
+
userId: r || null,
|
|
527
|
+
notify: !1,
|
|
528
|
+
// Don't notify for page views by default
|
|
529
|
+
displayAs: "message",
|
|
530
|
+
source: "stacksee-analytics"
|
|
531
|
+
});
|
|
528
532
|
this.log("Tracked page view", {
|
|
529
|
-
eventId:
|
|
530
|
-
path: (
|
|
533
|
+
eventId: f.data.id,
|
|
534
|
+
path: (g = e == null ? void 0 : e.page) == null ? void 0 : g.path,
|
|
531
535
|
userId: r,
|
|
532
536
|
channelName: l
|
|
533
537
|
});
|
|
534
|
-
}
|
|
535
|
-
console.error("[EmitKit-Server] Failed to track page view:",
|
|
536
|
-
}
|
|
538
|
+
} catch (f) {
|
|
539
|
+
console.error("[EmitKit-Server] Failed to track page view:", f);
|
|
540
|
+
}
|
|
537
541
|
}
|
|
538
542
|
async reset() {
|
|
539
543
|
!this.isEnabled() || !this.initialized || !this.client || (this.currentUserId = void 0, this.currentUserEmail = void 0, this.log("Reset user session"));
|
|
@@ -597,60 +601,60 @@ class N extends y {
|
|
|
597
601
|
}
|
|
598
602
|
}
|
|
599
603
|
async function B(d, u, i) {
|
|
600
|
-
var e, r, s,
|
|
604
|
+
var e, r, s, n;
|
|
601
605
|
try {
|
|
602
|
-
const
|
|
603
|
-
if (!
|
|
606
|
+
const a = await d.json();
|
|
607
|
+
if (!a.events || !Array.isArray(a.events))
|
|
604
608
|
throw new Error("Invalid payload: missing events array");
|
|
605
|
-
const h = i != null && i.extractIp ? i.extractIp(d) : $(d), l = d.headers.get("user-agent"),
|
|
606
|
-
for (const
|
|
609
|
+
const h = i != null && i.extractIp ? i.extractIp(d) : $(d), l = d.headers.get("user-agent"), o = i != null && i.enrichContext ? i.enrichContext(d) : {};
|
|
610
|
+
for (const t of a.events)
|
|
607
611
|
try {
|
|
608
|
-
switch (
|
|
612
|
+
switch (t.type) {
|
|
609
613
|
case "track": {
|
|
610
614
|
const p = {
|
|
611
|
-
...
|
|
612
|
-
...
|
|
615
|
+
...t.context,
|
|
616
|
+
...o,
|
|
613
617
|
server: {
|
|
614
|
-
...(e =
|
|
615
|
-
...typeof (
|
|
618
|
+
...(e = t.context) == null ? void 0 : e.server,
|
|
619
|
+
...typeof (o == null ? void 0 : o.server) == "object" && o.server !== null ? o.server : {},
|
|
616
620
|
...l ? { userAgent: l } : {}
|
|
617
621
|
},
|
|
618
622
|
device: {
|
|
619
|
-
...(r =
|
|
623
|
+
...(r = t.context) == null ? void 0 : r.device,
|
|
620
624
|
...h ? { ip: h } : {}
|
|
621
625
|
}
|
|
622
626
|
};
|
|
623
627
|
await u.track(
|
|
624
|
-
|
|
628
|
+
t.event.action,
|
|
625
629
|
// biome-ignore lint/suspicious/noExplicitAny: Properties from JSON cannot be type-checked against TEventMap at compile time
|
|
626
|
-
|
|
630
|
+
t.event.properties,
|
|
627
631
|
{
|
|
628
|
-
userId:
|
|
629
|
-
sessionId:
|
|
632
|
+
userId: t.event.userId,
|
|
633
|
+
sessionId: t.event.sessionId,
|
|
630
634
|
context: p
|
|
631
635
|
}
|
|
632
636
|
);
|
|
633
637
|
break;
|
|
634
638
|
}
|
|
635
639
|
case "identify": {
|
|
636
|
-
u.identify(
|
|
640
|
+
await u.identify(t.userId, t.traits);
|
|
637
641
|
break;
|
|
638
642
|
}
|
|
639
643
|
case "pageView": {
|
|
640
644
|
const p = {
|
|
641
|
-
...
|
|
642
|
-
...
|
|
645
|
+
...t.context,
|
|
646
|
+
...o,
|
|
643
647
|
server: {
|
|
644
|
-
...(s =
|
|
645
|
-
...typeof (
|
|
648
|
+
...(s = t.context) == null ? void 0 : s.server,
|
|
649
|
+
...typeof (o == null ? void 0 : o.server) == "object" && o.server !== null ? o.server : {},
|
|
646
650
|
...l ? { userAgent: l } : {}
|
|
647
651
|
},
|
|
648
652
|
device: {
|
|
649
|
-
...(
|
|
653
|
+
...(n = t.context) == null ? void 0 : n.device,
|
|
650
654
|
...h ? { ip: h } : {}
|
|
651
655
|
}
|
|
652
656
|
};
|
|
653
|
-
u.pageView(
|
|
657
|
+
await u.pageView(t.properties, {
|
|
654
658
|
context: p
|
|
655
659
|
});
|
|
656
660
|
break;
|
|
@@ -658,13 +662,13 @@ async function B(d, u, i) {
|
|
|
658
662
|
case "reset":
|
|
659
663
|
break;
|
|
660
664
|
default:
|
|
661
|
-
console.warn("[Proxy] Unknown event type:",
|
|
665
|
+
console.warn("[Proxy] Unknown event type:", t);
|
|
662
666
|
}
|
|
663
667
|
} catch (p) {
|
|
664
668
|
i != null && i.onError ? i.onError(p) : console.error("[Proxy] Failed to process event:", p);
|
|
665
669
|
}
|
|
666
|
-
} catch (
|
|
667
|
-
throw i != null && i.onError ? i.onError(
|
|
670
|
+
} catch (a) {
|
|
671
|
+
throw i != null && i.onError ? i.onError(a) : console.error("[Proxy] Failed to ingest events:", a), a;
|
|
668
672
|
}
|
|
669
673
|
}
|
|
670
674
|
function $(d) {
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var u = Object.defineProperty;
|
|
2
|
-
var h = (
|
|
3
|
-
var c = (
|
|
2
|
+
var h = (a, e, t) => e in a ? u(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
|
|
3
|
+
var c = (a, e, t) => h(a, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
import { P as w } from "./server-DjEk1fUD.js";
|
|
5
5
|
import { B as y } from "./base.provider-AfFL5W_P.js";
|
|
6
6
|
class f {
|
|
@@ -68,25 +68,25 @@ class f {
|
|
|
68
68
|
), r.excludeEvents && r.eventPatterns && console.warn(
|
|
69
69
|
`[Analytics] Provider ${r.provider.name} has both 'excludeEvents' and 'eventPatterns' specified. Using 'eventPatterns' and ignoring 'excludeEvents'.`
|
|
70
70
|
);
|
|
71
|
-
let
|
|
72
|
-
r.methods ?
|
|
71
|
+
let i;
|
|
72
|
+
r.methods ? i = new Set(r.methods) : r.exclude ? i = new Set(
|
|
73
73
|
t.filter(
|
|
74
|
-
(
|
|
74
|
+
(o) => {
|
|
75
75
|
var v;
|
|
76
|
-
return !((v = r.exclude) != null && v.includes(
|
|
76
|
+
return !((v = r.exclude) != null && v.includes(o));
|
|
77
77
|
}
|
|
78
78
|
)
|
|
79
|
-
) :
|
|
80
|
-
let
|
|
81
|
-
return r.events && r.events.length > 0 ?
|
|
82
|
-
const v =
|
|
79
|
+
) : i = new Set(t);
|
|
80
|
+
let s, l, d;
|
|
81
|
+
return r.events && r.events.length > 0 ? s = new Set(r.events) : r.eventPatterns && r.eventPatterns.length > 0 ? d = r.eventPatterns.map((o) => {
|
|
82
|
+
const v = o.replace(/\*/g, ".*");
|
|
83
83
|
return new RegExp(`^${v}$`);
|
|
84
|
-
}) : r.excludeEvents && r.excludeEvents.length > 0 && (
|
|
84
|
+
}) : r.excludeEvents && r.excludeEvents.length > 0 && (l = new Set(r.excludeEvents)), {
|
|
85
85
|
provider: r.provider,
|
|
86
|
-
enabledMethods:
|
|
87
|
-
enabledEvents:
|
|
88
|
-
excludedEvents:
|
|
89
|
-
eventPatterns:
|
|
86
|
+
enabledMethods: i,
|
|
87
|
+
enabledEvents: s,
|
|
88
|
+
excludedEvents: l,
|
|
89
|
+
eventPatterns: d
|
|
90
90
|
};
|
|
91
91
|
});
|
|
92
92
|
}
|
|
@@ -191,9 +191,11 @@ class f {
|
|
|
191
191
|
* }
|
|
192
192
|
* ```
|
|
193
193
|
*/
|
|
194
|
-
identify(e, t) {
|
|
195
|
-
|
|
196
|
-
|
|
194
|
+
async identify(e, t) {
|
|
195
|
+
const n = this.providerConfigs.filter((i) => this.shouldCallMethod(i, "identify")).map((i) => i.provider.identify(e, t)), r = await Promise.allSettled(n);
|
|
196
|
+
for (const i of r)
|
|
197
|
+
if (i.status === "rejected")
|
|
198
|
+
throw i.reason;
|
|
197
199
|
}
|
|
198
200
|
/**
|
|
199
201
|
* Tracks a custom event with properties and optional context.
|
|
@@ -317,7 +319,7 @@ class f {
|
|
|
317
319
|
* ```
|
|
318
320
|
*/
|
|
319
321
|
async track(e, t, n) {
|
|
320
|
-
var
|
|
322
|
+
var l;
|
|
321
323
|
if (!this.initialized) {
|
|
322
324
|
console.warn("[Analytics] Not initialized. Call initialize() first.");
|
|
323
325
|
return;
|
|
@@ -329,23 +331,23 @@ class f {
|
|
|
329
331
|
timestamp: Date.now(),
|
|
330
332
|
userId: n == null ? void 0 : n.userId,
|
|
331
333
|
sessionId: n == null ? void 0 : n.sessionId
|
|
332
|
-
},
|
|
334
|
+
}, i = {
|
|
333
335
|
...this.config.defaultContext,
|
|
334
336
|
...n == null ? void 0 : n.context,
|
|
335
|
-
user: (n == null ? void 0 : n.user) || ((
|
|
336
|
-
},
|
|
337
|
-
(
|
|
338
|
-
).map(async (
|
|
337
|
+
user: (n == null ? void 0 : n.user) || ((l = n == null ? void 0 : n.context) == null ? void 0 : l.user)
|
|
338
|
+
}, s = this.providerConfigs.filter(
|
|
339
|
+
(d) => this.shouldCallMethod(d, "track") && this.shouldTrackEvent(d, e)
|
|
340
|
+
).map(async (d) => {
|
|
339
341
|
try {
|
|
340
|
-
await
|
|
341
|
-
} catch (
|
|
342
|
+
await d.provider.track(r, i);
|
|
343
|
+
} catch (o) {
|
|
342
344
|
console.error(
|
|
343
|
-
`[Analytics] Provider ${
|
|
344
|
-
|
|
345
|
+
`[Analytics] Provider ${d.provider.name} failed to track event:`,
|
|
346
|
+
o
|
|
345
347
|
);
|
|
346
348
|
}
|
|
347
349
|
});
|
|
348
|
-
await Promise.all(
|
|
350
|
+
await Promise.all(s);
|
|
349
351
|
}
|
|
350
352
|
/**
|
|
351
353
|
* Tracks a page view event from the server side.
|
|
@@ -407,14 +409,15 @@ class f {
|
|
|
407
409
|
* }
|
|
408
410
|
* ```
|
|
409
411
|
*/
|
|
410
|
-
pageView(e, t) {
|
|
412
|
+
async pageView(e, t) {
|
|
411
413
|
if (!this.initialized) return;
|
|
412
414
|
const n = {
|
|
413
415
|
...this.config.defaultContext,
|
|
414
416
|
...t == null ? void 0 : t.context
|
|
415
|
-
};
|
|
416
|
-
for (const
|
|
417
|
-
|
|
417
|
+
}, r = this.providerConfigs.filter((s) => this.shouldCallMethod(s, "pageView")).map((s) => s.provider.pageView(e, n)), i = await Promise.allSettled(r);
|
|
418
|
+
for (const s of i)
|
|
419
|
+
if (s.status === "rejected")
|
|
420
|
+
throw s.reason;
|
|
418
421
|
}
|
|
419
422
|
/**
|
|
420
423
|
* Tracks when a user leaves a page from the server side.
|
|
@@ -577,11 +580,11 @@ class f {
|
|
|
577
580
|
return t.length > 1 && t[0] ? t[0] : "engagement";
|
|
578
581
|
}
|
|
579
582
|
}
|
|
580
|
-
function
|
|
583
|
+
function m(a) {
|
|
581
584
|
const e = {
|
|
582
|
-
providers:
|
|
583
|
-
debug:
|
|
584
|
-
enabled:
|
|
585
|
+
providers: a.providers || [],
|
|
586
|
+
debug: a.debug,
|
|
587
|
+
enabled: a.enabled
|
|
585
588
|
}, t = new f(e);
|
|
586
589
|
return t.initialize(), t;
|
|
587
590
|
}
|
|
@@ -589,5 +592,5 @@ export {
|
|
|
589
592
|
y as BaseAnalyticsProvider,
|
|
590
593
|
w as PostHogServerProvider,
|
|
591
594
|
f as ServerAnalytics,
|
|
592
|
-
|
|
595
|
+
m as createServerAnalytics
|
|
593
596
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksee/analytics",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "A highly typed, provider-agnostic analytics library for TypeScript applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"@vitest/coverage-v8": "3.1.4",
|
|
57
57
|
"globals": "^15.8.0",
|
|
58
58
|
"jsdom": "^26.1.0",
|
|
59
|
+
"playwright": "^1.58.2",
|
|
59
60
|
"prettier": "^3.3.3",
|
|
60
61
|
"typescript": "~5.5.3",
|
|
61
62
|
"vite": "^6.3.5",
|
|
@@ -76,12 +77,14 @@
|
|
|
76
77
|
"scripts": {
|
|
77
78
|
"test": "vitest run",
|
|
78
79
|
"test:watch": "vitest",
|
|
80
|
+
"test:e2e": "node e2e/pirsch.test.js",
|
|
81
|
+
"test:e2e:server": "node e2e/test-app/server.js",
|
|
79
82
|
"build": "vite build",
|
|
80
83
|
"dev": "pnpm --filter @stacksee/docs dev",
|
|
81
84
|
"build:docs": "pnpm --filter @stacksee/docs build",
|
|
82
85
|
"deploy": "npm publish",
|
|
83
86
|
"typecheck": "tsc --noEmit",
|
|
84
|
-
"ci:publish": "pnpm build && changeset publish",
|
|
87
|
+
"ci:publish": "pnpm build && changeset publish --provenance",
|
|
85
88
|
"lint": "biome lint .",
|
|
86
89
|
"format": "biome format --write .",
|
|
87
90
|
"biome": "biome"
|