@xhub-short/contracts 0.1.0-beta.1 → 0.1.0-beta.2

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
@@ -190,6 +190,13 @@ interface SessionSnapshot {
190
190
  * Backup for focusedIndex in case feed order changed
191
191
  */
192
192
  currentVideoId?: string;
193
+ /**
194
+ * Captured video frame at playback position (base64 JPEG)
195
+ * Used to show instant preview while video loads on restore
196
+ * Only saved when restorePlaybackPosition config is enabled
197
+ * Max size: ~100KB (compressed JPEG, quality 60%)
198
+ */
199
+ restoreFrame?: string;
193
200
  /** Snapshot creation time */
194
201
  savedAt: number;
195
202
  /** SDK version for compatibility checking */
@@ -287,6 +294,236 @@ interface LogEntry {
287
294
  stack?: string;
288
295
  }
289
296
 
297
+ /**
298
+ * Comment Feature Types
299
+ * Supports nested replies (1 level), pagination, and optimistic updates
300
+ */
301
+ /**
302
+ * Full comment item with replies support
303
+ */
304
+ interface CommentItem {
305
+ /** Unique comment ID */
306
+ id: string;
307
+ /** Video ID this comment belongs to */
308
+ videoId: string;
309
+ /** Comment text content */
310
+ content: string;
311
+ /** Comment author */
312
+ author: CommentAuthor;
313
+ /** Like count */
314
+ likeCount: number;
315
+ /** Whether current user liked this comment */
316
+ isLiked: boolean;
317
+ /** Total reply count */
318
+ replyCount: number;
319
+ /** Loaded replies (may be partial) */
320
+ replies?: ReplyItem[];
321
+ /** Cursor for loading more replies */
322
+ repliesCursor?: string | null;
323
+ /** Whether all replies are loaded */
324
+ repliesLoaded?: boolean;
325
+ /** Creation timestamp (ISO 8601) */
326
+ createdAt: string;
327
+ /** Last updated timestamp (ISO 8601) */
328
+ updatedAt?: string;
329
+ /** Whether this is user's own comment (for edit/delete) */
330
+ isOwner?: boolean;
331
+ /** Whether this comment is pending (optimistic) */
332
+ isPending?: boolean;
333
+ /** Optional: Parent comment ID (for flat list with parent reference) */
334
+ parentId?: string | null;
335
+ /** Whether this comment is pinned by video author */
336
+ isPinned?: boolean;
337
+ }
338
+ /**
339
+ * Reply item (Level 1 nested comment)
340
+ */
341
+ interface ReplyItem {
342
+ /** Unique reply ID */
343
+ id: string;
344
+ /** Parent comment ID */
345
+ parentId: string;
346
+ /** Reply text content */
347
+ content: string;
348
+ /** Reply author */
349
+ author: CommentAuthor;
350
+ /** Like count */
351
+ likeCount: number;
352
+ /** Whether current user liked this reply */
353
+ isLiked: boolean;
354
+ /** User being replied to (for @mention) */
355
+ replyTo?: CommentAuthor;
356
+ /** Creation timestamp (ISO 8601) */
357
+ createdAt: string;
358
+ /** Whether this is user's own reply */
359
+ isOwner?: boolean;
360
+ /** Whether this reply is pending (optimistic) */
361
+ isPending?: boolean;
362
+ }
363
+ /**
364
+ * Comment author (may differ from video Author)
365
+ */
366
+ interface CommentAuthor {
367
+ /** Unique author ID */
368
+ id: string;
369
+ /** Display name */
370
+ name: string;
371
+ /** Avatar URL */
372
+ avatar?: string;
373
+ /** Verified status */
374
+ isVerified?: boolean;
375
+ /** Additional badge (e.g., "Creator", "Top Fan") */
376
+ badge?: string;
377
+ }
378
+ /**
379
+ * Response for listing comments
380
+ */
381
+ interface CommentListResponse {
382
+ /** List of comments */
383
+ items: CommentItem[];
384
+ /** Total comment count for this video */
385
+ totalCount: number;
386
+ /** Cursor for next page (null if no more) */
387
+ nextCursor: string | null;
388
+ /** Whether there are more comments */
389
+ hasMore: boolean;
390
+ }
391
+ /**
392
+ * Response for listing replies
393
+ */
394
+ interface ReplyListResponse {
395
+ /** List of replies */
396
+ items: ReplyItem[];
397
+ /** Parent comment ID */
398
+ parentId: string;
399
+ /** Cursor for next page */
400
+ nextCursor: string | null;
401
+ /** Whether there are more replies */
402
+ hasMore: boolean;
403
+ }
404
+ /**
405
+ * Payload for posting a new comment
406
+ */
407
+ interface PostCommentPayload {
408
+ /** Video ID */
409
+ videoId: string;
410
+ /** Comment content */
411
+ content: string;
412
+ }
413
+ /**
414
+ * Payload for posting a reply
415
+ */
416
+ interface PostReplyPayload {
417
+ /** Video ID */
418
+ videoId: string;
419
+ /** Parent comment ID */
420
+ parentId: string;
421
+ /** Reply content */
422
+ content: string;
423
+ /** Optional: User being replied to */
424
+ replyToUserId?: string;
425
+ }
426
+ /**
427
+ * Payload for editing a comment/reply
428
+ */
429
+ interface EditCommentPayload {
430
+ /** Comment/Reply ID */
431
+ id: string;
432
+ /** New content */
433
+ content: string;
434
+ }
435
+ /**
436
+ * Payload for deleting a comment/reply
437
+ */
438
+ interface DeleteCommentPayload {
439
+ /** Comment/Reply ID */
440
+ id: string;
441
+ /** Whether this is a reply (affects API endpoint) */
442
+ isReply?: boolean;
443
+ /** Parent comment ID (required if isReply) */
444
+ parentId?: string;
445
+ }
446
+ /**
447
+ * Payload for reporting a comment
448
+ */
449
+ interface ReportCommentPayload {
450
+ /** Comment/Reply ID */
451
+ id: string;
452
+ /** Report reason */
453
+ reason: CommentReportReason;
454
+ /** Additional description */
455
+ description?: string;
456
+ }
457
+ /**
458
+ * Comment report reasons
459
+ */
460
+ type CommentReportReason = 'spam' | 'harassment' | 'hate_speech' | 'misinformation' | 'inappropriate' | 'other';
461
+ /**
462
+ * Comment state for a single video
463
+ */
464
+ interface CommentState {
465
+ /** Video ID */
466
+ videoId: string;
467
+ /** Comments map by ID */
468
+ commentsMap: Map<string, CommentItem>;
469
+ /** Ordered comment IDs */
470
+ orderedIds: string[];
471
+ /** Total count from API */
472
+ totalCount: number;
473
+ /** Pagination cursor */
474
+ cursor: string | null;
475
+ /** Whether more comments can be loaded */
476
+ hasMore: boolean;
477
+ /** Loading state */
478
+ isLoading: boolean;
479
+ /** Loading more state */
480
+ isLoadingMore: boolean;
481
+ /** Error state */
482
+ error: Error | null;
483
+ /** Cache timestamp for TTL */
484
+ cachedAt: number;
485
+ }
486
+ /**
487
+ * Global comment manager state
488
+ */
489
+ interface CommentManagerState {
490
+ /** Comments by video ID */
491
+ commentsByVideo: Map<string, CommentState>;
492
+ /** Currently active video ID (for comment sheet) */
493
+ activeVideoId: string | null;
494
+ /** Posting state */
495
+ isPosting: boolean;
496
+ /** Posting error */
497
+ postError: Error | null;
498
+ }
499
+ /**
500
+ * Comment feature configuration
501
+ */
502
+ interface CommentConfig {
503
+ /** Comments per page (default: 20) */
504
+ pageSize: number;
505
+ /** Replies per page (default: 10) */
506
+ replyPageSize: number;
507
+ /** Cache TTL in ms (default: 5 minutes) */
508
+ cacheTTL: number;
509
+ /** Auto-expand threshold for replies (default: 1) */
510
+ repliesAutoExpandThreshold: number;
511
+ /** Replies collapse limit (default: 3) */
512
+ repliesCollapseLimit: number;
513
+ /** Comment text max lines before collapse (default: 3) */
514
+ textMaxLines: number;
515
+ /** Input max length (default: 500) */
516
+ inputMaxLength: number;
517
+ /** Enable optimistic UI (default: true) */
518
+ enableOptimisticUI: boolean;
519
+ /** Require delete confirmation (default: true) */
520
+ requireDeleteConfirm: boolean;
521
+ }
522
+ /**
523
+ * Default comment configuration
524
+ */
525
+ declare const DEFAULT_COMMENT_CONFIG: CommentConfig;
526
+
290
527
  /**
291
528
  * IDataSource - Data Port Interface
292
529
  *
@@ -472,6 +709,39 @@ interface IInteraction {
472
709
  report?(videoId: string, reason: string, description?: string): Promise<void>;
473
710
  }
474
711
 
712
+ /**
713
+ * Data structure for prefetch cache
714
+ *
715
+ * Stored in localStorage for instant feed loading on fresh app open.
716
+ * Contains video metadata (NOT video data) for immediate display.
717
+ *
718
+ * @example
719
+ * ```typescript
720
+ * const cacheData: PrefetchCacheData = {
721
+ * items: [video1, video2, ...], // Last N videos from feed
722
+ * savedAt: Date.now(),
723
+ * cursor: 'abc123',
724
+ * };
725
+ * await storage.set('sv-prefetch-cache', cacheData);
726
+ * ```
727
+ */
728
+ interface PrefetchCacheData {
729
+ /**
730
+ * Cached video items (tail of feed - videos user hasn't seen)
731
+ * These are shown instantly on fresh load
732
+ */
733
+ items: VideoItem[];
734
+ /**
735
+ * Timestamp when cache was saved
736
+ * Used for debugging and potential TTL features
737
+ */
738
+ savedAt: number;
739
+ /**
740
+ * Pagination cursor for continuing from cached position
741
+ * Allows loadMore() to work correctly after hydrating from cache
742
+ */
743
+ cursor: string | null;
744
+ }
475
745
  /**
476
746
  * IStorage - Storage Port Interface
477
747
  *
@@ -1043,6 +1313,258 @@ interface IPosterLoader {
1043
1313
  clearCache(): void;
1044
1314
  }
1045
1315
 
1316
+ /**
1317
+ * Comment Adapter Interface (Port)
1318
+ * Defines the contract for comment data operations
1319
+ * Host app can implement this interface or use preset REST adapter
1320
+ */
1321
+
1322
+ /**
1323
+ * Comment adapter interface (Port in Hexagonal Architecture)
1324
+ * All comment operations go through this interface
1325
+ */
1326
+ interface ICommentAdapter {
1327
+ /**
1328
+ * Get comments for a video
1329
+ * @param videoId - Video ID
1330
+ * @param cursor - Pagination cursor (null for first page)
1331
+ * @param limit - Number of comments per page
1332
+ * @returns Paginated comment list
1333
+ */
1334
+ getComments(videoId: string, cursor?: string | null, limit?: number): Promise<CommentListResponse>;
1335
+ /**
1336
+ * Get replies for a comment
1337
+ * @param commentId - Parent comment ID
1338
+ * @param cursor - Pagination cursor
1339
+ * @param limit - Number of replies per page
1340
+ * @returns Paginated reply list
1341
+ */
1342
+ getReplies(commentId: string, cursor?: string | null, limit?: number): Promise<ReplyListResponse>;
1343
+ /**
1344
+ * Post a new comment
1345
+ * @param payload - Comment data
1346
+ * @returns Created comment
1347
+ */
1348
+ postComment(payload: PostCommentPayload): Promise<CommentItem>;
1349
+ /**
1350
+ * Post a reply to a comment
1351
+ * @param payload - Reply data
1352
+ * @returns Created reply
1353
+ */
1354
+ postReply(payload: PostReplyPayload): Promise<ReplyItem>;
1355
+ /**
1356
+ * Edit an existing comment/reply
1357
+ * @param payload - Edit data
1358
+ * @returns Updated comment/reply
1359
+ */
1360
+ editComment(payload: EditCommentPayload): Promise<CommentItem | ReplyItem>;
1361
+ /**
1362
+ * Delete a comment/reply
1363
+ * @param payload - Delete data
1364
+ */
1365
+ deleteComment(payload: DeleteCommentPayload): Promise<void>;
1366
+ /**
1367
+ * Like a comment/reply
1368
+ * @param id - Comment/Reply ID
1369
+ */
1370
+ likeComment(id: string): Promise<void>;
1371
+ /**
1372
+ * Unlike a comment/reply
1373
+ * @param id - Comment/Reply ID
1374
+ */
1375
+ unlikeComment(id: string): Promise<void>;
1376
+ /**
1377
+ * Report a comment/reply
1378
+ * @param payload - Report data
1379
+ */
1380
+ reportComment(payload: ReportCommentPayload): Promise<void>;
1381
+ }
1382
+ /**
1383
+ * Configuration for REST Comment Adapter
1384
+ */
1385
+ interface CommentAdapterConfig {
1386
+ /** Base URL for API */
1387
+ baseUrl: string;
1388
+ /** API endpoints */
1389
+ endpoints: CommentEndpoints;
1390
+ /** Custom headers getter */
1391
+ getHeaders?: () => Promise<Record<string, string>> | Record<string, string>;
1392
+ /** Custom params to include in all requests */
1393
+ customParams?: Record<string, string>;
1394
+ /** Response transformers */
1395
+ transformers?: CommentTransformers;
1396
+ }
1397
+ /**
1398
+ * Comment API endpoints configuration
1399
+ */
1400
+ interface CommentEndpoints {
1401
+ /** Get comments: GET /videos/:videoId/comments */
1402
+ list: string;
1403
+ /** Get replies: GET /comments/:commentId/replies */
1404
+ replies: string;
1405
+ /** Post comment: POST /videos/:videoId/comments */
1406
+ post: string;
1407
+ /** Post reply: POST /comments/:commentId/replies */
1408
+ postReply: string;
1409
+ /** Edit comment: PATCH /comments/:id */
1410
+ edit: string;
1411
+ /** Delete comment: DELETE /comments/:id */
1412
+ delete: string;
1413
+ /** Like comment: POST /comments/:id/like */
1414
+ like: string;
1415
+ /** Unlike comment: DELETE /comments/:id/like */
1416
+ unlike: string;
1417
+ /** Report comment: POST /comments/:id/report */
1418
+ report: string;
1419
+ }
1420
+ /**
1421
+ * Default endpoints (RESTful convention)
1422
+ */
1423
+ declare const DEFAULT_COMMENT_ENDPOINTS: CommentEndpoints;
1424
+ /**
1425
+ * Response transformers for custom API formats
1426
+ */
1427
+ interface CommentTransformers {
1428
+ /** Transform API response to CommentListResponse */
1429
+ commentList?: (raw: unknown) => CommentListResponse;
1430
+ /** Transform API response to ReplyListResponse */
1431
+ replyList?: (raw: unknown) => ReplyListResponse;
1432
+ /** Transform API response to CommentItem */
1433
+ comment?: (raw: unknown) => CommentItem;
1434
+ /** Transform API response to ReplyItem */
1435
+ reply?: (raw: unknown) => ReplyItem;
1436
+ }
1437
+ /**
1438
+ * Configuration for Mock Comment Adapter (testing/demo)
1439
+ */
1440
+ interface MockCommentAdapterConfig {
1441
+ /** Simulated delay in ms (default: 500) */
1442
+ delay?: number;
1443
+ /** Initial comments per video */
1444
+ initialComments?: CommentItem[];
1445
+ /** Simulate errors */
1446
+ simulateErrors?: boolean;
1447
+ /** Error rate (0-1, default: 0.1) */
1448
+ errorRate?: number;
1449
+ }
1450
+
1451
+ /**
1452
+ * @xhub-short/contracts - Localization Types
1453
+ *
1454
+ * Lightweight i18n support with ICU-like message format.
1455
+ * Custom implementation - NO external dependencies.
1456
+ *
1457
+ * Supported ICU features:
1458
+ * - Simple interpolation: {name}
1459
+ * - Plural: {count, plural, =0 {none} one {# item} other {# items}}
1460
+ * - Select: {key, select, value1 {text1} other {text2}}
1461
+ */
1462
+ /**
1463
+ * Values that can be interpolated into messages
1464
+ */
1465
+ type MessageValue = string | number | boolean;
1466
+ /**
1467
+ * Record of values for message interpolation
1468
+ */
1469
+ type MessageValues = Record<string, MessageValue>;
1470
+ /**
1471
+ * All supported message keys
1472
+ *
1473
+ * Using dot notation for namespacing:
1474
+ * - feed.* : Video feed related
1475
+ * - player.* : Video player related
1476
+ * - comment.* : Comment section related
1477
+ * - action.* : User actions (like, share, follow)
1478
+ * - time.* : Relative time formatting
1479
+ * - number.* : Number formatting suffixes
1480
+ * - error.* : Generic errors
1481
+ */
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';
1483
+ /**
1484
+ * Complete message catalog type
1485
+ * All keys must be present
1486
+ */
1487
+ type MessageCatalog = Record<MessageKey, string>;
1488
+ /**
1489
+ * Partial catalog for overrides
1490
+ */
1491
+ type PartialMessageCatalog = Partial<MessageCatalog>;
1492
+ /**
1493
+ * Localization Port - Core interface for i18n
1494
+ *
1495
+ * Adapters must implement this interface.
1496
+ * SDK provides default implementation with built-in ICU-like parser.
1497
+ */
1498
+ interface ILocalization {
1499
+ /**
1500
+ * Current locale (BCP 47 tag, e.g., 'en', 'vi', 'zh-CN')
1501
+ */
1502
+ readonly locale: string;
1503
+ /**
1504
+ * Translate a message key
1505
+ *
1506
+ * @param key - Message key from catalog
1507
+ * @param values - Optional interpolation values
1508
+ * @returns Translated string
1509
+ *
1510
+ * @example
1511
+ * // Simple
1512
+ * t('feed.loading') // "Loading..."
1513
+ *
1514
+ * // Interpolation
1515
+ * t('comment.replyTo', { name: 'John' }) // "Replying to John"
1516
+ *
1517
+ * // Plural
1518
+ * t('comment.count', { count: 5 }) // "5 comments"
1519
+ */
1520
+ t(key: MessageKey, values?: MessageValues): string;
1521
+ /**
1522
+ * Format a number with locale-aware separators
1523
+ *
1524
+ * @param value - Number to format
1525
+ * @returns Formatted string (e.g., "1,234" or "1.234")
1526
+ */
1527
+ formatNumber(value: number): string;
1528
+ /**
1529
+ * Format a number in compact form (1K, 1M, 1B)
1530
+ *
1531
+ * @param value - Number to format
1532
+ * @returns Compact string (e.g., "15K", "1.2M")
1533
+ */
1534
+ formatCompact(value: number): string;
1535
+ /**
1536
+ * Format relative time (e.g., "2 hours ago")
1537
+ *
1538
+ * @param date - Date or timestamp
1539
+ * @returns Relative time string
1540
+ */
1541
+ formatRelativeTime(date: Date | number): string;
1542
+ }
1543
+ /**
1544
+ * Localization configuration for SDK
1545
+ */
1546
+ interface LocalizationConfig {
1547
+ /**
1548
+ * Locale code (BCP 47)
1549
+ * @default 'en'
1550
+ */
1551
+ locale?: string;
1552
+ /**
1553
+ * Custom messages to override defaults
1554
+ */
1555
+ messages?: PartialMessageCatalog;
1556
+ /**
1557
+ * Fallback locale when translation not found
1558
+ * @default 'en'
1559
+ */
1560
+ fallbackLocale?: string;
1561
+ /**
1562
+ * Custom localization adapter (for integration with existing i18n systems)
1563
+ * If provided, SDK will use this instead of built-in implementation
1564
+ */
1565
+ adapter?: ILocalization;
1566
+ }
1567
+
1046
1568
  /**
1047
1569
  * UI Component Types for XHub-short SDK
1048
1570
  *
@@ -1287,6 +1809,12 @@ interface VideoSlotHeadlessProps {
1287
1809
  onVisible?: () => void;
1288
1810
  /** Called when video becomes hidden */
1289
1811
  onHidden?: () => void;
1812
+ /**
1813
+ * Restore frame for session restoration.
1814
+ * Base64 JPEG data URL of the video frame at restore position.
1815
+ * Displayed as instant preview while video loads.
1816
+ */
1817
+ restoreFrame?: string;
1290
1818
  }
