@stream-io/feeds-client 0.2.12 → 0.2.14

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 (53) 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 +22 -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 +22 -14
  8. package/dist/es/react-bindings.mjs.map +1 -1
  9. package/dist/{index-o7AeSkxa.js → index-B08vVRSZ.js} +159 -9
  10. package/dist/index-B08vVRSZ.js.map +1 -0
  11. package/dist/{index-D7QtnkUs.mjs → index-B3HHiF9S.mjs} +159 -9
  12. package/dist/index-B3HHiF9S.mjs.map +1 -0
  13. package/dist/tsconfig.tsbuildinfo +1 -1
  14. package/dist/types/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.d.ts +9 -4
  15. package/dist/types/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.d.ts.map +1 -1
  16. package/dist/types/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.d.ts.map +1 -1
  17. package/dist/types/common/real-time/StableWSConnection.d.ts +3 -3
  18. package/dist/types/common/real-time/StableWSConnection.d.ts.map +1 -1
  19. package/dist/types/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.d.ts +24 -0
  20. package/dist/types/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.d.ts.map +1 -0
  21. package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts +2 -0
  22. package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts.map +1 -0
  23. package/dist/types/feed/event-handlers/index.d.ts +1 -1
  24. package/dist/types/feed/event-handlers/index.d.ts.map +1 -1
  25. package/dist/types/feed/feed.d.ts +2 -2
  26. package/dist/types/feed/feed.d.ts.map +1 -1
  27. package/dist/types/feeds-client/feeds-client.d.ts +2 -2
  28. package/dist/types/gen/model-decoders/event-decoder-mapping.d.ts.map +1 -1
  29. package/dist/types/gen/models/index.d.ts +17 -1
  30. package/dist/types/gen/models/index.d.ts.map +1 -1
  31. package/dist/types/utils/unique-array-merge.d.ts +1 -0
  32. package/dist/types/utils/unique-array-merge.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/bindings/react/hooks/feed-state-hooks/useAggregatedActivities.ts +28 -4
  35. package/src/bindings/react/hooks/feed-state-hooks/useIsAggregatedActivityRead.ts +4 -5
  36. package/src/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.test.ts +644 -0
  37. package/src/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.ts +193 -0
  38. package/src/feed/event-handlers/aggregated-feed/index.ts +1 -0
  39. package/src/feed/event-handlers/index.ts +1 -1
  40. package/src/feed/feed.ts +23 -1
  41. package/src/gen/model-decoders/decoders.ts +14 -0
  42. package/src/gen/model-decoders/event-decoder-mapping.ts +3 -0
  43. package/src/gen/models/index.ts +26 -2
  44. package/src/utils/unique-array-merge.ts +30 -0
  45. package/dist/index-D7QtnkUs.mjs.map +0 -1
  46. package/dist/index-o7AeSkxa.js.map +0 -1
  47. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +0 -11
  48. package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +0 -1
  49. package/dist/types/feed/event-handlers/notification-feed/index.d.ts +0 -2
  50. package/dist/types/feed/event-handlers/notification-feed/index.d.ts.map +0 -1
  51. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.test.ts +0 -120
  52. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +0 -54
  53. package/src/feed/event-handlers/notification-feed/index.ts +0 -1
