@stream-io/feeds-client 0.3.31 → 0.3.33

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 (55) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/cjs/index.js +3 -2
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/react-bindings.js +39 -33
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +4 -3
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +39 -33
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/{feeds-client-DYnxEI2D.mjs → feeds-client-C-6NrDBy.mjs} +196 -182
  11. package/dist/feeds-client-C-6NrDBy.mjs.map +1 -0
  12. package/dist/{feeds-client-BUsd5D-y.js → feeds-client-CyaHg6lu.js} +196 -182
  13. package/dist/feeds-client-CyaHg6lu.js.map +1 -0
  14. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  15. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts +1 -1
  16. package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -1
  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/useOwnCapabilities.d.ts.map +1 -1
  20. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnFollowings.d.ts +8 -0
  21. package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnFollowings.d.ts.map +1 -0
  22. package/dist/types/common/types.d.ts +1 -1
  23. package/dist/types/common/types.d.ts.map +1 -1
  24. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
  25. package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
  26. package/dist/types/feed/feed.d.ts +2 -1
  27. package/dist/types/feed/feed.d.ts.map +1 -1
  28. package/dist/types/feeds-client/feeds-client.d.ts +7 -9
  29. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  30. package/dist/types/gen/models/index.d.ts +4 -0
  31. package/dist/types/gen/models/index.d.ts.map +1 -1
  32. package/dist/types/utils/check-own-fields-equality.d.ts +2 -0
  33. package/dist/types/utils/check-own-fields-equality.d.ts.map +1 -1
  34. package/dist/types/utils/throttling/index.d.ts +1 -1
  35. package/dist/types/utils/throttling/index.d.ts.map +1 -1
  36. package/dist/types/utils/throttling/throttled-get-batched-own-fields.d.ts +14 -0
  37. package/dist/types/utils/throttling/throttled-get-batched-own-fields.d.ts.map +1 -0
  38. package/package.json +1 -1
  39. package/src/activity-with-state-updates/activity-with-state-updates.ts +7 -2
  40. package/src/bindings/react/hooks/feed-state-hooks/index.ts +1 -0
  41. package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +14 -23
  42. package/src/bindings/react/hooks/feed-state-hooks/useOwnFollowings.ts +18 -0
  43. package/src/common/types.ts +1 -1
  44. package/src/feed/event-handlers/activity/handle-activity-added.ts +0 -6
  45. package/src/feed/event-handlers/activity/handle-activity-updated.ts +0 -4
  46. package/src/feed/feed.ts +51 -39
  47. package/src/feeds-client/feeds-client.ts +88 -91
  48. package/src/gen/models/index.ts +8 -0
  49. package/src/utils/check-own-fields-equality.ts +37 -10
  50. package/src/utils/throttling/index.ts +1 -1
  51. package/src/utils/throttling/{throttled-get-batched-own-capabilities.ts → throttled-get-batched-own-fields.ts} +10 -10
  52. package/dist/feeds-client-BUsd5D-y.js.map +0 -1
  53. package/dist/feeds-client-DYnxEI2D.mjs.map +0 -1
  54. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts +0 -14
  55. package/dist/types/utils/throttling/throttled-get-batched-own-capabilities.d.ts.map +0 -1
@@ -1,38 +1,29 @@
1
- import { useCallback } from 'react';
2
1
  import { useStateStore } from '@stream-io/state-store/react-bindings';
3
2
 
4
3
  import { useFeedContext } from '../../contexts/StreamFeedContext';
5
- import { useFeedsClient } from '../../contexts/StreamFeedsContext';
6
- import type { Feed } from '../../../../feed';
4
+ import type { Feed, FeedState } from '../../../../feed';
7
5
  import type { FeedOwnCapability } from '../../../../gen/models';
8
- import type { FeedsClientState } from '../../../../feeds-client';
6
+ import { useFeedsClient } from '../../contexts/StreamFeedsContext';
9
7
 
10
8
  const stableEmptyArray: readonly FeedOwnCapability[] = [];
11
9
 
