@stream-io/feeds-client 0.1.7 → 0.1.9
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/@react-bindings/hooks/util/index.ts +1 -0
- package/CHANGELOG.md +20 -0
- package/dist/@react-bindings/hooks/util/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/util/useBookmarkActions.d.ts +13 -0
- package/dist/@react-bindings/hooks/util/useReactionActions.d.ts +1 -1
- package/dist/index-react-bindings.browser.cjs +363 -141
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +363 -142
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +363 -141
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +363 -142
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +337 -140
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +337 -141
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +337 -140
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +337 -141
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +42 -11
- package/dist/src/FeedsClient.d.ts +10 -3
- package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/src/gen/models/index.d.ts +25 -2
- package/dist/src/gen-imports.d.ts +1 -1
- package/dist/src/state-updates/follow-utils.d.ts +19 -0
- package/dist/src/state-updates/state-update-queue.d.ts +15 -0
- package/dist/src/utils.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/Feed.ts +230 -192
- package/src/FeedsClient.ts +75 -3
- package/src/gen/feeds/FeedsApi.ts +0 -1
- package/src/gen/model-decoders/decoders.ts +16 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +3 -0
- package/src/gen/models/index.ts +42 -4
- package/src/gen-imports.ts +1 -1
- package/src/state-updates/activity-reaction-utils.test.ts +1 -0
- package/src/state-updates/activity-utils.test.ts +1 -0
- package/src/state-updates/follow-utils.test.ts +552 -0
- package/src/state-updates/follow-utils.ts +126 -0
- package/src/state-updates/state-update-queue.test.ts +53 -0
- package/src/state-updates/state-update-queue.ts +35 -0
- package/src/utils.test.ts +175 -0
- package/src/utils.ts +20 -0
package/dist/index.node.js
CHANGED
|
@@ -872,6 +872,18 @@ decoders.MuteResponse = (input) => {
|
|
|
872
872
|
};
|
|
873
873
|
return decode(typeMappings, input);
|
|
874
874
|
};
|
|
875
|
+
decoders.NotificationFeedUpdatedEvent = (input) => {
|
|
876
|
+
const typeMappings = {
|
|
877
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
878
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
879
|
+
aggregated_activities: {
|
|
880
|
+
type: 'AggregatedActivityResponse',
|
|
881
|
+
isSingle: false,
|
|
882
|
+
},
|
|
883
|
+
notification_status: { type: 'NotificationStatusResponse', isSingle: true },
|
|
884
|
+
};
|
|
885
|
+
return decode(typeMappings, input);
|
|
886
|
+
};
|
|
875
887
|
decoders.NotificationStatusResponse = (input) => {
|
|
876
888
|
const typeMappings = {
|
|
877
889
|
last_seen_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -2347,7 +2359,6 @@ class FeedsApi {
|
|
|
2347
2359
|
}
|
|
2348
2360
|
async updateLiveLocation(request) {
|
|
2349
2361
|
const body = {
|
|
2350
|
-
created_by_device_id: request?.created_by_device_id,
|
|
2351
2362
|
message_id: request?.message_id,
|
|
2352
2363
|
end_at: request?.end_at,
|
|
2353
2364
|
latitude: request?.latitude,
|
|
@@ -3712,6 +3723,7 @@ const eventDecoderMapping = {
|
|
|
3712
3723
|
'feeds.follow.created': (data) => decoders.FollowCreatedEvent(data),
|
|
3713
3724
|
'feeds.follow.deleted': (data) => decoders.FollowDeletedEvent(data),
|
|
3714
3725
|
'feeds.follow.updated': (data) => decoders.FollowUpdatedEvent(data),
|
|
3726
|
+
'feeds.notification_feed.updated': (data) => decoders.NotificationFeedUpdatedEvent(data),
|
|
3715
3727
|
'feeds.poll.closed': (data) => decoders.PollClosedFeedEvent(data),
|
|
3716
3728
|
'feeds.poll.deleted': (data) => decoders.PollDeletedFeedEvent(data),
|
|
3717
3729
|
'feeds.poll.updated': (data) => decoders.PollUpdatedFeedEvent(data),
|
|
@@ -4044,6 +4056,89 @@ const updateBookmarkInActivities = (event, activities, isCurrentUser) => {
|
|
|
4044
4056
|
return updateActivityInActivities(updatedActivity, activities);
|
|
4045
4057
|
};
|
|
4046
4058
|
|
|
4059
|
+
const isFeedResponse = (follow) => {
|
|
4060
|
+
return 'created_by' in follow;
|
|
4061
|
+
};
|
|
4062
|
+
const handleFollowCreated = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4063
|
+
// filter non-accepted follows (the way getOrCreate does by default)
|
|
4064
|
+
if (follow.status !== 'accepted') {
|
|
4065
|
+
return { changed: false, data: currentState };
|
|
4066
|
+
}
|
|
4067
|
+
let newState = { ...currentState };
|
|
4068
|
+
// this feed followed someone
|
|
4069
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4070
|
+
newState = {
|
|
4071
|
+
...newState,
|
|
4072
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4073
|
+
...follow.source_feed,
|
|
4074
|
+
};
|
|
4075
|
+
// Only update if following array already exists
|
|
4076
|
+
if (currentState.following !== undefined) {
|
|
4077
|
+
newState.following = [follow, ...currentState.following];
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
else if (
|
|
4081
|
+
// someone followed this feed
|
|
4082
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4083
|
+
const source = follow.source_feed;
|
|
4084
|
+
newState = {
|
|
4085
|
+
...newState,
|
|
4086
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4087
|
+
...follow.target_feed,
|
|
4088
|
+
};
|
|
4089
|
+
if (source.created_by.id === connectedUserId) {
|
|
4090
|
+
newState.own_follows = currentState.own_follows
|
|
4091
|
+
? currentState.own_follows.concat(follow)
|
|
4092
|
+
: [follow];
|
|
4093
|
+
}
|
|
4094
|
+
// Only update if followers array already exists
|
|
4095
|
+
if (currentState.followers !== undefined) {
|
|
4096
|
+
newState.followers = [follow, ...currentState.followers];
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
return { changed: true, data: newState };
|
|
4100
|
+
};
|
|
4101
|
+
const handleFollowDeleted = (follow, currentState, currentFeedId, connectedUserId) => {
|
|
4102
|
+
let newState = { ...currentState };
|
|
4103
|
+
// this feed unfollowed someone
|
|
4104
|
+
if (follow.source_feed.fid === currentFeedId) {
|
|
4105
|
+
newState = {
|
|
4106
|
+
...newState,
|
|
4107
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4108
|
+
...follow.source_feed,
|
|
4109
|
+
};
|
|
4110
|
+
// Only update if following array already exists
|
|
4111
|
+
if (currentState.following !== undefined) {
|
|
4112
|
+
newState.following = currentState.following.filter((followItem) => followItem.target_feed.fid !== follow.target_feed.fid);
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
else if (
|
|
4116
|
+
// someone unfollowed this feed
|
|
4117
|
+
follow.target_feed.fid === currentFeedId) {
|
|
4118
|
+
const source = follow.source_feed;
|
|
4119
|
+
newState = {
|
|
4120
|
+
...newState,
|
|
4121
|
+
// Update FeedResponse fields, that has the new follower/following count
|
|
4122
|
+
...follow.target_feed,
|
|
4123
|
+
};
|
|
4124
|
+
if (isFeedResponse(source) &&
|
|
4125
|
+
source.created_by.id === connectedUserId &&
|
|
4126
|
+
currentState.own_follows !== undefined) {
|
|
4127
|
+
newState.own_follows = currentState.own_follows.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4128
|
+
}
|
|
4129
|
+
// Only update if followers array already exists
|
|
4130
|
+
if (currentState.followers !== undefined) {
|
|
4131
|
+
newState.followers = currentState.followers.filter((followItem) => followItem.source_feed.fid !== follow.source_feed.fid);
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
return { changed: true, data: newState };
|
|
4135
|
+
};
|
|
4136
|
+
const handleFollowUpdated = (currentState) => {
|
|
4137
|
+
// For now, we'll treat follow updates as no-ops since the current implementation does
|
|
4138
|
+
// This can be enhanced later if needed
|
|
4139
|
+
return { changed: false, data: currentState };
|
|
4140
|
+
};
|
|
4141
|
+
|
|
4047
4142
|
const isImageFile = (file) => {
|
|
4048
4143
|
// photoshop files begin with 'image/'
|
|
4049
4144
|
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
@@ -4059,11 +4154,41 @@ const isCommentResponse = (entity) => {
|
|
|
4059
4154
|
const Constants = {
|
|
4060
4155
|
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
4061
4156
|
};
|
|
4157
|
+
const uniqueArrayMerge = (existingArray, arrayToMerge, getKey) => {
|
|
4158
|
+
const existing = new Set();
|
|
4159
|
+
existingArray.forEach((value) => {
|
|
4160
|
+
const key = getKey(value);
|
|
4161
|
+
existing.add(key);
|
|
4162
|
+
});
|
|
4163
|
+
const filteredArrayToMerge = arrayToMerge.filter((value) => {
|
|
4164
|
+
const key = getKey(value);
|
|
4165
|
+
return !existing.has(key);
|
|
4166
|
+
});
|
|
4167
|
+
return existingArray.concat(filteredArrayToMerge);
|
|
4168
|
+
};
|
|
4169
|
+
|
|
4170
|
+
const shouldUpdateState = ({ stateUpdateId, stateUpdateQueue, watch, }) => {
|
|
4171
|
+
if (!watch) {
|
|
4172
|
+
return true;
|
|
4173
|
+
}
|
|
4174
|
+
if (watch && stateUpdateQueue.has(stateUpdateId)) {
|
|
4175
|
+
stateUpdateQueue.delete(stateUpdateId);
|
|
4176
|
+
return false;
|
|
4177
|
+
}
|
|
4178
|
+
stateUpdateQueue.add(stateUpdateId);
|
|
4179
|
+
return true;
|
|
4180
|
+
};
|
|
4181
|
+
const getStateUpdateQueueIdForFollow = (follow) => {
|
|
4182
|
+
return `follow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4183
|
+
};
|
|
4184
|
+
const getStateUpdateQueueIdForUnfollow = (follow) => {
|
|
4185
|
+
return `unfollow${follow.source_feed.fid}-${follow.target_feed.fid}`;
|
|
4186
|
+
};
|
|
4062
4187
|
|
|
4063
4188
|
class Feed extends FeedApi {
|
|
4064
|
-
constructor(client, groupId, id, data) {
|
|
4065
|
-
// Need this ugly cast because fileUpload endpoints :(
|
|
4189
|
+
constructor(client, groupId, id, data, watch = false) {
|
|
4066
4190
|
super(client, groupId, id);
|
|
4191
|
+
this.stateUpdateQueue = new Set();
|
|
4067
4192
|
this.eventHandlers = {
|
|
4068
4193
|
'feeds.activity.added': (event) => {
|
|
4069
4194
|
const currentActivities = this.currentState.activities;
|
|
@@ -4209,74 +4334,14 @@ class Feed extends FeedApi {
|
|
|
4209
4334
|
'feeds.feed_group.changed': Feed.noop,
|
|
4210
4335
|
'feeds.feed_group.deleted': Feed.noop,
|
|
4211
4336
|
'feeds.follow.created': (event) => {
|
|
4212
|
-
|
|
4213
|
-
if (event.follow.status !== 'accepted')
|
|
4214
|
-
return;
|
|
4215
|
-
// this feed followed someone
|
|
4216
|
-
if (event.follow.source_feed.fid === this.fid) {
|
|
4217
|
-
this.state.next((currentState) => {
|
|
4218
|
-
const newState = {
|
|
4219
|
-
...currentState,
|
|
4220
|
-
...event.follow.source_feed,
|
|
4221
|
-
};
|
|
4222
|
-
if (!checkHasAnotherPage(currentState.following, currentState.following_pagination?.next)) {
|
|
4223
|
-
// TODO: respect sort
|
|
4224
|
-
newState.following = currentState.following
|
|
4225
|
-
? currentState.following.concat(event.follow)
|
|
4226
|
-
: [event.follow];
|
|
4227
|
-
}
|
|
4228
|
-
return newState;
|
|
4229
|
-
});
|
|
4230
|
-
}
|
|
4231
|
-
else if (
|
|
4232
|
-
// someone followed this feed
|
|
4233
|
-
event.follow.target_feed.fid === this.fid) {
|
|
4234
|
-
const source = event.follow.source_feed;
|
|
4235
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4236
|
-
this.state.next((currentState) => {
|
|
4237
|
-
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4238
|
-
if (source.created_by.id === connectedUser?.id) {
|
|
4239
|
-
newState.own_follows = currentState.own_follows
|
|
4240
|
-
? currentState.own_follows.concat(event.follow)
|
|
4241
|
-
: [event.follow];
|
|
4242
|
-
}
|
|
4243
|
-
if (!checkHasAnotherPage(currentState.followers, currentState.followers_pagination?.next)) {
|
|
4244
|
-
// TODO: respect sort
|
|
4245
|
-
newState.followers = currentState.followers
|
|
4246
|
-
? currentState.followers.concat(event.follow)
|
|
4247
|
-
: [event.follow];
|
|
4248
|
-
}
|
|
4249
|
-
return newState;
|
|
4250
|
-
});
|
|
4251
|
-
}
|
|
4337
|
+
this.handleFollowCreated(event.follow);
|
|
4252
4338
|
},
|
|
4253
4339
|
'feeds.follow.deleted': (event) => {
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
...currentState,
|
|
4259
|
-
...event.follow.source_feed,
|
|
4260
|
-
following: currentState.following?.filter((follow) => follow.target_feed.fid !== event.follow.target_feed.fid),
|
|
4261
|
-
};
|
|
4262
|
-
});
|
|
4263
|
-
}
|
|
4264
|
-
else if (
|
|
4265
|
-
// someone unfollowed this feed
|
|
4266
|
-
event.follow.target_feed.fid === this.fid) {
|
|
4267
|
-
const source = event.follow.source_feed;
|
|
4268
|
-
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4269
|
-
this.state.next((currentState) => {
|
|
4270
|
-
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4271
|
-
if (source.created_by.id === connectedUser?.id) {
|
|
4272
|
-
newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4273
|
-
}
|
|
4274
|
-
newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4275
|
-
return newState;
|
|
4276
|
-
});
|
|
4277
|
-
}
|
|
4340
|
+
this.handleFollowDeleted(event.follow);
|
|
4341
|
+
},
|
|
4342
|
+
'feeds.follow.updated': (_event) => {
|
|
4343
|
+
handleFollowUpdated(this.currentState);
|
|
4278
4344
|
},
|
|
4279
|
-
'feeds.follow.updated': Feed.noop,
|
|
4280
4345
|
'feeds.comment.reaction.added': this.handleCommentReactionEvent.bind(this),
|
|
4281
4346
|
'feeds.comment.reaction.deleted': this.handleCommentReactionEvent.bind(this),
|
|
4282
4347
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
@@ -4284,13 +4349,11 @@ class Feed extends FeedApi {
|
|
|
4284
4349
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
4285
4350
|
this.state.next((currentState) => {
|
|
4286
4351
|
let newState;
|
|
4287
|
-
if (
|
|
4352
|
+
if (typeof currentState.members !== 'undefined') {
|
|
4288
4353
|
newState ?? (newState = {
|
|
4289
4354
|
...currentState,
|
|
4290
4355
|
});
|
|
4291
|
-
newState.members =
|
|
4292
|
-
event.member,
|
|
4293
|
-
];
|
|
4356
|
+
newState.members = [event.member, ...currentState.members];
|
|
4294
4357
|
}
|
|
4295
4358
|
if (connectedUser?.id === event.member.user.id) {
|
|
4296
4359
|
newState ?? (newState = {
|
|
@@ -4337,6 +4400,10 @@ class Feed extends FeedApi {
|
|
|
4337
4400
|
return newState ?? currentState;
|
|
4338
4401
|
});
|
|
4339
4402
|
},
|
|
4403
|
+
'feeds.notification_feed.updated': (event) => {
|
|
4404
|
+
console.info('notification feed updated', event);
|
|
4405
|
+
// TODO: handle notification feed updates
|
|
4406
|
+
},
|
|
4340
4407
|
// the poll events should be removed from here
|
|
4341
4408
|
'feeds.poll.closed': Feed.noop,
|
|
4342
4409
|
'feeds.poll.deleted': Feed.noop,
|
|
@@ -4369,6 +4436,7 @@ class Feed extends FeedApi {
|
|
|
4369
4436
|
is_loading: false,
|
|
4370
4437
|
is_loading_activities: false,
|
|
4371
4438
|
comments_by_entity_id: {},
|
|
4439
|
+
watch,
|
|
4372
4440
|
});
|
|
4373
4441
|
this.client = client;
|
|
4374
4442
|
}
|
|
@@ -4448,6 +4516,8 @@ class Feed extends FeedApi {
|
|
|
4448
4516
|
}
|
|
4449
4517
|
}
|
|
4450
4518
|
else {
|
|
4519
|
+
// Empty queue when reinitializing the state
|
|
4520
|
+
this.stateUpdateQueue.clear();
|
|
4451
4521
|
const responseCopy = {
|
|
4452
4522
|
...response,
|
|
4453
4523
|
...response.feed,
|
|
@@ -4466,7 +4536,11 @@ class Feed extends FeedApi {
|
|
|
4466
4536
|
if (!request?.following_pagination?.limit) {
|
|
4467
4537
|
delete nextState.following;
|
|
4468
4538
|
}
|
|
4539
|
+
if (response.members.length === 0 && response.feed.member_count > 0) {
|
|
4540
|
+
delete nextState.members;
|
|
4541
|
+
}
|
|
4469
4542
|
nextState.last_get_or_create_request_config = request;
|
|
4543
|
+
nextState.watch = request?.watch ? request.watch : currentState.watch;
|
|
4470
4544
|
return nextState;
|
|
4471
4545
|
});
|
|
4472
4546
|
}
|
|
@@ -4480,6 +4554,56 @@ class Feed extends FeedApi {
|
|
|
4480
4554
|
});
|
|
4481
4555
|
}
|
|
4482
4556
|
}
|
|
4557
|
+
/**
|
|
4558
|
+
* @internal
|
|
4559
|
+
*/
|
|
4560
|
+
handleFollowCreated(follow) {
|
|
4561
|
+
if (!shouldUpdateState({
|
|
4562
|
+
stateUpdateId: getStateUpdateQueueIdForFollow(follow),
|
|
4563
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4564
|
+
watch: this.currentState.watch,
|
|
4565
|
+
})) {
|
|
4566
|
+
return;
|
|
4567
|
+
}
|
|
4568
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4569
|
+
const result = handleFollowCreated(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4570
|
+
if (result.changed) {
|
|
4571
|
+
this.state.next(result.data);
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
/**
|
|
4575
|
+
* @internal
|
|
4576
|
+
*/
|
|
4577
|
+
handleFollowDeleted(follow) {
|
|
4578
|
+
if (!shouldUpdateState({
|
|
4579
|
+
stateUpdateId: getStateUpdateQueueIdForUnfollow(follow),
|
|
4580
|
+
stateUpdateQueue: this.stateUpdateQueue,
|
|
4581
|
+
watch: this.currentState.watch,
|
|
4582
|
+
})) {
|
|
4583
|
+
return;
|
|
4584
|
+
}
|
|
4585
|
+
const connectedUser = this.client.state.getLatestValue().connected_user;
|
|
4586
|
+
const result = handleFollowDeleted(follow, this.currentState, this.fid, connectedUser?.id);
|
|
4587
|
+
{
|
|
4588
|
+
this.state.next(result.data);
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
/**
|
|
4592
|
+
* @internal
|
|
4593
|
+
*/
|
|
4594
|
+
handleWatchStopped() {
|
|
4595
|
+
this.state.partialNext({
|
|
4596
|
+
watch: false,
|
|
4597
|
+
});
|
|
4598
|
+
}
|
|
4599
|
+
/**
|
|
4600
|
+
* @internal
|
|
4601
|
+
*/
|
|
4602
|
+
handleWatchStarted() {
|
|
4603
|
+
this.state.partialNext({
|
|
4604
|
+
watch: true,
|
|
4605
|
+
});
|
|
4606
|
+
}
|
|
4483
4607
|
handleBookmarkAdded(event) {
|
|
4484
4608
|
const currentActivities = this.currentState.activities;
|
|
4485
4609
|
const { connected_user: connectedUser } = this.client.state.getLatestValue();
|
|
@@ -4524,70 +4648,85 @@ class Feed extends FeedApi {
|
|
|
4524
4648
|
}
|
|
4525
4649
|
return commentIndex;
|
|
4526
4650
|
}
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4651
|
+
/**
|
|
4652
|
+
* Load child comments of entity (activity or comment) into the state, if the target entity is comment,
|
|
4653
|
+
* `entityParentId` should be provided (`CommentResponse.parent_id ?? CommentResponse.object_id`).
|
|
4654
|
+
*/
|
|
4655
|
+
loadCommentsIntoState(data) {
|
|
4656
|
+
// add initial (top level) object for processing
|
|
4657
|
+
const traverseArray = [
|
|
4658
|
+
{
|
|
4659
|
+
entityId: data.entityId,
|
|
4660
|
+
entityParentId: data.entityParentId,
|
|
4661
|
+
comments: data.comments,
|
|
4662
|
+
next: data.next,
|
|
4663
|
+
},
|
|
4664
|
+
];
|
|
4540
4665
|
this.state.next((currentState) => {
|
|
4541
|
-
const
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4666
|
+
const newCommentsByEntityId = {
|
|
4667
|
+
...currentState.comments_by_entity_id,
|
|
4668
|
+
};
|
|
4669
|
+
while (traverseArray.length) {
|
|
4670
|
+
const item = traverseArray.pop();
|
|
4671
|
+
const entityId = item.entityId;
|
|
4672
|
+
// go over entity comments and generate new objects
|
|
4673
|
+
// for further processing if there are any replies
|
|
4674
|
+
item.comments.forEach((comment) => {
|
|
4675
|
+
if (!comment.replies?.length)
|
|
4676
|
+
return;
|
|
4677
|
+
traverseArray.push({
|
|
4678
|
+
entityId: comment.id,
|
|
4679
|
+
entityParentId: entityId,
|
|
4680
|
+
comments: comment.replies,
|
|
4681
|
+
next: comment.meta?.next_cursor,
|
|
4682
|
+
});
|
|
4683
|
+
});
|
|
4684
|
+
// omit replies & meta from the comments (transform ThreadedCommentResponse to CommentResponse)
|
|
4685
|
+
// this is somehow faster than copying the whole
|
|
4686
|
+
// object and deleting the desired properties
|
|
4687
|
+
const newComments = item.comments.map(({ replies: _r, meta: _m, ...restOfTheCommentResponse }) => restOfTheCommentResponse);
|
|
4688
|
+
newCommentsByEntityId[entityId] = {
|
|
4689
|
+
...newCommentsByEntityId[entityId],
|
|
4690
|
+
entity_parent_id: item.entityParentId,
|
|
4691
|
+
pagination: {
|
|
4692
|
+
...newCommentsByEntityId[entityId]?.pagination,
|
|
4693
|
+
next: item.next,
|
|
4694
|
+
sort: data.sort,
|
|
4695
|
+
},
|
|
4696
|
+
comments: newCommentsByEntityId[entityId]?.comments
|
|
4697
|
+
? newCommentsByEntityId[entityId].comments?.concat(newComments)
|
|
4698
|
+
: newComments,
|
|
4699
|
+
};
|
|
4700
|
+
}
|
|
4546
4701
|
return {
|
|
4547
4702
|
...currentState,
|
|
4548
|
-
|
|
4703
|
+
comments_by_entity_id: newCommentsByEntityId,
|
|
4549
4704
|
};
|
|
4550
4705
|
});
|
|
4551
4706
|
}
|
|
4552
|
-
async loadNextPageComments({
|
|
4707
|
+
async loadNextPageComments({ entityId, base, sort, entityParentId, }) {
|
|
4553
4708
|
let error;
|
|
4554
4709
|
try {
|
|
4555
4710
|
this.state.next((currentState) => ({
|
|
4556
4711
|
...currentState,
|
|
4557
4712
|
comments_by_entity_id: {
|
|
4558
4713
|
...currentState.comments_by_entity_id,
|
|
4559
|
-
[
|
|
4560
|
-
...currentState.comments_by_entity_id[
|
|
4714
|
+
[entityId]: {
|
|
4715
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4561
4716
|
pagination: {
|
|
4562
|
-
...currentState.comments_by_entity_id[
|
|
4717
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4563
4718
|
loading_next_page: true,
|
|
4564
4719
|
},
|
|
4565
4720
|
},
|
|
4566
4721
|
},
|
|
4567
4722
|
}));
|
|
4568
|
-
const { next
|
|
4569
|
-
this.
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
newPagination.sort = sort;
|
|
4576
|
-
}
|
|
4577
|
-
return {
|
|
4578
|
-
...currentState,
|
|
4579
|
-
comments_by_entity_id: {
|
|
4580
|
-
...currentState.comments_by_entity_id,
|
|
4581
|
-
[forId]: {
|
|
4582
|
-
...currentState.comments_by_entity_id[forId],
|
|
4583
|
-
parent_id: parentId,
|
|
4584
|
-
pagination: newPagination,
|
|
4585
|
-
comments: currentState.comments_by_entity_id[forId]?.comments
|
|
4586
|
-
? currentState.comments_by_entity_id[forId].comments?.concat(comments)
|
|
4587
|
-
: comments,
|
|
4588
|
-
},
|
|
4589
|
-
},
|
|
4590
|
-
};
|
|
4723
|
+
const { next, comments } = await base();
|
|
4724
|
+
this.loadCommentsIntoState({
|
|
4725
|
+
entityId,
|
|
4726
|
+
comments,
|
|
4727
|
+
entityParentId,
|
|
4728
|
+
next,
|
|
4729
|
+
sort,
|
|
4591
4730
|
});
|
|
4592
4731
|
}
|
|
4593
4732
|
catch (e) {
|
|
@@ -4598,10 +4737,10 @@ class Feed extends FeedApi {
|
|
|
4598
4737
|
...currentState,
|
|
4599
4738
|
comments_by_entity_id: {
|
|
4600
4739
|
...currentState.comments_by_entity_id,
|
|
4601
|
-
[
|
|
4602
|
-
...currentState.comments_by_entity_id[
|
|
4740
|
+
[entityId]: {
|
|
4741
|
+
...currentState.comments_by_entity_id[entityId],
|
|
4603
4742
|
pagination: {
|
|
4604
|
-
...currentState.comments_by_entity_id[
|
|
4743
|
+
...currentState.comments_by_entity_id[entityId]?.pagination,
|
|
4605
4744
|
loading_next_page: false,
|
|
4606
4745
|
},
|
|
4607
4746
|
},
|
|
@@ -4624,7 +4763,7 @@ class Feed extends FeedApi {
|
|
|
4624
4763
|
return;
|
|
4625
4764
|
}
|
|
4626
4765
|
await this.loadNextPageComments({
|
|
4627
|
-
|
|
4766
|
+
entityId: activity.id,
|
|
4628
4767
|
base: () => this.client.getComments({
|
|
4629
4768
|
...request,
|
|
4630
4769
|
sort,
|
|
@@ -4647,7 +4786,7 @@ class Feed extends FeedApi {
|
|
|
4647
4786
|
return;
|
|
4648
4787
|
}
|
|
4649
4788
|
await this.loadNextPageComments({
|
|
4650
|
-
|
|
4789
|
+
entityId: comment.id,
|
|
4651
4790
|
base: () => this.client.getCommentReplies({
|
|
4652
4791
|
...request,
|
|
4653
4792
|
comment_id: comment.id,
|
|
@@ -4657,7 +4796,7 @@ class Feed extends FeedApi {
|
|
|
4657
4796
|
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
4658
4797
|
next: currentNextCursor,
|
|
4659
4798
|
}),
|
|
4660
|
-
|
|
4799
|
+
entityParentId: comment.parent_id ?? comment.object_id,
|
|
4661
4800
|
sort,
|
|
4662
4801
|
});
|
|
4663
4802
|
}
|
|
@@ -4687,17 +4826,19 @@ class Feed extends FeedApi {
|
|
|
4687
4826
|
next: currentNextCursor,
|
|
4688
4827
|
sort,
|
|
4689
4828
|
});
|
|
4690
|
-
this.state.next((currentState) =>
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4829
|
+
this.state.next((currentState) => {
|
|
4830
|
+
return {
|
|
4831
|
+
...currentState,
|
|
4832
|
+
[type]: currentState[type] === undefined
|
|
4833
|
+
? follows
|
|
4834
|
+
: uniqueArrayMerge(currentState[type], follows, (follow) => `${follow.source_feed.fid}-${follow.target_feed.fid}`),
|
|
4835
|
+
[paginationKey]: {
|
|
4836
|
+
...currentState[paginationKey],
|
|
4837
|
+
next: newNextCursor,
|
|
4838
|
+
sort,
|
|
4839
|
+
},
|
|
4840
|
+
};
|
|
4841
|
+
});
|
|
4701
4842
|
}
|
|
4702
4843
|
catch (e) {
|
|
4703
4844
|
error = e;
|
|
@@ -4750,7 +4891,7 @@ class Feed extends FeedApi {
|
|
|
4750
4891
|
this.state.next((currentState) => ({
|
|
4751
4892
|
...currentState,
|
|
4752
4893
|
members: currentState.members
|
|
4753
|
-
? currentState.members
|
|
4894
|
+
? uniqueArrayMerge(currentState.members, members, ({ user }) => user.id)
|
|
4754
4895
|
: members,
|
|
4755
4896
|
member_pagination: {
|
|
4756
4897
|
...currentState.member_pagination,
|
|
@@ -5337,13 +5478,17 @@ class FeedsClient extends FeedsApi {
|
|
|
5337
5478
|
};
|
|
5338
5479
|
this.eventDispatcher.dispatch(networkEvent);
|
|
5339
5480
|
};
|
|
5340
|
-
this.getOrCreateActiveFeed = (group, id, data) => {
|
|
5481
|
+
this.getOrCreateActiveFeed = (group, id, data, watch) => {
|
|
5341
5482
|
const fid = `${group}:${id}`;
|
|
5342
5483
|
if (this.activeFeeds[fid]) {
|
|
5343
|
-
|
|
5484
|
+
const feed = this.activeFeeds[fid];
|
|
5485
|
+
if (watch && !feed.currentState.watch) {
|
|
5486
|
+
feed.handleWatchStarted();
|
|
5487
|
+
}
|
|
5488
|
+
return feed;
|
|
5344
5489
|
}
|
|
5345
5490
|
else {
|
|
5346
|
-
const feed = new Feed(this, group, id, data);
|
|
5491
|
+
const feed = new Feed(this, group, id, data, watch);
|
|
5347
5492
|
this.activeFeeds[fid] = feed;
|
|
5348
5493
|
return feed;
|
|
5349
5494
|
}
|
|
@@ -5372,6 +5517,11 @@ class FeedsClient extends FeedsApi {
|
|
|
5372
5517
|
}
|
|
5373
5518
|
}
|
|
5374
5519
|
}
|
|
5520
|
+
else {
|
|
5521
|
+
for (const activeFeed of Object.values(this.activeFeeds)) {
|
|
5522
|
+
activeFeed.handleWatchStopped();
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5375
5525
|
break;
|
|
5376
5526
|
}
|
|
5377
5527
|
case 'feeds.feed.created': {
|
|
@@ -5475,7 +5625,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5475
5625
|
}
|
|
5476
5626
|
async queryFeeds(request) {
|
|
5477
5627
|
const response = await this.feedsQueryFeeds(request);
|
|
5478
|
-
const feeds = response.feeds.map((f) => this.getOrCreateActiveFeed(f.group_id, f.id, f));
|
|
5628
|
+
const feeds = response.feeds.map((f) => this.getOrCreateActiveFeed(f.group_id, f.id, f, request?.watch));
|
|
5479
5629
|
return {
|
|
5480
5630
|
feeds,
|
|
5481
5631
|
next: response.next,
|
|
@@ -5484,6 +5634,52 @@ class FeedsClient extends FeedsApi {
|
|
|
5484
5634
|
duration: response.duration,
|
|
5485
5635
|
};
|
|
5486
5636
|
}
|
|
5637
|
+
// For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
|
|
5638
|
+
async follow(request) {
|
|
5639
|
+
const response = await super.follow(request);
|
|
5640
|
+
[response.follow.source_feed.fid, response.follow.target_feed.fid].forEach((fid) => {
|
|
5641
|
+
const feed = this.activeFeeds[fid];
|
|
5642
|
+
if (feed) {
|
|
5643
|
+
feed.handleFollowCreated(response.follow);
|
|
5644
|
+
}
|
|
5645
|
+
});
|
|
5646
|
+
return response;
|
|
5647
|
+
}
|
|
5648
|
+
async followBatch(request) {
|
|
5649
|
+
const response = await super.followBatch(request);
|
|
5650
|
+
response.follows.forEach((follow) => {
|
|
5651
|
+
const feed = this.activeFeeds[follow.source_feed.fid];
|
|
5652
|
+
if (feed) {
|
|
5653
|
+
feed.handleFollowCreated(follow);
|
|
5654
|
+
}
|
|
5655
|
+
});
|
|
5656
|
+
return response;
|
|
5657
|
+
}
|
|
5658
|
+
async unfollow(request) {
|
|
5659
|
+
const response = await super.unfollow(request);
|
|
5660
|
+
[request.source, request.target].forEach((fid) => {
|
|
5661
|
+
const feed = this.activeFeeds[fid];
|
|
5662
|
+
if (feed) {
|
|
5663
|
+
feed.handleFollowDeleted({
|
|
5664
|
+
source_feed: { fid: request.source },
|
|
5665
|
+
target_feed: { fid: request.target },
|
|
5666
|
+
});
|
|
5667
|
+
}
|
|
5668
|
+
});
|
|
5669
|
+
return response;
|
|
5670
|
+
}
|
|
5671
|
+
async stopWatchingFeed(request) {
|
|
5672
|
+
const connectionId = await this.connectionIdManager.getConnectionId();
|
|
5673
|
+
const response = await super.stopWatchingFeed({
|
|
5674
|
+
...request,
|
|
5675
|
+
connection_id: connectionId,
|
|
5676
|
+
});
|
|
5677
|
+
const feed = this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
|
|
5678
|
+
if (feed) {
|
|
5679
|
+
feed.handleWatchStopped();
|
|
5680
|
+
}
|
|
5681
|
+
return response;
|
|
5682
|
+
}
|
|
5487
5683
|
findActiveFeedByActivityId(activityId) {
|
|
5488
5684
|
return Object.values(this.activeFeeds).filter((feed) => feed.currentState.activities?.some((activity) => activity.id === activityId));
|
|
5489
5685
|
}
|
|
@@ -5996,5 +6192,5 @@ class FeedSearchSource extends BaseSearchSource {
|
|
|
5996
6192
|
}
|
|
5997
6193
|
}
|
|
5998
6194
|
|
|
5999
|
-
export { ActivitySearchSource, BaseSearchSource, ChannelOwnCapability, Constants, Feed, FeedOwnCapability, FeedSearchSource, FeedsClient, MergedStateStore, SearchController, StateStore, StreamApiError, StreamPoll, UserSearchSource, checkHasAnotherPage, isCommentResponse, isImageFile, isPatch, isVideoFile, isVoteAnswer };
|
|
6195
|
+
export { ActivitySearchSource, BaseSearchSource, ChannelOwnCapability, Constants, Feed, FeedOwnCapability, FeedSearchSource, FeedsClient, MergedStateStore, SearchController, StateStore, StreamApiError, StreamPoll, UserSearchSource, checkHasAnotherPage, isCommentResponse, isImageFile, isPatch, isVideoFile, isVoteAnswer, uniqueArrayMerge };
|
|
6000
6196
|
//# sourceMappingURL=index.node.js.map
|