@outlit/browser 1.4.1 → 1.4.5

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,9 +1,11 @@
1
+ // src/react/hooks.ts
2
+ import { useCallback as useCallback2, useContext } from "react";
3
+
1
4
  // src/react/provider.tsx
2
5
  import { createContext, useCallback, useEffect, useRef, useState } from "react";
3
6
 
4
7
  // src/tracker.ts
5
8
  import {
6
- DEFAULT_API_HOST,
7
9
  buildBillingEvent,
8
10
  buildCalendarEvent,
9
11
  buildCustomEvent,
@@ -11,7 +13,9 @@ import {
11
13
  buildIdentifyEvent,
12
14
  buildIngestPayload,
13
15
  buildPageviewEvent,
14
- buildStageEvent
16
+ buildStageEvent,
17
+ DEFAULT_API_HOST,
18
+ validateCustomerIdentity
15
19
  } from "@outlit/core";
16
20
 
17
21
  // src/autocapture.ts
@@ -655,11 +659,23 @@ var Outlit = class {
655
659
  currentUser = null;
656
660
  pendingUser = null;
657
661
  pendingStageEvents = [];
662
+ exitCleanups = [];
658
663
  constructor(options) {
659
664
  this.publicKey = options.publicKey;
660
665
  this.apiHost = options.apiHost ?? DEFAULT_API_HOST;
661
666
  this.flushInterval = options.flushInterval ?? 5e3;
662
667
  this.options = options;
668
+ const isDev = typeof window !== "undefined" && typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
669
+ if (isDev) {
670
+ const key = `__outlit_${options.publicKey}`;
671
+ if (window[key]) {
672
+ console.warn(
673
+ "[Outlit] Multiple instances created with the same key. If using HMR, this is expected. Otherwise, use init() for singleton behavior or call shutdown() on the previous instance."
674
+ );
675
+ }
676
+ ;
677
+ window[key] = true;
678
+ }
663
679
  if (typeof window !== "undefined") {
664
680
  const handleExit = () => {
665
681
  if (this.hasHandledExit) return;
@@ -667,15 +683,21 @@ var Outlit = class {
667
683
  this.sessionTracker?.emitEngagement();
668
684
  this.flush();
669
685
  };
670
- document.addEventListener("visibilitychange", () => {
686
+ const visibilityHandler = () => {
671
687
  if (document.visibilityState === "hidden") {
672
688
  handleExit();
673
689
  } else {
674
690
  this.hasHandledExit = false;
675
691
  }
676
- });
692
+ };
693
+ document.addEventListener("visibilitychange", visibilityHandler);
677
694
  window.addEventListener("pagehide", handleExit);
678
695
  window.addEventListener("beforeunload", handleExit);
696
+ this.exitCleanups = [
697
+ () => document.removeEventListener("visibilitychange", visibilityHandler),
698
+ () => window.removeEventListener("pagehide", handleExit),
699
+ () => window.removeEventListener("beforeunload", handleExit)
700
+ ];
679
701
  }
680
702
  this.isInitialized = true;
681
703
  const consent = getConsentState();
@@ -778,11 +800,19 @@ var Outlit = class {
778
800
  console.warn("[Outlit] Tracking not enabled. Call enableTracking() first.");
779
801
  return;
780
802
  }
803
+ if (!options.email && !options.userId) {
804
+ console.warn("[Outlit] identify requires email or userId");
805
+ return;
806
+ }
781
807
  if (options.email || options.userId) {
782
808
  const hadNoUser = !this.currentUser;
783
809
  this.currentUser = {
784
810
  email: options.email,
785
- userId: options.userId
811
+ userId: options.userId,
812
+ customerId: options.customerId,
813
+ customerDomain: options.customerDomain,
814
+ customerTraits: options.customerTraits,
815
+ traits: options.traits
786
816
  };
787
817
  if (hadNoUser) {
788
818
  this.flushPendingStageEvents();
@@ -793,6 +823,9 @@ var Outlit = class {
793
823
  referrer: document.referrer,
794
824
  email: options.email,
795
825
  userId: options.userId,
826
+ customerId: options.customerId,
827
+ customerDomain: options.customerDomain,
828
+ customerTraits: options.customerTraits,
796
829
  traits: options.traits
797
830
  });
798
831
  this.enqueue(event);
@@ -834,7 +867,14 @@ var Outlit = class {
834
867
  */
835
868
  applyUser(identity) {
836
869
  this.currentUser = identity;
837
- this.identify({ email: identity.email, userId: identity.userId, traits: identity.traits });
870
+ this.identify({
871
+ email: identity.email,
872
+ userId: identity.userId,
873
+ traits: identity.traits,
874
+ customerId: identity.customerId,
875
+ customerDomain: identity.customerDomain,
876
+ customerTraits: identity.customerTraits
877
+ });
838
878
  this.flushPendingStageEvents();
839
879
  }
840
880
  /**
@@ -902,11 +942,23 @@ var Outlit = class {
902
942
  console.warn("[Outlit] Tracking not enabled. Call enableTracking() first.");
903
943
  return;
904
944
  }
945
+ try {
946
+ validateCustomerIdentity(
947
+ options.customerId,
948
+ options.customerDomain,
949
+ options.domain,
950
+ options.stripeCustomerId
951
+ );
952
+ } catch (error) {
953
+ console.warn("[Outlit]", error instanceof Error ? error.message : error);
954
+ return;
955
+ }
905
956
  const event = buildBillingEvent({
906
957
  url: window.location.href,
907
958
  referrer: document.referrer,
908
959
  status,
909
960
  customerId: options.customerId,
961
+ customerDomain: options.customerDomain,
910
962
  stripeCustomerId: options.stripeCustomerId,
911
963
  domain: options.domain,
912
964
  properties: options.properties
@@ -941,6 +993,13 @@ var Outlit = class {
941
993
  stopCalendarTracking();
942
994
  stopSessionTracking();
943
995
  this.sessionTracker = null;
996
+ for (const cleanup of this.exitCleanups) {
997
+ cleanup();
998
+ }
999
+ this.exitCleanups = [];
1000
+ if (typeof window !== "undefined" && typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
1001
+ delete window[`__outlit_${this.publicKey}`];
1002
+ }
944
1003
  await this.flush();
945
1004
  }
946
1005
  // ============================================
@@ -1017,12 +1076,47 @@ var Outlit = class {
1017
1076
  this.flush();
1018
1077
  }, this.flushInterval);
1019
1078
  }
1079
+ getPayloadUserIdentity() {
1080
+ if (!this.currentUser) {
1081
+ return void 0;
1082
+ }
1083
+ const { email, userId } = this.currentUser;
1084
+ if (!email && !userId) {
1085
+ return void 0;
1086
+ }
1087
+ return {
1088
+ ...email && { email },
1089
+ ...userId && { userId }
1090
+ };
1091
+ }
1092
+ getPayloadCustomerIdentity() {
1093
+ if (!this.currentUser) {
1094
+ return void 0;
1095
+ }
1096
+ const { customerId, customerDomain } = this.currentUser;
1097
+ if (!customerId && !customerDomain) {
1098
+ return void 0;
1099
+ }
1100
+ return {
1101
+ ...customerId && { customerId },
1102
+ ...customerDomain && { customerDomain }
1103
+ };
1104
+ }
1020
1105
  async sendEvents(events) {
1021
1106
  if (events.length === 0) return;
1022
1107
  if (!this.visitorId) return;
1023
- const userIdentity = this.currentUser ?? void 0;
1108
+ const userIdentity = this.getPayloadUserIdentity();
1109
+ const customerIdentity = this.getPayloadCustomerIdentity();
1024
1110
  const sessionId = this.sessionTracker?.getSessionId();
1025
- const payload = buildIngestPayload(this.visitorId, "client", events, userIdentity, sessionId);
1111
+ const payload = buildIngestPayload(
1112
+ this.visitorId,
1113
+ "client",
1114
+ events,
1115
+ userIdentity,
1116
+ sessionId,
1117
+ void 0,
1118
+ customerIdentity
1119
+ );
1026
1120
  const url = `${this.apiHost}/api/i/v1/${this.publicKey}/events`;
1027
1121
  try {
1028
1122
  if (typeof navigator !== "undefined" && navigator.sendBeacon) {
@@ -1073,7 +1167,7 @@ function OutlitProvider(props) {
1073
1167
  useEffect(() => {
1074
1168
  if (initializedRef.current) return;
1075
1169
  if (props.client) {
1076
- if (process.env.NODE_ENV !== "production") {
1170
+ if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
1077
1171
  const configKeys = [
1078
1172
  "publicKey",
1079
1173
  "apiHost",
@@ -1171,7 +1265,6 @@ function OutlitProvider(props) {
1171
1265
  }
1172
1266
 
1173
1267
  // src/react/hooks.ts
1174
- import { useCallback as useCallback2, useContext } from "react";
1175
1268
  function useOutlit() {
1176
1269
  const { outlit, isInitialized, isTrackingEnabled, enableTracking, disableTracking } = useContext(OutlitContext);
1177
1270
  const track = useCallback2(