1291
1819
  /**
1292
1820
  * VideoPlayer headless component props
@@ -1538,6 +2066,189 @@ interface VideoInfoProps extends Omit<VideoInfoHeadlessProps, 'videoInfoState' |
1538
2066
  /** Called when location is clicked */
1539
2067
  onLocationClick?: () => void;
1540
2068
  }
2069
+
2070
+ /**
2071
+ * Comment state from useComment() hook
2072
+ */
2073
+ interface UICommentState {
2074
+ /** Comments for current video */
2075
+ comments: CommentItem[];
2076
+ /** Total comment count */
2077
+ totalCount: number;
2078
+ /** Whether comments are loading */
2079
+ isLoading: boolean;
2080
+ /** Whether more comments are loading */
2081
+ isLoadingMore: boolean;
2082
+ /** Whether there are more comments */
2083
+ hasMore: boolean;
2084
+ /** Error if any */
2085
+ error: Error | null;
2086
+ /** Whether currently posting a comment */
2087
+ isPosting: boolean;
2088
+ /** Config */
2089
+ config: CommentConfig;
2090
+ }
2091
+ /**
2092
+ * Comment actions from useComment() hook
2093
+ */
2094
+ interface UICommentActions {
2095
+ /** Load comments for a video */
2096
+ loadComments: (videoId: string) => Promise<void>;
2097
+ /** Load more comments */
2098
+ loadMore: () => Promise<void>;
2099
+ /** Post a new comment */
2100
+ postComment: (content: string) => Promise<void>;
2101
+ /** Post a reply */
2102
+ postReply: (parentId: string, content: string, replyTo?: CommentAuthor) => Promise<void>;
2103
+ /** Edit a comment/reply */
2104
+ editComment: (id: string, content: string) => Promise<void>;
2105
+ /** Delete a comment/reply */
2106
+ deleteComment: (id: string, isReply?: boolean, parentId?: string) => Promise<void>;
2107
+ /** Like a comment/reply */
2108
+ likeComment: (id: string) => Promise<void>;
2109
+ /** Unlike a comment/reply */
2110
+ unlikeComment: (id: string) => Promise<void>;
2111
+ /** Load replies for a comment */
2112
+ loadReplies: (commentId: string) => Promise<void>;
2113
+ /** Report a comment */
2114
+ reportComment: (id: string, reason: string) => Promise<void>;
2115
+ /** Refresh comments */
2116
+ refresh: () => Promise<void>;
2117
+ }
2118
+ /**
2119
+ * Comment sheet headless component props
2120
+ */
2121
+ interface CommentSheetHeadlessProps {
2122
+ /** Comment state */
2123
+ commentState: UICommentState;
2124
+ /** Comment actions */
2125
+ commentActions: UICommentActions;
2126
+ /** Video ID for comments */
2127
+ videoId: string;
2128
+ /** Whether sheet is open */
2129
+ isOpen: boolean;
2130
+ /** Close handler */
2131
+ onClose: () => void;
2132
+ /** Current user for posting (optional - show input only if provided) */
2133
+ currentUser?: CommentAuthor;
2134
+ /** Sheet height as percentage (0-1, default: 0.65) */
2135
+ sheetHeight?: number;
2136
+ /** Animation duration in ms (default: 300) */
2137
+ animationDuration?: number;
2138
+ /** Emoji bar config (optional) */
2139
+ emojiBar?: {
2140
+ enabled?: boolean;
2141
+ emojis?: string[];
2142
+ };
2143
+ /** Custom header content */
2144
+ headerContent?: UINode;
2145
+ /** Custom empty state */
2146
+ emptyContent?: UINode;
2147
+ /** Custom loading state */
2148
+ loadingContent?: UINode;
2149
+ /** Custom error state */
2150
+ errorContent?: UINode;
2151
+ /** Additional class name */
2152
+ className?: string;
2153
+ /** Children (compound components) */
2154
+ children?: UINode;
2155
+ /** Test ID */
2156
+ testId?: string;
2157
+ }
2158
+ /**
2159
+ * Comment sheet wired component props
2160
+ */
2161
+ interface CommentSheetProps extends Omit<CommentSheetHeadlessProps, 'commentState' | 'commentActions'> {
2162
+ /** Override comment state (optional) */
2163
+ commentState?: UICommentState;
2164
+ /** Override comment actions (optional) */
2165
+ commentActions?: UICommentActions;
2166
+ /** Video playback behavior when sheet opens */
2167
+ onOpenBehavior?: 'pause' | 'mute' | 'continue';
2168
+ /** Video animation config */
2169
+ videoAnimation?: {
2170
+ /** Enable video shrink animation (default: true) */
2171
+ enabled?: boolean;
2172
+ /** Animation duration in ms (default: 300) */
2173
+ duration?: number;
2174
+ /** Video behavior: 'shrink' | 'dim' | 'none' (default: 'shrink') */
2175
+ behavior?: 'shrink' | 'dim' | 'none';
2176
+ };
2177
+ /** Callback when input is focused (for Flutter bridge) */
2178
+ onInputFocus?: () => void;
2179
+ /** Callback when input is blurred */
2180
+ onInputBlur?: () => void;
2181
+ }
2182
+ /**
2183
+ * Comment item headless component props
2184
+ */
2185
+ interface CommentItemHeadlessProps {
2186
+ /** Comment data */
2187
+ comment: CommentItem;
2188
+ /** Comment actions */
2189
+ actions: UICommentActions;
2190
+ /** Config */
2191
+ config: CommentConfig;
2192
+ /** Whether to show replies section */
2193
+ showReplies?: boolean;
2194
+ /** Whether replies are expanded */
2195
+ repliesExpanded?: boolean;
2196
+ /** Toggle replies expansion */
2197
+ onToggleReplies?: () => void;
2198
+ /** Current user (for reply input) */
2199
+ currentUser?: CommentAuthor;
2200
+ /** Additional class name */
2201
+ className?: string;
2202
+ /** Test ID */
2203
+ testId?: string;
2204
+ }
2205
+ /**
2206
+ * Reply item headless component props
2207
+ */
2208
+ interface ReplyItemHeadlessProps {
2209
+ /** Reply data */
2210
+ reply: ReplyItem;
2211
+ /** Parent comment */
2212
+ parentComment: CommentItem;
2213
+ /** Comment actions */
2214
+ actions: UICommentActions;
2215
+ /** Config */
2216
+ config: CommentConfig;
2217
+ /** Additional class name */
2218
+ className?: string;
2219
+ /** Test ID */
2220
+ testId?: string;
2221
+ }
2222
+ /**
2223
+ * Comment input headless component props
2224
+ */
2225
+ interface CommentInputHeadlessProps {
2226
+ /** Current user */
2227
+ currentUser: CommentAuthor;
2228
+ /** Submit handler */
2229
+ onSubmit: (content: string) => Promise<void>;
2230
+ /** Whether submitting */
2231
+ isSubmitting?: boolean;
2232
+ /** Placeholder text */
2233
+ placeholder?: string;
2234
+ /** Reply to user (shows @mention) */
2235
+ replyTo?: CommentAuthor;
2236
+ /** Clear reply target */
2237
+ onClearReply?: () => void;
2238
+ /** Emoji bar config */
2239
+ emojiBar?: {
2240
+ enabled?: boolean;
2241
+ emojis?: string[];
2242
+ };
2243
+ /** Input focus handler */
2244
+ onFocus?: () => void;
2245
+ /** Input blur handler */
2246
+ onBlur?: () => void;
2247
+ /** Additional class name */
2248
+ className?: string;
2249
+ /** Test ID */
2250
+ testId?: string;
2251
+ }
1541
2252
  /**
1542
2253
  * Hook configuration for HOC factory
1543
2254
  */
