@xhub-short/sdk 1.0.0-beta.24 → 1.0.0-beta.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +135 -154
  2. package/dist/index.js +47 -54
  3. package/package.json +8 -8
package/dist/index.d.ts CHANGED
@@ -1365,27 +1365,6 @@ interface VideoSlotWiredProps extends VideoSlotProps {
1365
1365
  reportedButtonText?: string;
1366
1366
  /** Custom styles */
1367
1367
  style?: React.CSSProperties;
1368
- /**
1369
- * Disable long-press speed boost gesture.
1370
- * When true, holding won't trigger 2x speed.
1371
- * @default false
1372
- */
1373
- disableSpeedBoost?: boolean;
1374
- /**
1375
- * Speed multiplier for speed boost.
1376
- * @default 2
1377
- */
1378
- speedBoostSpeed?: number;
1379
- /**
1380
- * Hold delay in ms before speed boost activates.
1381
- * @default 2000
1382
- */
1383
- speedBoostHoldDelay?: number;
1384
- /**
1385
- * Pull-down distance in px to trigger speed lock.
1386
- * @default 50
1387
- */
1388
- speedBoostPullDownThreshold?: number;
1389
1368
  }
1390
1369
  /**
1391
1370
  * SDK Player Error - Preserves error metadata from PlayerEngine
@@ -1435,7 +1414,7 @@ declare class SDKPlayerError extends Error {
1435
1414
  * Host app must trigger these manually or wait for future IntersectionObserver
1436
1415
  * implementation in VideoSlotHeadless.
1437
1416
  */
1438
- declare function VideoSlot({ video, index, resourceState: resourceStateOverride, playerState: playerStateOverride, playerControls: playerControlsOverride, className, children, onVisible, onHidden, onTap, onDoubleTap, onLongPress, disableTap, renderError, renderLoading, reportedTitle, reportedMessage, reportedButtonText, style, disableSpeedBoost, speedBoostSpeed, speedBoostHoldDelay, speedBoostPullDownThreshold, }: VideoSlotWiredProps): React.ReactElement;
1417
+ declare function VideoSlot({ video, index, resourceState: resourceStateOverride, playerState: playerStateOverride, playerControls: playerControlsOverride, className, children, onVisible, onHidden, onTap, onDoubleTap, onLongPress, disableTap, renderError, renderLoading, reportedTitle, reportedMessage, reportedButtonText, style, }: VideoSlotWiredProps): React.ReactElement;
1439
1418
  declare namespace VideoSlot {
1440
1419
  var displayName: string;
1441
1420
  }
@@ -1735,18 +1714,134 @@ interface DefaultVideoSlotProps {
1735
1714
  enableZoom?: boolean;
1736
1715
  zoomMaxScale?: number;
1737
1716
  zoomSnapBackAnimation?: 'none' | 'ease' | 'spring';
1738
- /** Disable speed boost (default: false) */
1739
- disableSpeedBoost?: boolean;
1740
- /** Speed multiplier for speed boost (default: 2) */
1741
- speedBoostSpeed?: number;
1742
- /** Hold delay in ms before speed boost activates (default: 2000) */
1743
- speedBoostHoldDelay?: number;
1744
- /** Pull-down distance in px to trigger speed lock (default: 50) */
1745
- speedBoostPullDownThreshold?: number;
1746
1717
  className?: string;
1747
1718
  }
1748
1719
  declare const DefaultVideoSlot: react.NamedExoticComponent<DefaultVideoSlotProps>;
1749
1720
 
