@stream-io/feeds-client 0.3.7 → 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 (52) hide show
  1. package/CHANGELOG.md +7 -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/react-bindings.mjs +76 -14
  8. package/dist/es/react-bindings.mjs.map +1 -1
  9. package/dist/{feeds-client-DLiLkrA0.js → feeds-client-CwioZBvA.js} +274 -52
  10. package/dist/feeds-client-CwioZBvA.js.map +1 -0
  11. package/dist/{feeds-client-3aXF89xy.mjs → feeds-client-DVbsjKUf.mjs} +274 -52
  12. package/dist/feeds-client-DVbsjKUf.mjs.map +1 -0
  13. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts +49 -0
  14. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -0
  15. package/dist/types/activity-with-state-updates/get-feed.d.ts +3 -0
  16. package/dist/types/activity-with-state-updates/get-feed.d.ts.map +1 -0
  17. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts +1 -0
  18. package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts.map +1 -1
  19. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts +32 -0
  20. package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts.map +1 -0
  21. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts +4 -0
  22. package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts.map +1 -1
  23. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
  24. package/dist/types/bindings/react/hooks/useCreateFeedsClient.d.ts.map +1 -1
  25. package/dist/types/common/real-time/event-models.d.ts +1 -0
  26. package/dist/types/common/real-time/event-models.d.ts.map +1 -1
  27. package/dist/types/feed/feed.d.ts +1 -1
  28. package/dist/types/feed/feed.d.ts.map +1 -1
  29. package/dist/types/feeds-client/active-activity.d.ts +8 -0
  30. package/dist/types/feeds-client/active-activity.d.ts.map +1 -0
  31. package/dist/types/feeds-client/feeds-client.d.ts +36 -3
  32. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/types.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/src/activity-with-state-updates/activity-with-state-updates.ts +190 -0
  38. package/src/activity-with-state-updates/get-feed.ts +5 -0
  39. package/src/bindings/react/hooks/feed-state-hooks/index.ts +1 -0
  40. package/src/bindings/react/hooks/feed-state-hooks/useActivityComments.ts +113 -0
  41. package/src/bindings/react/hooks/feed-state-hooks/useComments.ts +4 -0
  42. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +12 -9
  43. package/src/bindings/react/hooks/useCreateFeedsClient.ts +0 -6
  44. package/src/common/real-time/event-models.ts +5 -1
  45. package/src/feed/feed.ts +16 -6
  46. package/src/feeds-client/active-activity.ts +42 -0
  47. package/src/feeds-client/feeds-client.ts +162 -53
  48. package/src/index.ts +1 -0
  49. package/src/test-utils/response-generators.ts +1 -0
  50. package/src/types.ts +8 -10
  51. package/dist/feeds-client-3aXF89xy.mjs.map +0 -1
  52. package/dist/feeds-client-DLiLkrA0.js.map +0 -1
@@ -3844,7 +3844,7 @@ const getRateLimitFromResponseHeader = (response_headers) => {
3844
3844
  };
3845
3845
  return result;
3846
3846
  };