@@ -1563,4 +2274,4 @@ type IconComponent = UIComponent<{
1563
2274
  */
1564
2275
  type FormatCountFn = (count: number) => string;
1565
2276
 
1566
- export type { ActionBarHeadlessProps, ActionBarProps, ActionButtonHeadlessProps, AnalyticsConfig, AnalyticsEvent, AnalyticsEventType, Author, AuthorInfoHeadlessProps, AuthorInfoProps, Comment, ErrorBoundaryProps, FeedResponse, FeedState, FormatCountFn, IAnalytics, IDataSource, IInteraction, ILogger, INetworkAdapter, IPosterLoader, ISessionStorage, IStorage, IVideoLoader, IconComponent, InternalLogger, LogEntry, LogLevel, LoggerConfig, MusicInfo, NetworkQuality, NetworkType, OptimisticAction, PlaybackState, PlayerError, PlayerState, PreloadConfig, PreloadResult, PreloadStatus, ProgressBarHeadlessProps, SDKConfig, SessionSnapshot, SkeletonProps, UIAuthorActions, UIAuthorState, UIComponent, UIFeedState, UIInteractionActions, UIInteractionState, UINode, UIPlayerControls, UIPlayerState, UIRef, UIResourceState, UISwipeState, UIVideoInfoActions, UIVideoInfoState, VideoFeedHeadlessProps, VideoFeedProps, VideoInfoHeadlessProps, VideoInfoProps, VideoItem, VideoPlayerHeadlessProps, VideoPlayerWiredProps, VideoQuality, VideoSlotHeadlessProps, VideoSlotProps, VideoSource, VideoStats, WiredComponent, WiredComponentConfig };
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 VideoStats, type WiredComponent, type WiredComponentConfig };
package/dist/index.js CHANGED
@@ -1 +1,28 @@
1
+ // src/comment-types.ts
2
+ var DEFAULT_COMMENT_CONFIG = {
3
+ pageSize: 20,
4
+ replyPageSize: 10,
5
+ cacheTTL: 5 * 60 * 1e3,
6
+ // 5 minutes
7
+ repliesAutoExpandThreshold: 1,
8
+ repliesCollapseLimit: 3,
9
+ textMaxLines: 3,
10
+ inputMaxLength: 500,
11
+ enableOptimisticUI: true,
12
+ requireDeleteConfirm: true
13
+ };
1
14
 
15
+ // src/comment-adapter.ts
16
+ var DEFAULT_COMMENT_ENDPOINTS = {
17
+ list: "/videos/:videoId/comments",
18
+ replies: "/comments/:commentId/replies",
19
+ post: "/videos/:videoId/comments",
20
+ postReply: "/comments/:commentId/replies",
21
+ edit: "/comments/:id",
22
+ delete: "/comments/:id",
23
+ like: "/comments/:id/like",
24
+ unlike: "/comments/:id/like",
25
+ report: "/comments/:id/report"
26
+ };
27
+
28
+ export { DEFAULT_COMMENT_CONFIG, DEFAULT_COMMENT_ENDPOINTS };
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@xhub-short/contracts",
3
- "version": "0.1.0-beta.1",
3
+ "sideEffects": false,
4
+ "version": "0.1.0-beta.2",
4
5
  "type": "module",
5
6
  "publishConfig": {
6
7
  "access": "public"