10
+ const selector = (currentState: FeedState) => {
11
+ return {
12
+ feedOwnCapabilities: currentState.own_capabilities ?? stableEmptyArray,
13
+ };
14
+ };
15
+
12
16
  export const useOwnCapabilities = (feedFromProps?: Feed | string) => {
13
17
  const client = useFeedsClient();
14
18
  const feedFromContext = useFeedContext();
15
- const feed = feedFromProps ?? feedFromContext;
16
- const fid = typeof feed === 'string' ? feed : feed?.feed;
17
-
18
- const selector = useCallback(
19
- (currentState: FeedsClientState) => {
20
- if (!fid) {
21
- return { feedOwnCapabilities: stableEmptyArray };
22
- }
23
-
24
- return {
25
- feedOwnCapabilities:
26
- currentState.own_capabilities_by_fid[fid] ?? stableEmptyArray,
27
- };
28
- },
29
- [fid],
30
- );
19
+ let feed = feedFromProps ?? feedFromContext;
20
+ if (typeof feed === 'string') {
21
+ const [groupId, id] = feed.split(':');
22
+ feed = groupId && id ? client?.feed(groupId, id) : undefined;
23
+ }
31
24
 
32
25
  const { feedOwnCapabilities = stableEmptyArray } =
33
- useStateStore(client?.state, selector) ?? {};
34
-
35
- // console.log('GETTING CAPA: ', feed?.feed, feedOwnCapabilities);
26
+ useStateStore(feed?.state, selector) ?? {};
36
27
 
37
28
  return feedOwnCapabilities;
38
29
  };
@@ -0,0 +1,18 @@
1
+ import { useStateStore } from '@stream-io/state-store/react-bindings';
2
+
3
+ import { useFeedContext } from '../../contexts/StreamFeedContext';
4
+ import type { Feed, FeedState } from '../../../../feed';
5
+
6
+ /**
7
+ * A React hook that returns a reactive array of feeds that the feeds's owner is following and is owned by the current user.
8
+ */
9
+ export const useOwnFollowings = (feedFromProps?: Feed) => {
10
+ const feedFromContext = useFeedContext();
11
+ const feed = feedFromProps ?? feedFromContext;
12
+
13
+ return useStateStore(feed?.state, selector);
14
+ };
15
+
16
+ const selector = ({ own_followings }: FeedState) => ({
17
+ own_followings,
18
+ });
@@ -6,7 +6,7 @@ export type FeedsClientOptions = {
6
6
  base_url?: string;
7
7
  timeout?: number;
8
8
  configure_loggers_options?: ConfigureLoggersOptions;
9
- query_batch_own_capabilties_throttling_interval?: number;
9
+ query_batch_own_fields_throttling_interval?: number;
10
10
  };
11
11
 
12
12
  export type RateLimit = {
@@ -62,12 +62,6 @@ export function handleActivityAdded(
62
62
  const activity = event.activity;
63
63
  this.client.hydratePollCache([activity]);
64
64
 
65
- const currentFeed = activity.current_feed;
66
-
67
- if (currentFeed) {
68
- this.client.hydrateCapabilitiesCache([currentFeed]);
69
- }
70
-
71
65
  this.state.partialNext({ activities: result.activities });
72
66
  }
73
67
  }