@@ -0,0 +1,193 @@
1
+ import type { Feed } from '../..';
2
+ import type {
3
+ AggregatedActivityResponse,
4
+ NotificationFeedUpdatedEvent,
5
+ NotificationStatusResponse,
6
+ StoriesFeedUpdatedEvent,
7
+ } from '../../../gen/models';
8
+ import type { EventPayload, UpdateStateResult } from '../../../types-internal';
9
+ import { replaceUniqueArrayMerge, uniqueArrayMerge } from '../../../utils';
10
+
11
+ export const addAggregatedActivitiesToState = (
12
+ newAggregatedActivities: AggregatedActivityResponse[],
13
+ aggregatedActivities: AggregatedActivityResponse[] | undefined,
14
+ position: 'start' | 'end' | 'replace',
15
+ ) => {
16
+ let result: UpdateStateResult<{
17
+ aggregated_activities: AggregatedActivityResponse[];
18
+ }>;
19
+ if (newAggregatedActivities.length === 0) {
20
+ result = {
21
+ changed: false,
22
+ aggregated_activities: [],
23
+ };
24
+ } else {
25
+ result = {
26
+ changed: true,
27
+ aggregated_activities: [],
28
+ };
29
+ }
30
+
31
+ switch (position) {
32
+ case 'start':
33
+ result.aggregated_activities = uniqueArrayMerge(
34
+ newAggregatedActivities,
35
+ aggregatedActivities ?? [],
36
+ (a) => a.group,
37
+ );
38
+ break;
39
+ case 'end':
40
+ result.aggregated_activities = uniqueArrayMerge(
41
+ aggregatedActivities ?? [],
42
+ newAggregatedActivities,
43
+ (a) => a.group,
44
+ );
45
+ break;
46
+ case 'replace':
47
+ result.aggregated_activities = replaceUniqueArrayMerge(
48
+ aggregatedActivities ?? [],
49
+ newAggregatedActivities,
50
+ (a) => a.group,
51
+ );
52
+ break;
53
+ }
54
+
55
+ return result;
56
+ };
57
+
58
+ export const updateNotificationStatus = (
59
+ newNotificationStatus?: NotificationStatusResponse,
60
+ currentNotificationStatus?: NotificationStatusResponse,
61
+ ) => {
62
+ if (!newNotificationStatus && !currentNotificationStatus) {
63
+ return {
64
+ changed: false,
65
+ notification_status: undefined,
66
+ };
67
+ } else if (!newNotificationStatus) {
68
+ return {
69
+ changed: false,
70
+ notification_status: currentNotificationStatus,
71
+ };
72
+ } else {
73
+ return {
74
+ changed: true,
75
+ notification_status: {
76
+ ...newNotificationStatus,
77
+ },
78
+ };
79
+ }
80
+ };
81
+
82
+ export const updateNotificationFeedFromEvent = (
83
+ event: NotificationFeedUpdatedEvent,
84
+ currentAggregatedActivities?: AggregatedActivityResponse[],
85
+ currentNotificationStatus?: NotificationStatusResponse,
86
+ ): UpdateStateResult<{
87
+ data?: {
88
+ notification_status?: NotificationStatusResponse;
89
+ aggregated_activities?: AggregatedActivityResponse[];
90
+ };
91
+ }> => {
92
+ const updates: {
93
+ notification_status?: NotificationStatusResponse;
94
+ aggregated_activities?: AggregatedActivityResponse[];
95
+ } = {};
96
+
97
+ if (event.notification_status && currentNotificationStatus) {
98
+ const notificationStatusResult = updateNotificationStatus(
99
+ event.notification_status,
100
+ currentNotificationStatus,
101
+ );
102
+
103
+ if (notificationStatusResult.changed) {
104
+ updates.notification_status =
105
+ notificationStatusResult.notification_status;
106
+ }
107
+ }
108
+
109
+ if (event.aggregated_activities && currentAggregatedActivities) {
110
+ const aggregatedActivitiesResult = addAggregatedActivitiesToState(
111
+ event.aggregated_activities,
112
+ currentAggregatedActivities,
113
+ 'start',
114
+ );
115
+
116
+ if (aggregatedActivitiesResult.changed) {
117
+ updates.aggregated_activities =
118
+ aggregatedActivitiesResult.aggregated_activities;
119
+ }
120
+ }
121
+
122
+ if (Object.keys(updates).length > 0) {
123
+ return {
124
+ changed: true,
125
+ data: updates,
126
+ };
127
+ }
128
+
129
+ return {
130
+ changed: false,
131
+ };
132
+ };
133
+
134
+ export function handleNotificationFeedUpdated(
135
+ this: Feed,
136
+ event: EventPayload<'feeds.notification_feed.updated'>,
137
+ ) {
138
+ const result = updateNotificationFeedFromEvent(
139
+ event,
140
+ this.currentState.aggregated_activities,
141
+ this.currentState.notification_status,
142
+ );
143
+ if (result.changed) {
144
+ this.state.partialNext({
145
+ notification_status: result.data?.notification_status,
146
+ aggregated_activities: result.data?.aggregated_activities,
147
+ });
148
+ }
149
+ }
150
+
151
+ export function updateStoriesFeedFromEvent(
152
+ aggregatedActivities: AggregatedActivityResponse[] | undefined,
153
+ event: StoriesFeedUpdatedEvent,
154
+ ): UpdateStateResult<{
155
+ data?: {
156
+ aggregated_activities?: AggregatedActivityResponse[];
157
+ };
158
+ }> {
159
+ if (!aggregatedActivities) {
160
+ return {
161
+ changed: false,
162
+ };
163
+ }
164
+
165
+ if (event.aggregated_activities) {
166
+ const result = addAggregatedActivitiesToState(
167
+ event.aggregated_activities,
168
+ aggregatedActivities,
169
+ 'replace',
170
+ );
171
+
172
+ return result;
173
+ }
174
+
175
+ return {
176
+ changed: false,
177
+ };
178
+ }
179
+
180
+ export function handleStoriesFeedUpdated(
181
+ this: Feed,
182
+ event: EventPayload<'feeds.stories_feed.updated'>,
183
+ ) {
184
+ const result = updateStoriesFeedFromEvent(
185
+ this.currentState.aggregated_activities,
186
+ event,
187
+ );
188
+ if (result.changed) {
189
+ this.state.partialNext({
190
+ aggregated_activities: result.data?.aggregated_activities,
191
+ });
192
+ }
193
+ }
@@ -0,0 +1 @@
1
+ export * from './handle-aggregated-feed-updated';
@@ -4,5 +4,5 @@ export * from './feed-member';
4
4
  export * from './bookmark';