1721
+ /**
1722
+ * Snap-back animation type
1723
+ * - 'none': Instant snap (no animation)
1724
+ * - 'ease': Smooth ease-out transition
1725
+ * - 'spring': Spring-like bounce effect
1726
+ */
1727
+ type SnapBackAnimation = 'none' | 'ease' | 'spring';
1728
+ /**
1729
+ * Configuration for useZoomGesture
1730
+ */
1731
+ interface UseZoomGestureConfig {
1732
+ /** Minimum scale factor (default: 1) */
1733
+ minScale?: number;
1734
+ /** Maximum scale factor (default: 5) */
1735
+ maxScale?: number;
1736
+ /** Whether to lock vertical swipe during zoom (default: true) */
1737
+ lockVerticalSwipe?: boolean;
1738
+ /**
1739
+ * Snap-back animation type (default: 'ease')
1740
+ * - 'none': Instant snap, onZoomEnd called immediately
1741
+ * - 'ease': Smooth ease-out, onZoomEnd called after duration
1742
+ * - 'spring': Spring bounce effect, onZoomEnd called after duration
1743
+ */
1744
+ snapBackAnimation?: SnapBackAnimation;
1745
+ /** Snap-back animation duration in ms (default: 200) */
1746
+ snapBackDuration?: number;
1747
+ /** Callback when zoom starts (scale > 1) */
1748
+ onZoomStart?: () => void;
1749
+ /** Callback when zoom ends (after snap-back animation completes) */
1750
+ onZoomEnd?: (finalScale: number) => void;
1751
+ /** Callback on scale change during gesture */
1752
+ onZoomChange?: (scale: number) => void;
1753
+ /** Whether zoom is enabled (default: true) */
1754
+ enabled?: boolean;
1755
+ }
1756
+ /**
1757
+ * Touch event handlers
1758
+ */
1759
+ interface ZoomGestureHandlers {
1760
+ onTouchStart: (e: react__default.TouchEvent) => void;
1761
+ onTouchMove: (e: react__default.TouchEvent) => void;
1762
+ onTouchEnd: (e: react__default.TouchEvent) => void;
1763
+ }
1764
+ /**
1765
+ * Return type for useZoomGesture
1766
+ */
1767
+ interface UseZoomGestureReturn {
1768
+ /** Current scale factor (1 = normal) */
1769
+ scale: number;
1770
+ /** Current X translation in pixels */
1771
+ translateX: number;
1772
+ /** Current Y translation in pixels */
1773
+ translateY: number;
1774
+ /** Whether actively zooming (2+ fingers) */
1775
+ isZooming: boolean;
1776
+ /** Whether currently panning while zoomed */
1777
+ isPanning: boolean;
1778
+ /** Whether snap-back animation is playing */
1779
+ isAnimating: boolean;
1780
+ /** Whether vertical swipe is locked */
1781
+ isSwipeLocked: boolean;
1782
+ /** Touch event handlers to spread on container */
1783
+ handlers: ZoomGestureHandlers;
1784
+ /** Manually reset to default state */
1785
+ reset: () => void;
1786
+ /** CSS transform string for convenience */
1787
+ transform: string;
1788
+ /** CSS transform-origin string */
1789
+ transformOrigin: string;
1790
+ /**
1791
+ * CSS styles for container element.
1792
+ * Includes `touchAction: 'none'` for proper gesture handling on mobile.
1793
+ * Always spread this on your container for best compatibility.
1794
+ */
1795
+ containerStyle: react__default.CSSProperties;
1796
+ /**
1797
+ * CSS transition string for snap-back animation.
1798
+ * Apply this to the transform property for smooth animations.
1799
+ */
1800
+ transitionStyle: react__default.CSSProperties;
1801
+ }
1802
+ /**
1803
+ * useZoomGesture - Pinch-to-zoom gesture handler
1804
+ *
1805
+ * Handles pinch gestures for video zoom with pan support.
1806
+ * Always snaps back to scale=1 on release (Instagram Reels behavior).
1807
+ *
1808
+ * @example
1809
+ * ```tsx
1810
+ * function VideoPlayer({ video }: { video: VideoItem }) {
1811
+ * const {
1812
+ * transform,
1813
+ * transformOrigin,
1814
+ * containerStyle,
1815
+ * handlers,
1816
+ * isZooming,
1817
+ * } = useZoomGesture({
1818
+ * onZoomStart: () => enterCleanMode('zoom'),
1819
+ * onZoomEnd: () => exitCleanMode(),
1820
+ * snapBackAnimation: 'ease', // smooth snap-back
1821
+ * });
1822
+ *
1823
+ * return (
1824
+ * <div
1825
+ * style={{
1826
+ * ...containerStyle, // includes touchAction: 'none' for proper gesture handling
1827
+ * transform,
1828
+ * transformOrigin,
1829
+ * }}
1830
+ * {...handlers}
1831
+ * >
1832
+ * <video src={video.url} />
1833
+ * </div>
1834
+ * );
1835
+ * }
1836
+ * ```
1837
+ *
1838
+ * @remarks
1839
+ * **Important:** Always spread `containerStyle` on your container element.
1840
+ * This sets `touchAction: 'none'` which is required for `preventDefault()` to work
1841
+ * on mobile browsers (Chrome 56+, Safari) where touch events are passive by default.
1842
+ */
1843
+ declare function useZoomGesture(config?: UseZoomGestureConfig): UseZoomGestureReturn;
1844
+
1750
1845
  /**
1751
1846
  * Minimum requirements for content used in SlotComposer
1752
1847
  */
