@stream-io/feeds-client 0.3.51 → 1.1.0

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 (121) hide show
  1. package/CHANGELOG.md +21 -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 +5 -19
  5. package/dist/cjs/react-bindings.js.map +1 -1
  6. package/dist/es/index.mjs +15 -14
  7. package/dist/es/index.mjs.map +1 -1
  8. package/dist/es/react-bindings.mjs +5 -19
  9. package/dist/es/react-bindings.mjs.map +1 -1
  10. package/dist/{feeds-client-B4zeBggL.js → feeds-client-C1c6lcS3.js} +705 -214
  11. package/dist/feeds-client-C1c6lcS3.js.map +1 -0
  12. package/dist/{feeds-client-DeAqnd1a.mjs → feeds-client-jtUTE4AC.mjs} +711 -220
  13. package/dist/feeds-client-jtUTE4AC.mjs.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.map +1 -1
  16. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts +6 -2
  17. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts.map +1 -1
  18. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts +6 -2
  19. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.d.ts.map +1 -1
  20. package/dist/types/feed/activity-filter.d.ts +11 -0
  21. package/dist/types/feed/activity-filter.d.ts.map +1 -0
  22. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts +3 -2
  23. package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
  24. package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts +3 -2
  25. package/dist/types/feed/event-handlers/activity/handle-activity-deleted.d.ts.map +1 -1
  26. package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts +5 -0
  27. package/dist/types/feed/event-handlers/activity/handle-activity-feedback.d.ts.map +1 -1
  28. package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts +3 -2
  29. package/dist/types/feed/event-handlers/activity/handle-activity-pinned.d.ts.map +1 -1
  30. package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts +3 -2
  31. package/dist/types/feed/event-handlers/activity/handle-activity-unpinned.d.ts.map +1 -1
  32. package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
  33. package/dist/types/feed/event-handlers/activity/index.d.ts +3 -1
  34. package/dist/types/feed/event-handlers/activity/index.d.ts.map +1 -1
  35. package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
  36. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
  37. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts +1 -1
  38. package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts.map +1 -1
  39. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +6 -5
  40. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts.map +1 -1
  41. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +6 -5
  42. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts.map +1 -1
  43. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +6 -5
  44. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts.map +1 -1
  45. package/dist/types/feed/event-handlers/comment/handle-comment-updated.d.ts.map +1 -1
  46. package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts +4 -0
  47. package/dist/types/feed/event-handlers/feed/handle-feed-deleted.d.ts.map +1 -0
  48. package/dist/types/feed/event-handlers/feed/handle-feed-updated.d.ts.map +1 -1
  49. package/dist/types/feed/event-handlers/feed/index.d.ts +1 -0
  50. package/dist/types/feed/event-handlers/feed/index.d.ts.map +1 -1
  51. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -2
  52. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-added.d.ts.map +1 -1
  53. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -2
  54. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts.map +1 -1
  55. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -2
  56. package/dist/types/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts.map +1 -1
  57. package/dist/types/feed/event-handlers/follow/handle-follow-created.d.ts +2 -2
  58. package/dist/types/feed/event-handlers/follow/handle-follow-created.d.ts.map +1 -1
  59. package/dist/types/feed/event-handlers/follow/handle-follow-updated.d.ts.map +1 -1
  60. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -2
  61. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -1
  62. package/dist/types/feed/feed.d.ts +17 -12
  63. package/dist/types/feed/feed.d.ts.map +1 -1
  64. package/dist/types/feeds-client/apply-new-activity-to-active-feeds.d.ts +4 -0
  65. package/dist/types/feeds-client/apply-new-activity-to-active-feeds.d.ts.map +1 -0
  66. package/dist/types/feeds-client/feeds-client.d.ts +29 -8
  67. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  68. package/dist/types/gen/feeds/FeedsApi.d.ts +6 -4
  69. package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
  70. package/dist/types/gen/models/index.d.ts +40 -2
  71. package/dist/types/gen/models/index.d.ts.map +1 -1
  72. package/dist/types/index.d.ts +1 -0
  73. package/dist/types/index.d.ts.map +1 -1
  74. package/dist/types/types.d.ts +15 -0
  75. package/dist/types/types.d.ts.map +1 -1
  76. package/dist/types/utils/state-update-queue.d.ts +11 -2
  77. package/dist/types/utils/state-update-queue.d.ts.map +1 -1
  78. package/dist/types/utils/unique-array-merge.d.ts +1 -1
  79. package/dist/types/utils/unique-array-merge.d.ts.map +1 -1
  80. package/package.json +2 -1
  81. package/src/activity-with-state-updates/activity-with-state-updates.ts +8 -2
  82. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts +6 -20
  83. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivitySeen.ts +6 -20
  84. package/src/feed/activity-filter.ts +44 -0
  85. package/src/feed/event-handlers/activity/handle-activity-added.ts +22 -8
  86. package/src/feed/event-handlers/activity/handle-activity-deleted.ts +28 -2
  87. package/src/feed/event-handlers/activity/handle-activity-feedback.ts +17 -7
  88. package/src/feed/event-handlers/activity/handle-activity-pinned.ts +25 -3
  89. package/src/feed/event-handlers/activity/handle-activity-unpinned.ts +25 -2
  90. package/src/feed/event-handlers/activity/handle-activity-updated.ts +5 -1
  91. package/src/feed/event-handlers/activity/index.ts +3 -1
  92. package/src/feed/event-handlers/add-aggregated-activities-to-state.ts +11 -2
  93. package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +20 -11
  94. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +21 -11
  95. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +24 -10
  96. package/src/feed/event-handlers/comment/handle-comment-updated.ts +11 -10
  97. package/src/feed/event-handlers/feed/handle-feed-deleted.ts +12 -0
  98. package/src/feed/event-handlers/feed/handle-feed-updated.ts +8 -0
  99. package/src/feed/event-handlers/feed/index.ts +1 -0
  100. package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +25 -2
  101. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +25 -2
  102. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +25 -2
  103. package/src/feed/event-handlers/follow/handle-follow-created.ts +18 -1
  104. package/src/feed/event-handlers/follow/handle-follow-updated.ts +14 -0
  105. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +68 -2
  106. package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.ts +1 -1
  107. package/src/feed/feed.ts +79 -26
  108. package/src/feeds-client/apply-new-activity-to-active-feeds.ts +9 -0
  109. package/src/feeds-client/feeds-client.ts +301 -28
  110. package/src/gen/feeds/FeedsApi.ts +79 -12
  111. package/src/gen/model-decoders/decoders.ts +7 -0
  112. package/src/gen/models/index.ts +66 -4
  113. package/src/index.ts +1 -0
  114. package/src/types.ts +17 -0
  115. package/src/utils/state-update-queue.ts +42 -28
  116. package/src/utils/unique-array-merge.ts +11 -3
  117. package/dist/feeds-client-B4zeBggL.js.map +0 -1
  118. package/dist/feeds-client-DeAqnd1a.mjs.map +0 -1
  119. package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts +0 -12
  120. package/dist/types/feed/event-handlers/activity/handle-activity-marked.d.ts.map +0 -1
  121. package/src/feed/event-handlers/activity/handle-activity-marked.ts +0 -68
