@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
@@ -154,6 +154,7 @@ decoders.ActivityResponse = (input) => {
154
154
  mentioned_users: { type: "UserResponse", isSingle: false },
155
155
  own_bookmarks: { type: "BookmarkResponse", isSingle: false },
156
156
  own_reactions: { type: "FeedsReactionResponse", isSingle: false },
157
+ collections: { type: "EnrichedCollectionResponse", isSingle: false },
157
158
  reaction_groups: { type: "ReactionGroupResponse", isSingle: false },
158
159
  user: { type: "UserResponse", isSingle: true },
159
160
  deleted_at: { type: "DatetimeType", isSingle: true },
@@ -448,6 +449,13 @@ decoders.ChannelResponse = (input) => {
448
449
  };
449
450
  return decode(typeMappings, input);
450
451
  };
452
+ decoders.CollectionResponse = (input) => {
453
+ const typeMappings = {
454
+ created_at: { type: "DatetimeType", isSingle: true },
455
+ updated_at: { type: "DatetimeType", isSingle: true }
456
+ };
457
+ return decode(typeMappings, input);
458
+ };
451
459
  decoders.Command = (input) => {
452
460
  const typeMappings = {
453
461
  created_at: { type: "DatetimeType", isSingle: true },
@@ -535,6 +543,12 @@ decoders.CreateBlockListResponse = (input) => {
535
543
  };
536
544
  return decode(typeMappings, input);
537
545
  };
546
+ decoders.CreateCollectionsResponse = (input) => {
547
+ const typeMappings = {
548
+ collections: { type: "CollectionResponse", isSingle: false }
549
+ };
550
+ return decode(typeMappings, input);
551
+ };
538
552
  decoders.CreateFeedsBatchResponse = (input) => {
539
553
  const typeMappings = {
540
554
  feeds: { type: "FeedResponse", isSingle: false }
@@ -608,6 +622,13 @@ decoders.EgressRTMPResponse = (input) => {
608
622
  };
609
623
  return decode(typeMappings, input);
610
624
  };
625
+ decoders.EnrichedCollectionResponse = (input) => {
626
+ const typeMappings = {
627
+ created_at: { type: "DatetimeType", isSingle: true },
628
+ updated_at: { type: "DatetimeType", isSingle: true }
629
+ };
630
+ return decode(typeMappings, input);
631
+ };
611
632
  decoders.EntityCreatorResponse = (input) => {
612
633
  const typeMappings = {
613
634
  created_at: { type: "DatetimeType", isSingle: true },
@@ -1213,6 +1234,12 @@ decoders.ReactionResponse = (input) => {
1213
1234
  };
1214
1235
  return decode(typeMappings, input);
1215
1236
  };
1237
+ decoders.ReadCollectionsResponse = (input) => {
1238
+ const typeMappings = {
1239
+ collections: { type: "CollectionResponse", isSingle: false }
1240
+ };
1241
+ return decode(typeMappings, input);
1242
+ };
1216
1243
  decoders.RejectFeedMemberInviteResponse = (input) => {
1217
1244
  const typeMappings = {
1218
1245
  member: { type: "FeedMemberResponse", isSingle: true }
@@ -1375,6 +1402,12 @@ decoders.UpdateBookmarkResponse = (input) => {
1375
1402
  };
1376
1403
  return decode(typeMappings, input);
1377
1404
  };
1405
+ decoders.UpdateCollectionsResponse = (input) => {
1406
+ const typeMappings = {
1407
+ collections: { type: "CollectionResponse", isSingle: false }
1408
+ };
1409
+ return decode(typeMappings, input);
1410
+ };
1378
1411
  decoders.UpdateCommentResponse = (input) => {
1379
1412
  const typeMappings = {
1380
1413
  comment: { type: "CommentResponse", isSingle: true }
@@ -1629,6 +1662,7 @@ class FeedsApi {
1629
1662
  visibility: request?.visibility,
1630
1663
  visibility_tag: request?.visibility_tag,
1631
1664
  attachments: request?.attachments,
1665
+ collection_refs: request?.collection_refs,
1632
1666
  filter_tags: request?.filter_tags,
1633
1667
  interest_tags: request?.interest_tags,
1634
1668
  mentioned_user_ids: request?.mentioned_user_ids,
@@ -1918,6 +1952,7 @@ class FeedsApi {
1918
1952
  text: request?.text,
1919
1953
  visibility: request?.visibility,
1920
1954
  attachments: request?.attachments,
1955
+ collection_refs: request?.collection_refs,
1921
1956
  feeds: request?.feeds,
1922
1957
  filter_tags: request?.filter_tags,
1923
1958
  interest_tags: request?.interest_tags,
@@ -2005,6 +2040,52 @@ class FeedsApi {
2005
2040
  decoders.QueryBookmarksResponse?.(response.body);
2006
2041
  return { ...response.body, metadata: response.metadata };
2007
2042
  }
2043
+ async deleteCollections(request) {
2044
+ const queryParams = {
2045
+ collection_refs: request?.collection_refs
2046
+ };
2047
+ const response = await this.apiClient.sendRequest("DELETE", "/api/v2/feeds/collections", void 0, queryParams);
2048
+ decoders.DeleteCollectionsResponse?.(response.body);
2049
+ return { ...response.body, metadata: response.metadata };
2050
+ }
2051
+ async readCollections(request) {
2052
+ const queryParams = {
2053
+ collection_refs: request?.collection_refs
2054
+ };
2055
+ const response = await this.apiClient.sendRequest("GET", "/api/v2/feeds/collections", void 0, queryParams);
2056
+ decoders.ReadCollectionsResponse?.(response.body);
2057
+ return { ...response.body, metadata: response.metadata };
2058
+ }
2059
+ async updateCollections(request) {
2060
+ const body = {
2061
+ collections: request?.collections
2062
+ };
2063
+ const response = await this.apiClient.sendRequest(
2064
+ "PATCH",
2065
+ "/api/v2/feeds/collections",
2066
+ void 0,
2067
+ void 0,
2068
+ body,
2069
+ "application/json"
2070
+ );
2071
+ decoders.UpdateCollectionsResponse?.(response.body);
2072
+ return { ...response.body, metadata: response.metadata };
2073
+ }
2074
+ async createCollections(request) {
2075
+ const body = {
2076
+ collections: request?.collections
2077
+ };
2078
+ const response = await this.apiClient.sendRequest(
2079
+ "POST",
2080
+ "/api/v2/feeds/collections",
2081
+ void 0,
2082
+ void 0,
2083
+ body,
2084
+ "application/json"
2085
+ );
2086
+ decoders.CreateCollectionsResponse?.(response.body);
2087
+ return { ...response.body, metadata: response.metadata };
2088
+ }
2008
2089
  async getComments(request) {
2009
2090
  const queryParams = {
2010
2091
  object_id: request?.object_id,
@@ -3781,7 +3862,7 @@ const getRateLimitFromResponseHeader = (response_headers) => {
3781
3862
  };
3782
3863
  return result;
3783
3864
  };
3784
- const version = "0.3.6";
3865
+ const version = "0.3.8";
3785
3866
  class ApiClient {
3786
3867
  constructor(apiKey, tokenManager, connectionIdManager, options) {
3787
3868
  this.apiKey = apiKey;
@@ -6417,7 +6498,7 @@ const _Feed = class _Feed extends FeedApi {
6417
6498
  }
6418
6499
  }
6419
6500
  async loadNextPageActivityComments(activity, request) {
6420
- 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];
6421
6502
  const currentPagination = currentEntityState?.pagination;
6422
6503
  const currentNextCursor = currentPagination?.next;
6423
6504
  const currentSort = currentPagination?.sort;
@@ -6426,12 +6507,13 @@ const _Feed = class _Feed extends FeedApi {
6426
6507
  if (isLoading || !checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)) {
6427
6508
  return;
6428
6509
  }
6510
+ const entityId = typeof activity === "string" ? activity : activity.id;
6429
6511
  await this.loadNextPageComments({
6430
- entityId: activity.id,
6512
+ entityId,
6431
6513
  base: () => this.client.getComments({
6432
6514
  ...request,
6433
6515
  sort,
6434
- object_id: activity.id,
6516
+ object_id: entityId,
6435
6517
  object_type: "activity",
6436
6518
  next: currentNextCursor
6437
6519
  }),
@@ -6666,7 +6748,7 @@ const _Feed = class _Feed extends FeedApi {
6666
6748
  eventHandler?.(event);
6667
6749
  }
6668
6750
  if (typeof eventHandler === "undefined") {
6669
- console.warn(`Received unknown event type: ${event.type}`, event);
6751
+ feedsLoggerSystem.getLogger("event-dispatcher").warn(`Received unknown feed event, type: ${event.type}`, event);
6670
6752
  }
6671
6753
  this.eventDispatcher.dispatch(event);
6672
6754
  }
@@ -6808,6 +6890,156 @@ function queueBatchedOwnCapabilities({ feeds }) {
6808
6890
  function clearQueuedFeeds() {
6809
6891
  queuedFeeds.clear();
6810
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
+ }
6811
7043
  class FeedsClient extends FeedsApi {
6812
7044
  constructor(apiKey, options) {
6813
7045
  const tokenManager = new TokenManager();
@@ -6820,6 +7052,7 @@ class FeedsClient extends FeedsApi {
6820
7052
  );
6821
7053
  super(apiClient);
6822
7054
  this.eventDispatcher = new EventDispatcher();
7055
+ this.activeActivities = {};
6823
7056
  this.activeFeeds = {};
6824
7057
  this.healthyConnectionChangedEventCount = 0;
6825
7058
  this.setGetBatchOwnCapabilitiesThrottlingInterval = (throttlingMs) => {
@@ -6848,13 +7081,20 @@ class FeedsClient extends FeedsApi {
6848
7081
  this.recoverOnReconnect = async () => {
6849
7082
  this.healthyConnectionChangedEventCount++;
6850
7083
  if (this.healthyConnectionChangedEventCount > 1) {
6851
- const entries = Object.entries(this.activeFeeds);
6852
- const results = await Promise.allSettled(
6853
- entries.map(([, feed]) => feed.synchronize())
6854
- );
6855
- const failures = results.flatMap(
6856
- (result, index) => result.status === "rejected" ? [{ feed: entries[index][0], reason: result.reason }] : []
6857
- );
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
+ });
6858
7098
  this.eventDispatcher.dispatch({
6859
7099
  type: "errors.unhandled",
6860
7100
  error_type: UnhandledErrorType.ReconnectionReconciliation,
@@ -6923,7 +7163,7 @@ class FeedsClient extends FeedsApi {
6923
7163
  };
6924
7164
  this.updateActivity = async (request) => {
6925
7165
  const response = await super.updateActivity(request);
6926
- for (const feed of Object.values(this.activeFeeds)) {
7166
+ for (const feed of this.allActiveFeeds) {
6927
7167
  handleActivityUpdated.bind(feed)(response, false);
6928
7168
  }
6929
7169
  return response;
@@ -6931,7 +7171,7 @@ class FeedsClient extends FeedsApi {
6931
7171
  this.addComment = async (request) => {
6932
7172
  const response = await super.addComment(request);
6933
7173
  const { comment } = response;
6934
- for (const feed of Object.values(this.activeFeeds)) {
7174
+ for (const feed of this.allActiveFeeds) {
6935
7175
  handleCommentAdded.bind(feed)(response, false);
6936
7176
  const parentActivityId = comment.object_id;
6937
7177
  if (feed.hasActivity(parentActivityId)) {
@@ -6954,7 +7194,7 @@ class FeedsClient extends FeedsApi {
6954
7194
  };
6955
7195
  this.updateComment = async (request) => {
6956
7196
  const response = await super.updateComment(request);
6957
- for (const feed of Object.values(this.activeFeeds)) {
7197
+ for (const feed of this.allActiveFeeds) {
6958
7198
  handleCommentUpdated.bind(feed)(response, false);
6959
7199
  }
6960
7200
  return response;
@@ -6962,7 +7202,7 @@ class FeedsClient extends FeedsApi {
6962
7202
  this.deleteComment = async (request) => {
6963
7203
  const response = await super.deleteComment(request);
6964
7204
  const { activity, comment } = response;
6965
- for (const feed of Object.values(this.activeFeeds)) {
7205
+ for (const feed of this.allActiveFeeds) {
6966
7206
  handleCommentDeleted.bind(feed)({ comment }, false);
6967
7207
  updateCommentCount.bind(feed)({
6968
7208
  activity,
@@ -6975,7 +7215,7 @@ class FeedsClient extends FeedsApi {
6975
7215
  this.addActivityReaction = async (request) => {
6976
7216
  const shouldEnforceUnique = request.enforce_unique;
6977
7217
  const response = await super.addActivityReaction(request);
6978
- for (const feed of Object.values(this.activeFeeds)) {
7218
+ for (const feed of this.allActiveFeeds) {
6979
7219
  if (shouldEnforceUnique) {
6980
7220
  handleActivityReactionUpdated.bind(feed)(response, false);
6981
7221
  } else {
@@ -6989,7 +7229,7 @@ class FeedsClient extends FeedsApi {
6989
7229
  };
6990
7230
  this.deleteActivityReaction = async (request) => {
6991
7231
  const response = await super.deleteActivityReaction(request);
6992
- for (const feed of Object.values(this.activeFeeds)) {
7232
+ for (const feed of this.allActiveFeeds) {
6993
7233
  handleActivityReactionDeleted.bind(feed)(response, false);
6994
7234
  }
6995
7235
  return response;
@@ -6997,7 +7237,7 @@ class FeedsClient extends FeedsApi {
6997
7237
  this.addCommentReaction = async (request) => {
6998
7238
  const shouldEnforceUnique = request.enforce_unique;
6999
7239
  const response = await super.addCommentReaction(request);
7000
- for (const feed of Object.values(this.activeFeeds)) {
7240
+ for (const feed of this.allActiveFeeds) {
7001
7241
  if (shouldEnforceUnique) {
7002
7242
  handleCommentReactionUpdated.bind(feed)(response, false);
7003
7243
  } else {
@@ -7008,7 +7248,7 @@ class FeedsClient extends FeedsApi {
7008
7248
  };
7009
7249
  this.deleteCommentReaction = async (request) => {
7010
7250
  const response = await super.deleteCommentReaction(request);
7011
- for (const feed of Object.values(this.activeFeeds)) {
7251
+ for (const feed of this.allActiveFeeds) {
7012
7252
  handleCommentReactionDeleted.bind(feed)(response, false);
7013
7253
  }
7014
7254
  return response;
@@ -7038,6 +7278,8 @@ class FeedsClient extends FeedsApi {
7038
7278
  this.connectionIdManager.reset();
7039
7279
  this.tokenManager.reset();
7040
7280
  this.polls_by_id.clear();
7281
+ this.activeActivities = {};
7282
+ this.activeFeeds = {};
7041
7283
  this.state.partialNext({
7042
7284
  connected_user: void 0,
7043
7285
  is_ws_connection_healthy: false,
@@ -7058,6 +7300,14 @@ class FeedsClient extends FeedsApi {
7058
7300
  options2?.activityAddedEventFilter
7059
7301
  );
7060
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
+ };
7061
7311
  this.updateNetworkConnectionStatus = (event) => {
7062
7312
  const networkEvent = {
7063
7313
  type: "network.changed",
@@ -7098,7 +7348,7 @@ class FeedsClient extends FeedsApi {
7098
7348
  feedsLoggerSystem.configureLoggers(options?.configure_loggers_options);
7099
7349
  this.on("all", (event) => {
7100
7350
  const fid = event.fid;
7101
- const feed = typeof fid === "string" ? this.activeFeeds[fid] : void 0;
7351
+ const feeds = this.findAllActiveFeedsFromWSEvent(event);
7102
7352
  switch (event.type) {
7103
7353
  case "connection.changed": {
7104
7354
  const { online } = event;
@@ -7106,14 +7356,14 @@ class FeedsClient extends FeedsApi {
7106
7356
  if (online) {
7107
7357
  this.recoverOnReconnect();
7108
7358
  } else {
7109
- for (const activeFeed of Object.values(this.activeFeeds)) {
7359
+ for (const activeFeed of this.allActiveFeeds) {
7110
7360
  handleWatchStopped.bind(activeFeed)();
7111
7361
  }
7112
7362
  }
7113
7363
  break;
7114
7364
  }
7115
7365
  case "feeds.feed.created": {
7116
- if (feed) break;
7366
+ if (this.activeFeeds[event.feed.id]) break;
7117
7367
  this.getOrCreateActiveFeed(
7118
7368
  event.feed.group_id,
7119
7369
  event.feed.id,
@@ -7122,9 +7372,15 @@ class FeedsClient extends FeedsApi {
7122
7372
  break;
7123
7373
  }
7124
7374
  case "feeds.feed.deleted": {
7125
- feed?.handleWSEvent(event);
7375
+ feeds.forEach((f) => f.handleWSEvent(event));
7126
7376
  if (typeof fid === "string") {
7127
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
+ });
7128
7384
  }
7129
7385
  break;
7130
7386
  }
@@ -7137,7 +7393,7 @@ class FeedsClient extends FeedsApi {
7137
7393
  case "feeds.poll.deleted": {
7138
7394
  if (event.poll?.id) {
7139
7395
  this.polls_by_id.delete(event.poll.id);
7140
- for (const activeFeed of Object.values(this.activeFeeds)) {
7396
+ for (const activeFeed of this.allActiveFeeds) {
7141
7397
  const currentActivities = activeFeed.currentState.activities;
7142
7398
  if (currentActivities) {
7143
7399
  const newActivities = [];
@@ -7185,14 +7441,14 @@ class FeedsClient extends FeedsApi {
7185
7441
  case "feeds.bookmark.deleted":
7186
7442
  case "feeds.bookmark.updated": {
7187
7443
  const activityId = event.bookmark.activity.id;
7188
- const feeds = this.findActiveFeedsByActivityId(activityId);
7189
- feeds.forEach((f) => f.handleWSEvent(event));
7444
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7445
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7190
7446
  break;
7191
7447
  }
7192
7448
  case "feeds.activity.feedback": {
7193
7449
  const activityId = event.activity_feedback.activity_id;
7194
- const feeds = this.findActiveFeedsByActivityId(activityId);
7195
- feeds.forEach((f) => f.handleWSEvent(event));
7450
+ const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
7451
+ allFeeds.forEach((f) => f.handleWSEvent(event));
7196
7452
  break;
7197
7453
  }
7198
7454
  case "user.updated": {
@@ -7200,11 +7456,20 @@ class FeedsClient extends FeedsApi {
7200
7456
  break;
7201
7457
  }
7202
7458
  default: {
7203
- 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
+ }
7204
7463
  }
7205
7464
  }
7206
7465
  });
7207
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
+ }
7208
7473
  hydratePollCache(activities) {
7209
7474
  for (const activity of activities) {
7210
7475
  if (!activity.poll) {
@@ -7276,10 +7541,8 @@ class FeedsClient extends FeedsApi {
7276
7541
  response.follow.source_feed.feed,
7277
7542
  response.follow.target_feed.feed
7278
7543
  ].forEach((fid) => {
7279
- const feed = this.activeFeeds[fid];
7280
- if (feed) {
7281
- handleFollowUpdated.bind(feed)(response, false);
7282
- }
7544
+ const feeds = this.findAllActiveFeedsByFid(fid);
7545
+ feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
7283
7546
  });
7284
7547
  return response;
7285
7548
  }
@@ -7290,30 +7553,24 @@ class FeedsClient extends FeedsApi {
7290
7553
  response.follow.source_feed.feed,
7291
7554
  response.follow.target_feed.feed
7292
7555
  ].forEach((fid) => {
7293
- const feed = this.activeFeeds[fid];
7294
- if (feed) {
7295
- handleFollowCreated.bind(feed)(response, false);
7296
- }
7556
+ const feeds = this.findAllActiveFeedsByFid(fid);
7557
+ feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
7297
7558
  });
7298
7559
  return response;
7299
7560
  }
7300
7561
  async followBatch(request) {
7301
7562
  const response = await super.followBatch(request);
7302
7563
  response.follows.forEach((follow) => {
7303
- const feed = this.activeFeeds[follow.source_feed.feed];
7304
- if (feed) {
7305
- handleFollowCreated.bind(feed)({ follow });
7306
- }
7564
+ const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
7565
+ feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
7307
7566
  });
7308
7567
  return response;
7309
7568
  }
7310
7569
  async unfollow(request) {
7311
7570
  const response = await super.unfollow(request);
7312
7571
  [request.source, request.target].forEach((fid) => {
7313
- const feed = this.activeFeeds[fid];
7314
- if (feed) {
7315
- handleFollowDeleted.bind(feed)(response, false);
7316
- }
7572
+ const feeds = this.findAllActiveFeedsByFid(fid);
7573
+ feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
7317
7574
  });
7318
7575
  return response;
7319
7576
  }
@@ -7323,18 +7580,64 @@ class FeedsClient extends FeedsApi {
7323
7580
  ...request,
7324
7581
  connection_id: connectionId
7325
7582
  });
7326
- const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
7327
- if (feed) {
7328
- 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)());
7329
7597
  }
7330
7598
  return response;
7331
7599
  }
7332
- findActiveFeedsByActivityId(activityId) {
7333
- 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(
7334
7605
  (feed) => feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId)
7335
7606
  );
7336
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
+ }
7337
7639
  }
7640
+ exports.ActivityWithStateUpdates = ActivityWithStateUpdates;
7338
7641
  exports.Constants = Constants;
7339
7642
  exports.Feed = Feed;
7340
7643
  exports.FeedsClient = FeedsClient;
@@ -7355,4 +7658,4 @@ exports.replaceUniqueArrayMerge = replaceUniqueArrayMerge;
7355
7658
  exports.shouldUpdateState = shouldUpdateState;
7356
7659
  exports.uniqueArrayMerge = uniqueArrayMerge;
7357
7660
  exports.updateEntityInArray = updateEntityInArray;
7358
- //# sourceMappingURL=feeds-client-47vliZx_.js.map
7661
+ //# sourceMappingURL=feeds-client-CwioZBvA.js.map