@stream-io/feeds-client 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/index.js +2 -1
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/react-bindings.js +76 -14
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +3 -2
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +76 -14
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/{feeds-client-47vliZx_.js → feeds-client-CwioZBvA.js} +355 -52
  11. package/dist/feeds-client-CwioZBvA.js.map +1 -0
  12. package/dist/{feeds-client-Cd2LsXp-.mjs → feeds-client-DVbsjKUf.mjs} +355 -52
  13. package/dist/feeds-client-DVbsjKUf.mjs.map +1 -0
  14. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts +49 -0
  15. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -0
  16. package/dist/types/activity-with-state-updates/get-feed.d.ts +3 -0
  17. package/dist/types/activity-with-state-updates/get-feed.d.ts.map +1 -0
  18. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts +1 -0
  19. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts.map +1 -1
  20. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts +32 -0
  21. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts.map +1 -0
  22. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts +4 -0
  23. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts.map +1 -1
  24. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
  25. package/dist/types/bindings/react/hooks/useCreateFeedsClient.d.ts.map +1 -1
  26. package/dist/types/common/real-time/event-models.d.ts +1 -0
  27. package/dist/types/common/real-time/event-models.d.ts.map +1 -1
  28. package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
  29. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
  30. package/dist/types/feed/feed.d.ts +1 -1
  31. package/dist/types/feed/feed.d.ts.map +1 -1
  32. package/dist/types/feeds-client/active-activity.d.ts +8 -0
  33. package/dist/types/feeds-client/active-activity.d.ts.map +1 -0
  34. package/dist/types/feeds-client/feeds-client.d.ts +36 -3
  35. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  36. package/dist/types/gen/feeds/FeedsApi.d.ts +9 -1
  37. package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
  38. package/dist/types/gen/models/index.d.ts +52 -0
  39. package/dist/types/gen/models/index.d.ts.map +1 -1
  40. package/dist/types/index.d.ts +1 -0
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/types.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/activity-with-state-updates/activity-with-state-updates.ts +190 -0
  45. package/src/activity-with-state-updates/get-feed.ts +5 -0
  46. package/src/bindings/react/hooks/feed-state-hooks/index.ts +1 -0
  47. package/src/bindings/react/hooks/feed-state-hooks/useActivityComments.ts +113 -0
  48. package/src/bindings/react/hooks/feed-state-hooks/useComments.ts +4 -0
  49. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +12 -9
  50. package/src/bindings/react/hooks/useCreateFeedsClient.ts +0 -6
  51. package/src/common/real-time/event-models.ts +5 -1
  52. package/src/feed/feed.ts +16 -6
  53. package/src/feeds-client/active-activity.ts +42 -0
  54. package/src/feeds-client/feeds-client.ts +162 -53
  55. package/src/gen/feeds/FeedsApi.ts +86 -0
  56. package/src/gen/model-decoders/decoders.ts +41 -0
  57. package/src/gen/models/index.ts +84 -0
  58. package/src/index.ts +1 -0
  59. package/src/test-utils/response-generators.ts +1 -0
  60. package/src/types.ts +8 -10
  61. package/dist/feeds-client-47vliZx_.js.map +0 -1
  62. package/dist/feeds-client-Cd2LsXp-.mjs.map +0 -1