package/src/feed/feed.ts CHANGED
@@ -13,7 +13,6 @@ import type {
13
13
  ThreadedCommentResponse,
14
14
  FollowRequest,
15
15
  QueryCommentsRequest,
16
- ActivityAddedEvent,
17
16
  EnrichmentOptions,
18
17
  } from '../gen/models';
19
18
  import type { StreamResponse } from '../gen-imports';
@@ -39,9 +38,9 @@ import {
39
38
  handleBookmarkAdded,
40
39
  handleActivityDeleted,
41
40
  handleActivityRemovedFromFeed,
41
+ handleFeedDeleted,
42
42
  handleFeedUpdated,
43
43
  handleNotificationFeedUpdated,
44
- handleActivityMarked,
45
44
  handleActivityReactionAdded,
46
45
  handleActivityReactionDeleted,
47
46
  handleActivityReactionUpdated,
@@ -51,15 +50,21 @@ import {
51
50
  addAggregatedActivitiesToState,
52
51
  updateNotificationStatus,
53
52
  handleStoriesFeedUpdated,
53
+ handleActivityPinned,
54
+ handleActivityUnpinned,
54
55
  } from './event-handlers';
55
56
  import { capitalize } from '../common/utils';
56
57
  import type {
57
58
  ActivityIdOrCommentId,
59
+ ConnectedUser,
58
60
  GetCommentsRepliesRequest,
59
61
  GetCommentsRequest,
60
62
  LoadingStates,
63
+ OnNewActivityCallback,
64
+ OnNewActivityResult,
61
65
  PagerResponseWithLoadingStates,
62
66
  } from '../types';
67
+ import { activityFilter } from './activity-filter';
63
68
  import {
64
69
  checkHasAnotherPage,
65
70
  Constants,
@@ -143,12 +148,6 @@ export type FeedState = Omit<
143
148
  * `true` if the feed is receiving real-time updates via WebSocket
144
149
  */
145
150
  watch: boolean;
146
-
147
- /**
148
- * When a new activity is received from a WebSocket event by default it's added to the start of the list. You can change this to `end` to add it to the end of the list.
149
- * Useful for story feeds.
150
- */
151
- addNewActivitiesTo: 'start' | 'end';
152
151
  };
153
152
 
154
153
  type EventHandlerByEventType = {
@@ -184,7 +183,7 @@ export class Feed extends FeedApi {
184
183
  'feeds.comment.deleted': handleCommentDeleted.bind(this),
185
184
  'feeds.comment.updated': handleCommentUpdated.bind(this),
186
185
  'feeds.feed.created': Feed.noop,
187
- 'feeds.feed.deleted': Feed.noop,
186
+ 'feeds.feed.deleted': handleFeedDeleted.bind(this),
188
187
  'feeds.feed.updated': handleFeedUpdated.bind(this),
189
188
  'feeds.feed_group.changed': Feed.noop,
190
189
  'feeds.feed_group.deleted': Feed.noop,
@@ -207,9 +206,9 @@ export class Feed extends FeedApi {
207
206
  'feeds.poll.vote_casted': Feed.noop,
208
207
  'feeds.poll.vote_changed': Feed.noop,
209
208
  'feeds.poll.vote_removed': Feed.noop,
210
- 'feeds.activity.pinned': Feed.noop,
211
- 'feeds.activity.unpinned': Feed.noop,
212
- 'feeds.activity.marked': handleActivityMarked.bind(this),
209
+ 'feeds.activity.pinned': handleActivityPinned.bind(this),
210
+ 'feeds.activity.unpinned': handleActivityUnpinned.bind(this),
211
+ 'feeds.activity.marked': Feed.noop,
213
212
  'moderation.custom_action': Feed.noop,
214
213
  'moderation.flagged': Feed.noop,
215
214
  'moderation.mark_reviewed': Feed.noop,
@@ -237,8 +236,7 @@ export class Feed extends FeedApi {
237
236
  id: string,
238
237
  data?: FeedResponse,
239
238
  watch = false,
240
- addNewActivitiesTo: 'start' | 'end' = 'start',
241
- public activityAddedEventFilter?: (event: ActivityAddedEvent) => boolean,
239
+ public onNewActivity?: OnNewActivityCallback,
242
240
  ) {
243
241
  super(client, groupId, id);
244
242
  this.state = new StateStore<FeedState>({
@@ -250,7 +248,6 @@ export class Feed extends FeedApi {
250
248
  is_loading_activities: false,
251
249
  comments_by_entity_id: {},
252
250
  watch,
253
- addNewActivitiesTo,
254
251
  });
255
252
  this.client = client;
256
253
 
@@ -278,10 +275,6 @@ export class Feed extends FeedApi {
278
275
  return this.state.getLatestValue();
279
276
  }
280
277
 
281
- set addNewActivitiesTo(value: 'start' | 'end') {
282
- this.state.partialNext({ addNewActivitiesTo: value });
283
- }
284
-
285
278
  hasActivity(activityId: string) {
286
279
  return this.indexedActivityIds.has(activityId);
287
280
  }
@@ -292,6 +285,31 @@ export class Feed extends FeedApi {
292
285
  );
293
286
  }
294
287
 
288
+ /**
289
+ * Resolves how to handle a new activity (WS or HTTP): ignore, add-to-start, or add-to-end.
290
+ * Uses onNewActivity if set; else default (current user + filter match) adds to start.
291
+ */
292
+ protected resolveNewActivityDecision(
293
+ activity: ActivityResponse,
294
+ currentUser: ConnectedUser | undefined,
295
+ _fromHttp: boolean,
296
+ ): OnNewActivityResult {
297
+ if (this.onNewActivity) {
298
+ return this.onNewActivity({ activity, currentUser });
299
+ }
300
+ if (!currentUser) return 'ignore';
301
+ if (activity.user?.id !== currentUser.id) return 'ignore';
302
+ if (
303
+ !activityFilter(
304
+ activity,
305
+ this.currentState.last_get_or_create_request_config,
306
+ )
307
+ ) {
308
+ return 'ignore';
309
+ }
310
+ return 'add-to-start';
311
+ }
312
+
295
313
  async synchronize() {
296
314
  const { last_get_or_create_request_config } = this.state.getLatestValue();
297
315
  if (last_get_or_create_request_config?.watch) {
@@ -346,6 +364,7 @@ export class Feed extends FeedApi {
346
364
  response.activities,
347
365
  currentActivities,
348
366
  'end',
367
+ { hasOwnFields: true, backfillOwnFields: false },
349
368
  );
350
369
 
351
370
  const aggregatedActivitiesResult = addAggregatedActivitiesToState(
@@ -416,7 +435,7 @@ export class Feed extends FeedApi {
416
435
  });
417
436
  }
418
437
 
419
- this.newActivitiesAdded(response.activities);
438
+ this.activitiesAddedOrUpdated(response.activities);
420
439
 
421
440
  return response;
422
441
  } finally {
@@ -939,12 +958,44 @@ export class Feed extends FeedApi {
939
958
  });
940
959
  }
941
960
 
961
+ /**
962
+ * Applies a new activity to this feed's state (decision + add to activities).
963
+ * Used when the activity was added via this feed's addActivity or via client.addActivity.
964
+ */
965
+ protected addActivityFromHTTPResponse(activity: ActivityResponse): void {
966
+ const currentUser = this.client.state.getLatestValue().connected_user;
967
+ const decision = this.resolveNewActivityDecision(
968
+ activity,
969
+ currentUser,
970
+ true,
971
+ );
972
+ if (decision !== 'ignore') {
973
+ const position = decision === 'add-to-end' ? 'end' : 'start';
974
+ const currentActivities = this.currentState.activities;
975
+ const result = addActivitiesToState.bind(this)(
976
+ [activity],
977
+ currentActivities,
978
+ position,
979
+ {
980
+ hasOwnFields: activity.current_feed?.own_capabilities !== undefined,
981
+ backfillOwnFields: false,
982
+ },
983
+ );
984
+ if (result.changed) {
985
+ this.client.hydratePollCache([activity]);
986
+ this.state.partialNext({ activities: result.activities });
987
+ }
988
+ }
989
+ }
990
+
942
991
  async addActivity(request: Omit<ActivityRequest, 'feeds'>) {
943
992
  const response = await this.client.addActivity({
944
993
  ...request,
945
994
  feeds: [this.feed],
946
995
  });
947
996
 
997
+ this.addActivityFromHTTPResponse(response.activity);
998
+
948
999
  return response;
949
1000
  }
950
1001
 
@@ -983,11 +1034,12 @@ export class Feed extends FeedApi {
983
1034
  this.eventDispatcher.dispatch(event);
984
1035
  }
985
1036
 
986
- protected newActivitiesAdded(
1037
+ protected activitiesAddedOrUpdated(
987
1038
  activities: ActivityResponse[],
988
1039
  options: {
989
- fromWebSocket: boolean;
990
- } = { fromWebSocket: false },
1040
+ hasOwnFields: boolean;
1041
+ backfillOwnFields: boolean;
1042
+ } = { hasOwnFields: true, backfillOwnFields: true },
991
1043
  ) {
992
1044
  this.client.hydratePollCache(activities);
993
1045
  this.getOrCreateFeeds(activities, options);
@@ -996,7 +1048,8 @@ export class Feed extends FeedApi {
996
1048
  private getOrCreateFeeds(
997
1049
  activities: ActivityResponse[],
998
1050
  options: {
999
- fromWebSocket: boolean;
1051
+ hasOwnFields: boolean;
1052
+ backfillOwnFields: boolean;
1000
1053
  },
1001
1054
  ) {
1002
1055
  const enrichmentOptions =
@@ -1018,7 +1071,7 @@ export class Feed extends FeedApi {
1018
1071
  const fieldsToUpdate: Array<
1019
1072
  'own_capabilities' | 'own_follows' | 'own_followings' | 'own_membership'
1020
1073
  > = [];
1021
- if (!options.fromWebSocket) {
1074
+ if (options.hasOwnFields) {
1022
1075
  fieldsToUpdate.push('own_membership');
1023
1076
  if (!enrichmentOptions?.skip_own_capabilities) {
1024
1077
  fieldsToUpdate.push('own_capabilities');
@@ -1038,7 +1091,7 @@ export class Feed extends FeedApi {
1038
1091
  fieldsToUpdate,
1039
1092
  });
1040
1093
  });
1041
- if (options.fromWebSocket) {
1094
+ if (!options.hasOwnFields && options.backfillOwnFields) {
1042
1095
  const uninitializedFeeds = newFeeds.filter((feedResponse) => {
1043
1096
  const feed = this.client.feed(feedResponse.group_id, feedResponse.id);
1044
1097
  // own_capabilities can only be undefined if we haven't fetched it yet
@@ -0,0 +1,9 @@
1
+ import type { Feed } from '../feed/feed';
2
+ import type { ActivityResponse } from '../gen/models';
3
+
4
+ export function applyNewActivityToActiveFeeds(
5
+ this: Feed,
6
+ activity: ActivityResponse,
7
+ ): void {
8
+ return this.addActivityFromHTTPResponse(activity);
9
+ }