@boldvideo/bold-js 1.18.0 → 1.19.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @boldvideo/bold-js
2
2
 
3
+ ## 1.19.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d423437: Redesign Community API types to eliminate N+1 queries
8
+
9
+ **Breaking changes to Post type:**
10
+
11
+ - `viewer` → `author` (creator of the post)
12
+ - `reactionsCount` → `reactions.count`
13
+ - `commentsCount` → `comments.count`
14
+ - `viewerReacted` → `reactions.viewer_has_reacted`
15
+ - `createdAt` → `created_at`
16
+
17
+ **New types:**
18
+
19
+ - `UserSummary` - minimal profile with `id`, `name`, `avatar_url`
20
+ - `ReactionSummary` - `{ count, reacted_by[], viewer_has_reacted? }`
21
+ - `CommentSummary` - `{ count, commented_by[], items? }`
22
+ - `CommentThread` and `Reply` - structured comment threading
23
+ - `PaginationMeta` and `PaginatedResponse<T>` - page-based pagination
24
+
25
+ **Pagination changes:**
26
+
27
+ - `posts.list()` now uses `page`/`pageSize` instead of `limit`/`offset`
28
+ - Returns `PaginatedResponse<Post>` with `data[]` and `meta`
29
+
30
+ **Benefits:**
31
+
32
+ - List endpoint now includes `reacted_by` and `commented_by` arrays (up to 10 users)
33
+ - Enables avatar display without fetching each post individually
34
+ - Consistent object shapes between list and detail views
35
+
3
36
  ## 1.18.0
4
37
 
5
38
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -407,8 +407,8 @@ function listPosts(client) {
407
407
  client,
408
408
  `community/posts${toQuery2({
409
409
  category: opts.category,
410
- limit: opts.limit,
411
- offset: opts.offset
410
+ page: opts.page,
411
+ page_size: opts.pageSize
412
412
  })}`,
413
413
  opts.viewerId
414
414
  );
package/dist/index.d.ts CHANGED
@@ -512,16 +512,63 @@ type ListVideosOptions = (ListVideosLatestOptions & {
512
512
  viewerId?: never;
513
513
  });
514
514
  /**
515
- * Author information for posts and comments
515
+ * Minimal profile object for list contexts
516
516
  */
