@stacksee/analytics 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  }
@@ -5,6 +5,8 @@ export { BentoClientProvider } from './bento/client.js';
5
5
  export type { BentoClientConfig } from './bento/client.js';
6
6
  export { PirschClientProvider } from './pirsch/client.js';
7
7
  export type { PirschClientConfig } from './pirsch/client.js';
8
+ export { VisitorsClientProvider } from './visitors/client.js';
9
+ export type { VisitorsClientConfig } from './visitors/client.js';
8
10
  export { ProxyProvider } from './proxy/client.js';
9
11
  export type { ProxyProviderConfig } from './proxy/client.js';
10
12
  export type { ProxyBatchConfig, ProxyRetryConfig, ProxyEvent, ProxyPayload, ProxyTrackEvent, ProxyIdentifyEvent, ProxyPageViewEvent, ProxyResetEvent, } from './proxy/types.js';
@@ -1,10 +1,10 @@
1
- var f = Object.defineProperty;
2
- var p = (o, h, e) => h in o ? f(o, h, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[h] = e;
3
- var r = (o, h, e) => p(o, typeof h != "symbol" ? h + "" : h, e);
4
- import { B as u } from "../base.provider-AfFL5W_P.js";
5
- import { i as a } from "../client-DTHZYkxx.js";
6
- import { P as z } from "../client-DTHZYkxx.js";
7
- class w extends u {
1
+ var g = Object.defineProperty;
2
+ var p = (o, l, e) => l in o ? g(o, l, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[l] = e;
3
+ var r = (o, l, e) => p(o, typeof l != "symbol" ? l + "" : l, e);
4
+ import { B as f } from "../base.provider-AfFL5W_P.js";
5
+ import { i as n } from "../client-DTHZYkxx.js";
6
+ import { P as C } from "../client-DTHZYkxx.js";
7
+ class w extends f {
8
8
  constructor(e) {
9
9
  super({ debug: e.debug, enabled: e.enabled });
10
10
  r(this, "name", "Bento-Client");
@@ -16,7 +16,7 @@ class w extends u {
16
16
  }
17
17
  async initialize() {
18
18
  if (this.isEnabled() && !this.initialized) {
19
- if (!a()) {
19
+ if (!n()) {
20
20
  this.log("Skipping initialization - not in browser environment");
21
21
  return;
22
22
  }
@@ -63,7 +63,7 @@ class w extends u {
63
63
  this.log("Identified user", { userId: e, email: s, traits: i });
64
64
  }
65
65
  track(e, i) {
66
- var t, n, l;
66
+ var t, a, h;
67
67
  if (!this.isEnabled() || !this.initialized || !this.bento) return;
68
68
  const s = {
69
69
  ...e.properties,
@@ -86,14 +86,14 @@ class w extends u {
86
86
  ...(i == null ? void 0 : i.utm) && { utm: i.utm },
87
87
  // Include user email and traits as regular event properties
88
88
  ...((t = i == null ? void 0 : i.user) == null ? void 0 : t.email) && { user_email: i.user.email },
89
- ...((n = i == null ? void 0 : i.user) == null ? void 0 : n.traits) && { user_traits: i.user.traits },
90
- ...((l = i == null ? void 0 : i.user) == null ? void 0 : l.userId) && { visitor: i.user.userId }
89
+ ...((a = i == null ? void 0 : i.user) == null ? void 0 : a.traits) && { user_traits: i.user.traits },
90
+ ...((h = i == null ? void 0 : i.user) == null ? void 0 : h.userId) && { visitor: i.user.userId }
91
91
  };
92
92
  this.bento.track(e.action, s), this.log("Tracked event", { event: e, context: i });
93
93
  }
94
94
  pageView(e, i) {
95
95
  var s;
96
- if (!(!this.isEnabled() || !this.initialized || !this.bento || !a())) {
96
+ if (!(!this.isEnabled() || !this.initialized || !this.bento || !n())) {
97
97
  if (this.bento.view(), e || i != null && i.page) {
98
98
  const t = {
99
99
  ...e,
@@ -118,7 +118,7 @@ class w extends u {
118
118
  }
119
119
  pageLeave(e, i) {
120
120
  var t;
121
- if (!this.isEnabled() || !this.initialized || !this.bento || !a())
121
+ if (!this.isEnabled() || !this.initialized || !this.bento || !n())
122
122
  return;
123
123
  const s = {
124
124
  ...e,
@@ -139,7 +139,7 @@ class w extends u {
139
139
  this.bento.track("$pageleave", s), this.log("Tracked page leave", { properties: e, context: i });
140
140
  }
141
141
  reset() {
142
- !this.isEnabled() || !this.initialized || !this.bento || !a() || this.log(
142
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || this.log(
143
143
  "Reset user session - Note: Bento doesn't have a native reset method"
144
144
  );
145
145
  }
@@ -156,7 +156,7 @@ class w extends u {
156
156
  * ```
157
157
  */
158
158
  tag(e) {
159
- !this.isEnabled() || !this.initialized || !this.bento || !a() || (this.bento.tag(e), this.log("Added tag to user", { tag: e }));
159
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || (this.bento.tag(e), this.log("Added tag to user", { tag: e }));
160
160
  }
161
161
  /**
162
162
  * Get the current user's email address
@@ -172,7 +172,7 @@ class w extends u {
172
172
  * ```
173
173
  */
174
174
  getEmail() {
175
- return !this.isEnabled() || !this.initialized || !this.bento || !a() ? null : this.bento.getEmail();
175
+ return !this.isEnabled() || !this.initialized || !this.bento || !n() ? null : this.bento.getEmail();
176
176
  }
177
177
  /**
178
178
  * Get the current user's name
@@ -188,7 +188,7 @@ class w extends u {
188
188
  * ```
189
189
  */
190
190
  getName() {
191
- return !this.isEnabled() || !this.initialized || !this.bento || !a() ? null : this.bento.getName();
191
+ return !this.isEnabled() || !this.initialized || !this.bento || !n() ? null : this.bento.getName();
192
192
  }
193
193
  // ============================================================================
194
194
  // Survey Methods
@@ -209,7 +209,7 @@ class w extends u {
209
209
  * ```
210
210
  */
211
211
  showSurveyForm(e, i, s = "popup") {
212
- !this.isEnabled() || !this.initialized || !this.bento || !a() || (this.bento.showSurveyForm(e, i, s), this.log("Showed survey form", { surveyId: i, type: s }));
212
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || (this.bento.showSurveyForm(e, i, s), this.log("Showed survey form", { surveyId: i, type: s }));
213
213
  }
214
214
  /**
215
215
  * Validate an email address using Bento's spam check
@@ -226,7 +226,7 @@ class w extends u {
226
226
  * ```
227
227
  */
228
228
  async spamCheck(e) {
229
- if (!this.isEnabled() || !this.initialized || !this.bento || !a())
229
+ if (!this.isEnabled() || !this.initialized || !this.bento || !n())
230
230
  return !1;
231
231
  try {
232
232
  const i = await this.bento.spamCheck(e);
@@ -247,7 +247,7 @@ class w extends u {
247
247
  * ```
248
248
  */
249
249
  showChat() {
250
- !this.isEnabled() || !this.initialized || !this.bento || !a() || (this.bento.showChat ? (this.bento.showChat(), this.log("Showed chat widget")) : console.warn(
250
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || (this.bento.showChat ? (this.bento.showChat(), this.log("Showed chat widget")) : console.warn(
251
251
  "[Bento-Client] Chat not available. Make sure chat is enabled in your Bento settings."
252
252
  ));
253
253
  }
@@ -260,7 +260,7 @@ class w extends u {
260
260
  * ```
261
261
  */
262
262
  hideChat() {
263
- !this.isEnabled() || !this.initialized || !this.bento || !a() || (this.bento.hideChat ? (this.bento.hideChat(), this.log("Hid chat widget")) : console.warn(
263
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || (this.bento.hideChat ? (this.bento.hideChat(), this.log("Hid chat widget")) : console.warn(
264
264
  "[Bento-Client] Chat not available. Make sure chat is enabled in your Bento settings."
265
265
  ));
266
266
  }
@@ -273,12 +273,12 @@ class w extends u {
273
273
  * ```
274
274
  */
275
275
  openChat() {
276
- !this.isEnabled() || !this.initialized || !this.bento || !a() || (this.bento.openChat ? (this.bento.openChat(), this.log("Opened chat widget")) : console.warn(
276
+ !this.isEnabled() || !this.initialized || !this.bento || !n() || (this.bento.openChat ? (this.bento.openChat(), this.log("Opened chat widget")) : console.warn(
277
277
  "[Bento-Client] Chat not available. Make sure chat is enabled in your Bento settings."
278
278
  ));
279
279
  }
280
280
  }
281
- class m extends u {
281
+ class m extends f {
282
282
  constructor(e) {
283
283
  super({ debug: e.debug, enabled: e.enabled });
284
284
  r(this, "name", "Pirsch-Client");
@@ -289,7 +289,7 @@ class m extends u {
289
289
  }
290
290
  async initialize() {
291
291
  if (this.isEnabled() && !this.initialized) {
292
- if (!a()) {
292
+ if (!n()) {
293
293
  this.log("Skipping initialization - not in browser environment");
294
294
  return;
295
295
  }
@@ -319,7 +319,7 @@ class m extends u {
319
319
  }), this.log("Identified user via event", { userId: e, traits: i }));
320
320
  }
321
321
  async track(e, i) {
322
- var t, n;
322
+ var t, a;
323
323
  if (!this.isEnabled() || !this.initialized || !this.client) return;
324
324
  const s = {
325
325
  ...e.properties,
@@ -334,33 +334,33 @@ class m extends u {
334
334
  ...(i == null ? void 0 : i.device) && { device: i.device },
335
335
  ...(i == null ? void 0 : i.utm) && { utm: i.utm },
336
336
  ...((t = i == null ? void 0 : i.user) == null ? void 0 : t.email) && { user_email: i.user.email },
337
- ...((n = i == null ? void 0 : i.user) == null ? void 0 : n.traits) && { user_traits: i.user.traits }
337
+ ...((a = i == null ? void 0 : i.user) == null ? void 0 : a.traits) && { user_traits: i.user.traits }
338
338
  };
339
339
  try {
340
340
  await this.client.event(e.action, 0, s), this.log("Tracked event", { event: e, context: i });
341
- } catch (l) {
342
- console.error("[Pirsch-Client] Failed to track event:", l);
341
+ } catch (h) {
342
+ console.error("[Pirsch-Client] Failed to track event:", h);
343
343
  }
344
344
  }
345
345
  pageView(e, i) {
346
- var l, g;
347
- if (!this.isEnabled() || !this.initialized || !this.client || !a())
346
+ var h, d;
347
+ if (!this.isEnabled() || !this.initialized || !this.client || !n())
348
348
  return;
349
349
  const s = e && Object.keys(e).length > 0 ? Object.fromEntries(
350
350
  Object.entries(e).filter(
351
- ([, d]) => typeof d == "string" || typeof d == "number" || typeof d == "boolean"
351
+ ([, u]) => typeof u == "string" || typeof u == "number" || typeof u == "boolean"
352
352
  )
353
353
  ) : void 0, t = {
354
- ...((l = i == null ? void 0 : i.page) == null ? void 0 : l.url) && { url: i.page.url },
355
- ...((g = i == null ? void 0 : i.page) == null ? void 0 : g.title) && { title: i.page.title },
354
+ ...((h = i == null ? void 0 : i.page) == null ? void 0 : h.url) && { url: i.page.url },
355
+ ...((d = i == null ? void 0 : i.page) == null ? void 0 : d.title) && { title: i.page.title },
356
356
  ...s && { tags: s }
357
- }, n = Object.keys(t).length > 0 ? t : void 0;
358
- this.client.hit(n).catch((d) => {
359
- console.error("[Pirsch-Client] Failed to track page view:", d);
357
+ }, a = Object.keys(t).length > 0 ? t : void 0;
358
+ this.client.hit(a).catch((u) => {
359
+ console.error("[Pirsch-Client] Failed to track page view:", u);
360
360
  }), this.log("Tracked page view", { properties: e, context: i });
361
361
  }
362
362
  pageLeave(e, i) {
363
- if (!this.isEnabled() || !this.initialized || !this.client || !a())
363
+ if (!this.isEnabled() || !this.initialized || !this.client || !n())
364
364
  return;
365
365
  const s = {
366
366
  ...e,
@@ -374,14 +374,127 @@ class m extends u {
374
374
  }), this.log("Tracked page leave", { properties: e, context: i });
375
375
  }
376
376
  reset() {
377
- !this.isEnabled() || !this.initialized || !this.client || !a() || (this.client.event("session_reset", 0, {}).catch((e) => {
377
+ !this.isEnabled() || !this.initialized || !this.client || !n() || (this.client.event("session_reset", 0, {}).catch((e) => {
378
378
  console.error("[Pirsch-Client] Failed to track session reset:", e);
379
379
  }), this.log("Reset user session"));
380
380
  }
381
381
  }
382
- class v extends u {
382
+ class v extends f {
383
383
  constructor(e) {
384
- var i, s, t, n, l;
384
+ super({ debug: e.debug, enabled: e.enabled });
385
+ r(this, "name", "Visitors-Client");
386
+ r(this, "visitors");
387
+ r(this, "initialized", !1);
388
+ r(this, "config");
389
+ r(this, "scriptLoaded", !1);
390
+ this.config = e;
391
+ }
392
+ async initialize() {
393
+ if (this.isEnabled() && !this.initialized) {
394
+ if (!n()) {
395
+ this.log("Skipping initialization - not in browser environment");
396
+ return;
397
+ }
398
+ if (!this.config.token || typeof this.config.token != "string")
399
+ throw new Error("Visitors requires a token");
400
+ try {
401
+ this.scriptLoaded || await this.loadScript(), await this.waitForVisitors(), this.visitors = window.visitors, this.initialized = !0, this.log("Initialized successfully", this.config);
402
+ } catch (e) {
403
+ throw console.error("[Visitors-Client] Failed to initialize:", e), e;
404
+ }
405
+ }
406
+ }
407
+ async loadScript() {
408
+ return new Promise((e, i) => {
409
+ if (document.querySelector(
410
+ 'script[src*="cdn.visitors.now"]'
411
+ )) {
412
+ this.scriptLoaded = !0, e();
413
+ return;
414
+ }
415
+ const t = document.createElement("script");
416
+ t.src = "https://cdn.visitors.now/v.js", t.setAttribute("data-token", this.config.token), t.async = !0, t.defer = !0, t.onload = () => {
417
+ this.scriptLoaded = !0, e();
418
+ }, t.onerror = () => {
419
+ i(new Error("Failed to load Visitors script"));
420
+ }, document.head.appendChild(t);
421
+ });
422
+ }
423
+ async waitForVisitors(e = 50, i = 100) {
424
+ for (let s = 0; s < e; s++) {
425
+ if (window.visitors)
426
+ return;
427
+ await new Promise((t) => setTimeout(t, i));
428
+ }
429
+ throw new Error("Visitors SDK not available after loading script");
430
+ }
431
+ identify(e, i) {
432
+ if (!this.isEnabled() || !this.initialized || !this.visitors) return;
433
+ const s = { id: e };
434
+ if (i)
435
+ for (const [t, a] of Object.entries(i))
436
+ (typeof a == "string" || typeof a == "number") && (s[t] = a);
437
+ this.visitors.identify(s), this.log("Identified user", { userId: e, traits: i });
438
+ }
439
+ track(e, i) {
440
+ var t, a;
441
+ if (!this.isEnabled() || !this.initialized || !this.visitors) return;
442
+ const s = {};
443
+ if (e.properties)
444
+ for (const [h, d] of Object.entries(e.properties))
445
+ (typeof d == "string" || typeof d == "number") && (s[h] = d);
446
+ e.category && (s.category = e.category), (t = i == null ? void 0 : i.page) != null && t.path && (s.page_path = i.page.path), (a = i == null ? void 0 : i.page) != null && a.title && (s.page_title = i.page.title), this.visitors.track(e.action, s), this.log("Tracked event", { event: e, context: i });
447
+ }
448
+ pageView(e, i) {
449
+ this.log("Page view - handled automatically by Visitors script", {
450
+ properties: e,
451
+ context: i
452
+ });
453
+ }
454
+ pageLeave(e, i) {
455
+ var t;
456
+ if (!this.isEnabled() || !this.initialized || !this.visitors || !n())
457
+ return;
458
+ const s = {};
459
+ if ((t = i == null ? void 0 : i.page) != null && t.path && (s.page_path = i.page.path), e)
460
+ for (const [a, h] of Object.entries(e))
461
+ (typeof h == "string" || typeof h == "number") && (s[a] = h);
462
+ this.visitors.track("page_leave", s), this.log("Tracked page leave", { properties: e, context: i });
463
+ }
464
+ reset() {
465
+ !this.isEnabled() || !this.initialized || !this.visitors || !n() || this.log("Reset user session - Note: Visitors does not have a native reset method");
466
+ }
467
+ // ============================================================================
468
+ // Stripe Revenue Attribution
469
+ // ============================================================================
470
+ /**
471
+ * Returns the current visitor ID from the `visitor` cookie set by the
472
+ * visitors.now script. Pass this value in your Stripe checkout session
473
+ * metadata so revenue is attributed to the correct visitor.
474
+ *
475
+ * Requires persist mode to be enabled in your visitors.now project settings.
476
+ *
477
+ * @example Server-side Stripe checkout creation:
478
+ * ```typescript
479
+ * // Client-side: get visitor ID and send to your server
480
+ * const visitorId = visitorsProvider.getVisitorId();
481
+ *
482
+ * // Server-side: include in Stripe checkout session
483
+ * const session = await stripe.checkout.sessions.create({
484
+ * // ...
485
+ * metadata: { visitor: visitorId },
486
+ * });
487
+ * ```
488
+ */
489
+ getVisitorId() {
490
+ if (!n()) return null;
491
+ const e = document.cookie.split("; ").find((i) => i.startsWith("visitor="));
492
+ return e ? decodeURIComponent(e.split("=")[1]) : null;
493
+ }
494
+ }
495
+ class k extends f {
496
+ constructor(e) {
497
+ var i, s, t, a, h;
385
498
  super({ debug: e.debug, enabled: e.enabled });
386
499
  r(this, "name", "Proxy");
387
500
  r(this, "config");
@@ -392,7 +505,7 @@ class v extends u {
392
505
  r(this, "retryAttempts");
393
506
  r(this, "retryBackoff");
394
507
  r(this, "retryInitialDelay");
395
- this.config = e, this.batchSize = ((i = e.batch) == null ? void 0 : i.size) ?? 10, this.batchInterval = ((s = e.batch) == null ? void 0 : s.interval) ?? 2e3, this.retryAttempts = ((t = e.retry) == null ? void 0 : t.attempts) ?? 3, this.retryBackoff = ((n = e.retry) == null ? void 0 : n.backoff) ?? "exponential", this.retryInitialDelay = ((l = e.retry) == null ? void 0 : l.initialDelay) ?? 1e3, typeof window < "u" && (window.addEventListener("beforeunload", () => {
508
+ this.config = e, this.batchSize = ((i = e.batch) == null ? void 0 : i.size) ?? 10, this.batchInterval = ((s = e.batch) == null ? void 0 : s.interval) ?? 2e3, this.retryAttempts = ((t = e.retry) == null ? void 0 : t.attempts) ?? 3, this.retryBackoff = ((a = e.retry) == null ? void 0 : a.backoff) ?? "exponential", this.retryInitialDelay = ((h = e.retry) == null ? void 0 : h.initialDelay) ?? 1e3, typeof window < "u" && (window.addEventListener("beforeunload", () => {
396
509
  this.flush(!0);
397
510
  }), document.addEventListener("visibilitychange", () => {
398
511
  document.visibilityState === "hidden" && this.flush(!0);
@@ -480,7 +593,7 @@ class v extends u {
480
593
  } catch (s) {
481
594
  if (i < this.retryAttempts) {
482
595
  const t = this.calculateRetryDelay(i);
483
- return this.log(`Retry attempt ${i + 1} after ${t}ms`, { error: s }), await new Promise((n) => setTimeout(n, t)), this.sendWithRetry(e, i + 1);
596
+ return this.log(`Retry attempt ${i + 1} after ${t}ms`, { error: s }), await new Promise((a) => setTimeout(a, t)), this.sendWithRetry(e, i + 1);
484
597
  }
485
598
  throw console.error("[Proxy] Failed to send events after retries:", s), s;
486
599
  }
@@ -519,9 +632,10 @@ class v extends u {
519
632
  }
520
633
  }
521
634
  export {
522
- u as BaseAnalyticsProvider,
635
+ f as BaseAnalyticsProvider,
523
636
  w as BentoClientProvider,
524
637
  m as PirschClientProvider,
525
- z as PostHogClientProvider,
526
- v as ProxyProvider
638
+ C as PostHogClientProvider,
639
+ k as ProxyProvider,
640
+ v as VisitorsClientProvider
527
641
  };
@@ -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
  }
@@ -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: a, ...t } = this.config;
27
- this.client = new r(t), 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 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, this.client.V1.addSubscriber({
51
- email: r,
52
- fields: s
53
- }).catch((a) => {
54
- console.error("[Bento-Server] Failed to identify user:", a);
55
- }), this.log("Identified user", { userId: i, email: r, traits: 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 t, h, l, n;
58
+ var a, h, l, o;
59
59
  if (!this.isEnabled() || !this.initialized || !this.client) return;
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;
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
- }, a = ((n = e == null ? void 0 : e.user) == null ? void 0 : n.traits) || {};
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: a
93
+ fields: n
94
94
  }), this.log("Tracked event", { event: i, context: e });
95
- } catch (o) {
96
- console.error("[Bento-Server] Failed to track event:", o);
95
+ } catch (t) {
96
+ console.error("[Bento-Server] Failed to track event:", t);
97
97
  }
98
98
  }
99
- pageView(i, e) {
100
- var t, h, l;
99
+ async pageView(i, e) {
100
+ var a, h, l;
101
101
  if (!this.isEnabled() || !this.initialized || !this.client) return;
102
- const r = ((t = e == null ? void 0 : e.user) == null ? void 0 : t.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."
@@ -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
- }, a = ((l = e == null ? void 0 : e.user) == null ? void 0 : l.traits) || {};
126
- this.client.V1.track({
127
- email: r,
128
- type: "$view",
129
- details: s,
130
- fields: a
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(), a = r ?? this.config.timeout ?? K, t = setTimeout(() => s.abort(), a);
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(t);
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 a = await this.fetchWithTimeout(
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 (a.status === 401 && r && !this.isAccessKey)
228
+ if (n.status === 401 && r && !this.isAccessKey)
232
229
  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}`);
230
+ if (!n.ok) {
231
+ const a = await n.text();
232
+ throw new Error(`Pirsch API error: ${n.status} ${a}`);
236
233
  }
237
- } catch (a) {
238
- throw a instanceof Error && a.name === "AbortError" ? new Error(
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
- ) : a;
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 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);
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: ((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}`),
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
- }), a = {
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
- 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 });
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, n, o;
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
- ...((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 = {
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
- ...a && { non_interactive: !0 }
340
+ ...n && { non_interactive: !0 }
342
341
  };
343
342
  try {
344
- await this.request("/api/v1/event", t), this.log("Tracked event", { event: i.action });
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)), 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 });
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), this.client.identify({
422
- user_id: i,
423
- properties: e || {},
424
- aliases: s.length > 0 ? s : void 0
425
- }).then((a) => {
426
- var t, h, l, n, o;
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: 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(
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
- a.data.aliases.failed
439
+ t.data.aliases.failed
436
440
  );
437
- }).catch((a) => {
438
- console.error("[EmitKit-Server] Failed to identify user:", a);
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 o, p;
446
+ var t, p;
443
447
  if (!this.isEnabled() || !this.initialized || !this.client) return;
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,
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), 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);
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: n,
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: n
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 n, o, p;
493
+ async pageView(i, e) {
494
+ var o, t, p, g;
491
495
  if (!this.isEnabled() || !this.initialized || !this.client) return;
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,
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
- this.client.events.create({
515
- channelName: l,
516
- title: "Page View",
517
- description: ((p = e == null ? void 0 : e.page) == null ? void 0 : p.path) || "User viewed a page",
518
- icon: "👁️",
519
- tags: ["page_view", "navigation"],
520
- metadata: t,
521
- userId: r || null,
522
- notify: !1,
523
- // Don't notify for page views by default
524
- displayAs: "message",
525
- source: "stacksee-analytics"
526
- }).then((g) => {
527
- var f;
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: g.data.id,
530
- path: (f = e == null ? void 0 : e.page) == null ? void 0 : f.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
- }).catch((g) => {
535
- console.error("[EmitKit-Server] Failed to track page view:", g);
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, a;
604
+ var e, r, s, n;
601
605
  try {
602
- const t = await d.json();
603
- if (!t.events || !Array.isArray(t.events))
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"), n = i != null && i.enrichContext ? i.enrichContext(d) : {};
606
- for (const o of t.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)
607
611
  try {
608
- switch (o.type) {
612
+ switch (t.type) {
609
613
  case "track": {
610
614
  const p = {
611
- ...o.context,
612
- ...n,
615
+ ...t.context,
616
+ ...o,
613
617
  server: {
614
- ...(e = o.context) == null ? void 0 : e.server,
615
- ...typeof (n == null ? void 0 : n.server) == "object" && n.server !== null ? n.server : {},
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 = o.context) == null ? void 0 : r.device,
623
+ ...(r = t.context) == null ? void 0 : r.device,
620
624
  ...h ? { ip: h } : {}
621
625
  }
622
626
  };
623
627
  await u.track(
624
- o.event.action,
628
+ t.event.action,
625
629
  // biome-ignore lint/suspicious/noExplicitAny: Properties from JSON cannot be type-checked against TEventMap at compile time
626
- o.event.properties,
630
+ t.event.properties,
627
631
  {
628
- userId: o.event.userId,
629
- sessionId: o.event.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(o.userId, o.traits);
640
+ await u.identify(t.userId, t.traits);
637
641
  break;
638
642
  }
639
643
  case "pageView": {
640
644
  const p = {
641
- ...o.context,
642
- ...n,
645
+ ...t.context,
646
+ ...o,
643
647
  server: {
644
- ...(s = o.context) == null ? void 0 : s.server,
645
- ...typeof (n == null ? void 0 : n.server) == "object" && n.server !== null ? n.server : {},
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
- ...(a = o.context) == null ? void 0 : a.device,
653
+ ...(n = t.context) == null ? void 0 : n.device,
650
654
  ...h ? { ip: h } : {}
651
655
  }
652
656
  };
653
- u.pageView(o.properties, {
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:", o);
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 (t) {
667
- throw i != null && i.onError ? i.onError(t) : console.error("[Proxy] Failed to ingest events:", t), t;
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) {
@@ -0,0 +1,67 @@
1
+ import { BaseEvent, EventContext } from '../../core/events/types.js';
2
+ import { BaseAnalyticsProvider } from '../base.provider.js';
3
+ interface VisitorsClient {
4
+ track(event: string, properties?: Record<string, string | number>): void;
5
+ identify(traits: {
6
+ id: string;
7
+ email?: string;
8
+ name?: string;
9
+ [key: string]: string | number | undefined;
10
+ }): void;
11
+ }
12
+ export interface VisitorsClientConfig {
13
+ /**
14
+ * Your Visitors project token from the dashboard
15
+ */
16
+ token: string;
17
+ /**
18
+ * Enable debug logging
19
+ */
20
+ debug?: boolean;
21
+ /**
22
+ * Enable/disable the provider
23
+ */
24
+ enabled?: boolean;
25
+ }
26
+ declare global {
27
+ interface Window {
28
+ visitors?: VisitorsClient;
29
+ }
30
+ }
31
+ export declare class VisitorsClientProvider extends BaseAnalyticsProvider {
32
+ name: string;
33
+ private visitors?;
34
+ private initialized;
35
+ private config;
36
+ private scriptLoaded;
37
+ constructor(config: VisitorsClientConfig);
38
+ initialize(): Promise<void>;
39
+ private loadScript;
40
+ private waitForVisitors;
41
+ identify(userId: string, traits?: Record<string, unknown>): void;
42
+ track(event: BaseEvent, context?: EventContext): void;
43
+ pageView(properties?: Record<string, unknown>, context?: EventContext): void;
44
+ pageLeave(properties?: Record<string, unknown>, context?: EventContext): void;
45
+ reset(): void;
46
+ /**
47
+ * Returns the current visitor ID from the `visitor` cookie set by the
48
+ * visitors.now script. Pass this value in your Stripe checkout session
49
+ * metadata so revenue is attributed to the correct visitor.
50
+ *
51
+ * Requires persist mode to be enabled in your visitors.now project settings.
52
+ *
53
+ * @example Server-side Stripe checkout creation:
54
+ * ```typescript
55
+ * // Client-side: get visitor ID and send to your server
56
+ * const visitorId = visitorsProvider.getVisitorId();
57
+ *
58
+ * // Server-side: include in Stripe checkout session
59
+ * const session = await stripe.checkout.sessions.create({
60
+ * // ...
61
+ * metadata: { visitor: visitorId },
62
+ * });
63
+ * ```
64
+ */
65
+ getVisitorId(): string | null;
66
+ }
67
+ export {};
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  var u = Object.defineProperty;
2
- var h = (i, e, t) => e in i ? u(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
3
- var c = (i, e, t) => h(i, typeof e != "symbol" ? e + "" : e, t);
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 a;
72
- r.methods ? a = new Set(r.methods) : r.exclude ? a = new Set(
71
+ let i;
72
+ r.methods ? i = new Set(r.methods) : r.exclude ? i = new Set(
73
73
  t.filter(
74
- (l) => {
74
+ (o) => {
75
75
  var v;
76
- return !((v = r.exclude) != null && v.includes(l));
76
+ return !((v = r.exclude) != null && v.includes(o));
77
77
  }
78
78
  )
79
- ) : a = new Set(t);
80
- let o, d, s;
81
- return r.events && r.events.length > 0 ? o = new Set(r.events) : r.eventPatterns && r.eventPatterns.length > 0 ? s = r.eventPatterns.map((l) => {
82
- const v = l.replace(/\*/g, ".*");
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 && (d = new Set(r.excludeEvents)), {
84
+ }) : r.excludeEvents && r.excludeEvents.length > 0 && (l = new Set(r.excludeEvents)), {
85
85
  provider: r.provider,
86
- enabledMethods: a,
87
- enabledEvents: o,
88
- excludedEvents: d,
89
- eventPatterns: s
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
- for (const n of this.providerConfigs)
196
- this.shouldCallMethod(n, "identify") && n.provider.identify(e, t);
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 d;
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
- }, a = {
334
+ }, i = {
333
335
  ...this.config.defaultContext,
334
336
  ...n == null ? void 0 : n.context,
335
- user: (n == null ? void 0 : n.user) || ((d = n == null ? void 0 : n.context) == null ? void 0 : d.user)
336
- }, o = this.providerConfigs.filter(
337
- (s) => this.shouldCallMethod(s, "track") && this.shouldTrackEvent(s, e)
338
- ).map(async (s) => {
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 s.provider.track(r, a);
341
- } catch (l) {
342
+ await d.provider.track(r, i);
343
+ } catch (o) {
342
344
  console.error(
343
- `[Analytics] Provider ${s.provider.name} failed to track event:`,
344
- l
345
+ `[Analytics] Provider ${d.provider.name} failed to track event:`,
346
+ o
345
347
  );
346
348
  }
347
349
  });
348
- await Promise.all(o);
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 r of this.providerConfigs)
417
- this.shouldCallMethod(r, "pageView") && r.provider.pageView(e, n);
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 x(i) {
583
+ function m(a) {
581
584
  const e = {
582
- providers: i.providers || [],
583
- debug: i.debug,
584
- enabled: i.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
- x as createServerAnalytics
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.1",
3
+ "version": "0.14.0",
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,16 @@
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",
82
+ "test:e2e:visitors": "node e2e/visitors.test.js",
83
+ "test:e2e:visitors:server": "node e2e/visitors-test-app/server.js",
79
84
  "build": "vite build",
80
85
  "dev": "pnpm --filter @stacksee/docs dev",
81
86
  "build:docs": "pnpm --filter @stacksee/docs build",
82
87
  "deploy": "npm publish",
83
88
  "typecheck": "tsc --noEmit",
84
- "ci:publish": "pnpm build && changeset publish",
89
+ "ci:publish": "pnpm build && changeset publish --provenance",
85
90
  "lint": "biome lint .",
86
91
  "format": "biome format --write .",
87
92
  "biome": "biome"