saltfish 0.2.50 → 0.2.52

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.
@@ -951,280 +951,6 @@ const playerStateMachineConfig = {
951
951
  }
952
952
  }
953
953
  };
954
- const STORAGE_KEYS = {
955
- PROGRESS: "saltfish_progress",
956
- SESSION: "saltfish_session",
957
- ANONYMOUS_USER: "saltfish_anonymous_user_data"
958
- };
959
- const TIMING = {
960
- // 5 seconds
961
- STEP_TIMEOUT: 6e4,
962
- // Session persistence
963
- SESSION_EXPIRY: 30 * 60 * 1e3
964
- // 30 minutes in milliseconds
965
- };
966
- const API = {
967
- BASE_URL: "https://player.saltfish.ai",
968
- ENDPOINTS: {
969
- VALIDATE_TOKEN: "/validate-token",
970
- USERS: "/clients/{token}/users/{userId}"
971
- }
972
- };
973
- const CSS_CLASSES = {
974
- PLAYER: "sf-player",
975
- PLAYER_MINIMIZED: "sf-player--minimized",
976
- CONTROLS_CONTAINER: "sf-controls-container",
977
- LOGO: "sf-player__logo",
978
- // Legacy error class
979
- ERROR_DISPLAY: "sf-error-display",
980
- ERROR_DISPLAY_VISIBLE: "sf-error-display--visible",
981
- ERROR_DISPLAY_CONTENT: "sf-error-display__content",
982
- ERROR_DISPLAY_MESSAGE: "sf-error-display__message",
983
- LOADING_SPINNER: "sf-loading-spinner"
984
- };
985
- class StorageManager {
986
- constructor() {
987
- __publicField(this, "isLocalStorageAvailable");
988
- this.isLocalStorageAvailable = this.checkLocalStorageAvailability();
989
- if (!this.isLocalStorageAvailable) ;
990
- }
991
- /**
992
- * Check if localStorage is available and working
993
- */
994
- checkLocalStorageAvailability() {
995
- if (typeof window === "undefined") {
996
- return false;
997
- }
998
- try {
999
- const testKey = "__storage_test__";
1000
- localStorage.setItem(testKey, "test");
1001
- localStorage.removeItem(testKey);
1002
- return true;
1003
- } catch (error2) {
1004
- return false;
1005
- }
1006
- }
1007
- /**
1008
- * Safely get an item from localStorage with JSON parsing
1009
- */
1010
- safeGetItem(key) {
1011
- if (!this.isLocalStorageAvailable) {
1012
- return null;
1013
- }
1014
- try {
1015
- const item = localStorage.getItem(key);
1016
- if (item === null) {
1017
- return null;
1018
- }
1019
- return JSON.parse(item);
1020
- } catch (error2) {
1021
- this.safeClearItem(key);
1022
- return null;
1023
- }
1024
- }
1025
- /**
1026
- * Safely set an item in localStorage with JSON stringification
1027
- */
1028
- safeSetItem(key, value) {
1029
- if (!this.isLocalStorageAvailable) {
1030
- return false;
1031
- }
1032
- try {
1033
- localStorage.setItem(key, JSON.stringify(value));
1034
- return true;
1035
- } catch (error2) {
1036
- if (error2 instanceof DOMException && error2.code === 22) {
1037
- this.clearOldData();
1038
- try {
1039
- localStorage.setItem(key, JSON.stringify(value));
1040
- return true;
1041
- } catch (retryError) {
1042
- }
1043
- }
1044
- return false;
1045
- }
1046
- }
1047
- /**
1048
- * Safely clear an item from localStorage
1049
- */
1050
- safeClearItem(key) {
1051
- if (!this.isLocalStorageAvailable) {
1052
- return;
1053
- }
1054
- try {
1055
- localStorage.removeItem(key);
1056
- } catch (error2) {
1057
- }
1058
- }
1059
- /**
1060
- * Clear old data to free up storage space
1061
- */
1062
- clearOldData() {
1063
- this.safeClearItem(STORAGE_KEYS.SESSION);
1064
- }
1065
- // =============================================================================
1066
- // Progress Data Methods
1067
- // =============================================================================
1068
- /**
1069
- * Get playlist progress data for a specific user
1070
- * If userId doesn't match stored userId, returns null (stale data)
1071
- * @param userId - The user ID to validate against stored data
1072
- */
1073
- getProgress(userId) {
1074
- const stored = this.safeGetItem(STORAGE_KEYS.PROGRESS);
1075
- if (!stored) {
1076
- return null;
1077
- }
1078
- if (userId && stored.userId && stored.userId !== userId) {
1079
- log(`[StorageManager] Progress belongs to different user (${stored.userId}), ignoring`);
1080
- return null;
1081
- }
1082
- return stored.playlists || null;
1083
- }
1084
- /**
1085
- * Set playlist progress data for a specific user
1086
- * Clears existing data if userId changes
1087
- * @param progress - The progress data to save
1088
- * @param userId - The user ID to associate with this progress
1089
- */
1090
- setProgress(progress, userId) {
1091
- const stored = {
1092
- userId,
1093
- playlists: progress
1094
- };
1095
- return this.safeSetItem(STORAGE_KEYS.PROGRESS, stored);
1096
- }
1097
- /**
1098
- * Clear all progress data
1099
- */
1100
- clearProgress() {
1101
- this.safeClearItem(STORAGE_KEYS.PROGRESS);
1102
- }
1103
- // =============================================================================
1104
- // Session Data Methods
1105
- // =============================================================================
1106
- /**
1107
- * Get session data
1108
- */
1109
- getSession() {
1110
- return this.safeGetItem(STORAGE_KEYS.SESSION);
1111
- }
1112
- /**
1113
- * Set session data
1114
- */
1115
- setSession(session) {
1116
- return this.safeSetItem(STORAGE_KEYS.SESSION, session);
1117
- }
1118
- /**
1119
- * Clear session data
1120
- */
1121
- clearSession() {
1122
- this.safeClearItem(STORAGE_KEYS.SESSION);
1123
- }
1124
- // =============================================================================
1125
- // Anonymous User Data Methods
1126
- // =============================================================================
1127
- /**
1128
- * Get anonymous user data
1129
- */
1130
- getAnonymousUserData() {
1131
- return this.safeGetItem(STORAGE_KEYS.ANONYMOUS_USER);
1132
- }
1133
- /**
1134
- * Set anonymous user data
1135
- */
1136
- setAnonymousUserData(data) {
1137
- return this.safeSetItem(STORAGE_KEYS.ANONYMOUS_USER, data);
1138
- }
1139
- /**
1140
- * Clear anonymous user data
1141
- */
1142
- clearAnonymousUserData() {
1143
- this.safeClearItem(STORAGE_KEYS.ANONYMOUS_USER);
1144
- }
1145
- // =============================================================================
1146
- // Anonymous User ID Methods
1147
- // =============================================================================
1148
- /**
1149
- * Get anonymous user ID
1150
- */
1151
- getAnonymousUserId() {
1152
- if (!this.isLocalStorageAvailable) {
1153
- return null;
1154
- }
1155
- try {
1156
- return localStorage.getItem("saltfish_anonymous_user_id");
1157
- } catch (error2) {
1158
- return null;
1159
- }
1160
- }
1161
- /**
1162
- * Set anonymous user ID
1163
- */
1164
- setAnonymousUserId(userId) {
1165
- if (!this.isLocalStorageAvailable) {
1166
- return false;
1167
- }
1168
- try {
1169
- localStorage.setItem("saltfish_anonymous_user_id", userId);
1170
- return true;
1171
- } catch (error2) {
1172
- return false;
1173
- }
1174
- }
1175
- /**
1176
- * Clear anonymous user ID
1177
- */
1178
- clearAnonymousUserId() {
1179
- if (!this.isLocalStorageAvailable) {
1180
- return;
1181
- }
1182
- try {
1183
- localStorage.removeItem("saltfish_anonymous_user_id");
1184
- } catch (error2) {
1185
- }
1186
- }
1187
- // =============================================================================
1188
- // Utility Methods
1189
- // =============================================================================
1190
- /**
1191
- * Clear all storage data
1192
- */
1193
- clearAll() {
1194
- this.clearProgress();
1195
- this.clearSession();
1196
- this.clearAnonymousUserData();
1197
- this.clearAnonymousUserId();
1198
- }
1199
- /**
1200
- * Get storage availability status
1201
- */
1202
- isStorageAvailable() {
1203
- return this.isLocalStorageAvailable;
1204
- }
1205
- /**
1206
- * Get storage usage information (if available)
1207
- */
1208
- getStorageInfo() {
1209
- const keys = [];
1210
- if (this.isLocalStorageAvailable) {
1211
- try {
1212
- for (let i = 0; i < localStorage.length; i++) {
1213
- const key = localStorage.key(i);
1214
- if (key && key.startsWith("saltfish_")) {
1215
- keys.push(key);
1216
- }
1217
- }
1218
- } catch (error2) {
1219
- }
1220
- }
1221
- return {
1222
- available: this.isLocalStorageAvailable,
1223
- keys
1224
- };
1225
- }
1226
- }
1227
- const storageManager = new StorageManager();
1228
954
  const createInitialContext = () => ({
1229
955
  currentStep: null,
1230
956
  error: null
@@ -1345,7 +1071,7 @@ const saltfishStore = createStore()(
1345
1071
  if (manifest && manifest.steps.some((step) => step.id === stepId)) {
1346
1072
  const targetStep = manifest.steps.find((step) => step.id === stepId);
1347
1073
  set2((state) => {
1348
- var _a, _b, _c;
1074
+ var _a;
1349
1075
  state.currentStepId = stepId;
1350
1076
  if (targetStep) {
1351
1077
  state.currentState = transitionState({
@@ -1361,11 +1087,6 @@ const saltfishStore = createStore()(
1361
1087
  lastStepId: stepId,
1362
1088
  lastVisited: (/* @__PURE__ */ new Date()).toISOString()
1363
1089
  };
1364
- const playlistPersistence = ((_b = state.playlistOptions) == null ? void 0 : _b.persistence) ?? true;
1365
- if (playlistPersistence) {
1366
- const userId = (_c = state.user) == null ? void 0 : _c.id;
1367
- storageManager.setProgress(state.progress, userId);
1368
- }
1369
1090
  });
1370
1091
  }
1371
1092
  },
@@ -1464,7 +1185,6 @@ const saltfishStore = createStore()(
1464
1185
  // New action to update progress when transitioning to completion waiting state
1465
1186
  updateProgressWithCompletion: (playlistId, currentStepId) => {
1466
1187
  set2((state) => {
1467
- var _a, _b;
1468
1188
  state.currentState = transitionState({ type: "COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION" });
1469
1189
  state.progress[playlistId] = {
1470
1190
  ...state.progress[playlistId],
@@ -1472,11 +1192,6 @@ const saltfishStore = createStore()(
1472
1192
  lastVisited: (/* @__PURE__ */ new Date()).toISOString(),
1473
1193
  completedWaitingForInteraction: true
1474
1194
  };
1475
- const playlistPersistence = ((_a = state.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
1476
- if (playlistPersistence) {
1477
- const userId = (_b = state.user) == null ? void 0 : _b.id;
1478
- storageManager.setProgress(state.progress, userId);
1479
- }
1480
1195
  });
1481
1196
  },
1482
1197
  setABTests: (abTests) => {
@@ -1517,6 +1232,37 @@ const useSaltfishStore = {
1517
1232
  subscribe: saltfishStore.subscribe,
1518
1233
  destroy: saltfishStore.destroy
1519
1234
  };
1235
+ const STORAGE_KEYS = {
1236
+ PROGRESS: "saltfish_progress",
1237
+ SESSION: "saltfish_session",
1238
+ ANONYMOUS_USER: "saltfish_anonymous_user_data"
1239
+ };
1240
+ const TIMING = {
1241
+ // 5 seconds
1242
+ STEP_TIMEOUT: 6e4,
1243
+ // Session persistence
1244
+ SESSION_EXPIRY: 30 * 60 * 1e3
1245
+ // 30 minutes in milliseconds
1246
+ };
1247
+ const API = {
1248
+ BASE_URL: "https://player.saltfish.ai",
1249
+ ENDPOINTS: {
1250
+ VALIDATE_TOKEN: "/validate-token",
1251
+ USERS: "/clients/{token}/users/{userId}"
1252
+ }
1253
+ };
1254
+ const CSS_CLASSES = {
1255
+ PLAYER: "sf-player",
1256
+ PLAYER_MINIMIZED: "sf-player--minimized",
1257
+ CONTROLS_CONTAINER: "sf-controls-container",
1258
+ LOGO: "sf-player__logo",
1259
+ // Legacy error class
1260
+ ERROR_DISPLAY: "sf-error-display",
1261
+ ERROR_DISPLAY_VISIBLE: "sf-error-display--visible",
1262
+ ERROR_DISPLAY_CONTENT: "sf-error-display__content",
1263
+ ERROR_DISPLAY_MESSAGE: "sf-error-display__message",
1264
+ LOADING_SPINNER: "sf-loading-spinner"
1265
+ };
1520
1266
  class ErrorHandler {
1521
1267
  /**
1522
1268
  * Handles an error with consistent logging, reporting, and response
@@ -2524,7 +2270,7 @@ class PlaylistOrchestrator {
2524
2270
  * Start a playlist with given options
2525
2271
  */
2526
2272
  async startPlaylist(playlistId, options) {
2527
- var _a, _b, _c, _d;
2273
+ var _a, _b, _c;
2528
2274
  try {
2529
2275
  const needsManagerRecreation = this.isInitialized() && !this.managers.uiManager.getPlayerElement();
2530
2276
  if (!this.isInitialized() && this.playerInitializationService) {
@@ -2646,35 +2392,11 @@ class PlaylistOrchestrator {
2646
2392
  }
2647
2393
  this.managers.uiManager.updatePosition();
2648
2394
  store.sendStateMachineEvent({ type: "LOAD_MANIFEST" });
2649
- const playlistPersistence = options == null ? void 0 : options.persistence;
2650
- if (typeof window !== "undefined") {
2651
- const userId = (_d = store.user) == null ? void 0 : _d.id;
2652
- const progressFromStorage = this.managers.storageManager.getProgress(userId);
2653
- if (progressFromStorage && progressFromStorage[playlistId]) {
2654
- store.loadPlaylistProgress(playlistId, progressFromStorage[playlistId]);
2655
- } else if (store.progress[playlistId]) {
2656
- log(`PlaylistOrchestrator: Clearing stale progress for ${playlistId} from store.progress`);
2657
- const cleanedProgress = { ...store.progress };
2658
- delete cleanedProgress[playlistId];
2659
- useSaltfishStore.setState((state) => {
2660
- state.progress = cleanedProgress;
2661
- });
2662
- }
2663
- }
2664
2395
  this.managers.analyticsManager.trackPlaylistStart(playlistId);
2665
2396
  this.managers.cursorManager.resetFirstAnimation();
2666
2397
  log(`[PlaylistOrchestrator.startPlaylist] Using validated manifest path: ${manifestPathToLoad}`);
2667
- await this.managers.playlistManager.load(manifestPathToLoad, { ...finalOptions, persistence: playlistPersistence });
2398
+ await this.managers.playlistManager.load(manifestPathToLoad, finalOptions);
2668
2399
  const updatedStore = useSaltfishStore.getState();
2669
- if (updatedStore.manifest) {
2670
- const manifestPersistence = finalOptions.persistence ?? updatedStore.manifest.isPersistent ?? true;
2671
- const currentOptions = updatedStore.playlistOptions || {};
2672
- updatedStore.setPlaylistOptions({
2673
- ...currentOptions,
2674
- ...finalOptions,
2675
- persistence: manifestPersistence
2676
- });
2677
- }
2678
2400
  if (finalOptions.startNodeId && updatedStore.manifest) {
2679
2401
  const targetStep = updatedStore.manifest.steps.find((step) => step.id === finalOptions.startNodeId);
2680
2402
  if (targetStep) {
@@ -3097,7 +2819,6 @@ class StateMachineActionHandler {
3097
2819
  }
3098
2820
  }
3099
2821
  handleTrackPlaylistComplete() {
3100
- var _a, _b;
3101
2822
  const store = useSaltfishStore.getState();
3102
2823
  if (store.manifest && this.managers.eventManager) {
3103
2824
  const playlistId = store.manifest.id;
@@ -3108,13 +2829,6 @@ class StateMachineActionHandler {
3108
2829
  title: store.manifest.name
3109
2830
  }
3110
2831
  });
3111
- const playlistPersistence = ((_a = store.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
3112
- if (playlistPersistence && store.progress[playlistId]) {
3113
- const updatedProgress = { ...store.progress };
3114
- delete updatedProgress[playlistId];
3115
- const userId = (_b = store.user) == null ? void 0 : _b.id;
3116
- this.managers.storageManager.setProgress(updatedProgress, userId);
3117
- }
3118
2832
  }
3119
2833
  }
3120
2834
  handleError(context) {
@@ -5047,7 +4761,6 @@ class VideoManager {
5047
4761
  * @param url - URL of the video to load
5048
4762
  */
5049
4763
  async loadVideo(url) {
5050
- var _a;
5051
4764
  const activeVideo = this.getActiveVideo();
5052
4765
  if (!activeVideo) {
5053
4766
  return;
@@ -5064,20 +4777,9 @@ class VideoManager {
5064
4777
  if (this.controls) {
5065
4778
  this.controls.reset();
5066
4779
  }
5067
- const store2 = useSaltfishStore.getState();
5068
- const isPersistenceEnabled = ((_a = store2.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
5069
4780
  if (this.currentVideoUrl === url && activeVideo.src && (activeVideo.src === url || activeVideo.src.endsWith(url))) {
5070
- if (isPersistenceEnabled) {
5071
- const savedPosition = this.playbackPositions.get(url);
5072
- if (savedPosition !== void 0 && savedPosition > 0 && Math.abs(activeVideo.currentTime - savedPosition) > 0.5) {
5073
- activeVideo.currentTime = savedPosition;
5074
- }
5075
- }
5076
4781
  return;
5077
4782
  }
5078
- if (isPersistenceEnabled && this.currentVideoUrl && activeVideo.currentTime > 0) {
5079
- this.playbackPositions.set(this.currentVideoUrl, activeVideo.currentTime);
5080
- }
5081
4783
  const inactiveVideo = this.getInactiveVideo();
5082
4784
  if (inactiveVideo && this.nextVideoUrl === url) {
5083
4785
  this.swapVideos();
@@ -5122,18 +4824,10 @@ class VideoManager {
5122
4824
  let loadTimeout;
5123
4825
  const onLoadedData = () => {
5124
4826
  if (!activeVideo) {
5125
- return;
5126
- }
5127
- clearTimeout(loadTimeout);
5128
- if (isPersistenceEnabled) {
5129
- const savedPosition = this.playbackPositions.get(url);
5130
- if (savedPosition !== void 0 && savedPosition > 0) {
5131
- const safePosition = Math.min(savedPosition, activeVideo.duration - 0.5);
5132
- activeVideo.currentTime = safePosition;
5133
- }
5134
- } else {
5135
- activeVideo.currentTime = 0;
4827
+ return;
5136
4828
  }
4829
+ clearTimeout(loadTimeout);
4830
+ activeVideo.currentTime = 0;
5137
4831
  this.transcriptManager.updateVideoElement(activeVideo);
5138
4832
  if (this.controls) {
5139
4833
  this.controls.updateVideoElement(activeVideo);
@@ -5222,7 +4916,6 @@ class VideoManager {
5222
4916
  * Plays the video
5223
4917
  */
5224
4918
  play() {
5225
- var _a;
5226
4919
  const activeVideo = this.getActiveVideo();
5227
4920
  if (!activeVideo) {
5228
4921
  console.error("VideoManager: No active video element found");
@@ -5235,14 +4928,6 @@ class VideoManager {
5235
4928
  if (activeVideo.ended) {
5236
4929
  activeVideo.currentTime = 0;
5237
4930
  }
5238
- const store = useSaltfishStore.getState();
5239
- const isPersistenceEnabled = ((_a = store.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
5240
- if (isPersistenceEnabled && this.currentVideoUrl) {
5241
- const savedPosition = this.playbackPositions.get(this.currentVideoUrl);
5242
- if (savedPosition && Math.abs(activeVideo.currentTime - savedPosition) > 0.5) {
5243
- activeVideo.currentTime = savedPosition;
5244
- }
5245
- }
5246
4931
  activeVideo.loop = false;
5247
4932
  if (!activeVideo.paused) {
5248
4933
  if (this.controls) {
@@ -5259,6 +4944,7 @@ class VideoManager {
5259
4944
  this.controls.startProgressTracking();
5260
4945
  }
5261
4946
  } else {
4947
+ const store = useSaltfishStore.getState();
5262
4948
  store.setAutoplayFallback();
5263
4949
  if (this.isMobileDevice()) {
5264
4950
  activeVideo.playsInline = true;
@@ -5274,8 +4960,8 @@ class VideoManager {
5274
4960
  }
5275
4961
  }).catch(() => {
5276
4962
  console.warn("VideoManager: Autoplay handler threw error - browser has strict autoplay policy");
5277
- const store2 = useSaltfishStore.getState();
5278
- store2.setAutoplayFallback();
4963
+ const store = useSaltfishStore.getState();
4964
+ store.setAutoplayFallback();
5279
4965
  });
5280
4966
  }
5281
4967
  /**
@@ -6753,7 +6439,6 @@ class InteractionManager {
6753
6439
  __publicField(this, "scrollIndicator", null);
6754
6440
  __publicField(this, "domEventListeners", /* @__PURE__ */ new Map());
6755
6441
  __publicField(this, "storeUnsubscribe", null);
6756
- __publicField(this, "storageManager", new StorageManager());
6757
6442
  /**
6758
6443
  * Handles the video90PercentReached event
6759
6444
  * @param _event - The custom event dispatched when video reaches 90%
@@ -6973,7 +6658,6 @@ class InteractionManager {
6973
6658
  * @param buttonConfig - The button configuration
6974
6659
  */
6975
6660
  async handleButtonClick(event, buttonConfig) {
6976
- var _a, _b;
6977
6661
  log(`InteractionManager: Button click detected on button "${buttonConfig.id}"`);
6978
6662
  event.preventDefault();
6979
6663
  event.stopPropagation();
@@ -6998,13 +6682,6 @@ class InteractionManager {
6998
6682
  };
6999
6683
  }
7000
6684
  });
7001
- const playlistPersistence = ((_a = currentStore.playlistOptions) == null ? void 0 : _a.persistence) ?? true;
7002
- if (playlistPersistence) {
7003
- const userId = (_b = currentStore.user) == null ? void 0 : _b.id;
7004
- const updatedStore = useSaltfishStore.getState();
7005
- this.storageManager.setProgress(updatedStore.progress, userId);
7006
- log(`InteractionManager: Saved progress for step ${buttonConfig.action.target} before URL redirect`);
7007
- }
7008
6685
  }
7009
6686
  log(`InteractionManager: Redirecting to ${buttonConfig.action.url}`);
7010
6687
  window.location.href = buttonConfig.action.url;
@@ -7522,12 +7199,254 @@ class AnalyticsManager {
7522
7199
  }
7523
7200
  }
7524
7201
  }
7202
+ class StorageManager {
7203
+ constructor() {
7204
+ __publicField(this, "isLocalStorageAvailable");
7205
+ this.isLocalStorageAvailable = this.checkLocalStorageAvailability();
7206
+ if (!this.isLocalStorageAvailable) ;
7207
+ }
7208
+ /**
7209
+ * Check if localStorage is available and working
7210
+ */
7211
+ checkLocalStorageAvailability() {
7212
+ if (typeof window === "undefined") {
7213
+ return false;
7214
+ }
7215
+ try {
7216
+ const testKey = "__storage_test__";
7217
+ localStorage.setItem(testKey, "test");
7218
+ localStorage.removeItem(testKey);
7219
+ return true;
7220
+ } catch (error2) {
7221
+ return false;
7222
+ }
7223
+ }
7224
+ /**
7225
+ * Safely get an item from localStorage with JSON parsing
7226
+ */
7227
+ safeGetItem(key) {
7228
+ if (!this.isLocalStorageAvailable) {
7229
+ return null;
7230
+ }
7231
+ try {
7232
+ const item = localStorage.getItem(key);
7233
+ if (item === null) {
7234
+ return null;
7235
+ }
7236
+ return JSON.parse(item);
7237
+ } catch (error2) {
7238
+ this.safeClearItem(key);
7239
+ return null;
7240
+ }
7241
+ }
7242
+ /**
7243
+ * Safely set an item in localStorage with JSON stringification
7244
+ */
7245
+ safeSetItem(key, value) {
7246
+ if (!this.isLocalStorageAvailable) {
7247
+ return false;
7248
+ }
7249
+ try {
7250
+ localStorage.setItem(key, JSON.stringify(value));
7251
+ return true;
7252
+ } catch (error2) {
7253
+ if (error2 instanceof DOMException && error2.code === 22) {
7254
+ this.clearOldData();
7255
+ try {
7256
+ localStorage.setItem(key, JSON.stringify(value));
7257
+ return true;
7258
+ } catch (retryError) {
7259
+ }
7260
+ }
7261
+ return false;
7262
+ }
7263
+ }
7264
+ /**
7265
+ * Safely clear an item from localStorage
7266
+ */
7267
+ safeClearItem(key) {
7268
+ if (!this.isLocalStorageAvailable) {
7269
+ return;
7270
+ }
7271
+ try {
7272
+ localStorage.removeItem(key);
7273
+ } catch (error2) {
7274
+ }
7275
+ }
7276
+ /**
7277
+ * Clear old data to free up storage space
7278
+ */
7279
+ clearOldData() {
7280
+ this.safeClearItem(STORAGE_KEYS.SESSION);
7281
+ }
7282
+ // =============================================================================
7283
+ // Progress Data Methods
7284
+ // =============================================================================
7285
+ /**
7286
+ * Get playlist progress data for a specific user
7287
+ * If userId doesn't match stored userId, returns null (stale data)
7288
+ * @param userId - The user ID to validate against stored data
7289
+ */
7290
+ getProgress(userId) {
7291
+ const stored = this.safeGetItem(STORAGE_KEYS.PROGRESS);
7292
+ if (!stored) {
7293
+ return null;
7294
+ }
7295
+ if (userId && stored.userId && stored.userId !== userId) {
7296
+ log(`[StorageManager] Progress belongs to different user (${stored.userId}), ignoring`);
7297
+ return null;
7298
+ }
7299
+ return stored.playlists || null;
7300
+ }
7301
+ /**
7302
+ * Set playlist progress data for a specific user
7303
+ * Clears existing data if userId changes
7304
+ * @param progress - The progress data to save
7305
+ * @param userId - The user ID to associate with this progress
7306
+ */
7307
+ setProgress(progress, userId) {
7308
+ const stored = {
7309
+ userId,
7310
+ playlists: progress
7311
+ };
7312
+ return this.safeSetItem(STORAGE_KEYS.PROGRESS, stored);
7313
+ }
7314
+ /**
7315
+ * Clear all progress data
7316
+ */
7317
+ clearProgress() {
7318
+ this.safeClearItem(STORAGE_KEYS.PROGRESS);
7319
+ }
7320
+ // =============================================================================
7321
+ // Session Data Methods
7322
+ // =============================================================================
7323
+ /**
7324
+ * Get session data
7325
+ */
7326
+ getSession() {
7327
+ return this.safeGetItem(STORAGE_KEYS.SESSION);
7328
+ }
7329
+ /**
7330
+ * Set session data
7331
+ */
7332
+ setSession(session) {
7333
+ return this.safeSetItem(STORAGE_KEYS.SESSION, session);
7334
+ }
7335
+ /**
7336
+ * Clear session data
7337
+ */
7338
+ clearSession() {
7339
+ this.safeClearItem(STORAGE_KEYS.SESSION);
7340
+ }
7341
+ // =============================================================================
7342
+ // Anonymous User Data Methods
7343
+ // =============================================================================
7344
+ /**
7345
+ * Get anonymous user data
7346
+ */
7347
+ getAnonymousUserData() {
7348
+ return this.safeGetItem(STORAGE_KEYS.ANONYMOUS_USER);
7349
+ }
7350
+ /**
7351
+ * Set anonymous user data
7352
+ */
7353
+ setAnonymousUserData(data) {
7354
+ return this.safeSetItem(STORAGE_KEYS.ANONYMOUS_USER, data);
7355
+ }
7356
+ /**
7357
+ * Clear anonymous user data
7358
+ */
7359
+ clearAnonymousUserData() {
7360
+ this.safeClearItem(STORAGE_KEYS.ANONYMOUS_USER);
7361
+ }
7362
+ // =============================================================================
7363
+ // Anonymous User ID Methods
7364
+ // =============================================================================
7365
+ /**
7366
+ * Get anonymous user ID
7367
+ */
7368
+ getAnonymousUserId() {
7369
+ if (!this.isLocalStorageAvailable) {
7370
+ return null;
7371
+ }
7372
+ try {
7373
+ return localStorage.getItem("saltfish_anonymous_user_id");
7374
+ } catch (error2) {
7375
+ return null;
7376
+ }
7377
+ }
7378
+ /**
7379
+ * Set anonymous user ID
7380
+ */
7381
+ setAnonymousUserId(userId) {
7382
+ if (!this.isLocalStorageAvailable) {
7383
+ return false;
7384
+ }
7385
+ try {
7386
+ localStorage.setItem("saltfish_anonymous_user_id", userId);
7387
+ return true;
7388
+ } catch (error2) {
7389
+ return false;
7390
+ }
7391
+ }
7392
+ /**
7393
+ * Clear anonymous user ID
7394
+ */
7395
+ clearAnonymousUserId() {
7396
+ if (!this.isLocalStorageAvailable) {
7397
+ return;
7398
+ }
7399
+ try {
7400
+ localStorage.removeItem("saltfish_anonymous_user_id");
7401
+ } catch (error2) {
7402
+ }
7403
+ }
7404
+ // =============================================================================
7405
+ // Utility Methods
7406
+ // =============================================================================
7407
+ /**
7408
+ * Clear all storage data
7409
+ */
7410
+ clearAll() {
7411
+ this.clearProgress();
7412
+ this.clearSession();
7413
+ this.clearAnonymousUserData();
7414
+ this.clearAnonymousUserId();
7415
+ }
7416
+ /**
7417
+ * Get storage availability status
7418
+ */
7419
+ isStorageAvailable() {
7420
+ return this.isLocalStorageAvailable;
7421
+ }
7422
+ /**
7423
+ * Get storage usage information (if available)
7424
+ */
7425
+ getStorageInfo() {
7426
+ const keys = [];
7427
+ if (this.isLocalStorageAvailable) {
7428
+ try {
7429
+ for (let i = 0; i < localStorage.length; i++) {
7430
+ const key = localStorage.key(i);
7431
+ if (key && key.startsWith("saltfish_")) {
7432
+ keys.push(key);
7433
+ }
7434
+ }
7435
+ } catch (error2) {
7436
+ }
7437
+ }
7438
+ return {
7439
+ available: this.isLocalStorageAvailable,
7440
+ keys
7441
+ };
7442
+ }
7443
+ }
7525
7444
  class SessionManager {
7526
- constructor(storageManager2) {
7445
+ constructor(storageManager) {
7527
7446
  __publicField(this, "sessionId");
7528
7447
  __publicField(this, "currentRunId", null);
7529
7448
  __publicField(this, "storageManager");
7530
- this.storageManager = storageManager2 || new StorageManager();
7449
+ this.storageManager = storageManager || new StorageManager();
7531
7450
  this.sessionId = this.getOrCreateSession();
7532
7451
  log(`SessionManager: Initialized with sessionId: ${this.sessionId}`);
7533
7452
  }
@@ -8849,11 +8768,11 @@ class PlaylistLoader {
8849
8768
  * @returns Promise resolving to manifest and determined start step
8850
8769
  */
8851
8770
  async loadManifest(options) {
8852
- const { manifestPath, playlistOptions, savedProgress } = options;
8771
+ const { manifestPath, playlistOptions } = options;
8853
8772
  try {
8854
8773
  const manifest = await this.fetchManifest(manifestPath);
8855
8774
  this.validateManifest(manifest);
8856
- const startStepId = this.determineStartStep(manifest, playlistOptions, savedProgress);
8775
+ const startStepId = this.determineStartStep(manifest, playlistOptions);
8857
8776
  log(`PlaylistLoader: Successfully loaded manifest '${manifest.id}' with start step '${startStepId}'`);
8858
8777
  return {
8859
8778
  manifest,
@@ -8939,16 +8858,14 @@ class PlaylistLoader {
8939
8858
  }
8940
8859
  }
8941
8860
  /**
8942
- * Determines which step to start from based on persistence and saved progress
8861
+ * Determines which step to start from based on options
8862
+ * Note: Persistence has been removed - playlists always start from beginning unless startNodeId is specified
8863
+ * The 4-second rule in PlayerInitializationService handles immediate resume during page transitions
8943
8864
  * @param manifest - The loaded playlist manifest
8944
8865
  * @param options - Playlist configuration options
8945
- * @param savedProgress - Previously saved progress data
8946
8866
  * @returns The step ID to start from
8947
8867
  */
8948
- determineStartStep(manifest, options, savedProgress) {
8949
- var _a;
8950
- const isPersistenceEnabled = options.persistence ?? manifest.isPersistent ?? true;
8951
- const manifestIdForProgress = manifest.id;
8868
+ determineStartStep(manifest, options) {
8952
8869
  let startStepId = manifest.startStep;
8953
8870
  if (options.startNodeId) {
8954
8871
  const customStep = manifest.steps.find((step) => step.id === options.startNodeId);
@@ -8958,17 +8875,6 @@ class PlaylistLoader {
8958
8875
  } else {
8959
8876
  log(`PlaylistLoader: Custom start node '${options.startNodeId}' not found, using default start step`);
8960
8877
  }
8961
- } else if (isPersistenceEnabled && savedProgress && ((_a = savedProgress[manifestIdForProgress]) == null ? void 0 : _a.lastStepId)) {
8962
- const progressData = savedProgress[manifestIdForProgress];
8963
- const lastStepId = progressData.lastStepId;
8964
- if (progressData.completedWaitingForInteraction) {
8965
- startStepId = manifest.startStep;
8966
- } else {
8967
- const savedStep = manifest.steps.find((step) => step.id === lastStepId);
8968
- if (savedStep) {
8969
- startStepId = lastStepId;
8970
- }
8971
- }
8972
8878
  }
8973
8879
  return startStepId;
8974
8880
  }
@@ -8979,13 +8885,13 @@ class PlaylistManager {
8979
8885
  * @param eventManager - Optional event manager to subscribe to events
8980
8886
  * @param storageManager - Optional storage manager for localStorage operations
8981
8887
  */
8982
- constructor(eventManager, storageManager2) {
8888
+ constructor(eventManager, storageManager) {
8983
8889
  __publicField(this, "eventManager", null);
8984
8890
  __publicField(this, "isUpdatingWatchedPlaylists", false);
8985
8891
  __publicField(this, "playlistLoader");
8986
8892
  __publicField(this, "storageManager");
8987
8893
  this.playlistLoader = new PlaylistLoader();
8988
- this.storageManager = storageManager2 || new StorageManager();
8894
+ this.storageManager = storageManager || new StorageManager();
8989
8895
  if (eventManager) {
8990
8896
  this.setEventManager(eventManager);
8991
8897
  }
@@ -10067,13 +9973,13 @@ class ManagerFactory {
10067
9973
  * Create all manager instances with proper dependencies
10068
9974
  */
10069
9975
  createManagers() {
10070
- const storageManager2 = new StorageManager();
10071
- const sessionManager = new SessionManager(storageManager2);
9976
+ const storageManager = new StorageManager();
9977
+ const sessionManager = new SessionManager(storageManager);
10072
9978
  const shadowDOMManager = new ShadowDOMManager();
10073
9979
  const videoManager = new VideoManager();
10074
9980
  const eventManager = new EventManager();
10075
9981
  const analyticsManager = new AnalyticsManager(eventManager);
10076
- const playlistManager = new PlaylistManager(eventManager, storageManager2);
9982
+ const playlistManager = new PlaylistManager(eventManager, storageManager);
10077
9983
  const abTestManager = new ABTestManager(eventManager);
10078
9984
  const cursorManager = new CursorManager();
10079
9985
  const interactionManager = new InteractionManager();
@@ -10097,7 +10003,7 @@ class ManagerFactory {
10097
10003
  playlistManager,
10098
10004
  stepTimeoutManager,
10099
10005
  uiManager,
10100
- storageManager: storageManager2
10006
+ storageManager
10101
10007
  };
10102
10008
  return managers;
10103
10009
  }
@@ -10318,7 +10224,7 @@ const SaltfishPlayer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
10318
10224
  __proto__: null,
10319
10225
  SaltfishPlayer
10320
10226
  }, Symbol.toStringTag, { value: "Module" }));
10321
- const version = "0.2.50";
10227
+ const version = "0.2.52";
10322
10228
  const packageJson = {
10323
10229
  version
10324
10230
  };