@stream-io/feeds-client 0.1.5 → 0.1.7

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 (44) hide show
  1. package/@react-bindings/hooks/feed-state-hooks/index.ts +2 -0
  2. package/CHANGELOG.md +25 -0
  3. package/dist/@react-bindings/hooks/client-state-hooks/useWsConnectionState.d.ts +1 -1
  4. package/dist/@react-bindings/hooks/feed-state-hooks/index.d.ts +2 -0
  5. package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +2 -2
  6. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +2 -2
  7. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedMetadata.d.ts +12 -0
  8. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +2 -2
  9. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +2 -2
  10. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnCapabilities.d.ts +30 -30
  11. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +8 -0
  12. package/dist/index-react-bindings.browser.cjs +147 -85
  13. package/dist/index-react-bindings.browser.cjs.map +1 -1
  14. package/dist/index-react-bindings.browser.js +146 -86
  15. package/dist/index-react-bindings.browser.js.map +1 -1
  16. package/dist/index-react-bindings.node.cjs +147 -85
  17. package/dist/index-react-bindings.node.cjs.map +1 -1
  18. package/dist/index-react-bindings.node.js +146 -86
  19. package/dist/index-react-bindings.node.js.map +1 -1
  20. package/dist/index.browser.cjs +67 -37
  21. package/dist/index.browser.cjs.map +1 -1
  22. package/dist/index.browser.js +67 -37
  23. package/dist/index.browser.js.map +1 -1
  24. package/dist/index.node.cjs +67 -37
  25. package/dist/index.node.cjs.map +1 -1
  26. package/dist/index.node.js +67 -37
  27. package/dist/index.node.js.map +1 -1
  28. package/dist/src/FeedsClient.d.ts +2 -2
  29. package/dist/src/gen/feeds/FeedApi.d.ts +3 -0
  30. package/dist/src/gen/feeds/FeedsApi.d.ts +5 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +6 -3
  33. package/src/Feed.ts +17 -11
  34. package/src/FeedsClient.ts +15 -10
  35. package/src/common/ActivitySearchSource.ts +5 -5
  36. package/src/common/ApiClient.ts +1 -1
  37. package/src/common/FeedSearchSource.ts +1 -1
  38. package/src/common/Poll.ts +35 -10
  39. package/src/common/TokenManager.ts +2 -3
  40. package/src/common/UserSearchSource.ts +1 -1
  41. package/src/gen/feeds/FeedApi.ts +10 -0
  42. package/src/gen/feeds/FeedsApi.ts +25 -0
  43. package/src/state-updates/bookmark-utils.test.ts +134 -8
  44. package/src/state-updates/bookmark-utils.ts +17 -7
@@ -2244,6 +2244,18 @@ class FeedsApi {
2244
2244
  decoders.RejectFeedMemberInviteResponse?.(response.body);
2245
2245
  return { ...response.body, metadata: response.metadata };
2246
2246
  }
