@tracelog/lib 0.12.0 → 0.12.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.
@@ -257,12 +257,25 @@ var formatLogMsg = (msg, error) => {
257
257
  const sanitizedMessage = error.message.replace(/\s+at\s+.*$/gm, "").replace(/\(.*?:\d+:\d+\)/g, "");
258
258
  return `[TraceLog] ${msg}: ${sanitizedMessage}`;
259
259
  }
260
- return `[TraceLog] ${msg}: ${error instanceof Error ? error.message : "Unknown error"}`;
260
+ if (error instanceof Error) {
261
+ return `[TraceLog] ${msg}: ${error.message}`;
262
+ }
263
+ if (typeof error === "string") {
264
+ return `[TraceLog] ${msg}: ${error}`;
265
+ }
266
+ if (typeof error === "object") {
267
+ try {
268
+ return `[TraceLog] ${msg}: ${JSON.stringify(error)}`;
269
+ } catch {
270
+ return `[TraceLog] ${msg}: [Unable to serialize error]`;
271
+ }
272
+ }
273
+ return `[TraceLog] ${msg}: ${String(error)}`;
261
274
  }
262
275
  return `[TraceLog] ${msg}`;
263
276
  };
264
277
  var log = (type, msg, extra) => {
265
- const { error, data, showToClient = false } = extra ?? {};
278
+ const { error, data, showToClient = false, style } = extra ?? {};
266
279
  const formattedMsg = error ? formatLogMsg(msg, error) : `[TraceLog] ${msg}`;
267
280
  const method = type === "error" ? "error" : type === "warn" ? "warn" : "log";
268
281
  const isProduction = process.env.NODE_ENV !== "development";
@@ -274,13 +287,21 @@ var log = (type, msg, extra) => {
274
287
  return;
275
288
  }
276
289
  }
277
- if (isProduction && data !== void 0) {
278
- const sanitizedData = sanitizeLogData(data);
279
- console[method](formattedMsg, sanitizedData);
280
- } else if (data !== void 0) {
281
- console[method](formattedMsg, data);
290
+ const hasStyle = style !== void 0 && style !== "";
291
+ const styledMsg = hasStyle ? `%c${formattedMsg}` : formattedMsg;
292
+ if (data !== void 0) {
293
+ const sanitizedData = isProduction ? sanitizeLogData(data) : data;
294
+ if (hasStyle) {
295
+ console[method](styledMsg, style, sanitizedData);
296
+ } else {
297
+ console[method](styledMsg, sanitizedData);
298
+ }
282
299
  } else {
283
- console[method](formattedMsg);
300
+ if (hasStyle) {
301
+ console[method](styledMsg, style);
302
+ } else {
303
+ console[method](styledMsg);
304
+ }
284
305
  }
285
306
  };
286
307
  var sanitizeLogData = (data) => {
@@ -290,6 +311,14 @@ var sanitizeLogData = (data) => {
290
311
  const lowerKey = key.toLowerCase();
291
312
  if (sensitiveKeys.some((sensitiveKey) => lowerKey.includes(sensitiveKey))) {
292
313
  sanitized[key] = "[REDACTED]";
314
+ continue;
315
+ }
316
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
317
+ sanitized[key] = sanitizeLogData(value);
318
+ } else if (Array.isArray(value)) {
319
+ sanitized[key] = value.map(
320
+ (item) => item !== null && typeof item === "object" && !Array.isArray(item) ? sanitizeLogData(item) : item
321
+ );
293
322
  } else {
294
323
  sanitized[key] = value;
295
324
  }
@@ -337,10 +366,17 @@ var getDeviceType = () => {
337
366
  }
338
367
  };
339
368
 
369
+ // src/constants/app.constants.ts
370
+ var LOG_STYLE_ACTIVE = "background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
371
+ var LOG_STYLE_DISABLED = "background: #9e9e9e; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
372
+
340
373
  // src/constants/storage.constants.ts
341
374
  var STORAGE_BASE_KEY = "tlog";
342
375
  var QA_MODE_KEY = `${STORAGE_BASE_KEY}:qa_mode`;
343
376
  var USER_ID_KEY = `${STORAGE_BASE_KEY}:uid`;
