@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
@@ -3862,7 +3862,7 @@ const getRateLimitFromResponseHeader = (response_headers) => {
3862
3862
  };
3863
3863
  return result;
3864
3864
  };
3865
- const version = "0.3.7";
3865
+ const version = "0.3.8";
3866
3866
  class ApiClient {
3867
3867
  constructor(apiKey, tokenManager, connectionIdManager, options) {
3868
3868
  this.apiKey = apiKey;
@@ -6498,7 +6498,7 @@ const _Feed = class _Feed extends FeedApi {
6498
6498
  }
6499
6499
  }
6500
6500
  async loadNextPageActivityComments(activity, request) {
6501
- const currentEntityState = this.currentState.comments_by_entity_id[activity.id];
6501
+ const currentEntityState = this.currentState.comments_by_entity_id[typeof activity === "string" ? activity : activity.id];
6502
6502
  const currentPagination = currentEntityState?.pagination;
6503
6503
  const currentNextCursor = currentPagination?.next;
6504
6504
  const currentSort = currentPagination?.sort;
@@ -6507,12 +6507,13 @@ const _Feed = class _Feed extends FeedApi {
6507
6507
  if (isLoading || !checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
6508
6508
  return;
6509
6509
  }
6510
+ const entityId = typeof activity === "string" ? activity : activity.id;
6510
6511
  await this.loadNextPageComments({
6511
- entityId: activity.id,
6512
+ entityId,
6512
6513
  base: () => this.client.getComments({
6513
6514
  ...request,
6514
6515
  sort,
6515
- object_id: activity.id,
6516
+ object_id: entityId,
6516
6517
  object_type: "activity",
6517
6518
  next: currentNextCursor
6518
6519
  }),
@@ -6747,7 +6748,7 @@ const _Feed = class _Feed extends FeedApi {
6747
6748
  eventHandler?.(event);
6748
6749
  }
6749
6750
  if (typeof eventHandler === "undefined") {
6750
- console.warn(`Received unknown event type: ${event.type}`, event);
6751
+ feedsLoggerSystem.getLogger("event-dispatcher").warn(`Received unknown feed event, type: ${event.type}`, event);
6751
6752
  }
6752
6753
  this.eventDispatcher.dispatch(event);
6753
6754
  }
@@ -6889,6 +6890,156 @@ function queueBatchedOwnCapabilities({ feeds }) {
6889
6890
  function clearQueuedFeeds() {
6890
6891
  queuedFeeds.clear();
6891
6892
  }
6893
+ function connectActivityToFeed({
6894
+ fid
6895
+ }) {
6896
+ const [group, id] = fid.split(":");
6897
+ const activeFeed = this.activeFeeds[fid];
6898
+ const feed = new Feed(
6899
+ this,
6900
+ group,
6901
+ id,
6902
+ void 0,
6903
+ activeFeed?.currentState.watch
6904
+ );
6905
+ return feed;
6906
+ }
6907
+ function isAnyFeedWatched(fids) {
6908
+ for (const fid of fids) {
6909
+ const feed = this.activeFeeds[fid];
6910
+ if (feed && feed.currentState.last_get_or_create_request_config?.watch) {
6911
+ return true;
6912
+ }
6913
+ }
6914
+ return false;
6915
+ }
6916
+ function disconnectActivityFromFeed(id) {
6917
+ const activeFeed = this.activeActivities[id];
6918
+ if (activeFeed) {
6919
+ delete this.activeActivities[id];
6920
+ }
6921
+ }
6922
+ class ActivityWithStateUpdates {
6923
+ constructor(id, feedsClient) {
6924
+ this.id = id;
6925
+ this.feedsClient = feedsClient;
6926
+ this.state = new stateStore.StateStore({
6927
+ activity: void 0,
6928
+ comments_by_entity_id: {},
6929
+ is_loading: false
6930
+ });
6931
+ }
6932
+ get currentState() {
6933
+ return this.state.getLatestValue();
6934
+ }
6935
+ get feeds() {
6936
+ return this.currentState.activity?.feeds ?? [];
6937
+ }
6938
+ /**
6939
+ * Fetch activity and load it into state
6940
+ * @param watch - Whether to watch the feed the activity belongs to for real-time updates
6941
+ * @param feed - The feed to watch. Use only if the activity belongs to multiple feeds and you want to specify the feed explicitly.
6942
+ * @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.
6943
+ */
6944
+ async get(request = {}) {
6945
+ if (this.inProgressGet && deepEqual(this.inProgressGet.request, request)) {
6946
+ return this.inProgressGet.promise;
6947
+ }
6948
+ const { comments } = request;
6949
+ this.state.partialNext({
6950
+ is_loading: true,
6951
+ last_get_request_config: request
6952
+ });
6953
+ const getActivityRequest = this.feedsClient.getActivity({
6954
+ id: this.id
6955
+ }).then((response) => response.activity);
6956
+ this.inProgressGet = { request, promise: getActivityRequest };
6957
+ const activityResponse = await getActivityRequest;
6958
+ this.feedsClient.hydratePollCache([activityResponse]);
6959
+ this.setFeed({
6960
+ // We set feed to first containing feed
6961
+ // 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
6962
+ // This is a bit hacky, proper solution would be to refactor all activity event handlers and detach them from feed instance
6963
+ fid: activityResponse.feeds[0],
6964
+ initialState: activityResponse
6965
+ });
6966
+ if (this.feed) {
6967
+ this.feed.activityAddedEventFilter = () => false;
6968
+ }
6969
+ if (comments) {
6970
+ await this.loadNextPageActivityComments(comments);
6971
+ }
6972
+ this.subscribeToFeedState();
6973
+ this.inProgressGet = void 0;
6974
+ return activityResponse;
6975
+ }
6976
+ loadNextPageActivityComments(request) {
6977
+ const activity = this.feed?.currentState.activities?.[0];
6978
+ if (!activity || !this.feed) {
6979
+ throw new Error("Initialize activity first");
6980
+ }
6981
+ if (!this.currentState.last_get_request_config?.comments) {
6982
+ this.state.partialNext({
6983
+ last_get_request_config: {
6984
+ ...this.currentState.last_get_request_config,
6985
+ comments: request
6986
+ }
6987
+ });
6988
+ }
6989
+ return this.feed.loadNextPageActivityComments(activity, request);
6990
+ }
6991
+ loadNextPageCommentReplies(...params) {
6992
+ if (!this.feed) {
6993
+ throw new Error("Initialize activity first");
6994
+ }
6995
+ return this.feed.loadNextPageCommentReplies(...params);
6996
+ }
6997
+ dispose() {
6998
+ this.unsubscribeFromFeedState?.();
6999
+ disconnectActivityFromFeed.call(this.feedsClient, this.id);
7000
+ }
7001
+ /**
7002
+ * @internal
7003
+ */
7004
+ async synchronize() {
7005
+ const allFids = this.currentState.activity?.feeds ?? [];
7006
+ if (!isAnyFeedWatched.call(this.feedsClient, allFids)) {
7007
+ return;
7008
+ }
7009
+ this.inProgressGet = void 0;
7010
+ return this.get(this.currentState.last_get_request_config);
7011
+ }
7012
+ setFeed({
7013
+ fid,
7014
+ initialState
7015
+ }) {
7016
+ this.feed = connectActivityToFeed.call(this.feedsClient, { fid });
7017
+ this.feed.state.partialNext({
7018
+ activities: [initialState]
7019
+ });
7020
+ }
7021
+ subscribeToFeedState() {
7022
+ this.unsubscribeFromFeedState?.();
7023
+ this.unsubscribeFromFeedState = this.feed?.state.subscribeWithSelector(
7024
+ (state) => ({
7025
+ activity: state.activities?.find((activity) => activity.id === this.id),
7026
+ comments_by_entity_id: state.comments_by_entity_id
7027
+ }),
7028
+ (state) => {
7029
+ if (state.activity) {
7030
+ this.state.partialNext({
7031
+ activity: state.activity,
7032
+ comments_by_entity_id: state.comments_by_entity_id,
7033
+ is_loading: false
7034
+ });
7035
+ }
7036
+ }
7037
+ );
7038
+ }
7039
+ }
7040
+ function getFeed() {
7041
+ return this.feed;
7042
+ }
6892
7043
  class FeedsClient extends FeedsApi {
6893
7044
  constructor(apiKey, options) {
6894
7045
  const tokenManager = new TokenManager();
@@ -6901,6 +7052,7 @@ class FeedsClient extends FeedsApi {
6901
7052
  );
6902
7053
  super(apiClient);
6903
7054
  this.eventDispatcher = new EventDispatcher();
7055
+ this.activeActivities = {};
6904
7056
  this.activeFeeds = {};
6905
7057
  this.healthyConnectionChangedEventCount = 0;
6906
7058
  this.setGetBatchOwnCapabilitiesThrottlingInterval = (throttlingMs) => {
@@ -6929,13 +7081,20 @@ class FeedsClient extends FeedsApi {
6929
7081
  this.recoverOnReconnect = async () => {
6930
7082
  this.healthyConnectionChangedEventCount++;
6931
7083
  if (this.healthyConnectionChangedEventCount > 1) {
6932
- const entries = Object.entries(this.activeFeeds);
6933
- const results = await Promise.allSettled(
6934
- entries.map(([, feed]) => feed.synchronize())
6935
- );
6936
- const failures = results.flatMap(
6937
- (result, index) => result.status === "rejected" ? [{ feed: entries[index][0], reason: result.reason }] : []
6938
- );
7084
+ const feedEntries = Object.entries(this.activeFeeds);
7085
+ const activityEntries = Object.entries(this.activeActivities);
7086
+ const results = await Promise.allSettled([
7087
+ ...feedEntries.map(([, feed]) => feed.synchronize()),
7088
+ ...activityEntries.map(([, activity]) => activity.synchronize())
7089
+ ]);
7090
+ const failures = results.flatMap((result, index) => {
7091
+ if (result.status === "fulfilled") {
7092
+ return [];
7093
+ }
7094
+ const activity = activityEntries[index - feedEntries.length]?.[1];
7095
+ const feed = feedEntries[index]?.[0] ?? (activity && getFeed.call(activity)?.feed);
7096
+ return [{ feed, reason: result.reason, activity_id: activity?.id }];
7097
+ });
6939
7098
  this.eventDispatcher.dispatch({
6940
7099
  type: "errors.unhandled",
6941
7100
  error_type: UnhandledErrorType.ReconnectionReconciliation,
@@ -7004,7 +7163,7 @@ class FeedsClient extends FeedsApi {
7004
7163
  };
7005
7164
  this.updateActivity = async (request) => {
7006
7165
  const response = await super.updateActivity(request);
7007
- for (const feed of Object.values(this.activeFeeds)) {
7166
+ for (const feed of this.allActiveFeeds) {
7008
7167
  handleActivityUpdated.bind(feed)(response, false);
7009
7168
  }
7010
7169
  return response;
@@ -7012,7 +7171,7 @@ class FeedsClient extends FeedsApi {
7012
7171
  this.addComment = async (request) => {
7013
7172
  const response = await super.addComment(request);
7014
7173
  const { comment } = response;
7015
- for (const feed of Object.values(this.activeFeeds)) {
7174
+ for (const feed of this.allActiveFeeds) {
7016
7175
  handleCommentAdded.bind(feed)(response, false);
7017
7176
  const parentActivityId = comment.object_id;
7018
7177
  if (feed.hasActivity(parentActivityId)) {
@@ -7035,7 +7194,7 @@ class FeedsClient extends FeedsApi {
7035
7194
  };
7036
7195
  this.updateComment = async (request) => {
7037
7196
  const response = await super.updateComment(request);
7038
- for (const feed of Object.values(this.activeFeeds)) {
7197
+ for (const feed of this.allActiveFeeds) {
7039
7198
  handleCommentUpdated.bind(feed)(response, false);
7040
7199
  }
7041
7200
  return response;
@@ -7043,7 +7202,7 @@ class FeedsClient extends FeedsApi {
7043
7202
  this.deleteComment = async (request) => {
7044
7203
  const response = await super.deleteComment(request);
7045
7204
  const { activity, comment } = response;
7046
- for (const feed of Object.values(this.activeFeeds)) {
7205
+ for (const feed of this.allActiveFeeds) {
7047
7206
  handleCommentDeleted.bind(feed)({ comment }, false);
7048
7207
  updateCommentCount.bind(feed)({
7049
7208
  activity,
@@ -7056,7 +7215,7 @@ class FeedsClient extends FeedsApi {
7056
7215
  this.addActivityReaction = async (request) => {
7057
7216
  const shouldEnforceUnique = request.enforce_unique;
7058
7217
  const response = await super.addActivityReaction(request);
7059
- for (const feed of Object.values(this.activeFeeds)) {
7218
+ for (const feed of this.allActiveFeeds) {
7060
7219
  if (shouldEnforceUnique) {
7061
7220
  handleActivityReactionUpdated.bind(feed)(response, false);
7062
7221
  } else {
@@ -7070,7 +7229,7 @@ class FeedsClient extends FeedsApi {
7070
7229
  };
7071
7230
  this.deleteActivityReaction = async (request) => {
7072
7231
  const response = await super.deleteActivityReaction(request);
7073
- for (const feed of Object.values(this.activeFeeds)) {
7232
+ for (const feed of this.allActiveFeeds) {
7074
7233
  handleActivityReactionDeleted.bind(feed)(response, false);
7075
7234
  }
7076
7235
  return response;
@@ -7078,7 +7237,7 @@ class FeedsClient extends FeedsApi {
7078
7237
  this.addCommentReaction = async (request) => {
7079
7238
  const shouldEnforceUnique = request.enforce_unique;
7080
7239
  const response = await super.addCommentReaction(request);
7081
- for (const feed of Object.values(this.activeFeeds)) {
7240
+ for (const feed of this.allActiveFeeds) {
7082
7241
  if (shouldEnforceUnique) {
7083
7242
  handleCommentReactionUpdated.bind(feed)(response, false);
7084
7243
  } else {
@@ -7089,7 +7248,7 @@ class FeedsClient extends FeedsApi {
7089
7248
  };
7090
7249
  this.deleteCommentReaction = async (request) => {
7091
7250
  const response = await super.deleteCommentReaction(request);
7092
- for (const feed of Object.values(this.activeFeeds)) {
7251
+ for (const feed of this.allActiveFeeds) {
7093
7252
  handleCommentReactionDeleted.bind(feed)(response, false);
7094
7253
  }
7095
7254
  return response;
@@ -7119,6 +7278,8 @@ class FeedsClient extends FeedsApi {
7119
7278
  this.connectionIdManager.reset();
7120
7279
  this.tokenManager.reset();
7121
7280
  this.polls_by_id.clear();
7281
+ this.activeActivities = {};
7282
+ this.activeFeeds = {};
7122
7283
  this.state.partialNext({
7123
7284
  connected_user: void 0,
7124
7285
  is_ws_connection_healthy: false,
@@ -7139,6 +7300,14 @@ class FeedsClient extends FeedsApi {
7139
7300
  options2?.activityAddedEventFilter
7140
7301
  );
7141
7302
  };
7303
+ this.activityWithStateUpdates = (id) => {
7304
+ let activity = this.activeActivities[id];
7305
+ if (!activity) {
7306
+ activity = new ActivityWithStateUpdates(id, this);
7307
+ this.activeActivities[id] = activity;
7308
+ }
7309
+ return activity;
7310
+ };
7142
7311
  this.updateNetworkConnectionStatus = (event) => {
7143
7312
  const networkEvent = {
7144
7313
  type: "network.changed",
@@ -7179,7 +7348,7 @@ class FeedsClient extends FeedsApi {
7179
7348
  feedsLoggerSystem.configureLoggers(options?.configure_loggers_options);
7180
7349
  this.on("all", (event) => {
7181
7350
  const fid = event.fid;
7182
- const feed = typeof fid === "string" ? this.activeFeeds[fid] : void 0;
7351
+ const feeds = this.findAllActiveFeedsFromWSEvent(event);
7183
7352
  switch (event.type) {
7184
7353
  case "connection.changed": {
7185
7354
  const { online } = event;
@@ -7187,14 +7356,14 @@ class FeedsClient extends FeedsApi {
7187
7356
  if (online) {
7188
7357
  this.recoverOnReconnect();
7189
7358
  } else {
7190
- for (const activeFeed of Object.values(this.activeFeeds)) {
7359
+ for (const activeFeed of this.allActiveFeeds) {
7191
7360
  handleWatchStopped.bind(activeFeed)();
7192
7361
  }
7193
7362
  }
7194
7363
  break;
7195
7364
  }
7196
7365
  case "feeds.feed.created": {
7197
- if (feed) break;
7366
+ if (this.activeFeeds[event.feed.id]) break;
7198
7367
  this.getOrCreateActiveFeed(
7199
7368
  event.feed.group_id,
7200
7369
  event.feed.id,
@@ -7203,9 +7372,15 @@ class FeedsClient extends FeedsApi {
7203
7372
  break;
7204
7373
  }
7205
7374
  case "feeds.feed.deleted": {
7206
- feed?.handleWSEvent(event);
7375
+ feeds.forEach((f) => f.handleWSEvent(event));
7207
7376
  if (typeof fid === "string") {
7208
7377
  delete this.activeFeeds[fid];
7378
+ Object.keys(this.activeActivities).forEach((activityId) => {
7379
+ const activity = this.activeActivities[activityId];
7380
+ if (getFeed.call(activity)?.feed === fid) {
7381
+ delete this.activeActivities[activityId];
7382
+ }
7383
+ });
7209
7384
  }
7210
7385
  break;
7211
7386
  }
@@ -7218,7 +7393,7 @@ class FeedsClient extends FeedsApi {
7218
7393
  case "feeds.poll.deleted": {
7219
7394
  if (event.poll?.id) {
7220
7395
  this.polls_by_id.delete(event.poll.id);
7221
- for (const activeFeed of Object.values(this.activeFeeds)) {
7396
+ for (const activeFeed of this.allActiveFeeds) {
7222
7397
  const currentActivities = activeFeed.currentState.activities;
7223
7398
  if (currentActivities) {
7224
7399
  const newActivities = [];
@@ -7266,14 +7441,14 @@ class FeedsClient extends FeedsApi {
7266
7441
  case "feeds.bookmark.deleted":
7267
7442
  case "feeds.bookmark.updated": {
7268
7443
  const activityId = event.bookmark.activity.id;
7269
- const feeds = this.findActiveFeedsByActivityId(activityId);
7270
- feeds.forEach((f) => f.handleWSEvent(event));
7444
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7445
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7271
7446
  break;
7272
7447
  }
7273
7448
  case "feeds.activity.feedback": {
7274
7449
  const activityId = event.activity_feedback.activity_id;
7275
- const feeds = this.findActiveFeedsByActivityId(activityId);
7276
- feeds.forEach((f) => f.handleWSEvent(event));
7450
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7451
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7277
7452
  break;
7278
7453
  }
7279
7454
  case "user.updated": {
@@ -7281,11 +7456,20 @@ class FeedsClient extends FeedsApi {
7281
7456
  break;
7282
7457
  }
7283
7458
  default: {
7284
- feed?.handleWSEvent(event);
7459
+ feeds.forEach((f) => f.handleWSEvent(event));
7460
+ if (event.type === "feeds.activity.deleted") {
7461
+ delete this.activeActivities[event.activity.id];
7462
+ }
7285
7463
  }
7286
7464
  }
7287
7465
  });
7288
7466
  }
7467
+ get allActiveFeeds() {
7468
+ return [
7469
+ ...Object.values(this.activeFeeds),
7470
+ ...Object.values(this.activeActivities).filter((a) => !!getFeed.call(a)).map((a) => getFeed.call(a))
7471
+ ];
7472
+ }
7289
7473
  hydratePollCache(activities) {
7290
7474
  for (const activity of activities) {
7291
7475
  if (!activity.poll) {
@@ -7357,10 +7541,8 @@ class FeedsClient extends FeedsApi {
7357
7541
  response.follow.source_feed.feed,
7358
7542
  response.follow.target_feed.feed
7359
7543
  ].forEach((fid) => {
7360
- const feed = this.activeFeeds[fid];
7361
- if (feed) {
7362
- handleFollowUpdated.bind(feed)(response, false);
7363
- }
7544
+ const feeds = this.findAllActiveFeedsByFid(fid);
7545
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
7364
7546
  });
7365
7547
  return response;
7366
7548
  }
@@ -7371,30 +7553,24 @@ class FeedsClient extends FeedsApi {
7371
7553
  response.follow.source_feed.feed,
7372
7554
  response.follow.target_feed.feed
7373
7555
  ].forEach((fid) => {
7374
- const feed = this.activeFeeds[fid];
7375
- if (feed) {
7376
- handleFollowCreated.bind(feed)(response, false);
7377
- }
7556
+ const feeds = this.findAllActiveFeedsByFid(fid);
7557
+ feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
7378
7558
  });
7379
7559
  return response;
7380
7560
  }
7381
7561
  async followBatch(request) {
7382
7562
  const response = await super.followBatch(request);
7383
7563
  response.follows.forEach((follow) => {
7384
- const feed = this.activeFeeds[follow.source_feed.feed];
7385
- if (feed) {
7386
- handleFollowCreated.bind(feed)({ follow });
7387
- }
7564
+ const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
7565
+ feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
7388
7566
  });
7389
7567
  return response;
7390
7568
  }
7391
7569
  async unfollow(request) {
7392
7570
  const response = await super.unfollow(request);
7393
7571
  [request.source, request.target].forEach((fid) => {
7394
- const feed = this.activeFeeds[fid];
7395
- if (feed) {
7396
- handleFollowDeleted.bind(feed)(response, false);
7397
- }
7572
+ const feeds = this.findAllActiveFeedsByFid(fid);
7573
+ feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
7398
7574
  });
7399
7575
  return response;
7400
7576
  }
@@ -7404,18 +7580,64 @@ class FeedsClient extends FeedsApi {
7404
7580
  ...request,
7405
7581
  connection_id: connectionId
7406
7582
  });
7407
- const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
7408
- if (feed) {
7409
- handleWatchStopped.bind(feed)();
7583
+ const feeds = this.findAllActiveFeedsByFid(
7584
+ `${request.feed_group_id}:${request.feed_id}`
7585
+ );
7586
+ feeds.forEach((f) => handleWatchStopped.bind(f)());
7587
+ return response;
7588
+ }
7589
+ async getOrCreateFeed(request) {
7590
+ const response = await super.getOrCreateFeed(request);
7591
+ this.hydrateCapabilitiesCache([response.feed]);
7592
+ if (request.watch) {
7593
+ const feeds = this.findAllActiveFeedsByFid(
7594
+ `${request.feed_group_id}:${request.feed_id}`
7595
+ );
7596
+ feeds.forEach((f) => handleWatchStarted.bind(f)());
7410
7597
  }
7411
7598
  return response;
7412
7599
  }
7413
- findActiveFeedsByActivityId(activityId) {
7414
- return Object.values(this.activeFeeds).filter(
7600
+ findAllActiveFeedsByActivityId(activityId) {
7601
+ return [
7602
+ ...Object.values(this.activeFeeds),
7603
+ ...Object.values(this.activeActivities).filter((a) => !!getFeed.call(a)).map((a) => getFeed.call(a))
7604
+ ].filter(
7415
7605
  (feed) => feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId)
7416
7606
  );
7417
7607
  }
7608
+ findAllActiveFeedsByFid(fid) {
7609
+ if (!fid) return [];
7610
+ const activeFeed = this.activeFeeds[fid];
7611
+ return [
7612
+ ...activeFeed ? [activeFeed] : [],
7613
+ ...Object.values(this.activeActivities).filter((a) => getFeed.call(a)?.feed === fid).map((a) => getFeed.call(a))
7614
+ ];
7615
+ }
7616
+ /**
7617
+ * When updating from WS events we need a special logic:
7618
+ * - Find active feeds that match a given fid.
7619
+ * - Find active feed from activities where fid matches any of the feeds the activity is posted to.
7620
+ *
7621
+ * This logic is different from `findAllActiveFeedsByFid` which only checks the first feed an activity is posted to.
7622
+ *
7623
+ * @param fid
7624
+ * @param activityId
7625
+ * @returns
7626
+ */
7627
+ findAllActiveFeedsFromWSEvent(event) {
7628
+ const fid = "fid" in event ? event.fid : void 0;
7629
+ if (!fid) return [];
7630
+ const activeFeed = fid ? this.activeFeeds[fid] : void 0;
7631
+ return [
7632
+ ...activeFeed ? [activeFeed] : [],
7633
+ ...Object.values(this.activeActivities).filter((a) => {
7634
+ const feed = getFeed.call(a);
7635
+ return feed?.feed === fid || a.currentState.activity?.feeds.some((f) => f === fid);
7636
+ }).map((a) => getFeed.call(a))
7637
+ ];
7638
+ }
7418
7639
  }
7640
+ exports.ActivityWithStateUpdates = ActivityWithStateUpdates;
7419
7641
  exports.Constants = Constants;
7420
7642
  exports.Feed = Feed;
7421
7643
  exports.FeedsClient = FeedsClient;
@@ -7436,4 +7658,4 @@ exports.replaceUniqueArrayMerge = replaceUniqueArrayMerge;
7436
7658
  exports.shouldUpdateState = shouldUpdateState;
7437
7659
  exports.uniqueArrayMerge = uniqueArrayMerge;
7438
7660
  exports.updateEntityInArray = updateEntityInArray;
7439
- //# sourceMappingURL=feeds-client-DLiLkrA0.js.map
7661
+ //# sourceMappingURL=feeds-client-CwioZBvA.js.map