2247
+ async stopWatchingFeed(request) {
2248
+ const queryParams = {
2249
+ connection_id: request?.connection_id,
2250
+ };
2251
+ const pathParams = {
2252
+ feed_group_id: request?.feed_group_id,
2253
+ feed_id: request?.feed_id,
2254
+ };
2255
+ const response = await this.apiClient.sendRequest('DELETE', '/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}/watch', pathParams, queryParams);
2256
+ decoders.Response?.(response.body);
2257
+ return { ...response.body, metadata: response.metadata };
2258
+ }
2247
2259
  async getFollowSuggestions(request) {
2248
2260
  const queryParams = {
2249
2261
  limit: request?.limit,
@@ -2781,7 +2793,7 @@ class TokenManager {
2781
2793
  }
2782
2794
  catch (e) {
2783
2795
  const numberOfFailures = ++previousFailuresCount;
2784
- await sleep(retryInterval(numberOfFailures));
2796
+ await sleep(1000);
2785
2797
  if (numberOfFailures === 3) {
2786
2798
  this.loadTokenPromise = null;
2787
2799
  return reject(new Error(`Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`, { cause: e }));
@@ -3629,7 +3641,7 @@ class ApiClient {
3629
3641
  rate_limit: getRateLimitFromResponseHeader(response_headers),
3630
3642
  };
3631
3643
  };
3632
- this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
3644
+ this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
3633
3645
  this.timeout = options?.timeout ?? 3000;
3634
3646
  this.axiosInstance = axios.create({
3635
3647
  baseURL: this.baseUrl,
@@ -3793,6 +3805,13 @@ class FeedApi {
3793
3805
  ...request,
3794
3806
  });
3795
3807
  }
3808
+ stopWatching(request) {
3809
+ return this.feedsApi.stopWatchingFeed({
3810
+ feed_id: this.id,
3811
+ feed_group_id: this.group,
3812
+ ...request,
3813
+ });
3814
+ }
3796
3815
  }
3797
3816
 
3798
3817
  const addActivitiesToState = (newActivities, activities, position) => {
@@ -3923,6 +3942,13 @@ const removeReactionFromActivities = (event, activities, isCurrentUser) => {
3923
3942
  return updateActivityInActivities$1(updatedActivity, activities);
3924
3943
  };
3925
3944
 
3945
+ // Helper function to check if two bookmarks are the same
3946
+ // A bookmark is identified by activity_id + folder_id + user_id
3947
+ const isSameBookmark = (bookmark1, bookmark2) => {
3948
+ return (bookmark1.user.id === bookmark2.user.id &&
3949
+ bookmark1.activity.id === bookmark2.activity.id &&
3950
+ bookmark1.folder?.id === bookmark2.folder?.id);
3951
+ };
3926
3952
  const updateActivityInActivities = (updatedActivity, activities) => {
3927
3953
  const index = activities.findIndex((a) => a.id === updatedActivity.id);
3928
3954
  if (index !== -1) {
@@ -3949,8 +3975,7 @@ const addBookmarkToActivity = (event, activity, isCurrentUser) => {
3949
3975
  const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
3950
3976
  // Update own_bookmarks if the bookmark is from the current user
3951
3977
  const ownBookmarks = isCurrentUser
3952
- ? (activity.own_bookmarks || []).filter((bookmark) => bookmark.user.id !== event.bookmark.user.id ||
3953
- bookmark.activity.id !== event.bookmark.activity.id)
3978
+ ? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
3954
3979
  : activity.own_bookmarks;
3955
3980
  return {
3956
3981
  ...activity,
@@ -3962,8 +3987,7 @@ const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
3962
3987
  // Update own_bookmarks if the bookmark is from the current user
3963
3988
  let ownBookmarks = activity.own_bookmarks || [];
3964
3989
  if (isCurrentUser) {
3965
- const bookmarkIndex = ownBookmarks.findIndex((bookmark) => bookmark.user.id === event.bookmark.user.id &&
3966
- bookmark.activity.id === event.bookmark.activity.id);
3990
+ const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
3967
3991
  if (bookmarkIndex !== -1) {
3968
3992
  ownBookmarks = [...ownBookmarks];
3969
3993
  ownBookmarks[bookmarkIndex] = event.bookmark;
@@ -4045,7 +4069,7 @@ class Feed extends FeedApi {
4045
4069
  },
4046
4070
  'feeds.activity.reaction.added': (event) => {
4047
4071
  const currentActivities = this.currentState.activities;
4048
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4072
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4049
4073
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4050
4074
  const result = addReactionToActivities(event, currentActivities, isCurrentUser);
4051
4075
  if (result.changed) {
@@ -4054,7 +4078,7 @@ class Feed extends FeedApi {
4054
4078
  },
4055
4079
  'feeds.activity.reaction.deleted': (event) => {
4056
4080
  const currentActivities = this.currentState.activities;
4057
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4081
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4058
4082
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4059
4083
  const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
4060
4084
  if (result.changed) {
@@ -4193,7 +4217,7 @@ class Feed extends FeedApi {
4193
4217
  // someone followed this feed
4194
4218
  event.follow.target_feed.fid === this.fid) {
4195
4219
  const source = event.follow.source_feed;
4196
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4220
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4197
4221
  this.state.next((currentState) => {
4198
4222
  const newState = { ...currentState, ...event.follow.target_feed };
4199
4223
  if (source.created_by.id === connectedUser?.id) {
@@ -4226,7 +4250,7 @@ class Feed extends FeedApi {
4226
4250
  // someone unfollowed this feed
4227
4251
  event.follow.target_feed.fid === this.fid) {
4228
4252
  const source = event.follow.source_feed;
4229
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4253
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4230
4254
  this.state.next((currentState) => {
4231
4255
  const newState = { ...currentState, ...event.follow.target_feed };
4232
4256
  if (source.created_by.id === connectedUser?.id) {
@@ -4242,7 +4266,7 @@ class Feed extends FeedApi {
4242
4266
  'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
4243
4267
  'feeds.comment.reaction.updated': Feed.noop,
4244
4268
  'feeds.feed_member.added': (event) => {
4245
- const { connectedUser } = this.client.state.getLatestValue();
4269
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4246
4270
  this.state.next((currentState) => {
4247
4271
  let newState;
4248
4272
  if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
@@ -4263,7 +4287,7 @@ class Feed extends FeedApi {
4263
4287
  });
4264
4288
  },
4265
4289
  'feeds.feed_member.removed': (event) => {
4266
- const { connectedUser } = this.client.state.getLatestValue();
4290
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4267
4291
  this.state.next((currentState) => {
4268
4292
  const newState = {
4269
4293
  ...currentState,
@@ -4276,7 +4300,7 @@ class Feed extends FeedApi {
4276
4300
  });
4277
4301
  },
4278
4302
  'feeds.feed_member.updated': (event) => {
4279
- const { connectedUser } = this.client.state.getLatestValue();
4303
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4280
4304
  this.state.next((currentState) => {
4281
4305
  const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
4282
4306
  let newState;
@@ -4341,7 +4365,7 @@ class Feed extends FeedApi {
4341
4365
  }
4342
4366
  handleCommentReactionEvent(event) {
4343
4367
  const { comment, reaction } = event;
4344
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4368
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4345
4369
  this.state.next((currentState) => {
4346
4370
  const forId = comment.parent_id ?? comment.object_id;
4347
4371
  const entityState = currentState.comments_by_entity_id[forId];
@@ -4443,7 +4467,7 @@ class Feed extends FeedApi {
4443
4467
  }
4444
4468
  handleBookmarkAdded(event) {
4445
4469
  const currentActivities = this.currentState.activities;
4446
- const { connectedUser } = this.client.state.getLatestValue();
4470
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4447
4471
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4448
4472
  const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
4449
4473
  if (result.changed) {
@@ -4452,7 +4476,7 @@ class Feed extends FeedApi {
4452
4476
  }
4453
4477
  handleBookmarkDeleted(event) {
4454
4478
  const currentActivities = this.currentState.activities;
4455
- const { connectedUser } = this.client.state.getLatestValue();
4479
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4456
4480
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4457
4481
  const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
4458
4482
  if (result.changed) {
@@ -4461,7 +4485,7 @@ class Feed extends FeedApi {
4461
4485
  }
4462
4486
  handleBookmarkUpdated(event) {
4463
4487
  const currentActivities = this.currentState.activities;
4464
- const { connectedUser } = this.client.state.getLatestValue();
4488
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4465
4489
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4466
4490
  const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
4467
4491
  if (result.changed) {
@@ -5016,7 +5040,8 @@ class StreamPoll {
5016
5040
  if (!isPollVoteCastedEvent(event))
5017
5041
  return;
5018
5042
  const currentState = this.data;
5019
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5043
+ const isOwnVote = event.poll_vote.user_id ===
5044
+ this.client.state.getLatestValue().connected_user?.id;
5020
5045
  let latestAnswers = [...currentState.latest_answers];
5021
5046
  let ownAnswer = currentState.own_answer;
5022
5047
  const ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5040,7 +5065,7 @@ class StreamPoll {
5040
5065
  else {
5041
5066
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5042
5067
  }
5043
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5068
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5044
5069
  this.state.partialNext({
5045
5070
  answers_count,
5046
5071
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5061,7 +5086,8 @@ class StreamPoll {
5061
5086
  if (!isPollVoteChangedEvent(event))
5062
5087
  return;
5063
5088
  const currentState = this.data;
5064
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5089
+ const isOwnVote = event.poll_vote.user_id ===
5090
+ this.client.state.getLatestValue().connected_user?.id;
5065
5091
  let latestAnswers = [...currentState.latest_answers];
5066
5092
  let ownAnswer = currentState.own_answer;
5067
5093
  let ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5108,7 +5134,7 @@ class StreamPoll {
5108
5134
  else {
5109
5135
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5110
5136
  }
5111
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5137
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5112
5138
  this.state.partialNext({
5113
5139
  answers_count,
5114
5140
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5128,7 +5154,8 @@ class StreamPoll {
5128
5154
  if (!isPollVoteRemovedEvent(event))
5129
5155
  return;
5130
5156
  const currentState = this.data;
5131
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5157
+ const isOwnVote = event.poll_vote.user_id ===
5158
+ this.client.state.getLatestValue().connected_user?.id;
5132
5159
  let latestAnswers = [...currentState.latest_answers];
5133
5160
  let ownAnswer = currentState.own_answer;
5134
5161
  const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
@@ -5146,7 +5173,7 @@ class StreamPoll {
5146
5173
  delete ownVotesByOptionId[event.poll_vote.option_id];
5147
5174
  }
5148
5175
  }
5149
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5176
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5150
5177
  this.state.partialNext({
5151
5178
  answers_count,
5152
5179
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5204,7 +5231,7 @@ class FeedsClient extends FeedsApi {
5204
5231
  this.healthyConnectionChangedEventCount = 0;
5205
5232
  this.pollFromState = (id) => this.polls_by_id.get(id);
5206
5233
  this.connectUser = async (user, tokenProvider) => {
5207
- if (this.state.getLatestValue().connectedUser !== undefined ||
5234
+ if (this.state.getLatestValue().connected_user !== undefined ||
5208
5235
  this.wsConnection) {
5209
5236
  throw new Error(`Can't connect a new user, call "disconnectUser" first`);
5210
5237
  }
@@ -5218,8 +5245,8 @@ class FeedsClient extends FeedsApi {
5218
5245
  this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
5219
5246
  const connectedEvent = await this.wsConnection.connect();
5220
5247
  this.state.partialNext({
5221
- connectedUser: connectedEvent?.me,
5222
- isWsConnectionHealthy: this.wsConnection.isHealthy,
5248
+ connected_user: connectedEvent?.me,
5249
+ is_ws_connection_healthy: !!this.wsConnection?.isHealthy,
5223
5250
  });
5224
5251
  }
5225
5252
  catch (err) {
@@ -5278,7 +5305,10 @@ class FeedsClient extends FeedsApi {
5278
5305
  removeConnectionEventListeners(this.updateNetworkConnectionStatus);
5279
5306
  this.connectionIdManager.reset();
5280
5307
  this.tokenManager.reset();
5281
- this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
5308
+ this.state.partialNext({
5309
+ connected_user: undefined,
5310
+ is_ws_connection_healthy: false,
5311
+ });
5282
5312
  };
5283
5313
  this.on = this.eventDispatcher.on;
5284
5314
  this.off = this.eventDispatcher.off;
@@ -5304,8 +5334,8 @@ class FeedsClient extends FeedsApi {
5304
5334
  }
5305
5335
  };
5306
5336
  this.state = new StateStore({
5307
- connectedUser: undefined,
5308
- isWsConnectionHealthy: false,
5337
+ connected_user: undefined,
5338
+ is_ws_connection_healthy: false,
5309
5339
  });
5310
5340
  this.moderation = new ModerationClient(apiClient);
5311
5341
  this.tokenManager = tokenManager;
@@ -5317,7 +5347,7 @@ class FeedsClient extends FeedsApi {
5317
5347
  switch (event.type) {
5318
5348
  case 'connection.changed': {
5319
5349
  const { online } = event;
5320
- this.state.partialNext({ isWsConnectionHealthy: online });
5350
+ this.state.partialNext({ is_ws_connection_healthy: online });
5321
5351
  if (online) {
5322
5352
  this.healthyConnectionChangedEventCount++;
5323
5353
  // we skip the first event as we could potentially be querying twice
@@ -5501,11 +5531,11 @@ const useFeedsClient = () => {
5501
5531
  */
5502
5532
  const useClientConnectedUser = () => {
5503
5533
  const client = useFeedsClient();
5504
- const { user } = useStateStore(client?.state, selector$5) ?? {};
5534
+ const { user } = useStateStore(client?.state, selector$7) ?? {};
5505
5535
  return user;
5506
5536
  };
5507
- const selector$5 = (nextState) => ({
5508
- user: nextState.connectedUser,
5537
+ const selector$7 = (nextState) => ({
5538
+ user: nextState.connected_user,
5509
5539
  });
5510
5540
 
5511
5541
  /**
@@ -5513,11 +5543,11 @@ const selector$5 = (nextState) => ({
5513
5543
  */
5514
5544
  const useWsConnectionState = () => {
5515
5545
  const client = useFeedsClient();
5516
- const { isHealthy } = useStateStore(client?.state, selector$4) ?? {};
5517
- return { isHealthy };
5546
+ const { is_healthy } = useStateStore(client?.state, selector$6) ?? {};
5547
+ return { is_healthy };
5518
5548
  };
5519
- const selector$4 = (nextState) => ({
5520
- isHealthy: nextState.isWsConnectionHealthy,
5549
+ const selector$6 = (nextState) => ({
5550
+ is_healthy: nextState.is_ws_connection_healthy,
5521
5551
  });
5522
5552
 
5523
5553
  const StreamFeedContext = createContext(undefined);
@@ -5566,19 +5596,19 @@ const useStableCallback = (callback) => {
5566
5596
  const useFeedActivities = (feedFromProps) => {
5567
5597
  const feedFromContext = useFeedContext();
5568
5598
  const feed = feedFromProps ?? feedFromContext;
5569
- const data = useStateStore(feed?.state, selector$3);
5599
+ const data = useStateStore(feed?.state, selector$5);
5570
5600
  const loadNextPage = useStableCallback(async () => {
5571
- if (!feed || !data?.hasNextPage || data?.isLoading) {
5601
+ if (!feed || !data?.has_next_page || data?.is_loading) {
5572
5602
  return;
5573
5603
  }
5574
5604
  await feed.getNextPage();
5575
5605
  });
5576
5606
  return useMemo(() => ({ ...data, loadNextPage }), [data, loadNextPage]);
5577
5607
  };
5578
- const selector$3 = (nextState) => ({
5579
- isLoading: nextState.is_loading_activities,
5580
- hasNextPage: typeof nextState.next !== 'undefined',
5581
- activities: nextState.activities ?? [],
5608
+ const selector$5 = ({ is_loading_activities, next, activities = [] }) => ({
5609
+ is_loading: is_loading_activities,
5610
+ has_next_page: typeof next !== 'undefined',
5611
+ activities,
5582
5612
  });
5583
5613
 
5584
5614
  function useComments({ feed: feedFromProps, parent, }) {
@@ -5607,8 +5637,8 @@ function useComments({ feed: feedFromProps, parent, }) {
5607
5637
  }
5608
5638
  return {
5609
5639
  ...data,
5610
- hasNextPage: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
5611
- isLoadingNextPage: data?.comments_pagination?.loading_next_page ?? false,
5640
+ has_next_page: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
5641
+ is_loading_next_page: data?.comments_pagination?.loading_next_page ?? false,
5612
5642
  loadNextPage,
5613
5643
  };
5614
5644
  }, [data, loadNextPage]);
@@ -5648,48 +5678,48 @@ const FeedOwnCapability = {
5648
5678
  };
5649
5679
 
5650
5680
  const stableEmptyArray = [];
5651
- const selector$2 = (currentState) => ({
5681
+ const selector$4 = (currentState) => ({
5652
5682
  oc: currentState.own_capabilities ?? stableEmptyArray,
5653
5683
  });
5654
5684
  const useOwnCapabilities = (feedFromProps) => {
5655
5685
  const feedFromContext = useFeedContext();
5656
5686
  const feed = feedFromProps ?? feedFromContext;
5657
- const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$2) ?? {};
5687
+ const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$4) ?? {};
5658
5688
  return useMemo(() => ({
5659
- canAddActivity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
5660
- canAddActivityReaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
5661
- canAddComment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
5662
- canAddCommentReaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
5663
- canBookmarkActivity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
5664
- canCreateFeed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
5665
- canDeleteBookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
5666
- canDeleteComment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
5667
- canDeleteFeed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
5668
- canEditBookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
5669
- canFollow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
5670
- canRemoveActivity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
5671
- canRemoveActivityReaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
5672
- canRemoveCommentReaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
5673
- canUnfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
5674
- canUpdateFeed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
5675
- canInviteFeed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
5676
- canJoinFeed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
5677
- canLeaveFeed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
5678
- canManageFeedGroup: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
5679
- canMarkActivity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
5680
- canPinActivity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
5681
- canQueryFeedMembers: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
5682
- canQueryFollows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
5683
- canReadActivities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
5684
- canReadFeed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
5685
- canUpdateActivity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
5686
- canUpdateComment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
5687
- canUpdateFeedFollowers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
5688
- canUpdateFeedMembers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
5689
+ can_add_activity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
5690
+ can_add_activity_reaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
5691
+ can_add_comment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
5692
+ can_add_comment_reaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
5693
+ can_bookmark_activity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
5694
+ can_create_feed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
5695
+ can_delete_bookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
5696
+ can_delete_comment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
5697
+ can_delete_feed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
5698
+ can_edit_bookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
5699
+ can_follow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
5700
+ can_remove_activity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
5701
+ can_remove_activity_reaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
5702
+ can_remove_comment_reaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
5703
+ can_unfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
5704
+ can_update_feed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
5705
+ can_invite_feed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
5706
+ can_join_feed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
5707
+ can_leave_feed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
5708
+ can_manage_feed_group: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
5709
+ can_mark_activity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
5710
+ can_pin_activity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
5711
+ can_query_feed_members: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
5712
+ can_query_follows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
5713
+ can_read_activities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
5714
+ can_read_feed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
5715
+ can_update_activity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
5716
+ can_update_comment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
5717
+ can_update_feed_followers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
5718
+ can_update_feed_members: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
5689
5719
  }), [oc]);
5690
5720
  };
5691
5721
 
5692
- const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
5722
+ const selector$3 = ({ follower_count, followers, followers_pagination, }) => ({
5693
5723
  follower_count,
5694
5724
  followers,
5695
5725
  followers_pagination,
@@ -5697,7 +5727,7 @@ const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
5697
5727
  function useFollowers(feedFromProps) {
5698
5728
  const feedFromContext = useFeedContext();
5699
5729
  const feed = feedFromProps ?? feedFromContext;
5700
- const data = useStateStore(feed?.state, selector$1);
5730
+ const data = useStateStore(feed?.state, selector$3);
5701
5731
  const loadNextPage = useCallback((...options) => feed?.loadNextPageFollowers(...options), [feed]);
5702
5732
  return useMemo(() => {
5703
5733
  if (!data) {
@@ -5705,14 +5735,14 @@ function useFollowers(feedFromProps) {
5705
5735
  }
5706
5736
  return {
5707
5737
  ...data,
5708
- isLoadingNextPage: data.followers_pagination?.loading_next_page ?? false,
5709
- hasNextPage: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
5738
+ is_loading_next_page: data.followers_pagination?.loading_next_page ?? false,
5739
+ has_next_page: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
5710
5740
  loadNextPage,
5711
5741
  };
5712
5742
  }, [data, loadNextPage]);
5713
5743
  }
5714
5744
 
5715
- const selector = ({ following_count, following, following_pagination, }) => ({
5745
+ const selector$2 = ({ following_count, following, following_pagination, }) => ({
5716
5746
  following_count,
5717
5747
  following,
5718
5748
  following_pagination,
@@ -5720,7 +5750,7 @@ const selector = ({ following_count, following, following_pagination, }) => ({
5720
5750
  function useFollowing(feedFromProps) {
5721
5751
  const feedFromContext = useFeedContext();
5722
5752
  const feed = feedFromProps ?? feedFromContext;
5723
- const data = useStateStore(feed?.state, selector);
5753
+ const data = useStateStore(feed?.state, selector$2);
5724
5754
  const loadNextPage = useCallback((...options) => feed?.loadNextPageFollowing(...options), [feed]);
5725
5755
  return useMemo(() => {
5726
5756
  if (!data) {
@@ -5728,13 +5758,43 @@ function useFollowing(feedFromProps) {
5728
5758
  }
5729
5759
  return {
5730
5760
  ...data,
5731
- isLoadingNextPage: data.following_pagination?.loading_next_page ?? false,
5732
- hasNextPage: checkHasAnotherPage(data.following, data.following_pagination?.next),
5761
+ is_loading_next_page: data.following_pagination?.loading_next_page ?? false,
5762
+ has_next_page: checkHasAnotherPage(data.following, data.following_pagination?.next),
5733
5763
  loadNextPage,
5734
5764
  };
5735
5765
  }, [data, loadNextPage]);
5736
5766
  }
5737
5767
 
5768
+ /**
5769
+ * A React hook that returns a reactive object containing some often used
5770
+ * metadata for a feed.
5771
+ */
5772
+ const useFeedMetadata = (feedFromProps) => {
5773
+ const feedFromContext = useFeedContext();
5774
+ const feed = feedFromProps ?? feedFromContext;
5775
+ return useStateStore(feed?.state, selector$1);
5776
+ };
5777
+ const selector$1 = ({ follower_count = 0, following_count = 0, created_by, created_at, updated_at, }) => ({
5778
+ created_by,
5779
+ follower_count,
5780
+ following_count,
5781
+ created_at,
5782
+ updated_at,
5783
+ });
5784
+
5785
+ /**
5786
+ * A React hook that returns a reactive array of feeds that the current user
5787
+ * owns and are following the respective feed that we are observing.
5788
+ */
5789
+ const useOwnFollows = (feedFromProps) => {
5790
+ const feedFromContext = useFeedContext();
5791
+ const feed = feedFromProps ?? feedFromContext;
5792
+ return useStateStore(feed?.state, selector);
5793
+ };
5794
+ const selector = ({ own_follows }) => ({
5795
+ own_follows,
5796
+ });
5797
+
5738
5798
  /**
5739
5799
  * A utility hook that takes in an entity and a reaction type, and creates reaction actions
5740
5800
  * that can then be used on the UI. The entity can be either an ActivityResponse or a CommentResponse
@@ -5781,5 +5841,5 @@ const StreamFeed = ({ feed, children }) => {
5781
5841
  };
5782
5842
  StreamFeed.displayName = 'StreamFeed';
5783
5843
 
5784
- export { StreamFeed, StreamFeedContext, StreamFeeds, StreamFeedsContext, useClientConnectedUser, useComments, useCreateFeedsClient, useFeedActivities, useFeedContext, useFeedsClient, useFollowers, useFollowing, useOwnCapabilities, useReactionActions, useStateStore, useWsConnectionState };
5844
+ export { StreamFeed, StreamFeedContext, StreamFeeds, StreamFeedsContext, useClientConnectedUser, useComments, useCreateFeedsClient, useFeedActivities, useFeedContext, useFeedMetadata, useFeedsClient, useFollowers, useFollowing, useOwnCapabilities, useOwnFollows, useReactionActions, useStateStore, useWsConnectionState };
5785
5845
  //# sourceMappingURL=index-react-bindings.node.js.map