@stacksee/analytics 0.13.0 → 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.
@@ -1,16 +1,16 @@
1
- var O = Object.defineProperty;
2
- var N = (t, u, i) => u in t ? O(t, u, { enumerable: !0, configurable: !0, writable: !0, value: i }) : t[u] = i;
3
- var f = (t, u, i) => N(t, typeof u != "symbol" ? u + "" : u, i);
4
- import { B } from "../base.provider-AfFL5W_P.js";
5
- import { P as X } from "../server-DjEk1fUD.js";
6
- class H extends B {
1
+ var U = Object.defineProperty;
2
+ var F = (d, u, i) => u in d ? U(d, u, { enumerable: !0, configurable: !0, writable: !0, value: i }) : d[u] = i;
3
+ var c = (d, u, i) => F(d, typeof u != "symbol" ? u + "" : u, i);
4
+ import { B as y } from "../base.provider-AfFL5W_P.js";
5
+ import { P as H } from "../server-DjEk1fUD.js";
6
+ class O extends y {
7
7
  constructor(i) {
8
8
  super({ debug: i.debug, enabled: i.enabled });
9
- f(this, "name", "Bento-Server");
10
- f(this, "client");
11
- f(this, "initialized", !1);
12
- f(this, "config");
13
- f(this, "currentUserEmail");
9
+ c(this, "name", "Bento-Server");
10
+ c(this, "client");
11
+ c(this, "initialized", !1);
12
+ c(this, "config");
13
+ c(this, "currentUserEmail");
14
14
  this.config = i;
15
15
  }
16
16
  async initialize() {
@@ -23,8 +23,8 @@ class H extends B {
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-CWEAoj97.js"), { debug: a, enabled: s, ...l } = this.config;
27
- this.client = new r(l), this.initialized = !0, this.log("Initialized successfully", {
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 H extends B {
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("@")) {
@@ -46,25 +46,25 @@ class H extends B {
46
46
  return;
47
47
  }
48
48
  this.currentUserEmail = r;
49
- const a = e ? { ...e } : {};
50
- a.email = void 0, this.client.V1.addSubscriber({
51
- email: r,
52
- fields: a
53
- }).catch((s) => {
54
- console.error("[Bento-Server] Failed to identify user:", s);
55
- }), this.log("Identified user", { userId: i, email: r, traits: e });
49
+ const s = e ? { ...e } : {};
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 l, n, p, d;
58
+ var a, h, l, o;
59
59
  if (!this.isEnabled() || !this.initialized || !this.client) return;
60
- const r = ((l = e == null ? void 0 : e.user) == null ? void 0 : l.email) || this.currentUserEmail || ((n = e == null ? void 0 : e.user) == null ? void 0 : n.userId) || i.userId;
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."
64
64
  );
65
65
  return;
66
66
  }
67
- const a = {
67
+ const s = {
68
68
  ...i.properties,
69
69
  category: i.category,
70
70
  timestamp: i.timestamp || Date.now(),
@@ -83,30 +83,30 @@ class H extends B {
83
83
  ...(e == null ? void 0 : e.device) && { device: e.device },
84
84
  ...(e == null ? void 0 : e.utm) && { utm: e.utm },
85
85
  site: this.config.siteUuid,
86
- ...((p = e == null ? void 0 : e.user) == null ? void 0 : p.userId) && { visitor: e.user.userId }
87
- }, s = ((d = e == null ? void 0 : e.user) == null ? void 0 : d.traits) || {};
86
+ ...((l = e == null ? void 0 : e.user) == null ? void 0 : l.userId) && { visitor: e.user.userId }
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
- details: a,
93
- fields: s
92
+ details: s,
93
+ fields: n
94
94
  }), this.log("Tracked event", { event: i, context: e });
95
- } catch (h) {
96
- console.error("[Bento-Server] Failed to track event:", h);
95
+ } catch (t) {
96
+ console.error("[Bento-Server] Failed to track event:", t);
97
97
  }
98
98
  }
99
- pageView(i, e) {
100
- var l, n, p;
99
+ async pageView(i, e) {
100
+ var a, h, l;
101
101
  if (!this.isEnabled() || !this.initialized || !this.client) return;
102
- const r = ((l = e == null ? void 0 : e.user) == null ? void 0 : l.email) || this.currentUserEmail;
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."
106
106
  );
107
107
  return;
108
108
  }
109
- const a = {
109
+ const s = {
110
110
  ...i,
111
111
  date: (/* @__PURE__ */ new Date()).toISOString(),
112
112
  ...(e == null ? void 0 : e.page) && {
@@ -121,16 +121,13 @@ class H extends B {
121
121
  }
122
122
  },
123
123
  site: this.config.siteUuid,
124
- ...((n = e == null ? void 0 : e.user) == null ? void 0 : n.userId) && { visitor: e.user.userId }
125
- }, s = ((p = e == null ? void 0 : e.user) == null ? void 0 : p.traits) || {};
126
- this.client.V1.track({
127
- email: r,
128
- type: "$view",
129
- details: a,
130
- fields: s
131
- }).catch((d) => {
132
- console.error("[Bento-Server] Failed to track page view:", d);
133
- }), this.log("Tracked page view", { properties: i, context: e });
124
+ ...((h = e == null ? void 0 : e.user) == null ? void 0 : h.userId) && { visitor: e.user.userId }
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"));
@@ -139,186 +136,262 @@ class H extends B {
139
136
  this.client = void 0, this.initialized = !1, this.log("Shutdown complete");
140
137
  }
141
138
  }
142
- class W extends B {
139
+ const T = "https://api.pirsch.io", K = 1e4;
140
+ class j extends y {
143
141
  constructor(i) {
144
142
  super({ debug: i.debug, enabled: i.enabled });
145
- f(this, "name", "Pirsch-Server");
146
- f(this, "client");
147
- f(this, "initialized", !1);
148
- f(this, "config");
143
+ c(this, "name", "Pirsch-Server");
144
+ c(this, "initialized", !1);
145
+ c(this, "config");
146
+ c(this, "accessToken", "");
147
+ c(this, "tokenExpiresAt", null);
148
+ c(this, "isAccessKey", !1);
149
149
  this.config = i;
150
150
  }
151
151
  async initialize() {
152
- if (!this.isEnabled() || this.initialized) return;
153
- if (!this.config.hostname || typeof this.config.hostname != "string")
154
- throw new Error("Pirsch requires a hostname");
155
- if (!this.config.clientSecret || typeof this.config.clientSecret != "string")
156
- throw new Error("Pirsch requires a clientSecret (or access key)");
157
- const i = this.config.clientSecret.startsWith("pa_");
158
- if (!i && !this.config.clientId)
159
- throw new Error(
160
- "Pirsch requires a clientId when using OAuth authentication (clientSecret doesn't start with 'pa_'). Either provide a clientId or use an access key (starts with 'pa_') as clientSecret."
161
- );
162
- try {
163
- const { Pirsch: e } = await import("../index-zS7gy63J.js").then((l) => l.i), { debug: r, enabled: a, ...s } = this.config;
164
- this.client = new e(s), this.initialized = !0, this.log("Initialized successfully", {
152
+ if (this.isEnabled() && !this.initialized) {
153
+ if (!this.config.hostname || typeof this.config.hostname != "string")
154
+ throw new Error("Pirsch requires a hostname");
155
+ if (!this.config.clientSecret || typeof this.config.clientSecret != "string")
156
+ throw new Error("Pirsch requires a clientSecret (or access key)");
157
+ if (this.isAccessKey = this.config.clientSecret.startsWith("pa_"), !this.isAccessKey && !this.config.clientId)
158
+ throw new Error(
159
+ "Pirsch requires a clientId when using OAuth authentication (clientSecret doesn't start with 'pa_'). Either provide a clientId or use an access key (starts with 'pa_') as clientSecret."
160
+ );
161
+ this.isAccessKey && (this.accessToken = this.config.clientSecret), this.initialized = !0, this.log("Initialized successfully", {
165
162
  hostname: this.config.hostname,
166
- authMode: i ? "access-key" : "oauth"
163
+ authMode: this.isAccessKey ? "access-key" : "oauth"
167
164
  });
168
- } catch (e) {
169
- throw console.error(
170
- "[Pirsch-Server] Failed to initialize. Make sure pirsch-sdk is installed:",
171
- e
172
- ), e;
173
165
  }
174
166
  }
175
- identify(i, e) {
176
- if (!this.isEnabled() || !this.initialized || !this.client) return;
177
- const r = {
178
- url: "https://identify",
179
- ip: "0.0.0.0",
180
- user_agent: "analytics-library"
181
- }, a = {
182
- userId: i,
183
- ...e && Object.fromEntries(
184
- Object.entries(e).filter(
185
- ([, s]) => typeof s == "string" || typeof s == "number" || typeof s == "boolean"
186
- )
187
- )
188
- };
189
- this.client.event("user_identified", r, 0, a).catch((s) => {
190
- console.error("[Pirsch-Server] Failed to track identify event:", s);
191
- }), this.log("Identified user via event", { userId: i, traits: e });
167
+ /**
168
+ * Fetch with timeout using AbortController
169
+ */
170
+ async fetchWithTimeout(i, e, r) {
171
+ const s = new AbortController(), n = r ?? this.config.timeout ?? K, a = setTimeout(() => s.abort(), n);
172
+ try {
173
+ return await fetch(i, {
174
+ ...e,
175
+ signal: s.signal
176
+ });
177
+ } finally {
178
+ clearTimeout(a);
179
+ }
192
180
  }
193
- async track(i, e) {
194
- var h, g, o, c, y, m, w, b, E, I, k, _, S, z, P, U, K, A, v, $, D, j, V;
195
- if (!this.isEnabled() || !this.initialized || !this.client) return;
196
- const r = e, a = ((h = r == null ? void 0 : r.device) == null ? void 0 : h.ip) || ((g = r == null ? void 0 : r.server) == null ? void 0 : g.ip), s = ((o = r == null ? void 0 : r.server) == null ? void 0 : o.userAgent) || ((c = r == null ? void 0 : r.device) == null ? void 0 : c.userAgent);
197
- if (!a || !s) {
198
- this.log(
199
- "Skipping event - missing required IP or user-agent from context",
181
+ /**
182
+ * Ensure we have a valid access token (for OAuth mode)
183
+ */
184
+ async ensureToken() {
185
+ if (this.isAccessKey)
186
+ return this.accessToken;
187
+ if (this.accessToken && this.tokenExpiresAt && /* @__PURE__ */ new Date() < new Date(this.tokenExpiresAt.getTime() - 6e4))
188
+ return this.accessToken;
189
+ try {
190
+ const i = await this.fetchWithTimeout(
191
+ `${T}/api/v1/token`,
200
192
  {
201
- hasIp: !!a,
202
- hasUserAgent: !!s,
203
- event: i.action
193
+ method: "POST",
194
+ headers: { "Content-Type": "application/json" },
195
+ body: JSON.stringify({
196
+ client_id: this.config.clientId,
197
+ client_secret: this.config.clientSecret
198
+ })
204
199
  }
205
200
  );
206
- return;
201
+ if (!i.ok) {
202
+ const r = await i.text();
203
+ throw new Error(`Failed to get Pirsch token: ${i.status} ${r}`);
204
+ }
205
+ const e = await i.json();
206
+ return this.accessToken = e.access_token, this.tokenExpiresAt = new Date(e.expires_at), this.log("OAuth token refreshed", { expiresAt: e.expires_at }), this.accessToken;
207
+ } catch (i) {
208
+ throw console.error("[Pirsch-Server] Failed to refresh token:", i), i;
209
+ }
210
+ }
211
+ /**
212
+ * Make an authenticated request to Pirsch API
213
+ */
214
+ async request(i, e, r = !0) {
215
+ const s = await this.ensureToken();
216
+ try {
217
+ const n = await this.fetchWithTimeout(
218
+ `${T}${i}`,
219
+ {
220
+ method: "POST",
221
+ headers: {
222
+ "Content-Type": "application/json",
223
+ Authorization: `Bearer ${s}`
224
+ },
225
+ body: JSON.stringify(e)
226
+ }
227
+ );
228
+ if (n.status === 401 && r && !this.isAccessKey)
229
+ return this.accessToken = "", this.tokenExpiresAt = null, this.request(i, e, !1);
230
+ if (!n.ok) {
231
+ const a = await n.text();
232
+ throw new Error(`Pirsch API error: ${n.status} ${a}`);
233
+ }
234
+ } catch (n) {
235
+ throw n instanceof Error && n.name === "AbortError" ? new Error(
236
+ `Pirsch request timeout after ${this.config.timeout ?? K}ms`
237
+ ) : n;
207
238
  }
208
- const n = {
209
- url: ((y = e == null ? void 0 : e.page) == null ? void 0 : y.url) || ((m = e == null ? void 0 : e.page) != null && m.protocol && ((w = e == null ? void 0 : e.page) != null && w.host) && ((b = e == null ? void 0 : e.page) != null && b.path) ? `${e.page.protocol}://${e.page.host}${e.page.path}` : (E = e == null ? void 0 : e.page) != null && E.path ? `https://${this.config.hostname}${e.page.path}` : "https://event"),
210
- ip: a,
239
+ }
240
+ /**
241
+ * Filter object to only include scalar values (string, number, boolean)
242
+ */
243
+ filterScalars(i) {
244
+ return Object.fromEntries(
245
+ Object.entries(i).filter(
246
+ ([, e]) => typeof e == "string" || typeof e == "number" || typeof e == "boolean"
247
+ )
248
+ );
249
+ }
250
+ /**
251
+ * Convert object values to strings for Pirsch event_meta
252
+ * Pirsch API requires event_meta to be a single dimension object of string values
253
+ */
254
+ toStringRecord(i) {
255
+ return Object.fromEntries(
256
+ Object.entries(i).filter(
257
+ ([, e]) => e != null && typeof e != "object"
258
+ ).map(([e, r]) => [e, String(r)])
259
+ );
260
+ }
261
+ /**
262
+ * Build a Pirsch hit from context
263
+ */
264
+ buildHit(i) {
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);
267
+ return !r || !s ? null : {
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}`),
269
+ ip: r,
211
270
  user_agent: s,
212
- ...((I = e == null ? void 0 : e.page) == null ? void 0 : I.title) && { title: e.page.title },
213
- ...((k = e == null ? void 0 : e.page) == null ? void 0 : k.referrer) && { referrer: e.page.referrer },
214
- ...((S = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : S.width) && {
215
- screen_width: e.device.screen.width
271
+ ...((v = i == null ? void 0 : i.page) == null ? void 0 : v.title) && { title: i.page.title },
272
+ ...((w = i == null ? void 0 : i.page) == null ? void 0 : w.referrer) && { referrer: i.page.referrer },
273
+ ...((k = (b = i == null ? void 0 : i.device) == null ? void 0 : b.screen) == null ? void 0 : k.width) && {
274
+ screen_width: i.device.screen.width
216
275
  },
217
- ...((P = (z = e == null ? void 0 : e.device) == null ? void 0 : z.screen) == null ? void 0 : P.height) && {
218
- screen_height: e.device.screen.height
276
+ ...((_ = (E = i == null ? void 0 : i.device) == null ? void 0 : E.screen) == null ? void 0 : _.height) && {
277
+ screen_height: i.device.screen.height
219
278
  },
220
- ...((K = (U = e == null ? void 0 : e.device) == null ? void 0 : U.viewport) == null ? void 0 : K.width) && {
221
- sec_ch_viewport_width: String(e.device.viewport.width)
279
+ ...((I = (S = i == null ? void 0 : i.device) == null ? void 0 : S.viewport) == null ? void 0 : I.width) && {
280
+ sec_ch_viewport_width: String(i.device.viewport.width)
222
281
  },
223
- ...((A = e == null ? void 0 : e.device) == null ? void 0 : A.language) && {
224
- accept_language: e.device.language
282
+ ...((A = i == null ? void 0 : i.device) == null ? void 0 : A.language) && {
283
+ accept_language: i.device.language
225
284
  },
226
- ...((v = e == null ? void 0 : e.device) == null ? void 0 : v.type) && {
227
- sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0"
285
+ ...((z = i == null ? void 0 : i.device) == null ? void 0 : z.type) && {
286
+ sec_ch_ua_mobile: i.device.type === "mobile" || i.device.type === "tablet" ? "?1" : "?0"
228
287
  },
229
- ...(($ = e == null ? void 0 : e.device) == null ? void 0 : $.os) && { sec_ch_ua_platform: e.device.os }
230
- }, d = {
231
- ...Object.fromEntries(
232
- Object.entries(i.properties).filter(
233
- ([, F]) => typeof F == "string" || typeof F == "number" || typeof F == "boolean"
234
- )
235
- ),
288
+ ...((P = i == null ? void 0 : i.device) == null ? void 0 : P.os) && { sec_ch_ua_platform: i.device.os },
289
+ ...this.config.disableBotFilter && { disable_bot_filter: !0 }
290
+ };
291
+ }
292
+ async identify(i, e) {
293
+ if (!this.isEnabled() || !this.initialized) return;
294
+ const r = {
295
+ url: `https://${this.config.hostname}/identify`,
296
+ ip: "0.0.0.0",
297
+ user_agent: "stacksee-analytics",
298
+ ...this.config.disableBotFilter && { disable_bot_filter: !0 }
299
+ }, s = this.toStringRecord({
300
+ userId: i,
301
+ ...e
302
+ }), n = {
303
+ ...r,
304
+ event_name: "user_identified",
305
+ event_duration: 0,
306
+ event_meta: s,
307
+ non_interactive: !0
308
+ // Synthetic event shouldn't affect bounce rate
309
+ };
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
+ }
315
+ }
316
+ async track(i, e) {
317
+ var h, l, o, t;
318
+ if (!this.isEnabled() || !this.initialized) return;
319
+ const r = this.buildHit(e);
320
+ if (!r) {
321
+ this.log("Skipping event - missing required IP or user-agent", {
322
+ event: i.action
323
+ });
324
+ return;
325
+ }
326
+ const s = this.toStringRecord({
327
+ ...i.properties,
236
328
  category: i.category,
237
- timestamp: String(i.timestamp || Date.now()),
329
+ timestamp: i.timestamp || Date.now(),
238
330
  ...i.userId && { userId: i.userId },
239
331
  ...i.sessionId && { sessionId: i.sessionId },
240
- ...((D = e == null ? void 0 : e.user) == null ? void 0 : D.email) && { user_email: e.user.email },
241
- ...((j = e == null ? void 0 : e.device) == null ? void 0 : j.timezone) && { timezone: e.device.timezone },
242
- ...((V = e == null ? void 0 : e.device) == null ? void 0 : V.browser) && { browser: e.device.browser }
332
+ ...((h = e == null ? void 0 : e.user) == null ? void 0 : h.email) && { user_email: e.user.email },
333
+ ...((l = e == null ? void 0 : e.device) == null ? void 0 : l.timezone) && { timezone: e.device.timezone },
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 = {
336
+ ...r,
337
+ event_name: i.action,
338
+ event_duration: 0,
339
+ event_meta: s,
340
+ ...n && { non_interactive: !0 }
243
341
  };
244
342
  try {
245
- await this.client.event(i.action, n, 0, d), this.log("Tracked event", { event: i, context: e });
246
- } catch (F) {
247
- console.error("[Pirsch-Server] Failed to track event:", F);
343
+ await this.request("/api/v1/event", a), this.log("Tracked event", { event: i.action });
344
+ } catch (p) {
345
+ console.error("[Pirsch-Server] Failed to track event:", p);
248
346
  }
249
347
  }
250
- pageView(i, e) {
251
- var p, d, h, g, o, c, y, m, w, b, E, I, k, _, S, z, P, U, K, A;
252
- if (!this.isEnabled() || !this.initialized || !this.client) return;
253
- const r = e, a = ((p = r == null ? void 0 : r.device) == null ? void 0 : p.ip) || ((d = r == null ? void 0 : r.server) == null ? void 0 : d.ip), s = ((h = r == null ? void 0 : r.server) == null ? void 0 : h.userAgent) || ((g = r == null ? void 0 : r.device) == null ? void 0 : g.userAgent);
254
- if (!a || !s) {
255
- this.log(
256
- "Skipping pageView - missing required IP or user-agent from context",
257
- {
258
- hasIp: !!a,
259
- hasUserAgent: !!s
260
- }
261
- );
348
+ async pageView(i, e) {
349
+ var s;
350
+ if (!this.isEnabled() || !this.initialized) return;
351
+ const r = this.buildHit(e);
352
+ if (!r) {
353
+ this.log("Skipping pageView - missing required IP or user-agent");
262
354
  return;
263
355
  }
264
- const n = {
265
- url: ((o = e == null ? void 0 : e.page) == null ? void 0 : o.url) || ((c = e == null ? void 0 : e.page) != null && c.protocol && ((y = e == null ? void 0 : e.page) != null && y.host) && ((m = e == null ? void 0 : e.page) != null && m.path) ? `${e.page.protocol}://${e.page.host}${e.page.path}` : (w = e == null ? void 0 : e.page) != null && w.path ? `https://${this.config.hostname}${e.page.path}` : "https://pageview"),
266
- ip: a,
267
- user_agent: s,
268
- ...((b = e == null ? void 0 : e.page) == null ? void 0 : b.title) && { title: e.page.title },
269
- ...((E = e == null ? void 0 : e.page) == null ? void 0 : E.referrer) && { referrer: e.page.referrer },
270
- ...((k = (I = e == null ? void 0 : e.device) == null ? void 0 : I.screen) == null ? void 0 : k.width) && {
271
- screen_width: e.device.screen.width
272
- },
273
- ...((S = (_ = e == null ? void 0 : e.device) == null ? void 0 : _.screen) == null ? void 0 : S.height) && {
274
- screen_height: e.device.screen.height
275
- },
276
- ...((P = (z = e == null ? void 0 : e.device) == null ? void 0 : z.viewport) == null ? void 0 : P.width) && {
277
- sec_ch_viewport_width: String(e.device.viewport.width)
278
- },
279
- ...((U = e == null ? void 0 : e.device) == null ? void 0 : U.language) && {
280
- accept_language: e.device.language
281
- },
282
- ...((K = e == null ? void 0 : e.device) == null ? void 0 : K.type) && {
283
- sec_ch_ua_mobile: e.device.type === "mobile" || e.device.type === "tablet" ? "?1" : "?0"
284
- },
285
- ...((A = e == null ? void 0 : e.device) == null ? void 0 : A.os) && { sec_ch_ua_platform: e.device.os },
286
- ...i && {
287
- tags: Object.fromEntries(
288
- Object.entries(i).filter(
289
- ([, v]) => typeof v == "string" || typeof v == "number" || typeof v == "boolean"
290
- )
291
- )
292
- }
293
- };
294
- this.client.hit(n).catch((v) => {
295
- console.error("[Pirsch-Server] Failed to track page view:", v);
296
- }), this.log("Tracked page view", { properties: i, context: e });
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
+ }
297
362
  }
298
363
  async reset() {
299
- if (!this.isEnabled() || !this.initialized || !this.client) return;
300
- const i = {
301
- url: "https://session-reset",
302
- ip: "0.0.0.0",
303
- user_agent: "analytics-library"
364
+ if (!this.isEnabled() || !this.initialized) return;
365
+ const e = {
366
+ ...{
367
+ url: `https://${this.config.hostname}/session-reset`,
368
+ ip: "0.0.0.0",
369
+ user_agent: "stacksee-analytics",
370
+ ...this.config.disableBotFilter && { disable_bot_filter: !0 }
371
+ },
372
+ event_name: "session_reset",
373
+ event_duration: 0,
374
+ event_meta: {},
375
+ non_interactive: !0
376
+ // Synthetic event shouldn't affect bounce rate
304
377
  };
305
- await this.client.event("session_reset", i, 0, {}).catch((e) => {
306
- console.error("[Pirsch-Server] Failed to track session reset:", e);
378
+ await this.request("/api/v1/event", e).catch((r) => {
379
+ console.error("[Pirsch-Server] Failed to track session reset:", r);
307
380
  }), this.log("Reset user session");
308
381
  }
309
382
  async shutdown() {
310
- this.client = void 0, this.initialized = !1, this.log("Shutdown complete");
383
+ this.accessToken = "", this.tokenExpiresAt = null, this.initialized = !1, this.log("Shutdown complete");
311
384
  }
312
385
  }
313
- class G extends B {
386
+ class N extends y {
314
387
  constructor(i) {
315
388
  super({ debug: i.debug, enabled: i.enabled });
316
- f(this, "name", "EmitKit-Server");
317
- f(this, "client");
318
- f(this, "initialized", !1);
319
- f(this, "config");
320
- f(this, "currentUserId");
321
- f(this, "currentUserEmail");
389
+ c(this, "name", "EmitKit-Server");
390
+ c(this, "client");
391
+ c(this, "initialized", !1);
392
+ c(this, "config");
393
+ c(this, "currentUserId");
394
+ c(this, "currentUserEmail");
322
395
  this.config = i;
323
396
  }
324
397
  async initialize() {
@@ -330,7 +403,9 @@ class G extends B {
330
403
  );
331
404
  try {
332
405
  const { EmitKit: i } = await import("../index-CBs091W0.js");
333
- this.client = new i(this.config.apiKey), this.initialized = !0, this.log("Initialized successfully");
406
+ this.client = new i(this.config.apiKey, {
407
+ ...this.config.timeout && { timeout: this.config.timeout }
408
+ }), this.initialized = !0, this.log("Initialized successfully");
334
409
  } catch (i) {
335
410
  throw console.error(
336
411
  "[EmitKit-Server] Failed to initialize. Make sure @emitkit/js is installed:",
@@ -339,37 +414,39 @@ class G extends B {
339
414
  }
340
415
  }
341
416
  }
342
- identify(i, e) {
417
+ async identify(i, e) {
418
+ var n, a, h, l, o;
343
419
  if (!this.isEnabled() || !this.initialized || !this.client) return;
344
420
  this.currentUserId = i;
345
421
  const r = (e == null ? void 0 : e.email) || i;
346
422
  r != null && r.includes("@") && (this.currentUserEmail = r);
347
- const a = [];
348
- i && a.push(i), r && r !== i && a.push(r), e != null && e.username && typeof e.username == "string" && a.push(e.username), this.client.identify({
349
- user_id: i,
350
- properties: e || {},
351
- aliases: a.length > 0 ? a : void 0
352
- }).then((s) => {
353
- var l, n, p, d, h;
423
+ const s = [];
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
+ });
354
431
  this.log("Identified user", {
355
432
  userId: i,
356
433
  email: r,
357
- identityId: s.data.id,
358
- aliasesCreated: ((n = (l = s.data.aliases) == null ? void 0 : l.created) == null ? void 0 : n.length) || 0,
359
- aliasesFailed: ((d = (p = s.data.aliases) == null ? void 0 : p.failed) == null ? void 0 : d.length) || 0
360
- }), (h = s.data.aliases) != null && h.failed && s.data.aliases.failed.length > 0 && console.warn(
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(
361
438
  "[EmitKit-Server] Some aliases failed to create:",
362
- s.data.aliases.failed
439
+ t.data.aliases.failed
363
440
  );
364
- }).catch((s) => {
365
- console.error("[EmitKit-Server] Failed to identify user:", s);
366
- });
441
+ } catch (t) {
442
+ console.error("[EmitKit-Server] Failed to identify user:", t);
443
+ }
367
444
  }
368
445
  async track(i, e) {
369
- var h, g;
446
+ var t, p;
370
447
  if (!this.isEnabled() || !this.initialized || !this.client) return;
371
- const r = ((h = e == null ? void 0 : e.user) == null ? void 0 : h.email) || ((g = e == null ? void 0 : e.user) == null ? void 0 : g.userId) || i.userId || this.currentUserEmail || this.currentUserId, a = this.formatEventTitle(i.action), { __emitkit_channel: s, ...l } = i.properties || {}, n = {
372
- ...l,
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,
373
450
  category: i.category,
374
451
  timestamp: i.timestamp || Date.now(),
375
452
  ...i.sessionId && { sessionId: i.sessionId },
@@ -387,37 +464,37 @@ class G extends B {
387
464
  ...(e == null ? void 0 : e.device) && { device: e.device },
388
465
  ...(e == null ? void 0 : e.utm) && { utm: e.utm },
389
466
  ...(e == null ? void 0 : e.server) && { server: e.server }
390
- }, p = [];
391
- i.category && p.push(i.category), l != null && l.tags && Array.isArray(l.tags) && l.tags.every((o) => typeof o == "string") && p.push(...l.tags);
392
- const d = this.resolveChannelName(i);
467
+ }, l = [];
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);
393
470
  try {
394
- const o = await this.client.events.create({
395
- channelName: d,
396
- title: a,
471
+ const g = await this.client.events.create({
472
+ channelName: o,
473
+ title: s,
397
474
  description: this.getEventDescription(i, e),
398
475
  icon: this.getEventIcon(i.category),
399
- tags: p.length > 0 ? p : void 0,
400
- metadata: n,
476
+ tags: l.length > 0 ? l : void 0,
477
+ metadata: h,
401
478
  userId: r || null,
402
479
  notify: this.config.notify ?? !0,
403
480
  displayAs: this.config.displayAs || "notification",
404
481
  source: "stacksee-analytics"
405
482
  });
406
483
  this.log("Tracked event", {
407
- eventId: o.data.id,
484
+ eventId: g.data.id,
408
485
  action: i.action,
409
486
  userId: r,
410
- channelName: d
487
+ channelName: o
411
488
  });
412
- } catch (o) {
413
- throw console.error("[EmitKit-Server] Failed to track event:", o), o;
489
+ } catch (g) {
490
+ throw console.error("[EmitKit-Server] Failed to track event:", g), g;
414
491
  }
415
492
  }
416
- pageView(i, e) {
417
- var d, h, g;
493
+ async pageView(i, e) {
494
+ var o, t, p, g;
418
495
  if (!this.isEnabled() || !this.initialized || !this.client) return;
419
- const r = ((d = e == null ? void 0 : e.user) == null ? void 0 : d.email) || ((h = e == null ? void 0 : e.user) == null ? void 0 : h.userId) || this.currentUserEmail || this.currentUserId, { __emitkit_channel: a, ...s } = i || {}, l = {
420
- ...s,
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,
421
498
  date: (/* @__PURE__ */ new Date()).toISOString(),
422
499
  ...(e == null ? void 0 : e.page) && {
423
500
  page: {
@@ -433,34 +510,34 @@ class G extends B {
433
510
  ...(e == null ? void 0 : e.device) && { device: e.device },
434
511
  ...(e == null ? void 0 : e.utm) && { utm: e.utm },
435
512
  ...(e == null ? void 0 : e.server) && { server: e.server }
436
- }, n = {
513
+ }, h = {
437
514
  action: "page_view",
438
515
  category: "navigation",
439
516
  properties: i || {}
440
- }, p = this.resolveChannelName(n);
441
- this.client.events.create({
442
- channelName: p,
443
- title: "Page View",
444
- description: ((g = e == null ? void 0 : e.page) == null ? void 0 : g.path) || "User viewed a page",
445
- icon: "👁️",
446
- tags: ["page_view", "navigation"],
447
- metadata: l,
448
- userId: r || null,
449
- notify: !1,
450
- // Don't notify for page views by default
451
- displayAs: "message",
452
- source: "stacksee-analytics"
453
- }).then((o) => {
454
- var c;
517
+ }, l = this.resolveChannelName(h);
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
+ });
455
532
  this.log("Tracked page view", {
456
- eventId: o.data.id,
457
- path: (c = e == null ? void 0 : e.page) == null ? void 0 : c.path,
533
+ eventId: f.data.id,
534
+ path: (g = e == null ? void 0 : e.page) == null ? void 0 : g.path,
458
535
  userId: r,
459
- channelName: p
536
+ channelName: l
460
537
  });
461
- }).catch((o) => {
462
- console.error("[EmitKit-Server] Failed to track page view:", o);
463
- });
538
+ } catch (f) {
539
+ console.error("[EmitKit-Server] Failed to track page view:", f);
540
+ }
464
541
  }
465
542
  async reset() {
466
543
  !this.isEnabled() || !this.initialized || !this.client || (this.currentUserId = void 0, this.currentUserEmail = void 0, this.log("Reset user session"));
@@ -482,8 +559,8 @@ class G extends B {
482
559
  * Generate a description for the event
483
560
  */
484
561
  getEventDescription(i, e) {
485
- var a;
486
- return (a = i.properties) != null && a.description && typeof i.properties.description == "string" ? i.properties.description : {
562
+ var s;
563
+ return (s = i.properties) != null && s.description && typeof i.properties.description == "string" ? i.properties.description : {
487
564
  engagement: "User interaction event",
488
565
  user: "User lifecycle event",
489
566
  navigation: "Navigation event",
@@ -516,85 +593,85 @@ class G extends B {
516
593
  if ((r = i.properties) != null && r.__emitkit_channel && typeof i.properties.__emitkit_channel == "string")
517
594
  return i.properties.__emitkit_channel;
518
595
  if (this.config.categoryChannelMap && i.category) {
519
- const a = this.config.categoryChannelMap[i.category];
520
- if (a)
521
- return a;
596
+ const s = this.config.categoryChannelMap[i.category];
597
+ if (s)
598
+ return s;
522
599
  }
523
600
  return e || this.config.channelName || "general";
524
601
  }
525
602
  }
526
- async function q(t, u, i) {
527
- var e, r, a, s;
603
+ async function B(d, u, i) {
604
+ var e, r, s, n;
528
605
  try {
529
- const l = await t.json();
530
- if (!l.events || !Array.isArray(l.events))
606
+ const a = await d.json();
607
+ if (!a.events || !Array.isArray(a.events))
531
608
  throw new Error("Invalid payload: missing events array");
532
- const n = i != null && i.extractIp ? i.extractIp(t) : T(t), p = t.headers.get("user-agent"), d = i != null && i.enrichContext ? i.enrichContext(t) : {};
533
- for (const h of l.events)
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)
534
611
  try {
535
- switch (h.type) {
612
+ switch (t.type) {
536
613
  case "track": {
537
- const g = {
538
- ...h.context,
539
- ...d,
614
+ const p = {
615
+ ...t.context,
616
+ ...o,
540
617
  server: {
541
- ...(e = h.context) == null ? void 0 : e.server,
542
- ...typeof (d == null ? void 0 : d.server) == "object" && d.server !== null ? d.server : {},
543
- ...p ? { userAgent: p } : {}
618
+ ...(e = t.context) == null ? void 0 : e.server,
619
+ ...typeof (o == null ? void 0 : o.server) == "object" && o.server !== null ? o.server : {},
620
+ ...l ? { userAgent: l } : {}
544
621
  },
545
622
  device: {
546
- ...(r = h.context) == null ? void 0 : r.device,
547
- ...n ? { ip: n } : {}
623
+ ...(r = t.context) == null ? void 0 : r.device,
624
+ ...h ? { ip: h } : {}
548
625
  }
549
626
  };
550
627
  await u.track(
551
- h.event.action,
628
+ t.event.action,
552
629
  // biome-ignore lint/suspicious/noExplicitAny: Properties from JSON cannot be type-checked against TEventMap at compile time
553
- h.event.properties,
630
+ t.event.properties,
554
631
  {
555
- userId: h.event.userId,
556
- sessionId: h.event.sessionId,
557
- context: g
632
+ userId: t.event.userId,
633
+ sessionId: t.event.sessionId,
634
+ context: p
558
635
  }
559
636
  );
560
637
  break;
561
638
  }
562
639
  case "identify": {
563
- u.identify(h.userId, h.traits);
640
+ await u.identify(t.userId, t.traits);
564
641
  break;
565
642
  }
566
643
  case "pageView": {
567
- const g = {
568
- ...h.context,
569
- ...d,
644
+ const p = {
645
+ ...t.context,
646
+ ...o,
570
647
  server: {
571
- ...(a = h.context) == null ? void 0 : a.server,
572
- ...typeof (d == null ? void 0 : d.server) == "object" && d.server !== null ? d.server : {},
573
- ...p ? { userAgent: p } : {}
648
+ ...(s = t.context) == null ? void 0 : s.server,
649
+ ...typeof (o == null ? void 0 : o.server) == "object" && o.server !== null ? o.server : {},
650
+ ...l ? { userAgent: l } : {}
574
651
  },
575
652
  device: {
576
- ...(s = h.context) == null ? void 0 : s.device,
577
- ...n ? { ip: n } : {}
653
+ ...(n = t.context) == null ? void 0 : n.device,
654
+ ...h ? { ip: h } : {}
578
655
  }
579
656
  };
580
- u.pageView(h.properties, {
581
- context: g
657
+ await u.pageView(t.properties, {
658
+ context: p
582
659
  });
583
660
  break;
584
661
  }
585
662
  case "reset":
586
663
  break;
587
664
  default:
588
- console.warn("[Proxy] Unknown event type:", h);
665
+ console.warn("[Proxy] Unknown event type:", t);
589
666
  }
590
- } catch (g) {
591
- i != null && i.onError ? i.onError(g) : console.error("[Proxy] Failed to process event:", g);
667
+ } catch (p) {
668
+ i != null && i.onError ? i.onError(p) : console.error("[Proxy] Failed to process event:", p);
592
669
  }
593
- } catch (l) {
594
- throw i != null && i.onError ? i.onError(l) : console.error("[Proxy] Failed to ingest events:", l), l;
670
+ } catch (a) {
671
+ throw i != null && i.onError ? i.onError(a) : console.error("[Proxy] Failed to ingest events:", a), a;
595
672
  }
596
673
  }
597
- function T(t) {
674
+ function $(d) {
598
675
  var i;
599
676
  const u = [
600
677
  "x-forwarded-for",
@@ -605,26 +682,26 @@ function T(t) {
605
682
  "x-cluster-client-ip"
606
683
  ];
607
684
  for (const e of u) {
608
- const r = t.headers.get(e);
685
+ const r = d.headers.get(e);
609
686
  if (r)
610
687
  return (i = r.split(",")[0]) == null ? void 0 : i.trim();
611
688
  }
612
689
  }
613
- function J(t, u) {
690
+ function V(d, u) {
614
691
  return async (i) => {
615
692
  try {
616
- return await q(i, t, u), new Response("OK", { status: 200 });
693
+ return await B(i, d, u), new Response("OK", { status: 200 });
617
694
  } catch (e) {
618
695
  return console.error("[Proxy] Handler error:", e), new Response("Internal Server Error", { status: 500 });
619
696
  }
620
697
  };
621
698
  }
622
699
  export {
623
- B as BaseAnalyticsProvider,
624
- H as BentoServerProvider,
625
- G as EmitKitServerProvider,
626
- W as PirschServerProvider,
627
- X as PostHogServerProvider,
628
- J as createProxyHandler,
629
- q as ingestProxyEvents
700
+ y as BaseAnalyticsProvider,
701
+ O as BentoServerProvider,
702
+ N as EmitKitServerProvider,
703
+ j as PirschServerProvider,
704
+ H as PostHogServerProvider,
705
+ V as createProxyHandler,
706
+ B as ingestProxyEvents
630
707
  };