@tell-rs/browser 0.2.5 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,7 @@ bun add @tell-rs/browser
23
23
  ```ts
24
24
  import tell from "@tell-rs/browser";
25
25
 
26
- tell.configure("your-api-key");
26
+ tell.configure("feed1e11feed1e11feed1e11feed1e11");
27
27
 
28
28
  // Track an event
29
29
  tell.track("Button Clicked", { button: "signup" });
@@ -44,8 +44,9 @@ Events called before `configure()` are automatically queued and replayed.
44
44
  Initialize the SDK. Call once on page load.
45
45
 
46
46
  ```ts
47
- tell.configure("your-api-key", {
47
+ tell.configure("feed1e11feed1e11feed1e11feed1e11", {
48
48
  // All options below are optional:
49
+ service: "landing-page", // stamped on every event and log (defaults to window.location.hostname)
49
50
  endpoint: "https://collect.tell.app", // default
50
51
  batchSize: 20, // events per batch
51
52
  flushInterval: 5_000, // ms between auto-flushes
@@ -122,8 +123,8 @@ await tell.close() // flush + shut down
122
123
  ```ts
123
124
  import tell, { development, production } from "@tell-rs/browser";
124
125
 
125
- tell.configure("your-api-key", development()); // localhost, debug logging
126
- tell.configure("your-api-key", production()); // defaults, error-only logging
126
+ tell.configure("feed1e11feed1e11feed1e11feed1e11", development()); // localhost, debug logging
127
+ tell.configure("feed1e11feed1e11feed1e11feed1e11", production()); // defaults, error-only logging
127
128
  ```
128
129
 
129
130
  ## Features
@@ -144,7 +145,7 @@ The browser SDK automatically collects anonymous device context (browser, OS, sc
144
145
  ```ts
145
146
  import tell, { redact, redactLog, SENSITIVE_PARAMS } from "@tell-rs/browser";
146
147
 
147
- tell.configure("your-api-key", {
148
+ tell.configure("feed1e11feed1e11feed1e11feed1e11", {
148
149
  beforeSend: redact({
149
150
  dropRoutes: ["/internal", "/health"],
150
151
  stripParams: [...SENSITIVE_PARAMS, "session_id"],
package/dist/index.cjs CHANGED
@@ -435,18 +435,13 @@ function generateId() {
435
435
  if (typeof crypto !== "undefined" && crypto.getRandomValues) {
436
436
  const bytes = new Uint8Array(16);
437
437
  crypto.getRandomValues(bytes);
438
- bytes[6] = bytes[6] & 15 | 64;
439
- bytes[8] = bytes[8] & 63 | 128;
440
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join(
441
- ""
442
- );
443
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
438
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
439
+ }
440
+ let hex = "";
441
+ for (let i = 0; i < 32; i++) {
442
+ hex += (Math.random() * 16 | 0).toString(16);
444
443
  }
445
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
446
- const r = Math.random() * 16 | 0;
447
- const v = c === "x" ? r : r & 3 | 8;
448
- return v.toString(16);
449
- });
444
+ return hex;
450
445
  }
451
446
 
452
447
  // src/bot.ts
@@ -479,13 +474,19 @@ function captureContext() {
479
474
  }
480
475
  ctx.device_type = inferDeviceType(parsed.os, ua, ctx.touch);
481
476
  const conn = navigator.connection;
482
- if (conn?.effectiveType) {
483
- ctx.connection_type = conn.effectiveType;
477
+ if (conn) {
478
+ if (conn.effectiveType) ctx.connection_type = conn.effectiveType;
479
+ if (typeof conn.downlink === "number") ctx.downlink = conn.downlink;
480
+ if (typeof conn.rtt === "number") ctx.rtt = conn.rtt;
481
+ if (conn.saveData) ctx.save_data = true;
484
482
  }
483
+ if (navigator.webdriver) ctx.bot = true;
485
484
  }
486
485
  if (typeof screen !== "undefined") {
487
486
  ctx.screen_width = screen.width;
488
487
  ctx.screen_height = screen.height;
488
+ const orient = screen.orientation;
489
+ if (orient?.type) ctx.screen_orientation = orient.type;
489
490
  }
490
491
  if (typeof window !== "undefined") {
491
492
  ctx.viewport_width = window.innerWidth;
@@ -506,11 +507,18 @@ function captureContext() {
506
507
  }
507
508
  if (typeof location !== "undefined") {
508
509
  ctx.url = location.href;
510
+ if (location.pathname) ctx.path = location.pathname;
509
511
  }
510
512
  try {
511
513
  ctx.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
512
514
  } catch {
513
515
  }
516
+ if (typeof window !== "undefined" && window.matchMedia) {
517
+ try {
518
+ ctx.dark_mode = window.matchMedia("(prefers-color-scheme: dark)").matches;
519
+ } catch {
520
+ }
521
+ }
514
522
  return ctx;
515
523
  }
516
524
  function inferDeviceType(os, ua, touch) {
@@ -584,7 +592,6 @@ var SessionManager = class {
584
592
  timeout;
585
593
  onNewSession;
586
594
  visibilityHandler;
587
- checkTimer;
588
595
  lastContextAt = {};
589
596
  constructor(config) {
590
597
  this.timeout = config.timeout;
@@ -596,10 +603,6 @@ var SessionManager = class {
596
603
  if (typeof document !== "undefined") {
597
604
  document.addEventListener("visibilitychange", this.visibilityHandler);
598
605
  }
599
- this.checkTimer = setInterval(() => this.checkTimeout(), 6e4);
600
- if (typeof this.checkTimer.unref === "function") {
601
- this.checkTimer.unref();
602
- }
603
606
  }
604
607
  get sessionId() {
605
608
  return this._sessionId;
@@ -607,14 +610,18 @@ var SessionManager = class {
607
610
  set sessionId(id) {
608
611
  this._sessionId = id;
609
612
  }
613
+ /** Update activity timestamp; rotates session if idle longer than timeout. */
610
614
  touch() {
611
- this.lastActivityAt = Date.now();
615
+ const now = Date.now();
616
+ if (now - this.lastActivityAt > this.timeout) {
617
+ this.rotateSession("session_timeout");
618
+ }
619
+ this.lastActivityAt = now;
612
620
  }
613
621
  destroy() {
614
622
  if (typeof document !== "undefined") {
615
623
  document.removeEventListener("visibilitychange", this.visibilityHandler);
616
624
  }
617
- clearInterval(this.checkTimer);
618
625
  }
619
626
  handleVisibility() {
620
627
  if (document.visibilityState === "hidden") {
@@ -628,11 +635,6 @@ var SessionManager = class {
628
635
  this.lastHiddenAt = 0;
629
636
  }
630
637
  }
631
- checkTimeout() {
632
- if (Date.now() - this.lastActivityAt > this.timeout) {
633
- this.rotateSession("session_timeout");
634
- }
635
- }
636
638
  rotateSession(reason) {
637
639
  this._sessionId = generateId();
638
640
  this.lastActivityAt = Date.now();
@@ -836,6 +838,7 @@ var logBatcher;
836
838
  var sessionManager;
837
839
  var resolvedConfig;
838
840
  var _apiKey;
841
+ var resolvedService;
839
842
  var deviceId;
840
843
  var userId;
841
844
  var superProperties = {};
@@ -878,6 +881,7 @@ function onNewSession(reason, sessionId) {
878
881
  const ctx = captureContext();
879
882
  const event = {
880
883
  type: "context",
884
+ service: resolvedService,
881
885
  device_id: deviceId,
882
886
  session_id: sessionId,
883
887
  user_id: userId,
@@ -912,6 +916,7 @@ var tell = {
912
916
  validateApiKey(apiKey);
913
917
  _apiKey = apiKey;
914
918
  resolvedConfig = resolveConfig(options);
919
+ resolvedService = options?.service ?? (typeof window !== "undefined" ? window.location?.hostname : void 0) ?? "browser";
915
920
  sdkLogLevel = LOG_LEVELS[resolvedConfig.logLevel] ?? 0;
916
921
  beforeSend = resolvedConfig.beforeSend;
917
922
  beforeSendLog = resolvedConfig.beforeSendLog;
@@ -1021,9 +1026,11 @@ var tell = {
1021
1026
  reportError(err);
1022
1027
  return;
1023
1028
  }
1029
+ sessionManager.touch();
1024
1030
  let event = {
1025
1031
  type: "track",
1026
1032
  event: eventName,
1033
+ service: resolvedService,
1027
1034
  device_id: deviceId,
1028
1035
  session_id: sessionManager.sessionId,
1029
1036
  user_id: userId,
@@ -1035,7 +1042,6 @@ var tell = {
1035
1042
  event = runBeforeSend(event, beforeSend);
1036
1043
  if (event === null) return;
1037
1044
  }
1038
- sessionManager.touch();
1039
1045
  eventBatcher.add(event);
1040
1046
  },
1041
1047
  identify(newUserId, traits) {
@@ -1056,8 +1062,10 @@ var tell = {
1056
1062
  }
1057
1063
  userId = newUserId;
1058
1064
  storage.set(STORAGE_KEYS.USER_ID, userId);
1065
+ sessionManager.touch();
1059
1066
  let event = {
1060
1067
  type: "identify",
1068
+ service: resolvedService,
1061
1069
  device_id: deviceId,
1062
1070
  session_id: sessionManager.sessionId,
1063
1071
  user_id: userId,
@@ -1068,7 +1076,6 @@ var tell = {
1068
1076
  event = runBeforeSend(event, beforeSend);
1069
1077
  if (event === null) return;
1070
1078
  }
1071
- sessionManager.touch();
1072
1079
  eventBatcher.add(event);
1073
1080
  },
1074
1081
  group(groupId, properties) {
@@ -1087,8 +1094,10 @@ var tell = {
1087
1094
  reportError(err);
1088
1095
  return;
1089
1096
  }
1097
+ sessionManager.touch();
1090
1098
  let event = {
1091
1099
  type: "group",
1100
+ service: resolvedService,
1092
1101
  device_id: deviceId,
1093
1102
  session_id: sessionManager.sessionId,
1094
1103
  user_id: userId,
@@ -1101,7 +1110,6 @@ var tell = {
1101
1110
  event = runBeforeSend(event, beforeSend);
1102
1111
  if (event === null) return;
1103
1112
  }
1104
- sessionManager.touch();
1105
1113
  eventBatcher.add(event);
1106
1114
  },
1107
1115
  revenue(amount, currency, orderId, properties) {
@@ -1122,9 +1130,11 @@ var tell = {
1122
1130
  reportError(err);
1123
1131
  return;
1124
1132
  }
1133
+ sessionManager.touch();
1125
1134
  let event = {
1126
1135
  type: "track",
1127
1136
  event: "Order Completed",
1137
+ service: resolvedService,
1128
1138
  device_id: deviceId,
1129
1139
  session_id: sessionManager.sessionId,
1130
1140
  user_id: userId,
@@ -1139,7 +1149,6 @@ var tell = {
1139
1149
  event = runBeforeSend(event, beforeSend);
1140
1150
  if (event === null) return;
1141
1151
  }
1142
- sessionManager.touch();
1143
1152
  eventBatcher.add(event);
1144
1153
  },
1145
1154
  alias(previousId, newUserId) {
@@ -1160,8 +1169,10 @@ var tell = {
1160
1169
  reportError(err);
1161
1170
  return;
1162
1171
  }
1172
+ sessionManager.touch();
1163
1173
  let event = {
1164
1174
  type: "alias",
1175
+ service: resolvedService,
1165
1176
  device_id: deviceId,
1166
1177
  session_id: sessionManager.sessionId,
1167
1178
  user_id: newUserId,
@@ -1172,7 +1183,6 @@ var tell = {
1172
1183
  event = runBeforeSend(event, beforeSend);
1173
1184
  if (event === null) return;
1174
1185
  }
1175
- sessionManager.touch();
1176
1186
  eventBatcher.add(event);
1177
1187
  },
1178
1188
  // -----------------------------------------------------------------------
@@ -1198,7 +1208,7 @@ var tell = {
1198
1208
  level,
1199
1209
  message,
1200
1210
  source: resolvedConfig.source,
1201
- service: service ?? "app",
1211
+ service: service ?? resolvedService,
1202
1212
  session_id: sessionManager.sessionId,
1203
1213
  timestamp: Date.now(),
1204
1214
  data