saltfish 0.3.2 → 0.3.4

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.
@@ -956,7 +956,7 @@ const STORAGE_KEYS = {
956
956
  SESSION: "saltfish_session",
957
957
  ANONYMOUS_USER: "saltfish_anonymous_user_data"
958
958
  };
959
- const TIMING = {
959
+ const TIMING$1 = {
960
960
  // 5 seconds
961
961
  STEP_TIMEOUT: 12e4,
962
962
  // Session persistence
@@ -982,12 +982,29 @@ const CSS_CLASSES = {
982
982
  ERROR_DISPLAY_MESSAGE: "sf-error-display__message",
983
983
  LOADING_SPINNER: "sf-loading-spinner"
984
984
  };
985
- class StorageManager {
985
+ const _StorageManager = class _StorageManager {
986
986
  constructor() {
987
987
  __publicField(this, "isLocalStorageAvailable");
988
988
  this.isLocalStorageAvailable = this.checkLocalStorageAvailability();
989
989
  if (!this.isLocalStorageAvailable) ;
990
990
  }
991
+ /**
992
+ * Get the singleton instance of StorageManager
993
+ * @returns The StorageManager instance
994
+ */
995
+ static getInstance() {
996
+ if (!_StorageManager.instance) {
997
+ _StorageManager.instance = new _StorageManager();
998
+ }
999
+ return _StorageManager.instance;
1000
+ }
1001
+ /**
1002
+ * Reset the singleton instance (useful for testing)
1003
+ * @internal
1004
+ */
1005
+ static resetInstance() {
1006
+ _StorageManager.instance = null;
1007
+ }
991
1008
  /**
992
1009
  * Check if localStorage is available and working
993
1010
  */
@@ -1223,8 +1240,10 @@ class StorageManager {
1223
1240
  keys
1224
1241
  };
1225
1242
  }
1226
- }
1227
- const storageManager = new StorageManager();
1243
+ };
1244
+ __publicField(_StorageManager, "instance", null);
1245
+ let StorageManager = _StorageManager;
1246
+ const storageManager = StorageManager.getInstance();
1228
1247
  const createInitialContext = () => ({
1229
1248
  currentStep: null,
1230
1249
  error: null
@@ -6147,6 +6166,24 @@ class VideoManager {
6147
6166
  this.soundbarElement = null;
6148
6167
  }
6149
6168
  }
6169
+ const ANALYTICS = {
6170
+ /** Interval for flushing analytics events to the backend (30 seconds) */
6171
+ FLUSH_INTERVAL_MS: 3e4
6172
+ };
6173
+ const TIMING = {
6174
+ /** Delay for DOM stabilization before cursor operations (0.5 seconds) */
6175
+ DOM_STABILIZATION_DELAY_MS: 500,
6176
+ /** Delay for state processing operations (100 milliseconds) */
6177
+ STATE_PROCESSING_DELAY_MS: 100,
6178
+ /** Interval for checking URL path changes (5 seconds) */
6179
+ URL_PATH_CHECK_INTERVAL_MS: 5e3,
6180
+ /** Retry delay for failed operations (0.5 seconds) */
6181
+ RETRY_DELAY_MS: 500
6182
+ };
6183
+ const THRESHOLDS = {
6184
+ /** Minimum scroll distance in pixels to trigger scroll events */
6185
+ SCROLL_THRESHOLD_PX: 10
6186
+ };
6150
6187
  class CursorManager {
6151
6188
  constructor() {
6152
6189
  __publicField(this, "cursor", null);
@@ -6799,7 +6836,7 @@ class CursorManager {
6799
6836
  console.warn("CursorManager: No targetSelector provided in animation");
6800
6837
  return;
6801
6838
  }
6802
- await new Promise((resolve) => setTimeout(resolve, 500));
6839
+ await new Promise((resolve) => setTimeout(resolve, TIMING.DOM_STABILIZATION_DELAY_MS));
6803
6840
  if (this.isAutoplayBlocked()) {
6804
6841
  return;
6805
6842
  }
@@ -7425,7 +7462,7 @@ class InteractionManager {
7425
7462
  __publicField(this, "scrollIndicator", null);
7426
7463
  __publicField(this, "domEventListeners", /* @__PURE__ */ new Map());
7427
7464
  __publicField(this, "storeUnsubscribe", null);
7428
- __publicField(this, "storageManager", new StorageManager());
7465
+ __publicField(this, "storageManager", StorageManager.getInstance());
7429
7466
  /**
7430
7467
  * Handles the video90PercentReached event
7431
7468
  * @param _event - The custom event dispatched when video reaches 90%
@@ -7528,7 +7565,7 @@ class InteractionManager {
7528
7565
  const scrollHeight = container.scrollHeight;
7529
7566
  const scrollTop = container.scrollTop;
7530
7567
  const clientHeight = container.clientHeight;
7531
- if (scrollHeight - scrollTop - clientHeight < 10) {
7568
+ if (scrollHeight - scrollTop - clientHeight < THRESHOLDS.SCROLL_THRESHOLD_PX) {
7532
7569
  this.scrollIndicator.classList.add("sf-scroll-indicator--hidden");
7533
7570
  } else {
7534
7571
  this.scrollIndicator.classList.remove("sf-scroll-indicator--hidden");
@@ -7731,12 +7768,12 @@ class InteractionManager {
7731
7768
  await this.flushAnalytics();
7732
7769
  if (store.currentState === "completedWaitingForInteraction") {
7733
7770
  store.completePlaylist();
7734
- await new Promise((resolve) => setTimeout(resolve, 100));
7771
+ await new Promise((resolve) => setTimeout(resolve, TIMING.STATE_PROCESSING_DELAY_MS));
7735
7772
  } else {
7736
7773
  const isLastStep = this.isCurrentStepLast(store);
7737
7774
  if (isLastStep) {
7738
7775
  store.goToStep("completed");
7739
- await new Promise((resolve) => setTimeout(resolve, 100));
7776
+ await new Promise((resolve) => setTimeout(resolve, TIMING.STATE_PROCESSING_DELAY_MS));
7740
7777
  }
7741
7778
  }
7742
7779
  window.open(buttonConfig.action.target, "_blank");
@@ -7752,7 +7789,7 @@ class InteractionManager {
7752
7789
  await this.flushAnalytics();
7753
7790
  log("InteractionManager: Completing current playlist before starting new one");
7754
7791
  store.completePlaylist();
7755
- await new Promise((resolve) => setTimeout(resolve, 100));
7792
+ await new Promise((resolve) => setTimeout(resolve, TIMING.STATE_PROCESSING_DELAY_MS));
7756
7793
  const { SaltfishPlayer: SaltfishPlayer22 } = await Promise.resolve().then(() => SaltfishPlayer$1);
7757
7794
  const player2 = SaltfishPlayer22.getInstance();
7758
7795
  if (player2) {
@@ -7867,6 +7904,13 @@ class InteractionManager {
7867
7904
  this.container = null;
7868
7905
  }
7869
7906
  }
7907
+ function getSaltfishStore() {
7908
+ try {
7909
+ return useSaltfishStore.getState();
7910
+ } catch (error2) {
7911
+ return null;
7912
+ }
7913
+ }
7870
7914
  class AnalyticsManager {
7871
7915
  // Default to enabled
7872
7916
  /**
@@ -7902,7 +7946,7 @@ class AnalyticsManager {
7902
7946
  return;
7903
7947
  }
7904
7948
  this.eventManager.on("playerPaused", (_) => {
7905
- const store = this.getStore();
7949
+ const store = getSaltfishStore();
7906
7950
  const runId = this.getRunId();
7907
7951
  if ((store == null ? void 0 : store.manifest) && store.currentStepId && runId) {
7908
7952
  this.trackEvent({
@@ -7915,7 +7959,7 @@ class AnalyticsManager {
7915
7959
  }
7916
7960
  });
7917
7961
  this.eventManager.on("playerResumed", (_) => {
7918
- const store = this.getStore();
7962
+ const store = getSaltfishStore();
7919
7963
  const runId = this.getRunId();
7920
7964
  if ((store == null ? void 0 : store.manifest) && store.currentStepId && runId) {
7921
7965
  this.trackEvent({
@@ -7954,7 +7998,7 @@ class AnalyticsManager {
7954
7998
  }
7955
7999
  });
7956
8000
  this.eventManager.on("playerMinimized", (_) => {
7957
- const store = this.getStore();
8001
+ const store = getSaltfishStore();
7958
8002
  const runId = this.getRunId();
7959
8003
  if ((store == null ? void 0 : store.manifest) && store.currentStepId && runId) {
7960
8004
  this.trackEvent({
@@ -7967,7 +8011,7 @@ class AnalyticsManager {
7967
8011
  }
7968
8012
  });
7969
8013
  this.eventManager.on("playerMaximized", (_) => {
7970
- const store = this.getStore();
8014
+ const store = getSaltfishStore();
7971
8015
  const runId = this.getRunId();
7972
8016
  if ((store == null ? void 0 : store.manifest) && store.currentStepId && runId) {
7973
8017
  this.trackEvent({
@@ -7980,17 +8024,6 @@ class AnalyticsManager {
7980
8024
  }
7981
8025
  });
7982
8026
  }
7983
- /**
7984
- * Helper to get the store state when needed
7985
- */
7986
- getStore() {
7987
- try {
7988
- return useSaltfishStore.getState();
7989
- } catch (error2) {
7990
- console.error("Failed to access store:", error2);
7991
- return null;
7992
- }
7993
- }
7994
8027
  /**
7995
8028
  * Initializes the analytics manager
7996
8029
  * @param config - Saltfish configuration
@@ -8005,7 +8038,7 @@ class AnalyticsManager {
8005
8038
  if (this.analyticsEnabled) {
8006
8039
  this.flushInterval = window.setInterval(() => {
8007
8040
  this.flushEvents();
8008
- }, 3e4);
8041
+ }, ANALYTICS.FLUSH_INTERVAL_MS);
8009
8042
  }
8010
8043
  }
8011
8044
  /**
@@ -8240,7 +8273,7 @@ class SessionManager {
8240
8273
  __publicField(this, "sessionId");
8241
8274
  __publicField(this, "currentRunId", null);
8242
8275
  __publicField(this, "storageManager");
8243
- this.storageManager = storageManager2 || new StorageManager();
8276
+ this.storageManager = storageManager2 || StorageManager.getInstance();
8244
8277
  this.sessionId = this.getOrCreateSession();
8245
8278
  log(`SessionManager: Initialized with sessionId: ${this.sessionId}`);
8246
8279
  }
@@ -8255,7 +8288,7 @@ class SessionManager {
8255
8288
  const sessionData = this.storageManager.getSession();
8256
8289
  if (sessionData) {
8257
8290
  const now = Date.now();
8258
- if (now - sessionData.lastActivity < TIMING.SESSION_EXPIRY) {
8291
+ if (now - sessionData.lastActivity < TIMING$1.SESSION_EXPIRY) {
8259
8292
  log(`SessionManager: Using existing session: ${sessionData.sessionId}`);
8260
8293
  this.updateSessionActivity(sessionData.sessionId);
8261
8294
  return sessionData.sessionId;
@@ -8587,10 +8620,10 @@ class TransitionManager {
8587
8620
  this.triggerTransition(nextStepId);
8588
8621
  } else if (retries < maxRetries) {
8589
8622
  log(`TransitionManager: State still incompatible (${currentStore.currentState}), will retry`);
8590
- setTimeout(retryTransition, 500);
8623
+ setTimeout(retryTransition, TIMING.RETRY_DELAY_MS);
8591
8624
  }
8592
8625
  };
8593
- setTimeout(retryTransition, 500);
8626
+ setTimeout(retryTransition, TIMING.RETRY_DELAY_MS);
8594
8627
  }
8595
8628
  const transitionId = `url-path-${Date.now()}`;
8596
8629
  const intervalId = window.setInterval(() => {
@@ -8599,7 +8632,7 @@ class TransitionManager {
8599
8632
  clearInterval(intervalId);
8600
8633
  this.triggerTransition(nextStepId);
8601
8634
  }
8602
- }, 5e3);
8635
+ }, TIMING.URL_PATH_CHECK_INTERVAL_MS);
8603
8636
  this.activeTransitions.set(transitionId, {
8604
8637
  handlers: /* @__PURE__ */ new Map(),
8605
8638
  // No DOM handlers for URL path transitions
@@ -8736,7 +8769,7 @@ class TransitionManager {
8736
8769
  try {
8737
8770
  log(`TransitionManager: Conditions met, transitioning to step '${nextStepId}'`);
8738
8771
  this.triggerTransition(nextStepId);
8739
- await new Promise((resolve) => setTimeout(resolve, 100));
8772
+ await new Promise((resolve) => setTimeout(resolve, TIMING.STATE_PROCESSING_DELAY_MS));
8740
8773
  log(`TransitionManager: Transition to '${nextStepId}' completed successfully`);
8741
8774
  return true;
8742
8775
  } catch (error2) {
@@ -9873,7 +9906,7 @@ class PlaylistManager {
9873
9906
  __publicField(this, "playlistLoader");
9874
9907
  __publicField(this, "storageManager");
9875
9908
  this.playlistLoader = new PlaylistLoader();
9876
- this.storageManager = storageManager2 || new StorageManager();
9909
+ this.storageManager = storageManager2 || StorageManager.getInstance();
9877
9910
  if (eventManager) {
9878
9911
  this.setEventManager(eventManager);
9879
9912
  }
@@ -9912,17 +9945,6 @@ class PlaylistManager {
9912
9945
  this.updateWatchedPlaylistStatus(event.playlist.id, "in_progress", event.step.id);
9913
9946
  });
9914
9947
  }
9915
- /**
9916
- * Helper to get the store state when needed
9917
- */
9918
- getStore() {
9919
- try {
9920
- return useSaltfishStore.getState();
9921
- } catch (error2) {
9922
- console.error("Failed to access store:", error2);
9923
- return null;
9924
- }
9925
- }
9926
9948
  /**
9927
9949
  * Updates the watched playlist status locally and in the backend
9928
9950
  * @param playlistId - ID of the playlist
@@ -9936,7 +9958,7 @@ class PlaylistManager {
9936
9958
  }
9937
9959
  this.isUpdatingWatchedPlaylists = true;
9938
9960
  try {
9939
- const store = this.getStore();
9961
+ const store = getSaltfishStore();
9940
9962
  if (!store) {
9941
9963
  return;
9942
9964
  }
@@ -10027,7 +10049,10 @@ class PlaylistManager {
10027
10049
  async load(playlistId, options) {
10028
10050
  var _a, _b;
10029
10051
  try {
10030
- const store = useSaltfishStore.getState();
10052
+ const store = getSaltfishStore();
10053
+ if (!store) {
10054
+ throw new Error("Store not available");
10055
+ }
10031
10056
  const isAnonymous = ((_a = store.user) == null ? void 0 : _a.__isAnonymous) === true;
10032
10057
  const savedProgress = isAnonymous ? store.progress : ((_b = store.userData) == null ? void 0 : _b.watchedPlaylists) || store.progress;
10033
10058
  const loadResult = await this.playlistLoader.loadManifest({
@@ -10045,9 +10070,13 @@ class PlaylistManager {
10045
10070
  });
10046
10071
  }
10047
10072
  } catch (error2) {
10048
- const store = useSaltfishStore.getState();
10073
+ const store = getSaltfishStore();
10049
10074
  const errorObj = error2 instanceof Error ? error2 : new Error("Unknown error loading manifest");
10050
- store.setError(errorObj);
10075
+ if (store) {
10076
+ store.setError(errorObj);
10077
+ } else {
10078
+ console.error("[PlaylistManager] Cannot set error: Store not available", errorObj);
10079
+ }
10051
10080
  }
10052
10081
  }
10053
10082
  /**
@@ -10957,14 +10986,14 @@ const _StepTimeoutManager = class _StepTimeoutManager {
10957
10986
  this.destroyCallback = null;
10958
10987
  }
10959
10988
  };
10960
- __publicField(_StepTimeoutManager, "STEP_TIMEOUT_MS", TIMING.STEP_TIMEOUT);
10989
+ __publicField(_StepTimeoutManager, "STEP_TIMEOUT_MS", TIMING$1.STEP_TIMEOUT);
10961
10990
  let StepTimeoutManager = _StepTimeoutManager;
10962
10991
  class ManagerFactory {
10963
10992
  /**
10964
10993
  * Create all manager instances with proper dependencies
10965
10994
  */
10966
10995
  createManagers() {
10967
- const storageManager2 = new StorageManager();
10996
+ const storageManager2 = StorageManager.getInstance();
10968
10997
  const sessionManager = new SessionManager(storageManager2);
10969
10998
  const shadowDOMManager = new ShadowDOMManager();
10970
10999
  const videoManager = new VideoManager();
@@ -11215,7 +11244,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
11215
11244
  __proto__: null,
11216
11245
  SaltfishPlayer
11217
11246
  }, Symbol.toStringTag, { value: "Module" }));
11218
- const version = "0.3.2";
11247
+ const version = "0.3.4";
11219
11248
  const packageJson = {
11220
11249
  version
11221
11250
  };