@stream-io/feeds-client 0.2.17 → 0.2.18
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.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/react-bindings.js +1 -1
- package/dist/es/index.mjs +2 -2
- package/dist/es/react-bindings.mjs +1 -1
- package/dist/{index-nq6SDtbt.js → index--koeDtxd.js} +147 -56
- package/dist/index--koeDtxd.js.map +1 -0
- package/dist/{index-BZL77zNq.mjs → index-Zde8UE5f.mjs} +147 -56
- package/dist/index-Zde8UE5f.mjs.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts +4 -3
- package/dist/types/feed/event-handlers/activity/handle-activity-added.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity-updater.d.ts +44 -0
- package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts +6 -0
- package/dist/types/feed/event-handlers/add-aggregated-activities-to-state.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/index.d.ts +3 -1
- package/dist/types/feed/event-handlers/index.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/{aggregated-feed/handle-aggregated-feed-updated.d.ts → notification-feed/handle-notification-feed-updated.d.ts} +2 -11
- package/dist/types/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/notification-feed/index.d.ts +2 -0
- package/dist/types/feed/event-handlers/notification-feed/index.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/story-feeds/handle-story-feeds-updated.d.ts +15 -0
- package/dist/types/feed/event-handlers/story-feeds/handle-story-feeds-updated.d.ts.map +1 -0
- package/dist/types/feed/event-handlers/story-feeds/index.d.ts +2 -0
- package/dist/types/feed/event-handlers/story-feeds/index.d.ts.map +1 -0
- package/dist/types/feed/feed.d.ts +9 -3
- package/dist/types/feed/feed.d.ts.map +1 -1
- package/dist/types/feeds-client/feeds-client.d.ts +5 -3
- package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
- package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
- package/dist/types/gen/models/index.d.ts +42 -451
- package/dist/types/gen/models/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/feed/event-handlers/activity/handle-activity-added.test.ts +16 -5
- package/src/feed/event-handlers/activity/handle-activity-added.ts +9 -11
- package/src/feed/event-handlers/activity/handle-activity-updated.ts +8 -16
- package/src/feed/event-handlers/activity-updater.ts +15 -0
- package/src/feed/event-handlers/add-aggregated-activities-to-state.test.ts +510 -0
- package/src/feed/event-handlers/add-aggregated-activities-to-state.ts +72 -0
- package/src/feed/event-handlers/index.ts +3 -1
- package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.test.ts +182 -0
- package/src/feed/event-handlers/{aggregated-feed/handle-aggregated-feed-updated.ts → notification-feed/handle-notification-feed-updated.ts} +2 -94
- package/src/feed/event-handlers/notification-feed/index.ts +1 -0
- package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.test.ts +45 -0
- package/src/feed/event-handlers/story-feeds/handle-story-feeds-updated.ts +122 -0
- package/src/feed/event-handlers/story-feeds/index.ts +1 -0
- package/src/feed/feed.ts +12 -0
- package/src/feeds-client/feeds-client.ts +21 -3
- package/src/gen/feeds/FeedsApi.ts +5 -0
- package/src/gen/model-decoders/decoders.ts +10 -4
- package/src/gen/models/index.ts +75 -834
- package/src/test-utils/response-generators.ts +37 -1
- package/dist/index-BZL77zNq.mjs.map +0 -1
- package/dist/index-nq6SDtbt.js.map +0 -1
- package/dist/types/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.d.ts.map +0 -1
- package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts +0 -2
- package/dist/types/feed/event-handlers/aggregated-feed/index.d.ts.map +0 -1
- package/src/feed/event-handlers/activity/activity-utils.test.ts +0 -252
- package/src/feed/event-handlers/aggregated-feed/handle-aggregated-feed-updated.test.ts +0 -644
- package/src/feed/event-handlers/aggregated-feed/index.ts +0 -1
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
updateNotificationFeedFromEvent,
|
|
4
|
+
updateNotificationStatus,
|
|
5
|
+
} from './handle-notification-feed-updated';
|
|
6
|
+
import {
|
|
7
|
+
createMockAggregatedActivity,
|
|
8
|
+
createMockNotificationFeedUpdatedEvent,
|
|
9
|
+
createMockNotificationStatus,
|
|
10
|
+
} from '../../../test-utils';
|
|
11
|
+
|
|
12
|
+
describe('notification-feed-utils', () => {
|
|
13
|
+
describe('updateNotificationFeedFromEvent', () => {
|
|
14
|
+
it('should return unchanged if event has no notification_status or aggregated_activities', () => {
|
|
15
|
+
const event = createMockNotificationFeedUpdatedEvent();
|
|
16
|
+
|
|
17
|
+
const result = updateNotificationFeedFromEvent(event, [], {
|
|
18
|
+
unread: 0,
|
|
19
|
+
unseen: 0,
|
|
20
|
+
read_activities: [],
|
|
21
|
+
seen_activities: [],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(result.changed).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it(`should update notification_status when event has notification_status and currentNotificationStatus is undefined`, () => {
|
|
28
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
29
|
+
notification_status: createMockNotificationStatus(),
|
|
30
|
+
});
|
|
31
|
+
const result = updateNotificationFeedFromEvent(event, [], undefined);
|
|
32
|
+
|
|
33
|
+
expect(result.changed).toBe(true);
|
|
34
|
+
expect(result.data?.notification_status).toStrictEqual(
|
|
35
|
+
event.notification_status,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it(`shouldn't update aggregated_activities when event has aggregated_activities but currentAggregatedActivities is undefined`, () => {
|
|
40
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
41
|
+
aggregated_activities: [createMockAggregatedActivity()],
|
|
42
|
+
});
|
|
43
|
+
const result = updateNotificationFeedFromEvent(
|
|
44
|
+
event,
|
|
45
|
+
undefined,
|
|
46
|
+
createMockNotificationStatus(),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(result.changed).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should update notification_status when event has notification_status', () => {
|
|
53
|
+
const notificationStatus = createMockNotificationStatus({
|
|
54
|
+
unread: 5,
|
|
55
|
+
unseen: 3,
|
|
56
|
+
read_activities: ['activity1', 'activity2'],
|
|
57
|
+
seen_activities: [],
|
|
58
|
+
});
|
|
59
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
60
|
+
notification_status: notificationStatus,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const result = updateNotificationFeedFromEvent(event, [], {
|
|
64
|
+
unread: 0,
|
|
65
|
+
unseen: 0,
|
|
66
|
+
read_activities: [],
|
|
67
|
+
seen_activities: [],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(result.changed).toBe(true);
|
|
71
|
+
expect(result.data?.notification_status).toStrictEqual(
|
|
72
|
+
notificationStatus,
|
|
73
|
+
);
|
|
74
|
+
expect(result.data?.aggregated_activities).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should update aggregated_activities when event has aggregated_activities', () => {
|
|
78
|
+
const aggregatedActivities = [
|
|
79
|
+
createMockAggregatedActivity({ group: 'group1' }),
|
|
80
|
+
createMockAggregatedActivity({ group: 'group2' }),
|
|
81
|
+
];
|
|
82
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
83
|
+
aggregated_activities: aggregatedActivities,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const result = updateNotificationFeedFromEvent(event, [], {
|
|
87
|
+
unread: 0,
|
|
88
|
+
unseen: 0,
|
|
89
|
+
read_activities: [],
|
|
90
|
+
seen_activities: [],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(result.changed).toBe(true);
|
|
94
|
+
expect(result.data?.aggregated_activities).toStrictEqual(
|
|
95
|
+
aggregatedActivities,
|
|
96
|
+
);
|
|
97
|
+
expect(result.data?.notification_status).toBeUndefined();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should update both notification_status and aggregated_activities when event has both', () => {
|
|
101
|
+
const notificationStatus = createMockNotificationStatus({
|
|
102
|
+
unread: 2,
|
|
103
|
+
unseen: 1,
|
|
104
|
+
});
|
|
105
|
+
const aggregatedActivities = [
|
|
106
|
+
createMockAggregatedActivity({ group: 'group1' }),
|
|
107
|
+
];
|
|
108
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
109
|
+
notification_status: notificationStatus,
|
|
110
|
+
aggregated_activities: aggregatedActivities,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const result = updateNotificationFeedFromEvent(event, [], {
|
|
114
|
+
unread: 0,
|
|
115
|
+
unseen: 0,
|
|
116
|
+
read_activities: [],
|
|
117
|
+
seen_activities: [],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(result.changed).toBe(true);
|
|
121
|
+
expect(result.data?.notification_status?.unread).toBe(
|
|
122
|
+
notificationStatus.unread,
|
|
123
|
+
);
|
|
124
|
+
expect(result.data?.notification_status?.unseen).toBe(
|
|
125
|
+
notificationStatus.unseen,
|
|
126
|
+
);
|
|
127
|
+
expect(result.data?.aggregated_activities).toStrictEqual(
|
|
128
|
+
aggregatedActivities,
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle notification_status with all fields', () => {
|
|
133
|
+
const notificationStatus = createMockNotificationStatus({
|
|
134
|
+
unread: 10,
|
|
135
|
+
unseen: 5,
|
|
136
|
+
last_seen_at: new Date('2023-01-01'),
|
|
137
|
+
seen_activities: [],
|
|
138
|
+
read_activities: ['activity1', 'activity2', 'activity3'],
|
|
139
|
+
});
|
|
140
|
+
const event = createMockNotificationFeedUpdatedEvent({
|
|
141
|
+
notification_status: notificationStatus,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const result = updateNotificationFeedFromEvent(event, [], {
|
|
145
|
+
unread: 0,
|
|
146
|
+
unseen: 0,
|
|
147
|
+
read_activities: [],
|
|
148
|
+
seen_activities: [],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
expect(result.changed).toBe(true);
|
|
152
|
+
expect(result.data?.notification_status).toStrictEqual(
|
|
153
|
+
notificationStatus,
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('updateNotificationStatus', () => {
|
|
159
|
+
it('should replace old state with new one', () => {
|
|
160
|
+
const newNotificationStatus = createMockNotificationStatus({
|
|
161
|
+
unread: 5,
|
|
162
|
+
unseen: 3,
|
|
163
|
+
read_activities: ['activity1', 'activity2'],
|
|
164
|
+
seen_activities: ['activity3', 'activity4'],
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const currentNotificationStatus = createMockNotificationStatus({
|
|
168
|
+
unread: 2,
|
|
169
|
+
unseen: 1,
|
|
170
|
+
read_activities: ['activity5', 'activity6'],
|
|
171
|
+
seen_activities: ['activity7', 'activity8'],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const result = updateNotificationStatus(
|
|
175
|
+
newNotificationStatus,
|
|
176
|
+
currentNotificationStatus,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
expect(result.notification_status).toStrictEqual(newNotificationStatus);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
});
|
|
@@ -3,57 +3,9 @@ import type {
|
|
|
3
3
|
AggregatedActivityResponse,
|
|
4
4
|
NotificationFeedUpdatedEvent,
|
|
5
5
|
NotificationStatusResponse,
|
|
6
|
-
StoriesFeedUpdatedEvent,
|
|
7
6
|
} from '../../../gen/models';
|
|
8
7
|
import type { EventPayload, UpdateStateResult } from '../../../types-internal';
|
|
9
|
-
import {
|
|
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
|
-
};
|
|
8
|
+
import { addAggregatedActivitiesToState } from '../add-aggregated-activities-to-state';
|
|
57
9
|
|
|
58
10
|
export const updateNotificationStatus = (
|
|
59
11
|
newNotificationStatus?: NotificationStatusResponse,
|
|
@@ -94,7 +46,7 @@ export const updateNotificationFeedFromEvent = (
|
|
|
94
46
|
aggregated_activities?: AggregatedActivityResponse[];
|
|
95
47
|
} = {};
|
|
96
48
|
|
|
97
|
-
if (event.notification_status
|
|
49
|
+
if (event.notification_status) {
|
|
98
50
|
const notificationStatusResult = updateNotificationStatus(
|
|
99
51
|
event.notification_status,
|
|
100
52
|
currentNotificationStatus,
|
|
@@ -147,47 +99,3 @@ export function handleNotificationFeedUpdated(
|
|
|
147
99
|
});
|
|
148
100
|
}
|
|
149
101
|
}
|
|
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-notification-feed-updated';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateActivityResponse,
|
|
3
|
+
generateFeedReactionResponse,
|
|
4
|
+
} from '../../../test-utils';
|
|
5
|
+
import { updateActivities } from './handle-story-feeds-updated';
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
|
|
8
|
+
describe('updateActivities', () => {
|
|
9
|
+
it('should return unchanged if new activities is empty', () => {
|
|
10
|
+
const currentActivities = [generateActivityResponse({ id: 'activity1' })];
|
|
11
|
+
const result = updateActivities([], currentActivities);
|
|
12
|
+
expect(result.changed).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should return unchanged if current activities is undefined', () => {
|
|
16
|
+
const newActivities = [generateActivityResponse({ id: 'activity1' })];
|
|
17
|
+
const result = updateActivities(newActivities, undefined);
|
|
18
|
+
expect(result.changed).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should update existing activities, ignore new ones', () => {
|
|
22
|
+
const newActivities = [
|
|
23
|
+
generateActivityResponse({ id: 'activity1', is_watched: true }),
|
|
24
|
+
generateActivityResponse({ id: 'activity3' }),
|
|
25
|
+
];
|
|
26
|
+
const currentActivities = [
|
|
27
|
+
generateActivityResponse({
|
|
28
|
+
id: 'activity1',
|
|
29
|
+
own_reactions: [generateFeedReactionResponse({ type: 'like' })],
|
|
30
|
+
}),
|
|
31
|
+
generateActivityResponse({
|
|
32
|
+
id: 'activity2',
|
|
33
|
+
}),
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const result = updateActivities(newActivities, currentActivities);
|
|
37
|
+
|
|
38
|
+
expect(result.changed).toBe(true);
|
|
39
|
+
expect(result.activities).toHaveLength(2);
|
|
40
|
+
expect(result.activities[0].own_reactions).toHaveLength(1);
|
|
41
|
+
expect(result.activities[0].own_reactions[0].type).toBe('like');
|
|
42
|
+
expect(result.activities[0].is_watched).toBe(true);
|
|
43
|
+
expect(result.activities[1].id).toBe('activity2');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ActivityResponse,
|
|
3
|
+
AggregatedActivityResponse,
|
|
4
|
+
StoriesFeedUpdatedEvent,
|
|
5
|
+
} from '../../../gen/models';
|
|
6
|
+
import type { UpdateStateResult, EventPayload } from '../../../types-internal';
|
|
7
|
+
import type { Feed } from '../../feed';
|
|
8
|
+
import { updateActivity } from '../activity-updater';
|
|
9
|
+
import { addAggregatedActivitiesToState } from '../add-aggregated-activities-to-state';
|
|
10
|
+
|
|
11
|
+
export const updateActivities = (
|
|
12
|
+
activitiesToUpsert: ActivityResponse[],
|
|
13
|
+
currentActivities: ActivityResponse[] | undefined,
|
|
14
|
+
) => {
|
|
15
|
+
if (
|
|
16
|
+
!activitiesToUpsert ||
|
|
17
|
+
activitiesToUpsert.length === 0 ||
|
|
18
|
+
!currentActivities
|
|
19
|
+
) {
|
|
20
|
+
return {
|
|
21
|
+
changed: false,
|
|
22
|
+
activities: currentActivities ?? [],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result: ActivityResponse[] = [];
|
|
27
|
+
for (let i = 0; i < currentActivities.length; i++) {
|
|
28
|
+
const activity = currentActivities[i];
|
|
29
|
+
const updatedActivity = activitiesToUpsert.find(
|
|
30
|
+
(a) => a.id === activity.id,
|
|
31
|
+
);
|
|
32
|
+
if (updatedActivity) {
|
|
33
|
+
result.push(
|
|
34
|
+
updateActivity({
|
|
35
|
+
currentActivity: activity,
|
|
36
|
+
newActivtiy: updatedActivity,
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
} else {
|
|
40
|
+
result.push(activity);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
changed: true,
|
|
46
|
+
activities: result,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function updateStoriesFeedFromEvent(
|
|
51
|
+
aggregatedActivities: AggregatedActivityResponse[] | undefined,
|
|
52
|
+
activities: ActivityResponse[] | undefined,
|
|
53
|
+
event: StoriesFeedUpdatedEvent,
|
|
54
|
+
): UpdateStateResult<{
|
|
55
|
+
data?: {
|
|
56
|
+
aggregated_activities?: AggregatedActivityResponse[];
|
|
57
|
+
activities?: ActivityResponse[];
|
|
58
|
+
};
|
|
59
|
+
}> {
|
|
60
|
+
if (
|
|
61
|
+
(!aggregatedActivities &&
|
|
62
|
+
event.aggregated_activities &&
|
|
63
|
+
event.aggregated_activities?.length > 0) ||
|
|
64
|
+
(!activities && event.activities && event.activities?.length > 0)
|
|
65
|
+
) {
|
|
66
|
+
return {
|
|
67
|
+
changed: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = {
|
|
72
|
+
changed: true,
|
|
73
|
+
data: {
|
|
74
|
+
aggregated_activities: aggregatedActivities,
|
|
75
|
+
activities: activities,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
if (event.aggregated_activities) {
|
|
79
|
+
const aggregatedActivitiesResult = addAggregatedActivitiesToState(
|
|
80
|
+
event.aggregated_activities,
|
|
81
|
+
aggregatedActivities,
|
|
82
|
+
'replace',
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (aggregatedActivitiesResult.changed) {
|
|
86
|
+
result.data.aggregated_activities =
|
|
87
|
+
aggregatedActivitiesResult.aggregated_activities;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (event.activities) {
|
|
92
|
+
const activitiesResult = updateActivities(event.activities, activities);
|
|
93
|
+
if (activitiesResult.changed) {
|
|
94
|
+
result.data.activities = activitiesResult.activities;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (event.aggregated_activities || event.activities) {
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
changed: false,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function handleStoriesFeedUpdated(
|
|
108
|
+
this: Feed,
|
|
109
|
+
event: EventPayload<'feeds.stories_feed.updated'>,
|
|
110
|
+
) {
|
|
111
|
+
const result = updateStoriesFeedFromEvent(
|
|
112
|
+
this.currentState.aggregated_activities,
|
|
113
|
+
this.currentState.activities,
|
|
114
|
+
event,
|
|
115
|
+
);
|
|
116
|
+
if (result.changed) {
|
|
117
|
+
this.state.partialNext({
|
|
118
|
+
aggregated_activities: result.data?.aggregated_activities,
|
|
119
|
+
activities: result.data?.activities,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './handle-story-feeds-updated';
|
package/src/feed/feed.ts
CHANGED
|
@@ -131,6 +131,12 @@ export type FeedState = Omit<
|
|
|
131
131
|
* `true` if the feed is receiving real-time updates via WebSocket
|
|
132
132
|
*/
|
|
133
133
|
watch: boolean;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 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.
|
|
137
|
+
* Useful for story feeds.
|
|
138
|
+
*/
|
|
139
|
+
addNewActivitiesTo: 'start' | 'end';
|
|
134
140
|
};
|
|
135
141
|
|
|
136
142
|
type EventHandlerByEventType = {
|
|
@@ -212,6 +218,7 @@ export class Feed extends FeedApi {
|
|
|
212
218
|
id: string,
|
|
213
219
|
data?: FeedResponse,
|
|
214
220
|
watch = false,
|
|
221
|
+
addNewActivitiesTo: 'start' | 'end' = 'start',
|
|
215
222
|
) {
|
|
216
223
|
super(client, groupId, id);
|
|
217
224
|
this.state = new StateStore<FeedState>({
|
|
@@ -223,6 +230,7 @@ export class Feed extends FeedApi {
|
|
|
223
230
|
is_loading_activities: false,
|
|
224
231
|
comments_by_entity_id: {},
|
|
225
232
|
watch,
|
|
233
|
+
addNewActivitiesTo,
|
|
226
234
|
});
|
|
227
235
|
this.client = client;
|
|
228
236
|
|
|
@@ -250,6 +258,10 @@ export class Feed extends FeedApi {
|
|
|
250
258
|
return this.state.getLatestValue();
|
|
251
259
|
}
|
|
252
260
|
|
|
261
|
+
set addNewActivitiesTo(value: 'start' | 'end') {
|
|
262
|
+
this.state.partialNext({ addNewActivitiesTo: value });
|
|
263
|
+
}
|
|
264
|
+
|
|
253
265
|
hasActivity(activityId: string) {
|
|
254
266
|
return this.indexedActivityIds.has(activityId);
|
|
255
267
|
}
|
|
@@ -525,8 +525,18 @@ export class FeedsClient extends FeedsApi {
|
|
|
525
525
|
on = this.eventDispatcher.on;
|
|
526
526
|
off = this.eventDispatcher.off;
|
|
527
527
|
|
|
528
|
-
feed = (
|
|
529
|
-
|
|
528
|
+
feed = (
|
|
529
|
+
groupId: string,
|
|
530
|
+
id: string,
|
|
531
|
+
options?: { addNewActivitiesTo?: 'start' | 'end' },
|
|
532
|
+
) => {
|
|
533
|
+
return this.getOrCreateActiveFeed(
|
|
534
|
+
groupId,
|
|
535
|
+
id,
|
|
536
|
+
undefined,
|
|
537
|
+
undefined,
|
|
538
|
+
options?.addNewActivitiesTo,
|
|
539
|
+
);
|
|
530
540
|
};
|
|
531
541
|
|
|
532
542
|
async queryFeeds(request?: QueryFeedsRequest) {
|
|
@@ -640,11 +650,19 @@ export class FeedsClient extends FeedsApi {
|
|
|
640
650
|
id: string,
|
|
641
651
|
data?: FeedResponse,
|
|
642
652
|
watch?: boolean,
|
|
653
|
+
addNewActivitiesTo?: 'start' | 'end',
|
|
643
654
|
) => {
|
|
644
655
|
const fid = `${group}:${id}`;
|
|
645
656
|
|
|
646
657
|
if (!this.activeFeeds[fid]) {
|
|
647
|
-
this.activeFeeds[fid] = new Feed(
|
|
658
|
+
this.activeFeeds[fid] = new Feed(
|
|
659
|
+
this,
|
|
660
|
+
group,
|
|
661
|
+
id,
|
|
662
|
+
data,
|
|
663
|
+
watch,
|
|
664
|
+
addNewActivitiesTo,
|
|
665
|
+
);
|
|
648
666
|
}
|
|
649
667
|
|
|
650
668
|
const feed = this.activeFeeds[fid];
|
|
@@ -170,6 +170,8 @@ export class FeedsApi {
|
|
|
170
170
|
const body = {
|
|
171
171
|
name: request?.name,
|
|
172
172
|
words: request?.words,
|
|
173
|
+
is_leet_check_enabled: request?.is_leet_check_enabled,
|
|
174
|
+
is_plural_check_enabled: request?.is_plural_check_enabled,
|
|
173
175
|
team: request?.team,
|
|
174
176
|
type: request?.type,
|
|
175
177
|
};
|
|
@@ -220,6 +222,8 @@ export class FeedsApi {
|
|
|
220
222
|
name: request?.name,
|
|
221
223
|
};
|
|
222
224
|
const body = {
|
|
225
|
+
is_leet_check_enabled: request?.is_leet_check_enabled,
|
|
226
|
+
is_plural_check_enabled: request?.is_plural_check_enabled,
|
|
223
227
|
team: request?.team,
|
|
224
228
|
words: request?.words,
|
|
225
229
|
};
|
|
@@ -499,6 +503,7 @@ export class FeedsApi {
|
|
|
499
503
|
reason: request?.reason,
|
|
500
504
|
report: request?.report,
|
|
501
505
|
show_less: request?.show_less,
|
|
506
|
+
show_more: request?.show_more,
|
|
502
507
|
};
|
|
503
508
|
|
|
504
509
|
const response = await this.apiClient.sendRequest<
|
|
@@ -1233,9 +1233,11 @@ decoders.ModerationCustomActionEvent = (input?: Record<string, any>) => {
|
|
|
1233
1233
|
const typeMappings: TypeMapping = {
|
|
1234
1234
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
1235
1235
|
|
|
1236
|
-
|
|
1236
|
+
review_queue_item: { type: 'ReviewQueueItemResponse', isSingle: true },
|
|
1237
1237
|
|
|
1238
|
-
|
|
1238
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
1239
|
+
|
|
1240
|
+
message: { type: 'MessageResponse', isSingle: true },
|
|
1239
1241
|
};
|
|
1240
1242
|
return decode(typeMappings, input);
|
|
1241
1243
|
};
|
|
@@ -1266,9 +1268,11 @@ decoders.ModerationMarkReviewedEvent = (input?: Record<string, any>) => {
|
|
|
1266
1268
|
const typeMappings: TypeMapping = {
|
|
1267
1269
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
1268
1270
|
|
|
1269
|
-
|
|
1271
|
+
item: { type: 'ReviewQueueItemResponse', isSingle: true },
|
|
1270
1272
|
|
|
1271
|
-
|
|
1273
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
1274
|
+
|
|
1275
|
+
message: { type: 'MessageResponse', isSingle: true },
|
|
1272
1276
|
};
|
|
1273
1277
|
return decode(typeMappings, input);
|
|
1274
1278
|
};
|
|
@@ -1745,6 +1749,8 @@ decoders.StoriesFeedUpdatedEvent = (input?: Record<string, any>) => {
|
|
|
1745
1749
|
|
|
1746
1750
|
received_at: { type: 'DatetimeType', isSingle: true },
|
|
1747
1751
|
|
|
1752
|
+
activities: { type: 'ActivityResponse', isSingle: false },
|
|
1753
|
+
|
|
1748
1754
|
aggregated_activities: {
|
|
1749
1755
|
type: 'AggregatedActivityResponse',
|
|
1750
1756
|
isSingle: false,
|