517
- type PostAuthor = {
517
+ type UserSummary = {
518
518
  id: string;
519
519
  name: string;
520
+ avatar_url: string | null;
521
+ };
522
+ /**
523
+ * Author information for posts and comments (extended for admin context)
524
+ */
525
+ type PostAuthor = UserSummary & {
520
526
  email?: string;
521
- isAdmin: boolean;
527
+ isAdmin?: boolean;
528
+ };
529
+ /**
530
+ * Reaction summary with users who reacted
531
+ */
532
+ type ReactionSummary = {
533
+ count: number;
534
+ /** Users who reacted (capped to 10 from API) */
535
+ reacted_by: UserSummary[];
536
+ /** Present when viewer context exists */
537
+ viewer_has_reacted?: boolean;
538
+ };
539
+ /**
540
+ * Comment summary with users who commented
541
+ */
542
+ type CommentSummary = {
543
+ count: number;
544
+ /** Users who commented (capped to 10 from API) */
545
+ commented_by: UserSummary[];
546
+ /** Full comment threads (present in detail only) */
547
+ items?: CommentThread[];
548
+ };
549
+ /**
550
+ * A reply to a comment
551
+ */
552
+ type Reply = {
553
+ id: string;
554
+ content: string;
555
+ created_at: string;
556
+ author: UserSummary;
557
+ parent_comment_id: string;
558
+ };
559
+ /**
560
+ * A top-level comment with replies
561
+ */
562
+ type CommentThread = {
563
+ id: string;
564
+ content: string;
565
+ created_at: string;
566
+ author: UserSummary;
567
+ replies: Reply[];
522
568
  };
523
569
  /**
524
- * A comment on a community post
570
+ * @deprecated Use CommentThread instead
571
+ * A comment on a community post (legacy format)
525
572
  */
526
573
  type Comment = {
527
574
  id: string;
@@ -531,30 +578,38 @@ type Comment = {
531
578
  reactionsCount: number;
532
579
  /** Whether current viewer has reacted (only present when X-Viewer-ID header sent) */
533
580
  viewerReacted?: boolean;
581
+ /** @deprecated Use author instead */
534
582
  viewer: PostAuthor;
583
+ author: PostAuthor;
535
584
  /** Nested replies */
536
585
  replies: Comment[];
537
586
  createdAt: string;
538
587
  updatedAt: string;
539
588
  };
540
589
  /**
541
- * A community post
590
+ * A community post (list view)
542
591
  */
543
592
  type Post = {
544
593
  id: string;
545
594
  content: string;
546
- category: string;
547
- pinned: boolean;
595
+ category?: string;
596
+ pinned?: boolean;
548
597
  pinnedAt?: string | null;
549
- reactionsCount: number;
550
- commentsCount: number;
551
- /** Whether current viewer has reacted (only present when X-Viewer-ID header sent) */
598
+ created_at: string;
599
+ author: PostAuthor;
600
+ reactions: ReactionSummary;
601
+ comments: CommentSummary;
602
+ /** @deprecated Use created_at */
603
+ createdAt?: string;
604
+ /** @deprecated Use reactions.count */
605
+ reactionsCount?: number;
606
+ /** @deprecated Use comments.count */
607
+ commentsCount?: number;
608
+ /** @deprecated Use reactions.viewer_has_reacted */
552
609
  viewerReacted?: boolean;
553
- viewer: PostAuthor;
554
- /** Comments (only present on single post fetch) */
555
- comments?: Comment[];
556
- createdAt: string;
557
- updatedAt: string;
610
+ /** @deprecated Use author */
611
+ viewer?: PostAuthor;
612
+ updatedAt?: string;
558
613
  };
559
614
  /**
560
615
  * Response from react endpoints (toggle)
@@ -563,17 +618,37 @@ type ReactionResponse = {
563
618
  reacted: boolean;
564
619
  reactionsCount: number;
565
620
  };
621
+ /**
622
+ * Pagination metadata from API
623
+ */
624
+ type PaginationMeta = {
625
+ /** Current page (1-indexed) */
626
+ page: number;
627
+ /** Items per page */
628
+ page_size: number;
629
+ /** Total items across all pages */
630
+ total_entries: number;
631
+ /** Total number of pages */
632
+ total_pages: number;
633
+ };
634
+ /**
635
+ * Paginated response wrapper
636
+ */
637
+ type PaginatedResponse<T> = {
638
+ data: T[];
639
+ meta: PaginationMeta;
640
+ };
566
641
  /**
567
642
  * Options for listing community posts
568
643
  */
569
644
  type ListPostsOptions = {
570
645
  /** Filter by category (e.g., "announcements", "general") */
571
646
  category?: string;
572
- /** Max posts to return (default: 20) */
573
- limit?: number;
574
- /** Pagination offset */
575
- offset?: number;
576
- /** Viewer ID to include viewerReacted in response */
647
+ /** Page number (1-indexed, default: 1) */
648
+ page?: number;
649
+ /** Items per page (default: 20, max: 100) */
650
+ pageSize?: number;
651
+ /** Viewer ID to include viewer_has_reacted in response */
577
652
  viewerId?: string;
578
653
  };
579
654
  /**
@@ -787,9 +862,7 @@ declare function createClient(apiKey: string, options?: ClientOptions): {
787
862
  ai: AIClient;
788
863
  community: {
789
864
  posts: {
790
- list: (opts?: ListPostsOptions) => Promise<{
791
- data: Post[];
792
- }>;
865
+ list: (opts?: ListPostsOptions) => Promise<PaginatedResponse<Post>>;
793
866
  get: (id: string, viewerId?: string | undefined) => Promise<{
794
867
  data: Post;
795
868
  }>;
@@ -836,4 +909,4 @@ declare class CommunityAPIError extends Error {
836
909
  constructor(method: string, url: string, error: unknown);
837
910
  }
838
911
 
839
- export { AIContextMessage, AIEvent, AIResponse, AIUsage, Account, AccountAI, AnalyticsProvider, AskOptions, AssistantConfig, ChatOptions, Citation, ClientOptions, Comment, CommunityAPIError, Conversation, ConversationMessage, ConversationMetadata, CreateCommentData, CreatePostData, CreateViewerData, CustomRedirect, DEFAULT_API_BASE_URL, DEFAULT_INTERNAL_API_BASE_URL, ListPostsOptions, ListProgressOptions, ListVideosIndexOptions, ListVideosLatestOptions, ListVideosOptions, MenuItem, Playlist, Portal, PortalDisplay, PortalHero, PortalLayout, PortalNavigation, PortalTheme, Post, PostAuthor, ProgressListMeta, ReactionResponse, RecommendOptions, RecommendResponse, Recommendation, RecommendationVideo, RecommendationsOptions, RecommendationsResponse, SaveProgressData, SearchOptions, Segment, Settings, Source, ThemeColors, ThemeConfig, UpdatePostData, UpdateViewerData, Video, VideoAttachment, VideoDownloadUrls, VideoMetadata, VideoSubtitles, VideoTranscript, Viewer, ViewerAPIError, ViewerLookupParams, ViewerProgress, createClient };
912
+ export { AIContextMessage, AIEvent, AIResponse, AIUsage, Account, AccountAI, AnalyticsProvider, AskOptions, AssistantConfig, ChatOptions, Citation, ClientOptions, Comment, CommentSummary, CommentThread, CommunityAPIError, Conversation, ConversationMessage, ConversationMetadata, CreateCommentData, CreatePostData, CreateViewerData, CustomRedirect, DEFAULT_API_BASE_URL, DEFAULT_INTERNAL_API_BASE_URL, ListPostsOptions, ListProgressOptions, ListVideosIndexOptions, ListVideosLatestOptions, ListVideosOptions, MenuItem, PaginatedResponse, PaginationMeta, Playlist, Portal, PortalDisplay, PortalHero, PortalLayout, PortalNavigation, PortalTheme, Post, PostAuthor, ProgressListMeta, ReactionResponse, ReactionSummary, RecommendOptions, RecommendResponse, Recommendation, RecommendationVideo, RecommendationsOptions, RecommendationsResponse, Reply, SaveProgressData, SearchOptions, Segment, Settings, Source, ThemeColors, ThemeConfig, UpdatePostData, UpdateViewerData, UserSummary, Video, VideoAttachment, VideoDownloadUrls, VideoMetadata, VideoSubtitles, VideoTranscript, Viewer, ViewerAPIError, ViewerLookupParams, ViewerProgress, createClient };
package/dist/index.js CHANGED
@@ -367,8 +367,8 @@ function listPosts(client) {
367
367
  client,
368
368
  `community/posts${toQuery2({
369
369
  category: opts.category,
370
- limit: opts.limit,
371
- offset: opts.offset
370
+ page: opts.page,
371
+ page_size: opts.pageSize
372
372
  })}`,
373
373
  opts.viewerId
374
374
  );
package/llms.txt CHANGED
@@ -117,8 +117,8 @@ Build community features with posts, comments, and reactions. Write operations r
117
117
 
118
118
  ### Posts
119
119
 
120
- - `bold.community.posts.list(opts?)` - List posts with optional filters
121
- - `bold.community.posts.get(id, viewerId?)` - Get post with comments
120
+ - `bold.community.posts.list(opts?)` - List posts with pagination (returns `PaginatedResponse<Post>`)
121
+ - `bold.community.posts.get(id, viewerId?)` - Get post with full comments
122
122
  - `bold.community.posts.create(viewerId, data)` - Create a post
123
123
  - `bold.community.posts.update(viewerId, id, data)` - Update post (owner/admin)
124
124
  - `bold.community.posts.delete(viewerId, id)` - Delete post (owner/admin)
@@ -131,11 +131,21 @@ Build community features with posts, comments, and reactions. Write operations r
131
131
  - `bold.community.comments.react(viewerId, id)` - Toggle reaction
132
132
 
133
133
  ```typescript
134
- // Example
135
- const { data: posts } = await bold.community.posts.list({ category: 'general', limit: 20 });
134
+ // Example: List posts with pagination
135
+ const response = await bold.community.posts.list({ page: 1, pageSize: 20, viewerId });
136
+ // response.data = Post[]
137
+ // response.meta = { page, page_size, total_entries, total_pages }
138
+
139
+ // Access users who reacted/commented (for avatar display)
140
+ const post = response.data[0];
141
+ post.reactions.reacted_by; // UserSummary[] (up to 10)
142
+ post.comments.commented_by; // UserSummary[] (up to 10)
143
+ post.reactions.viewer_has_reacted; // boolean (when viewerId provided)
144
+
145
+ // Create and interact
136
146
  await bold.community.posts.create(viewerId, { content: 'Hello!', category: 'general' });
137
- await bold.community.posts.react(viewerId, posts[0].id);
138
- await bold.community.comments.create(viewerId, posts[0].id, { content: 'Great post!' });
147
+ await bold.community.posts.react(viewerId, post.id);
148
+ await bold.community.comments.create(viewerId, post.id, { content: 'Great post!' });
139
149
  ```
140
150
 
141
151
  ## AI Methods
@@ -302,44 +312,94 @@ type AIEvent =
302
312
  }
303
313
  ```
304
314
 
315
+ ### UserSummary
316
+
317
+ ```typescript
318
+ {
319
+ id: string;
320
+ name: string;
321
+ avatar_url: string | null;
322
+ }
323
+ ```
324
+
305
325
  ### Post
306
326
 
307
327
  ```typescript
308
328
  {
309
329
  id: string;
310
330
  content: string; // Markdown content
311
- category: string;
312
- pinned: boolean;
331
+ created_at: string;
332
+ author: PostAuthor; // Creator of the post
333
+ reactions: ReactionSummary; // { count, reacted_by, viewer_has_reacted? }
334
+ comments: CommentSummary; // { count, commented_by, items? }
335
+ category?: string;
336
+ pinned?: boolean;
313
337
  pinnedAt?: string | null;
314
- reactionsCount: number;
315
- commentsCount: number;
316
- viewerReacted?: boolean; // Only with X-Viewer-ID
317
- viewer: PostAuthor;
318
- comments?: Comment[]; // Only on single post fetch
319
- createdAt: string;
320
- updatedAt: string;
338
+ updatedAt?: string;
339
+ }
340
+ ```
341
+
342
+ ### ReactionSummary
343
+
344
+ ```typescript
345
+ {
346
+ count: number;
347
+ reacted_by: UserSummary[]; // Capped to 10 from API
348
+ viewer_has_reacted?: boolean; // Present when viewerId provided
349
+ }
350
+ ```
351
+
352
+ ### CommentSummary
353
+
354
+ ```typescript
355
+ {
356
+ count: number;
357
+ commented_by: UserSummary[]; // Capped to 10 from API
358
+ items?: CommentThread[]; // Full threads (detail view only)
321
359
  }
322
360
  ```
323
361
 
324
- ### Comment
362
+ ### CommentThread
325
363
 
326
364
  ```typescript
327
365
  {
328
366
  id: string;
329
367
  content: string;
330
- depth: number; // Nesting level (0 = top-level)
331
- reactionsCount: number;
332
- viewerReacted?: boolean;
333
- viewer: PostAuthor;
334
- replies: Comment[]; // Nested replies
335
- createdAt: string;
336
- updatedAt: string;
368
+ created_at: string;
369
+ author: UserSummary;
370
+ replies: Reply[]; // Nested replies
371
+ }
372
+ ```
373
+
374
+ ### Reply
375
+
376
+ ```typescript
377
+ {
378
+ id: string;
379
+ content: string;
380
+ created_at: string;
381
+ author: UserSummary;
382
+ parent_comment_id: string;
383
+ }
384
+ ```
385
+
386
+ ### PaginatedResponse<T>
387
+
388
+ ```typescript
389
+ {
390
+ data: T[];
391
+ meta: {
392
+ page: number; // Current page (1-indexed)
393
+ page_size: number;
394
+ total_entries: number;
395
+ total_pages: number;
396
+ };
337
397
  }
338
398
  ```
339
399
 
340
400
  ### Other types exported
341
401
 
342
- `Playlist`, `Settings`, `Portal`, `MenuItem`, `AIResponse`, `AIUsage`, `AIContextMessage`, `Conversation`, `ConversationMessage`, `RecommendationsResponse`, `Viewer`, `ViewerProgress`, `ViewerLookupParams`, `ListProgressOptions`, `ListVideosOptions`, `ListVideosLatestOptions`, `ListVideosIndexOptions`, `Post`, `PostAuthor`, `Comment`, `ReactionResponse`, `ListPostsOptions`, `CreatePostData`, `UpdatePostData`, `CreateCommentData`, `CommunityAPIError`
402
+ `Playlist`, `Settings`, `Portal`, `MenuItem`, `AIResponse`, `AIUsage`, `AIContextMessage`, `Conversation`, `ConversationMessage`, `RecommendationsResponse`, `Viewer`, `ViewerProgress`, `ViewerLookupParams`, `ListProgressOptions`, `ListVideosOptions`, `ListVideosLatestOptions`, `ListVideosIndexOptions`, `Post`, `PostAuthor`, `UserSummary`, `ReactionSummary`, `CommentSummary`, `CommentThread`, `Reply`, `Comment`, `ReactionResponse`, `ListPostsOptions`, `CreatePostData`, `UpdatePostData`, `CreateCommentData`, `PaginationMeta`, `PaginatedResponse`, `CommunityAPIError`
343
403
 
344
404
  ## Error Handling
345
405
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@boldvideo/bold-js",
3
3
  "license": "MIT",
4
- "version": "1.18.0",
4
+ "version": "1.19.0",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
7
7
  "types": "dist/index.d.ts",