@@ -1778,6 +1873,14 @@ interface ComposerState {
1778
1873
  isMenuOpen: boolean;
1779
1874
  /** Whether report sheet is open */
1780
1875
  isReportSheetOpen: boolean;
1876
+ /** Zoom transform property */
1877
+ zoomTransform: string;
1878
+ /** Zoom transform origin */
1879
+ zoomTransformOrigin: string;
1880
+ /** Zoom container style (includes touchAction: 'none') */
1881
+ zoomContainerStyle: React.CSSProperties;
1882
+ /** Zoom snap-back transition style */
1883
+ zoomTransitionStyle: React.CSSProperties;
1781
1884
  }
1782
1885
  /**
1783
1886
  * Handlers provided by SlotComposer
@@ -1801,6 +1904,8 @@ interface ComposerHandlers {
1801
1904
  setCommentSheetOpen: (open: boolean) => void;
1802
1905
  setMenuOpen: (open: boolean) => void;
1803
1906
  setReportSheetOpen: (open: boolean) => void;
1907
+ /** Pinch-to-zoom touch event handlers */
1908
+ zoomHandlers: ReturnType<typeof useZoomGesture>['handlers'];
1804
1909
  }
1805
1910
  /**
1806
1911
  * Pre-configured wired components
@@ -3754,130 +3859,6 @@ interface UseAdvancedControlsConfig {
3754
3859
  */
3755
3860
  declare function useAdvancedControls(config?: UseAdvancedControlsConfig): UseAdvancedControlsReturn;
3756
3861
 
