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