@tell-rs/browser 0.2.8 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,7 +32,7 @@ tell.track("Button Clicked", { button: "signup" });
32
32
  tell.identify("user_123", { name: "Alice" });
33
33
 
34
34
  // Structured logging
35
- tell.logInfo("Checkout started", "commerce");
35
+ tell.logInfo("Checkout started", { section: "commerce" });
36
36
  ```
37
37
 
38
38
  Events called before `configure()` are automatically queued and replayed.
@@ -57,6 +57,7 @@ tell.configure("feed1e11feed1e11feed1e11feed1e11", {
57
57
  disabled: false, // disable all tracking
58
58
  maxQueueSize: 1000, // max queued items
59
59
  sessionTimeout: 1_800_000, // 30 min session timeout
60
+ maxSessionLength: 86_400_000, // 24 hour max session length
60
61
  persistence: "localStorage", // "localStorage" | "memory"
61
62
  respectDoNotTrack: false, // honor browser DNT setting
62
63
  botDetection: true, // auto-disable for bots
@@ -81,13 +82,13 @@ No `userId` parameter on `track`, `group`, or `revenue` — the browser SDK uses
81
82
  ### Logging
82
83
 
83
84
  ```ts
84
- tell.log(level, message, service?, data?)
85
+ tell.log(level, message, data?)
85
86
 
86
87
  // Convenience methods
87
- tell.logError(message, service?, data?)
88
- tell.logWarning(message, service?, data?)
89
- tell.logInfo(message, service?, data?)
90
- tell.logDebug(message, service?, data?)
88
+ tell.logError(message, data?)
89
+ tell.logWarning(message, data?)
90
+ tell.logInfo(message, data?)
91
+ tell.logDebug(message, data?)
91
92
  // ... and logEmergency, logAlert, logCritical, logNotice, logTrace