3757
- /**
3758
- * Snap-back animation type
3759
- * - 'none': Instant snap (no animation)
3760
- * - 'ease': Smooth ease-out transition
3761
- * - 'spring': Spring-like bounce effect
3762
- */
3763
- type SnapBackAnimation = 'none' | 'ease' | 'spring';
3764
- /**
3765
- * Configuration for useZoomGesture
3766
- */
3767
- interface UseZoomGestureConfig {
3768
- /** Minimum scale factor (default: 1) */
3769
- minScale?: number;
3770
- /** Maximum scale factor (default: 5) */
3771
- maxScale?: number;
3772
- /** Whether to lock vertical swipe during zoom (default: true) */
3773
- lockVerticalSwipe?: boolean;
3774
- /**
3775
- * Snap-back animation type (default: 'ease')
3776
- * - 'none': Instant snap, onZoomEnd called immediately
3777
- * - 'ease': Smooth ease-out, onZoomEnd called after duration
3778
- * - 'spring': Spring bounce effect, onZoomEnd called after duration
3779
- */
3780
- snapBackAnimation?: SnapBackAnimation;
3781
- /** Snap-back animation duration in ms (default: 200) */
3782
- snapBackDuration?: number;
3783
- /** Callback when zoom starts (scale > 1) */
3784
- onZoomStart?: () => void;
3785
- /** Callback when zoom ends (after snap-back animation completes) */
3786
- onZoomEnd?: (finalScale: number) => void;
3787
- /** Callback on scale change during gesture */
3788
- onZoomChange?: (scale: number) => void;
3789
- /** Whether zoom is enabled (default: true) */
3790
- enabled?: boolean;
3791
- }
3792
- /**
3793
- * Touch event handlers
3794
- */
3795
- interface ZoomGestureHandlers {
3796
- onTouchStart: (e: react__default.TouchEvent) => void;
3797
- onTouchMove: (e: react__default.TouchEvent) => void;
3798
- onTouchEnd: (e: react__default.TouchEvent) => void;
3799
- }
3800
- /**
3801
- * Return type for useZoomGesture
3802
- */
3803
- interface UseZoomGestureReturn {
3804
- /** Current scale factor (1 = normal) */
3805
- scale: number;
3806
- /** Current X translation in pixels */
3807
- translateX: number;
3808
- /** Current Y translation in pixels */
3809
- translateY: number;
3810
- /** Whether actively zooming (2+ fingers) */
3811
- isZooming: boolean;
3812
- /** Whether currently panning while zoomed */
3813
- isPanning: boolean;
3814
- /** Whether snap-back animation is playing */
3815
- isAnimating: boolean;
3816
- /** Whether vertical swipe is locked */
3817
- isSwipeLocked: boolean;
3818
- /** Touch event handlers to spread on container */
3819
- handlers: ZoomGestureHandlers;
3820
- /** Manually reset to default state */
3821
- reset: () => void;
3822
- /** CSS transform string for convenience */
3823
- transform: string;
3824
- /** CSS transform-origin string */
3825
- transformOrigin: string;
3826
- /**
3827
- * CSS styles for container element.
3828
- * Includes `touchAction: 'none'` for proper gesture handling on mobile.
3829
- * Always spread this on your container for best compatibility.
3830
- */
3831
- containerStyle: react__default.CSSProperties;
3832
- /**
3833
- * CSS transition string for snap-back animation.
3834
- * Apply this to the transform property for smooth animations.
3835
- */
3836
- transitionStyle: react__default.CSSProperties;
3837
- }
3838
- /**
3839
- * useZoomGesture - Pinch-to-zoom gesture handler
3840
- *
3841
- * Handles pinch gestures for video zoom with pan support.
3842
- * Always snaps back to scale=1 on release (Instagram Reels behavior).
3843
- *
3844
- * @example
3845
- * ```tsx
3846
- * function VideoPlayer({ video }: { video: VideoItem }) {
3847
- * const {
3848
- * transform,
3849
- * transformOrigin,
3850
- * containerStyle,
3851
- * handlers,
3852
- * isZooming,
3853
- * } = useZoomGesture({
3854
- * onZoomStart: () => enterCleanMode('zoom'),
3855
- * onZoomEnd: () => exitCleanMode(),
3856
- * snapBackAnimation: 'ease', // smooth snap-back
3857
- * });
3858
- *
3859
- * return (
3860
- * <div
3861
- * style={{
3862
- * ...containerStyle, // includes touchAction: 'none' for proper gesture handling
3863
- * transform,
3864
- * transformOrigin,
3865
- * }}
3866
- * {...handlers}
3867
- * >
3868
- * <video src={video.url} />
3869
- * </div>
3870
- * );
3871
- * }
3872
- * ```
3873
- *
3874
- * @remarks
3875
- * **Important:** Always spread `containerStyle` on your container element.
3876
- * This sets `touchAction: 'none'` which is required for `preventDefault()` to work
3877
- * on mobile browsers (Chrome 56+, Safari) where touch events are passive by default.
3878
- */
3879
- declare function useZoomGesture(config?: UseZoomGestureConfig): UseZoomGestureReturn;
3880
-
3881
3862
  /**
3882
3863
  * useReportedVideo - Hook to check/manage reported video state
3883
3864
  *
package/dist/index.js CHANGED
@@ -46,19 +46,17 @@ var PlaylistFeedAdapter = class {
46
46
  });
47
47
  });
48
48
  }
49
- const currentState = this.playlistManager.store.getState();
50
- const items = currentState.items;
49
+ const items = this.playlistManager.getFullItems();
51
50
  return {
52
51
  items,
53
52
  nextCursor: null,
54
- // Playlist sliding window handles content
53
+ // Playlist is finite — sliding window manages memory, not pagination
55
54
  hasMore: false
56
55
  };
57
56
  }
58
57
  async getContentDetail(id) {
59
- const state = this.playlistManager.store.getState();
60
- const item = state.items.find((i) => i.id === id);
61
- if (item) return item;
58
+ const fullItem = this.playlistManager.getFullItems().find((i) => i.id === id);
59
+ if (fullItem) return fullItem;
62
60
  throw new Error(`Content not found in playlist: ${id}`);
63
61
  }
64
62
  /**
@@ -3742,8 +3740,8 @@ function PlaylistSheet({ headerAccessory, translations }) {
3742
3740
  );
3743
3741
  const isOpen = state.isPlaylistSheetOpen;
3744
3742
  const onClose = useCallback(() => {
3745
- state.closePlaylistSheet();
3746
- }, [state]);
3743
+ uiStore.getState().closePlaylistSheet();
3744
+ }, [uiStore]);
3747
3745
  const handleItemSelect = useCallback(
3748
3746
  (index) => {
3749
3747
  jumpTo(index);
@@ -4419,7 +4417,14 @@ function SlotComposer({
4419
4417
  const reactiveContent = useFeedSelector(
4420
4418
  (state) => state.itemsById.get(initialContent.id) ?? initialContent
4421
4419
  );
4422
- const { isZooming } = useZoomGesture({
4420
+ const {
4421
+ isZooming,
4422
+ transform,
4423
+ transformOrigin,
4424
+ containerStyle,
4425
+ transitionStyle,
4426
+ handlers: zoomHandlers
4427
+ } = useZoomGesture({
4423
4428
  enabled: true,
4424
4429
  maxScale: zoomMaxScale,
4425
4430
  snapBackAnimation: zoomSnapBackAnimation,
@@ -4500,6 +4505,10 @@ function SlotComposer({
4500
4505
  state: {
4501
4506
  cleanMode,
4502
4507
  isZoomActive: isZooming,
4508
+ zoomTransform: transform,
4509
+ zoomTransformOrigin: transformOrigin,
4510
+ zoomContainerStyle: containerStyle,
4511
+ zoomTransitionStyle: transitionStyle,
4503
4512
  isLiked: reactiveContent.isLiked ?? false,
4504
4513
  isBookmarked,
4505
4514
  isCommentSheetOpen,
@@ -4516,7 +4525,8 @@ function SlotComposer({
4516
4525
  handleCloseAll,
4517
4526
  setCommentSheetOpen,
4518
4527
  setMenuOpen,
4519
- setReportSheetOpen
4528
+ setReportSheetOpen,
4529
+ zoomHandlers
4520
4530
  },
4521
4531
  components: {
4522
4532
  ActionBarComponent: ({ icons, onOpenComments: onOpenC, onShare: onS }) => {
@@ -4579,6 +4589,11 @@ function SlotComposer({
4579
4589
  initialContent.id,
4580
4590
  cleanMode,
4581
4591
  isZooming,
4592
+ transform,
4593
+ transformOrigin,
4594
+ containerStyle,
4595
+ transitionStyle,
4596
+ zoomHandlers,
4582
4597
  isBookmarked,
4583
4598
  isCommentSheetOpen,
4584
4599
  isMenuOpen,
@@ -5236,11 +5251,7 @@ function VideoSlot({
5236
5251
  reportedTitle,
5237
5252
  reportedMessage,
5238
5253
  reportedButtonText,
5239
- style,
5240
- disableSpeedBoost,
5241
- speedBoostSpeed,
5242
- speedBoostHoldDelay,
5243
- speedBoostPullDownThreshold
5254
+ style
5244
5255
  }) {
5245
5256
  const { playerEngine, uiStore } = useSDK();
5246
5257
  const { shouldShowOverlay, dismissOverlay } = useReportedVideo(video.id);
@@ -5301,31 +5312,6 @@ function VideoSlot({
5301
5312
  const setVolume = useCallback((v) => playerEngine.setVolume(v), [playerEngine]);
5302
5313
  const toggleMute = useCallback(() => playerEngine.setMuted(!muted), [playerEngine, muted]);
5303
5314
  const setMuted = useCallback((m) => playerEngine.setMuted(m), [playerEngine]);
5304
- const speedLockedVideoIdRef = useRef(null);
5305
- const preBoostSpeedRef = useRef(1);
5306
- const handleSpeedBoost = useCallback(
5307
- (speed) => {
5308
- preBoostSpeedRef.current = playerEngine.store.getState().playbackRate;
5309
- playerEngine.setPlaybackRate(speed);
5310
- },
5311
- [playerEngine]
5312
- );
5313
- const handleSpeedReset = useCallback(() => {
5314
- playerEngine.setPlaybackRate(preBoostSpeedRef.current);
5315
- }, [playerEngine]);
5316
- const handleSpeedLock = useCallback(
5317
- (speed) => {
5318
- playerEngine.setPlaybackRate(speed);
5319
- speedLockedVideoIdRef.current = video.id;
5320
- },
5321
- [playerEngine, video.id]
5322
- );
5323
- useEffect(() => {
5324
- if (speedLockedVideoIdRef.current && speedLockedVideoIdRef.current !== video.id) {
5325
- speedLockedVideoIdRef.current = null;
5326
- playerEngine.setPlaybackRate(1);
5327
- }
5328
- }, [video.id, playerEngine]);
5329
5315
  const baseResourceState = useMemo(
5330
5316
  () => resourceStateOverride ?? mapToResourceState(allocation, index, focusedIndex),
5331
5317
  [resourceStateOverride, allocation, index, focusedIndex]
@@ -5371,13 +5357,6 @@ function VideoSlot({
5371
5357
  renderError,
5372
5358
  renderLoading,
5373
5359
  restoreFrame: pendingRestoreFrame ?? void 0,
5374
- onSpeedBoost: disableSpeedBoost ? void 0 : handleSpeedBoost,
5375
- onSpeedReset: disableSpeedBoost ? void 0 : handleSpeedReset,
5376
- onSpeedLock: disableSpeedBoost ? void 0 : handleSpeedLock,
5377
- disableSpeedBoost,
5378
- speedBoostSpeed,
5379
- speedBoostHoldDelay,
5380
- speedBoostPullDownThreshold,
5381
5360
  children: [
5382
5361
  children,
5383
5362
  shouldShowOverlay && /* @__PURE__ */ jsx(
@@ -5474,13 +5453,25 @@ function DefaultVideoSlotContent(props) {
5474
5453
  renderError: renderError ?? defaultErrorRenderer,
5475
5454
  className,
5476
5455
  disableTap: enableZoom && isZoomActive,
5477
- disableSpeedBoost: props.disableSpeedBoost,
5478
- speedBoostSpeed: props.speedBoostSpeed,
5479
- speedBoostHoldDelay: props.speedBoostHoldDelay,
5480
- speedBoostPullDownThreshold: props.speedBoostPullDownThreshold,
5481
5456
  onHidden: () => onContentHidden?.(video.id),
5482
5457
  children: [
5483
- renderPlayer ? renderPlayer({ muted: false }) : /* @__PURE__ */ jsx(VideoPlayer, { muted: false }),
5458
+ enableZoom ? /* @__PURE__ */ jsx(
5459
+ "div",
5460
+ {
5461
+ style: {
5462
+ ...state.zoomContainerStyle,
5463
+ transform: state.zoomTransform,
5464
+ transformOrigin: state.zoomTransformOrigin,
5465
+ transition: state.zoomTransitionStyle.transition,
5466
+ position: "absolute",
5467
+ inset: 0,
5468
+ width: "100%",
5469
+ height: "100%"
5470
+ },
5471
+ ...handlers.zoomHandlers,
5472
+ children: renderPlayer ? renderPlayer({ muted: false }) : /* @__PURE__ */ jsx(VideoPlayer, { muted: false })
5473
+ }
5474
+ ) : renderPlayer ? renderPlayer({ muted: false }) : /* @__PURE__ */ jsx(VideoPlayer, { muted: false }),
5484
5475
  showPoster && !isZoomActive && !cleanMode && /* @__PURE__ */ jsx(VideoSlotPoster, {}),
5485
5476
  showPlayIndicator && !isZoomActive && /* @__PURE__ */ jsx(VideoSlotPlayIndicator, { persistWhenPaused: persistPlayIndicatorWhenPaused }),
5486
5477
  showLikeAnimation && /* @__PURE__ */ jsx(
@@ -6552,8 +6543,8 @@ function createSDK(config) {
6552
6543
  ...config?.optimistic
6553
6544
  });
6554
6545
  const uiStore = createUIStore();
6555
- const playlistManager = new PlaylistManager(playlist);
6556
- const playlistCollectionManager = new PlaylistCollectionManager(playlist);
6546
+ const playlistManager = new PlaylistManager(playlist, {}, resourceGovernor, storage);
6547
+ const playlistCollectionManager = new PlaylistCollectionManager(playlist, storage);
6557
6548
  const bootstrapSettings = async () => {
6558
6549
  try {
6559
6550
  const savedSpeed = await storage.get(STORAGE_KEY_SPEED);
@@ -6566,6 +6557,8 @@ function createSDK(config) {
6566
6557
  uiStore.getState().setAutoScrollEnabled(!!savedAutoScroll);
6567
6558
  logger.debug("[SDK] Restored auto-scroll from storage", { enabled: !!savedAutoScroll });
6568
6559
  }
6560
+ await playlistCollectionManager.hydrateFromCache();
6561
+ logger.debug("[SDK] Hydrated playlist collection from cache");
6569
6562
  } catch (error) {
6570
6563
  logger.error("[SDK] Failed to restore settings from storage", error);
6571
6564
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xhub-short/sdk",
3
3
  "sideEffects": false,
4
- "version": "1.0.0-beta.24",
4
+ "version": "1.0.0-beta.26",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -21,13 +21,13 @@
21
21
  ],
22
22
  "dependencies": {
23
23
  "zustand": "^5.0.0",
24
- "@xhub-short/contracts": "1.0.0-beta.24",
25
- "@xhub-short/adapters": "1.0.0-beta.24",
26
- "@xhub-short/ui": "1.0.0-beta.24",
27
- "@xhub-short/core": "1.0.0-beta.24"
24
+ "@xhub-short/contracts": "1.0.0-beta.26",
25
+ "@xhub-short/adapters": "1.0.0-beta.26",
26
+ "@xhub-short/core": "1.0.0-beta.26",
27
+ "@xhub-short/ui": "1.0.0-beta.26"
28
28
  },
29
29
  "optionalDependencies": {
30
- "@xhub-short/bridge": "0.1.0-beta.23"
30
+ "@xhub-short/bridge": "0.1.0-beta.25"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": "^19.0.0",
@@ -43,8 +43,8 @@
43
43
  "tsup": "^8.3.0",
44
44
  "typescript": "^5.7.0",
45
45
  "vitest": "^2.1.0",
46
- "@xhub-short/tsconfig": "0.1.0-beta.3",
47
- "@xhub-short/vitest-config": "0.1.0-beta.14"
46
+ "@xhub-short/vitest-config": "0.1.0-beta.13",
47
+ "@xhub-short/tsconfig": "0.0.1-beta.2"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsup",