@stream-io/feeds-client 1.0.0 → 1.2.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/index.js +477 -466
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/react-bindings.js +454 -463
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +440 -466
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +447 -493
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/feeds-client-ACVPbpUP.mjs +8752 -0
  11. package/dist/feeds-client-ACVPbpUP.mjs.map +1 -0
  12. package/dist/feeds-client-BP0fE4NZ.js +8918 -0
  13. package/dist/feeds-client-BP0fE4NZ.js.map +1 -0
  14. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  15. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts +6 -2
  16. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts.map +1 -1
  17. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts +6 -2
  18. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts.map +1 -1
  19. package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts +3 -2
  20. package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts.map +1 -1
  21. package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts +5 -0
  22. package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts.map +1 -1
  23. package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts +3 -2
  24. package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts.map +1 -1
  25. package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts +3 -2
  26. package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts.map +1 -1
  27. package/dist/types/feed/event-handlers/activity/index.d.ts +3 -1
  28. package/dist/types/feed/event-handlers/activity/index.d.ts.map +1 -1
  29. package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
  30. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
  31. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts +1 -1
  32. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts.map +1 -1
  33. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +6 -5
  34. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts.map +1 -1
  35. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +6 -5
  36. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts.map +1 -1
  37. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +6 -5
  38. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts.map +1 -1
  39. package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts +4 -0
  40. package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts.map +1 -0
  41. package/dist/types/feed/event-handlers/feed/handle-feed-updated.d.ts.map +1 -1
  42. package/dist/types/feed/event-handlers/feed/index.d.ts +1 -0
  43. package/dist/types/feed/event-handlers/feed/index.d.ts.map +1 -1
  44. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -2
  45. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts.map +1 -1
  46. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -2
  47. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts.map +1 -1
  48. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -2
  49. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts.map +1 -1
  50. package/dist/types/feed/event-handlers/follow/handle-follow-updated.d.ts.map +1 -1
  51. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -2
  52. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -1
  53. package/dist/types/feed/feed.d.ts.map +1 -1
  54. package/dist/types/feeds-client/feeds-client.d.ts +25 -1
  55. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  56. package/dist/types/gen/feeds/FeedsApi.d.ts +6 -4
  57. package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
  58. package/dist/types/gen/models/index.d.ts +40 -2
  59. package/dist/types/gen/models/index.d.ts.map +1 -1
  60. package/dist/types/utils/state-update-queue.d.ts +11 -2
  61. package/dist/types/utils/state-update-queue.d.ts.map +1 -1
  62. package/dist/types/utils/unique-array-merge.d.ts +1 -1
  63. package/dist/types/utils/unique-array-merge.d.ts.map +1 -1
  64. package/package.json +15 -15
  65. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts +6 -20
  66. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.ts +6 -20
  67. package/src/feed/event-handlers/activity/handle-activity-deleted.ts +28 -2
  68. package/src/feed/event-handlers/activity/handle-activity-feedback.ts +17 -7
  69. package/src/feed/event-handlers/activity/handle-activity-pinned.ts +25 -3
  70. package/src/feed/event-handlers/activity/handle-activity-unpinned.ts +25 -2
  71. package/src/feed/event-handlers/activity/index.ts +3 -1
  72. package/src/feed/event-handlers/add-aggregated-activities-to-state.ts +11 -2
  73. package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +20 -11
  74. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +21 -11
  75. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +24 -10
  76. package/src/feed/event-handlers/feed/handle-feed-deleted.ts +12 -0
  77. package/src/feed/event-handlers/feed/handle-feed-updated.ts +8 -0
  78. package/src/feed/event-handlers/feed/index.ts +1 -0
  79. package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +25 -2
  80. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +25 -2
  81. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +25 -2
  82. package/src/feed/event-handlers/follow/handle-follow-updated.ts +14 -0
  83. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +64 -2
  84. package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.ts +1 -1
  85. package/src/feed/feed.ts +7 -5
  86. package/src/feeds-client/feeds-client.ts +359 -45
  87. package/src/gen/feeds/FeedsApi.ts +79 -12
  88. package/src/gen/model-decoders/decoders.ts +7 -0
  89. package/src/gen/models/index.ts +66 -4
  90. package/src/utils/state-update-queue.ts +42 -28
  91. package/src/utils/unique-array-merge.ts +11 -3
  92. package/dist/feeds-client-B03y08Kq.mjs +0 -8409
  93. package/dist/feeds-client-B03y08Kq.mjs.map +0 -1
  94. package/dist/feeds-client-tw63OGrd.js +0 -8425
  95. package/dist/feeds-client-tw63OGrd.js.map +0 -1
  96. package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts +0 -12
  97. package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts.map +0 -1
  98. package/src/feed/event-handlers/activity/handle-activity-marked.ts +0 -68
@@ -1,8 +1,13 @@
1
1
  import { FeedsApi } from '../gen/feeds/FeedsApi';
2
2
  import type {
3
+ AcceptFeedMemberInviteResponse,
4
+ ActivityFeedbackRequest,
5
+ ActivityFeedbackResponse,
3
6
  ActivityResponse,
4
7
  AddActivityRequest,
5
8
  AddActivityResponse,
9
+ AddBookmarkRequest,
10
+ AddBookmarkResponse,
6
11
  AddCommentReactionRequest,
7
12
  AddCommentReactionResponse,
8
13
  AddCommentRequest,
@@ -11,8 +16,11 @@ import type {
11
16
  CastPollVoteRequest,
12
17
  CreateGuestResponse,
13
18
  DeleteActivityReactionResponse,
19
+ DeleteActivityResponse,
20
+ DeleteBookmarkResponse,
14
21
  DeleteCommentReactionResponse,
15
22
  DeleteCommentResponse,
23
+ DeleteFeedResponse,
16
24
  FeedResponse,
17
25
  FileUploadRequest,
18
26
  FollowBatchRequest,
@@ -23,16 +31,24 @@ import type {
23
31
  ImageSize,
24
32
  ImageUploadRequest,
25
33
  OwnBatchRequest,
34
+ PinActivityResponse,
26
35
  PollResponse,
27
36
  PollVoteResponse,
28
37
  PollVotesResponse,
29
38
  QueryFeedsRequest,
30
39
  QueryPollVotesRequest,
40
+ RejectFeedMemberInviteResponse,
31
41
  UnfollowBatchRequest,
42
+ UnpinActivityResponse,
43
+ UpdateActivityPartialResponse,
32
44
  UpdateActivityRequest,
33
45
  UpdateActivityResponse,
46
+ UpdateBookmarkRequest,
47
+ UpdateBookmarkResponse,
34
48
  UpdateCommentRequest,
35
49
  UpdateCommentResponse,
50
+ UpdateFeedMembersResponse,
51
+ UpdateFeedResponse,
36
52
  UpdateFollowRequest,
37
53
  UpdatePollPartialRequest,
38
54
  UpdatePollRequest,
@@ -68,21 +84,32 @@ import { StreamPoll } from '../common/Poll';
68
84
  import {
69
85
  Feed,
70
86
  type FeedState,
87
+ handleActivityDeleted,
71
88
  handleActivityReactionAdded,
72
89
  handleActivityReactionDeleted,
73
90
  handleActivityReactionUpdated,
74
91
  handleActivityUpdated,
92
+ handleActivityPinned,
93
+ handleActivityUnpinned,
94
+ handleBookmarkAdded,
95
+ handleBookmarkDeleted,
96
+ handleBookmarkUpdated,
75
97
  handleCommentAdded,
76
98
  handleCommentDeleted,
77
99
  handleCommentReactionAdded,
78
100
  handleCommentReactionDeleted,
79
101
  handleCommentUpdated,
102
+ handleFeedDeleted,
103
+ handleFeedMemberAdded,
104
+ handleFeedMemberRemoved,
105
+ handleFeedMemberUpdated,
80
106
  handleFeedUpdated,
81
107
  handleFollowCreated,
82
108
  handleFollowDeleted,
83
109
  handleFollowUpdated,
84
110
  handleWatchStarted,
85
111
  handleWatchStopped,
112
+ updateActivityFromFeedback,
86
113
  } from '../feed';
87
114
  import { applyNewActivityToActiveFeeds } from './apply-new-activity-to-active-feeds';
88
115
  import { handleUserUpdated } from './event-handlers';
@@ -564,6 +591,66 @@ export class FeedsClient extends FeedsApi {
564
591
  return response;
565
592
  };
566
593
 
594
+ updateActivityPartial = async (
595
+ ...args: Parameters<FeedsApi['updateActivityPartial']>
596
+ ): Promise<StreamResponse<UpdateActivityPartialResponse>> => {
597
+ const response = await super.updateActivityPartial(...args);
598
+ for (const feed of this.allActiveFeeds) {
599
+ handleActivityUpdated.bind(feed)(response, false);
600
+ }
601
+ return response;
602
+ };
603
+
604
+ deleteActivity = async (
605
+ ...args: Parameters<FeedsApi['deleteActivity']>
606
+ ): Promise<StreamResponse<DeleteActivityResponse>> => {
607
+ const response = await super.deleteActivity(...args);
608
+ const activityId = args[0].id;
609
+ for (const feed of this.allActiveFeeds) {
610
+ handleActivityDeleted.bind(feed)(
611
+ { activity: { id: activityId } } as Parameters<
612
+ typeof handleActivityDeleted
613
+ >[0],
614
+ false,
615
+ );
616
+ }
617
+ this.activeActivities = this.activeActivities.filter(
618
+ (activity) => activity.id !== activityId,
619
+ );
620
+ return response;
621
+ };
622
+
623
+ activityFeedback = async (
624
+ request: ActivityFeedbackRequest & { activity_id: string },
625
+ ): Promise<StreamResponse<ActivityFeedbackResponse>> => {
626
+ const response = await super.activityFeedback(request);
627
+ if (request.hide !== undefined) {
628
+ const feedback = {
629
+ activity_id: request.activity_id,
630
+ action: 'hide' as const,
631
+ value: request.hide ? 'true' : 'false',
632
+ };
633
+ for (const feed of this.allActiveFeeds) {
634
+ const {
635
+ activities: currentActivities,
636
+ pinned_activities: currentPinnedActivities,
637
+ } = feed.currentState;
638
+ const [result1, result2] = [
639
+ updateActivityFromFeedback(feedback, currentActivities),
640
+ updateActivityFromFeedback(feedback, currentPinnedActivities),
641
+ ];
642
+
643
+ if (result1.changed || result2.changed) {
644
+ feed.state.partialNext({
645
+ activities: result1.entities,
646
+ pinned_activities: result2.entities,
647
+ });
648
+ }
649
+ }
650
+ }
651
+ return response;
652
+ };
653
+
567
654
  addComment = async (
568
655
  request: AddCommentRequest,
569
656
  ): Promise<StreamResponse<AddCommentResponse>> => {
@@ -693,6 +780,161 @@ export class FeedsClient extends FeedsApi {
693
780
  return response;
694
781
  };
695
782
 
783
+ addBookmark = async (
784
+ request: AddBookmarkRequest & { activity_id: string },
785
+ ): Promise<StreamResponse<AddBookmarkResponse>> => {
786
+ const response = await super.addBookmark(request);
787
+ for (const feed of this.allActiveFeeds) {
788
+ handleBookmarkAdded.bind(feed)(response);
789
+ }
790
+ return response;
791
+ };
792
+
793
+ updateBookmark = async (
794
+ request: UpdateBookmarkRequest & { activity_id: string },
795
+ ): Promise<StreamResponse<UpdateBookmarkResponse>> => {
796
+ const response = await super.updateBookmark(request);
797
+ for (const feed of this.allActiveFeeds) {
798
+ handleBookmarkUpdated.bind(feed)(response);
799
+ }
800
+ return response;
801
+ };
802
+
803
+ deleteBookmark = async (request: {
804
+ activity_id: string;
805
+ folder_id?: string;
806
+ }): Promise<StreamResponse<DeleteBookmarkResponse>> => {
807
+ const response = await super.deleteBookmark(request);
808
+ for (const feed of this.allActiveFeeds) {
809
+ handleBookmarkDeleted.bind(feed)(response);
810
+ }
811
+ return response;
812
+ };
813
+
814
+ pinActivity = async (
815
+ ...args: Parameters<FeedsApi['pinActivity']>
816
+ ): Promise<StreamResponse<PinActivityResponse>> => {
817
+ const response = await super.pinActivity(...args);
818
+ const feedIds =
819
+ response.activity?.feeds ?? (response.feed ? [response.feed] : []);
820
+ for (const fid of feedIds) {
821
+ const feed = this.activeFeeds[fid];
822
+ if (feed) {
823
+ handleActivityPinned.bind(feed)(
824
+ { pinned_activity: response } as Parameters<
825
+ typeof handleActivityPinned
826
+ >[0],
827
+ false,
828
+ );
829
+ }
830
+ }
831
+ return response;
832
+ };
833
+
834
+ unpinActivity = async (
835
+ ...args: Parameters<FeedsApi['unpinActivity']>
836
+ ): Promise<StreamResponse<UnpinActivityResponse>> => {
837
+ const response = await super.unpinActivity(...args);
838
+ const feedIds =
839
+ response.activity?.feeds ?? (response.feed ? [response.feed] : []);
840
+ for (const fid of feedIds) {
841
+ const feed = this.activeFeeds[fid];
842
+ if (feed) {
843
+ handleActivityUnpinned.bind(feed)(
844
+ {
845
+ pinned_activity: {
846
+ ...response,
847
+ created_at: new Date(),
848
+ },
849
+ } as Parameters<typeof handleActivityUnpinned>[0],
850
+ false,
851
+ );
852
+ }
853
+ }
854
+ return response;
855
+ };
856
+
857
+ updateFeed = async (
858
+ ...args: Parameters<FeedsApi['updateFeed']>
859
+ ): Promise<StreamResponse<UpdateFeedResponse>> => {
860
+ const response = await super.updateFeed(...args);
861
+ const fid = `${args[0].feed_group_id}:${args[0].feed_id}`;
862
+ const feed = this.activeFeeds[fid];
863
+ if (feed) {
864
+ handleFeedUpdated.call(feed, { feed: response.feed } as Parameters<
865
+ typeof handleFeedUpdated
866
+ >[0]);
867
+ }
868
+ this.checkIfOwnFieldsChanged(response.feed, !!args[0].enrich_own_fields);
869
+ return response;
870
+ };
871
+
872
+ deleteFeed = async (
873
+ ...args: Parameters<FeedsApi['deleteFeed']>
874
+ ): Promise<StreamResponse<DeleteFeedResponse>> => {
875
+ const response = await super.deleteFeed(...args);
876
+ const fid = `${args[0].feed_group_id}:${args[0].feed_id}`;
877
+ const feed = this.activeFeeds[fid];
878
+ if (feed) {
879
+ handleFeedDeleted.call(feed, {
880
+ created_at: new Date(),
881
+ } as Parameters<typeof handleFeedDeleted>[0]);
882
+ // If the feed is not watched, clean up immediately (no WS event will follow).
883
+ // If watched, the WS handler will clean up after dispatching the event.
884
+ if (!feed.currentState.watch) {
885
+ delete this.activeFeeds[fid];
886
+ this.activeActivities = this.activeActivities.filter(
887
+ (activity) => getFeed.call(activity)?.feed !== fid,
888
+ );
889
+ }
890
+ }
891
+ return response;
892
+ };
893
+
894
+ updateFeedMembers = async (
895
+ ...args: Parameters<FeedsApi['updateFeedMembers']>
896
+ ): Promise<StreamResponse<UpdateFeedMembersResponse>> => {
897
+ const response = await super.updateFeedMembers(...args);
898
+ const fid = `${args[0].feed_group_id}:${args[0].feed_id}`;
899
+ const feed = this.activeFeeds[fid];
900
+ if (feed) {
901
+ for (const member of response.added) {
902
+ handleFeedMemberAdded.call(feed, { member }, false);
903
+ }
904
+ for (const member of response.updated) {
905
+ handleFeedMemberUpdated.call(feed, { member }, false);
906
+ }
907
+ for (const memberId of response.removed_ids) {
908
+ handleFeedMemberRemoved.call(feed, { member_id: memberId }, false);
909
+ }
910
+ }
911
+ return response;
912
+ };
913
+
914
+ acceptFeedMemberInvite = async (
915
+ ...args: Parameters<FeedsApi['acceptFeedMemberInvite']>
916
+ ): Promise<StreamResponse<AcceptFeedMemberInviteResponse>> => {
917
+ const response = await super.acceptFeedMemberInvite(...args);
918
+ const fid = `${args[0].feed_group_id}:${args[0].feed_id}`;
919
+ const feed = this.activeFeeds[fid];
920
+ if (feed) {
921
+ handleFeedMemberUpdated.call(feed, { member: response.member }, false);
922
+ }
923
+ return response;
924
+ };
925
+
926
+ rejectFeedMemberInvite = async (
927
+ ...args: Parameters<FeedsApi['rejectFeedMemberInvite']>
928
+ ): Promise<StreamResponse<RejectFeedMemberInviteResponse>> => {
929
+ const response = await super.rejectFeedMemberInvite(...args);
930
+ const fid = `${args[0].feed_group_id}:${args[0].feed_id}`;
931
+ const feed = this.activeFeeds[fid];
932
+ if (feed) {
933
+ handleFeedMemberUpdated.call(feed, { member: response.member }, false);
934
+ }
935
+ return response;
936
+ };
937
+
696
938
  queryPollAnswers = async (
697
939
  request: QueryPollVotesRequest & { poll_id: string; user_id?: string },
698
940
  ): Promise<StreamResponse<PollVotesResponse>> => {
@@ -853,6 +1095,28 @@ export class FeedsClient extends FeedsApi {
853
1095
  feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
854
1096
  });
855
1097
 
1098
+ this.checkIfOwnFieldsChanged(
1099
+ response.follow.source_feed,
1100
+ !!request.enrich_own_fields,
1101
+ );
1102
+ this.checkIfOwnFieldsChanged(
1103
+ response.follow.target_feed,
1104
+ !!request.enrich_own_fields,
1105
+ );
1106
+ return response;
1107
+ }
1108
+
1109
+ async acceptFollow(...args: Parameters<FeedsApi['acceptFollow']>) {
1110
+ const response = await super.acceptFollow(...args);
1111
+
1112
+ [
1113
+ response.follow.source_feed.feed,
1114
+ response.follow.target_feed.feed,
1115
+ ].forEach((fid) => {
1116
+ const feeds = this.findAllActiveFeedsByFid(fid);
1117
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
1118
+ });
1119
+
856
1120
  return response;
857
1121
  }
858
1122
 
@@ -860,7 +1124,14 @@ export class FeedsClient extends FeedsApi {
860
1124
  async follow(request: FollowRequest) {
861
1125
  const response = await super.follow(request);
862
1126
  this.updateStateFromFollows([response.follow], !!request.enrich_own_fields);
863
-
1127
+ this.checkIfOwnFieldsChanged(
1128
+ response.follow.source_feed,
1129
+ !!request.enrich_own_fields,
1130
+ );
1131
+ this.checkIfOwnFieldsChanged(
1132
+ response.follow.target_feed,
1133
+ !!request.enrich_own_fields,
1134
+ );
864
1135
  return response;
865
1136
  }
866
1137
 
@@ -872,7 +1143,11 @@ export class FeedsClient extends FeedsApi {
872
1143
  async followBatch(request: FollowBatchRequest) {
873
1144
  const response = await super.followBatch(request);
874
1145
  this.updateStateFromFollows(response.follows, !!request.enrich_own_fields);
875
-
1146
+ const enrichOwnFields = !!request.enrich_own_fields;
1147
+ for (const follow of response.follows) {
1148
+ this.checkIfOwnFieldsChanged(follow.source_feed, enrichOwnFields);
1149
+ this.checkIfOwnFieldsChanged(follow.target_feed, enrichOwnFields);
1150
+ }
876
1151
  return response;
877
1152
  }
878
1153
 
@@ -880,7 +1155,12 @@ export class FeedsClient extends FeedsApi {
880
1155
  const response = await super.getOrCreateFollows(request);
881
1156
 
882
1157
  this.updateStateFromFollows(response.created, !!request.enrich_own_fields);
883
-
1158
+ const enrichOwnFields = !!request.enrich_own_fields;
1159
+ const allFollows = [...response.created, ...response.follows];
1160
+ for (const follow of allFollows) {
1161
+ this.checkIfOwnFieldsChanged(follow.source_feed, enrichOwnFields);
1162
+ this.checkIfOwnFieldsChanged(follow.target_feed, enrichOwnFields);
1163
+ }
884
1164
  return response;
885
1165
  }
886
1166
 
@@ -891,14 +1171,25 @@ export class FeedsClient extends FeedsApi {
891
1171
  }) {
892
1172
  const response = await super.unfollow(request);
893
1173
  this.updateStateFromUnfollows([response.follow]);
894
-
1174
+ this.checkIfOwnFieldsChanged(
1175
+ response.follow.source_feed,
1176
+ !!request.enrich_own_fields,
1177
+ );
1178
+ this.checkIfOwnFieldsChanged(
1179
+ response.follow.target_feed,
1180
+ !!request.enrich_own_fields,
1181
+ );
895
1182
  return response;
896
1183
  }
897
1184
 
898
1185
  async getOrCreateUnfollows(request: UnfollowBatchRequest) {
899
1186
  const response = await super.getOrCreateUnfollows(request);
900
1187
  this.updateStateFromUnfollows(response.follows);
901
-
1188
+ const enrichOwnFields = !!request.enrich_own_fields;
1189
+ for (const follow of response.follows) {
1190
+ this.checkIfOwnFieldsChanged(follow.source_feed, enrichOwnFields);
1191
+ this.checkIfOwnFieldsChanged(follow.target_feed, enrichOwnFields);
1192
+ }
902
1193
  return response;
903
1194
  }
904
1195
 
@@ -998,6 +1289,7 @@ export class FeedsClient extends FeedsApi {
998
1289
  feed.onNewActivity = options.onNewActivity;
999
1290
  }
1000
1291
 
1292
+ let wasFullUpdate = isCreated;
1001
1293
  if (!feed.currentState.watch) {
1002
1294
  if (!isCreated && data) {
1003
1295
  if (
@@ -1005,54 +1297,76 @@ export class FeedsClient extends FeedsApi {
1005
1297
  data.updated_at.getTime()
1006
1298
  ) {
1007
1299
  handleFeedUpdated.call(feed, { feed: data });
1008
- } else if (
1009
- (feed.currentState.updated_at?.getTime() ?? 0) ===
1010
- data.updated_at.getTime()
1011
- ) {
1012
- const fieldsToUpdateData: Array<keyof FeedResponse> = [];
1013
- const fieldChecks: Array<
1014
- [
1015
- (
1016
- | 'own_capabilities'
1017
- | 'own_follows'
1018
- | 'own_membership'
1019
- | 'own_followings'
1020
- ),
1021
- (currentState: FeedState, newState: FeedResponse) => boolean,
1022
- ]
1023
- > = [
1024
- ['own_capabilities', isOwnCapabilitiesEqual],
1025
- ['own_follows', isOwnFollowsEqual],
1026
- ['own_membership', isOwnMembershipEqual],
1027
- ['own_followings', isOwnFollowingsEqual],
1028
- ];
1029
- fieldChecks.forEach(([field, isEqual]) => {
1030
- if (
1031
- fieldsToUpdate.includes(field) &&
1032
- !isEqual(feed.currentState, data)
1033
- ) {
1034
- fieldsToUpdateData.push(field);
1035
- }
1036
- });
1037
- if (fieldsToUpdateData.length > 0) {
1038
- const fieldsToUpdatePayload = fieldsToUpdateData.reduce(
1039
- (acc: Partial<FeedResponse>, field) => {
1040
- // @ts-expect-error TODO: fix this
1041
- acc[field] = data[field];
1042
- return acc;
1043
- },
1044
- {},
1045
- );
1046
- feed.state.partialNext(fieldsToUpdatePayload);
1047
- }
1300
+ wasFullUpdate = true;
1048
1301
  }
1049
1302
  }
1050
1303
  if (watch) handleWatchStarted.call(feed);
1051
1304
  }
1052
1305
 
1306
+ // If we didn't do a full update, check if own_* fields have changed
1307
+ if (!wasFullUpdate && data && fieldsToUpdate.length > 0) {
1308
+ const fieldsToUpdateData: Array<keyof FeedResponse> = [];
1309
+ const fieldChecks: Array<
1310
+ [
1311
+ (
1312
+ | 'own_capabilities'
1313
+ | 'own_follows'
1314
+ | 'own_membership'
1315
+ | 'own_followings'
1316
+ ),
1317
+ (currentState: FeedState, newState: FeedResponse) => boolean,
1318
+ ]
1319
+ > = [
1320
+ ['own_capabilities', isOwnCapabilitiesEqual],
1321
+ ['own_follows', isOwnFollowsEqual],
1322
+ ['own_membership', isOwnMembershipEqual],
1323
+ ['own_followings', isOwnFollowingsEqual],
1324
+ ];
1325
+ fieldChecks.forEach(([field, isEqual]) => {
1326
+ if (
1327
+ fieldsToUpdate.includes(field) &&
1328
+ !isEqual(feed.currentState, data)
1329
+ ) {
1330
+ fieldsToUpdateData.push(field);
1331
+ }
1332
+ });
1333
+ if (fieldsToUpdateData.length > 0) {
1334
+ const fieldsToUpdatePayload = fieldsToUpdateData.reduce(
1335
+ (acc: Partial<FeedResponse>, field) => {
1336
+ // @ts-expect-error TODO: fix this
1337
+ acc[field] = data[field];
1338
+ return acc;
1339
+ },
1340
+ {},
1341
+ );
1342
+ feed.state.partialNext(fieldsToUpdatePayload);
1343
+ }
1344
+ }
1345
+
1053
1346
  return feed;
1054
1347
  };
1055
1348
 
1349
+ // Used when updating from HTTP responses to check if own_* fields have changed
1350
+ // It'll do a state update if WS update ran before HTTP, but WS doesn't have own_* fields
1351
+ private checkIfOwnFieldsChanged(
1352
+ feed: FeedResponse,
1353
+ enrichOwnFields: boolean,
1354
+ ) {
1355
+ if (!enrichOwnFields || !this.activeFeeds[feed.feed]) return false;
1356
+
1357
+ this.getOrCreateActiveFeed({
1358
+ group: feed.group_id,
1359
+ id: feed.id,
1360
+ data: feed,
1361
+ fieldsToUpdate: [
1362
+ 'own_capabilities',
1363
+ 'own_follows',
1364
+ 'own_membership',
1365
+ 'own_followings',
1366
+ ],
1367
+ });
1368
+ }
1369
+
1056
1370
  private findAllActiveFeedsByActivityId(activityId: string) {
1057
1371
  return [
1058
1372
  ...Object.values(this.activeFeeds),
@@ -84,6 +84,8 @@ import type {
84
84
  QueryBookmarkFoldersResponse,
85
85
  QueryBookmarksRequest,
86
86
  QueryBookmarksResponse,
87
+ QueryCollectionsRequest,
88
+ QueryCollectionsResponse,
87
89
  QueryCommentReactionsRequest,
88
90
  QueryCommentReactionsResponse,
89
91
  QueryCommentsRequest,
@@ -106,6 +108,7 @@ import type {
106
108
  RejectFeedMemberInviteResponse,
107
109
  RejectFollowRequest,
108
110
  RejectFollowResponse,
111
+ RemoveUserGroupMembersRequest,
109
112
  RemoveUserGroupMembersResponse,
110
113
  Response,
111
114
  RestoreActivityRequest,
@@ -114,6 +117,8 @@ import type {
114
117
  SharedLocationResponse,
115
118
  SharedLocationsResponse,
116
119
  SingleFollowResponse,
120
+ TrackActivityMetricsRequest,
121
+ TrackActivityMetricsResponse,
117
122
  UnblockUsersRequest,
118
123
  UnblockUsersResponse,
119
124
  UnfollowBatchRequest,
@@ -413,6 +418,29 @@ export class FeedsApi {
413
418
  return { ...response.body, metadata: response.metadata };
414
419
  }
415
420
 
421
+ async trackActivityMetrics(
422
+ request: TrackActivityMetricsRequest,
423
+ ): Promise<StreamResponse<TrackActivityMetricsResponse>> {
424
+ const body = {
425
+ events: request?.events,
426
+ };
427
+
428
+ const response = await this.apiClient.sendRequest<
429
+ StreamResponse<TrackActivityMetricsResponse>
430
+ >(
431
+ 'POST',
432
+ '/api/v2/feeds/activities/metrics/track',
433
+ undefined,
434
+ undefined,
435
+ body,
436
+ 'application/json',
437
+ );
438
+
439
+ decoders.TrackActivityMetricsResponse?.(response.body);
440
+
441
+ return { ...response.body, metadata: response.metadata };
442
+ }
443
+
416
444
  async queryActivities(
417
445
  request?: QueryActivitiesRequest,
418
446
  ): Promise<StreamResponse<QueryActivitiesResponse>> {
@@ -1020,6 +1048,33 @@ export class FeedsApi {
1020
1048
  return { ...response.body, metadata: response.metadata };
1021
1049
  }
1022
1050
 
1051
+ async queryCollections(
1052
+ request?: QueryCollectionsRequest,
1053
+ ): Promise<StreamResponse<QueryCollectionsResponse>> {
1054
+ const body = {
1055
+ limit: request?.limit,
1056
+ next: request?.next,
1057
+ prev: request?.prev,
1058
+ sort: request?.sort,
1059
+ filter: request?.filter,
1060
+ };
1061
+
1062
+ const response = await this.apiClient.sendRequest<
1063
+ StreamResponse<QueryCollectionsResponse>
1064
+ >(
1065
+ 'POST',
1066
+ '/api/v2/feeds/collections/query',
1067
+ undefined,
1068
+ undefined,
1069
+ body,
1070
+ 'application/json',
1071
+ );
1072
+
1073
+ decoders.QueryCollectionsResponse?.(response.body);
1074
+
1075
+ return { ...response.body, metadata: response.metadata };
1076
+ }
1077
+
1023
1078
  async getComments(request: {
1024
1079
  object_id: string;
1025
1080
  object_type: string;
@@ -1112,6 +1167,7 @@ export class FeedsApi {
1112
1167
  ): Promise<StreamResponse<QueryCommentsResponse>> {
1113
1168
  const body = {
1114
1169
  filter: request?.filter,
1170
+ id_around: request?.id_around,
1115
1171
  limit: request?.limit,
1116
1172
  next: request?.next,
1117
1173
  prev: request?.prev,
@@ -2649,25 +2705,36 @@ export class FeedsApi {
2649
2705
  return { ...response.body, metadata: response.metadata };
2650
2706
  }
2651
2707
 
2652
- async removeUserGroupMembers(request: {
2653
- id: string;
2654
- }): Promise<StreamResponse<RemoveUserGroupMembersResponse>> {
2708
+ async addUserGroupMembers(
2709
+ request: AddUserGroupMembersRequest & { id: string },
2710
+ ): Promise<StreamResponse<AddUserGroupMembersResponse>> {
2655
2711
  const pathParams = {
2656
2712
  id: request?.id,
2657
2713
  };
2714
+ const body = {
2715
+ member_ids: request?.member_ids,
2716
+ team_id: request?.team_id,
2717
+ };
2658
2718
 
2659
2719
  const response = await this.apiClient.sendRequest<
2660
- StreamResponse<RemoveUserGroupMembersResponse>
2661
- >('DELETE', '/api/v2/usergroups/{id}/members', pathParams, undefined);
2720
+ StreamResponse<AddUserGroupMembersResponse>
2721
+ >(
2722
+ 'POST',
2723
+ '/api/v2/usergroups/{id}/members',
2724
+ pathParams,
2725
+ undefined,
2726
+ body,
2727
+ 'application/json',
2728
+ );
2662
2729
 
2663
- decoders.RemoveUserGroupMembersResponse?.(response.body);
2730
+ decoders.AddUserGroupMembersResponse?.(response.body);
2664
2731
 
2665
2732
  return { ...response.body, metadata: response.metadata };
2666
2733
  }
2667
2734
 
2668
- async addUserGroupMembers(
2669
- request: AddUserGroupMembersRequest & { id: string },
2670
- ): Promise<StreamResponse<AddUserGroupMembersResponse>> {
2735
+ async removeUserGroupMembers(
2736
+ request: RemoveUserGroupMembersRequest & { id: string },
2737
+ ): Promise<StreamResponse<RemoveUserGroupMembersResponse>> {
2671
2738
  const pathParams = {
2672
2739
  id: request?.id,
2673
2740
  };
@@ -2677,17 +2744,17 @@ export class FeedsApi {
2677
2744
  };
2678
2745
 
2679
2746
  const response = await this.apiClient.sendRequest<
2680
- StreamResponse<AddUserGroupMembersResponse>
2747
+ StreamResponse<RemoveUserGroupMembersResponse>
2681
2748
  >(
2682
2749
  'POST',
2683
- '/api/v2/usergroups/{id}/members',
2750
+ '/api/v2/usergroups/{id}/members/delete',
2684
2751
  pathParams,
2685
2752
  undefined,
2686
2753
  body,
2687
2754
  'application/json',
2688
2755
  );
2689
2756
 
2690
- decoders.AddUserGroupMembersResponse?.(response.body);
2757
+ decoders.RemoveUserGroupMembersResponse?.(response.body);
2691
2758
 
2692
2759
  return { ...response.body, metadata: response.metadata };
2693
2760
  }
@@ -1554,6 +1554,13 @@ decoders.QueryBookmarksResponse = (input?: Record<string, any>) => {
1554
1554
  return decode(typeMappings, input);
1555
1555
  };
1556
1556
 
1557
+ decoders.QueryCollectionsResponse = (input?: Record<string, any>) => {
1558
+ const typeMappings: TypeMapping = {
1559
+ collections: { type: 'CollectionResponse', isSingle: false },
1560
+ };
1561
+ return decode(typeMappings, input);
1562
+ };
1563
+
1557
1564
  decoders.QueryCommentReactionsResponse = (input?: Record<string, any>) => {
1558
1565
  const typeMappings: TypeMapping = {
1559
1566
  reactions: { type: 'FeedsReactionResponse', isSingle: false },