92
93
  ```
93
94
 
@@ -129,7 +130,7 @@ tell.configure("feed1e11feed1e11feed1e11feed1e11", production()); // defaults,
129
130
 
130
131
  ## Features
131
132
 
132
- - **Automatic sessions** — rotated on 30-min inactivity or tab hidden/visible
133
+ - **Automatic sessions** — persisted across page loads, rotated on 30-min inactivity or 24-hour max lifetime
133
134
  - **Pre-init queue** — events called before `configure()` are buffered and replayed
134
135
  - **sendBeacon flush** — events are flushed via `navigator.sendBeacon` on page unload
135
136
  - **Bot detection** — auto-disables for headless browsers and bots
package/dist/index.cjs CHANGED
@@ -353,6 +353,8 @@ var DEFAULTS = {
353
353
  maxQueueSize: 1e3,
354
354
  sessionTimeout: 18e5,
355
355
  // 30 min
356
+ maxSessionLength: 864e5,
357
+ // 24 hours
356
358
  persistence: "localStorage",
357
359
  respectDoNotTrack: false,
358
360
  botDetection: true,
@@ -585,20 +587,41 @@ function captureUtm() {
585
587
  }
586
588
 
587
589
  // src/session.ts
590
+ var SESSION_ID_KEY = "tell_session_id";
591
+ var SESSION_TS_KEY = "tell_session_ts";
592
+ var SESSION_START_KEY = "tell_session_start";
593
+ var PERSIST_INTERVAL = 6e4;
588
594
  var SessionManager = class {
589
595
  _sessionId;
590
596
  lastHiddenAt = 0;
591
597
  lastActivityAt;
598
+ sessionStartedAt;
599
+ lastPersistedAt = 0;
592
600
  timeout;
601
+ maxLength;
602
+ storage;
593
603
  onNewSession;
594
604
  visibilityHandler;
595
- lastContextAt = {};
596
605
  constructor(config) {
597
606
  this.timeout = config.timeout;
607
+ this.maxLength = config.maxLength;
608
+ this.storage = config.storage;
598
609
  this.onNewSession = config.onNewSession;
599
- this._sessionId = generateId();
600
- this.lastActivityAt = Date.now();
601
- this.emitContext("session_start");
610
+ const now = Date.now();
611
+ const storedId = this.storage.get(SESSION_ID_KEY);
612
+ const storedTs = Number(this.storage.get(SESSION_TS_KEY) || 0);
613
+ const storedStart = Number(this.storage.get(SESSION_START_KEY) || 0);
614
+ if (storedId && storedTs > 0 && storedStart > 0 && now - storedTs < this.timeout && now - storedStart < this.maxLength) {
615
+ this._sessionId = storedId;
616
+ this.lastActivityAt = storedTs;
617
+ this.sessionStartedAt = storedStart;
618
+ } else {
619
+ this._sessionId = generateId();
620
+ this.lastActivityAt = now;
621
+ this.sessionStartedAt = now;
622
+ this.persist();
623
+ this.onNewSession("session_start", this._sessionId);
624
+ }
602
625
  this.visibilityHandler = () => this.handleVisibility();
603
626
  if (typeof document !== "undefined") {
604
627
  document.addEventListener("visibilitychange", this.visibilityHandler);
@@ -609,14 +632,21 @@ var SessionManager = class {
609
632
  }
610
633
  set sessionId(id) {
611
634
  this._sessionId = id;
635
+ const now = Date.now();
636
+ this.lastActivityAt = now;
637
+ this.sessionStartedAt = now;
638
+ this.persist();
612
639
  }
613
- /** Update activity timestamp; rotates session if idle longer than timeout. */
640
+ /** Update activity timestamp; rotates session if idle longer than timeout or exceeds max length. */
614
641
  touch() {
615
642
  const now = Date.now();
616
- if (now - this.lastActivityAt > this.timeout) {
643
+ if (now - this.lastActivityAt > this.timeout || now - this.sessionStartedAt > this.maxLength) {
617
644
  this.rotateSession("session_timeout");
618
645
  }
619
646
  this.lastActivityAt = now;
647
+ if (now - this.lastPersistedAt >= PERSIST_INTERVAL) {
648
+ this.persistActivity();
649
+ }
620
650
  }
621
651
  destroy() {
622
652
  if (typeof document !== "undefined") {
@@ -627,26 +657,31 @@ var SessionManager = class {
627
657
  if (document.visibilityState === "hidden") {
628
658
  this.lastHiddenAt = Date.now();
629
659
  } else if (document.visibilityState === "visible") {
630
- if (this.lastHiddenAt > 0 && Date.now() - this.lastHiddenAt > this.timeout) {
660
+ const now = Date.now();
661
+ if (this.lastHiddenAt > 0 && (now - this.lastHiddenAt > this.timeout || now - this.sessionStartedAt > this.maxLength)) {
631
662
  this.rotateSession("session_timeout");
632
- } else if (this.lastHiddenAt > 0) {
633
- this.emitContext("app_foreground");
634
663
  }
635
664
  this.lastHiddenAt = 0;
636
665
  }
637
666
  }
638
667
  rotateSession(reason) {
639
668
  this._sessionId = generateId();
640
- this.lastActivityAt = Date.now();
641
- this.emitContext(reason);
642
- }
643
- emitContext(reason) {
644
669
  const now = Date.now();
645
- const last = this.lastContextAt[reason] ?? 0;
646
- if (now - last < 1e3) return;
647
- this.lastContextAt[reason] = now;
670
+ this.lastActivityAt = now;
671
+ this.sessionStartedAt = now;
672
+ this.persist();
648
673
  this.onNewSession(reason, this._sessionId);
649
674
  }
675
+ persist() {
676
+ this.storage.set(SESSION_ID_KEY, this._sessionId);
677
+ this.storage.set(SESSION_TS_KEY, String(this.lastActivityAt));
678
+ this.storage.set(SESSION_START_KEY, String(this.sessionStartedAt));
679
+ this.lastPersistedAt = Date.now();
680
+ }
681
+ persistActivity() {
682
+ this.storage.set(SESSION_TS_KEY, String(this.lastActivityAt));
683
+ this.lastPersistedAt = Date.now();
684
+ }
650
685
  };
651
686
 
652
687
  // src/transport.ts
@@ -968,6 +1003,8 @@ var tell = {
968
1003
  });
969
1004
  sessionManager = new SessionManager({
970
1005
  timeout: resolvedConfig.sessionTimeout,
1006
+ maxLength: resolvedConfig.maxSessionLength,
1007
+ storage,
971
1008
  onNewSession
972
1009
  });
973
1010
  if (typeof window !== "undefined") {
@@ -987,7 +1024,7 @@ var tell = {
987
1024
  if (event.lineno) data.lineno = event.lineno;
988
1025
  if (event.colno) data.colno = event.colno;
989
1026
  if (event.error?.stack) data.stack = event.error.stack;
990
- tell.logError(msg, "browser", data);
1027
+ tell.logError(msg, data);
991
1028
  };
992
1029
  rejectionHandler = (event) => {
993
1030
  if (_disabled || _optedOut || closed) return;
@@ -995,7 +1032,7 @@ var tell = {
995
1032
  const msg = reason instanceof Error ? reason.message : String(reason ?? "Unhandled promise rejection");
996
1033
  const data = {};
997
1034
  if (reason instanceof Error && reason.stack) data.stack = reason.stack;
998
- tell.logError(msg, "browser", data);
1035
+ tell.logError(msg, data);
999
1036
  };
1000
1037
  window.addEventListener("error", errorHandler);
1001
1038
  window.addEventListener("unhandledrejection", rejectionHandler);
@@ -1188,9 +1225,9 @@ var tell = {
1188
1225
  // -----------------------------------------------------------------------
1189
1226
  // Logging
1190
1227
  // -----------------------------------------------------------------------
1191
- log(level, message, service, data) {
1228
+ log(level, message, data) {
1192
1229
  if (!configured) {
1193
- queue.push({ method: "log", args: [level, message, service, data] });
1230
+ queue.push({ method: "log", args: [level, message, data] });
1194
1231
  return;
1195
1232
  }
1196
1233
  if (_disabled || _optedOut) return;
@@ -1208,7 +1245,7 @@ var tell = {
1208
1245
  level,
1209
1246
  message,
1210
1247
  source: resolvedConfig.source,
1211
- service: service ?? resolvedService,
1248
+ service: resolvedService,
1212
1249
  session_id: sessionManager.sessionId,
1213
1250
  timestamp: Date.now(),
1214
1251
  data
@@ -1219,32 +1256,32 @@ var tell = {
1219
1256
  }
1220
1257
  logBatcher.add(logEntry);
1221
1258
  },
1222
- logEmergency(message, service, data) {
1223
- tell.log("emergency", message, service, data);
1259
+ logEmergency(message, data) {
1260
+ tell.log("emergency", message, data);
1224
1261
  },
1225
- logAlert(message, service, data) {
1226
- tell.log("alert", message, service, data);
1262
+ logAlert(message, data) {
1263
+ tell.log("alert", message, data);
1227
1264
  },
1228
- logCritical(message, service, data) {
1229
- tell.log("critical", message, service, data);
1265
+ logCritical(message, data) {
1266
+ tell.log("critical", message, data);
1230
1267
  },
1231
- logError(message, service, data) {
1232
- tell.log("error", message, service, data);
1268
+ logError(message, data) {
1269
+ tell.log("error", message, data);
1233
1270
  },
1234
- logWarning(message, service, data) {
1235
- tell.log("warning", message, service, data);
1271
+ logWarning(message, data) {
1272
+ tell.log("warning", message, data);
1236
1273
  },
1237
- logNotice(message, service, data) {
1238
- tell.log("notice", message, service, data);
1274
+ logNotice(message, data) {
1275
+ tell.log("notice", message, data);
1239
1276
  },
1240
- logInfo(message, service, data) {
1241
- tell.log("info", message, service, data);
1277
+ logInfo(message, data) {
1278
+ tell.log("info", message, data);
1242
1279
  },
1243
- logDebug(message, service, data) {
1244
- tell.log("debug", message, service, data);
1280
+ logDebug(message, data) {
1281
+ tell.log("debug", message, data);
1245
1282
  },
1246
- logTrace(message, service, data) {
1247
- tell.log("trace", message, service, data);
1283
+ logTrace(message, data) {
1284
+ tell.log("trace", message, data);
1248
1285
  },
1249
1286
  // -----------------------------------------------------------------------
1250
1287
  // Super Properties