377
+ var QA_MODE_URL_PARAM = "tlog_mode";
378
+ var QA_MODE_ENABLE_VALUE = "qa";
379
+ var QA_MODE_DISABLE_VALUE = "qa_off";
344
380
  var QUEUE_KEY = (id) => id ? `${STORAGE_BASE_KEY}:${id}:queue` : `${STORAGE_BASE_KEY}:queue`;
345
381
  var SESSION_STORAGE_KEY = (id) => id ? `${STORAGE_BASE_KEY}:${id}:session` : `${STORAGE_BASE_KEY}:session`;
346
382
  var BROADCAST_CHANNEL_NAME = (id) => id ? `${STORAGE_BASE_KEY}:${id}:broadcast` : `${STORAGE_BASE_KEY}:broadcast`;
@@ -430,32 +466,65 @@ var ERROR_BURST_BACKOFF_MS = 5e3;
430
466
  var PERMANENT_ERROR_LOG_THROTTLE_MS = 6e4;
431
467
 
432
468
  // src/utils/browser/qa-mode.utils.ts
433
- var QA_MODE_PARAM = "tlog_mode";
434
- var QA_MODE_VALUE = "qa";
435
469
  var detectQaMode = () => {
436
- const stored = sessionStorage.getItem(QA_MODE_KEY);
437
- if (stored === "true") {
438
- return true;
470
+ if (typeof window === "undefined" || typeof document === "undefined") {
471
+ return false;
439
472
  }
440
- const params = new URLSearchParams(window.location.search);
441
- const modeParam = params.get(QA_MODE_PARAM);
442
- const isQaMode = modeParam === QA_MODE_VALUE;
443
- if (isQaMode) {
444
- sessionStorage.setItem(QA_MODE_KEY, "true");
445
- params.delete(QA_MODE_PARAM);
446
- const newSearch = params.toString();
447
- const newUrl = `${window.location.pathname}${newSearch ? "?" + newSearch : ""}${window.location.hash}`;
448
- try {
449
- window.history.replaceState({}, "", newUrl);
450
- } catch (error) {
451
- log("warn", "History API not available, cannot replace URL", { error });
473
+ try {
474
+ const params = new URLSearchParams(window.location.search);
475
+ const urlParam = params.get(QA_MODE_URL_PARAM);
476
+ const storedState = sessionStorage.getItem(QA_MODE_KEY);
477
+ let newState = null;
478
+ if (urlParam === QA_MODE_ENABLE_VALUE) {
479
+ newState = true;
480
+ sessionStorage.setItem(QA_MODE_KEY, "true");
481
+ log("info", "QA Mode ACTIVE", {
482
+ showToClient: true,
483
+ style: LOG_STYLE_ACTIVE
484
+ });
485
+ } else if (urlParam === QA_MODE_DISABLE_VALUE) {
486
+ newState = false;
487
+ sessionStorage.removeItem(QA_MODE_KEY);
488
+ log("info", "QA Mode DISABLED", {
489
+ showToClient: true,
490
+ style: LOG_STYLE_DISABLED
491
+ });
452
492
  }
453
- console.log(
454
- "%c[TraceLog] QA Mode ACTIVE",
455
- "background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;"
456
- );
493
+ if (urlParam === QA_MODE_ENABLE_VALUE || urlParam === QA_MODE_DISABLE_VALUE) {
494
+ try {
495
+ params.delete(QA_MODE_URL_PARAM);
496
+ const search = params.toString();
497
+ const url = window.location.pathname + (search ? "?" + search : "") + window.location.hash;
498
+ window.history.replaceState({}, "", url);
499
+ } catch {
500
+ }
501
+ }
502
+ return newState ?? storedState === "true";
503
+ } catch {
504
+ return false;
505
+ }
506
+ };
507
+ var setQaMode = (enabled) => {
508
+ if (typeof window === "undefined" || typeof document === "undefined") {
509
+ return;
510
+ }
511
+ try {
512
+ if (enabled) {
513
+ sessionStorage.setItem(QA_MODE_KEY, "true");
514
+ log("info", "QA Mode ENABLED", {
515
+ showToClient: true,
516
+ style: LOG_STYLE_ACTIVE
517
+ });
518
+ } else {
519
+ sessionStorage.removeItem(QA_MODE_KEY);
520
+ log("info", "QA Mode DISABLED", {
521
+ showToClient: true,
522
+ style: LOG_STYLE_DISABLED
523
+ });
524
+ }
525
+ } catch {
526
+ log("warn", "Cannot set QA mode: sessionStorage unavailable");
457
527
  }
458
- return isQaMode;
459
528
  };
460
529
 
461
530
  // src/utils/browser/utm-params.utils.ts
@@ -1582,9 +1651,12 @@ var EventManager = class extends StateManager {
1582
1651
  return;
1583
1652
  }
1584
1653
  if (this.get("mode") === "qa" /* QA */ && eventType === "custom" /* CUSTOM */ && custom_event) {
1585
- console.log("[TraceLog] Event", {
1586
- name: custom_event.name,
1587
- ...custom_event.metadata && { metadata: custom_event.metadata }
1654
+ log("info", "Event", {
1655
+ showToClient: true,
1656
+ data: {
1657
+ name: custom_event.name,
1658
+ ...custom_event.metadata && { metadata: custom_event.metadata }
1659
+ }
1588
1660
  });
1589
1661
  this.emitEvent(payload);
1590
1662
  return;
@@ -4360,6 +4432,12 @@ var __setAppInstance = (instance) => {
4360
4432
  }
4361
4433
  app = instance;
4362
4434
  };
4435
+ var setQaMode2 = (enabled) => {
4436
+ if (typeof window === "undefined" || typeof document === "undefined") {
4437
+ return;
4438
+ }
4439
+ setQaMode(enabled);
4440
+ };
4363
4441
  if (process.env.NODE_ENV === "development" && typeof window !== "undefined" && typeof document !== "undefined") {
4364
4442
  const injectTestingBridge = () => {
4365
4443
  window.__traceLogBridge = new TestBridge(isInitializing, isDestroying);
@@ -4389,23 +4467,10 @@ var SESSION_ANALYTICS = {
4389
4467
  SHORT_SESSION_THRESHOLD_MS: 30 * 1e3,
4390
4468
  MEDIUM_SESSION_THRESHOLD_MS: 5 * 60 * 1e3,
4391
4469
  LONG_SESSION_THRESHOLD_MS: 30 * 60 * 1e3,
4392
- MAX_REALISTIC_SESSION_DURATION_MS: 8 * 60 * 60 * 1e3
4470
+ MAX_REALISTIC_SESSION_DURATION_MS: 8 * 60 * 60 * 1e3,
4393
4471
  // Filter outliers
4394
- };
4395
- var DEVICE_ANALYTICS = {
4396
- MOBILE_MAX_WIDTH: 768,
4397
- TABLET_MAX_WIDTH: 1024,
4398
- MOBILE_PERFORMANCE_FACTOR: 1.5,
4399
- // Mobile typically 1.5x slower
4400
- TABLET_PERFORMANCE_FACTOR: 1.2
4401
- };
4402
- var CONTENT_ANALYTICS = {
4403
- MIN_TEXT_LENGTH_FOR_ANALYSIS: 10,
4404
- MIN_CLICKS_FOR_HOT_ELEMENT: 10,
4405
- // Popular element threshold
4406
- MIN_SCROLL_COMPLETION_PERCENT: 80,
4407
- // Page consumption threshold
4408
- MIN_TIME_ON_PAGE_FOR_READ_MS: 15 * 1e3
4472
+ MIN_EVENTS_FOR_DURATION: 2
4473
+ // Minimum events required to calculate session duration
4409
4474
  };
4410
4475
  var INSIGHT_THRESHOLDS = {
4411
4476
  SIGNIFICANT_CHANGE_PERCENT: 20,
@@ -4418,20 +4483,6 @@ var INSIGHT_THRESHOLDS = {
4418
4483
  HIGH_ERROR_RATE_PERCENT: 5,
4419
4484
  CRITICAL_ERROR_RATE_PERCENT: 10
4420
4485
  };
4421
- var TEMPORAL_ANALYSIS = {
4422
- SHORT_TERM_TREND_HOURS: 24,
4423
- MEDIUM_TERM_TREND_DAYS: 7,
4424
- LONG_TERM_TREND_DAYS: 30,
4425
- MIN_DATA_POINTS_FOR_TREND: 5,
4426
- WEEKLY_PATTERN_MIN_WEEKS: 4,
4427
- DAILY_PATTERN_MIN_DAYS: 14
4428
- };
4429
- var SEGMENTATION_ANALYTICS = {
4430
- MIN_SEGMENT_SIZE: 10,
4431
- MIN_COHORT_SIZE: 5,
4432
- COHORT_ANALYSIS_DAYS: [1, 3, 7, 14, 30],
4433
- MIN_FUNNEL_EVENTS: 20
4434
- };
4435
4486
  var ANALYTICS_QUERY_LIMITS = {
4436
4487
  DEFAULT_EVENTS_LIMIT: 5,
4437
4488
  DEFAULT_SESSIONS_LIMIT: 5,
@@ -4441,14 +4492,6 @@ var ANALYTICS_QUERY_LIMITS = {
4441
4492
  ANALYTICS_BATCH_SIZE: 1e3
4442
4493
  // For historical analysis
4443
4494
  };
4444
- var ANOMALY_DETECTION = {
4445
- ANOMALY_THRESHOLD_SIGMA: 2.5,
4446
- STRONG_ANOMALY_THRESHOLD_SIGMA: 3,
4447
- TRAFFIC_DROP_ALERT_PERCENT: -30,
4448
- TRAFFIC_SPIKE_ALERT_PERCENT: 200,
4449
- MIN_BASELINE_DAYS: 7,
4450
- MIN_EVENTS_FOR_ANOMALY_DETECTION: 50
4451
- };
4452
4495
  var SPECIAL_PAGE_URLS = {
4453
4496
  PAGE_URL_EXCLUDED: "excluded",
4454
4497
  PAGE_URL_UNKNOWN: "unknown"
@@ -4461,15 +4504,14 @@ var tracelog = {
4461
4504
  on,
4462
4505
  off,
4463
4506
  isInitialized,
4464
- destroy
4507
+ destroy,
4508
+ setQaMode: setQaMode2
4465
4509
  };
4466
4510
 
4467
4511
  exports.ANALYTICS_QUERY_LIMITS = ANALYTICS_QUERY_LIMITS;
4468
- exports.ANOMALY_DETECTION = ANOMALY_DETECTION;
4469
4512
  exports.AppConfigValidationError = AppConfigValidationError;
4470
- exports.CONTENT_ANALYTICS = CONTENT_ANALYTICS;
4513
+ exports.DEFAULT_SESSION_TIMEOUT = DEFAULT_SESSION_TIMEOUT;
4471
4514
  exports.DEFAULT_WEB_VITALS_MODE = DEFAULT_WEB_VITALS_MODE;
4472
- exports.DEVICE_ANALYTICS = DEVICE_ANALYTICS;
4473
4515
  exports.DeviceType = DeviceType;
4474
4516
  exports.ENGAGEMENT_THRESHOLDS = ENGAGEMENT_THRESHOLDS;
4475
4517
  exports.EmitterEvent = EmitterEvent;
@@ -4490,14 +4532,12 @@ exports.MAX_STRING_LENGTH_IN_ARRAY = MAX_STRING_LENGTH_IN_ARRAY;
4490
4532
  exports.Mode = Mode;
4491
4533
  exports.PII_PATTERNS = PII_PATTERNS;
4492
4534
  exports.PermanentError = PermanentError;
4493
- exports.SEGMENTATION_ANALYTICS = SEGMENTATION_ANALYTICS;
4494
4535
  exports.SESSION_ANALYTICS = SESSION_ANALYTICS;
4495
4536
  exports.SPECIAL_PAGE_URLS = SPECIAL_PAGE_URLS;
4496
4537
  exports.SamplingRateValidationError = SamplingRateValidationError;
4497
4538
  exports.ScrollDirection = ScrollDirection;
4498
4539
  exports.SessionTimeoutValidationError = SessionTimeoutValidationError;
4499
4540
  exports.SpecialApiUrl = SpecialApiUrl;
4500
- exports.TEMPORAL_ANALYSIS = TEMPORAL_ANALYSIS;
4501
4541
  exports.TraceLogValidationError = TraceLogValidationError;
4502
4542
  exports.WEB_VITALS_GOOD_THRESHOLDS = WEB_VITALS_GOOD_THRESHOLDS;
4503
4543
  exports.WEB_VITALS_NEEDS_IMPROVEMENT_THRESHOLDS = WEB_VITALS_NEEDS_IMPROVEMENT_THRESHOLDS;