5
5
  export * from './activity';
6
6
  export * from './feed';
7
- export * from './notification-feed';
7
+ export * from './aggregated-feed';
8
8
  export * from './watch';
package/src/feed/feed.ts CHANGED
@@ -44,6 +44,9 @@ import {
44
44
  handleActivityReactionDeleted,
45
45
  handleCommentReactionAdded,
46
46
  handleCommentReactionDeleted,
47
+ addAggregatedActivitiesToState,
48
+ updateNotificationStatus,
49
+ handleStoriesFeedUpdated,
47
50
  } from './event-handlers';
48
51
  import { capitalize } from '../common/utils';
49
52
  import type {
@@ -175,6 +178,7 @@ export class Feed extends FeedApi {
175
178
  'feeds.feed_member.removed': handleFeedMemberRemoved.bind(this),
176
179
  'feeds.feed_member.updated': handleFeedMemberUpdated.bind(this),
177
180
  'feeds.notification_feed.updated': handleNotificationFeedUpdated.bind(this),
181
+ 'feeds.stories_feed.updated': handleStoriesFeedUpdated.bind(this),
178
182
  // the poll events should be removed from here
179
183
  'feeds.poll.closed': Feed.noop,
180
184
  'feeds.poll.deleted': Feed.noop,
@@ -279,9 +283,27 @@ export class Feed extends FeedApi {
279
283
  'end',
280
284
  );
281
285
 
282
- if (result.changed) {
286
+ const aggregatedActivitiesResult = addAggregatedActivitiesToState(
287
+ response.aggregated_activities,
288
+ this.currentState.aggregated_activities,
289
+ 'end',
290
+ );
291
+
292
+ const notificationStatusResult = updateNotificationStatus(
293
+ response.notification_status,
294
+ this.currentState.notification_status,
295
+ );
296
+
297
+ if (
298
+ result.changed ||
299
+ aggregatedActivitiesResult.changed ||
300
+ notificationStatusResult.changed
301
+ ) {
283
302
  this.state.partialNext({
284
303
  activities: result.activities,
304
+ aggregated_activities:
305
+ aggregatedActivitiesResult.aggregated_activities,
306
+ notification_status: notificationStatusResult.notification_status,
285
307
  next: response.next,
286
308
  prev: response.prev,
287
309
  });
@@ -1739,6 +1739,20 @@ decoders.SingleFollowResponse = (input?: Record<string, any>) => {
1739
1739
  return decode(typeMappings, input);
1740
1740
  };
1741
1741
 
1742
+ decoders.StoriesFeedUpdatedEvent = (input?: Record<string, any>) => {
1743
+ const typeMappings: TypeMapping = {
1744
+ created_at: { type: 'DatetimeType', isSingle: true },
1745
+
1746
+ received_at: { type: 'DatetimeType', isSingle: true },
1747
+
1748
+ aggregated_activities: {
1749
+ type: 'AggregatedActivityResponse',
1750
+ isSingle: false,
1751
+ },
1752
+ };
1753
+ return decode(typeMappings, input);
1754
+ };
1755
+
1742
1756
  decoders.SubmitActionResponse = (input?: Record<string, any>) => {
1743
1757
  const typeMappings: TypeMapping = {
1744
1758
  item: { type: 'ReviewQueueItemResponse', isSingle: true },
@@ -124,6 +124,9 @@ const eventDecoderMapping: Record<
124
124
  'feeds.poll.vote_removed': (data: Record<string, any>) =>
125
125
  decoders.PollVoteRemovedFeedEvent(data),
126
126
 
127
+ 'feeds.stories_feed.updated': (data: Record<string, any>) =>
128
+ decoders.StoriesFeedUpdatedEvent(data),
129
+
127
130
  'health.check': (data: Record<string, any>) =>
128
131
  decoders.HealthCheckEvent(data),
129
132
 
@@ -463,6 +463,8 @@ export interface ActivityResponse {
463
463
 
464
464
  hidden?: boolean;
465
465
 
466
+ is_watched?: boolean;
467
+
466
468
  text?: string;
467
469
 
468
470
  visibility_tag?: string;
@@ -680,6 +682,8 @@ export interface AggregatedActivityResponse {
680
682
  user_count_truncated: boolean;
681
683
 
682
684
  activities: ActivityResponse[];
685
+
686
+ is_watched?: boolean;
683
687
  }
684
688
 
685
689
  export interface AggregationConfig {
@@ -5548,9 +5552,27 @@ export interface SpeechSegmentConfig {
5548
5552
  }
5549
5553
 
5550
5554
  export interface StoriesConfig {
5551
- expiration_behaviour?: 'hide_for_everyone' | 'visible_for_author';
5552
-
5553
5555
  skip_watched?: boolean;
5556
+
5557
+ track_watched?: boolean;
5558
+ }
5559
+
5560
+ export interface StoriesFeedUpdatedEvent {
5561
+ created_at: Date;
5562
+
5563
+ fid: string;
5564
+
5565
+ custom: Record<string, any>;
5566
+
5567
+ type: string;
5568
+
5569
+ feed_visibility?: string;
5570
+
5571
+ received_at?: Date;
5572
+
5573
+ aggregated_activities?: AggregatedActivityResponse[];
5574
+
5575
+ user?: UserResponseCommonFields;
5554
5576
  }
5555
5577
 
5556
5578
  export interface SubmitActionRequest {
@@ -6571,6 +6593,7 @@ export type WSClientEvent =
6571
6593
  | ({ type: 'feeds.poll.vote_casted' } & PollVoteCastedFeedEvent)
6572
6594
  | ({ type: 'feeds.poll.vote_changed' } & PollVoteChangedFeedEvent)
6573
6595
  | ({ type: 'feeds.poll.vote_removed' } & PollVoteRemovedFeedEvent)
6596
+ | ({ type: 'feeds.stories_feed.updated' } & StoriesFeedUpdatedEvent)
6574
6597
  | ({ type: 'health.check' } & HealthCheckEvent)
6575
6598
  | ({ type: 'user.updated' } & UserUpdatedEvent);
6576
6599
 
@@ -6617,6 +6640,7 @@ export type WSEvent =
6617
6640
  | ({ type: 'feeds.poll.vote_casted' } & PollVoteCastedFeedEvent)
6618
6641
  | ({ type: 'feeds.poll.vote_changed' } & PollVoteChangedFeedEvent)
6619
6642
  | ({ type: 'feeds.poll.vote_removed' } & PollVoteRemovedFeedEvent)
6643
+ | ({ type: 'feeds.stories_feed.updated' } & StoriesFeedUpdatedEvent)
6620
6644
  | ({ type: 'health.check' } & HealthCheckEvent)
6621
6645
  | ({ type: 'moderation.custom_action' } & ModerationCustomActionEvent)
6622
6646
  | ({ type: 'moderation.flagged' } & ModerationFlaggedEvent)
@@ -17,3 +17,33 @@ export const uniqueArrayMerge = <T>(
17
17
 
18
18
  return existingArray.concat(filteredArrayToMerge);
19
19
  };
20
+
21
+ export const replaceUniqueArrayMerge = <T>(
22
+ existingArray: T[],
23
+ arrayToMerge: T[],
24
+ getKey: (v: T) => string,
25
+ ) => {
26
+ const existingMap = new Map<string, T>();
27
+ (existingArray ?? []).forEach((item) => {
28
+ existingMap.set(getKey(item), item);
29
+ });
30
+
31
+ const result: T[] = [];
32
+ arrayToMerge.forEach((item) => {
33
+ existingMap.set(getKey(item), item);
34
+ });
35
+
36
+ existingArray.forEach((originalItem) => {
37
+ const updatedItem = existingMap.get(getKey(originalItem));
38
+ if (updatedItem) {
39
+ result.push(updatedItem);
40
+ existingMap.delete(getKey(originalItem));
41
+ }
42
+ });
43
+
44
+ existingMap.forEach((item) => {
45
+ result.push(item);
46
+ });
47
+
48
+ return result;
49
+ };