@@ -92,10 +92,6 @@ export function handleActivityUpdated(
92
92
  if (result1?.changed || result2.changed) {
93
93
  this.client.hydratePollCache([payload.activity]);
94
94
 
95
- if (payload.activity.current_feed) {
96
- this.client.hydrateCapabilitiesCache([payload.activity.current_feed]);
97
- }
98
-
99
95
  this.state.partialNext({
100
96
  activities: result1?.changed ? result1.entities : currentActivities,
101
97
  pinned_activities: result2.entities,
package/src/feed/feed.ts CHANGED
@@ -14,6 +14,7 @@ import type {
14
14
  FollowRequest,
15
15
  QueryCommentsRequest,
16
16
  ActivityAddedEvent,
17
+ EnrichmentOptions,
17
18
  } from '../gen/models';
18
19
  import type { StreamResponse } from '../gen-imports';
19
20
  import { StateStore } from '@stream-io/state-store';
@@ -63,16 +64,16 @@ import {
63
64
  checkHasAnotherPage,
64
65
  Constants,
65
66
  feedsLoggerSystem,
66
- ownFeedFields,
67
67
  uniqueArrayMerge,
68
68
  } from '../utils';
69
69
  import { handleActivityFeedback } from './event-handlers/activity/handle-activity-feedback';
70
70
  import { deepEqual } from '../utils/deep-equal';
71
71
  import { getOrCreateActiveFeed } from '../feeds-client/get-or-create-active-feed';
72
+ import { queueBatchedOwnFields } from '../utils/throttling';
72
73
 
73
74
  export type FeedState = Omit<
74
75
  Partial<GetOrCreateFeedResponse & FeedResponse>,
75
- 'feed' | 'own_capabilities' | 'duration'
76
+ 'feed' | 'duration'
76
77
  > & {
77
78
  /**
78
79
  * True when loading state using `getOrCreate`
@@ -333,11 +334,6 @@ export class Feed extends FeedApi {
333
334
  }
334
335
  }
335
336
 
336
- this.client.hydrateCapabilitiesCache([
337
- response.feed,
338
- ...currentActivityFeeds,
339
- ]);
340
-
341
337
  if (request?.next) {
342
338
  const { activities: currentActivities = [] } = this.currentState;
343
339
 
@@ -919,10 +915,7 @@ export class Feed extends FeedApi {
919
915
  ...request,
920
916
  feeds: [this.feed],
921
917
  });
922
- const currentFeed = response.activity.current_feed;
923
- if (currentFeed) {
924
- this.client.hydrateCapabilitiesCache([currentFeed]);
925
- }
918
+
926
919
  return response;
927
920
  }
928
921
 
@@ -934,34 +927,19 @@ export class Feed extends FeedApi {
934
927
 
935
928
  // no need to run noop function
936
929
  if (eventHandler !== Feed.noop) {
937
- if ('activity' in event && this.hasActivity(event.activity.id)) {
930
+ // Backfill current_feed if activity is posted to multiple feeds
931
+ if (
932
+ 'activity' in event &&
933
+ event.activity.feeds.length > 1 &&
934
+ this.hasActivity(event.activity.id)
935
+ ) {
938
936
  const currentActivity = this.currentState.activities?.find(
939
937
  (a) => a.id === event.activity.id,
940
938
  );
941
939
 
942
- // Backfill current_feed if activity is posted to multiple feeds
943
- if (
944
- event.activity.feeds.length > 1 &&
945
- !event.activity.current_feed &&
946
- currentActivity?.current_feed
947
- ) {
940
+ if (!event.activity.current_feed && currentActivity?.current_feed) {
948
941
  event.activity.current_feed = currentActivity.current_feed;
949
942
  }
950
-
951
- // Backfill own_ fields if activity is posted to a single feed
952
- if (
953
- event.activity.feeds.length === 1 &&
954
- event.activity.current_feed &&
955
- currentActivity?.current_feed
956
- ) {
957
- ownFeedFields.forEach((field) => {
958
- if (field in currentActivity.current_feed!) {
959
- // @ts-expect-error TODO: fix this
960
- event.activity.current_feed![field] =
961
- currentActivity.current_feed![field];
962
- }
963
- });
964
- }
965
943
  }
966
944
  // @ts-expect-error intersection of handler arguments results to never
967
945
  eventHandler?.(event);
@@ -994,10 +972,7 @@ export class Feed extends FeedApi {
994
972
  ) {
995
973
  const enrichmentOptions =
996
974
  this.currentState.last_get_or_create_request_config?.enrichment_options;
997
- if (
998
- !enrichmentOptions?.skip_activity_current_feed &&
999
- !enrichmentOptions?.skip_all
1000
- ) {
975
+ if (this.shouldAddToActiveFeeds(enrichmentOptions)) {
1001
976
  const feedsToGetOrCreate = new Map<string, FeedResponse>();
1002
977
  activities.forEach((activity) => {
1003
978
  if (
@@ -1010,14 +985,51 @@ export class Feed extends FeedApi {
1010
985
  );
1011
986
  }
1012
987
  });
1013
- Array.from(feedsToGetOrCreate.values()).forEach((feed) => {
988
+ const newFeeds = Array.from(feedsToGetOrCreate.values());
989
+ const fieldsToUpdate: Array<
990
+ 'own_capabilities' | 'own_follows' | 'own_followings' | 'own_membership'
991
+ > = [];
992
+ if (!options.fromWebSocket) {
993
+ fieldsToUpdate.push(
994
+ 'own_capabilities',
995
+ 'own_follows',
996
+ 'own_membership',
997
+ );
998
+ if (enrichmentOptions?.enrich_own_followings) {
999
+ fieldsToUpdate.push('own_followings');
1000
+ }
1001
+ }
1002
+ newFeeds.forEach((feed) => {
1014
1003
  getOrCreateActiveFeed.bind(this.client)({
1015
1004
  group: feed.group_id,
1016
1005
  id: feed.id,
1017
1006
  data: feed,
1018
- fromWebSocket: options.fromWebSocket,
1007
+ fieldsToUpdate,
1019
1008
  });
1020
1009
  });
1010
+ if (options.fromWebSocket) {
1011
+ const uninitializedFeeds = newFeeds.filter((feedResponse) => {
1012
+ const feed = this.client.feed(feedResponse.group_id, feedResponse.id);
1013
+ // own_capabilities can only be undefined if we haven't fetched it yet
1014
+ return feed.currentState.own_capabilities === undefined;
1015
+ });
1016
+ if (uninitializedFeeds.length > 0) {
1017
+ queueBatchedOwnFields.bind(this.client)({
1018
+ feeds: uninitializedFeeds.map((feed) => feed.feed),
1019
+ });
1020
+ }
1021
+ }
1021
1022
  }
1022
1023
  }
1024
+
1025
+ private shouldAddToActiveFeeds(enrichmentOptions?: EnrichmentOptions) {
1026
+ if (!enrichmentOptions) {
1027
+ return true;
1028
+ }
1029
+ return (
1030
+ !enrichmentOptions?.skip_activity &&
1031
+ !enrichmentOptions?.skip_activity_current_feed &&
1032
+ !enrichmentOptions?.skip_all
1033
+ );
1034
+ }
1023
1035
  }
@@ -60,6 +60,7 @@ import { ModerationClient } from '../moderation-client';
60
60
  import { StreamPoll } from '../common/Poll';
61
61
  import {
62
62
  Feed,
63
+ type FeedState,
63
64
  handleActivityReactionAdded,
64
65
  handleActivityReactionDeleted,
65
66
  handleActivityReactionUpdated,
@@ -86,15 +87,16 @@ import { feedsLoggerSystem } from '../utils';
86
87
  import { handleCommentReactionUpdated } from '../feed/event-handlers/comment/handle-comment-reaction-updated';
87
88
  import {
88
89
  throttle,
89
- DEFAULT_BATCH_OWN_CAPABILITIES_THROTTLING_INTERVAL,
90
- type GetBatchedOwnCapabilitiesThrottledCallback,
91
- queueBatchedOwnCapabilities,
92
- type ThrottledGetBatchedOwnCapabilities,
93
90
  clearQueuedFeeds,
91
+ type ThrottledGetBatchedOwnFields,
92
+ type GetBatchedOwnFieldsThrottledCallback,
93
+ DEFAULT_BATCH_OWN_FIELDS_THROTTLING_INTERVAL,
94
94
  } from '../utils/throttling';
95
95
  import { ActivityWithStateUpdates } from '../activity-with-state-updates/activity-with-state-updates';
96
96
  import { getFeed } from '../activity-with-state-updates/get-feed';
97
97
  import {
98
+ isOwnCapabilitiesEqual,
99
+ isOwnFollowingsEqual,
98
100
  isOwnFollowsEqual,
99
101
  isOwnMembershipEqual,
100
102
  } from '../utils/check-own-fields-equality';
@@ -102,7 +104,6 @@ import {
102
104
  export type FeedsClientState = {
103
105
  connected_user: ConnectedUser | undefined;
104
106
  is_ws_connection_healthy: boolean;
105
- own_capabilities_by_fid: Record<string, FeedResponse['own_capabilities']>;
106
107
  };
107
108
 
108
109
  type FID = string;
@@ -128,9 +129,9 @@ export class FeedsClient extends FeedsApi {
128
129
 
129
130
  private healthyConnectionChangedEventCount = 0;
130
131
 
131
- protected throttledGetBatchOwnCapabilities!: ThrottledGetBatchedOwnCapabilities;
132
- private cancelGetBatchOwnCapabilitiesTimer!: () => void;
133
- private query_batch_own_capabilties_throttling_interval!: number;
132
+ protected throttledGetBatchOwnFields!: ThrottledGetBatchedOwnFields;
133
+ private cancelGetBatchOwnFieldsTimer!: () => void;
134
+ private query_batch_own_fields_throttling_interval!: number;
134
135
 
135
136
  constructor(apiKey: string, options?: FeedsClientOptions) {
136
137
  const tokenManager = new TokenManager();
@@ -145,16 +146,15 @@ export class FeedsClient extends FeedsApi {
145
146
  this.state = new StateStore<FeedsClientState>({
146
147
  connected_user: undefined,
147
148
  is_ws_connection_healthy: false,
148
- own_capabilities_by_fid: {},
149
149
  });
150
150
  this.moderation = new ModerationClient(apiClient);
151
151
  this.tokenManager = tokenManager;
152
152
  this.connectionIdManager = connectionIdManager;
153
153
  this.polls_by_id = new Map();
154
154
 
155
- this.query_batch_own_capabilties_throttling_interval =
156
- options?.query_batch_own_capabilties_throttling_interval ??
157
- DEFAULT_BATCH_OWN_CAPABILITIES_THROTTLING_INTERVAL;
155
+ this.query_batch_own_fields_throttling_interval =
156
+ options?.query_batch_own_fields_throttling_interval ??
157
+ DEFAULT_BATCH_OWN_FIELDS_THROTTLING_INTERVAL;
158
158
 
159
159
  feedsLoggerSystem.configureLoggers(options?.configure_loggers_options);
160
160
 
@@ -184,6 +184,7 @@ export class FeedsClient extends FeedsApi {
184
184
  group: event.feed.group_id,
185
185
  id: event.feed.id,
186
186
  data: event.feed,
187
+ fieldsToUpdate: [],
187
188
  });
188
189
 
189
190
  break;
@@ -284,30 +285,27 @@ export class FeedsClient extends FeedsApi {
284
285
  });
285
286
  }
286
287
 
287
- private setGetBatchOwnCapabilitiesThrottlingInterval = (
288
- throttlingMs: number,
289
- ) => {
290
- const {
291
- throttledFn: throttledGetBatchOwnCapabilities,
292
- cancelTimer: cancel,
293
- } = throttle<GetBatchedOwnCapabilitiesThrottledCallback>(
294
- (feeds, callback) => {
295
- this.ownBatch({
296
- feeds,
297
- }).catch((error) => {
298
- this.eventDispatcher.dispatch({
299
- type: 'errors.unhandled',
300
- error_type: UnhandledErrorType.FetchingOwnCapabilitiesOnNewActivity,
301
- error,
288
+ private setGetBatchOwnFieldsThrottlingInterval = (throttlingMs: number) => {
289
+ const { throttledFn: throttledGetBatchOwnFields, cancelTimer: cancel } =
290
+ throttle<GetBatchedOwnFieldsThrottledCallback>(
291
+ (feeds, callback) => {
292
+ this.ownBatch({
293
+ feeds,
294
+ }).catch((error) => {
295
+ this.eventDispatcher.dispatch({
296
+ type: 'errors.unhandled',
297
+ error_type:
298
+ UnhandledErrorType.FetchingOwnCapabilitiesOnNewActivity,
299
+ error,
300
+ });
302
301
  });
303
- });
304
- callback(feeds);
305
- },
306
- throttlingMs,
307
- { trailing: true },
308
- );
309
- this.throttledGetBatchOwnCapabilities = throttledGetBatchOwnCapabilities;
310
- this.cancelGetBatchOwnCapabilitiesTimer = cancel;
302
+ callback(feeds);
303
+ },
304
+ throttlingMs,
305
+ { trailing: true },
306
+ );
307
+ this.throttledGetBatchOwnFields = throttledGetBatchOwnFields;
308
+ this.cancelGetBatchOwnFieldsTimer = cancel;
311
309
  };
312
310
 
313
311
  private recoverOnReconnect = async () => {
@@ -369,34 +367,6 @@ export class FeedsClient extends FeedsApi {
369
367
  }
370
368
  }
371
369
 
372
- public hydrateCapabilitiesCache(
373
- feedResponses: Array<Pick<FeedResponse, 'feed' | 'own_capabilities'>>,
374
- ) {
375
- let ownCapabilitiesCache =
376
- this.state.getLatestValue().own_capabilities_by_fid;
377
-
378
- const capabilitiesToFetchQueue: string[] = [];
379
-
380
- for (const feedResponse of feedResponses) {
381
- const { feed, own_capabilities } = feedResponse;
382
-
383
- if (!Object.prototype.hasOwnProperty.call(ownCapabilitiesCache, feed)) {
384
- if (own_capabilities) {
385
- ownCapabilitiesCache = {
386
- ...ownCapabilitiesCache,
387
- [feed]: own_capabilities,
388
- };
389
- } else {
390
- capabilitiesToFetchQueue.push(feed);
391
- }
392
- }
393
- }
394
-
395
- queueBatchedOwnCapabilities.bind(this)({ feeds: capabilitiesToFetchQueue });
396
-
397
- this.state.partialNext({ own_capabilities_by_fid: ownCapabilitiesCache });
398
- }
399
-
400
370
  connectUser = async (user: UserRequest, tokenProvider?: TokenOrProvider) => {
401
371
  if (
402
372
  this.state.getLatestValue().connected_user !== undefined ||
@@ -407,8 +377,8 @@ export class FeedsClient extends FeedsApi {
407
377
 
408
378
  this.tokenManager.setTokenOrProvider(tokenProvider);
409
379
 
410
- this.setGetBatchOwnCapabilitiesThrottlingInterval(
411
- this.query_batch_own_capabilties_throttling_interval,
380
+ this.setGetBatchOwnFieldsThrottlingInterval(
381
+ this.query_batch_own_fields_throttling_interval,
412
382
  );
413
383
 
414
384
  try {
@@ -649,10 +619,9 @@ export class FeedsClient extends FeedsApi {
649
619
  this.state.partialNext({
650
620
  connected_user: undefined,
651
621
  is_ws_connection_healthy: false,
652
- own_capabilities_by_fid: {},
653
622
  });
654
623
 
655
- this.cancelGetBatchOwnCapabilitiesTimer();
624
+ this.cancelGetBatchOwnFieldsTimer();
656
625
  clearQueuedFeeds();
657
626
  };
658
627
 
@@ -680,6 +649,7 @@ export class FeedsClient extends FeedsApi {
680
649
  group: groupId,
681
650
  id,
682
651
  options,
652
+ fieldsToUpdate: [],
683
653
  });
684
654
  };
685
655
 
@@ -711,11 +681,15 @@ export class FeedsClient extends FeedsApi {
711
681
  id: feedResponse.id,
712
682
  data: feedResponse,
713
683
  watch: request?.watch,
684
+ fieldsToUpdate: [
685
+ 'own_capabilities',
686
+ 'own_follows',
687
+ 'own_membership',
688
+ 'own_followings',
689
+ ],
714
690
  }),
715
691
  );
716
692
 
717
- this.hydrateCapabilitiesCache(feedResponses);
718
-
719
693
  return {
720
694
  feeds,
721
695
  next: response.next,
@@ -727,13 +701,12 @@ export class FeedsClient extends FeedsApi {
727
701
 
728
702
  async ownBatch(request: OwnBatchRequest) {
729
703
  const response = await super.ownBatch(request);
730
- const feedResponses = Object.entries(response.data).map(
731
- ([feed, ownFields]) => ({
732
- feed,
733
- own_capabilities: ownFields.own_capabilities,
734
- }),
735
- );
736
- this.hydrateCapabilitiesCache(feedResponses);
704
+ Object.entries(response.data).forEach(([fid, ownFields]) => {
705
+ const feed = this.activeFeeds[fid];
706
+ if (feed) {
707
+ feed.state.partialNext(ownFields);
708
+ }
709
+ });
737
710
  return response;
738
711
  }
739
712
 
@@ -826,7 +799,6 @@ export class FeedsClient extends FeedsApi {
826
799
  },
827
800
  ) {
828
801
  const response = await super.getOrCreateFeed(request);
829
- this.hydrateCapabilitiesCache([response.feed]);
830
802
 
831
803
  if (request.watch) {
832
804
  const feeds = this.findAllActiveFeedsByFid(
@@ -848,6 +820,12 @@ export class FeedsClient extends FeedsApi {
848
820
  group: suggestion.group_id,
849
821
  id: suggestion.id,
850
822
  data: suggestion,
823
+ fieldsToUpdate: [
824
+ 'own_capabilities',
825
+ 'own_follows',
826
+ 'own_membership',
827
+ 'own_followings',
828
+ ],
851
829
  });
852
830
  });
853
831
 
@@ -861,7 +839,7 @@ export class FeedsClient extends FeedsApi {
861
839
  data,
862
840
  watch,
863
841
  options,
864
- fromWebSocket = false,
842
+ fieldsToUpdate,
865
843
  }: {
866
844
  group: string;
867
845
  id: string;
@@ -871,7 +849,9 @@ export class FeedsClient extends FeedsApi {
871
849
  addNewActivitiesTo?: 'start' | 'end';
872
850
  activityAddedEventFilter?: (event: ActivityAddedEvent) => boolean;
873
851
  };
874
- fromWebSocket?: boolean;
852
+ fieldsToUpdate: Array<
853
+ 'own_capabilities' | 'own_follows' | 'own_followings' | 'own_membership'
854
+ >;
875
855
  }) => {
876
856
  const fid = `${group}:${id}`;
877
857
  let isCreated = false;
@@ -909,18 +889,35 @@ export class FeedsClient extends FeedsApi {
909
889
  handleFeedUpdated.call(feed, { feed: data });
910
890
  } else if (
911
891
  (feed.currentState.updated_at?.getTime() ?? 0) ===
912
- data.updated_at.getTime() &&
913
- !fromWebSocket
892
+ data.updated_at.getTime()
914
893
  ) {
915
- const fieldsToUpdate: Array<keyof FeedResponse> = [];
916
- if (!isOwnFollowsEqual(feed.currentState, data)) {
917
- fieldsToUpdate.push('own_follows');
918
- }
919
- if (!isOwnMembershipEqual(feed.currentState, data)) {
920
- fieldsToUpdate.push('own_membership');
921
- }
922
- if (fieldsToUpdate.length > 0) {
923
- const fieldsToUpdateData = fieldsToUpdate.reduce(
894
+ const fieldsToUpdateData: Array<keyof FeedResponse> = [];
895
+ const fieldChecks: Array<
896
+ [
897
+ (
898
+ | 'own_capabilities'
899
+ | 'own_follows'
900
+ | 'own_membership'
901
+ | 'own_followings'
902
+ ),
903
+ (currentState: FeedState, newState: FeedResponse) => boolean,
904
+ ]
905
+ > = [
906
+ ['own_capabilities', isOwnCapabilitiesEqual],
907
+ ['own_follows', isOwnFollowsEqual],
908
+ ['own_membership', isOwnMembershipEqual],
909
+ ['own_followings', isOwnFollowingsEqual],
910
+ ];
911
+ fieldChecks.forEach(([field, isEqual]) => {
912
+ if (
913
+ fieldsToUpdate.includes(field) &&
914
+ !isEqual(feed.currentState, data)
915
+ ) {
916
+ fieldsToUpdateData.push(field);
917
+ }
918
+ });
919
+ if (fieldsToUpdateData.length > 0) {
920
+ const fieldsToUpdatePayload = fieldsToUpdateData.reduce(
924
921
  (acc: Partial<FeedResponse>, field) => {
925
922
  // @ts-expect-error TODO: fix this
926
923
  acc[field] = data[field];
@@ -928,7 +925,7 @@ export class FeedsClient extends FeedsApi {
928
925
  },
929
926
  {},
930
927
  );
931
- feed.state.partialNext(fieldsToUpdateData);
928
+ feed.state.partialNext(fieldsToUpdatePayload);
932
929
  }
933
930
  }
934
931
  }
@@ -614,6 +614,8 @@ export interface AddCommentReactionResponse {
614
614
  comment: CommentResponse;
615
615
 
616
616
  reaction: FeedsReactionResponse;
617
+
618
+ notification_created?: boolean;
617
619
  }
618
620
 
619
621
  export interface AddCommentRequest {
@@ -644,6 +646,8 @@ export interface AddCommentResponse {
644
646
  duration: string;
645
647
 
646
648
  comment: CommentResponse;
649
+
650
+ notification_created?: boolean;
647
651
  }
648
652
 
649
653
  export interface AddCommentsBatchRequest {
@@ -680,6 +684,8 @@ export interface AddReactionResponse {
680
684
  activity: ActivityResponse;
681
685
 
682
686
  reaction: FeedsReactionResponse;
687
+
688
+ notification_created?: boolean;
683
689
  }
684
690
 
685
691
  export interface AggregatedActivityResponse {
@@ -5258,6 +5264,8 @@ export interface SingleFollowResponse {
5258
5264
  duration: string;
5259
5265
 
5260
5266
  follow: FollowResponse;
5267
+
5268
+ notification_created?: boolean;
5261
5269
  }
5262
5270
 
5263
5271
  export interface SortParam {