@stream-io/feeds-client 0.3.6 → 0.3.8

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 (62) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/index.js +2 -1
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/react-bindings.js +76 -14
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +3 -2
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +76 -14
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/{feeds-client-47vliZx_.js → feeds-client-CwioZBvA.js} +355 -52
  11. package/dist/feeds-client-CwioZBvA.js.map +1 -0
  12. package/dist/{feeds-client-Cd2LsXp-.mjs → feeds-client-DVbsjKUf.mjs} +355 -52
  13. package/dist/feeds-client-DVbsjKUf.mjs.map +1 -0
  14. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts +49 -0
  15. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -0
  16. package/dist/types/activity-with-state-updates/get-feed.d.ts +3 -0
  17. package/dist/types/activity-with-state-updates/get-feed.d.ts.map +1 -0
  18. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts +1 -0
  19. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts.map +1 -1
  20. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts +32 -0
  21. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts.map +1 -0
  22. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts +4 -0
  23. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts.map +1 -1
  24. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
  25. package/dist/types/bindings/react/hooks/useCreateFeedsClient.d.ts.map +1 -1
  26. package/dist/types/common/real-time/event-models.d.ts +1 -0
  27. package/dist/types/common/real-time/event-models.d.ts.map +1 -1
  28. package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
  29. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
  30. package/dist/types/feed/feed.d.ts +1 -1
  31. package/dist/types/feed/feed.d.ts.map +1 -1
  32. package/dist/types/feeds-client/active-activity.d.ts +8 -0
  33. package/dist/types/feeds-client/active-activity.d.ts.map +1 -0
  34. package/dist/types/feeds-client/feeds-client.d.ts +36 -3
  35. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  36. package/dist/types/gen/feeds/FeedsApi.d.ts +9 -1
  37. package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
  38. package/dist/types/gen/models/index.d.ts +52 -0
  39. package/dist/types/gen/models/index.d.ts.map +1 -1
  40. package/dist/types/index.d.ts +1 -0
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/types.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/activity-with-state-updates/activity-with-state-updates.ts +190 -0
  45. package/src/activity-with-state-updates/get-feed.ts +5 -0
  46. package/src/bindings/react/hooks/feed-state-hooks/index.ts +1 -0
  47. package/src/bindings/react/hooks/feed-state-hooks/useActivityComments.ts +113 -0
  48. package/src/bindings/react/hooks/feed-state-hooks/useComments.ts +4 -0
  49. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +12 -9
  50. package/src/bindings/react/hooks/useCreateFeedsClient.ts +0 -6
  51. package/src/common/real-time/event-models.ts +5 -1
  52. package/src/feed/feed.ts +16 -6
  53. package/src/feeds-client/active-activity.ts +42 -0
  54. package/src/feeds-client/feeds-client.ts +162 -53
  55. package/src/gen/feeds/FeedsApi.ts +86 -0
  56. package/src/gen/model-decoders/decoders.ts +41 -0
  57. package/src/gen/models/index.ts +84 -0
  58. package/src/index.ts +1 -0
  59. package/src/test-utils/response-generators.ts +1 -0
  60. package/src/types.ts +8 -10
  61. package/dist/feeds-client-47vliZx_.js.map +0 -1
  62. package/dist/feeds-client-Cd2LsXp-.mjs.map +0 -1
@@ -136,6 +136,7 @@ decoders.ActivityResponse = (input) => {
136
136
  mentioned_users: { type: "UserResponse", isSingle: false },
137
137
  own_bookmarks: { type: "BookmarkResponse", isSingle: false },
138
138
  own_reactions: { type: "FeedsReactionResponse", isSingle: false },
139
+ collections: { type: "EnrichedCollectionResponse", isSingle: false },
139
140
  reaction_groups: { type: "ReactionGroupResponse", isSingle: false },
140
141
  user: { type: "UserResponse", isSingle: true },
141
142
  deleted_at: { type: "DatetimeType", isSingle: true },
@@ -430,6 +431,13 @@ decoders.ChannelResponse = (input) => {
430
431
  };
431
432
  return decode(typeMappings, input);
432
433
  };
