@amplifyup/sdk 0.1.24 → 0.1.25

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.
@@ -348,6 +348,10 @@ function isComposerPreview() {
348
348
 
349
349
  // src/index.ts
350
350
  var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
351
+ var DWELL_MILESTONES_SEC = [15, 30, 60, 120, 300];
352
+ var DWELL_CHECKPOINT_SEC = 15 * 60;
353
+ var DWELL_ACTIVITY_IDLE_MS = 2 * 60 * 1e3;
354
+ var DWELL_POLL_MS = 5e3;
351
355
  function readPreviewQueryOverrides() {
352
356
  if (typeof window === "undefined") return {};
353
357
  const params = new URLSearchParams(window.location.search);
@@ -418,7 +422,10 @@ var AmplifyUpSDK = class {
418
422
  visibleSince: null,
419
423
  lastDwellSecondsSent: 0,
420
424
  /** When the tab last became hidden — used for idle-resume re-page. */
421
- hiddenAt: null
425
+ hiddenAt: null,
426
+ /** Last user interaction — freezes dwell when stale while visible. */
427
+ lastActivityAt: 0,
428
+ activityIdle: false
422
429
  };
423
430
  this.adapter = adapter || new AWSAdapter();
424
431
  if (typeof window !== "undefined") {
@@ -641,8 +648,10 @@ var AmplifyUpSDK = class {
641
648
  return window.location.pathname || "/";
642
649
  }
643
650
  /**
644
- * Automatic page-level Scroll Depth + Time on Page (dwell heartbeat).
645
- * State lives on the instance so SPA route changes can reset milestones.
651
+ * Automatic page-level Scroll Depth + Time on Page.
652
+ * Dwell uses milestones / sparse checkpoints (not a fixed 15s heartbeat),
653
+ * freezes while the tab is visible but the user is idle, and always flushes
654
+ * on hide / unload / SPA route change.
646
655
  */
647
656
  setupPageEngagement() {
648
657
  if (typeof window === "undefined" || typeof document === "undefined") return;
@@ -655,6 +664,8 @@ var AmplifyUpSDK = class {
655
664
  state.visibleSince = document.visibilityState === "visible" ? Date.now() : null;
656
665
  state.lastDwellSecondsSent = 0;
657
666
  state.hiddenAt = document.visibilityState === "hidden" ? Date.now() : null;
667
+ state.lastActivityAt = Date.now();
668
+ state.activityIdle = false;
658
669
  let scrollRaf = null;
659
670
  const path = () => this.currentPath();
660
671
  const measureScrollPercent = () => {
@@ -686,6 +697,7 @@ var AmplifyUpSDK = class {
686
697
  }
687
698
  };
688
699
  const onScroll = () => {
700
+ noteActivity();
689
701
  if (scrollRaf != null) return;
690
702
  scrollRaf = window.requestAnimationFrame(() => {
691
703
  scrollRaf = null;
@@ -697,19 +709,58 @@ var AmplifyUpSDK = class {
697
709
  state.visibleMs += Date.now() - state.visibleSince;
698
710
  state.visibleSince = Date.now();
699
711
  };
700
- const emitDwell = (_force = false) => {
701
- if (this.isPreviewMode()) return;
712
+ const freezeActivityIdle = () => {
713
+ if (state.activityIdle) return;
702
714
  accumulateVisible();
715
+ state.visibleSince = null;
716
+ state.activityIdle = true;
717
+ };
718
+ const noteActivity = () => {
719
+ state.lastActivityAt = Date.now();
720
+ if (state.activityIdle) {
721
+ state.activityIdle = false;
722
+ if (document.visibilityState === "visible" && state.visibleSince == null) {
723
+ state.visibleSince = Date.now();
724
+ }
725
+ }
726
+ };
727
+ const nextEmitTarget = (lastSent) => {
728
+ for (const m of DWELL_MILESTONES_SEC) {
729
+ if (m > lastSent) return { seconds: m, reason: "milestone" };
730
+ }
731
+ const nextCheckpoint = Math.floor(lastSent / DWELL_CHECKPOINT_SEC) * DWELL_CHECKPOINT_SEC + DWELL_CHECKPOINT_SEC;
732
+ const target = nextCheckpoint > lastSent ? nextCheckpoint : lastSent + DWELL_CHECKPOINT_SEC;
733
+ return { seconds: target, reason: "checkpoint" };
734
+ };
735
+ const emitDwell = (reason, force = false) => {
736
+ if (this.isPreviewMode()) return;
737
+ if (!state.activityIdle) {
738
+ accumulateVisible();
739
+ }
703
740
  const seconds = Math.floor(state.visibleMs / 1e3);
704
741
  if (seconds <= 0) return;
705
742
  if (seconds <= state.lastDwellSecondsSent) return;
743
+ if (!force) {
744
+ const target = nextEmitTarget(state.lastDwellSecondsSent);
745
+ if (!target || seconds < target.seconds) return;
746
+ reason = target.reason;
747
+ }
706
748
  state.lastDwellSecondsSent = seconds;
707
749
  this.track("Time on Page", {
708
750
  seconds,
709
- path: this.lastTrackedPath || path()
751
+ path: this.lastTrackedPath || path(),
752
+ reason
710
753
  });
711
754
  };
712
- this._emitPageDwell = emitDwell;
755
+ const evaluateDwell = () => {
756
+ if (document.visibilityState !== "visible") return;
757
+ if (Date.now() - state.lastActivityAt >= DWELL_ACTIVITY_IDLE_MS) {
758
+ freezeActivityIdle();
759
+ return;
760
+ }
761
+ emitDwell("milestone", false);
762
+ };
763
+ this._emitPageDwell = (force) => emitDwell("route", force !== false);
713
764
  const onVisibility = () => {
714
765
  if (document.visibilityState === "visible") {
715
766
  const idleMs = state.hiddenAt != null ? Date.now() - state.hiddenAt : 0;
@@ -727,35 +778,51 @@ var AmplifyUpSDK = class {
727
778
  );
728
779
  }
729
780
  }
781
+ noteActivity();
730
782
  state.visibleSince = Date.now();
783
+ state.activityIdle = false;
731
784
  } else {
732
- emitDwell(true);
785
+ emitDwell("hidden", true);
733
786
  state.hiddenAt = Date.now();
734
787
  state.visibleSince = null;
788
+ state.activityIdle = false;
735
789
  }
736
790
  };
737
791
  const onPageHide = () => {
738
- emitDwell(true);
792
+ emitDwell("unload", true);
739
793
  if (state.hiddenAt == null) {
740
794
  state.hiddenAt = Date.now();
741
795
  }
742
796
  state.visibleSince = null;
743
797
  };
798
+ const activityEvents = [
799
+ "pointerdown",
800
+ "keydown",
801
+ "scroll",
802
+ "touchstart"
803
+ ];
804
+ const onActivity = () => noteActivity();
744
805
  window.addEventListener("scroll", onScroll, { passive: true });
745
806
  document.addEventListener("visibilitychange", onVisibility);
746
807
  window.addEventListener("pagehide", onPageHide);
808
+ for (const evt of activityEvents) {
809
+ if (evt === "scroll") continue;
810
+ window.addEventListener(evt, onActivity, { passive: true });
811
+ }
747
812
  checkScroll();
748
813
  const heartbeat = setInterval(() => {
749
- if (document.visibilityState === "visible") {
750
- emitDwell(false);
751
- }
752
- }, 15e3);
814
+ evaluateDwell();
815
+ }, DWELL_POLL_MS);
753
816
  this.trackingIntervals.push(heartbeat);
754
817
  const previousCleanup = this.trackingCleanup;
755
818
  this.trackingCleanup = () => {
756
819
  window.removeEventListener("scroll", onScroll);
757
820
  document.removeEventListener("visibilitychange", onVisibility);
758
821
  window.removeEventListener("pagehide", onPageHide);
822
+ for (const evt of activityEvents) {
823
+ if (evt === "scroll") continue;
824
+ window.removeEventListener(evt, onActivity);
825
+ }
759
826
  if (scrollRaf != null) {
760
827
  window.cancelAnimationFrame(scrollRaf);
761
828
  scrollRaf = null;
@@ -781,6 +848,8 @@ var AmplifyUpSDK = class {
781
848
  state.visibleMs = 0;
782
849
  state.lastDwellSecondsSent = 0;
783
850
  state.hiddenAt = null;
851
+ state.lastActivityAt = Date.now();
852
+ state.activityIdle = false;
784
853
  state.visibleSince = typeof document !== "undefined" && document.visibilityState === "visible" ? Date.now() : null;
785
854
  this.componentViewSeen.clear();
786
855
  }