@amplifyup/sdk 0.1.24 → 0.1.26

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.
package/dist/index.mjs CHANGED
@@ -47,7 +47,10 @@ var AWSAdapter = class {
47
47
  headers: {
48
48
  "Content-Type": "application/json"
49
49
  },
50
- body: JSON.stringify(eventData)
50
+ body: JSON.stringify(eventData),
51
+ // Keep the request alive through tab close so the single Time on Page
52
+ // flush on pagehide is not cancelled with the document.
53
+ keepalive: true
51
54
  });
52
55
  if (!response.ok) {
53
56
  if (this.config.debug) {
@@ -506,6 +509,8 @@ async function fetchContent(options) {
506
509
 
507
510
  // src/index.ts
508
511
  var SESSION_IDLE_GAP_MS = 30 * 60 * 1e3;
512
+ var DWELL_ACTIVITY_IDLE_MS = 2 * 60 * 1e3;
513
+ var DWELL_POLL_MS = 5e3;
509
514
  function readPreviewQueryOverrides() {
510
515
  if (typeof window === "undefined") return {};
511
516
  const params = new URLSearchParams(window.location.search);
@@ -574,9 +579,13 @@ var AmplifyUpSDK = class {
574
579
  reached: /* @__PURE__ */ new Set(),
575
580
  visibleMs: 0,
576
581
  visibleSince: null,
577
- lastDwellSecondsSent: 0,
582
+ /** True after Time on Page has been sent for the current visit. */
583
+ dwellEmitted: false,
578
584
  /** When the tab last became hidden — used for idle-resume re-page. */
579
- hiddenAt: null
585
+ hiddenAt: null,
586
+ /** Last user interaction — freezes dwell when stale while visible. */
587
+ lastActivityAt: 0,
588
+ activityIdle: false
580
589
  };
581
590
  this.adapter = adapter || new AWSAdapter();
582
591
  if (typeof window !== "undefined") {
@@ -799,8 +808,10 @@ var AmplifyUpSDK = class {
799
808
  return window.location.pathname || "/";
800
809
  }
801
810
  /**
802
- * Automatic page-level Scroll Depth + Time on Page (dwell heartbeat).
803
- * State lives on the instance so SPA route changes can reset milestones.
811
+ * Automatic page-level Scroll Depth + Time on Page.
812
+ * Time on Page fires once per visit when the visit ends (route change,
813
+ * tab close, or 30-minute idle resume). Hidden tabs pause the clock;
814
+ * visible-but-idle tabs freeze after DWELL_ACTIVITY_IDLE_MS.
804
815
  */
805
816
  setupPageEngagement() {
806
817
  if (typeof window === "undefined" || typeof document === "undefined") return;
@@ -811,8 +822,10 @@ var AmplifyUpSDK = class {
811
822
  state.reached = /* @__PURE__ */ new Set();
812
823
  state.visibleMs = 0;
813
824
  state.visibleSince = document.visibilityState === "visible" ? Date.now() : null;
814
- state.lastDwellSecondsSent = 0;
825
+ state.dwellEmitted = false;
815
826
  state.hiddenAt = document.visibilityState === "hidden" ? Date.now() : null;
827
+ state.lastActivityAt = Date.now();
828
+ state.activityIdle = false;
816
829
  let scrollRaf = null;
817
830
  const path = () => this.currentPath();
818
831
  const measureScrollPercent = () => {
@@ -844,6 +857,7 @@ var AmplifyUpSDK = class {
844
857
  }
845
858
  };
846
859
  const onScroll = () => {
860
+ noteActivity();
847
861
  if (scrollRaf != null) return;
848
862
  scrollRaf = window.requestAnimationFrame(() => {
849
863
  scrollRaf = null;
@@ -855,24 +869,49 @@ var AmplifyUpSDK = class {
855
869
  state.visibleMs += Date.now() - state.visibleSince;
856
870
  state.visibleSince = Date.now();
857
871
  };
858
- const emitDwell = (_force = false) => {
859
- if (this.isPreviewMode()) return;
872
+ const freezeActivityIdle = () => {
873
+ if (state.activityIdle) return;
860
874
  accumulateVisible();
875
+ state.visibleSince = null;
876
+ state.activityIdle = true;
877
+ };
878
+ const noteActivity = () => {
879
+ state.lastActivityAt = Date.now();
880
+ if (state.activityIdle) {
881
+ state.activityIdle = false;
882
+ if (document.visibilityState === "visible" && state.visibleSince == null) {
883
+ state.visibleSince = Date.now();
884
+ }
885
+ }
886
+ };
887
+ const emitDwell = (reason) => {
888
+ if (this.isPreviewMode()) return;
889
+ if (state.dwellEmitted) return;
890
+ if (!state.activityIdle) {
891
+ accumulateVisible();
892
+ }
861
893
  const seconds = Math.floor(state.visibleMs / 1e3);
862
894
  if (seconds <= 0) return;
863
- if (seconds <= state.lastDwellSecondsSent) return;
864
- state.lastDwellSecondsSent = seconds;
895
+ state.dwellEmitted = true;
865
896
  this.track("Time on Page", {
866
897
  seconds,
867
- path: this.lastTrackedPath || path()
898
+ path: this.lastTrackedPath || path(),
899
+ reason
868
900
  });
869
901
  };
870
- this._emitPageDwell = emitDwell;
902
+ const evaluateIdle = () => {
903
+ if (document.visibilityState !== "visible") return;
904
+ if (Date.now() - state.lastActivityAt >= DWELL_ACTIVITY_IDLE_MS) {
905
+ freezeActivityIdle();
906
+ }
907
+ };
908
+ this._emitPageDwell = () => emitDwell("route");
871
909
  const onVisibility = () => {
872
910
  if (document.visibilityState === "visible") {
873
911
  const idleMs = state.hiddenAt != null ? Date.now() - state.hiddenAt : 0;
874
912
  state.hiddenAt = null;
875
913
  if (idleMs >= SESSION_IDLE_GAP_MS) {
914
+ emitDwell("idle-resume");
876
915
  this.resetEngagementQuiet();
877
916
  const resumePath = path();
878
917
  this.page(resumePath, { resumed: true });
@@ -885,35 +924,51 @@ var AmplifyUpSDK = class {
885
924
  );
886
925
  }
887
926
  }
927
+ noteActivity();
888
928
  state.visibleSince = Date.now();
929
+ state.activityIdle = false;
889
930
  } else {
890
- emitDwell(true);
931
+ accumulateVisible();
891
932
  state.hiddenAt = Date.now();
892
933
  state.visibleSince = null;
934
+ state.activityIdle = false;
893
935
  }
894
936
  };
895
937
  const onPageHide = () => {
896
- emitDwell(true);
938
+ emitDwell("unload");
897
939
  if (state.hiddenAt == null) {
898
940
  state.hiddenAt = Date.now();
899
941
  }
900
942
  state.visibleSince = null;
901
943
  };
944
+ const activityEvents = [
945
+ "pointerdown",
946
+ "keydown",
947
+ "scroll",
948
+ "touchstart"
949
+ ];
950
+ const onActivity = () => noteActivity();
902
951
  window.addEventListener("scroll", onScroll, { passive: true });
903
952
  document.addEventListener("visibilitychange", onVisibility);
904
953
  window.addEventListener("pagehide", onPageHide);
954
+ for (const evt of activityEvents) {
955
+ if (evt === "scroll") continue;
956
+ window.addEventListener(evt, onActivity, { passive: true });
957
+ }
905
958
  checkScroll();
906
- const heartbeat = setInterval(() => {
907
- if (document.visibilityState === "visible") {
908
- emitDwell(false);
909
- }
910
- }, 15e3);
911
- this.trackingIntervals.push(heartbeat);
959
+ const idlePoll = setInterval(() => {
960
+ evaluateIdle();
961
+ }, DWELL_POLL_MS);
962
+ this.trackingIntervals.push(idlePoll);
912
963
  const previousCleanup = this.trackingCleanup;
913
964
  this.trackingCleanup = () => {
914
965
  window.removeEventListener("scroll", onScroll);
915
966
  document.removeEventListener("visibilitychange", onVisibility);
916
967
  window.removeEventListener("pagehide", onPageHide);
968
+ for (const evt of activityEvents) {
969
+ if (evt === "scroll") continue;
970
+ window.removeEventListener(evt, onActivity);
971
+ }
917
972
  if (scrollRaf != null) {
918
973
  window.cancelAnimationFrame(scrollRaf);
919
974
  scrollRaf = null;
@@ -932,13 +987,15 @@ var AmplifyUpSDK = class {
932
987
  emit?.(true);
933
988
  this.resetEngagementQuiet();
934
989
  }
935
- /** Reset dwell/scroll state without emitting (idle resume already flushed on hide). */
990
+ /** Reset dwell/scroll state without emitting (idle resume already flushed). */
936
991
  resetEngagementQuiet() {
937
992
  const state = this.pageEngagementState;
938
993
  state.reached = /* @__PURE__ */ new Set();
939
994
  state.visibleMs = 0;
940
- state.lastDwellSecondsSent = 0;
995
+ state.dwellEmitted = false;
941
996
  state.hiddenAt = null;
997
+ state.lastActivityAt = Date.now();
998
+ state.activityIdle = false;
942
999
  state.visibleSince = typeof document !== "undefined" && document.visibilityState === "visible" ? Date.now() : null;
943
1000
  this.componentViewSeen.clear();
944
1001
  }
@@ -2688,6 +2745,6 @@ var verifyAWSConnection = () => {
2688
2745
  };
2689
2746
  var index_default = getSDK();
2690
2747
 
2691
- export { AmplifyUpSDK, EdgeResolveError, SESSION_IDLE_GAP_MS, buildLayoutProviderUrl, buildPageRenderUrl, cleanupEventTracking, index_default as default, fetchContent, fetchEdgeResolve, fetchPageConfig, getDiagnostics, getInstanceId2 as getInstanceId, getOrchestratorUrl, getSDK, getStatus, getTarget, getTrackingId, getUserId2 as getUserId, identify, init, isAmplifyUpTarget, isComposerPreview, isPreviewRequest, mapResolvedToPageConfig, normalizeAmplifyUpTarget, normalizeRoute, page, refreshEventTracking, reset, resolveAmplifyUpTarget, resolveAmplifyUpUrls, routeChange, setProfileFields, setupComponentViewTracking, setupEventTracking, testTracking, track, trackClick, trackContentEngagement, trackContentView, trackFormFieldInteraction, trackFormSubmit, verifyAWSConnection };
2748
+ export { AmplifyUpSDK, DWELL_ACTIVITY_IDLE_MS, EdgeResolveError, SESSION_IDLE_GAP_MS, buildLayoutProviderUrl, buildPageRenderUrl, cleanupEventTracking, index_default as default, fetchContent, fetchEdgeResolve, fetchPageConfig, getDiagnostics, getInstanceId2 as getInstanceId, getOrchestratorUrl, getSDK, getStatus, getTarget, getTrackingId, getUserId2 as getUserId, identify, init, isAmplifyUpTarget, isComposerPreview, isPreviewRequest, mapResolvedToPageConfig, normalizeAmplifyUpTarget, normalizeRoute, page, refreshEventTracking, reset, resolveAmplifyUpTarget, resolveAmplifyUpUrls, routeChange, setProfileFields, setupComponentViewTracking, setupEventTracking, testTracking, track, trackClick, trackContentEngagement, trackContentView, trackFormFieldInteraction, trackFormSubmit, verifyAWSConnection };
2692
2749
  //# sourceMappingURL=index.mjs.map
2693
2750
  //# sourceMappingURL=index.mjs.map