@stacksee/analytics 0.12.0 → 0.13.1

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