@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
@@ -1973,6 +1973,18 @@ class FeedsApi {
1973
1973
  decoders.RejectFeedMemberInviteResponse?.(response.body);
1974
1974
  return { ...response.body, metadata: response.metadata };
1975
1975
  }
1976
+ async stopWatchingFeed(request) {
1977
+ const queryParams = {
1978
+ connection_id: request?.connection_id,
1979
+ };
1980
+ const pathParams = {
1981
+ feed_group_id: request?.feed_group_id,
1982
+ feed_id: request?.feed_id,
1983
+ };
1984
+ const response = await this.apiClient.sendRequest('DELETE', '/api/v2/feeds/feed_groups/{feed_group_id}/feeds/{feed_id}/watch', pathParams, queryParams);
1985
+ decoders.Response?.(response.body);
1986
+ return { ...response.body, metadata: response.metadata };
1987
+ }
1976
1988
  async getFollowSuggestions(request) {
1977
1989
  const queryParams = {
1978
1990
  limit: request?.limit,
@@ -2791,7 +2803,7 @@ class TokenManager {
2791
2803
  }
2792
2804
  catch (e) {
2793
2805
  const numberOfFailures = ++previousFailuresCount;
2794
- await sleep(retryInterval(numberOfFailures));
2806
+ await sleep(1000);
2795
2807
  if (numberOfFailures === 3) {
2796
2808
  this.loadTokenPromise = null;
2797
2809
  return reject(new Error(`Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`, { cause: e }));
@@ -3639,7 +3651,7 @@ class ApiClient {
3639
3651
  rate_limit: getRateLimitFromResponseHeader(response_headers),
3640
3652
  };
3641
3653
  };
3642
- this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
3654
+ this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
3643
3655
  this.timeout = options?.timeout ?? 3000;
3644
3656
  this.axiosInstance = axios.create({
3645
3657
  baseURL: this.baseUrl,
@@ -3803,6 +3815,13 @@ class FeedApi {
3803
3815
  ...request,
3804
3816
  });
3805
3817
  }
3818
+ stopWatching(request) {
3819
+ return this.feedsApi.stopWatchingFeed({
3820
+ feed_id: this.id,
3821
+ feed_group_id: this.group,
3822
+ ...request,
3823
+ });
3824
+ }
3806
3825
  }
3807
3826
 
3808
3827
  const addActivitiesToState = (newActivities, activities, position) => {
@@ -3933,6 +3952,13 @@ const removeReactionFromActivities = (event, activities, isCurrentUser) => {
3933
3952
  return updateActivityInActivities$1(updatedActivity, activities);
3934
3953
  };
3935
3954
 
3955
+ // Helper function to check if two bookmarks are the same
3956
+ // A bookmark is identified by activity_id + folder_id + user_id
3957
+ const isSameBookmark = (bookmark1, bookmark2) => {
3958
+ return (bookmark1.user.id === bookmark2.user.id &&
3959
+ bookmark1.activity.id === bookmark2.activity.id &&
3960
+ bookmark1.folder?.id === bookmark2.folder?.id);
3961
+ };
3936
3962
  const updateActivityInActivities = (updatedActivity, activities) => {
3937
3963
  const index = activities.findIndex((a) => a.id === updatedActivity.id);
3938
3964
  if (index !== -1) {
@@ -3959,8 +3985,7 @@ const addBookmarkToActivity = (event, activity, isCurrentUser) => {
3959
3985
  const removeBookmarkFromActivity = (event, activity, isCurrentUser) => {
3960
3986
  // Update own_bookmarks if the bookmark is from the current user
3961
3987
  const ownBookmarks = isCurrentUser
3962
- ? (activity.own_bookmarks || []).filter((bookmark) => bookmark.user.id !== event.bookmark.user.id ||
3963
- bookmark.activity.id !== event.bookmark.activity.id)
3988
+ ? (activity.own_bookmarks || []).filter((bookmark) => !isSameBookmark(bookmark, event.bookmark))
3964
3989
  : activity.own_bookmarks;
3965
3990
  return {
3966
3991
  ...activity,
@@ -3972,8 +3997,7 @@ const updateBookmarkInActivity = (event, activity, isCurrentUser) => {
3972
3997
  // Update own_bookmarks if the bookmark is from the current user
3973
3998
  let ownBookmarks = activity.own_bookmarks || [];
3974
3999
  if (isCurrentUser) {
3975
- const bookmarkIndex = ownBookmarks.findIndex((bookmark) => bookmark.user.id === event.bookmark.user.id &&
3976
- bookmark.activity.id === event.bookmark.activity.id);
4000
+ const bookmarkIndex = ownBookmarks.findIndex((bookmark) => isSameBookmark(bookmark, event.bookmark));
3977
4001
  if (bookmarkIndex !== -1) {
3978
4002
  ownBookmarks = [...ownBookmarks];
3979
4003
  ownBookmarks[bookmarkIndex] = event.bookmark;
@@ -4062,7 +4086,7 @@ class Feed extends FeedApi {
4062
4086
  },
4063
4087
  'feeds.activity.reaction.added': (event) => {
4064
4088
  const currentActivities = this.currentState.activities;
4065
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4089
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4066
4090
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4067
4091
  const result = addReactionToActivities(event, currentActivities, isCurrentUser);
4068
4092
  if (result.changed) {
@@ -4071,7 +4095,7 @@ class Feed extends FeedApi {
4071
4095
  },
4072
4096
  'feeds.activity.reaction.deleted': (event) => {
4073
4097
  const currentActivities = this.currentState.activities;
4074
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4098
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4075
4099
  const isCurrentUser = Boolean(connectedUser && event.reaction.user.id === connectedUser.id);
4076
4100
  const result = removeReactionFromActivities(event, currentActivities, isCurrentUser);
4077
4101
  if (result.changed) {
@@ -4210,7 +4234,7 @@ class Feed extends FeedApi {
4210
4234
  // someone followed this feed
4211
4235
  event.follow.target_feed.fid === this.fid) {
4212
4236
  const source = event.follow.source_feed;
4213
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4237
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4214
4238
  this.state.next((currentState) => {
4215
4239
  const newState = { ...currentState, ...event.follow.target_feed };
4216
4240
  if (source.created_by.id === connectedUser?.id) {
@@ -4243,7 +4267,7 @@ class Feed extends FeedApi {
4243
4267
  // someone unfollowed this feed
4244
4268
  event.follow.target_feed.fid === this.fid) {
4245
4269
  const source = event.follow.source_feed;
4246
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4270
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4247
4271
  this.state.next((currentState) => {
4248
4272
  const newState = { ...currentState, ...event.follow.target_feed };
4249
4273
  if (source.created_by.id === connectedUser?.id) {
@@ -4259,7 +4283,7 @@ class Feed extends FeedApi {
4259
4283
  'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
4260
4284
  'feeds.comment.reaction.updated': Feed.noop,
4261
4285
  'feeds.feed_member.added': (event) => {
4262
- const { connectedUser } = this.client.state.getLatestValue();
4286
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4263
4287
  this.state.next((currentState) => {
4264
4288
  let newState;
4265
4289
  if (!checkHasAnotherPage(currentState.members, currentState.member_pagination?.next)) {
@@ -4280,7 +4304,7 @@ class Feed extends FeedApi {
4280
4304
  });
4281
4305
  },
4282
4306
  'feeds.feed_member.removed': (event) => {
4283
- const { connectedUser } = this.client.state.getLatestValue();
4307
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4284
4308
  this.state.next((currentState) => {
4285
4309
  const newState = {
4286
4310
  ...currentState,
@@ -4293,7 +4317,7 @@ class Feed extends FeedApi {
4293
4317
  });
4294
4318
  },
4295
4319
  'feeds.feed_member.updated': (event) => {
4296
- const { connectedUser } = this.client.state.getLatestValue();
4320
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4297
4321
  this.state.next((currentState) => {
4298
4322
  const memberIndex = currentState.members?.findIndex((member) => member.user.id === event.member.user.id) ?? -1;
4299
4323
  let newState;
@@ -4358,7 +4382,7 @@ class Feed extends FeedApi {
4358
4382
  }
4359
4383
  handleCommentReactionEvent(event) {
4360
4384
  const { comment, reaction } = event;
4361
- const connectedUser = this.client.state.getLatestValue().connectedUser;
4385
+ const connectedUser = this.client.state.getLatestValue().connected_user;
4362
4386
  this.state.next((currentState) => {
4363
4387
  const forId = comment.parent_id ?? comment.object_id;
4364
4388
  const entityState = currentState.comments_by_entity_id[forId];
@@ -4460,7 +4484,7 @@ class Feed extends FeedApi {
4460
4484
  }
4461
4485
  handleBookmarkAdded(event) {
4462
4486
  const currentActivities = this.currentState.activities;
4463
- const { connectedUser } = this.client.state.getLatestValue();
4487
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4464
4488
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4465
4489
  const result = addBookmarkToActivities(event, currentActivities, isCurrentUser);
4466
4490
  if (result.changed) {
@@ -4469,7 +4493,7 @@ class Feed extends FeedApi {
4469
4493
  }
4470
4494
  handleBookmarkDeleted(event) {
4471
4495
  const currentActivities = this.currentState.activities;
4472
- const { connectedUser } = this.client.state.getLatestValue();
4496
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4473
4497
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4474
4498
  const result = removeBookmarkFromActivities(event, currentActivities, isCurrentUser);
4475
4499
  if (result.changed) {
@@ -4478,7 +4502,7 @@ class Feed extends FeedApi {
4478
4502
  }
4479
4503
  handleBookmarkUpdated(event) {
4480
4504
  const currentActivities = this.currentState.activities;
4481
- const { connectedUser } = this.client.state.getLatestValue();
4505
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
4482
4506
  const isCurrentUser = event.bookmark.user.id === connectedUser?.id;
4483
4507
  const result = updateBookmarkInActivities(event, currentActivities, isCurrentUser);
4484
4508
  if (result.changed) {
@@ -5033,7 +5057,8 @@ class StreamPoll {
5033
5057
  if (!isPollVoteCastedEvent(event))
5034
5058
  return;
5035
5059
  const currentState = this.data;
5036
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5060
+ const isOwnVote = event.poll_vote.user_id ===
5061
+ this.client.state.getLatestValue().connected_user?.id;
5037
5062
  let latestAnswers = [...currentState.latest_answers];
5038
5063
  let ownAnswer = currentState.own_answer;
5039
5064
  const ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5057,7 +5082,7 @@ class StreamPoll {
5057
5082
  else {
5058
5083
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5059
5084
  }
5060
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5085
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5061
5086
  this.state.partialNext({
5062
5087
  answers_count,
5063
5088
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5078,7 +5103,8 @@ class StreamPoll {
5078
5103
  if (!isPollVoteChangedEvent(event))
5079
5104
  return;
5080
5105
  const currentState = this.data;
5081
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5106
+ const isOwnVote = event.poll_vote.user_id ===
5107
+ this.client.state.getLatestValue().connected_user?.id;
5082
5108
  let latestAnswers = [...currentState.latest_answers];
5083
5109
  let ownAnswer = currentState.own_answer;
5084
5110
  let ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -5125,7 +5151,7 @@ class StreamPoll {
5125
5151
  else {
5126
5152
  maxVotedOptionIds = getMaxVotedOptionIds(event.poll.vote_counts_by_option);
5127
5153
  }
5128
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5154
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5129
5155
  this.state.partialNext({
5130
5156
  answers_count,
5131
5157
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5145,7 +5171,8 @@ class StreamPoll {
5145
5171
  if (!isPollVoteRemovedEvent(event))
5146
5172
  return;
5147
5173
  const currentState = this.data;
5148
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
5174
+ const isOwnVote = event.poll_vote.user_id ===
5175
+ this.client.state.getLatestValue().connected_user?.id;
5149
5176
  let latestAnswers = [...currentState.latest_answers];
5150
5177
  let ownAnswer = currentState.own_answer;
5151
5178
  const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
@@ -5163,7 +5190,7 @@ class StreamPoll {
5163
5190
  delete ownVotesByOptionId[event.poll_vote.option_id];
5164
5191
  }
5165
5192
  }
5166
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
5193
+ const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option, } = event.poll;
5167
5194
  this.state.partialNext({
5168
5195
  answers_count,
5169
5196
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -5221,7 +5248,7 @@ class FeedsClient extends FeedsApi {
5221
5248
  this.healthyConnectionChangedEventCount = 0;
5222
5249
  this.pollFromState = (id) => this.polls_by_id.get(id);
5223
5250
  this.connectUser = async (user, tokenProvider) => {
5224
- if (this.state.getLatestValue().connectedUser !== undefined ||
5251
+ if (this.state.getLatestValue().connected_user !== undefined ||
5225
5252
  this.wsConnection) {
5226
5253
  throw new Error(`Can't connect a new user, call "disconnectUser" first`);
5227
5254
  }
@@ -5235,8 +5262,8 @@ class FeedsClient extends FeedsApi {
5235
5262
  this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
5236
5263
  const connectedEvent = await this.wsConnection.connect();
5237
5264
  this.state.partialNext({
5238
- connectedUser: connectedEvent?.me,
5239
- isWsConnectionHealthy: this.wsConnection.isHealthy,
5265
+ connected_user: connectedEvent?.me,
5266
+ is_ws_connection_healthy: !!this.wsConnection?.isHealthy,
5240
5267
  });
5241
5268
  }
5242
5269
  catch (err) {
@@ -5295,7 +5322,10 @@ class FeedsClient extends FeedsApi {
5295
5322
  removeConnectionEventListeners(this.updateNetworkConnectionStatus);
5296
5323
  this.connectionIdManager.reset();
5297
5324
  this.tokenManager.reset();
5298
- this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
5325
+ this.state.partialNext({
5326
+ connected_user: undefined,
5327
+ is_ws_connection_healthy: false,
5328
+ });
5299
5329
  };
5300
5330
  this.on = this.eventDispatcher.on;
5301
5331
  this.off = this.eventDispatcher.off;
@@ -5321,8 +5351,8 @@ class FeedsClient extends FeedsApi {
5321
5351
  }
5322
5352
  };
5323
5353
  this.state = new StateStore({
5324
- connectedUser: undefined,
5325
- isWsConnectionHealthy: false,
5354
+ connected_user: undefined,
5355
+ is_ws_connection_healthy: false,
5326
5356
  });
5327
5357
  this.moderation = new ModerationClient(apiClient);
5328
5358
  this.tokenManager = tokenManager;
@@ -5334,7 +5364,7 @@ class FeedsClient extends FeedsApi {
5334
5364
  switch (event.type) {
5335
5365
  case 'connection.changed': {
5336
5366
  const { online } = event;
5337
- this.state.partialNext({ isWsConnectionHealthy: online });
5367
+ this.state.partialNext({ is_ws_connection_healthy: online });
5338
5368
  if (online) {
5339
5369
  this.healthyConnectionChangedEventCount++;
5340
5370
  // we skip the first event as we could potentially be querying twice
@@ -5792,7 +5822,7 @@ class ActivitySearchSource extends BaseSearchSource {
5792
5822
  this.client = client;
5793
5823
  }
5794
5824
  async query(searchQuery) {
5795
- const { connectedUser } = this.client.state.getLatestValue();
5825
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5796
5826
  if (!connectedUser)
5797
5827
  return { items: [] };
5798
5828
  const { activities: items, next } = await this.client.queryActivities({
@@ -5807,10 +5837,10 @@ class ActivitySearchSource extends BaseSearchSource {
5807
5837
  return items;
5808
5838
  }
5809
5839
  }
5810
- // filter: {
5811
- // 'feed.name': { $autocomplete: searchQuery }
5812
- // 'feed.description': { $autocomplete: searchQuery }
5813
- // 'created_by.name': { $autocomplete: searchQuery }
5840
+ // filter: {
5841
+ // 'feed.name': { $autocomplete: searchQuery }
5842
+ // 'feed.description': { $autocomplete: searchQuery }
5843
+ // 'created_by.name': { $autocomplete: searchQuery }
5814
5844
  // },
5815
5845
 
5816
5846
  class UserSearchSource extends BaseSearchSource {
@@ -5826,7 +5856,7 @@ class UserSearchSource extends BaseSearchSource {
5826
5856
  this.client = client;
5827
5857
  }
5828
5858
  async query(searchQuery) {
5829
- const { connectedUser } = this.client.state.getLatestValue();
5859
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5830
5860
  if (!connectedUser)
5831
5861
  return { items: [] };
5832
5862
  // const channelFilters: ChannelFilters = {
@@ -5903,7 +5933,7 @@ class FeedSearchSource extends BaseSearchSource {
5903
5933
  this.client = client;
5904
5934
  }
5905
5935
  async query(searchQuery) {
5906
- const { connectedUser } = this.client.state.getLatestValue();
5936
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
5907
5937
  if (!connectedUser)
5908
5938
  return { items: [] };
5909
5939
  // const channelFilters: ChannelFilters = {