@journium/js 1.1.1 → 1.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"JourniumAnalytics.d.ts","sourceRoot":"","sources":["../src/JourniumAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAK1F,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,wBAAwB,CAAC,CAAa;gBAElC,MAAM,EAAE,cAAc;IAqBlC,OAAO,CAAC,yBAAyB;IAiBjC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxE,KAAK,IAAI,IAAI;IAIb,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,gBAAgB,IAAI,IAAI;IA4BxB,eAAe,IAAI,IAAI;IAMvB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAkCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA6BrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,mBAAmB;IAInB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAI9E,OAAO,IAAI,IAAI;CAQhB;AAED,eAAO,MAAM,IAAI,GAAI,QAAQ,cAAc,KAAG,iBAE7C,CAAC;;mBAF2B,cAAc,KAAG,iBAAiB;;AAI/D,wBAAwB"}
1
+ {"version":3,"file":"JourniumAnalytics.d.ts","sourceRoot":"","sources":["../src/JourniumAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAK1F,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,wBAAwB,CAAC,CAAa;gBAElC,MAAM,EAAE,cAAc;IAqBlC,OAAO,CAAC,yBAAyB;IAiBjC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxE,KAAK,IAAI,IAAI;IAIb,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,gBAAgB,IAAI,IAAI;IA4BxB,eAAe,IAAI,IAAI;IAMvB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAkCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA+BrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,mBAAmB;IAInB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAI9E,OAAO,IAAI,IAAI;CAQhB;AAED,eAAO,MAAM,IAAI,WAAY,cAAc,KAAG,iBAE7C,CAAC;;mBAF2B,cAAc,KAAG,iBAAiB;;AAI/D,wBAAwB"}
@@ -1,10 +1,14 @@
1
1
  import { JourniumConfig, JourniumLocalOptions } from '@journium/core';
2
2
  export declare class JourniumClient {
3
+ private static readonly REMOTE_OPTIONS_REFRESH_INTERVAL;
3
4
  private config;
4
5
  private effectiveOptions;
5
6
  private queue;
6
7
  private stagedEvents;
7
8
  private flushTimer;
9
+ private remoteOptionsRefreshTimer;
10
+ private isRefreshing;
11
+ private lastRemoteOptions;
8
12
  private initializationComplete;
9
13
  private initializationFailed;
10
14
  private identityManager;
@@ -22,6 +26,10 @@ export declare class JourniumClient {
22
26
  private notifyOptionsChange;
23
27
  private processStagedEvents;
24
28
  private startFlushTimer;
29
+ private startRemoteOptionsRefreshTimer;
30
+ private refreshRemoteOptions;
31
+ private applyRemoteOptions;
32
+ private buildIdentityProperties;
25
33
  private sendEvents;
26
34
  identify(distinctId: string, attributes?: Record<string, unknown>): void;
27
35
  reset(): void;
@@ -29,5 +37,6 @@ export declare class JourniumClient {
29
37
  flush(): Promise<void>;
30
38
  destroy(): void;
31
39
  getEffectiveOptions(): JourniumLocalOptions;
40
+ private get ingestionPaused();
32
41
  }
33
42
  //# sourceMappingURL=JourniumClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JourniumClient.d.ts","sourceRoot":"","sources":["../src/JourniumClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,cAAc,EAAyB,oBAAoB,EAAyG,MAAM,gBAAgB,CAAC;AAEnN,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,sBAAsB,CAA2D;gBAE7E,MAAM,EAAE,cAAc;IAiClC,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,iBAAiB;YAYX,eAAe;YAyEf,2BAA2B;IAiDzC;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ9E,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,mBAAmB;IA0C3B,OAAO,CAAC,eAAe;YAYT,UAAU;IA0BxB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAqB5E,KAAK,IAAI,IAAI;IAab,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IA2D9D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,OAAO,IAAI,IAAI;IAQf,mBAAmB,IAAI,oBAAoB;CAG5C"}
1
+ {"version":3,"file":"JourniumClient.d.ts","sourceRoot":"","sources":["../src/JourniumClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,cAAc,EAAyB,oBAAoB,EAAyG,MAAM,gBAAgB,CAAC;AAEnN,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAkB;IAEzE,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,yBAAyB,CAA+C;IAChF,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,iBAAiB,CAAsC;IAC/D,OAAO,CAAC,sBAAsB,CAAkB;IAChD,OAAO,CAAC,oBAAoB,CAAkB;IAC9C,OAAO,CAAC,eAAe,CAA0B;IACjD,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,sBAAsB,CAA2D;gBAE7E,MAAM,EAAE,cAAc;IAiClC,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,iBAAiB;YAYX,eAAe;YAoCf,2BAA2B;IAiDzC;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ9E,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,8BAA8B;YAcxB,oBAAoB;IA6ClC,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,uBAAuB;YAiBjB,UAAU;IA0BxB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAqB5E,KAAK,IAAI,IAAI;IAab,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAsC9D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB5B,OAAO,IAAI,IAAI;IAYf,mBAAmB,IAAI,oBAAoB;IAI3C,OAAO,KAAK,eAAe,GAE1B;CACF"}
@@ -9,9 +9,10 @@ export declare class PageviewTracker {
9
9
  capturePageview(customProperties?: Record<string, unknown>): void;
10
10
  /**
11
11
  * Start automatic autocapture for pageviews
12
- * @returns void
12
+ * @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
13
+ * Pass false when restarting after a remote options update to avoid a spurious pageview.
13
14
  */
14
- startAutoPageviewTracking(): void;
15
+ startAutoPageviewTracking(captureInitialPageview?: boolean): void;
15
16
  /**
16
17
  * Stop automatic autocapture for pageviews
17
18
  * @returns void
@@ -1 +1 @@
1
- {"version":3,"file":"PageviewTracker.d.ts","sourceRoot":"","sources":["../src/PageviewTracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAC/E,OAAO,CAAC,eAAe,CAA6B;gBAExC,MAAM,EAAE,cAAc;IAIlC,eAAe,CAAC,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAkBrE;;;OAGG;IACH,yBAAyB,IAAI,IAAI;IA0BjC;;;OAGG;IACH,eAAe,IAAI,IAAI;CAmBxB"}
1
+ {"version":3,"file":"PageviewTracker.d.ts","sourceRoot":"","sources":["../src/PageviewTracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAC/E,OAAO,CAAC,eAAe,CAA6B;gBAExC,MAAM,EAAE,cAAc;IAIlC,eAAe,CAAC,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAkBrE;;;;OAIG;IACH,yBAAyB,CAAC,sBAAsB,GAAE,OAAc,GAAG,IAAI;IA4BvE;;;OAGG;IACH,eAAe,IAAI,IAAI;CAmBxB"}
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * uuidv7: A JavaScript implementation of UUID version 7
5
5
  *
6
- * Copyright 2021-2024 LiosK
6
+ * Copyright 2021-2025 LiosK
7
7
  *
8
8
  * @license Apache-2.0
9
9
  * @packageDocumentation
@@ -232,7 +232,10 @@ class V7Generator {
232
232
  * number generator should be cryptographically strong and securely seeded.
233
233
  */
234
234
  constructor(randomNumberGenerator) {
235
- this.timestamp = 0;
235
+ /**
236
+ * Biased by one to distinguish zero (uninitialized) and zero (UNIX epoch).
237
+ */
238
+ this.timestamp_biased = 0;
236
239
  this.counter = 0;
237
240
  this.random = randomNumberGenerator !== null && randomNumberGenerator !== void 0 ? randomNumberGenerator : getDefaultRandom();
238
241
  }
@@ -278,13 +281,13 @@ class V7Generator {
278
281
  *
279
282
  * @param rollbackAllowance - The amount of `unixTsMs` rollback that is
280
283
  * considered significant. A suggested value is `10_000` (milliseconds).
281
- * @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
284
+ * @throws RangeError if `unixTsMs` is not a 48-bit unsigned integer.
282
285
  */
283
286
  generateOrResetCore(unixTsMs, rollbackAllowance) {
284
287
  let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
285
288
  if (value === undefined) {
286
289
  // reset state and resume
287
- this.timestamp = 0;
290
+ this.timestamp_biased = 0;
288
291
  value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
289
292
  }
290
293
  return value;
@@ -298,28 +301,29 @@ class V7Generator {
298
301
  *
299
302
  * @param rollbackAllowance - The amount of `unixTsMs` rollback that is
300
303
  * considered significant. A suggested value is `10_000` (milliseconds).
301
- * @throws RangeError if `unixTsMs` is not a 48-bit positive integer.
304
+ * @throws RangeError if `unixTsMs` is not a 48-bit unsigned integer.
302
305
  */
303
306
  generateOrAbortCore(unixTsMs, rollbackAllowance) {
304
307
  const MAX_COUNTER = 4398046511103;
305
308
  if (!Number.isInteger(unixTsMs) ||
306
- unixTsMs < 1 ||
309
+ unixTsMs < 0 ||
307
310
  unixTsMs > 281474976710655) {
308
- throw new RangeError("`unixTsMs` must be a 48-bit positive integer");
311
+ throw new RangeError("`unixTsMs` must be a 48-bit unsigned integer");
309
312
  }
310
313
  else if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) {
311
314
  throw new RangeError("`rollbackAllowance` out of reasonable range");
312
315
  }
313
- if (unixTsMs > this.timestamp) {
314
- this.timestamp = unixTsMs;
316
+ unixTsMs++;
317
+ if (unixTsMs > this.timestamp_biased) {
318
+ this.timestamp_biased = unixTsMs;
315
319
  this.resetCounter();
316
320
  }
317
- else if (unixTsMs + rollbackAllowance >= this.timestamp) {
321
+ else if (unixTsMs + rollbackAllowance >= this.timestamp_biased) {
318
322
  // go on with previous timestamp if new one is not much smaller
319
323
  this.counter++;
320
324
  if (this.counter > MAX_COUNTER) {
321
325
  // increment timestamp at counter overflow
322
- this.timestamp++;
326
+ this.timestamp_biased++;
323
327
  this.resetCounter();
324
328
  }
325
329
  }
@@ -327,7 +331,7 @@ class V7Generator {
327
331
  // abort if clock went backwards to unbearable extent
328
332
  return undefined;
329
333
  }
330
- return UUID.fromFieldsV7(this.timestamp, Math.trunc(this.counter / 2 ** 30), this.counter & (2 ** 30 - 1), this.random.nextUint32());
334
+ return UUID.fromFieldsV7(this.timestamp_biased - 1, Math.trunc(this.counter / 2 ** 30), this.counter & (2 ** 30 - 1), this.random.nextUint32());
331
335
  }
332
336
  /** Initializes the counter at a 42-bit random integer. */
333
337
  resetCounter() {
@@ -703,6 +707,9 @@ class JourniumClient {
703
707
  this.queue = [];
704
708
  this.stagedEvents = [];
705
709
  this.flushTimer = null;
710
+ this.remoteOptionsRefreshTimer = null;
711
+ this.isRefreshing = false;
712
+ this.lastRemoteOptions = null;
706
713
  this.initializationComplete = false;
707
714
  this.initializationFailed = false;
708
715
  this.optionsChangeCallbacks = new Set();
@@ -756,61 +763,24 @@ class JourniumClient {
756
763
  }
757
764
  }
758
765
  async initializeAsync() {
759
- var _a;
760
766
  try {
761
767
  Logger.log('Journium: Starting initialization - fetching fresh remote config...');
762
- // Step 1: Try to fetch fresh remote config with timeout and retry
763
768
  const remoteOptions = await this.fetchRemoteOptionsWithRetry();
764
- if (remoteOptions) {
765
- // Step 2: Cache the fresh remote config
766
- this.saveCachedOptions(remoteOptions);
767
- // Step 3: Merge local options over remote config (local overrides remote)
768
- if (this.config.options) {
769
- this.effectiveOptions = mergeOptions(this.config.options, remoteOptions);
770
- Logger.log('Journium: Using fresh remote config merged with local options:', this.effectiveOptions);
771
- }
772
- else {
773
- this.effectiveOptions = remoteOptions;
774
- Logger.log('Journium: Using fresh remote config:', this.effectiveOptions);
775
- }
776
- }
777
- else {
778
- // Step 4: Fallback to cached config if fresh fetch failed
779
- /* const cachedRemoteOptions = this.loadCachedOptions();
780
-
781
- if (cachedRemoteOptions) {
782
- if (this.config.options) {
783
- this.effectiveOptions = mergeOptions(this.config.options, cachedRemoteOptions);
784
- Logger.log('Journium: Fresh config failed, using cached remote config merged with local options:', this.effectiveOptions);
785
- } else {
786
- this.effectiveOptions = cachedRemoteOptions;
787
- Logger.log('Journium: Fresh config failed, using cached remote config:', this.effectiveOptions);
788
- }
789
- } else {
790
- // Step 5: No remote config and no cached config - initialization fails
791
- Logger.error('Journium: Initialization failed - no remote config available and no cached config found');
792
- this.initializationFailed = true;
793
- this.initializationComplete = false;
794
- return;
795
- } */
796
- }
797
- // Step 6: Update identity manager session timeout if provided
798
- if (this.effectiveOptions.sessionTimeout) {
799
- this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
769
+ if (!remoteOptions) {
770
+ Logger.error('Journium: Initialization failed - no remote config available');
771
+ this.initializationFailed = true;
772
+ return;
800
773
  }
801
- // Step 7: Update Logger debug setting
802
- Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
803
- // Step 8: Mark initialization as complete
774
+ this.applyRemoteOptions(remoteOptions);
775
+ Logger.log('Journium: Effective options after init:', this.effectiveOptions);
804
776
  this.initializationComplete = true;
805
777
  this.initializationFailed = false;
806
- // Step 9: Process any staged events
807
778
  this.processStagedEvents();
808
- // Step 10: Start flush timer
809
779
  if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
810
780
  this.startFlushTimer();
811
781
  }
812
- Logger.log('Journium: Initialization complete with options:', this.effectiveOptions);
813
- // Step 11: Notify callbacks about options
782
+ this.startRemoteOptionsRefreshTimer();
783
+ Logger.log('Journium: Initialization complete');
814
784
  this.notifyOptionsChange();
815
785
  }
816
786
  catch (error) {
@@ -881,35 +851,21 @@ class JourniumClient {
881
851
  processStagedEvents() {
882
852
  if (this.stagedEvents.length === 0)
883
853
  return;
854
+ if (this.ingestionPaused) {
855
+ Logger.warn(`Journium: Ingestion is paused — discarding ${this.stagedEvents.length} staged events`);
856
+ this.stagedEvents = [];
857
+ return;
858
+ }
884
859
  Logger.log(`Journium: Processing ${this.stagedEvents.length} staged events`);
885
- // Move staged events to main queue, adding identity properties now
886
- const identity = this.identityManager.getIdentity();
887
- const userAgentInfo = this.identityManager.getUserAgentInfo();
888
860
  for (const stagedEvent of this.stagedEvents) {
889
- // Add identity properties that weren't available during staging
890
- const eventWithIdentity = {
861
+ this.queue.push({
891
862
  ...stagedEvent,
892
- properties: {
893
- $device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
894
- distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
895
- $session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
896
- $is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
897
- $current_url: typeof window !== 'undefined' ? window.location.href : '',
898
- $pathname: typeof window !== 'undefined' ? window.location.pathname : '',
899
- ...userAgentInfo,
900
- $lib_version: '0.1.0', // TODO: Get from package.json
901
- $platform: 'web',
902
- ...stagedEvent.properties, // Original properties override system properties
903
- },
904
- };
905
- this.queue.push(eventWithIdentity);
863
+ properties: this.buildIdentityProperties(stagedEvent.properties),
864
+ });
906
865
  }
907
- // Clear staged events
908
866
  this.stagedEvents = [];
909
867
  Logger.log('Journium: Staged events processed and moved to main queue');
910
- // Check if we should flush immediately
911
868
  if (this.queue.length >= this.effectiveOptions.flushAt) {
912
- // console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
913
869
  this.flush();
914
870
  }
915
871
  }
@@ -917,12 +873,88 @@ class JourniumClient {
917
873
  if (this.flushTimer) {
918
874
  clearInterval(this.flushTimer);
919
875
  }
920
- // Use universal setInterval (works in both browser and Node.js)
921
876
  this.flushTimer = setInterval(() => {
922
- // console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
923
877
  this.flush();
924
878
  }, this.effectiveOptions.flushInterval);
925
879
  }
880
+ startRemoteOptionsRefreshTimer() {
881
+ // Clear any existing timer to prevent duplicate intervals
882
+ if (this.remoteOptionsRefreshTimer) {
883
+ clearInterval(this.remoteOptionsRefreshTimer);
884
+ this.remoteOptionsRefreshTimer = null;
885
+ }
886
+ this.remoteOptionsRefreshTimer = setInterval(() => {
887
+ this.refreshRemoteOptions();
888
+ }, JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL);
889
+ Logger.log(`Journium: Scheduling remote options refresh every ${JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL}ms`);
890
+ }
891
+ async refreshRemoteOptions() {
892
+ if (this.isRefreshing) {
893
+ Logger.log('Journium: Remote options refresh already in progress, skipping');
894
+ return;
895
+ }
896
+ this.isRefreshing = true;
897
+ Logger.log('Journium: Periodic remote options refresh triggered');
898
+ try {
899
+ const remoteOptions = await this.fetchRemoteOptionsWithRetry();
900
+ if (!remoteOptions) {
901
+ Logger.warn('Journium: Periodic remote options refresh failed, keeping current options');
902
+ return;
903
+ }
904
+ const prevRemoteSnapshot = JSON.stringify(this.lastRemoteOptions);
905
+ const prevFlushInterval = this.effectiveOptions.flushInterval;
906
+ this.applyRemoteOptions(remoteOptions);
907
+ if (prevRemoteSnapshot === JSON.stringify(this.lastRemoteOptions)) {
908
+ Logger.log('Journium: Remote options unchanged after refresh, no update needed');
909
+ return;
910
+ }
911
+ Logger.log('Journium: Remote options updated after refresh:', this.effectiveOptions);
912
+ if (this.effectiveOptions.flushInterval !== prevFlushInterval) {
913
+ if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
914
+ this.startFlushTimer();
915
+ }
916
+ else if (this.flushTimer) {
917
+ clearInterval(this.flushTimer);
918
+ this.flushTimer = null;
919
+ }
920
+ }
921
+ this.notifyOptionsChange();
922
+ }
923
+ catch (error) {
924
+ Logger.error('Journium: Periodic remote options refresh encountered an error:', error);
925
+ }
926
+ finally {
927
+ this.isRefreshing = false;
928
+ }
929
+ }
930
+ applyRemoteOptions(remoteOptions) {
931
+ var _a;
932
+ this.lastRemoteOptions = remoteOptions;
933
+ this.effectiveOptions = this.config.options
934
+ ? mergeOptions(this.config.options, remoteOptions)
935
+ : remoteOptions;
936
+ this.saveCachedOptions(remoteOptions);
937
+ if (this.effectiveOptions.sessionTimeout) {
938
+ this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
939
+ }
940
+ Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
941
+ }
942
+ buildIdentityProperties(userProperties = {}) {
943
+ const identity = this.identityManager.getIdentity();
944
+ const userAgentInfo = this.identityManager.getUserAgentInfo();
945
+ return {
946
+ $device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
947
+ distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
948
+ $session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
949
+ $is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
950
+ $current_url: typeof window !== 'undefined' ? window.location.href : '',
951
+ $pathname: typeof window !== 'undefined' ? window.location.pathname : '',
952
+ ...userAgentInfo,
953
+ $lib_version: '0.1.0', // TODO: Get from package.json
954
+ $platform: 'web',
955
+ ...userProperties,
956
+ };
957
+ }
926
958
  async sendEvents(events) {
927
959
  if (!events.length)
928
960
  return;
@@ -982,9 +1014,7 @@ class JourniumClient {
982
1014
  event,
983
1015
  properties: { ...properties }, // Only user properties for now
984
1016
  };
985
- // Stage events during initialization, add to queue after initialization
986
1017
  if (!this.initializationComplete) {
987
- // If initialization failed, reject events
988
1018
  if (this.initializationFailed) {
989
1019
  Logger.warn('Journium: track() call rejected - initialization failed');
990
1020
  return;
@@ -993,34 +1023,17 @@ class JourniumClient {
993
1023
  Logger.log('Journium: Event staged during initialization', journiumEvent);
994
1024
  return;
995
1025
  }
996
- // If initialization failed, reject events
997
- if (this.initializationFailed) {
998
- Logger.warn('Journium: track() call rejected - initialization failed');
1026
+ if (this.ingestionPaused) {
1027
+ Logger.warn('Journium: Ingestion is paused — event dropped:', journiumEvent.event);
999
1028
  return;
1000
1029
  }
1001
- // Add identity properties for immediate events (after initialization)
1002
- const identity = this.identityManager.getIdentity();
1003
- const userAgentInfo = this.identityManager.getUserAgentInfo();
1004
1030
  const eventWithIdentity = {
1005
1031
  ...journiumEvent,
1006
- properties: {
1007
- $device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
1008
- distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
1009
- $session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
1010
- $is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
1011
- $current_url: typeof window !== 'undefined' ? window.location.href : '',
1012
- $pathname: typeof window !== 'undefined' ? window.location.pathname : '',
1013
- ...userAgentInfo,
1014
- $lib_version: '0.1.0', // TODO: Get from package.json
1015
- $platform: 'web',
1016
- ...properties, // User-provided properties override system properties
1017
- },
1032
+ properties: this.buildIdentityProperties(properties),
1018
1033
  };
1019
1034
  this.queue.push(eventWithIdentity);
1020
1035
  Logger.log('Journium: Event tracked', eventWithIdentity);
1021
- // Only flush if we have effective options (after initialization)
1022
1036
  if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
1023
- // console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
1024
1037
  this.flush();
1025
1038
  }
1026
1039
  }
@@ -1047,12 +1060,20 @@ class JourniumClient {
1047
1060
  clearInterval(this.flushTimer);
1048
1061
  this.flushTimer = null;
1049
1062
  }
1063
+ if (this.remoteOptionsRefreshTimer) {
1064
+ clearInterval(this.remoteOptionsRefreshTimer);
1065
+ this.remoteOptionsRefreshTimer = null;
1066
+ }
1050
1067
  this.flush();
1051
1068
  }
1052
1069
  getEffectiveOptions() {
1053
1070
  return this.effectiveOptions;
1054
1071
  }
1072
+ get ingestionPaused() {
1073
+ return this.effectiveOptions['ingestionPaused'] === true;
1074
+ }
1055
1075
  }
1076
+ JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes
1056
1077
 
1057
1078
  class PageviewTracker {
1058
1079
  constructor(client) {
@@ -1079,10 +1100,13 @@ class PageviewTracker {
1079
1100
  }
1080
1101
  /**
1081
1102
  * Start automatic autocapture for pageviews
1082
- * @returns void
1103
+ * @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
1104
+ * Pass false when restarting after a remote options update to avoid a spurious pageview.
1083
1105
  */
1084
- startAutoPageviewTracking() {
1085
- this.capturePageview();
1106
+ startAutoPageviewTracking(captureInitialPageview = true) {
1107
+ if (captureInitialPageview) {
1108
+ this.capturePageview();
1109
+ }
1086
1110
  if (typeof window !== 'undefined') {
1087
1111
  // Store original methods for cleanup
1088
1112
  this.originalPushState = window.history.pushState;
@@ -1601,21 +1625,22 @@ class JourniumAnalytics {
1601
1625
  * Handle effective options change (e.g., when remote options are fetched)
1602
1626
  */
1603
1627
  handleOptionsChange(effectiveOptions) {
1604
- // Stop current autocapture if it was already started
1628
+ // If autocapture was never started before, this is the initial options application
1629
+ // (async init completed) — treat it like a page load and capture a pageview.
1630
+ // If it was already started, this is a periodic remote options update — only
1631
+ // re-register listeners without emitting a spurious pageview.
1632
+ const isFirstStart = !this.autocaptureStarted;
1605
1633
  if (this.autocaptureStarted) {
1606
1634
  this.pageviewTracker.stopAutocapture();
1607
1635
  this.autocaptureTracker.stop();
1608
1636
  this.autocaptureStarted = false;
1609
1637
  }
1610
- // Evaluate if autocapture should be enabled with new options
1611
1638
  const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1612
1639
  const autocaptureEnabled = effectiveOptions.autocapture !== false;
1613
- // Update autocapture tracker options
1614
1640
  const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1615
1641
  this.autocaptureTracker.updateOptions(autocaptureOptions);
1616
- // Start autocapture based on new options (even if it wasn't started before)
1617
1642
  if (autoTrackPageviews) {
1618
- this.pageviewTracker.startAutoPageviewTracking();
1643
+ this.pageviewTracker.startAutoPageviewTracking(isFirstStart);
1619
1644
  }
1620
1645
  if (autocaptureEnabled) {
1621
1646
  this.autocaptureTracker.start();