@stream-io/feeds-client 0.1.5 → 0.1.6

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 (40) hide show
  1. package/@react-bindings/hooks/feed-state-hooks/index.ts +2 -0
  2. package/CHANGELOG.md +15 -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 +128 -85
  13. package/dist/index-react-bindings.browser.cjs.map +1 -1
  14. package/dist/index-react-bindings.browser.js +127 -86
  15. package/dist/index-react-bindings.browser.js.map +1 -1
  16. package/dist/index-react-bindings.node.cjs +128 -85
  17. package/dist/index-react-bindings.node.cjs.map +1 -1
  18. package/dist/index-react-bindings.node.js +127 -86
  19. package/dist/index-react-bindings.node.js.map +1 -1
  20. package/dist/index.browser.cjs +48 -37
  21. package/dist/index.browser.cjs.map +1 -1
  22. package/dist/index.browser.js +48 -37
  23. package/dist/index.browser.js.map +1 -1
  24. package/dist/index.node.cjs +48 -37
  25. package/dist/index.node.cjs.map +1 -1
  26. package/dist/index.node.js +48 -37
  27. package/dist/index.node.js.map +1 -1
  28. package/dist/src/FeedsClient.d.ts +2 -2
  29. package/dist/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +6 -3
  31. package/src/Feed.ts +17 -11
  32. package/src/FeedsClient.ts +15 -10
  33. package/src/common/ActivitySearchSource.ts +5 -5
  34. package/src/common/ApiClient.ts +1 -1
  35. package/src/common/FeedSearchSource.ts +1 -1
  36. package/src/common/Poll.ts +35 -10
  37. package/src/common/TokenManager.ts +2 -3
  38. package/src/common/UserSearchSource.ts +1 -1
  39. package/src/state-updates/bookmark-utils.test.ts +134 -8
  40. package/src/state-updates/bookmark-utils.ts +17 -7
@@ -2783,7 +2783,7 @@ class TokenManager {
2783
2783
  }
