@xhub-short/contracts 0.1.0-beta.9 → 1.0.0-beta.22

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.d.ts CHANGED
@@ -45,42 +45,60 @@ interface Author {
45
45
  isVerified?: boolean;
46
46
  }
47
47
  /**
48
- * Video statistics
48
+ * Music/Sound information for content
49
49
  */
50
- interface VideoStats {
51
- /** Total view count */
52
- views: number;
50
+ interface MusicInfo {
51
+ /** Music ID */
52
+ id: string;
53
+ /** Music title */
54
+ title: string;
55
+ /** Artist name */
56
+ artist: string;
57
+ /** Cover image URL */
58
+ cover?: string;
59
+ /**
60
+ * Audio URL for playback (optional)
61
+ * Required for Image Post background music
62
+ */
63
+ audioUrl?: string;
64
+ }
65
+ /**
66
+ * Base statistics shared by all content types
67
+ */
68
+ interface ContentStats {
53
69
  /** Total like count */
54
70
  likes: number;
55
71
  /** Total comment count */
56
72
  comments: number;
57
73
  /** Total share count */
58
74
  shares: number;
75
+ /** Total bookmark/save count (optional) */
76
+ bookmarks?: number;
77
+ /** Total view count */
78
+ views: number;
59
79
  }
60
80
  /**
61
- * Main video item structure
62
- * This is the core data model for a video in the feed
81
+ * Article statistics (alias for ContentStats)
82
+ * @see ContentStats
83
+ */
84
+ type ArticleStats = ContentStats;
85
+ /**
86
+ * @deprecated Use ArticleStats instead. Will be removed in v3.0
87
+ */
88
+ type ImagePostStats = ArticleStats;
89
+ /**
90
+ * Base content item shared by all content types
63
91
  */
64
- interface VideoItem {
65
- /** Unique video ID */
92
+ interface BaseContentItem {
93
+ /** Unique content ID */
66
94
  id: string;
67
- /** Video source configuration */
68
- source: VideoSource;
69
- /** Poster/thumbnail image URL */
70
- poster?: string;
71
- /** Video duration in seconds */
72
- duration: number;
73
- /** Video title/description */
74
- title?: string;
75
95
  /** Author information */
76
96
  author: Author;
77
- /** Video statistics */
78
- stats: VideoStats;
79
- /** Whether current user has liked this video */
97
+ /** Whether current user has liked this content */
80
98
  isLiked: boolean;
81
99
  /** Whether current user is following the author */
82
100
  isFollowing: boolean;
83
- /** Video creation timestamp */
101
+ /** Content creation timestamp */
84
102
  createdAt: string;
85
103
  /** Optional hashtags */
86
104
  hashtags?: string[];
@@ -88,24 +106,63 @@ interface VideoItem {
88
106
  music?: MusicInfo;
89
107
  }
90
108
  /**
91
- * Music/Sound information for a video
109
+ * Main video item structure
110
+ * This is the core data model for a video in the feed
92
111
  */
93
- interface MusicInfo {
94
- /** Music ID */
95
- id: string;
96
- /** Music title */
97
- title: string;
98
- /** Artist name */
99
- artist: string;
100
- /** Cover image URL */
101
- cover?: string;
112
+ interface VideoItem extends BaseContentItem {
113
+ /** Content type discriminator */
114
+ type: 'video';
115
+ /** Video source configuration */
116
+ source: VideoSource;
117
+ /** Poster/thumbnail image URL */
118
+ poster?: string;
119
+ /** Video duration in seconds */
120
+ duration: number;
121
+ /** Video title/description */
122
+ title?: string;
123
+ /** Video statistics */
124
+ stats: ContentStats;
102
125
  }
126
+ /**
127
+ * Article content structure
128
+ * Represents a carousel of images/other content in the feed
129
+ */
130
+ interface Article extends BaseContentItem {
131
+ /** Content type discriminator */
132
+ type: 'article';
133
+ /** Array of image URLs (1 or more) */
134
+ images: string[];
135
+ /** Post caption/description */
136
+ caption?: string;
137
+ /** Post statistics */
138
+ stats: ArticleStats;
139
+ }
140
+ /**
141
+ * @deprecated Use Article instead. Will be removed in v3.0
142
+ */
143
+ type ImagePost = Article;
144
+ /**
145
+ * Union type for all feed content types
146
+ * Use type guards to narrow the type
147
+ */
148
+ type ContentItem = VideoItem | Article;
103
149
  /**
104
150
  * Feed pagination response
151
+ *
152
+ * @typeParam T - Content item type (default: VideoItem for backward compatibility)
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * // Video-only feed (default, backward compatible)
157
+ * const feed: FeedResponse = await dataSource.fetchFeed();
158
+ *
159
+ * // Mixed content feed (videos + images) - for future use
160
+ * const mixedFeed: FeedResponse<ContentItem> = await dataSource.fetchFeed();
161
+ * ```
105
162
  */
106
- interface FeedResponse {
107
- /** List of video items */
108
- items: VideoItem[];
163
+ interface FeedResponse<T = ContentItem> {
164
+ /** List of content items */
165
+ items: T[];
109
166
  /** Cursor for next page (null if no more data) */
110
167
  nextCursor: string | null;
111
168
  /** Whether there are more items to load */
@@ -115,9 +172,9 @@ interface FeedResponse {
115
172
  * Feed state for state management
116
173
  */
117
174
  interface FeedState {
118
- /** Map of video items by ID (for O(1) lookup and deduplication) */
119
- itemsMap: Map<string, VideoItem>;
120
- /** Ordered list of video IDs for rendering */
175
+ /** Map of content items by ID (for O(1) lookup and deduplication) */
176
+ itemsMap: Map<string, ContentItem>;
177
+ /** Ordered list of item IDs for rendering */
121
178
  orderedIds: string[];
122
179
  /** Current cursor for pagination */
123
180
  cursor: string | null;
@@ -171,8 +228,10 @@ interface PlayerError {
171
228
  * Used by Lifecycle Manager for state restoration
172
229
  */
173
230
  interface SessionSnapshot {
174
- /** Video items from feed (for offline restore) */
175
- items: VideoItem[];
231
+ /** Content items from feed (for offline restore) */
232
+ items: ContentItem[];
233
+ /** @deprecated Use items instead. Will be removed in v3.0 */
234
+ videos?: VideoItem[];
176
235
  /** Feed cursor position for pagination */
177
236
  cursor: string | null;
178
237
  /** Index of the currently focused video */
@@ -294,6 +353,19 @@ interface LogEntry {
294
353
  stack?: string;
295
354
  }
296
355
 
356
+ /**
357
+ * Type guard to check if content is a VideoItem
358
+ */
359
+ declare function isVideoItem(item: ContentItem): item is VideoItem;
360
+ /**
361
+ * Type guard to check if content is an Article
362
+ */
363
+ declare function isArticle(item: ContentItem): item is Article;
364
+ /**
365
+ * @deprecated Use isArticle instead. Will be removed in v3.0
366
+ */
367
+ declare function isImagePost(item: ContentItem): item is Article;
368
+
297
369
  /**
298
370
  * Comment Feature Types
299
371
  * Supports nested replies (1 level), pagination, and optimistic updates
@@ -529,7 +601,7 @@ declare const DEFAULT_COMMENT_CONFIG: CommentConfig;
529
601
  /**
530
602
  * IDataSource - Data Port Interface
531
603
  *
532
- * This interface defines the contract for fetching video data.
604
+ * This interface defines the contract for fetching feed content.
533
605
  * SDK core never knows about specific APIs - it only talks to this interface.
534
606
  *
535
607
  * Implementations:
@@ -553,7 +625,7 @@ declare const DEFAULT_COMMENT_CONFIG: CommentConfig;
553
625
  */
554
626
  interface IDataSource {
555
627
  /**
556
- * Fetch a page of videos for the feed
628
+ * Fetch a page of items for the feed
557
629
  *
558
630
  * @param cursor - Pagination cursor from previous response (undefined for first page)
559
631
  * @returns Promise resolving to feed response with items and pagination info
@@ -566,21 +638,25 @@ interface IDataSource {
566
638
  */
567
639
  fetchFeed(cursor?: string): Promise<FeedResponse>;
568
640
  /**
569
- * Get detailed information for a specific video
641
+ * Get detailed information for a specific content item
570
642
  *
571
- * @param id - Video ID
572
- * @returns Promise resolving to video item details
573
- * @throws Error if video not found or network fails
643
+ * @param id - Content ID
644
+ * @returns Promise resolving to content item details
645
+ * @throws Error if content not found or network fails
574
646
  *
575
647
  * Implementation notes:
576
648
  * - May return cached data if available
577
- * - Should throw specific error for 404 (video deleted/not found)
649
+ * - Should throw specific error for 404 (content deleted/not found)
578
650
  */
579
- getVideoDetail(id: string): Promise<VideoItem>;
651
+ getContentDetail(id: string): Promise<ContentItem>;
580
652
  /**
581
- * Optional: Prefetch videos for smoother scrolling
653
+ * @deprecated Use getContentDetail instead. Will be removed in v3.0
654
+ */
655
+ getVideoDetail?(id: string): Promise<VideoItem>;
656
+ /**
657
+ * Optional: Prefetch content for smoother scrolling
582
658
  *
583
- * @param ids - Array of video IDs to prefetch
659
+ * @param ids - Array of content IDs to prefetch
584
660
  * @returns Promise resolving when prefetch is complete
585
661
  *
586
662
  * Implementation notes:
@@ -591,6 +667,17 @@ interface IDataSource {
591
667
  prefetch?(ids: string[]): Promise<void>;
592
668
  }
593
669
 
670
+ /**
671
+ * Report reason option from API
672
+ */
673
+ interface ReportReason {
674
+ /** Unique reason ID */
675
+ id: string;
676
+ /** Display label */
677
+ label: string;
678
+ /** Optional description */
679
+ description?: string;
680
+ }
594
681
  /**
595
682
  * IInteraction - Interaction Port Interface
596
683
  *
@@ -709,13 +796,34 @@ interface IInteraction {
709
796
  * @returns Promise that resolves when report is submitted
710
797
  */
711
798
  report?(videoId: string, reason: string, description?: string): Promise<void>;
799
+ /**
800
+ * Get available report reasons from API
801
+ *
802
+ * @returns Promise resolving to array of report reasons
803
+ *
804
+ * Implementation notes:
805
+ * - Returns list of reasons for report form UI
806
+ * - Can be cached by adapter
807
+ */
808
+ getReportReasons?(): Promise<ReportReason[]>;
809
+ /**
810
+ * Mark content as "not interested"
811
+ *
812
+ * @param contentId - ID of the content (video or image post)
813
+ * @returns Promise that resolves when marked
814
+ *
815
+ * Implementation notes:
816
+ * - Used for recommendation algorithm feedback
817
+ * - Content should be hidden from feed after this
818
+ */
819
+ notInterested?(contentId: string): Promise<void>;
712
820
  }
713
821
 
714
822
  /**
715
823
  * Data structure for prefetch cache
716
824
  *
717
825
  * Stored in localStorage for instant feed loading on fresh app open.
718
- * Contains video metadata (NOT video data) for immediate display.
826
+ * Contains content metadata (NOT heavy media data) for immediate display.
719
827
  *
720
828
  * @example
721
829
  * ```typescript
@@ -729,10 +837,10 @@ interface IInteraction {
729
837
  */
730
838
  interface PrefetchCacheData {
731
839
  /**
732
- * Cached video items (tail of feed - videos user hasn't seen)
840
+ * Cached content items (tail of feed - items user hasn't seen)
733
841
  * These are shown instantly on fresh load
734
842
  */
735
- items: VideoItem[];
843
+ items: ContentItem[];
736
844
  /**
737
845
  * Timestamp when cache was saved
738
846
  * Used for debugging and potential TTL features
@@ -829,6 +937,18 @@ interface IStorage {
829
937
  * - Used for debugging and LRU eviction
830
938
  */
831
939
  keys(): Promise<string[]>;
940
+ /**
941
+ * Get a value from storage synchronously (optional)
942
+ *
943
+ * Used for zero-flash cache hydration during React render phase.
944
+ * Only implement if the underlying storage supports synchronous reads
945
+ * (e.g., localStorage). Async-only storage (e.g., IndexedDB) should
946
+ * not implement this.
947
+ *
948
+ * @param key - Storage key
949
+ * @returns The stored value or null if not found / not supported
950
+ */
951
+ getSync?<T>(key: string): T | null;
832
952
  }
833
953
  /**
834
954
  * Specialized interface for session snapshot storage
@@ -1481,7 +1601,7 @@ type MessageValues = Record<string, MessageValue>;
1481
1601
  * - number.* : Number formatting suffixes
1482
1602
  * - error.* : Generic errors
1483
1603
  */
1484
- type MessageKey = 'feed.loading' | 'feed.empty' | 'feed.endReached' | 'feed.error' | 'feed.retry' | 'player.loading' | 'player.error' | 'player.error.network' | 'player.error.decode' | 'player.error.notSupported' | 'player.error.aborted' | 'player.tapToRetry' | 'comment.title' | 'comment.placeholder' | 'comment.empty' | 'comment.loading' | 'comment.error' | 'comment.retry' | 'comment.post' | 'comment.reply' | 'comment.replyTo' | 'comment.viewReplies' | 'comment.hideReplies' | 'comment.loadReplies' | 'comment.viewMoreReplies' | 'comment.delete' | 'comment.edit' | 'comment.report' | 'comment.deleteConfirmTitle' | 'comment.deleteConfirmMessage' | 'comment.deleteConfirmButton' | 'comment.count' | 'comment.replyCount' | 'comment.expand' | 'comment.collapse' | 'action.like' | 'action.liked' | 'action.comment' | 'action.share' | 'action.bookmark' | 'action.bookmarked' | 'action.follow' | 'action.following' | 'time.now' | 'time.seconds' | 'time.minutes' | 'time.hours' | 'time.days' | 'time.weeks' | 'time.months' | 'time.years' | 'number.thousand' | 'number.million' | 'number.billion' | 'error.generic' | 'error.network' | 'error.timeout' | 'common.cancel' | 'cancel' | 'close' | 'ok' | 'done' | 'aria.loading' | 'aria.videoPlayer' | 'aria.retry' | 'aria.sortComments' | 'aria.closeComments' | 'aria.addMedia' | 'aria.submitComment' | 'aria.openEmoji' | 'aria.cancelReply' | 'guest.loginToComment';
1604
+ type MessageKey = 'feed.loading' | 'feed.empty' | 'feed.endReached' | 'feed.error' | 'feed.retry' | 'player.loading' | 'player.error' | 'player.error.network' | 'player.error.decode' | 'player.error.notSupported' | 'player.error.aborted' | 'player.tapToRetry' | 'comment.title' | 'comment.placeholder' | 'comment.empty' | 'comment.loading' | 'comment.error' | 'comment.retry' | 'comment.post' | 'comment.reply' | 'comment.replyTo' | 'comment.viewReplies' | 'comment.hideReplies' | 'comment.loadReplies' | 'comment.viewMoreReplies' | 'comment.delete' | 'comment.edit' | 'comment.report' | 'comment.deleteConfirmTitle' | 'comment.deleteConfirmMessage' | 'comment.deleteConfirmButton' | 'comment.count' | 'comment.replyCount' | 'comment.expand' | 'comment.collapse' | 'action.like' | 'action.liked' | 'action.comment' | 'action.share' | 'action.bookmark' | 'action.bookmarked' | 'action.follow' | 'action.following' | 'time.now' | 'time.seconds' | 'time.minutes' | 'time.hours' | 'time.days' | 'time.weeks' | 'time.months' | 'time.years' | 'number.thousand' | 'number.million' | 'number.billion' | 'error.generic' | 'error.network' | 'error.timeout' | 'common.cancel' | 'cancel' | 'close' | 'ok' | 'done' | 'aria.loading' | 'aria.videoPlayer' | 'aria.retry' | 'aria.sortComments' | 'aria.closeComments' | 'aria.addMedia' | 'aria.submitComment' | 'aria.openEmoji' | 'aria.cancelReply' | 'guest.loginToComment' | 'playlist.collection.title' | 'playlist.collection.items_count' | 'playlist.collection.empty_title' | 'playlist.collection.empty_desc' | 'playlist.collection.error_title' | 'playlist.collection.retry' | 'playlist.collection.return_home';
1485
1605
  /**
1486
1606
  * Complete message catalog type
1487
1607
  * All keys must be present
@@ -1567,6 +1687,85 @@ interface LocalizationConfig {
1567
1687
  adapter?: ILocalization;
1568
1688
  }
1569
1689
 
1690
+ /**
1691
+ * Playlist data structure
1692
+ */
1693
+ interface PlaylistData {
1694
+ /** Unique playlist ID */
1695
+ id: string;
1696
+ /** Playlist title */
1697
+ title: string;
1698
+ /** Playlist description */
1699
+ description?: string;
1700
+ /** Playlist cover image URL */
1701
+ cover?: string;
1702
+ /** List of content items in this playlist */
1703
+ items: ContentItem[];
1704
+ /** Total number of items in playlist */
1705
+ totalItems: number;
1706
+ }
1707
+ /**
1708
+ * Playlist item metadata (within a playlist)
1709
+ */
1710
+ type PlaylistItem = ContentItem & {
1711
+ /** Position in the playlist (0-indexed) */
1712
+ position: number;
1713
+ /** ID of the playlist this item belongs to */
1714
+ playlistId: string;
1715
+ };
1716
+ /**
1717
+ * Summary of a playlist for collection views
1718
+ */
1719
+ interface PlaylistSummary {
1720
+ /** Unique playlist ID */
1721
+ id: string;
1722
+ /** Playlist title */
1723
+ title: string;
1724
+ /** Playlist description */
1725
+ description?: string;
1726
+ /** Playlist cover image URL */
1727
+ cover?: string;
1728
+ /** Total number of items in playlist */
1729
+ totalItems: number;
1730
+ /** Author/Creator information */
1731
+ author?: {
1732
+ id: string;
1733
+ name: string;
1734
+ };
1735
+ /** Last update timestamp */
1736
+ updatedAt?: string;
1737
+ }
1738
+ /**
1739
+ * Response structure for playlist collection
1740
+ */
1741
+ interface PlaylistCollectionResponse {
1742
+ /** List of playlist summaries */
1743
+ playlists: PlaylistSummary[];
1744
+ /** Cursor for next page (null if no more data) */
1745
+ nextCursor: string | null;
1746
+ /** Whether there are more items to load */
1747
+ hasMore: boolean;
1748
+ }
1749
+ /**
1750
+ * Port for fetching playlist data
1751
+ */
1752
+ interface IPlaylistDataSource {
1753
+ /**
1754
+ * Fetch a complete playlist by ID
1755
+ *
1756
+ * @param id - The playlist ID
1757
+ * @returns Promise resolving to PlaylistData
1758
+ */
1759
+ fetchPlaylist(id: string): Promise<PlaylistData>;
1760
+ /**
1761
+ * Fetch a collection of playlists
1762
+ *
1763
+ * @param cursor - Pagination cursor
1764
+ * @returns Promise resolving to PlaylistCollectionResponse
1765
+ */
1766
+ fetchPlaylistCollection(cursor?: string): Promise<PlaylistCollectionResponse>;
1767
+ }
1768
+
1570
1769
  /**
1571
1770
  * UI Component Types for XHub-short SDK
1572
1771
  *
@@ -1600,7 +1799,9 @@ type UIComponent<P = object> = (props: P) => UINode;
1600
1799
  * Feed state from useFeed() hook
1601
1800
  */
1602
1801
  interface UIFeedState {
1603
- /** List of video items */
1802
+ /** List of content items (Video or Article) */
1803
+ items: ContentItem[];
1804
+ /** @deprecated Use items instead. Will be removed in v3.0 */
1604
1805
  videos: VideoItem[];
1605
1806
  /** Whether feed is loading */
1606
1807
  isLoading: boolean;
@@ -1708,7 +1909,7 @@ interface UIInteractionState {
1708
1909
  interface UIInteractionActions {
1709
1910
  /** Toggle like state (debounced - updates UI immediately, API call is debounced) */
1710
1911
  toggleLike: () => void;
1711
- /** Share video */
1912
+ /** Share content */
1712
1913
  share: () => Promise<void>;
1713
1914
  /** Open comments */
1714
1915
  openComments: () => void;
@@ -1734,16 +1935,18 @@ interface UIAuthorActions {
1734
1935
  openProfile: () => void;
1735
1936
  }
1736
1937
  /**
1737
- * Video info state for VideoInfo component
1938
+ * Content info state for VideoInfo/ArticleInfo component
1738
1939
  */
1739
1940
  interface UIVideoInfoState {
1740
- /** Video item */
1741
- video: VideoItem;
1941
+ /** Content item (Video or Article) */
1942
+ content: ContentItem;
1943
+ /** @deprecated Use content instead. Will be removed in v3.0 */
1944
+ video?: VideoItem;
1742
1945
  /** Author name */
1743
1946
  authorName: string;
1744
1947
  /** Whether author is verified */
1745
1948
  isVerified: boolean;
1746
- /** Video caption/title */
1949
+ /** Content caption/title */
1747
1950
  caption: string;
1748
1951
  /** Hashtags array */
1749
1952
  hashtags: string[];
@@ -1771,10 +1974,41 @@ interface UIVideoInfoActions {
1771
1974
  onLocationClick?: () => void;
1772
1975
  }
1773
1976
  /**
1774
- * VideoFeed headless component props
1977
+ * Article-specific UI state
1775
1978
  */
1776
- interface VideoFeedHeadlessProps {
1777
- /** Feed state (videos, loading, etc.) */
1979
+ interface UIArticleState {
1980
+ /** Article item */
1981
+ article: Article;
1982
+ /** Current image index */
1983
+ currentImageIndex: number;
1984
+ /** Whether music is playing */
1985
+ isMusicPlaying: boolean;
1986
+ /** Last music toggle timestamp (for synchronization) */
1987
+ lastMusicToggleTime: number;
1988
+ }
1989
+ /**
1990
+ * Article-specific UI actions
1991
+ */
1992
+ interface UIArticleActions {
1993
+ /** Set current image index */
1994
+ setCurrentIndex: (index: number) => void;
1995
+ /** Toggle music playback */
1996
+ toggleMusic: () => void;
1997
+ /** Toggle like state */
1998
+ toggleLike: () => Promise<void>;
1999
+ /** Toggle bookmark state */
2000
+ toggleBookmark: () => void;
2001
+ /** Open detail view */
2002
+ openDetail: () => void;
2003
+ /** Close detail view */
2004
+ closeDetail: () => void;
2005
+ }
2006
+ /**
2007
+ * Feed headless component props
2008
+ * Position-based virtual scroller for mixed content.
2009
+ */
2010
+ interface FeedHeadlessProps {
2011
+ /** Feed state (items, loading, etc.) */
1778
2012
  feedState: UIFeedState;
1779
2013
  /** Swipe/scroll state */
1780
2014
  swipeState: UISwipeState;
@@ -1782,8 +2016,8 @@ interface VideoFeedHeadlessProps {
1782
2016
  height?: number | string;
1783
2017
  /** Additional CSS classes */
1784
2018
  className?: string;
1785
- /** Render function for each video slot */
1786
- renderSlot: (video: VideoItem, index: number) => UINode;
2019
+ /** Render function for each content slot */
2020
+ renderSlot: (item: ContentItem, index: number) => UINode;
1787
2021
  /** Called when active index changes */
1788
2022
  onIndexChange?: (index: number) => void;
1789
2023
  /** Called when reaching near end of feed */
@@ -1791,6 +2025,8 @@ interface VideoFeedHeadlessProps {
1791
2025
  /** Threshold for triggering onEndReached (default: 2) */
1792
2026
  endReachedThreshold?: number;
1793
2027
  }
2028
+ /** @deprecated Use FeedHeadlessProps instead. Will be removed in v3.0 */
2029
+ type VideoFeedHeadlessProps = FeedHeadlessProps;
1794
2030
  /**
1795
2031
  * VideoSlot headless component props
1796
2032
  */
@@ -1817,6 +2053,12 @@ interface VideoSlotHeadlessProps {
1817
2053
  * Displayed as instant preview while video loads.
1818
2054
  */
1819
2055
  restoreFrame?: string;
2056
+ /** Called when long-press speed boost activates (hold 2s → 2x speed) */
2057
+ onSpeedBoost?: (speed: number) => void;
2058
+ /** Called when speed boost deactivates (finger released, not locked) */
2059
+ onSpeedReset?: () => void;
2060
+ /** Called when speed is locked via pull-down gesture while boosted */
2061
+ onSpeedLock?: (speed: number) => void;
1820
2062
  }
1821
2063
  /**
1822
2064
  * VideoPlayer headless component props
@@ -1964,6 +2206,84 @@ interface VideoInfoHeadlessProps {
1964
2206
  /** Children (for compound pattern) */
1965
2207
  children?: UINode;
1966
2208
  }
2209
+ /**
2210
+ * ArticleSlot headless component props
2211
+ */
2212
+ interface ArticleSlotHeadlessProps {
2213
+ /** Article to display */
2214
+ article: Article;
2215
+ /** Whether slot is active */
2216
+ isActive: boolean;
2217
+ /** Current image index */
2218
+ currentImageIndex: number;
2219
+ /** Index change handler */
2220
+ onImageIndexChange: (index: number) => void;
2221
+ /** Music toggle handler */
2222
+ onToggleMusic: () => void;
2223
+ /** Whether music is playing */
2224
+ isMusicPlaying: boolean;
2225
+ /** Last music toggle timestamp */
2226
+ lastMusicToggleTime?: number;
2227
+ /** Double tap handler (usually for like) */
2228
+ onDoubleTap?: () => void;
2229
+ /** "Read More" click handler */
2230
+ onReadMoreClick?: () => void;
2231
+ /** Long press handler */
2232
+ onLongPress?: () => void;
2233
+ /** Single tap handler */
2234
+ onTap?: () => void;
2235
+ /** Swipe direction change handler (for gesture locking) */
2236
+ onSwipeDirectionChange?: (direction: 'horizontal' | 'vertical' | null) => void;
2237
+ /** Children (overlay content) */
2238
+ children?: UINode;
2239
+ /** Additional CSS classes */
2240
+ className?: string;
2241
+ /** Music info (optional) */
2242
+ music?: {
2243
+ id: string;
2244
+ title: string;
2245
+ artist: string;
2246
+ };
2247
+ }
2248
+ /** @deprecated Use ArticleSlotHeadlessProps instead */
2249
+ type ImagePostSlotHeadlessProps = ArticleSlotHeadlessProps;
2250
+ /**
2251
+ * DetailView headless component props
2252
+ */
2253
+ interface DetailViewHeadlessProps {
2254
+ /** Whether open */
2255
+ isOpen: boolean;
2256
+ /** Close handler */
2257
+ onClose: () => void;
2258
+ /** Article to display */
2259
+ article: Article;
2260
+ /** Initial index */
2261
+ initialImageIndex?: number;
2262
+ /** Header title */
2263
+ headerTitle?: string;
2264
+ /** Liked state */
2265
+ isLiked?: boolean;
2266
+ /** Following state */
2267
+ isFollowing?: boolean;
2268
+ /** Bookmarked state */
2269
+ isBookmarked?: boolean;
2270
+ /** Like handler */
2271
+ onLike?: () => void;
2272
+ /** Comment handler */
2273
+ onComment?: () => void;
2274
+ /** Share handler */
2275
+ onShare?: () => void;
2276
+ /** Bookmark handler */
2277
+ onBookmark?: () => void;
2278
+ /** Follow handler */
2279
+ onFollow?: () => void;
2280
+ /** Gesture lock handler */
2281
+ onGestureLock?: (locked: boolean) => void;
2282
+ /** Children (compound components) */
2283
+ children?: UINode;
2284
+ /** Custom bottom bar renderer */
2285
+ renderBottomBar?: (props: any) => UINode;
2286
+ }
1967
2287
  /**
1968
2288
  * ErrorBoundary component props
1969
2289
  */
@@ -1995,15 +2315,17 @@ interface SkeletonProps {
1995
2315
  className?: string;
1996
2316
  }
1997
2317
  /**
1998
- * VideoFeed wired component props
2318
+ * Feed wired component props
1999
2319
  * feedState and swipeState are injected by SDK
2000
2320
  */
2001
- interface VideoFeedProps extends Omit<VideoFeedHeadlessProps, 'feedState' | 'swipeState'> {
2321
+ interface FeedProps extends Omit<FeedHeadlessProps, 'feedState' | 'swipeState'> {
2002
2322
  /** Override feed state (optional) */
2003
2323
  feedState?: UIFeedState;
2004
2324
  /** Override swipe state (optional) */
2005
2325
  swipeState?: UISwipeState;
2006
2326
  }
2327
+ /** @deprecated Use FeedProps instead. Will be removed in v3.0 */
2328
+ type VideoFeedProps = FeedProps;
2007
2329
  /**
2008
2330
  * VideoSlot wired component props
2009
2331
  * resourceState, playerState, playerControls are injected by SDK
@@ -2029,8 +2351,10 @@ interface VideoPlayerWiredProps extends Partial<VideoPlayerHeadlessProps> {
2029
2351
  * interactionState and interactionActions are injected by SDK
2030
2352
  */
2031
2353
  interface ActionBarProps extends Omit<ActionBarHeadlessProps, 'interactionState' | 'interactionActions'> {
2032
- /** Video to get interaction state for */
2033
- video: VideoItem;
2354
+ /** Content to get interaction state for */
2355
+ content: ContentItem;
2356
+ /** @deprecated Use content instead. Will be removed in v3.0 */
2357
+ video?: VideoItem;
2034
2358
  /** Override interaction state (optional) */
2035
2359
  interactionState?: UIInteractionState;
2036
2360
  /** Override interaction actions (optional) */
@@ -2041,8 +2365,10 @@ interface ActionBarProps extends Omit<ActionBarHeadlessProps, 'interactionState'
2041
2365
  * authorState and authorActions are injected by SDK
2042
2366
  */
2043
2367
  interface AuthorInfoProps extends Omit<AuthorInfoHeadlessProps, 'authorState' | 'authorActions'> {
2044
- /** Video to get author from */
2045
- video: VideoItem;
2368
+ /** Content to get author from */
2369
+ content: ContentItem;
2370
+ /** @deprecated Use content instead. Will be removed in v3.0 */
2371
+ video?: VideoItem;
2046
2372
  /** Override author state (optional) */
2047
2373
  authorState?: UIAuthorState;
2048
2374
  /** Override author actions (optional) */
@@ -2053,8 +2379,10 @@ interface AuthorInfoProps extends Omit<AuthorInfoHeadlessProps, 'authorState' |
2053
2379
  * videoInfoState and videoInfoActions are injected by SDK
2054
2380
  */
2055
2381
  interface VideoInfoProps extends Omit<VideoInfoHeadlessProps, 'videoInfoState' | 'videoInfoActions'> {
2056
- /** Video to get info from */
2057
- video: VideoItem;
2382
+ /** Content to get info from */
2383
+ content: ContentItem;
2384
+ /** @deprecated Use content instead. Will be removed in v3.0 */
2385
+ video?: VideoItem;
2058
2386
  /** Override video info state (optional) */
2059
2387
  videoInfoState?: UIVideoInfoState;
2060
2388
  /** Override video info actions (optional) */
@@ -2276,4 +2604,4 @@ type IconComponent = UIComponent<{
2276
2604
  */
2277
2605
  type FormatCountFn = (count: number) => string;
2278
2606
 
2279
- export { type ActionBarHeadlessProps, type ActionBarProps, type ActionButtonHeadlessProps, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Author, type AuthorInfoHeadlessProps, type AuthorInfoProps, type Comment, type CommentAdapterConfig, type CommentAuthor, type CommentConfig, type CommentEndpoints, type CommentInputHeadlessProps, type CommentItem, type CommentItemHeadlessProps, type CommentListResponse, type CommentManagerState, type CommentReportReason, type CommentSheetHeadlessProps, type CommentSheetProps, type CommentState, type CommentTransformers, DEFAULT_COMMENT_CONFIG, DEFAULT_COMMENT_ENDPOINTS, type DeleteCommentPayload, type EditCommentPayload, type ErrorBoundaryProps, type FeedResponse, type FeedState, type FormatCountFn, type IAnalytics, type ICommentAdapter, type IDataSource, type IInteraction, type ILocalization, type ILogger, type INetworkAdapter, type IPosterLoader, type ISessionStorage, type IStorage, type IVideoLoader, type IconComponent, type InternalLogger, type LocalizationConfig, type LogEntry, type LogLevel, type LoggerConfig, type MessageCatalog, type MessageKey, type MessageValue, type MessageValues, type MockCommentAdapterConfig, type MusicInfo, type NetworkQuality, type NetworkType, type OptimisticAction, type PartialMessageCatalog, type PlaybackState, type PlayerError, type PlayerState, type PostCommentPayload, type PostReplyPayload, type PrefetchCacheData, type PreloadConfig, type PreloadResult, type PreloadStatus, type ProgressBarHeadlessProps, type ReplyItem, type ReplyItemHeadlessProps, type ReplyListResponse, type ReportCommentPayload, type SDKConfig, type SessionSnapshot, type SkeletonProps, type UIAuthorActions, type UIAuthorState, type UICommentActions, type UICommentState, type UIComponent, type UIFeedState, type UIInteractionActions, type UIInteractionState, type UINode, type UIPlayerControls, type UIPlayerState, type UIRef, type UIResourceState, type UISwipeState, type UIVideoInfoActions, type UIVideoInfoState, type VideoFeedHeadlessProps, type VideoFeedProps, type VideoInfoHeadlessProps, type VideoInfoProps, type VideoItem, type VideoPlayerHeadlessProps, type VideoPlayerWiredProps, type VideoQuality, type VideoSlotHeadlessProps, type VideoSlotProps, type VideoSource, type VideoStats, type WiredComponent, type WiredComponentConfig };
2607
+ export { type ActionBarHeadlessProps, type ActionBarProps, type ActionButtonHeadlessProps, type AnalyticsConfig, type AnalyticsEvent, type AnalyticsEventType, type Article, type ArticleSlotHeadlessProps, type ArticleStats, type Author, type AuthorInfoHeadlessProps, type AuthorInfoProps, type BaseContentItem, type Comment, type CommentAdapterConfig, type CommentAuthor, type CommentConfig, type CommentEndpoints, type CommentInputHeadlessProps, type CommentItem, type CommentItemHeadlessProps, type CommentListResponse, type CommentManagerState, type CommentReportReason, type CommentSheetHeadlessProps, type CommentSheetProps, type CommentState, type CommentTransformers, type ContentItem, type ContentStats, DEFAULT_COMMENT_CONFIG, DEFAULT_COMMENT_ENDPOINTS, type DeleteCommentPayload, type DetailViewHeadlessProps, type EditCommentPayload, type ErrorBoundaryProps, type FeedResponse, type FeedState, type FormatCountFn, type IAnalytics, type ICommentAdapter, type IDataSource, type IInteraction, type ILocalization, type ILogger, type INetworkAdapter, type IPlaylistDataSource, type IPosterLoader, type ISessionStorage, type IStorage, type IVideoLoader, type IconComponent, type ImagePost, type ImagePostSlotHeadlessProps, type ImagePostStats, type InternalLogger, type LocalizationConfig, type LogEntry, type LogLevel, type LoggerConfig, type MessageCatalog, type MessageKey, type MessageKey as MessageKeyType, type MessageValue, type MessageValues, type MockCommentAdapterConfig, type MusicInfo, type NetworkQuality, type NetworkType, type OptimisticAction, type PartialMessageCatalog, type PlaybackState, type PlayerError, type PlayerState, type PlaylistCollectionResponse, type PlaylistData, type PlaylistItem, type PlaylistSummary, type PostCommentPayload, type PostReplyPayload, type PrefetchCacheData, type PreloadConfig, type PreloadResult, type PreloadStatus, type ProgressBarHeadlessProps, type ReplyItem, type ReplyItemHeadlessProps, type ReplyListResponse, type ReportCommentPayload, type ReportReason, type SDKConfig, type SessionSnapshot, type SkeletonProps, type UIArticleActions, type UIArticleState, type UIAuthorActions, type UIAuthorState, type UICommentActions, type UICommentState, type UIComponent, type UIFeedState, type UIInteractionActions, type UIInteractionState, type UINode, type UIPlayerControls, type UIPlayerState, type UIRef, type UIResourceState, type UISwipeState, type UIVideoInfoActions, type UIVideoInfoState, type VideoFeedHeadlessProps, type VideoFeedProps, type VideoInfoHeadlessProps, type VideoInfoProps, type VideoItem, type VideoPlayerHeadlessProps, type VideoPlayerWiredProps, type VideoQuality, type VideoSlotHeadlessProps, type VideoSlotProps, type VideoSource, type WiredComponent, type WiredComponentConfig, isArticle, isImagePost, isVideoItem };
package/dist/index.js CHANGED
@@ -1,3 +1,17 @@
1
+ // src/type-guards.ts
2
+ function isVideoItem(item) {
3
+ return item.type === "video";
4
+ }
5
+ function isArticle(item) {
6
+ return item.type === "article";
7
+ }
8
+ function isImagePost(item) {
9
+ if (process.env.NODE_ENV !== "production") {
10
+ console.warn("[xhub-short] isImagePost is deprecated. Use isArticle instead.");
11
+ }
12
+ return isArticle(item);
13
+ }
14
+
1
15
  // src/comment-types.ts
2
16
  var DEFAULT_COMMENT_CONFIG = {
3
17
  pageSize: 20,
@@ -25,4 +39,4 @@ var DEFAULT_COMMENT_ENDPOINTS = {
25
39
  report: "/comments/:id/report"
26
40
  };
27
41
 
28
- export { DEFAULT_COMMENT_CONFIG, DEFAULT_COMMENT_ENDPOINTS };
42
+ export { DEFAULT_COMMENT_CONFIG, DEFAULT_COMMENT_ENDPOINTS, isArticle, isImagePost, isVideoItem };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xhub-short/contracts",
3
3
  "sideEffects": false,
4
- "version": "0.1.0-beta.9",
4
+ "version": "1.0.0-beta.22",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -20,14 +20,20 @@
20
20
  "dist"
21
21
  ],
22
22
  "devDependencies": {
23
+ "@types/node": "^22.0.0",
23
24
  "tsup": "^8.3.0",
24
25
  "typescript": "^5.7.0",
25
- "@xhub-short/tsconfig": "0.0.0"
26
+ "vitest": "^2.1.0",
27
+ "@vitest/coverage-v8": "^2.1.0",
28
+ "@xhub-short/tsconfig": "0.1.0-beta.3",
29
+ "@xhub-short/vitest-config": "0.1.0-beta.14"
26
30
  },
27
31
  "scripts": {
28
32
  "build": "tsup",
29
33
  "dev": "tsup --watch",
30
34
  "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "test:coverage": "vitest run --coverage",
31
37
  "clean": "rm -rf dist"
32
38
  }
33
39
  }