434
+ decoders.CollectionResponse = (input) => {
435
+ const typeMappings = {
436
+ created_at: { type: "DatetimeType", isSingle: true },
437
+ updated_at: { type: "DatetimeType", isSingle: true }
438
+ };
439
+ return decode(typeMappings, input);
440
+ };
433
441
  decoders.Command = (input) => {
434
442
  const typeMappings = {
435
443
  created_at: { type: "DatetimeType", isSingle: true },
@@ -517,6 +525,12 @@ decoders.CreateBlockListResponse = (input) => {
517
525
  };
518
526
  return decode(typeMappings, input);
519
527
  };
528
+ decoders.CreateCollectionsResponse = (input) => {
529
+ const typeMappings = {
530
+ collections: { type: "CollectionResponse", isSingle: false }
531
+ };
532
+ return decode(typeMappings, input);
533
+ };
520
534
  decoders.CreateFeedsBatchResponse = (input) => {
521
535
  const typeMappings = {
522
536
  feeds: { type: "FeedResponse", isSingle: false }
@@ -590,6 +604,13 @@ decoders.EgressRTMPResponse = (input) => {
590
604
  };
591
605
  return decode(typeMappings, input);
592
606
  };
607
+ decoders.EnrichedCollectionResponse = (input) => {
608
+ const typeMappings = {
609
+ created_at: { type: "DatetimeType", isSingle: true },
610
+ updated_at: { type: "DatetimeType", isSingle: true }
611
+ };
612
+ return decode(typeMappings, input);
613
+ };
593
614
  decoders.EntityCreatorResponse = (input) => {
594
615
  const typeMappings = {
595
616
  created_at: { type: "DatetimeType", isSingle: true },
@@ -1195,6 +1216,12 @@ decoders.ReactionResponse = (input) => {
1195
1216
  };
1196
1217
  return decode(typeMappings, input);
1197
1218
  };
1219
+ decoders.ReadCollectionsResponse = (input) => {
1220
+ const typeMappings = {
1221
+ collections: { type: "CollectionResponse", isSingle: false }
1222
+ };
1223
+ return decode(typeMappings, input);
1224
+ };
1198
1225
  decoders.RejectFeedMemberInviteResponse = (input) => {
1199
1226
  const typeMappings = {
1200
1227
  member: { type: "FeedMemberResponse", isSingle: true }
@@ -1357,6 +1384,12 @@ decoders.UpdateBookmarkResponse = (input) => {
1357
1384
  };
1358
1385
  return decode(typeMappings, input);
1359
1386
  };
1387
+ decoders.UpdateCollectionsResponse = (input) => {
1388
+ const typeMappings = {
1389
+ collections: { type: "CollectionResponse", isSingle: false }
1390
+ };
1391
+ return decode(typeMappings, input);
1392
+ };
1360
1393
  decoders.UpdateCommentResponse = (input) => {
1361
1394
  const typeMappings = {
1362
1395
  comment: { type: "CommentResponse", isSingle: true }
@@ -1611,6 +1644,7 @@ class FeedsApi {
1611
1644
  visibility: request?.visibility,
1612
1645
  visibility_tag: request?.visibility_tag,
1613
1646
  attachments: request?.attachments,
1647
+ collection_refs: request?.collection_refs,
1614
1648
  filter_tags: request?.filter_tags,
1615
1649
  interest_tags: request?.interest_tags,
1616
1650
  mentioned_user_ids: request?.mentioned_user_ids,
@@ -1900,6 +1934,7 @@ class FeedsApi {
1900
1934
  text: request?.text,
1901
1935
  visibility: request?.visibility,
1902
1936
  attachments: request?.attachments,
1937
+ collection_refs: request?.collection_refs,
1903
1938
  feeds: request?.feeds,
1904
1939
  filter_tags: request?.filter_tags,
1905
1940
  interest_tags: request?.interest_tags,
@@ -1987,6 +2022,52 @@ class FeedsApi {
1987
2022
  decoders.QueryBookmarksResponse?.(response.body);
1988
2023
  return { ...response.body, metadata: response.metadata };
1989
2024
  }
2025
+ async deleteCollections(request) {
2026
+ const queryParams = {
2027
+ collection_refs: request?.collection_refs
2028
+ };
2029
+ const response = await this.apiClient.sendRequest("DELETE", "/api/v2/feeds/collections", void 0, queryParams);
2030
+ decoders.DeleteCollectionsResponse?.(response.body);
2031
+ return { ...response.body, metadata: response.metadata };
2032
+ }
2033
+ async readCollections(request) {
2034
+ const queryParams = {
2035
+ collection_refs: request?.collection_refs
2036
+ };
2037
+ const response = await this.apiClient.sendRequest("GET", "/api/v2/feeds/collections", void 0, queryParams);
2038
+ decoders.ReadCollectionsResponse?.(response.body);
2039
+ return { ...response.body, metadata: response.metadata };
2040
+ }
2041
+ async updateCollections(request) {
2042
+ const body = {
2043
+ collections: request?.collections
2044
+ };
2045
+ const response = await this.apiClient.sendRequest(
2046
+ "PATCH",
2047
+ "/api/v2/feeds/collections",
2048
+ void 0,
2049
+ void 0,
2050
+ body,
2051
+ "application/json"
2052
+ );
2053
+ decoders.UpdateCollectionsResponse?.(response.body);
2054
+ return { ...response.body, metadata: response.metadata };
2055
+ }
2056
+ async createCollections(request) {
2057
+ const body = {
2058
+ collections: request?.collections
2059
+ };
2060
+ const response = await this.apiClient.sendRequest(
2061
+ "POST",
2062
+ "/api/v2/feeds/collections",
2063
+ void 0,
2064
+ void 0,
2065
+ body,
2066
+ "application/json"
2067
+ );
2068
+ decoders.CreateCollectionsResponse?.(response.body);
2069
+ return { ...response.body, metadata: response.metadata };
2070
+ }
1990
2071
  async getComments(request) {
1991
2072
  const queryParams = {
1992
2073
  object_id: request?.object_id,
@@ -3763,7 +3844,7 @@ const getRateLimitFromResponseHeader = (response_headers) => {
3763
3844
  };
3764
3845
  return result;
3765
3846
  };
3766
- const version = "0.3.6";
3847
+ const version = "0.3.8";
3767
3848
  class ApiClient {
3768
3849
  constructor(apiKey, tokenManager, connectionIdManager, options) {
3769
3850
  this.apiKey = apiKey;
@@ -6399,7 +6480,7 @@ const _Feed = class _Feed extends FeedApi {
6399
6480
  }
6400
6481
  }
6401
6482
  async loadNextPageActivityComments(activity, request) {
6402
- const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
6483
+ const currentEntityState = this.currentState.comments_by_entity_id[typeof activity === "string" ? activity : activity.id];
6403
6484
  const currentPagination = currentEntityState?.pagination;
6404
6485
  const currentNextCursor = currentPagination?.next;
6405
6486
  const currentSort = currentPagination?.sort;
@@ -6408,12 +6489,13 @@ const _Feed = class _Feed extends FeedApi {
6408
6489
  if (isLoading || !checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
6409
6490
  return;
6410
6491
  }
6492
+ const entityId = typeof activity === "string" ? activity : activity.id;
6411
6493
  await this.loadNextPageComments({
6412
- entityId: activity.id,
6494
+ entityId,
6413
6495
  base: () => this.client.getComments({
6414
6496
  ...request,
6415
6497
  sort,
6416
- object_id: activity.id,
6498
+ object_id: entityId,
6417
6499
  object_type: "activity",
6418
6500
  next: currentNextCursor
6419
6501
  }),
@@ -6648,7 +6730,7 @@ const _Feed = class _Feed extends FeedApi {
6648
6730
  eventHandler?.(event);
6649
6731
  }
6650
6732
  if (typeof eventHandler === "undefined") {
6651
- console.warn(`Received unknown event type: ${event.type}`, event);
6733
+ feedsLoggerSystem.getLogger("event-dispatcher").warn(`Received unknown feed event, type: ${event.type}`, event);
6652
6734
  }
6653
6735
  this.eventDispatcher.dispatch(event);
6654
6736
  }
@@ -6790,6 +6872,156 @@ function queueBatchedOwnCapabilities({ feeds }) {
6790
6872
  function clearQueuedFeeds() {
6791
6873
  queuedFeeds.clear();
6792
6874
  }
6875
+ function connectActivityToFeed({
6876
+ fid
6877
+ }) {
6878
+ const [group, id] = fid.split(":");
6879
+ const activeFeed = this.activeFeeds[fid];
6880
+ const feed = new Feed(
6881
+ this,
6882
+ group,
6883
+ id,
6884
+ void 0,
6885
+ activeFeed?.currentState.watch
6886
+ );
6887
+ return feed;
6888
+ }
6889
+ function isAnyFeedWatched(fids) {
6890
+ for (const fid of fids) {
6891
+ const feed = this.activeFeeds[fid];
6892
+ if (feed && feed.currentState.last_get_or_create_request_config?.watch) {
6893
+ return true;
6894
+ }
6895
+ }
6896
+ return false;
6897
+ }
6898
+ function disconnectActivityFromFeed(id) {
6899
+ const activeFeed = this.activeActivities[id];
6900
+ if (activeFeed) {
6901
+ delete this.activeActivities[id];
6902
+ }
6903
+ }
6904
+ class ActivityWithStateUpdates {
6905
+ constructor(id, feedsClient) {
6906
+ this.id = id;
6907
+ this.feedsClient = feedsClient;
6908
+ this.state = new StateStore({
6909
+ activity: void 0,
6910
+ comments_by_entity_id: {},
6911
+ is_loading: false
6912
+ });
6913
+ }
6914
+ get currentState() {
6915
+ return this.state.getLatestValue();
6916
+ }
6917
+ get feeds() {
6918
+ return this.currentState.activity?.feeds ?? [];
6919
+ }
6920
+ /**
6921
+ * Fetch activity and load it into state
6922
+ * @param watch - Whether to watch the feed the activity belongs to for real-time updates
6923
+ * @param feed - The feed to watch. Use only if the activity belongs to multiple feeds and you want to specify the feed explicitly.
6924
+ * @param feedSelector - A function to select the feed from the activity response. Use only if the activity belongs to multiple feeds and you want to specify the feed explicitly.
6925
+ */
6926
+ async get(request = {}) {
6927
+ if (this.inProgressGet && deepEqual(this.inProgressGet.request, request)) {
6928
+ return this.inProgressGet.promise;
6929
+ }
6930
+ const { comments } = request;
6931
+ this.state.partialNext({
6932
+ is_loading: true,
6933
+ last_get_request_config: request
6934
+ });
6935
+ const getActivityRequest = this.feedsClient.getActivity({
6936
+ id: this.id
6937
+ }).then((response) => response.activity);
6938
+ this.inProgressGet = { request, promise: getActivityRequest };
6939
+ const activityResponse = await getActivityRequest;
6940
+ this.feedsClient.hydratePollCache([activityResponse]);
6941
+ this.setFeed({
6942
+ // We set feed to first containing feed
6943
+ // But in WS event handler we match events by any of the containing feeds, so as long as any of the containing feeds are watched, we'll do a state update
6944
+ // This is a bit hacky, proper solution would be to refactor all activity event handlers and detach them from feed instance
6945
+ fid: activityResponse.feeds[0],
6946
+ initialState: activityResponse
6947
+ });
6948
+ if (this.feed) {
6949
+ this.feed.activityAddedEventFilter = () => false;
6950
+ }
6951
+ if (comments) {
6952
+ await this.loadNextPageActivityComments(comments);
6953
+ }
6954
+ this.subscribeToFeedState();
6955
+ this.inProgressGet = void 0;
6956
+ return activityResponse;
6957
+ }
6958
+ loadNextPageActivityComments(request) {
6959
+ const activity = this.feed?.currentState.activities?.[0];
6960
+ if (!activity || !this.feed) {
6961
+ throw new Error("Initialize activity first");
6962
+ }
6963
+ if (!this.currentState.last_get_request_config?.comments) {
6964
+ this.state.partialNext({
6965
+ last_get_request_config: {
6966
+ ...this.currentState.last_get_request_config,
6967
+ comments: request
6968
+ }
6969
+ });
6970
+ }
6971
+ return this.feed.loadNextPageActivityComments(activity, request);
6972
+ }
6973
+ loadNextPageCommentReplies(...params) {
6974
+ if (!this.feed) {
6975
+ throw new Error("Initialize activity first");
6976
+ }
6977
+ return this.feed.loadNextPageCommentReplies(...params);
6978
+ }
6979
+ dispose() {
6980
+ this.unsubscribeFromFeedState?.();
6981
+ disconnectActivityFromFeed.call(this.feedsClient, this.id);
6982
+ }
6983
+ /**
6984
+ * @internal
6985
+ */
6986
+ async synchronize() {
6987
+ const allFids = this.currentState.activity?.feeds ?? [];
6988
+ if (!isAnyFeedWatched.call(this.feedsClient, allFids)) {
6989
+ return;
6990
+ }
6991
+ this.inProgressGet = void 0;
6992
+ return this.get(this.currentState.last_get_request_config);
6993
+ }
6994
+ setFeed({
6995
+ fid,
6996
+ initialState
6997
+ }) {
6998
+ this.feed = connectActivityToFeed.call(this.feedsClient, { fid });
6999
+ this.feed.state.partialNext({
7000
+ activities: [initialState]
7001
+ });
7002
+ }
7003
+ subscribeToFeedState() {
7004
+ this.unsubscribeFromFeedState?.();
7005
+ this.unsubscribeFromFeedState = this.feed?.state.subscribeWithSelector(
7006
+ (state) => ({
7007
+ activity: state.activities?.find((activity) => activity.id === this.id),
7008
+ comments_by_entity_id: state.comments_by_entity_id
7009
+ }),
7010
+ (state) => {
7011
+ if (state.activity) {
7012
+ this.state.partialNext({
7013
+ activity: state.activity,
7014
+ comments_by_entity_id: state.comments_by_entity_id,
7015
+ is_loading: false
7016
+ });
7017
+ }
7018
+ }
7019
+ );
7020
+ }
7021
+ }
7022
+ function getFeed() {
7023
+ return this.feed;
7024
+ }
6793
7025
  class FeedsClient extends FeedsApi {
6794
7026
  constructor(apiKey, options) {
6795
7027
  const tokenManager = new TokenManager();
@@ -6802,6 +7034,7 @@ class FeedsClient extends FeedsApi {
6802
7034
  );
6803
7035
  super(apiClient);
6804
7036
  this.eventDispatcher = new EventDispatcher();
7037
+ this.activeActivities = {};
6805
7038
  this.activeFeeds = {};
6806
7039
  this.healthyConnectionChangedEventCount = 0;
6807
7040
  this.setGetBatchOwnCapabilitiesThrottlingInterval = (throttlingMs) => {
@@ -6830,13 +7063,20 @@ class FeedsClient extends FeedsApi {
6830
7063
  this.recoverOnReconnect = async () => {
6831
7064
  this.healthyConnectionChangedEventCount++;
6832
7065
  if (this.healthyConnectionChangedEventCount > 1) {
6833
- const entries = Object.entries(this.activeFeeds);
6834
- const results = await Promise.allSettled(
6835
- entries.map(([, feed]) => feed.synchronize())
6836
- );
6837
- const failures = results.flatMap(
6838
- (result, index) => result.status === "rejected" ? [{ feed: entries[index][0], reason: result.reason }] : []
6839
- );
7066
+ const feedEntries = Object.entries(this.activeFeeds);
7067
+ const activityEntries = Object.entries(this.activeActivities);
7068
+ const results = await Promise.allSettled([
7069
+ ...feedEntries.map(([, feed]) => feed.synchronize()),
7070
+ ...activityEntries.map(([, activity]) => activity.synchronize())
7071
+ ]);
7072
+ const failures = results.flatMap((result, index) => {
7073
+ if (result.status === "fulfilled") {
7074
+ return [];
7075
+ }
7076
+ const activity = activityEntries[index - feedEntries.length]?.[1];
7077
+ const feed = feedEntries[index]?.[0] ?? (activity && getFeed.call(activity)?.feed);
7078
+ return [{ feed, reason: result.reason, activity_id: activity?.id }];
7079
+ });
6840
7080
  this.eventDispatcher.dispatch({
6841
7081
  type: "errors.unhandled",
6842
7082
  error_type: UnhandledErrorType.ReconnectionReconciliation,
@@ -6905,7 +7145,7 @@ class FeedsClient extends FeedsApi {
6905
7145
  };
6906
7146
  this.updateActivity = async (request) => {
6907
7147
  const response = await super.updateActivity(request);
6908
- for (const feed of Object.values(this.activeFeeds)) {
7148
+ for (const feed of this.allActiveFeeds) {
6909
7149
  handleActivityUpdated.bind(feed)(response, false);
6910
7150
  }
6911
7151
  return response;
@@ -6913,7 +7153,7 @@ class FeedsClient extends FeedsApi {
6913
7153
  this.addComment = async (request) => {
6914
7154
  const response = await super.addComment(request);
6915
7155
  const { comment } = response;
6916
- for (const feed of Object.values(this.activeFeeds)) {
7156
+ for (const feed of this.allActiveFeeds) {
6917
7157
  handleCommentAdded.bind(feed)(response, false);
6918
7158
  const parentActivityId = comment.object_id;
6919
7159
  if (feed.hasActivity(parentActivityId)) {
@@ -6936,7 +7176,7 @@ class FeedsClient extends FeedsApi {
6936
7176
  };
6937
7177
  this.updateComment = async (request) => {
6938
7178
  const response = await super.updateComment(request);
6939
- for (const feed of Object.values(this.activeFeeds)) {
7179
+ for (const feed of this.allActiveFeeds) {
6940
7180
  handleCommentUpdated.bind(feed)(response, false);
6941
7181
  }
6942
7182
  return response;
@@ -6944,7 +7184,7 @@ class FeedsClient extends FeedsApi {
6944
7184
  this.deleteComment = async (request) => {
6945
7185
  const response = await super.deleteComment(request);
6946
7186
  const { activity, comment } = response;
6947
- for (const feed of Object.values(this.activeFeeds)) {
7187
+ for (const feed of this.allActiveFeeds) {
6948
7188
  handleCommentDeleted.bind(feed)({ comment }, false);
6949
7189
  updateCommentCount.bind(feed)({
6950
7190
  activity,
@@ -6957,7 +7197,7 @@ class FeedsClient extends FeedsApi {
6957
7197
  this.addActivityReaction = async (request) => {
6958
7198
  const shouldEnforceUnique = request.enforce_unique;
6959
7199
  const response = await super.addActivityReaction(request);
6960
- for (const feed of Object.values(this.activeFeeds)) {
7200
+ for (const feed of this.allActiveFeeds) {
6961
7201
  if (shouldEnforceUnique) {
6962
7202
  handleActivityReactionUpdated.bind(feed)(response, false);
6963
7203
  } else {
@@ -6971,7 +7211,7 @@ class FeedsClient extends FeedsApi {
6971
7211
  };
6972
7212
  this.deleteActivityReaction = async (request) => {
6973
7213
  const response = await super.deleteActivityReaction(request);
6974
- for (const feed of Object.values(this.activeFeeds)) {
7214
+ for (const feed of this.allActiveFeeds) {
6975
7215
  handleActivityReactionDeleted.bind(feed)(response, false);
6976
7216
  }
6977
7217
  return response;
@@ -6979,7 +7219,7 @@ class FeedsClient extends FeedsApi {
6979
7219
  this.addCommentReaction = async (request) => {
6980
7220
  const shouldEnforceUnique = request.enforce_unique;
6981
7221
  const response = await super.addCommentReaction(request);
6982
- for (const feed of Object.values(this.activeFeeds)) {
7222
+ for (const feed of this.allActiveFeeds) {
6983
7223
  if (shouldEnforceUnique) {
6984
7224
  handleCommentReactionUpdated.bind(feed)(response, false);
6985
7225
  } else {
@@ -6990,7 +7230,7 @@ class FeedsClient extends FeedsApi {
6990
7230
  };
6991
7231
  this.deleteCommentReaction = async (request) => {
6992
7232
  const response = await super.deleteCommentReaction(request);
6993
- for (const feed of Object.values(this.activeFeeds)) {
7233
+ for (const feed of this.allActiveFeeds) {
6994
7234
  handleCommentReactionDeleted.bind(feed)(response, false);
6995
7235
  }
6996
7236
  return response;
@@ -7020,6 +7260,8 @@ class FeedsClient extends FeedsApi {
7020
7260
  this.connectionIdManager.reset();
7021
7261
  this.tokenManager.reset();
7022
7262
  this.polls_by_id.clear();
7263
+ this.activeActivities = {};
7264
+ this.activeFeeds = {};
7023
7265
  this.state.partialNext({
7024
7266
  connected_user: void 0,
7025
7267
  is_ws_connection_healthy: false,
@@ -7040,6 +7282,14 @@ class FeedsClient extends FeedsApi {
7040
7282
  options2?.activityAddedEventFilter
7041
7283
  );
7042
7284
  };
7285
+ this.activityWithStateUpdates = (id) => {
7286
+ let activity = this.activeActivities[id];
7287
+ if (!activity) {
7288
+ activity = new ActivityWithStateUpdates(id, this);
7289
+ this.activeActivities[id] = activity;
7290
+ }
7291
+ return activity;
7292
+ };
7043
7293
  this.updateNetworkConnectionStatus = (event) => {
7044
7294
  const networkEvent = {
7045
7295
  type: "network.changed",
@@ -7080,7 +7330,7 @@ class FeedsClient extends FeedsApi {
7080
7330
  feedsLoggerSystem.configureLoggers(options?.configure_loggers_options);
7081
7331
  this.on("all", (event) => {
7082
7332
  const fid = event.fid;
7083
- const feed = typeof fid === "string" ? this.activeFeeds[fid] : void 0;
7333
+ const feeds = this.findAllActiveFeedsFromWSEvent(event);
7084
7334
  switch (event.type) {
7085
7335
  case "connection.changed": {
7086
7336
  const { online } = event;
@@ -7088,14 +7338,14 @@ class FeedsClient extends FeedsApi {
7088
7338
  if (online) {
7089
7339
  this.recoverOnReconnect();
7090
7340
  } else {
7091
- for (const activeFeed of Object.values(this.activeFeeds)) {
7341
+ for (const activeFeed of this.allActiveFeeds) {
7092
7342
  handleWatchStopped.bind(activeFeed)();
7093
7343
  }
7094
7344
  }
7095
7345
  break;
7096
7346
  }
7097
7347
  case "feeds.feed.created": {
7098
- if (feed) break;
7348
+ if (this.activeFeeds[event.feed.id]) break;
7099
7349
  this.getOrCreateActiveFeed(
7100
7350
  event.feed.group_id,
7101
7351
  event.feed.id,
@@ -7104,9 +7354,15 @@ class FeedsClient extends FeedsApi {
7104
7354
  break;
7105
7355
  }
7106
7356
  case "feeds.feed.deleted": {
7107
- feed?.handleWSEvent(event);
7357
+ feeds.forEach((f) => f.handleWSEvent(event));
7108
7358
  if (typeof fid === "string") {
7109
7359
  delete this.activeFeeds[fid];
7360
+ Object.keys(this.activeActivities).forEach((activityId) => {
7361
+ const activity = this.activeActivities[activityId];
7362
+ if (getFeed.call(activity)?.feed === fid) {
7363
+ delete this.activeActivities[activityId];
7364
+ }
7365
+ });
7110
7366
  }
7111
7367
  break;
7112
7368
  }
@@ -7119,7 +7375,7 @@ class FeedsClient extends FeedsApi {
7119
7375
  case "feeds.poll.deleted": {
7120
7376
  if (event.poll?.id) {
7121
7377
  this.polls_by_id.delete(event.poll.id);
7122
- for (const activeFeed of Object.values(this.activeFeeds)) {
7378
+ for (const activeFeed of this.allActiveFeeds) {
7123
7379
  const currentActivities = activeFeed.currentState.activities;
7124
7380
  if (currentActivities) {
7125
7381
  const newActivities = [];
@@ -7167,14 +7423,14 @@ class FeedsClient extends FeedsApi {
7167
7423
  case "feeds.bookmark.deleted":
7168
7424
  case "feeds.bookmark.updated": {
7169
7425
  const activityId = event.bookmark.activity.id;
7170
- const feeds = this.findActiveFeedsByActivityId(activityId);
7171
- feeds.forEach((f) => f.handleWSEvent(event));
7426
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7427
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7172
7428
  break;
7173
7429
  }
7174
7430
  case "feeds.activity.feedback": {
7175
7431
  const activityId = event.activity_feedback.activity_id;
7176
- const feeds = this.findActiveFeedsByActivityId(activityId);
7177
- feeds.forEach((f) => f.handleWSEvent(event));
7432
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7433
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7178
7434
  break;
7179
7435
  }
7180
7436
  case "user.updated": {
@@ -7182,11 +7438,20 @@ class FeedsClient extends FeedsApi {
7182
7438
  break;
7183
7439
  }
7184
7440
  default: {
7185
- feed?.handleWSEvent(event);
7441
+ feeds.forEach((f) => f.handleWSEvent(event));
7442
+ if (event.type === "feeds.activity.deleted") {
7443
+ delete this.activeActivities[event.activity.id];
7444
+ }
7186
7445
  }
7187
7446
  }
7188
7447
  });
7189
7448
  }
7449
+ get allActiveFeeds() {
7450
+ return [
7451
+ ...Object.values(this.activeFeeds),
7452
+ ...Object.values(this.activeActivities).filter((a) => !!getFeed.call(a)).map((a) => getFeed.call(a))
7453
+ ];
7454
+ }
7190
7455
  hydratePollCache(activities) {
7191
7456
  for (const activity of activities) {
7192
7457
  if (!activity.poll) {
@@ -7258,10 +7523,8 @@ class FeedsClient extends FeedsApi {
7258
7523
  response.follow.source_feed.feed,
7259
7524
  response.follow.target_feed.feed
7260
7525
  ].forEach((fid) => {
7261
- const feed = this.activeFeeds[fid];
7262
- if (feed) {
7263
- handleFollowUpdated.bind(feed)(response, false);
7264
- }
7526
+ const feeds = this.findAllActiveFeedsByFid(fid);
7527
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
7265
7528
  });
7266
7529
  return response;
7267
7530
  }
@@ -7272,30 +7535,24 @@ class FeedsClient extends FeedsApi {
7272
7535
  response.follow.source_feed.feed,
7273
7536
  response.follow.target_feed.feed
7274
7537
  ].forEach((fid) => {
7275
- const feed = this.activeFeeds[fid];
7276
- if (feed) {
7277
- handleFollowCreated.bind(feed)(response, false);
7278
- }
7538
+ const feeds = this.findAllActiveFeedsByFid(fid);
7539
+ feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
7279
7540
  });
7280
7541
  return response;
7281
7542
  }
7282
7543
  async followBatch(request) {
7283
7544
  const response = await super.followBatch(request);
7284
7545
  response.follows.forEach((follow) => {
7285
- const feed = this.activeFeeds[follow.source_feed.feed];
7286
- if (feed) {
7287
- handleFollowCreated.bind(feed)({ follow });
7288
- }
7546
+ const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
7547
+ feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
7289
7548
  });
7290
7549
  return response;
7291
7550
  }
7292
7551
  async unfollow(request) {
7293
7552
  const response = await super.unfollow(request);
7294
7553
  [request.source, request.target].forEach((fid) => {
7295
- const feed = this.activeFeeds[fid];
7296
- if (feed) {
7297
- handleFollowDeleted.bind(feed)(response, false);
7298
- }
7554
+ const feeds = this.findAllActiveFeedsByFid(fid);
7555
+ feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
7299
7556
  });
7300
7557
  return response;
7301
7558
  }
@@ -7305,19 +7562,65 @@ class FeedsClient extends FeedsApi {
7305
7562
  ...request,
7306
7563
  connection_id: connectionId
7307
7564
  });
7308
- const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
7309
- if (feed) {
7310
- handleWatchStopped.bind(feed)();
7565
+ const feeds = this.findAllActiveFeedsByFid(
7566
+ `${request.feed_group_id}:${request.feed_id}`
7567
+ );
7568
+ feeds.forEach((f) => handleWatchStopped.bind(f)());
7569
+ return response;
7570
+ }
7571
+ async getOrCreateFeed(request) {
7572
+ const response = await super.getOrCreateFeed(request);
7573
+ this.hydrateCapabilitiesCache([response.feed]);
7574
+ if (request.watch) {
7575
+ const feeds = this.findAllActiveFeedsByFid(
7576
+ `${request.feed_group_id}:${request.feed_id}`
7577
+ );
7578
+ feeds.forEach((f) => handleWatchStarted.bind(f)());
7311
7579
  }
7312
7580
  return response;
7313
7581
  }
7314
- findActiveFeedsByActivityId(activityId) {
7315
- return Object.values(this.activeFeeds).filter(
7582
+ findAllActiveFeedsByActivityId(activityId) {
7583
+ return [
7584
+ ...Object.values(this.activeFeeds),
7585
+ ...Object.values(this.activeActivities).filter((a) => !!getFeed.call(a)).map((a) => getFeed.call(a))
7586
+ ].filter(
7316
7587
  (feed) => feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId)
7317
7588
  );
7318
7589
  }
7590
+ findAllActiveFeedsByFid(fid) {
7591
+ if (!fid) return [];
7592
+ const activeFeed = this.activeFeeds[fid];
7593
+ return [
7594
+ ...activeFeed ? [activeFeed] : [],
7595
+ ...Object.values(this.activeActivities).filter((a) => getFeed.call(a)?.feed === fid).map((a) => getFeed.call(a))
7596
+ ];
7597
+ }
7598
+ /**
7599
+ * When updating from WS events we need a special logic:
7600
+ * - Find active feeds that match a given fid.
7601
+ * - Find active feed from activities where fid matches any of the feeds the activity is posted to.
7602
+ *
7603
+ * This logic is different from `findAllActiveFeedsByFid` which only checks the first feed an activity is posted to.
7604
+ *
7605
+ * @param fid
7606
+ * @param activityId
7607
+ * @returns
7608
+ */
7609
+ findAllActiveFeedsFromWSEvent(event) {
7610
+ const fid = "fid" in event ? event.fid : void 0;
7611
+ if (!fid) return [];
7612
+ const activeFeed = fid ? this.activeFeeds[fid] : void 0;
7613
+ return [
7614
+ ...activeFeed ? [activeFeed] : [],
7615
+ ...Object.values(this.activeActivities).filter((a) => {
7616
+ const feed = getFeed.call(a);
7617
+ return feed?.feed === fid || a.currentState.activity?.feeds.some((f) => f === fid);
7618
+ }).map((a) => getFeed.call(a))
7619
+ ];
7620
+ }
7319
7621
  }
7320
7622
  export {
7623
+ ActivityWithStateUpdates as A,
7321
7624
  Constants as C,
7322
7625
  FeedsClient as F,
7323
7626
  StreamApiError as S,
@@ -7339,4 +7642,4 @@ export {
7339
7642
  shouldUpdateState as s,
7340
7643
  uniqueArrayMerge as u
7341
7644
  };
7342
- //# sourceMappingURL=feeds-client-Cd2LsXp-.mjs.map
7645
+ //# sourceMappingURL=feeds-client-DVbsjKUf.mjs.map