3847
- const version = "0.3.7";
3847
+ const version = "0.3.8";
3848
3848
  class ApiClient {
3849
3849
  constructor(apiKey, tokenManager, connectionIdManager, options) {
3850
3850
  this.apiKey = apiKey;
@@ -6480,7 +6480,7 @@ const _Feed = class _Feed extends FeedApi {
6480
6480
  }
6481
6481
  }
6482
6482
  async loadNextPageActivityComments(activity, request) {
6483
- 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];
6484
6484
  const currentPagination = currentEntityState?.pagination;
6485
6485
  const currentNextCursor = currentPagination?.next;
6486
6486
  const currentSort = currentPagination?.sort;
@@ -6489,12 +6489,13 @@ const _Feed = class _Feed extends FeedApi {
6489
6489
  if (isLoading || !checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
6490
6490
  return;
6491
6491
  }
6492
+ const entityId = typeof activity === "string" ? activity : activity.id;
6492
6493
  await this.loadNextPageComments({
6493
- entityId: activity.id,
6494
+ entityId,
6494
6495
  base: () => this.client.getComments({
6495
6496
  ...request,
6496
6497
  sort,
6497
- object_id: activity.id,
6498
+ object_id: entityId,
6498
6499
  object_type: "activity",
6499
6500
  next: currentNextCursor
6500
6501
  }),
@@ -6729,7 +6730,7 @@ const _Feed = class _Feed extends FeedApi {
6729
6730
  eventHandler?.(event);
6730
6731
  }
6731
6732
  if (typeof eventHandler === "undefined") {
6732
- console.warn(`Received unknown event type: ${event.type}`, event);
6733
+ feedsLoggerSystem.getLogger("event-dispatcher").warn(`Received unknown feed event, type: ${event.type}`, event);
6733
6734
  }
6734
6735
  this.eventDispatcher.dispatch(event);
6735
6736
  }
@@ -6871,6 +6872,156 @@ function queueBatchedOwnCapabilities({ feeds }) {
6871
6872
  function clearQueuedFeeds() {
6872
6873
  queuedFeeds.clear();
6873
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
+ }
6874
7025
  class FeedsClient extends FeedsApi {
6875
7026
  constructor(apiKey, options) {
6876
7027
  const tokenManager = new TokenManager();
@@ -6883,6 +7034,7 @@ class FeedsClient extends FeedsApi {
6883
7034
  );
6884
7035
  super(apiClient);
6885
7036
  this.eventDispatcher = new EventDispatcher();
7037
+ this.activeActivities = {};
6886
7038
  this.activeFeeds = {};
6887
7039
  this.healthyConnectionChangedEventCount = 0;
6888
7040
  this.setGetBatchOwnCapabilitiesThrottlingInterval = (throttlingMs) => {
@@ -6911,13 +7063,20 @@ class FeedsClient extends FeedsApi {
6911
7063
  this.recoverOnReconnect = async () => {
6912
7064
  this.healthyConnectionChangedEventCount++;
6913
7065
  if (this.healthyConnectionChangedEventCount > 1) {
6914
- const entries = Object.entries(this.activeFeeds);
6915
- const results = await Promise.allSettled(
6916
- entries.map(([, feed]) => feed.synchronize())
6917
- );
6918
- const failures = results.flatMap(
6919
- (result, index) => result.status === "rejected" ? [{ feed: entries[index][0], reason: result.reason }] : []
6920
- );
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
+ });
6921
7080
  this.eventDispatcher.dispatch({
6922
7081
  type: "errors.unhandled",
6923
7082
  error_type: UnhandledErrorType.ReconnectionReconciliation,
@@ -6986,7 +7145,7 @@ class FeedsClient extends FeedsApi {
6986
7145
  };
6987
7146
  this.updateActivity = async (request) => {
6988
7147
  const response = await super.updateActivity(request);
6989
- for (const feed of Object.values(this.activeFeeds)) {
7148
+ for (const feed of this.allActiveFeeds) {
6990
7149
  handleActivityUpdated.bind(feed)(response, false);
6991
7150
  }
6992
7151
  return response;
@@ -6994,7 +7153,7 @@ class FeedsClient extends FeedsApi {
6994
7153
  this.addComment = async (request) => {
6995
7154
  const response = await super.addComment(request);
6996
7155
  const { comment } = response;
6997
- for (const feed of Object.values(this.activeFeeds)) {
7156
+ for (const feed of this.allActiveFeeds) {
6998
7157
  handleCommentAdded.bind(feed)(response, false);
6999
7158
  const parentActivityId = comment.object_id;
7000
7159
  if (feed.hasActivity(parentActivityId)) {
@@ -7017,7 +7176,7 @@ class FeedsClient extends FeedsApi {
7017
7176
  };
7018
7177
  this.updateComment = async (request) => {
7019
7178
  const response = await super.updateComment(request);
7020
- for (const feed of Object.values(this.activeFeeds)) {
7179
+ for (const feed of this.allActiveFeeds) {
7021
7180
  handleCommentUpdated.bind(feed)(response, false);
7022
7181
  }
7023
7182
  return response;
@@ -7025,7 +7184,7 @@ class FeedsClient extends FeedsApi {
7025
7184
  this.deleteComment = async (request) => {
7026
7185
  const response = await super.deleteComment(request);
7027
7186
  const { activity, comment } = response;
7028
- for (const feed of Object.values(this.activeFeeds)) {
7187
+ for (const feed of this.allActiveFeeds) {
7029
7188
  handleCommentDeleted.bind(feed)({ comment }, false);
7030
7189
  updateCommentCount.bind(feed)({
7031
7190
  activity,
@@ -7038,7 +7197,7 @@ class FeedsClient extends FeedsApi {
7038
7197
  this.addActivityReaction = async (request) => {
7039
7198
  const shouldEnforceUnique = request.enforce_unique;
7040
7199
  const response = await super.addActivityReaction(request);
7041
- for (const feed of Object.values(this.activeFeeds)) {
7200
+ for (const feed of this.allActiveFeeds) {
7042
7201
  if (shouldEnforceUnique) {
7043
7202
  handleActivityReactionUpdated.bind(feed)(response, false);
7044
7203
  } else {
@@ -7052,7 +7211,7 @@ class FeedsClient extends FeedsApi {
7052
7211
  };
7053
7212
  this.deleteActivityReaction = async (request) => {
7054
7213
  const response = await super.deleteActivityReaction(request);
7055
- for (const feed of Object.values(this.activeFeeds)) {
7214
+ for (const feed of this.allActiveFeeds) {
7056
7215
  handleActivityReactionDeleted.bind(feed)(response, false);
7057
7216
  }
7058
7217
  return response;
@@ -7060,7 +7219,7 @@ class FeedsClient extends FeedsApi {
7060
7219
  this.addCommentReaction = async (request) => {
7061
7220
  const shouldEnforceUnique = request.enforce_unique;
7062
7221
  const response = await super.addCommentReaction(request);
7063
- for (const feed of Object.values(this.activeFeeds)) {
7222
+ for (const feed of this.allActiveFeeds) {
7064
7223
  if (shouldEnforceUnique) {
7065
7224
  handleCommentReactionUpdated.bind(feed)(response, false);
7066
7225
  } else {
@@ -7071,7 +7230,7 @@ class FeedsClient extends FeedsApi {
7071
7230
  };
7072
7231
  this.deleteCommentReaction = async (request) => {
7073
7232
  const response = await super.deleteCommentReaction(request);
7074
- for (const feed of Object.values(this.activeFeeds)) {
7233
+ for (const feed of this.allActiveFeeds) {
7075
7234
  handleCommentReactionDeleted.bind(feed)(response, false);
7076
7235
  }
7077
7236
  return response;
@@ -7101,6 +7260,8 @@ class FeedsClient extends FeedsApi {
7101
7260
  this.connectionIdManager.reset();
7102
7261
  this.tokenManager.reset();
7103
7262
  this.polls_by_id.clear();
7263
+ this.activeActivities = {};
7264
+ this.activeFeeds = {};
7104
7265
  this.state.partialNext({
7105
7266
  connected_user: void 0,
7106
7267
  is_ws_connection_healthy: false,
@@ -7121,6 +7282,14 @@ class FeedsClient extends FeedsApi {
7121
7282
  options2?.activityAddedEventFilter
7122
7283
  );
7123
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
+ };
7124
7293
  this.updateNetworkConnectionStatus = (event) => {
7125
7294
  const networkEvent = {
7126
7295
  type: "network.changed",
@@ -7161,7 +7330,7 @@ class FeedsClient extends FeedsApi {
7161
7330
  feedsLoggerSystem.configureLoggers(options?.configure_loggers_options);
7162
7331
  this.on("all", (event) => {
7163
7332
  const fid = event.fid;
7164
- const feed = typeof fid === "string" ? this.activeFeeds[fid] : void 0;
7333
+ const feeds = this.findAllActiveFeedsFromWSEvent(event);
7165
7334
  switch (event.type) {
7166
7335
  case "connection.changed": {
7167
7336
  const { online } = event;
@@ -7169,14 +7338,14 @@ class FeedsClient extends FeedsApi {
7169
7338
  if (online) {
7170
7339
  this.recoverOnReconnect();
7171
7340
  } else {
7172
- for (const activeFeed of Object.values(this.activeFeeds)) {
7341
+ for (const activeFeed of this.allActiveFeeds) {
7173
7342
  handleWatchStopped.bind(activeFeed)();
7174
7343
  }
7175
7344
  }
7176
7345
  break;
7177
7346
  }
7178
7347
  case "feeds.feed.created": {
7179
- if (feed) break;
7348
+ if (this.activeFeeds[event.feed.id]) break;
7180
7349
  this.getOrCreateActiveFeed(
7181
7350
  event.feed.group_id,
7182
7351
  event.feed.id,
@@ -7185,9 +7354,15 @@ class FeedsClient extends FeedsApi {
7185
7354
  break;
7186
7355
  }
7187
7356
  case "feeds.feed.deleted": {
7188
- feed?.handleWSEvent(event);
7357
+ feeds.forEach((f) => f.handleWSEvent(event));
7189
7358
  if (typeof fid === "string") {
7190
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
+ });
7191
7366
  }
7192
7367
  break;
7193
7368
  }
@@ -7200,7 +7375,7 @@ class FeedsClient extends FeedsApi {
7200
7375
  case "feeds.poll.deleted": {
7201
7376
  if (event.poll?.id) {
7202
7377
  this.polls_by_id.delete(event.poll.id);
7203
- for (const activeFeed of Object.values(this.activeFeeds)) {
7378
+ for (const activeFeed of this.allActiveFeeds) {
7204
7379
  const currentActivities = activeFeed.currentState.activities;
7205
7380
  if (currentActivities) {
7206
7381
  const newActivities = [];
@@ -7248,14 +7423,14 @@ class FeedsClient extends FeedsApi {
7248
7423
  case "feeds.bookmark.deleted":
7249
7424
  case "feeds.bookmark.updated": {
7250
7425
  const activityId = event.bookmark.activity.id;
7251
- const feeds = this.findActiveFeedsByActivityId(activityId);
7252
- feeds.forEach((f) => f.handleWSEvent(event));
7426
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7427
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7253
7428
  break;
7254
7429
  }
7255
7430
  case "feeds.activity.feedback": {
7256
7431
  const activityId = event.activity_feedback.activity_id;
7257
- const feeds = this.findActiveFeedsByActivityId(activityId);
7258
- feeds.forEach((f) => f.handleWSEvent(event));
7432
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7433
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7259
7434
  break;
7260
7435
  }
7261
7436
  case "user.updated": {
@@ -7263,11 +7438,20 @@ class FeedsClient extends FeedsApi {
7263
7438
  break;
7264
7439
  }
7265
7440
  default: {
7266
- 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
+ }
7267
7445
  }
7268
7446
  }
7269
7447
  });
7270
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
+ }
7271
7455
  hydratePollCache(activities) {
7272
7456
  for (const activity of activities) {
7273
7457
  if (!activity.poll) {
@@ -7339,10 +7523,8 @@ class FeedsClient extends FeedsApi {
7339
7523
  response.follow.source_feed.feed,
7340
7524
  response.follow.target_feed.feed
7341
7525
  ].forEach((fid) => {
7342
- const feed = this.activeFeeds[fid];
7343
- if (feed) {
7344
- handleFollowUpdated.bind(feed)(response, false);
7345
- }
7526
+ const feeds = this.findAllActiveFeedsByFid(fid);
7527
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
7346
7528
  });
7347
7529
  return response;
7348
7530
  }
@@ -7353,30 +7535,24 @@ class FeedsClient extends FeedsApi {
7353
7535
  response.follow.source_feed.feed,
7354
7536
  response.follow.target_feed.feed
7355
7537
  ].forEach((fid) => {
7356
- const feed = this.activeFeeds[fid];
7357
- if (feed) {
7358
- handleFollowCreated.bind(feed)(response, false);
7359
- }
7538
+ const feeds = this.findAllActiveFeedsByFid(fid);
7539
+ feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
7360
7540
  });
7361
7541
  return response;
7362
7542
  }
7363
7543
  async followBatch(request) {
7364
7544
  const response = await super.followBatch(request);
7365
7545
  response.follows.forEach((follow) => {
7366
- const feed = this.activeFeeds[follow.source_feed.feed];
7367
- if (feed) {
7368
- handleFollowCreated.bind(feed)({ follow });
7369
- }
7546
+ const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
7547
+ feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
7370
7548
  });
7371
7549
  return response;
7372
7550
  }
7373
7551
  async unfollow(request) {
7374
7552
  const response = await super.unfollow(request);
7375
7553
  [request.source, request.target].forEach((fid) => {
7376
- const feed = this.activeFeeds[fid];
7377
- if (feed) {
7378
- handleFollowDeleted.bind(feed)(response, false);
7379
- }
7554
+ const feeds = this.findAllActiveFeedsByFid(fid);
7555
+ feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
7380
7556
  });
7381
7557
  return response;
7382
7558
  }
@@ -7386,19 +7562,65 @@ class FeedsClient extends FeedsApi {
7386
7562
  ...request,
7387
7563
  connection_id: connectionId
7388
7564
  });
7389
- const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
7390
- if (feed) {
7391
- 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)());
7392
7579
  }
7393
7580
  return response;
7394
7581
  }
7395
- findActiveFeedsByActivityId(activityId) {
7396
- 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(
7397
7587
  (feed) => feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId)
7398
7588
  );
7399
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
+ }
7400
7621
  }
7401
7622
  export {
7623
+ ActivityWithStateUpdates as A,
7402
7624
  Constants as C,
7403
7625
  FeedsClient as F,
7404
7626
  StreamApiError as S,
@@ -7420,4 +7642,4 @@ export {
7420
7642
  shouldUpdateState as s,
7421
7643
  uniqueArrayMerge as u
7422
7644
  };
7423
- //# sourceMappingURL=feeds-client-3aXF89xy.mjs.map
7645
+ //# sourceMappingURL=feeds-client-DVbsjKUf.mjs.map