@@ -14,6 +14,7 @@ import type {
14
14
  FileUploadRequest,
15
15
  FollowBatchRequest,
16
16
  FollowRequest,
17
+ GetOrCreateFeedRequest,
17
18
  ImageUploadRequest,
18
19
  OwnCapabilitiesBatchRequest,
19
20
  OwnUser,
@@ -83,6 +84,8 @@ import {
83
84
  type ThrottledGetBatchedOwnCapabilities,
84
85
  clearQueuedFeeds,
85
86
  } from '../utils/throttling';
87
+ import { ActivityWithStateUpdates } from '../activity-with-state-updates/activity-with-state-updates';
88
+ import { getFeed } from '../activity-with-state-updates/get-feed';
86
89
 
87
90
  export type FeedsClientState = {
88
91
  connected_user: OwnUser | undefined;
@@ -92,6 +95,8 @@ export type FeedsClientState = {
92
95
 
93
96
  type FID = string;
94
97
 
98
+ type ActivityId = string;
99
+
95
100
  export class FeedsClient extends FeedsApi {
96
101
  readonly state: StateStore<FeedsClientState>;
97
102
  readonly moderation: ModerationClient;
@@ -106,7 +111,8 @@ export class FeedsClient extends FeedsApi {
106
111
 
107
112
  private readonly polls_by_id: Map<string, StreamPoll>;
108
113
 
109
- private activeFeeds: Record<FID, Feed> = {};
114
+ protected activeActivities: Record<ActivityId, ActivityWithStateUpdates> = {};
115
+ protected activeFeeds: Record<FID, Feed> = {};
110
116
 
111
117
  private healthyConnectionChangedEventCount = 0;
112
118
 
@@ -143,8 +149,7 @@ export class FeedsClient extends FeedsApi {
143
149
  this.on('all', (event) => {
144
150
  const fid = event.fid;
145
151
 
146
- const feed: Feed | undefined =
147
- typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
152
+ const feeds = this.findAllActiveFeedsFromWSEvent(event);
148
153
 
149
154
  switch (event.type) {
150
155
  case 'connection.changed': {
@@ -154,14 +159,14 @@ export class FeedsClient extends FeedsApi {
154
159
  if (online) {
155
160
  this.recoverOnReconnect();
156
161
  } else {
157
- for (const activeFeed of Object.values(this.activeFeeds)) {
162
+ for (const activeFeed of this.allActiveFeeds) {
158
163
  handleWatchStopped.bind(activeFeed)();
159
164
  }
160
165
  }
161
166
  break;
162
167
  }
163
168
  case 'feeds.feed.created': {
164
- if (feed) break;
169
+ if (this.activeFeeds[event.feed.id]) break;
165
170
 
166
171
  this.getOrCreateActiveFeed(
167
172
  event.feed.group_id,
@@ -172,9 +177,15 @@ export class FeedsClient extends FeedsApi {
172
177
  break;
173
178
  }
174
179
  case 'feeds.feed.deleted': {
175
- feed?.handleWSEvent(event as unknown as WSEvent);
180
+ feeds.forEach((f) => f.handleWSEvent(event as unknown as WSEvent));
176
181
  if (typeof fid === 'string') {
177
182
  delete this.activeFeeds[fid];
183
+ Object.keys(this.activeActivities).forEach((activityId) => {
184
+ const activity = this.activeActivities[activityId];
185
+ if (getFeed.call(activity)?.feed === fid) {
186
+ delete this.activeActivities[activityId];
187
+ }
188
+ });
178
189
  }
179
190
  break;
180
191
  }
@@ -188,7 +199,7 @@ export class FeedsClient extends FeedsApi {
188
199
  if (event.poll?.id) {
189
200
  this.polls_by_id.delete(event.poll.id);
190
201
 
191
- for (const activeFeed of Object.values(this.activeFeeds)) {
202
+ for (const activeFeed of this.allActiveFeeds) {
192
203
  const currentActivities = activeFeed.currentState.activities;
193
204
  if (currentActivities) {
194
205
  const newActivities = [];
@@ -236,17 +247,15 @@ export class FeedsClient extends FeedsApi {
236
247
  case 'feeds.bookmark.deleted':
237
248
  case 'feeds.bookmark.updated': {
238
249
  const activityId = event.bookmark.activity.id;
239
- // TODO: find faster way later on
240
- const feeds = this.findActiveFeedsByActivityId(activityId);
241
- feeds.forEach((f) => f.handleWSEvent(event));
250
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
251
+ allFeeds.forEach((f) => f.handleWSEvent(event));
242
252
 
243
253
  break;
244
254
  }
245
255
  case 'feeds.activity.feedback': {
246
256
  const activityId = event.activity_feedback.activity_id;
247
- const feeds = this.findActiveFeedsByActivityId(activityId);
248
- feeds.forEach((f) => f.handleWSEvent(event));
249
-
257
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
258
+ allFeeds.forEach((f) => f.handleWSEvent(event));
250
259
  break;
251
260
  }
252
261
  case 'user.updated': {
@@ -254,7 +263,10 @@ export class FeedsClient extends FeedsApi {
254
263
  break;
255
264
  }
256
265
  default: {
257
- feed?.handleWSEvent(event as unknown as WSEvent);
266
+ feeds.forEach((f) => f.handleWSEvent(event as unknown as WSEvent));
267
+ if (event.type === 'feeds.activity.deleted') {
268
+ delete this.activeActivities[event.activity.id];
269
+ }
258
270
  }
259
271
  }
260
272
  });
@@ -291,17 +303,24 @@ export class FeedsClient extends FeedsApi {
291
303
 
292
304
  // we skip the first event as we could potentially be querying twice
293
305
  if (this.healthyConnectionChangedEventCount > 1) {
294
- const entries = Object.entries(this.activeFeeds);
306
+ const feedEntries = Object.entries(this.activeFeeds);
307
+ const activityEntries = Object.entries(this.activeActivities);
295
308
 
296
- const results = await Promise.allSettled(
297
- entries.map(([, feed]) => feed.synchronize()),
298
- );
309
+ const results = await Promise.allSettled([
310
+ ...feedEntries.map(([, feed]) => feed.synchronize()),
311
+ ...activityEntries.map(([, activity]) => activity.synchronize()),
312
+ ]);
299
313
 
300
- const failures: SyncFailure[] = results.flatMap((result, index) =>
301
- result.status === 'rejected'
302
- ? [{ feed: entries[index][0], reason: result.reason }]
303
- : [],
304
- );
314
+ const failures: SyncFailure[] = results.flatMap((result, index) => {
315
+ if (result.status === 'fulfilled') {
316
+ return [];
317
+ }
318
+ const activity = activityEntries[index - feedEntries.length]?.[1];
319
+ const feed =
320
+ feedEntries[index]?.[0] ?? (activity && getFeed.call(activity)?.feed);
321
+
322
+ return [{ feed, reason: result.reason, activity_id: activity?.id }];
323
+ });
305
324
 
306
325
  this.eventDispatcher.dispatch({
307
326
  type: 'errors.unhandled',
@@ -311,6 +330,15 @@ export class FeedsClient extends FeedsApi {
311
330
  }
312
331
  };
313
332
 
333
+ private get allActiveFeeds() {
334
+ return [
335
+ ...Object.values(this.activeFeeds),
336
+ ...Object.values(this.activeActivities)
337
+ .filter((a) => !!getFeed.call(a))
338
+ .map((a) => getFeed.call(a)!),
339
+ ];
340
+ }
341
+
314
342
  public pollFromState = (id: string) => this.polls_by_id.get(id);
315
343
 
316
344
  public hydratePollCache(activities: ActivityResponse[]) {
@@ -441,7 +469,7 @@ export class FeedsClient extends FeedsApi {
441
469
  },
442
470
  ): Promise<StreamResponse<UpdateActivityResponse>> => {
443
471
  const response = await super.updateActivity(request);
444
- for (const feed of Object.values(this.activeFeeds)) {
472
+ for (const feed of this.allActiveFeeds) {
445
473
  handleActivityUpdated.bind(feed)(response, false);
446
474
  }
447
475
  return response;
@@ -452,7 +480,7 @@ export class FeedsClient extends FeedsApi {
452
480
  ): Promise<StreamResponse<AddCommentResponse>> => {
453
481
  const response = await super.addComment(request);
454
482
  const { comment } = response;
455
- for (const feed of Object.values(this.activeFeeds)) {
483
+ for (const feed of this.allActiveFeeds) {
456
484
  handleCommentAdded.bind(feed)(response, false);
457
485
  const parentActivityId = comment.object_id;
458
486
  if (feed.hasActivity(parentActivityId)) {
@@ -478,7 +506,7 @@ export class FeedsClient extends FeedsApi {
478
506
  request: UpdateCommentRequest & { id: string },
479
507
  ): Promise<StreamResponse<UpdateCommentResponse>> => {
480
508
  const response = await super.updateComment(request);
481
- for (const feed of Object.values(this.activeFeeds)) {
509
+ for (const feed of this.allActiveFeeds) {
482
510
  handleCommentUpdated.bind(feed)(response, false);
483
511
  }
484
512
  return response;
@@ -490,7 +518,7 @@ export class FeedsClient extends FeedsApi {
490
518
  }): Promise<StreamResponse<DeleteCommentResponse>> => {
491
519
  const response = await super.deleteComment(request);
492
520
  const { activity, comment } = response;
493
- for (const feed of Object.values(this.activeFeeds)) {
521
+ for (const feed of this.allActiveFeeds) {
494
522
  handleCommentDeleted.bind(feed)({ comment }, false);
495
523
  updateCommentCount.bind(feed)({
496
524
  activity,
@@ -508,7 +536,7 @@ export class FeedsClient extends FeedsApi {
508
536
  ) => {
509
537
  const shouldEnforceUnique = request.enforce_unique;
510
538
  const response = await super.addActivityReaction(request);
511
- for (const feed of Object.values(this.activeFeeds)) {
539
+ for (const feed of this.allActiveFeeds) {
512
540
  if (shouldEnforceUnique) {
513
541
  handleActivityReactionUpdated.bind(feed)(response, false);
514
542
  } else {
@@ -534,7 +562,7 @@ export class FeedsClient extends FeedsApi {
534
562
  type: string;
535
563
  }): Promise<StreamResponse<DeleteActivityReactionResponse>> => {
536
564
  const response = await super.deleteActivityReaction(request);
537
- for (const feed of Object.values(this.activeFeeds)) {
565
+ for (const feed of this.allActiveFeeds) {
538
566
  handleActivityReactionDeleted.bind(feed)(response, false);
539
567
  }
540
568
  return response;
@@ -545,7 +573,7 @@ export class FeedsClient extends FeedsApi {
545
573
  ): Promise<StreamResponse<AddCommentReactionResponse>> => {
546
574
  const shouldEnforceUnique = request.enforce_unique;
547
575
  const response = await super.addCommentReaction(request);
548
- for (const feed of Object.values(this.activeFeeds)) {
576
+ for (const feed of this.allActiveFeeds) {
549
577
  if (shouldEnforceUnique) {
550
578
  handleCommentReactionUpdated.bind(feed)(response, false);
551
579
  } else {
@@ -560,7 +588,7 @@ export class FeedsClient extends FeedsApi {
560
588
  type: string;
561
589
  }): Promise<StreamResponse<DeleteCommentReactionResponse>> => {
562
590
  const response = await super.deleteCommentReaction(request);
563
- for (const feed of Object.values(this.activeFeeds)) {
591
+ for (const feed of this.allActiveFeeds) {
564
592
  handleCommentReactionDeleted.bind(feed)(response, false);
565
593
  }
566
594
  return response;
@@ -607,6 +635,9 @@ export class FeedsClient extends FeedsApi {
607
635
  // clear all caches
608
636
  this.polls_by_id.clear();
609
637
 
638
+ this.activeActivities = {};
639
+ this.activeFeeds = {};
640
+
610
641
  this.state.partialNext({
611
642
  connected_user: undefined,
612
643
  is_ws_connection_healthy: false,
@@ -647,6 +678,23 @@ export class FeedsClient extends FeedsApi {
647
678
  );
648
679
  };
649
680
 
681
+ /**
682
+ * If you want to get an activity with state updates outside of a feed, use this method.
683
+ *
684
+ * Usually it's used when you implement an activity details page.
685
+ *
686
+ * @param id - The id of the activity
687
+ * @returns The activity with state updates
688
+ */
689
+ activityWithStateUpdates = (id: ActivityId) => {
690
+ let activity = this.activeActivities[id];
691
+ if (!activity) {
692
+ activity = new ActivityWithStateUpdates(id, this);
693
+ this.activeActivities[id] = activity;
694
+ }
695
+ return activity;
696
+ };
697
+
650
698
  async queryFeeds(request?: QueryFeedsRequest) {
651
699
  const response = await this._queryFeeds(request);
652
700
 
@@ -701,10 +749,8 @@ export class FeedsClient extends FeedsApi {
701
749
  response.follow.source_feed.feed,
702
750
  response.follow.target_feed.feed,
703
751
  ].forEach((fid) => {
704
- const feed = this.activeFeeds[fid];
705
- if (feed) {
706
- handleFollowUpdated.bind(feed)(response, false);
707
- }
752
+ const feeds = this.findAllActiveFeedsByFid(fid);
753
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
708
754
  });
709
755
 
710
756
  return response;
@@ -718,10 +764,8 @@ export class FeedsClient extends FeedsApi {
718
764
  response.follow.source_feed.feed,
719
765
  response.follow.target_feed.feed,
720
766
  ].forEach((fid) => {
721
- const feed = this.activeFeeds[fid];
722
- if (feed) {
723
- handleFollowCreated.bind(feed)(response, false);
724
- }
767
+ const feeds = this.findAllActiveFeedsByFid(fid);
768
+ feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
725
769
  });
726
770
 
727
771
  return response;
@@ -731,10 +775,8 @@ export class FeedsClient extends FeedsApi {
731
775
  const response = await super.followBatch(request);
732
776
 
733
777
  response.follows.forEach((follow) => {
734
- const feed = this.activeFeeds[follow.source_feed.feed];
735
- if (feed) {
736
- handleFollowCreated.bind(feed)({ follow });
737
- }
778
+ const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
779
+ feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
738
780
  });
739
781
 
740
782
  return response;
@@ -744,10 +786,8 @@ export class FeedsClient extends FeedsApi {
744
786
  const response = await super.unfollow(request);
745
787
 
746
788
  [request.source, request.target].forEach((fid) => {
747
- const feed = this.activeFeeds[fid];
748
- if (feed) {
749
- handleFollowDeleted.bind(feed)(response, false);
750
- }
789
+ const feeds = this.findAllActiveFeedsByFid(fid);
790
+ feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
751
791
  });
752
792
 
753
793
  return response;
@@ -760,10 +800,29 @@ export class FeedsClient extends FeedsApi {
760
800
  connection_id: connectionId,
761
801
  });
762
802
 
763
- const feed =
764
- this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
765
- if (feed) {
766
- handleWatchStopped.bind(feed)();
803
+ const feeds = this.findAllActiveFeedsByFid(
804
+ `${request.feed_group_id}:${request.feed_id}`,
805
+ );
806
+ feeds.forEach((f) => handleWatchStopped.bind(f)());
807
+
808
+ return response;
809
+ }
810
+
811
+ async getOrCreateFeed(
812
+ request: GetOrCreateFeedRequest & {
813
+ feed_group_id: string;
814
+ feed_id: string;
815
+ connection_id?: string;
816
+ },
817
+ ) {
818
+ const response = await super.getOrCreateFeed(request);
819
+ this.hydrateCapabilitiesCache([response.feed]);
820
+
821
+ if (request.watch) {
822
+ const feeds = this.findAllActiveFeedsByFid(
823
+ `${request.feed_group_id}:${request.feed_id}`,
824
+ );
825
+ feeds.forEach((f) => handleWatchStarted.bind(f)());
767
826
  }
768
827
 
769
828
  return response;
@@ -802,10 +861,60 @@ export class FeedsClient extends FeedsApi {
802
861
  return feed;
803
862
  };
804
863
 
805
- private findActiveFeedsByActivityId(activityId: string) {
806
- return Object.values(this.activeFeeds).filter(
864
+ private findAllActiveFeedsByActivityId(activityId: string) {
865
+ return [
866
+ ...Object.values(this.activeFeeds),
867
+ ...Object.values(this.activeActivities)
868
+ .filter((a) => !!getFeed.call(a))
869
+ .map((a) => getFeed.call(a)!),
870
+ ].filter(
807
871
  (feed) =>
808
872
  feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId),
809
873
  );
810
874
  }
875
+
876
+ private findAllActiveFeedsByFid(fid: string | undefined) {
877
+ if (!fid) return [];
878
+
879
+ const activeFeed = this.activeFeeds[fid];
880
+
881
+ return [
882
+ ...(activeFeed ? [activeFeed] : []),
883
+ ...Object.values(this.activeActivities)
884
+ .filter((a) => getFeed.call(a)?.feed === fid)
885
+ .map((a) => getFeed.call(a)!),
886
+ ];
887
+ }
888
+
889
+ /**
890
+ * When updating from WS events we need a special logic:
891
+ * - Find active feeds that match a given fid.
892
+ * - Find active feed from activities where fid matches any of the feeds the activity is posted to.
893
+ *
894
+ * This logic is different from `findAllActiveFeedsByFid` which only checks the first feed an activity is posted to.
895
+ *
896
+ * @param fid
897
+ * @param activityId
898
+ * @returns
899
+ */
900
+ private findAllActiveFeedsFromWSEvent(event: FeedsEvent) {
901
+ const fid = 'fid' in event ? event.fid : undefined;
902
+
903
+ if (!fid) return [];
904
+
905
+ const activeFeed = fid ? this.activeFeeds[fid] : undefined;
906
+
907
+ return [
908
+ ...(activeFeed ? [activeFeed] : []),
909
+ ...Object.values(this.activeActivities)
910
+ .filter((a) => {
911
+ const feed = getFeed.call(a);
912
+ return (
913
+ feed?.feed === fid ||
914
+ a.currentState.activity?.feeds.some((f) => f === fid)
915
+ );
916
+ })
917
+ .map((a) => getFeed.call(a)!),
918
+ ];
919
+ }
811
920
  }
@@ -23,6 +23,8 @@ import type {
23
23
  CastPollVoteRequest,
24
24
  CreateBlockListRequest,
25
25
  CreateBlockListResponse,
26
+ CreateCollectionsRequest,
27
+ CreateCollectionsResponse,
26
28
  CreateDeviceRequest,
27
29
  CreateFeedsBatchRequest,
28
30
  CreateFeedsBatchResponse,
@@ -36,6 +38,7 @@ import type {
36
38
  DeleteActivityResponse,
37
39
  DeleteBookmarkFolderResponse,
38
40
  DeleteBookmarkResponse,
41
+ DeleteCollectionsResponse,
39
42
  DeleteCommentReactionResponse,
40
43
  DeleteCommentResponse,
41
44
  DeleteFeedResponse,
@@ -90,6 +93,7 @@ import type {
90
93
  QueryPollsResponse,
91
94
  QueryUsersPayload,
92
95
  QueryUsersResponse,
96
+ ReadCollectionsResponse,
93
97
  RejectFeedMemberInviteRequest,
94
98
  RejectFeedMemberInviteResponse,
95
99
  RejectFollowRequest,
@@ -112,6 +116,8 @@ import type {
112
116
  UpdateBookmarkFolderResponse,
113
117
  UpdateBookmarkRequest,
114
118
  UpdateBookmarkResponse,
119
+ UpdateCollectionsRequest,
120
+ UpdateCollectionsResponse,
115
121
  UpdateCommentRequest,
116
122
  UpdateCommentResponse,
117
123
  UpdateFeedMembersRequest,
@@ -312,6 +318,7 @@ export class FeedsApi {
312
318
  visibility: request?.visibility,
313
319
  visibility_tag: request?.visibility_tag,
314
320
  attachments: request?.attachments,
321
+ collection_refs: request?.collection_refs,
315
322
  filter_tags: request?.filter_tags,
316
323
  interest_tags: request?.interest_tags,
317
324
  mentioned_user_ids: request?.mentioned_user_ids,
@@ -735,6 +742,7 @@ export class FeedsApi {
735
742
  text: request?.text,
736
743
  visibility: request?.visibility,
737
744
  attachments: request?.attachments,
745
+ collection_refs: request?.collection_refs,
738
746
  feeds: request?.feeds,
739
747
  filter_tags: request?.filter_tags,
740
748
  interest_tags: request?.interest_tags,
@@ -860,6 +868,84 @@ export class FeedsApi {
860
868
  return { ...response.body, metadata: response.metadata };
861
869
  }
862
870
 
871
+ async deleteCollections(request: {
872
+ collection_refs: string[];
873
+ }): Promise<StreamResponse<DeleteCollectionsResponse>> {
874
+ const queryParams = {
875
+ collection_refs: request?.collection_refs,
876
+ };
877
+
878
+ const response = await this.apiClient.sendRequest<
879
+ StreamResponse<DeleteCollectionsResponse>
880
+ >('DELETE', '/api/v2/feeds/collections', undefined, queryParams);
881
+
882
+ decoders.DeleteCollectionsResponse?.(response.body);
883
+
884
+ return { ...response.body, metadata: response.metadata };
885
+ }
886
+
887
+ async readCollections(request: {
888
+ collection_refs: string[];
889
+ }): Promise<StreamResponse<ReadCollectionsResponse>> {
890
+ const queryParams = {
891
+ collection_refs: request?.collection_refs,
892
+ };
893
+
894
+ const response = await this.apiClient.sendRequest<
895
+ StreamResponse<ReadCollectionsResponse>
896
+ >('GET', '/api/v2/feeds/collections', undefined, queryParams);
897
+
898
+ decoders.ReadCollectionsResponse?.(response.body);
899
+
900
+ return { ...response.body, metadata: response.metadata };
901
+ }
902
+
903
+ async updateCollections(
904
+ request: UpdateCollectionsRequest,
905
+ ): Promise<StreamResponse<UpdateCollectionsResponse>> {
906
+ const body = {
907
+ collections: request?.collections,
908
+ };
909
+
910
+ const response = await this.apiClient.sendRequest<
911
+ StreamResponse<UpdateCollectionsResponse>
912
+ >(
913
+ 'PATCH',
914
+ '/api/v2/feeds/collections',
915
+ undefined,
916
+ undefined,
917
+ body,
918
+ 'application/json',
919
+ );
920
+
921
+ decoders.UpdateCollectionsResponse?.(response.body);
922
+
923
+ return { ...response.body, metadata: response.metadata };
924
+ }
925
+
926
+ async createCollections(
927
+ request: CreateCollectionsRequest,
928
+ ): Promise<StreamResponse<CreateCollectionsResponse>> {
929
+ const body = {
930
+ collections: request?.collections,
931
+ };
932
+
933
+ const response = await this.apiClient.sendRequest<
934
+ StreamResponse<CreateCollectionsResponse>
935
+ >(
936
+ 'POST',
937
+ '/api/v2/feeds/collections',
938
+ undefined,
939
+ undefined,
940
+ body,
941
+ 'application/json',
942
+ );
943
+
944
+ decoders.CreateCollectionsResponse?.(response.body);
945
+
946
+ return { ...response.body, metadata: response.metadata };
947
+ }
948
+
863
949
  async getComments(request: {
864
950
  object_id: string;
865
951
  object_type: string;
@@ -191,6 +191,8 @@ decoders.ActivityResponse = (input?: Record<string, any>) => {
191
191
 
192
192
  own_reactions: { type: 'FeedsReactionResponse', isSingle: false },
193
193
 
194
+ collections: { type: 'EnrichedCollectionResponse', isSingle: false },
195
+
194
196
  reaction_groups: { type: 'ReactionGroupResponse', isSingle: false },
195
197
 
196
198
  user: { type: 'UserResponse', isSingle: true },
@@ -616,6 +618,15 @@ decoders.ChannelResponse = (input?: Record<string, any>) => {
616
618
  return decode(typeMappings, input);
617
619
  };
618
620
 
621
+ decoders.CollectionResponse = (input?: Record<string, any>) => {
622
+ const typeMappings: TypeMapping = {
623
+ created_at: { type: 'DatetimeType', isSingle: true },
624
+
625
+ updated_at: { type: 'DatetimeType', isSingle: true },
626
+ };
627
+ return decode(typeMappings, input);
628
+ };
629
+
619
630
  decoders.Command = (input?: Record<string, any>) => {
620
631
  const typeMappings: TypeMapping = {
621
632
  created_at: { type: 'DatetimeType', isSingle: true },
@@ -740,6 +751,13 @@ decoders.CreateBlockListResponse = (input?: Record<string, any>) => {
740
751
  return decode(typeMappings, input);
741
752
  };
742
753
 
754
+ decoders.CreateCollectionsResponse = (input?: Record<string, any>) => {
755
+ const typeMappings: TypeMapping = {
756
+ collections: { type: 'CollectionResponse', isSingle: false },
757
+ };
758
+ return decode(typeMappings, input);
759
+ };
760
+
743
761
  decoders.CreateFeedsBatchResponse = (input?: Record<string, any>) => {
744
762
  const typeMappings: TypeMapping = {
745
763
  feeds: { type: 'FeedResponse', isSingle: false },
@@ -831,6 +849,15 @@ decoders.EgressRTMPResponse = (input?: Record<string, any>) => {
831
849
  return decode(typeMappings, input);
832
850
  };
833
851
 
852
+ decoders.EnrichedCollectionResponse = (input?: Record<string, any>) => {
853
+ const typeMappings: TypeMapping = {
854
+ created_at: { type: 'DatetimeType', isSingle: true },
855
+
856
+ updated_at: { type: 'DatetimeType', isSingle: true },
857
+ };
858
+ return decode(typeMappings, input);
859
+ };
860
+
834
861
  decoders.EntityCreatorResponse = (input?: Record<string, any>) => {
835
862
  const typeMappings: TypeMapping = {
836
863
  created_at: { type: 'DatetimeType', isSingle: true },
@@ -1670,6 +1697,13 @@ decoders.ReactionResponse = (input?: Record<string, any>) => {
1670
1697
  return decode(typeMappings, input);
1671
1698
  };
1672
1699
 
1700
+ decoders.ReadCollectionsResponse = (input?: Record<string, any>) => {
1701
+ const typeMappings: TypeMapping = {
1702
+ collections: { type: 'CollectionResponse', isSingle: false },
1703
+ };
1704
+ return decode(typeMappings, input);
1705
+ };
1706
+
1673
1707
  decoders.RejectFeedMemberInviteResponse = (input?: Record<string, any>) => {
1674
1708
  const typeMappings: TypeMapping = {
1675
1709
  member: { type: 'FeedMemberResponse', isSingle: true },
@@ -1893,6 +1927,13 @@ decoders.UpdateBookmarkResponse = (input?: Record<string, any>) => {
1893
1927
  return decode(typeMappings, input);
1894
1928
  };
1895
1929
 
1930
+ decoders.UpdateCollectionsResponse = (input?: Record<string, any>) => {
1931
+ const typeMappings: TypeMapping = {
1932
+ collections: { type: 'CollectionResponse', isSingle: false },
1933
+ };
1934
+ return decode(typeMappings, input);
1935
+ };
1936
+
1896
1937
  decoders.UpdateCommentResponse = (input?: Record<string, any>) => {
1897
1938
  const typeMappings: TypeMapping = {
1898
1939
  comment: { type: 'CommentResponse', isSingle: true },