2784
2784
  catch (e) {
2785
2785
  const numberOfFailures = ++previousFailuresCount;
2786
- await sleep(retryInterval(numberOfFailures));
2786
+ await sleep(1000);
2787
2787
  if (numberOfFailures === 3) {
2788
2788
  this.loadTokenPromise = null;
2789
2789
  return reject(new Error(`Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`, { cause: e }));
@@ -3631,7 +3631,7 @@ class ApiClient {
3631
3631
  rate_limit: getRateLimitFromResponseHeader(response_headers),
3632
3632
  };
3633
3633
  };
3634
- this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
3634
+ this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
3635
3635
  this.timeout = options?.timeout ?? 3000;
3636
3636
  this.axiosInstance = axios.create({
3637
3637
  baseURL: this.baseUrl,
@@ -3925,6 +3925,13 @@ const removeReactionFromActivities = (event, activities, isCurrentUser) => {
3925
3925
  return updateActivityInActivities$1(updatedActivity, activities);
3926
3926
  };
3927
3927
 
3928
+ // Helper function to check if two bookmarks are the same
3929
+ // A bookmark is identified by activity_id + folder_id + user_id
3930
+ const isSameBookmark = (bookmark1, bookmark2) => {
3931
+ return (bookmark1.user.id === bookmark2.user.id &&
3932
+ bookmark1.activity.id === bookmark2.activity.id &&
3933
+ bookmark1.folder?.id === bookmark2.folder?.id);
3934
+ };
3928
3935
  const updateActivityInActivities = (updatedActivity, activities) => {
3929
3936
  const index = activities.findIndex((a) => a.id === updatedActivity.id);
3930
3937
  if (index !== -1) {
@@ -3951,8 +3958,7 @@ const addBookmarkToActivity = (event, activity, isCurrentUser) => {
3951
3958
  const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
3952
3959
  // Update own_bookmarks if the bookmark is from the current user
3953
3960
  const ownBookmarks = isCurrentUser
3954
- ? (activity.own_bookmarks || []).filter((bookmark) => bookmark.user.id !== event.bookmark.user.id ||
3955
- bookmark.activity.id !== event.bookmark.activity.id)
3961
+ ? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
3956
3962
  : activity.own_bookmarks;
3957
3963
  return {
3958
3964
  ...activity,
@@ -3964,8 +3970,7 @@ const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
3964
3970
  // Update own_bookmarks if the bookmark is from the current user
3965
3971
  let ownBookmarks = activity.own_bookmarks || [];
3966
3972
  if (isCurrentUser) {
3967
- const bookmarkIndex = ownBookmarks.findIndex((bookmark) => bookmark.user.id === event.bookmark.user.id &&
3968
- bookmark.activity.id === event.bookmark.activity.id);
3973
+ const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
3969
3974
  if (bookmarkIndex !== -1) {
3970
3975
  ownBookmarks = [...ownBookmarks];
3971
3976
  ownBookmarks[bookmarkIndex] = event.bookmark;
@@ -4047,7 +4052,7 @@ class Feed extends FeedApi {
4047
4052
  },
4048
4053
  'feeds.activity.reaction.added': (event) => {
4049
4054
  const currentActivities = this.currentState.activities;
4050
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4055
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4051
4056
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4052
4057
  const result = addReactionToActivities(event, currentActivities, isCurrentUser);
4053
4058
  if (result.changed) {
@@ -4056,7 +4061,7 @@ class Feed extends FeedApi {
4056
4061
  },
4057
4062
  'feeds.activity.reaction.deleted': (event) => {
4058
4063
  const currentActivities = this.currentState.activities;
4059
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4064
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4060
4065
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4061
4066
  const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
4062
4067
  if (result.changed) {
@@ -4195,7 +4200,7 @@ class Feed extends FeedApi {
4195
4200
  // someone followed this feed
4196
4201
  event.follow.target_feed.fid === this.fid) {
4197
4202
  const source = event.follow.source_feed;
4198
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4203
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4199
4204
  this.state.next((currentState) => {
4200
4205
  const newState = { ...currentState, ...event.follow.target_feed };
4201
4206
  if (source.created_by.id === connectedUser?.id) {
@@ -4228,7 +4233,7 @@ class Feed extends FeedApi {
4228
4233
  // someone unfollowed this feed
4229
4234
  event.follow.target_feed.fid === this.fid) {
4230
4235
  const source = event.follow.source_feed;
4231
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4236
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4232
4237
  this.state.next((currentState) => {
4233
4238
  const newState = { ...currentState, ...event.follow.target_feed };
4234
4239
  if (source.created_by.id === connectedUser?.id) {
@@ -4244,7 +4249,7 @@ class Feed extends FeedApi {
4244
4249
  'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
4245
4250
  'feeds.comment.reaction.updated': Feed.noop,
4246
4251
  'feeds.feed_member.added': (event) => {
4247
- const { connectedUser } = this.client.state.getLatestValue();
4252
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4248
4253
  this.state.next((currentState) => {
4249
4254
  let newState;
4250
4255
  if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
@@ -4265,7 +4270,7 @@ class Feed extends FeedApi {
4265
4270
  });
4266
4271
  },
4267
4272
  'feeds.feed_member.removed': (event) => {
4268
- const { connectedUser } = this.client.state.getLatestValue();
4273
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4269
4274
  this.state.next((currentState) => {
4270
4275
  const newState = {
4271
4276
  ...currentState,
@@ -4278,7 +4283,7 @@ class Feed extends FeedApi {
4278
4283
  });
4279
4284
  },
4280
4285
  'feeds.feed_member.updated': (event) => {
4281
- const { connectedUser } = this.client.state.getLatestValue();
4286
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4282
4287
  this.state.next((currentState) => {
4283
4288
  const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
4284
4289
  let newState;
@@ -4343,7 +4348,7 @@ class Feed extends FeedApi {
4343
4348
  }
4344
4349
  handleCommentReactionEvent(event) {
4345
4350
  const { comment, reaction } = event;
4346
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4351
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4347
4352
  this.state.next((currentState) => {
4348
4353
  const forId = comment.parent_id ?? comment.object_id;
4349
4354
  const entityState = currentState.comments_by_entity_id[forId];
@@ -4445,7 +4450,7 @@ class Feed extends FeedApi {
4445
4450
  }
4446
4451
  handleBookmarkAdded(event) {
4447
4452
  const currentActivities = this.currentState.activities;
4448
- const { connectedUser } = this.client.state.getLatestValue();
4453
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4449
4454
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4450
4455
  const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
4451
4456
  if (result.changed) {
@@ -4454,7 +4459,7 @@ class Feed extends FeedApi {
4454
4459
  }
4455
4460
  handleBookmarkDeleted(event) {
4456
4461
  const currentActivities = this.currentState.activities;
4457
- const { connectedUser } = this.client.state.getLatestValue();
4462
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4458
4463
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4459
4464
  const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
4460
4465
  if (result.changed) {
@@ -4463,7 +4468,7 @@ class Feed extends FeedApi {
4463
4468
  }
4464
4469
  handleBookmarkUpdated(event) {
4465
4470
  const currentActivities = this.currentState.activities;
4466
- const { connectedUser } = this.client.state.getLatestValue();
4471
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4467
4472
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4468
4473
  const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
4469
4474
  if (result.changed) {
@@ -5018,7 +5023,8 @@ class StreamPoll {
5018
5023
  if (!isPollVoteCastedEvent(event))
5019
5024
  return;
5020
5025
  const currentState = this.data;
5021
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5026
+ const isOwnVote = event.poll_vote.user_id ===
5027
+ this.client.state.getLatestValue().connected_user?.id;
5022
5028
  let latestAnswers = [...currentState.latest_answers];
5023
5029
  let ownAnswer = currentState.own_answer;
5024
5030
  const ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5042,7 +5048,7 @@ class StreamPoll {
5042
5048
  else {
5043
5049
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5044
5050
  }
5045
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5051
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5046
5052
  this.state.partialNext({
5047
5053
  answers_count,
5048
5054
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5063,7 +5069,8 @@ class StreamPoll {
5063
5069
  if (!isPollVoteChangedEvent(event))
5064
5070
  return;
5065
5071
  const currentState = this.data;
5066
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5072
+ const isOwnVote = event.poll_vote.user_id ===
5073
+ this.client.state.getLatestValue().connected_user?.id;
5067
5074
  let latestAnswers = [...currentState.latest_answers];
5068
5075
  let ownAnswer = currentState.own_answer;
5069
5076
  let ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5110,7 +5117,7 @@ class StreamPoll {
5110
5117
  else {
5111
5118
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5112
5119
  }
5113
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5120
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5114
5121
  this.state.partialNext({
5115
5122
  answers_count,
5116
5123
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5130,7 +5137,8 @@ class StreamPoll {
5130
5137
  if (!isPollVoteRemovedEvent(event))
5131
5138
  return;
5132
5139
  const currentState = this.data;
5133
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5140
+ const isOwnVote = event.poll_vote.user_id ===
5141
+ this.client.state.getLatestValue().connected_user?.id;
5134
5142
  let latestAnswers = [...currentState.latest_answers];
5135
5143
  let ownAnswer = currentState.own_answer;
5136
5144
  const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
@@ -5148,7 +5156,7 @@ class StreamPoll {
5148
5156
  delete ownVotesByOptionId[event.poll_vote.option_id];
5149
5157
  }
5150
5158
  }
5151
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5159
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5152
5160
  this.state.partialNext({
5153
5161
  answers_count,
5154
5162
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5206,7 +5214,7 @@ class FeedsClient extends FeedsApi {
5206
5214
  this.healthyConnectionChangedEventCount = 0;
5207
5215
  this.pollFromState = (id) => this.polls_by_id.get(id);
5208
5216
  this.connectUser = async (user, tokenProvider) => {
5209
- if (this.state.getLatestValue().connectedUser !== undefined ||
5217
+ if (this.state.getLatestValue().connected_user !== undefined ||
5210
5218
  this.wsConnection) {
5211
5219
  throw new Error(`Can't connect a new user, call "disconnectUser" first`);
5212
5220
  }
@@ -5220,8 +5228,8 @@ class FeedsClient extends FeedsApi {
5220
5228
  this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
5221
5229
  const connectedEvent = await this.wsConnection.connect();
5222
5230
  this.state.partialNext({
5223
- connectedUser: connectedEvent?.me,
5224
- isWsConnectionHealthy: this.wsConnection.isHealthy,
5231
+ connected_user: connectedEvent?.me,
5232
+ is_ws_connection_healthy: !!this.wsConnection?.isHealthy,
5225
5233
  });
5226
5234
  }
5227
5235
  catch (err) {
@@ -5280,7 +5288,10 @@ class FeedsClient extends FeedsApi {
5280
5288
  removeConnectionEventListeners(this.updateNetworkConnectionStatus);
5281
5289
  this.connectionIdManager.reset();
5282
5290
  this.tokenManager.reset();
5283
- this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
5291
+ this.state.partialNext({
5292
+ connected_user: undefined,
5293
+ is_ws_connection_healthy: false,
5294
+ });
5284
5295
  };
5285
5296
  this.on = this.eventDispatcher.on;
5286
5297
  this.off = this.eventDispatcher.off;
@@ -5306,8 +5317,8 @@ class FeedsClient extends FeedsApi {
5306
5317
  }
5307
5318
  };
5308
5319
  this.state = new StateStore({
5309
- connectedUser: undefined,
5310
- isWsConnectionHealthy: false,
5320
+ connected_user: undefined,
5321
+ is_ws_connection_healthy: false,
5311
5322
  });
5312
5323
  this.moderation = new ModerationClient(apiClient);
5313
5324
  this.tokenManager = tokenManager;
@@ -5319,7 +5330,7 @@ class FeedsClient extends FeedsApi {
5319
5330
  switch (event.type) {
5320
5331
  case 'connection.changed': {
5321
5332
  const { online } = event;
5322
- this.state.partialNext({ isWsConnectionHealthy: online });
5333
+ this.state.partialNext({ is_ws_connection_healthy: online });
5323
5334
  if (online) {
5324
5335
  this.healthyConnectionChangedEventCount++;
5325
5336
  // we skip the first event as we could potentially be querying twice
@@ -5503,11 +5514,11 @@ const useFeedsClient = () => {
5503
5514
  */
5504
5515
  const useClientConnectedUser = () => {
5505
5516
  const client = useFeedsClient();
5506
- const { user } = useStateStore(client?.state, selector$5) ?? {};
5517
+ const { user } = useStateStore(client?.state, selector$7) ?? {};
5507
5518
  return user;
5508
5519
  };
5509
- const selector$5 = (nextState) => ({
5510
- user: nextState.connectedUser,
5520
+ const selector$7 = (nextState) => ({
5521
+ user: nextState.connected_user,
5511
5522
  });
5512
5523
 
5513
5524
  /**
@@ -5515,11 +5526,11 @@ const selector$5 = (nextState) => ({
5515
5526
  */
5516
5527
  const useWsConnectionState = () => {
5517
5528
  const client = useFeedsClient();
5518
- const { isHealthy } = useStateStore(client?.state, selector$4) ?? {};
5519
- return { isHealthy };
5529
+ const { is_healthy } = useStateStore(client?.state, selector$6) ?? {};
5530
+ return { is_healthy };
5520
5531
  };
5521
- const selector$4 = (nextState) => ({
5522
- isHealthy: nextState.isWsConnectionHealthy,
5532
+ const selector$6 = (nextState) => ({
5533
+ is_healthy: nextState.is_ws_connection_healthy,
5523
5534
  });
5524
5535
 
5525
5536
  const StreamFeedContext = react.createContext(undefined);
@@ -5568,19 +5579,19 @@ const useStableCallback = (callback) => {
5568
5579
  const useFeedActivities = (feedFromProps) => {
5569
5580
  const feedFromContext = useFeedContext();
5570
5581
  const feed = feedFromProps ?? feedFromContext;
5571
- const data = useStateStore(feed?.state, selector$3);
5582
+ const data = useStateStore(feed?.state, selector$5);
5572
5583
  const loadNextPage = useStableCallback(async () => {
5573
- if (!feed || !data?.hasNextPage || data?.isLoading) {
5584
+ if (!feed || !data?.has_next_page || data?.is_loading) {
5574
5585
  return;
5575
5586
  }
5576
5587
  await feed.getNextPage();
5577
5588
  });
5578
5589
  return react.useMemo(() => ({ ...data, loadNextPage }), [data, loadNextPage]);
5579
5590
  };
5580
- const selector$3 = (nextState) => ({
5581
- isLoading: nextState.is_loading_activities,
5582
- hasNextPage: typeof nextState.next !== 'undefined',
5583
- activities: nextState.activities ?? [],
5591
+ const selector$5 = ({ is_loading_activities, next, activities = [] }) => ({
5592
+ is_loading: is_loading_activities,
5593
+ has_next_page: typeof next !== 'undefined',
5594
+ activities,
5584
5595
  });
5585
5596
 
5586
5597
  function useComments({ feed: feedFromProps, parent, }) {
@@ -5609,8 +5620,8 @@ function useComments({ feed: feedFromProps, parent, }) {
5609
5620
  }
5610
5621
  return {
5611
5622
  ...data,
5612
- hasNextPage: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
5613
- isLoadingNextPage: data?.comments_pagination?.loading_next_page ?? false,
5623
+ has_next_page: checkHasAnotherPage(data.comments, data.comments_pagination?.next),
5624
+ is_loading_next_page: data?.comments_pagination?.loading_next_page ?? false,
5614
5625
  loadNextPage,
5615
5626
  };
5616
5627
  }, [data, loadNextPage]);
@@ -5650,48 +5661,48 @@ const FeedOwnCapability = {
5650
5661
  };
5651
5662
 
5652
5663
  const stableEmptyArray = [];
5653
- const selector$2 = (currentState) => ({
5664
+ const selector$4 = (currentState) => ({
5654
5665
  oc: currentState.own_capabilities ?? stableEmptyArray,
5655
5666
  });
5656
5667
  const useOwnCapabilities = (feedFromProps) => {
5657
5668
  const feedFromContext = useFeedContext();
5658
5669
  const feed = feedFromProps ?? feedFromContext;
5659
- const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$2) ?? {};
5670
+ const { oc = stableEmptyArray } = useStateStore(feed?.state, selector$4) ?? {};
5660
5671
  return react.useMemo(() => ({
5661
- canAddActivity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
5662
- canAddActivityReaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
5663
- canAddComment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
5664
- canAddCommentReaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
5665
- canBookmarkActivity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
5666
- canCreateFeed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
5667
- canDeleteBookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
5668
- canDeleteComment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
5669
- canDeleteFeed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
5670
- canEditBookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
5671
- canFollow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
5672
- canRemoveActivity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
5673
- canRemoveActivityReaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
5674
- canRemoveCommentReaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
5675
- canUnfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
5676
- canUpdateFeed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
5677
- canInviteFeed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
5678
- canJoinFeed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
5679
- canLeaveFeed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
5680
- canManageFeedGroup: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
5681
- canMarkActivity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
5682
- canPinActivity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
5683
- canQueryFeedMembers: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
5684
- canQueryFollows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
5685
- canReadActivities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
5686
- canReadFeed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
5687
- canUpdateActivity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
5688
- canUpdateComment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
5689
- canUpdateFeedFollowers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
5690
- canUpdateFeedMembers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
5672
+ can_add_activity: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY) > -1,
5673
+ can_add_activity_reaction: oc.indexOf(FeedOwnCapability.ADD_ACTIVITY_REACTION) > -1,
5674
+ can_add_comment: oc.indexOf(FeedOwnCapability.ADD_COMMENT) > -1,
5675
+ can_add_comment_reaction: oc.indexOf(FeedOwnCapability.ADD_COMMENT_REACTION) > -1,
5676
+ can_bookmark_activity: oc.indexOf(FeedOwnCapability.BOOKMARK_ACTIVITY) > -1,
5677
+ can_create_feed: oc.indexOf(FeedOwnCapability.CREATE_FEED) > -1,
5678
+ can_delete_bookmark: oc.indexOf(FeedOwnCapability.DELETE_BOOKMARK) > -1,
5679
+ can_delete_comment: oc.indexOf(FeedOwnCapability.DELETE_COMMENT) > -1,
5680
+ can_delete_feed: oc.indexOf(FeedOwnCapability.DELETE_FEED) > -1,
5681
+ can_edit_bookmark: oc.indexOf(FeedOwnCapability.EDIT_BOOKMARK) > -1,
5682
+ can_follow: oc.indexOf(FeedOwnCapability.FOLLOW) > -1,
5683
+ can_remove_activity: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY) > -1,
5684
+ can_remove_activity_reaction: oc.indexOf(FeedOwnCapability.REMOVE_ACTIVITY_REACTION) > -1,
5685
+ can_remove_comment_reaction: oc.indexOf(FeedOwnCapability.REMOVE_COMMENT_REACTION) > -1,
5686
+ can_unfollow: oc.indexOf(FeedOwnCapability.UNFOLLOW) > -1,
5687
+ can_update_feed: oc.indexOf(FeedOwnCapability.UPDATE_FEED) > -1,
5688
+ can_invite_feed: oc.indexOf(FeedOwnCapability.INVITE_FEED) > -1,
5689
+ can_join_feed: oc.indexOf(FeedOwnCapability.JOIN_FEED) > -1,
5690
+ can_leave_feed: oc.indexOf(FeedOwnCapability.LEAVE_FEED) > -1,
5691
+ can_manage_feed_group: oc.indexOf(FeedOwnCapability.MANAGE_FEED_GROUP) > -1,
5692
+ can_mark_activity: oc.indexOf(FeedOwnCapability.MARK_ACTIVITY) > -1,
5693
+ can_pin_activity: oc.indexOf(FeedOwnCapability.PIN_ACTIVITY) > -1,
5694
+ can_query_feed_members: oc.indexOf(FeedOwnCapability.QUERY_FEED_MEMBERS) > -1,
5695
+ can_query_follows: oc.indexOf(FeedOwnCapability.QUERY_FOLLOWS) > -1,
5696
+ can_read_activities: oc.indexOf(FeedOwnCapability.READ_ACTIVITIES) > -1,
5697
+ can_read_feed: oc.indexOf(FeedOwnCapability.READ_FEED) > -1,
5698
+ can_update_activity: oc.indexOf(FeedOwnCapability.UPDATE_ACTIVITY) > -1,
5699
+ can_update_comment: oc.indexOf(FeedOwnCapability.UPDATE_COMMENT) > -1,
5700
+ can_update_feed_followers: oc.indexOf(FeedOwnCapability.UPDATE_FEED_FOLLOWERS) > -1,
5701
+ can_update_feed_members: oc.indexOf(FeedOwnCapability.UPDATE_FEED_MEMBERS) > -1,
5691
5702
  }), [oc]);
5692
5703
  };
5693
5704
 
5694
- const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
5705
+ const selector$3 = ({ follower_count, followers, followers_pagination, }) => ({
5695
5706
  follower_count,
5696
5707
  followers,
5697
5708
  followers_pagination,
@@ -5699,7 +5710,7 @@ const selector$1 = ({ follower_count, followers, followers_pagination, }) => ({
5699
5710
  function useFollowers(feedFromProps) {
5700
5711
  const feedFromContext = useFeedContext();
5701
5712
  const feed = feedFromProps ?? feedFromContext;
5702
- const data = useStateStore(feed?.state, selector$1);
5713
+ const data = useStateStore(feed?.state, selector$3);
5703
5714
  const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowers(...options), [feed]);
5704
5715
  return react.useMemo(() => {
5705
5716
  if (!data) {
@@ -5707,14 +5718,14 @@ function useFollowers(feedFromProps) {
5707
5718
  }
5708
5719
  return {
5709
5720
  ...data,
5710
- isLoadingNextPage: data.followers_pagination?.loading_next_page ?? false,
5711
- hasNextPage: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
5721
+ is_loading_next_page: data.followers_pagination?.loading_next_page ?? false,
5722
+ has_next_page: checkHasAnotherPage(data.followers, data.followers_pagination?.next),
5712
5723
  loadNextPage,
5713
5724
  };
5714
5725
  }, [data, loadNextPage]);
5715
5726
  }
5716
5727
 
5717
- const selector = ({ following_count, following, following_pagination, }) => ({
5728
+ const selector$2 = ({ following_count, following, following_pagination, }) => ({
5718
5729
  following_count,
5719
5730
  following,
5720
5731
  following_pagination,
@@ -5722,7 +5733,7 @@ const selector = ({ following_count, following, following_pagination, }) => ({
5722
5733
  function useFollowing(feedFromProps) {
5723
5734
  const feedFromContext = useFeedContext();
5724
5735
  const feed = feedFromProps ?? feedFromContext;
5725
- const data = useStateStore(feed?.state, selector);
5736
+ const data = useStateStore(feed?.state, selector$2);
5726
5737
  const loadNextPage = react.useCallback((...options) => feed?.loadNextPageFollowing(...options), [feed]);
5727
5738
  return react.useMemo(() => {
5728
5739
  if (!data) {
@@ -5730,13 +5741,43 @@ function useFollowing(feedFromProps) {
5730
5741
  }
5731
5742
  return {
5732
5743
  ...data,
5733
- isLoadingNextPage: data.following_pagination?.loading_next_page ?? false,
5734
- hasNextPage: checkHasAnotherPage(data.following, data.following_pagination?.next),
5744
+ is_loading_next_page: data.following_pagination?.loading_next_page ?? false,
5745
+ has_next_page: checkHasAnotherPage(data.following, data.following_pagination?.next),
5735
5746
  loadNextPage,
5736
5747
  };
5737
5748
  }, [data, loadNextPage]);
5738
5749
  }
5739
5750
 
5751
+ /**
5752
+ * A React hook that returns a reactive object containing some often used
5753
+ * metadata for a feed.
5754
+ */
5755
+ const useFeedMetadata = (feedFromProps) => {
5756
+ const feedFromContext = useFeedContext();
5757
+ const feed = feedFromProps ?? feedFromContext;
5758
+ return useStateStore(feed?.state, selector$1);
5759
+ };
5760
+ const selector$1 = ({ follower_count = 0, following_count = 0, created_by, created_at, updated_at, }) => ({
5761
+ created_by,
5762
+ follower_count,
5763
+ following_count,
5764
+ created_at,
5765
+ updated_at,
5766
+ });
5767
+
5768
+ /**
5769
+ * A React hook that returns a reactive array of feeds that the current user
5770
+ * owns and are following the respective feed that we are observing.
5771
+ */
5772
+ const useOwnFollows = (feedFromProps) => {
5773
+ const feedFromContext = useFeedContext();
5774
+ const feed = feedFromProps ?? feedFromContext;
5775
+ return useStateStore(feed?.state, selector);
5776
+ };
5777
+ const selector = ({ own_follows }) => ({
5778
+ own_follows,
5779
+ });
5780
+
5740
5781
  /**
5741
5782
  * A utility hook that takes in an entity and a reaction type, and creates reaction actions
5742
5783
  * that can then be used on the UI. The entity can be either an ActivityResponse or a CommentResponse
@@ -5792,10 +5833,12 @@ exports.useComments = useComments;
5792
5833
  exports.useCreateFeedsClient = useCreateFeedsClient;
5793
5834
  exports.useFeedActivities = useFeedActivities;
5794
5835
  exports.useFeedContext = useFeedContext;
5836
+ exports.useFeedMetadata = useFeedMetadata;
5795
5837
  exports.useFeedsClient = useFeedsClient;
5796
5838
  exports.useFollowers = useFollowers;
5797
5839
  exports.useFollowing = useFollowing;
5798
5840
  exports.useOwnCapabilities = useOwnCapabilities;
5841
+ exports.useOwnFollows = useOwnFollows;
5799
5842
  exports.useReactionActions = useReactionActions;
5800
5843
  exports.useStateStore = useStateStore;
5801
5844
  exports.useWsConnectionState = useWsConnectionState;