@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
@@ -1971,6 +1971,18 @@ class FeedsApi {
1971
1971
  decoders.RejectFeedMemberInviteResponse?.(response.body);
1972
1972
  return { ...response.body, metadata: response.metadata };
1973
1973
  }
1974
+ async stopWatchingFeed(request) {
1975
+ const queryParams = {
1976
+ connection_id: request?.connection_id,
1977
+ };
1978
+ const pathParams = {
1979
+ feed_group_id: request?.feed_group_id,
1980
+ feed_id: request?.feed_id,
1981
+ };
1982
+ const response = await this.apiClient.sendRequest('DELETE', '/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}/watch', pathParams, queryParams);
1983
+ decoders.Response?.(response.body);
1984
+ return { ...response.body, metadata: response.metadata };
1985
+ }
1974
1986
  async getFollowSuggestions(request) {
1975
1987
  const queryParams = {
1976
1988
  limit: request?.limit,
@@ -2789,7 +2801,7 @@ class TokenManager {
2789
2801
  }
2790
2802
  catch (e) {
2791
2803
  const numberOfFailures = ++previousFailuresCount;
2792
- await sleep(retryInterval(numberOfFailures));
2804
+ await sleep(1000);
2793
2805
  if (numberOfFailures === 3) {
2794
2806
  this.loadTokenPromise = null;
2795
2807
  return reject(new Error(`Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`, { cause: e }));
@@ -3637,7 +3649,7 @@ class ApiClient {
3637
3649
  rate_limit: getRateLimitFromResponseHeader(response_headers),
3638
3650
  };
3639
3651
  };
3640
- this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
3652
+ this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
3641
3653
  this.timeout = options?.timeout ?? 3000;
3642
3654
  this.axiosInstance = axios.create({
3643
3655
  baseURL: this.baseUrl,
@@ -3801,6 +3813,13 @@ class FeedApi {
3801
3813
  ...request,
3802
3814
  });
3803
3815
  }
3816
+ stopWatching(request) {
3817
+ return this.feedsApi.stopWatchingFeed({
3818
+ feed_id: this.id,
3819
+ feed_group_id: this.group,
3820
+ ...request,
3821
+ });
3822
+ }
3804
3823
  }
3805
3824
 
3806
3825
  const addActivitiesToState = (newActivities, activities, position) => {
@@ -3931,6 +3950,13 @@ const removeReactionFromActivities = (event, activities, isCurrentUser) => {
3931
3950
  return updateActivityInActivities$1(updatedActivity, activities);
3932
3951
  };
3933
3952
 
3953
+ // Helper function to check if two bookmarks are the same
3954
+ // A bookmark is identified by activity_id + folder_id + user_id
3955
+ const isSameBookmark = (bookmark1, bookmark2) => {
3956
+ return (bookmark1.user.id === bookmark2.user.id &&
3957
+ bookmark1.activity.id === bookmark2.activity.id &&
3958
+ bookmark1.folder?.id === bookmark2.folder?.id);
3959
+ };
3934
3960
  const updateActivityInActivities = (updatedActivity, activities) => {
3935
3961
  const index = activities.findIndex((a) => a.id === updatedActivity.id);
3936
3962
  if (index !== -1) {
@@ -3957,8 +3983,7 @@ const addBookmarkToActivity = (event, activity, isCurrentUser) => {
3957
3983
  const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
3958
3984
  // Update own_bookmarks if the bookmark is from the current user
3959
3985
  const ownBookmarks = isCurrentUser
3960
- ? (activity.own_bookmarks || []).filter((bookmark) => bookmark.user.id !== event.bookmark.user.id ||
3961
- bookmark.activity.id !== event.bookmark.activity.id)
3986
+ ? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
3962
3987
  : activity.own_bookmarks;
3963
3988
  return {
3964
3989
  ...activity,
@@ -3970,8 +3995,7 @@ const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
3970
3995
  // Update own_bookmarks if the bookmark is from the current user
3971
3996
  let ownBookmarks = activity.own_bookmarks || [];
3972
3997
  if (isCurrentUser) {
3973
- const bookmarkIndex = ownBookmarks.findIndex((bookmark) => bookmark.user.id === event.bookmark.user.id &&
3974
- bookmark.activity.id === event.bookmark.activity.id);
3998
+ const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
3975
3999
  if (bookmarkIndex !== -1) {
3976
4000
  ownBookmarks = [...ownBookmarks];
3977
4001
  ownBookmarks[bookmarkIndex] = event.bookmark;
@@ -4060,7 +4084,7 @@ class Feed extends FeedApi {
4060
4084
  },
4061
4085
  'feeds.activity.reaction.added': (event) => {
4062
4086
  const currentActivities = this.currentState.activities;
4063
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4087
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4064
4088
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4065
4089
  const result = addReactionToActivities(event, currentActivities, isCurrentUser);
4066
4090
  if (result.changed) {
@@ -4069,7 +4093,7 @@ class Feed extends FeedApi {
4069
4093
  },
4070
4094
  'feeds.activity.reaction.deleted': (event) => {
4071
4095
  const currentActivities = this.currentState.activities;
4072
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4096
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4073
4097
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4074
4098
  const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
4075
4099
  if (result.changed) {
@@ -4208,7 +4232,7 @@ class Feed extends FeedApi {
4208
4232
  // someone followed this feed
4209
4233
  event.follow.target_feed.fid === this.fid) {
4210
4234
  const source = event.follow.source_feed;
4211
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4235
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4212
4236
  this.state.next((currentState) => {
4213
4237
  const newState = { ...currentState, ...event.follow.target_feed };
4214
4238
  if (source.created_by.id === connectedUser?.id) {
@@ -4241,7 +4265,7 @@ class Feed extends FeedApi {
4241
4265
  // someone unfollowed this feed
4242
4266
  event.follow.target_feed.fid === this.fid) {
4243
4267
  const source = event.follow.source_feed;
4244
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4268
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4245
4269
  this.state.next((currentState) => {
4246
4270
  const newState = { ...currentState, ...event.follow.target_feed };
4247
4271
  if (source.created_by.id === connectedUser?.id) {
@@ -4257,7 +4281,7 @@ class Feed extends FeedApi {
4257
4281
  'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
4258
4282
  'feeds.comment.reaction.updated': Feed.noop,
4259
4283
  'feeds.feed_member.added': (event) => {
4260
- const { connectedUser } = this.client.state.getLatestValue();
4284
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4261
4285
  this.state.next((currentState) => {
4262
4286
  let newState;
4263
4287
  if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
@@ -4278,7 +4302,7 @@ class Feed extends FeedApi {
4278
4302
  });
4279
4303
  },
4280
4304
  'feeds.feed_member.removed': (event) => {
4281
- const { connectedUser } = this.client.state.getLatestValue();
4305
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4282
4306
  this.state.next((currentState) => {
4283
4307
  const newState = {
4284
4308
  ...currentState,
@@ -4291,7 +4315,7 @@ class Feed extends FeedApi {
4291
4315
  });
4292
4316
  },
4293
4317
  'feeds.feed_member.updated': (event) => {
4294
- const { connectedUser } = this.client.state.getLatestValue();
4318
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4295
4319
  this.state.next((currentState) => {
4296
4320
  const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
4297
4321
  let newState;
@@ -4356,7 +4380,7 @@ class Feed extends FeedApi {
4356
4380
  }
4357
4381
  handleCommentReactionEvent(event) {
4358
4382
  const { comment, reaction } = event;
4359
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4383
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4360
4384
  this.state.next((currentState) => {
4361
4385
  const forId = comment.parent_id ?? comment.object_id;
4362
4386
  const entityState = currentState.comments_by_entity_id[forId];
@@ -4458,7 +4482,7 @@ class Feed extends FeedApi {
4458
4482
  }
4459
4483
  handleBookmarkAdded(event) {
4460
4484
  const currentActivities = this.currentState.activities;
4461
- const { connectedUser } = this.client.state.getLatestValue();
4485
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4462
4486
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4463
4487
  const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
4464
4488
  if (result.changed) {
@@ -4467,7 +4491,7 @@ class Feed extends FeedApi {
4467
4491
  }
4468
4492
  handleBookmarkDeleted(event) {
4469
4493
  const currentActivities = this.currentState.activities;
4470
- const { connectedUser } = this.client.state.getLatestValue();
4494
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4471
4495
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4472
4496
  const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
4473
4497
  if (result.changed) {
@@ -4476,7 +4500,7 @@ class Feed extends FeedApi {
4476
4500
  }
4477
4501
  handleBookmarkUpdated(event) {
4478
4502
  const currentActivities = this.currentState.activities;
4479
- const { connectedUser } = this.client.state.getLatestValue();
4503
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4480
4504
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4481
4505
  const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
4482
4506
  if (result.changed) {
@@ -5031,7 +5055,8 @@ class StreamPoll {
5031
5055
  if (!isPollVoteCastedEvent(event))
5032
5056
  return;
5033
5057
  const currentState = this.data;
5034
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5058
+ const isOwnVote = event.poll_vote.user_id ===
5059
+ this.client.state.getLatestValue().connected_user?.id;
5035
5060
  let latestAnswers = [...currentState.latest_answers];
5036
5061
  let ownAnswer = currentState.own_answer;
5037
5062
  const ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5055,7 +5080,7 @@ class StreamPoll {
5055
5080
  else {
5056
5081
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5057
5082
  }
5058
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5083
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5059
5084
  this.state.partialNext({
5060
5085
  answers_count,
5061
5086
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5076,7 +5101,8 @@ class StreamPoll {
5076
5101
  if (!isPollVoteChangedEvent(event))
5077
5102
  return;
5078
5103
  const currentState = this.data;
5079
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5104
+ const isOwnVote = event.poll_vote.user_id ===
5105
+ this.client.state.getLatestValue().connected_user?.id;
5080
5106
  let latestAnswers = [...currentState.latest_answers];
5081
5107
  let ownAnswer = currentState.own_answer;
5082
5108
  let ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5123,7 +5149,7 @@ class StreamPoll {
5123
5149
  else {
5124
5150
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5125
5151
  }
5126
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5152
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5127
5153
  this.state.partialNext({
5128
5154
  answers_count,
5129
5155
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5143,7 +5169,8 @@ class StreamPoll {
5143
5169
  if (!isPollVoteRemovedEvent(event))
5144
5170
  return;
5145
5171
  const currentState = this.data;
5146
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5172
+ const isOwnVote = event.poll_vote.user_id ===
5173
+ this.client.state.getLatestValue().connected_user?.id;
5147
5174
  let latestAnswers = [...currentState.latest_answers];
5148
5175
  let ownAnswer = currentState.own_answer;
5149
5176
  const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
@@ -5161,7 +5188,7 @@ class StreamPoll {
5161
5188
  delete ownVotesByOptionId[event.poll_vote.option_id];
5162
5189
  }
5163
5190
  }
5164
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5191
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5165
5192
  this.state.partialNext({
5166
5193
  answers_count,
5167
5194
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5219,7 +5246,7 @@ class FeedsClient extends FeedsApi {
5219
5246
  this.healthyConnectionChangedEventCount = 0;
5220
5247
  this.pollFromState = (id) => this.polls_by_id.get(id);
5221
5248
  this.connectUser = async (user, tokenProvider) => {
5222
- if (this.state.getLatestValue().connectedUser !== undefined ||
5249
+ if (this.state.getLatestValue().connected_user !== undefined ||
5223
5250
  this.wsConnection) {
5224
5251
  throw new Error(`Can't connect a new user, call "disconnectUser" first`);
5225
5252
  }
@@ -5233,8 +5260,8 @@ class FeedsClient extends FeedsApi {
5233
5260
  this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
5234
5261
  const connectedEvent = await this.wsConnection.connect();
5235
5262
  this.state.partialNext({
5236
- connectedUser: connectedEvent?.me,
5237
- isWsConnectionHealthy: this.wsConnection.isHealthy,
5263
+ connected_user: connectedEvent?.me,
5264
+ is_ws_connection_healthy: !!this.wsConnection?.isHealthy,
5238
5265
  });
5239
5266
  }
5240
5267
  catch (err) {
@@ -5293,7 +5320,10 @@ class FeedsClient extends FeedsApi {
5293
5320
  removeConnectionEventListeners(this.updateNetworkConnectionStatus);
5294
5321
  this.connectionIdManager.reset();
5295
5322
  this.tokenManager.reset();
5296
- this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
5323
+ this.state.partialNext({
5324
+ connected_user: undefined,
5325
+ is_ws_connection_healthy: false,
5326
+ });
5297
5327
  };
5298
5328
  this.on = this.eventDispatcher.on;
5299
5329
  this.off = this.eventDispatcher.off;
@@ -5319,8 +5349,8 @@ class FeedsClient extends FeedsApi {
5319
5349
  }
5320
5350
  };
5321
5351
  this.state = new StateStore({
5322
- connectedUser: undefined,
5323
- isWsConnectionHealthy: false,
5352
+ connected_user: undefined,
5353
+ is_ws_connection_healthy: false,
5324
5354
  });
5325
5355
  this.moderation = new ModerationClient(apiClient);
5326
5356
  this.tokenManager = tokenManager;
@@ -5332,7 +5362,7 @@ class FeedsClient extends FeedsApi {
5332
5362
  switch (event.type) {
5333
5363
  case 'connection.changed': {
5334
5364
  const { online } = event;
5335
- this.state.partialNext({ isWsConnectionHealthy: online });
5365
+ this.state.partialNext({ is_ws_connection_healthy: online });
5336
5366
  if (online) {
5337
5367
  this.healthyConnectionChangedEventCount++;
5338
5368
  // we skip the first event as we could potentially be querying twice
@@ -5790,7 +5820,7 @@ class ActivitySearchSource extends BaseSearchSource {
5790
5820
  this.client = client;
5791
5821
  }
5792
5822
  async query(searchQuery) {
5793
- const { connectedUser } = this.client.state.getLatestValue();
5823
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5794
5824
  if (!connectedUser)
5795
5825
  return { items: [] };
5796
5826
  const { activities: items, next } = await this.client.queryActivities({
@@ -5805,10 +5835,10 @@ class ActivitySearchSource extends BaseSearchSource {
5805
5835
  return items;
5806
5836
  }
5807
5837
  }
5808
- // filter: {
5809
- // 'feed.name': { $autocomplete: searchQuery }
5810
- // 'feed.description': { $autocomplete: searchQuery }
5811
- // 'created_by.name': { $autocomplete: searchQuery }
5838
+ // filter: {
5839
+ // 'feed.name': { $autocomplete: searchQuery }
5840
+ // 'feed.description': { $autocomplete: searchQuery }
5841
+ // 'created_by.name': { $autocomplete: searchQuery }
5812
5842
  // },
5813
5843
 
5814
5844
  class UserSearchSource extends BaseSearchSource {
@@ -5824,7 +5854,7 @@ class UserSearchSource extends BaseSearchSource {
5824
5854
  this.client = client;
5825
5855
  }
5826
5856
  async query(searchQuery) {
5827
- const { connectedUser } = this.client.state.getLatestValue();
5857
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5828
5858
  if (!connectedUser)
5829
5859
  return { items: [] };
5830
5860
  // const channelFilters: ChannelFilters = {
@@ -5901,7 +5931,7 @@ class FeedSearchSource extends BaseSearchSource {
5901
5931
  this.client = client;
5902
5932
  }
5903
5933
  async query(searchQuery) {
5904
- const { connectedUser } = this.client.state.getLatestValue();
5934
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5905
5935
  if (!connectedUser)
5906
5936
  return { items: [] };
5907
5937
  // const channelFilters: ChannelFilters = {