@tracelog/lib 2.1.2 → 2.2.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.
@@ -558,7 +558,7 @@ var LONG_TASK_THROTTLE_MS = 1e3;
558
558
  var MAX_NAVIGATION_HISTORY = 50;
559
559
 
560
560
  // package.json
561
- var version = "2.1.1";
561
+ var version = "2.1.2";
562
562
 
563
563
  // src/constants/version.constants.ts
564
564
  var LIB_VERSION = version;
@@ -1587,6 +1587,8 @@ var SenderManager = class extends StateManager {
1587
1587
  integrationId;
1588
1588
  apiUrl;
1589
1589
  transformers;
1590
+ staticHeaders;
1591
+ customHeadersProvider;
1590
1592
  lastPermanentErrorLog = null;
1591
1593
  recoveryInProgress = false;
1592
1594
  lastMetadataTimestamp = 0;
@@ -1601,9 +1603,11 @@ var SenderManager = class extends StateManager {
1601
1603
  * @param integrationId - Optional integration identifier ('saas' or 'custom')
1602
1604
  * @param apiUrl - Optional API endpoint URL
1603
1605
  * @param transformers - Optional event transformation hooks
1606
+ * @param staticHeaders - Optional static HTTP headers (from config)
1607
+ * @param customHeadersProvider - Optional callback for dynamic headers
1604
1608
  * @throws Error if integrationId and apiUrl are not both provided or both undefined
1605
1609
  */
1606
- constructor(storeManager, integrationId, apiUrl, transformers = {}) {
1610
+ constructor(storeManager, integrationId, apiUrl, transformers = {}, staticHeaders = {}, customHeadersProvider) {
1607
1611
  super();
1608
1612
  if (integrationId && !apiUrl || !integrationId && apiUrl) {
1609
1613
  throw new Error("SenderManager: integrationId and apiUrl must either both be provided or both be undefined");
@@ -1612,6 +1616,8 @@ var SenderManager = class extends StateManager {
1612
1616
  this.integrationId = integrationId;
1613
1617
  this.apiUrl = apiUrl;
1614
1618
  this.transformers = transformers;
1619
+ this.staticHeaders = staticHeaders;
1620
+ this.customHeadersProvider = customHeadersProvider;
1615
1621
  }
1616
1622
  /**
1617
1623
  * Get the integration ID for this sender
@@ -1620,6 +1626,49 @@ var SenderManager = class extends StateManager {
1620
1626
  getIntegrationId() {
1621
1627
  return this.integrationId;
1622
1628
  }
1629
+ /**
1630
+ * Sets the custom headers provider callback.
1631
+ * Only applies to 'custom' integration (ignored for 'saas').
1632
+ *
1633
+ * @param provider - Callback function that returns custom headers
1634
+ */
1635
+ setCustomHeadersProvider(provider) {
1636
+ this.customHeadersProvider = provider;
1637
+ }
1638
+ /**
1639
+ * Removes the custom headers provider callback.
1640
+ */
1641
+ removeCustomHeadersProvider() {
1642
+ this.customHeadersProvider = void 0;
1643
+ }
1644
+ /**
1645
+ * Builds custom headers by merging static headers with dynamic headers from provider.
1646
+ * Only applies to 'custom' integration (returns empty object for 'saas').
1647
+ *
1648
+ * @returns Merged custom headers object (dynamic headers override static)
1649
+ * @private
1650
+ */
1651
+ getCustomHeaders() {
1652
+ if (this.integrationId !== "custom") {
1653
+ return {};
1654
+ }
1655
+ let dynamicHeaders = {};
1656
+ if (this.customHeadersProvider) {
1657
+ try {
1658
+ const result = this.customHeadersProvider();
1659
+ if (typeof result === "object" && result !== null && !Array.isArray(result)) {
1660
+ dynamicHeaders = result;
1661
+ } else {
1662
+ log("warn", "Custom headers provider returned invalid value, expected object", {
1663
+ data: { received: typeof result }
1664
+ });
1665
+ }
1666
+ } catch (error) {
1667
+ log("warn", "Custom headers provider threw an error, using static headers only", { error });
1668
+ }
1669
+ }
1670
+ return { ...this.staticHeaders, ...dynamicHeaders };
1671
+ }
1623
1672
  getQueueStorageKey() {
1624
1673
  const userId = this.get("userId") || "anonymous";
1625
1674
  const baseKey = QUEUE_KEY(userId);
@@ -1647,6 +1696,11 @@ var SenderManager = class extends StateManager {
1647
1696
  *
1648
1697
  * **Important**: No retry mechanism for failures. Events are NOT persisted.
1649
1698
  *
1699
+ * **Custom Headers Limitation**: Custom headers set via `setCustomHeaders()` are NOT applied
1700
+ * to sendBeacon requests due to browser API limitations. The sendBeacon API only supports
1701
+ * Content-Type header via Blob. For scenarios requiring custom headers, ensure async
1702
+ * sends complete before page unload.
1703
+ *
1650
1704
  * @param body - Event queue to send
1651
1705
  * @returns `true` if send succeeded or was skipped, `false` if failed
1652
1706
  *
@@ -2069,6 +2123,7 @@ var SenderManager = class extends StateManager {
2069
2123
  controller.abort();
2070
2124
  }, REQUEST_TIMEOUT_MS);
2071
2125
  try {
2126
+ const customHeaders = this.getCustomHeaders();
2072
2127
  const response = await fetch(url, {
2073
2128
  method: "POST",
2074
2129
  body: payload,
@@ -2076,6 +2131,7 @@ var SenderManager = class extends StateManager {
2076
2131
  credentials: "include",
2077
2132
  signal: controller.signal,
2078
2133
  headers: {
2134
+ ...customHeaders,
2079
2135
  "Content-Type": "application/json"
2080
2136
  }
2081
2137
  });
@@ -2538,8 +2594,10 @@ var EventManager = class extends StateManager {
2538
2594
  * @param storeManager - Storage manager for persistence
2539
2595
  * @param emitter - Optional event emitter for local event consumption
2540
2596
  * @param transformers - Optional event transformation hooks
2597
+ * @param staticHeaders - Optional static HTTP headers for custom backend (from config)
2598
+ * @param customHeadersProvider - Optional callback for dynamic headers
2541
2599
  */
2542
- constructor(storeManager, emitter = null, transformers = {}) {
2600
+ constructor(storeManager, emitter = null, transformers = {}, staticHeaders = {}, customHeadersProvider) {
2543
2601
  super();
2544
2602
  this.emitter = emitter;
2545
2603
  this.transformers = transformers;
@@ -2550,7 +2608,16 @@ var EventManager = class extends StateManager {
2550
2608
  this.dataSenders.push(new SenderManager(storeManager, "saas", collectApiUrls.saas, transformers));
2551
2609
  }
2552
2610
  if (collectApiUrls?.custom) {
2553
- this.dataSenders.push(new SenderManager(storeManager, "custom", collectApiUrls.custom, transformers));
2611
+ this.dataSenders.push(
2612
+ new SenderManager(
2613
+ storeManager,
2614
+ "custom",
2615
+ collectApiUrls.custom,
2616
+ transformers,
2617
+ staticHeaders,
2618
+ customHeadersProvider
2619
+ )
2620
+ );
2554
2621
  }
2555
2622
  this.saveSessionCountsDebounced = this.debounce((sessionId) => {
2556
2623
  this.saveSessionCounts(sessionId);
@@ -2957,6 +3024,29 @@ var EventManager = class extends StateManager {
2957
3024
  flushImmediatelySync() {
2958
3025
  return this.flushEvents(true);
2959
3026
  }
3027
+ /**
3028
+ * Sets the custom headers provider callback for the custom integration.
3029
+ * Only affects requests to custom backend (not TraceLog SaaS).
3030
+ *
3031
+ * @param provider - Callback function that returns custom headers
3032
+ */
3033
+ setCustomHeadersProvider(provider) {
3034
+ for (const sender of this.dataSenders) {
3035
+ if (sender.getIntegrationId() === "custom") {
3036
+ sender.setCustomHeadersProvider(provider);
3037
+ }
3038
+ }
3039
+ }
3040
+ /**
3041
+ * Removes the custom headers provider callback from the custom integration.
3042
+ */
3043
+ removeCustomHeadersProvider() {
3044
+ for (const sender of this.dataSenders) {
3045
+ if (sender.getIntegrationId() === "custom") {
3046
+ sender.removeCustomHeadersProvider();
3047
+ }
3048
+ }
3049
+ }
2960
3050
  /**
2961
3051
  * Returns the current number of events in the main queue.
2962
3052
  *
@@ -6053,6 +6143,7 @@ var App = class extends StateManager {
6053
6143
  suppressNextScrollTimer = null;
6054
6144
  emitter = new Emitter();
6055
6145
  transformers = {};
6146
+ customHeadersProvider;
6056
6147
  managers = {};
6057
6148
  handlers = {};
6058
6149
  get initialized() {
@@ -6072,7 +6163,14 @@ var App = class extends StateManager {
6072
6163
  this.managers.storage = new StorageManager();
6073
6164
  try {
6074
6165
  this.setupState(config);
6075
- this.managers.event = new EventManager(this.managers.storage, this.emitter, this.transformers);
6166
+ const staticHeaders = config.integrations?.custom?.headers ?? {};
6167
+ this.managers.event = new EventManager(
6168
+ this.managers.storage,
6169
+ this.emitter,
6170
+ this.transformers,
6171
+ staticHeaders,
6172
+ this.customHeadersProvider
6173
+ );
6076
6174
  this.initializeHandlers();
6077
6175
  await this.managers.event.recoverPersistedEvents().catch((error) => {
6078
6176
  log("warn", "Failed to recover persisted events", { error });
@@ -6135,6 +6233,34 @@ var App = class extends StateManager {
6135
6233
  getTransformer(hook) {
6136
6234
  return this.transformers[hook];
6137
6235
  }
6236
+ /**
6237
+ * Sets a callback to provide custom HTTP headers for requests to custom backends.
6238
+ * Only applies to custom backend integration (not TraceLog SaaS).
6239
+ *
6240
+ * @param provider - Callback function that returns custom headers
6241
+ * @throws {Error} If provider is not a function
6242
+ * @internal Called from api.setCustomHeaders()
6243
+ */
6244
+ setCustomHeaders(provider) {
6245
+ if (typeof provider !== "function") {
6246
+ throw new Error(`[TraceLog] Custom headers provider must be a function, received: ${typeof provider}`);
6247
+ }
6248
+ this.customHeadersProvider = provider;
6249
+ if (this.managers.event) {
6250
+ this.managers.event.setCustomHeadersProvider(provider);
6251
+ }
6252
+ }
6253
+ /**
6254
+ * Removes the custom headers provider callback.
6255
+ *
6256
+ * @internal Called from api.removeCustomHeaders()
6257
+ */
6258
+ removeCustomHeaders() {
6259
+ this.customHeadersProvider = void 0;
6260
+ if (this.managers.event) {
6261
+ this.managers.event.removeCustomHeadersProvider();
6262
+ }
6263
+ }
6138
6264
  /**
6139
6265
  * Destroys the TraceLog instance and cleans up all resources.
6140
6266
  *
@@ -6160,6 +6286,7 @@ var App = class extends StateManager {
6160
6286
  this.emitter.removeAllListeners();
6161
6287
  this.transformers.beforeSend = void 0;
6162
6288
  this.transformers.beforeBatch = void 0;
6289
+ this.customHeadersProvider = void 0;
6163
6290
  this.set("suppressNextScroll", false);
6164
6291
  this.set("sessionId", null);
6165
6292
  this.isInitialized = false;
@@ -6314,6 +6441,7 @@ var App = class extends StateManager {
6314
6441
  // src/api.ts
6315
6442
  var pendingListeners = [];
6316
6443
  var pendingTransformers = [];
6444
+ var pendingCustomHeadersProvider = null;
6317
6445
  var app = null;
6318
6446
  var isInitializing = false;
6319
6447
  var isDestroying = false;
@@ -6348,6 +6476,10 @@ var init = async (config) => {
6348
6476
  }
6349
6477
  });
6350
6478
  pendingTransformers.length = 0;
6479
+ if (pendingCustomHeadersProvider) {
6480
+ instance.setCustomHeaders(pendingCustomHeadersProvider);
6481
+ pendingCustomHeadersProvider = null;
6482
+ }
6351
6483
  const initPromise = instance.init(validatedConfig);
6352
6484
  const timeoutPromise = new Promise((_, reject) => {
6353
6485
  setTimeout(() => {
@@ -6446,6 +6578,35 @@ var removeTransformer = (hook) => {
6446
6578
  }
6447
6579
  app.removeTransformer(hook);
6448
6580
  };
6581
+ var setCustomHeaders = (provider) => {
6582
+ if (typeof window === "undefined" || typeof document === "undefined") {
6583
+ return;
6584
+ }
6585
+ if (typeof provider !== "function") {
6586
+ throw new Error(`[TraceLog] Custom headers provider must be a function, received: ${typeof provider}`);
6587
+ }
6588
+ if (!app || isInitializing) {
6589
+ pendingCustomHeadersProvider = provider;
6590
+ return;
6591
+ }
6592
+ if (isDestroying) {
6593
+ throw new Error("[TraceLog] Cannot set custom headers while TraceLog is being destroyed");
6594
+ }
6595
+ app.setCustomHeaders(provider);
6596
+ };
6597
+ var removeCustomHeaders = () => {
6598
+ if (typeof window === "undefined" || typeof document === "undefined") {
6599
+ return;
6600
+ }
6601
+ if (!app) {
6602
+ pendingCustomHeadersProvider = null;
6603
+ return;
6604
+ }
6605
+ if (isDestroying) {
6606
+ throw new Error("[TraceLog] Cannot remove custom headers while TraceLog is being destroyed");
6607
+ }
6608
+ app.removeCustomHeaders();
6609
+ };
6449
6610
  var isInitialized = () => {
6450
6611
  if (typeof window === "undefined" || typeof document === "undefined") {
6451
6612
  return false;
@@ -6470,6 +6631,7 @@ var destroy = () => {
6470
6631
  isInitializing = false;
6471
6632
  pendingListeners.length = 0;
6472
6633
  pendingTransformers.length = 0;
6634
+ pendingCustomHeadersProvider = null;
6473
6635
  if (false) ;
6474
6636
  isDestroying = false;
6475
6637
  } catch (error) {
@@ -6477,6 +6639,7 @@ var destroy = () => {
6477
6639
  isInitializing = false;
6478
6640
  pendingListeners.length = 0;
6479
6641
  pendingTransformers.length = 0;
6642
+ pendingCustomHeadersProvider = null;
6480
6643
  isDestroying = false;
6481
6644
  log("warn", "Error during destroy, forced cleanup completed", { error });
6482
6645
  }
@@ -6520,6 +6683,8 @@ var tracelog = {
6520
6683
  off,
6521
6684
  setTransformer,
6522
6685
  removeTransformer,
6686
+ setCustomHeaders,
6687
+ removeCustomHeaders,
6523
6688
  isInitialized,
6524
6689
  destroy,
6525
6690
  setQaMode: setQaMode2,