@xhub-short/contracts 0.1.0-beta.2 → 0.1.0-beta.20
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 +400 -76
- package/dist/index.js +16 -2
- package/package.json +8 -2
package/dist/index.d.ts
CHANGED
|
@@ -45,42 +45,60 @@ interface Author {
|
|
|
45
45
|
isVerified?: boolean;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
48
|
+
* Music/Sound information for content
|
|
49
49
|
*/
|
|
50
|
-
interface
|
|
51
|
-
/**
|
|
52
|
-
|
|
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
|
-
*
|
|
62
|
-
*
|
|
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
|
|
65
|
-
/** Unique
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
109
|
+
* Main video item structure
|
|
110
|
+
* This is the core data model for a video in the feed
|
|
92
111
|
*/
|
|
93
|
-
interface
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
|
|
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
|
|
108
|
-
items:
|
|
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
|
|
119
|
-
itemsMap: Map<string,
|
|
120
|
-
/** Ordered list of
|
|
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
|
-
/**
|
|
175
|
-
items:
|
|
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
|
|
@@ -436,11 +508,13 @@ interface EditCommentPayload {
|
|
|
436
508
|
* Payload for deleting a comment/reply
|
|
437
509
|
*/
|
|
438
510
|
interface DeleteCommentPayload {
|
|
511
|
+
/** Video/Reel ID */
|
|
512
|
+
videoId: string;
|
|
439
513
|
/** Comment/Reply ID */
|
|
440
|
-
|
|
441
|
-
/** Whether this is a reply (affects
|
|
514
|
+
commentId: string;
|
|
515
|
+
/** Whether this is a reply (affects local state update) */
|
|
442
516
|
isReply?: boolean;
|
|
443
|
-
/** Parent comment ID (required if isReply) */
|
|
517
|
+
/** Parent comment ID (required if isReply, for local state update) */
|
|
444
518
|
parentId?: string;
|
|
445
519
|
}
|
|
446
520
|
/**
|
|
@@ -527,7 +601,7 @@ declare const DEFAULT_COMMENT_CONFIG: CommentConfig;
|
|
|
527
601
|
/**
|
|
528
602
|
* IDataSource - Data Port Interface
|
|
529
603
|
*
|
|
530
|
-
* This interface defines the contract for fetching
|
|
604
|
+
* This interface defines the contract for fetching feed content.
|
|
531
605
|
* SDK core never knows about specific APIs - it only talks to this interface.
|
|
532
606
|
*
|
|
533
607
|
* Implementations:
|
|
@@ -551,7 +625,7 @@ declare const DEFAULT_COMMENT_CONFIG: CommentConfig;
|
|
|
551
625
|
*/
|
|
552
626
|
interface IDataSource {
|
|
553
627
|
/**
|
|
554
|
-
* Fetch a page of
|
|
628
|
+
* Fetch a page of items for the feed
|
|
555
629
|
*
|
|
556
630
|
* @param cursor - Pagination cursor from previous response (undefined for first page)
|
|
557
631
|
* @returns Promise resolving to feed response with items and pagination info
|
|
@@ -564,21 +638,25 @@ interface IDataSource {
|
|
|
564
638
|
*/
|
|
565
639
|
fetchFeed(cursor?: string): Promise<FeedResponse>;
|
|
566
640
|
/**
|
|
567
|
-
* Get detailed information for a specific
|
|
641
|
+
* Get detailed information for a specific content item
|
|
568
642
|
*
|
|
569
|
-
* @param id -
|
|
570
|
-
* @returns Promise resolving to
|
|
571
|
-
* @throws Error if
|
|
643
|
+
* @param id - Content ID
|
|
644
|
+
* @returns Promise resolving to content item details
|
|
645
|
+
* @throws Error if content not found or network fails
|
|
572
646
|
*
|
|
573
647
|
* Implementation notes:
|
|
574
648
|
* - May return cached data if available
|
|
575
|
-
* - Should throw specific error for 404 (
|
|
649
|
+
* - Should throw specific error for 404 (content deleted/not found)
|
|
650
|
+
*/
|
|
651
|
+
getContentDetail(id: string): Promise<ContentItem>;
|
|
652
|
+
/**
|
|
653
|
+
* @deprecated Use getContentDetail instead. Will be removed in v3.0
|
|
576
654
|
*/
|
|
577
|
-
getVideoDetail(id: string): Promise<VideoItem>;
|
|
655
|
+
getVideoDetail?(id: string): Promise<VideoItem>;
|
|
578
656
|
/**
|
|
579
|
-
* Optional: Prefetch
|
|
657
|
+
* Optional: Prefetch content for smoother scrolling
|
|
580
658
|
*
|
|
581
|
-
* @param ids - Array of
|
|
659
|
+
* @param ids - Array of content IDs to prefetch
|
|
582
660
|
* @returns Promise resolving when prefetch is complete
|
|
583
661
|
*
|
|
584
662
|
* Implementation notes:
|
|
@@ -589,6 +667,17 @@ interface IDataSource {
|
|
|
589
667
|
prefetch?(ids: string[]): Promise<void>;
|
|
590
668
|
}
|
|
591
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
|
+
}
|
|
592
681
|
/**
|
|
593
682
|
* IInteraction - Interaction Port Interface
|
|
594
683
|
*
|
|
@@ -707,13 +796,34 @@ interface IInteraction {
|
|
|
707
796
|
* @returns Promise that resolves when report is submitted
|
|
708
797
|
*/
|
|
709
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>;
|
|
710
820
|
}
|
|
711
821
|
|
|
712
822
|
/**
|
|
713
823
|
* Data structure for prefetch cache
|
|
714
824
|
*
|
|
715
825
|
* Stored in localStorage for instant feed loading on fresh app open.
|
|
716
|
-
* Contains
|
|
826
|
+
* Contains content metadata (NOT heavy media data) for immediate display.
|
|
717
827
|
*
|
|
718
828
|
* @example
|
|
719
829
|
* ```typescript
|
|
@@ -727,10 +837,10 @@ interface IInteraction {
|
|
|
727
837
|
*/
|
|
728
838
|
interface PrefetchCacheData {
|
|
729
839
|
/**
|
|
730
|
-
* Cached
|
|
840
|
+
* Cached content items (tail of feed - items user hasn't seen)
|
|
731
841
|
* These are shown instantly on fresh load
|
|
732
842
|
*/
|
|
733
|
-
items:
|
|
843
|
+
items: ContentItem[];
|
|
734
844
|
/**
|
|
735
845
|
* Timestamp when cache was saved
|
|
736
846
|
* Used for debugging and potential TTL features
|
|
@@ -827,6 +937,18 @@ interface IStorage {
|
|
|
827
937
|
* - Used for debugging and LRU eviction
|
|
828
938
|
*/
|
|
829
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;
|
|
830
952
|
}
|
|
831
953
|
/**
|
|
832
954
|
* Specialized interface for session snapshot storage
|
|
@@ -1408,7 +1530,7 @@ interface CommentEndpoints {
|
|
|
1408
1530
|
postReply: string;
|
|
1409
1531
|
/** Edit comment: PATCH /comments/:id */
|
|
1410
1532
|
edit: string;
|
|
1411
|
-
/** Delete comment: DELETE /comments/:
|
|
1533
|
+
/** Delete comment: DELETE /reels/:id/comments/:commentId */
|
|
1412
1534
|
delete: string;
|
|
1413
1535
|
/** Like comment: POST /comments/:id/like */
|
|
1414
1536
|
like: string;
|
|
@@ -1479,7 +1601,7 @@ type MessageValues = Record<string, MessageValue>;
|
|
|
1479
1601
|
* - number.* : Number formatting suffixes
|
|
1480
1602
|
* - error.* : Generic errors
|
|
1481
1603
|
*/
|
|
1482
|
-
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.report' | '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' | 'cancel' | 'close' | 'ok' | 'done' | 'aria.loading' | 'aria.videoPlayer' | 'aria.retry' | 'aria.sortComments' | 'aria.closeComments' | 'aria.addMedia' | 'aria.submitComment' | 'aria.openEmoji' | 'aria.cancelReply';
|
|
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';
|
|
1483
1605
|
/**
|
|
1484
1606
|
* Complete message catalog type
|
|
1485
1607
|
* All keys must be present
|
|
@@ -1565,6 +1687,85 @@ interface LocalizationConfig {
|
|
|
1565
1687
|
adapter?: ILocalization;
|
|
1566
1688
|
}
|
|
1567
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
|
+
|
|
1568
1769
|
/**
|
|
1569
1770
|
* UI Component Types for XHub-short SDK
|
|
1570
1771
|
*
|
|
@@ -1598,7 +1799,9 @@ type UIComponent<P = object> = (props: P) => UINode;
|
|
|
1598
1799
|
* Feed state from useFeed() hook
|
|
1599
1800
|
*/
|
|
1600
1801
|
interface UIFeedState {
|
|
1601
|
-
/** List of
|
|
1802
|
+
/** List of content items (Video or Article) */
|
|
1803
|
+
items: ContentItem[];
|
|
1804
|
+
/** @deprecated Use items instead. Will be removed in v3.0 */
|
|
1602
1805
|
videos: VideoItem[];
|
|
1603
1806
|
/** Whether feed is loading */
|
|
1604
1807
|
isLoading: boolean;
|
|
@@ -1706,7 +1909,7 @@ interface UIInteractionState {
|
|
|
1706
1909
|
interface UIInteractionActions {
|
|
1707
1910
|
/** Toggle like state (debounced - updates UI immediately, API call is debounced) */
|
|
1708
1911
|
toggleLike: () => void;
|
|
1709
|
-
/** Share
|
|
1912
|
+
/** Share content */
|
|
1710
1913
|
share: () => Promise<void>;
|
|
1711
1914
|
/** Open comments */
|
|
1712
1915
|
openComments: () => void;
|
|
@@ -1732,16 +1935,18 @@ interface UIAuthorActions {
|
|
|
1732
1935
|
openProfile: () => void;
|
|
1733
1936
|
}
|
|
1734
1937
|
/**
|
|
1735
|
-
*
|
|
1938
|
+
* Content info state for VideoInfo/ArticleInfo component
|
|
1736
1939
|
*/
|
|
1737
1940
|
interface UIVideoInfoState {
|
|
1738
|
-
/**
|
|
1739
|
-
|
|
1941
|
+
/** Content item (Video or Article) */
|
|
1942
|
+
content: ContentItem;
|
|
1943
|
+
/** @deprecated Use content instead. Will be removed in v3.0 */
|
|
1944
|
+
video?: VideoItem;
|
|
1740
1945
|
/** Author name */
|
|
1741
1946
|
authorName: string;
|
|
1742
1947
|
/** Whether author is verified */
|
|
1743
1948
|
isVerified: boolean;
|
|
1744
|
-
/**
|
|
1949
|
+
/** Content caption/title */
|
|
1745
1950
|
caption: string;
|
|
1746
1951
|
/** Hashtags array */
|
|
1747
1952
|
hashtags: string[];
|
|
@@ -1769,10 +1974,41 @@ interface UIVideoInfoActions {
|
|
|
1769
1974
|
onLocationClick?: () => void;
|
|
1770
1975
|
}
|
|
1771
1976
|
/**
|
|
1772
|
-
*
|
|
1977
|
+
* Article-specific UI state
|
|
1773
1978
|
*/
|
|
1774
|
-
interface
|
|
1775
|
-
/**
|
|
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.) */
|
|
1776
2012
|
feedState: UIFeedState;
|
|
1777
2013
|
/** Swipe/scroll state */
|
|
1778
2014
|
swipeState: UISwipeState;
|
|
@@ -1780,8 +2016,8 @@ interface VideoFeedHeadlessProps {
|
|
|
1780
2016
|
height?: number | string;
|
|
1781
2017
|
/** Additional CSS classes */
|
|
1782
2018
|
className?: string;
|
|
1783
|
-
/** Render function for each
|
|
1784
|
-
renderSlot: (
|
|
2019
|
+
/** Render function for each content slot */
|
|
2020
|
+
renderSlot: (item: ContentItem, index: number) => UINode;
|
|
1785
2021
|
/** Called when active index changes */
|
|
1786
2022
|
onIndexChange?: (index: number) => void;
|
|
1787
2023
|
/** Called when reaching near end of feed */
|
|
@@ -1789,6 +2025,8 @@ interface VideoFeedHeadlessProps {
|
|
|
1789
2025
|
/** Threshold for triggering onEndReached (default: 2) */
|
|
1790
2026
|
endReachedThreshold?: number;
|
|
1791
2027
|
}
|
|
2028
|
+
/** @deprecated Use FeedHeadlessProps instead. Will be removed in v3.0 */
|
|
2029
|
+
type VideoFeedHeadlessProps = FeedHeadlessProps;
|
|
1792
2030
|
/**
|
|
1793
2031
|
* VideoSlot headless component props
|
|
1794
2032
|
*/
|
|
@@ -1962,6 +2200,84 @@ interface VideoInfoHeadlessProps {
|
|
|
1962
2200
|
/** Children (for compound pattern) */
|
|
1963
2201
|
children?: UINode;
|
|
1964
2202
|
}
|
|
2203
|
+
/**
|
|
2204
|
+
* ArticleSlot headless component props
|
|
2205
|
+
*/
|
|
2206
|
+
interface ArticleSlotHeadlessProps {
|
|
2207
|
+
/** Article to display */
|
|
2208
|
+
article: Article;
|
|
2209
|
+
/** Whether slot is active */
|
|
2210
|
+
isActive: boolean;
|
|
2211
|
+
/** Current image index */
|
|
2212
|
+
currentImageIndex: number;
|
|
2213
|
+
/** Index change handler */
|
|
2214
|
+
onImageIndexChange: (index: number) => void;
|
|
2215
|
+
/** Music toggle handler */
|
|
2216
|
+
onToggleMusic: () => void;
|
|
2217
|
+
/** Whether music is playing */
|
|
2218
|
+
isMusicPlaying: boolean;
|
|
2219
|
+
/** Last music toggle timestamp */
|
|
2220
|
+
lastMusicToggleTime?: number;
|
|
2221
|
+
/** Double tap handler (usually for like) */
|
|
2222
|
+
onDoubleTap?: () => void;
|
|
2223
|
+
/** "Read More" click handler */
|
|
2224
|
+
onReadMoreClick?: () => void;
|
|
2225
|
+
/** Long press handler */
|
|
2226
|
+
onLongPress?: () => void;
|
|
2227
|
+
/** Single tap handler */
|
|
2228
|
+
onTap?: () => void;
|
|
2229
|
+
/** Swipe direction change handler (for gesture locking) */
|
|
2230
|
+
onSwipeDirectionChange?: (direction: 'horizontal' | 'vertical' | null) => void;
|
|
2231
|
+
/** Children (overlay content) */
|
|
2232
|
+
children?: UINode;
|
|
2233
|
+
/** Additional CSS classes */
|
|
2234
|
+
className?: string;
|
|
2235
|
+
/** Music info (optional) */
|
|
2236
|
+
music?: {
|
|
2237
|
+
id: string;
|
|
2238
|
+
title: string;
|
|
2239
|
+
artist: string;
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
/** @deprecated Use ArticleSlotHeadlessProps instead */
|
|
2243
|
+
type ImagePostSlotHeadlessProps = ArticleSlotHeadlessProps;
|
|
2244
|
+
/**
|
|
2245
|
+
* DetailView headless component props
|
|
2246
|
+
*/
|
|
2247
|
+
interface DetailViewHeadlessProps {
|
|
2248
|
+
/** Whether open */
|
|
2249
|
+
isOpen: boolean;
|
|
2250
|
+
/** Close handler */
|
|
2251
|
+
onClose: () => void;
|
|
2252
|
+
/** Article to display */
|
|
2253
|
+
article: Article;
|
|
2254
|
+
/** Initial index */
|
|
2255
|
+
initialImageIndex?: number;
|
|
2256
|
+
/** Header title */
|
|
2257
|
+
headerTitle?: string;
|
|
2258
|
+
/** Liked state */
|
|
2259
|
+
isLiked?: boolean;
|
|
2260
|
+
/** Following state */
|
|
2261
|
+
isFollowing?: boolean;
|
|
2262
|
+
/** Bookmarked state */
|
|
2263
|
+
isBookmarked?: boolean;
|
|
2264
|
+
/** Like handler */
|
|
2265
|
+
onLike?: () => void;
|
|
2266
|
+
/** Comment handler */
|
|
2267
|
+
onComment?: () => void;
|
|
2268
|
+
/** Share handler */
|
|
2269
|
+
onShare?: () => void;
|
|
2270
|
+
/** Bookmark handler */
|
|
2271
|
+
onBookmark?: () => void;
|
|
2272
|
+
/** Follow handler */
|
|
2273
|
+
onFollow?: () => void;
|
|
2274
|
+
/** Gesture lock handler */
|
|
2275
|
+
onGestureLock?: (locked: boolean) => void;
|
|
2276
|
+
/** Children (compound components) */
|
|
2277
|
+
children?: UINode;
|
|
2278
|
+
/** Custom bottom bar renderer */
|
|
2279
|
+
renderBottomBar?: (props: any) => UINode;
|
|
2280
|
+
}
|
|
1965
2281
|
/**
|
|
1966
2282
|
* ErrorBoundary component props
|
|
1967
2283
|
*/
|
|
@@ -1993,15 +2309,17 @@ interface SkeletonProps {
|
|
|
1993
2309
|
className?: string;
|
|
1994
2310
|
}
|
|
1995
2311
|
/**
|
|
1996
|
-
*
|
|
2312
|
+
* Feed wired component props
|
|
1997
2313
|
* feedState and swipeState are injected by SDK
|
|
1998
2314
|
*/
|
|
1999
|
-
interface
|
|
2315
|
+
interface FeedProps extends Omit<FeedHeadlessProps, 'feedState' | 'swipeState'> {
|
|
2000
2316
|
/** Override feed state (optional) */
|
|
2001
2317
|
feedState?: UIFeedState;
|
|
2002
2318
|
/** Override swipe state (optional) */
|
|
2003
2319
|
swipeState?: UISwipeState;
|
|
2004
2320
|
}
|
|
2321
|
+
/** @deprecated Use FeedProps instead. Will be removed in v3.0 */
|
|
2322
|
+
type VideoFeedProps = FeedProps;
|
|
2005
2323
|
/**
|
|
2006
2324
|
* VideoSlot wired component props
|
|
2007
2325
|
* resourceState, playerState, playerControls are injected by SDK
|
|
@@ -2027,8 +2345,10 @@ interface VideoPlayerWiredProps extends Partial<VideoPlayerHeadlessProps> {
|
|
|
2027
2345
|
* interactionState and interactionActions are injected by SDK
|
|
2028
2346
|
*/
|
|
2029
2347
|
interface ActionBarProps extends Omit<ActionBarHeadlessProps, 'interactionState' | 'interactionActions'> {
|
|
2030
|
-
/**
|
|
2031
|
-
|
|
2348
|
+
/** Content to get interaction state for */
|
|
2349
|
+
content: ContentItem;
|
|
2350
|
+
/** @deprecated Use content instead. Will be removed in v3.0 */
|
|
2351
|
+
video?: VideoItem;
|
|
2032
2352
|
/** Override interaction state (optional) */
|
|
2033
2353
|
interactionState?: UIInteractionState;
|
|
2034
2354
|
/** Override interaction actions (optional) */
|
|
@@ -2039,8 +2359,10 @@ interface ActionBarProps extends Omit<ActionBarHeadlessProps, 'interactionState'
|
|
|
2039
2359
|
* authorState and authorActions are injected by SDK
|
|
2040
2360
|
*/
|
|
2041
2361
|
interface AuthorInfoProps extends Omit<AuthorInfoHeadlessProps, 'authorState' | 'authorActions'> {
|
|
2042
|
-
/**
|
|
2043
|
-
|
|
2362
|
+
/** Content to get author from */
|
|
2363
|
+
content: ContentItem;
|
|
2364
|
+
/** @deprecated Use content instead. Will be removed in v3.0 */
|
|
2365
|
+
video?: VideoItem;
|
|
2044
2366
|
/** Override author state (optional) */
|
|
2045
2367
|
authorState?: UIAuthorState;
|
|
2046
2368
|
/** Override author actions (optional) */
|
|
@@ -2051,8 +2373,10 @@ interface AuthorInfoProps extends Omit<AuthorInfoHeadlessProps, 'authorState' |
|
|
|
2051
2373
|
* videoInfoState and videoInfoActions are injected by SDK
|
|
2052
2374
|
*/
|
|
2053
2375
|
interface VideoInfoProps extends Omit<VideoInfoHeadlessProps, 'videoInfoState' | 'videoInfoActions'> {
|
|
2054
|
-
/**
|
|
2055
|
-
|
|
2376
|
+
/** Content to get info from */
|
|
2377
|
+
content: ContentItem;
|
|
2378
|
+
/** @deprecated Use content instead. Will be removed in v3.0 */
|
|
2379
|
+
video?: VideoItem;
|
|
2056
2380
|
/** Override video info state (optional) */
|
|
2057
2381
|
videoInfoState?: UIVideoInfoState;
|
|
2058
2382
|
/** Override video info actions (optional) */
|
|
@@ -2274,4 +2598,4 @@ type IconComponent = UIComponent<{
|
|
|
2274
2598
|
*/
|
|
2275
2599
|
type FormatCountFn = (count: number) => string;
|
|
2276
2600
|
|
|
2277
|
-
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
|
|
2601
|
+
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,
|
|
@@ -19,10 +33,10 @@ var DEFAULT_COMMENT_ENDPOINTS = {
|
|
|
19
33
|
post: "/videos/:videoId/comments",
|
|
20
34
|
postReply: "/comments/:commentId/replies",
|
|
21
35
|
edit: "/comments/:id",
|
|
22
|
-
delete: "/comments/:
|
|
36
|
+
delete: "/reels/:id/comments/:commentId",
|
|
23
37
|
like: "/comments/:id/like",
|
|
24
38
|
unlike: "/comments/:id/like",
|
|
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.
|
|
4
|
+
"version": "0.1.0-beta.20",
|
|
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
|
-
"
|
|
26
|
+
"vitest": "^2.1.0",
|
|
27
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
28
|
+
"@xhub-short/tsconfig": "0.0.1-beta.2",
|
|
29
|
+
"@xhub-short/vitest-config": "0.1.0-beta.13"
|
|
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
|
}
|