@stream-io/feeds-client 0.3.6 → 0.3.8
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 +14 -0
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react-bindings.js +76 -14
- package/dist/cjs/react-bindings.js.map +1 -1
- package/dist/es/index.mjs +3 -2
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/react-bindings.mjs +76 -14
- package/dist/es/react-bindings.mjs.map +1 -1
- package/dist/{feeds-client-47vliZx_.js → feeds-client-CwioZBvA.js} +355 -52
- package/dist/feeds-client-CwioZBvA.js.map +1 -0
- package/dist/{feeds-client-Cd2LsXp-.mjs → feeds-client-DVbsjKUf.mjs} +355 -52
- package/dist/feeds-client-DVbsjKUf.mjs.map +1 -0
- package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts +49 -0
- package/dist/types/activity-with-state-updates/activity-with-state-updates.d.ts.map +1 -0
- package/dist/types/activity-with-state-updates/get-feed.d.ts +3 -0
- package/dist/types/activity-with-state-updates/get-feed.d.ts.map +1 -0
- package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts +1 -0
- package/dist/types/bindings/react/hooks/feed-state-hooks/index.d.ts.map +1 -1
- package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts +32 -0
- package/dist/types/bindings/react/hooks/feed-state-hooks/useActivityComments.d.ts.map +1 -0
- package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts +4 -0
- package/dist/types/bindings/react/hooks/feed-state-hooks/useComments.d.ts.map +1 -1
- package/dist/types/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.d.ts.map +1 -1
- package/dist/types/bindings/react/hooks/useCreateFeedsClient.d.ts.map +1 -1
- package/dist/types/common/real-time/event-models.d.ts +1 -0
- package/dist/types/common/real-time/event-models.d.ts.map +1 -1
- package/dist/types/feed/event-handlers/activity-updater.d.ts +1 -0
- package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
- package/dist/types/feed/feed.d.ts +1 -1
- package/dist/types/feed/feed.d.ts.map +1 -1
- package/dist/types/feeds-client/active-activity.d.ts +8 -0
- package/dist/types/feeds-client/active-activity.d.ts.map +1 -0
- package/dist/types/feeds-client/feeds-client.d.ts +36 -3
- package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
- package/dist/types/gen/feeds/FeedsApi.d.ts +9 -1
- package/dist/types/gen/feeds/FeedsApi.d.ts.map +1 -1
- package/dist/types/gen/models/index.d.ts +52 -0
- package/dist/types/gen/models/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/activity-with-state-updates/activity-with-state-updates.ts +190 -0
- package/src/activity-with-state-updates/get-feed.ts +5 -0
- package/src/bindings/react/hooks/feed-state-hooks/index.ts +1 -0
- package/src/bindings/react/hooks/feed-state-hooks/useActivityComments.ts +113 -0
- package/src/bindings/react/hooks/feed-state-hooks/useComments.ts +4 -0
- package/src/bindings/react/hooks/feed-state-hooks/useOwnCapabilities.ts +12 -9
- package/src/bindings/react/hooks/useCreateFeedsClient.ts +0 -6
- package/src/common/real-time/event-models.ts +5 -1
- package/src/feed/feed.ts +16 -6
- package/src/feeds-client/active-activity.ts +42 -0
- package/src/feeds-client/feeds-client.ts +162 -53
- package/src/gen/feeds/FeedsApi.ts +86 -0
- package/src/gen/model-decoders/decoders.ts +41 -0
- package/src/gen/models/index.ts +84 -0
- package/src/index.ts +1 -0
- package/src/test-utils/response-generators.ts +1 -0
- package/src/types.ts +8 -10
- package/dist/feeds-client-47vliZx_.js.map +0 -1
- package/dist/feeds-client-Cd2LsXp-.mjs.map +0 -1
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
FileUploadRequest,
|
|
15
15
|
FollowBatchRequest,
|
|
16
16
|
FollowRequest,
|
|
17
|
+
GetOrCreateFeedRequest,
|
|
17
18
|
ImageUploadRequest,
|
|
18
19
|
OwnCapabilitiesBatchRequest,
|
|
19
20
|
OwnUser,
|
|
@@ -83,6 +84,8 @@ import {
|
|
|
83
84
|
type ThrottledGetBatchedOwnCapabilities,
|
|
84
85
|
clearQueuedFeeds,
|
|
85
86
|
} from '../utils/throttling';
|
|
87
|
+
import { ActivityWithStateUpdates } from '../activity-with-state-updates/activity-with-state-updates';
|
|
88
|
+
import { getFeed } from '../activity-with-state-updates/get-feed';
|
|
86
89
|
|
|
87
90
|
export type FeedsClientState = {
|
|
88
91
|
connected_user: OwnUser | undefined;
|
|
@@ -92,6 +95,8 @@ export type FeedsClientState = {
|
|
|
92
95
|
|
|
93
96
|
type FID = string;
|
|
94
97
|
|
|
98
|
+
type ActivityId = string;
|
|
99
|
+
|
|
95
100
|
export class FeedsClient extends FeedsApi {
|
|
96
101
|
readonly state: StateStore<FeedsClientState>;
|
|
97
102
|
readonly moderation: ModerationClient;
|
|
@@ -106,7 +111,8 @@ export class FeedsClient extends FeedsApi {
|
|
|
106
111
|
|
|
107
112
|
private readonly polls_by_id: Map<string, StreamPoll>;
|
|
108
113
|
|
|
109
|
-
|
|
114
|
+
protected activeActivities: Record<ActivityId, ActivityWithStateUpdates> = {};
|
|
115
|
+
protected activeFeeds: Record<FID, Feed> = {};
|
|
110
116
|
|
|
111
117
|
private healthyConnectionChangedEventCount = 0;
|
|
112
118
|
|
|
@@ -143,8 +149,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
143
149
|
this.on('all', (event) => {
|
|
144
150
|
const fid = event.fid;
|
|
145
151
|
|
|
146
|
-
const
|
|
147
|
-
typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
|
|
152
|
+
const feeds = this.findAllActiveFeedsFromWSEvent(event);
|
|
148
153
|
|
|
149
154
|
switch (event.type) {
|
|
150
155
|
case 'connection.changed': {
|
|
@@ -154,14 +159,14 @@ export class FeedsClient extends FeedsApi {
|
|
|
154
159
|
if (online) {
|
|
155
160
|
this.recoverOnReconnect();
|
|
156
161
|
} else {
|
|
157
|
-
for (const activeFeed of
|
|
162
|
+
for (const activeFeed of this.allActiveFeeds) {
|
|
158
163
|
handleWatchStopped.bind(activeFeed)();
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
166
|
break;
|
|
162
167
|
}
|
|
163
168
|
case 'feeds.feed.created': {
|
|
164
|
-
if (feed) break;
|
|
169
|
+
if (this.activeFeeds[event.feed.id]) break;
|
|
165
170
|
|
|
166
171
|
this.getOrCreateActiveFeed(
|
|
167
172
|
event.feed.group_id,
|
|
@@ -172,9 +177,15 @@ export class FeedsClient extends FeedsApi {
|
|
|
172
177
|
break;
|
|
173
178
|
}
|
|
174
179
|
case 'feeds.feed.deleted': {
|
|
175
|
-
|
|
180
|
+
feeds.forEach((f) => f.handleWSEvent(event as unknown as WSEvent));
|
|
176
181
|
if (typeof fid === 'string') {
|
|
177
182
|
delete this.activeFeeds[fid];
|
|
183
|
+
Object.keys(this.activeActivities).forEach((activityId) => {
|
|
184
|
+
const activity = this.activeActivities[activityId];
|
|
185
|
+
if (getFeed.call(activity)?.feed === fid) {
|
|
186
|
+
delete this.activeActivities[activityId];
|
|
187
|
+
}
|
|
188
|
+
});
|
|
178
189
|
}
|
|
179
190
|
break;
|
|
180
191
|
}
|
|
@@ -188,7 +199,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
188
199
|
if (event.poll?.id) {
|
|
189
200
|
this.polls_by_id.delete(event.poll.id);
|
|
190
201
|
|
|
191
|
-
for (const activeFeed of
|
|
202
|
+
for (const activeFeed of this.allActiveFeeds) {
|
|
192
203
|
const currentActivities = activeFeed.currentState.activities;
|
|
193
204
|
if (currentActivities) {
|
|
194
205
|
const newActivities = [];
|
|
@@ -236,17 +247,15 @@ export class FeedsClient extends FeedsApi {
|
|
|
236
247
|
case 'feeds.bookmark.deleted':
|
|
237
248
|
case 'feeds.bookmark.updated': {
|
|
238
249
|
const activityId = event.bookmark.activity.id;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
feeds.forEach((f) => f.handleWSEvent(event));
|
|
250
|
+
const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
|
|
251
|
+
allFeeds.forEach((f) => f.handleWSEvent(event));
|
|
242
252
|
|
|
243
253
|
break;
|
|
244
254
|
}
|
|
245
255
|
case 'feeds.activity.feedback': {
|
|
246
256
|
const activityId = event.activity_feedback.activity_id;
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
257
|
+
const allFeeds = this.findAllActiveFeedsByActivityId(activityId);
|
|
258
|
+
allFeeds.forEach((f) => f.handleWSEvent(event));
|
|
250
259
|
break;
|
|
251
260
|
}
|
|
252
261
|
case 'user.updated': {
|
|
@@ -254,7 +263,10 @@ export class FeedsClient extends FeedsApi {
|
|
|
254
263
|
break;
|
|
255
264
|
}
|
|
256
265
|
default: {
|
|
257
|
-
|
|
266
|
+
feeds.forEach((f) => f.handleWSEvent(event as unknown as WSEvent));
|
|
267
|
+
if (event.type === 'feeds.activity.deleted') {
|
|
268
|
+
delete this.activeActivities[event.activity.id];
|
|
269
|
+
}
|
|
258
270
|
}
|
|
259
271
|
}
|
|
260
272
|
});
|
|
@@ -291,17 +303,24 @@ export class FeedsClient extends FeedsApi {
|
|
|
291
303
|
|
|
292
304
|
// we skip the first event as we could potentially be querying twice
|
|
293
305
|
if (this.healthyConnectionChangedEventCount > 1) {
|
|
294
|
-
const
|
|
306
|
+
const feedEntries = Object.entries(this.activeFeeds);
|
|
307
|
+
const activityEntries = Object.entries(this.activeActivities);
|
|
295
308
|
|
|
296
|
-
const results = await Promise.allSettled(
|
|
297
|
-
|
|
298
|
-
|
|
309
|
+
const results = await Promise.allSettled([
|
|
310
|
+
...feedEntries.map(([, feed]) => feed.synchronize()),
|
|
311
|
+
...activityEntries.map(([, activity]) => activity.synchronize()),
|
|
312
|
+
]);
|
|
299
313
|
|
|
300
|
-
const failures: SyncFailure[] = results.flatMap((result, index) =>
|
|
301
|
-
result.status === '
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
314
|
+
const failures: SyncFailure[] = results.flatMap((result, index) => {
|
|
315
|
+
if (result.status === 'fulfilled') {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
const activity = activityEntries[index - feedEntries.length]?.[1];
|
|
319
|
+
const feed =
|
|
320
|
+
feedEntries[index]?.[0] ?? (activity && getFeed.call(activity)?.feed);
|
|
321
|
+
|
|
322
|
+
return [{ feed, reason: result.reason, activity_id: activity?.id }];
|
|
323
|
+
});
|
|
305
324
|
|
|
306
325
|
this.eventDispatcher.dispatch({
|
|
307
326
|
type: 'errors.unhandled',
|
|
@@ -311,6 +330,15 @@ export class FeedsClient extends FeedsApi {
|
|
|
311
330
|
}
|
|
312
331
|
};
|
|
313
332
|
|
|
333
|
+
private get allActiveFeeds() {
|
|
334
|
+
return [
|
|
335
|
+
...Object.values(this.activeFeeds),
|
|
336
|
+
...Object.values(this.activeActivities)
|
|
337
|
+
.filter((a) => !!getFeed.call(a))
|
|
338
|
+
.map((a) => getFeed.call(a)!),
|
|
339
|
+
];
|
|
340
|
+
}
|
|
341
|
+
|
|
314
342
|
public pollFromState = (id: string) => this.polls_by_id.get(id);
|
|
315
343
|
|
|
316
344
|
public hydratePollCache(activities: ActivityResponse[]) {
|
|
@@ -441,7 +469,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
441
469
|
},
|
|
442
470
|
): Promise<StreamResponse<UpdateActivityResponse>> => {
|
|
443
471
|
const response = await super.updateActivity(request);
|
|
444
|
-
for (const feed of
|
|
472
|
+
for (const feed of this.allActiveFeeds) {
|
|
445
473
|
handleActivityUpdated.bind(feed)(response, false);
|
|
446
474
|
}
|
|
447
475
|
return response;
|
|
@@ -452,7 +480,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
452
480
|
): Promise<StreamResponse<AddCommentResponse>> => {
|
|
453
481
|
const response = await super.addComment(request);
|
|
454
482
|
const { comment } = response;
|
|
455
|
-
for (const feed of
|
|
483
|
+
for (const feed of this.allActiveFeeds) {
|
|
456
484
|
handleCommentAdded.bind(feed)(response, false);
|
|
457
485
|
const parentActivityId = comment.object_id;
|
|
458
486
|
if (feed.hasActivity(parentActivityId)) {
|
|
@@ -478,7 +506,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
478
506
|
request: UpdateCommentRequest & { id: string },
|
|
479
507
|
): Promise<StreamResponse<UpdateCommentResponse>> => {
|
|
480
508
|
const response = await super.updateComment(request);
|
|
481
|
-
for (const feed of
|
|
509
|
+
for (const feed of this.allActiveFeeds) {
|
|
482
510
|
handleCommentUpdated.bind(feed)(response, false);
|
|
483
511
|
}
|
|
484
512
|
return response;
|
|
@@ -490,7 +518,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
490
518
|
}): Promise<StreamResponse<DeleteCommentResponse>> => {
|
|
491
519
|
const response = await super.deleteComment(request);
|
|
492
520
|
const { activity, comment } = response;
|
|
493
|
-
for (const feed of
|
|
521
|
+
for (const feed of this.allActiveFeeds) {
|
|
494
522
|
handleCommentDeleted.bind(feed)({ comment }, false);
|
|
495
523
|
updateCommentCount.bind(feed)({
|
|
496
524
|
activity,
|
|
@@ -508,7 +536,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
508
536
|
) => {
|
|
509
537
|
const shouldEnforceUnique = request.enforce_unique;
|
|
510
538
|
const response = await super.addActivityReaction(request);
|
|
511
|
-
for (const feed of
|
|
539
|
+
for (const feed of this.allActiveFeeds) {
|
|
512
540
|
if (shouldEnforceUnique) {
|
|
513
541
|
handleActivityReactionUpdated.bind(feed)(response, false);
|
|
514
542
|
} else {
|
|
@@ -534,7 +562,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
534
562
|
type: string;
|
|
535
563
|
}): Promise<StreamResponse<DeleteActivityReactionResponse>> => {
|
|
536
564
|
const response = await super.deleteActivityReaction(request);
|
|
537
|
-
for (const feed of
|
|
565
|
+
for (const feed of this.allActiveFeeds) {
|
|
538
566
|
handleActivityReactionDeleted.bind(feed)(response, false);
|
|
539
567
|
}
|
|
540
568
|
return response;
|
|
@@ -545,7 +573,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
545
573
|
): Promise<StreamResponse<AddCommentReactionResponse>> => {
|
|
546
574
|
const shouldEnforceUnique = request.enforce_unique;
|
|
547
575
|
const response = await super.addCommentReaction(request);
|
|
548
|
-
for (const feed of
|
|
576
|
+
for (const feed of this.allActiveFeeds) {
|
|
549
577
|
if (shouldEnforceUnique) {
|
|
550
578
|
handleCommentReactionUpdated.bind(feed)(response, false);
|
|
551
579
|
} else {
|
|
@@ -560,7 +588,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
560
588
|
type: string;
|
|
561
589
|
}): Promise<StreamResponse<DeleteCommentReactionResponse>> => {
|
|
562
590
|
const response = await super.deleteCommentReaction(request);
|
|
563
|
-
for (const feed of
|
|
591
|
+
for (const feed of this.allActiveFeeds) {
|
|
564
592
|
handleCommentReactionDeleted.bind(feed)(response, false);
|
|
565
593
|
}
|
|
566
594
|
return response;
|
|
@@ -607,6 +635,9 @@ export class FeedsClient extends FeedsApi {
|
|
|
607
635
|
// clear all caches
|
|
608
636
|
this.polls_by_id.clear();
|
|
609
637
|
|
|
638
|
+
this.activeActivities = {};
|
|
639
|
+
this.activeFeeds = {};
|
|
640
|
+
|
|
610
641
|
this.state.partialNext({
|
|
611
642
|
connected_user: undefined,
|
|
612
643
|
is_ws_connection_healthy: false,
|
|
@@ -647,6 +678,23 @@ export class FeedsClient extends FeedsApi {
|
|
|
647
678
|
);
|
|
648
679
|
};
|
|
649
680
|
|
|
681
|
+
/**
|
|
682
|
+
* If you want to get an activity with state updates outside of a feed, use this method.
|
|
683
|
+
*
|
|
684
|
+
* Usually it's used when you implement an activity details page.
|
|
685
|
+
*
|
|
686
|
+
* @param id - The id of the activity
|
|
687
|
+
* @returns The activity with state updates
|
|
688
|
+
*/
|
|
689
|
+
activityWithStateUpdates = (id: ActivityId) => {
|
|
690
|
+
let activity = this.activeActivities[id];
|
|
691
|
+
if (!activity) {
|
|
692
|
+
activity = new ActivityWithStateUpdates(id, this);
|
|
693
|
+
this.activeActivities[id] = activity;
|
|
694
|
+
}
|
|
695
|
+
return activity;
|
|
696
|
+
};
|
|
697
|
+
|
|
650
698
|
async queryFeeds(request?: QueryFeedsRequest) {
|
|
651
699
|
const response = await this._queryFeeds(request);
|
|
652
700
|
|
|
@@ -701,10 +749,8 @@ export class FeedsClient extends FeedsApi {
|
|
|
701
749
|
response.follow.source_feed.feed,
|
|
702
750
|
response.follow.target_feed.feed,
|
|
703
751
|
].forEach((fid) => {
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
handleFollowUpdated.bind(feed)(response, false);
|
|
707
|
-
}
|
|
752
|
+
const feeds = this.findAllActiveFeedsByFid(fid);
|
|
753
|
+
feeds.forEach((f) => handleFollowUpdated.bind(f)(response, false));
|
|
708
754
|
});
|
|
709
755
|
|
|
710
756
|
return response;
|
|
@@ -718,10 +764,8 @@ export class FeedsClient extends FeedsApi {
|
|
|
718
764
|
response.follow.source_feed.feed,
|
|
719
765
|
response.follow.target_feed.feed,
|
|
720
766
|
].forEach((fid) => {
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
handleFollowCreated.bind(feed)(response, false);
|
|
724
|
-
}
|
|
767
|
+
const feeds = this.findAllActiveFeedsByFid(fid);
|
|
768
|
+
feeds.forEach((f) => handleFollowCreated.bind(f)(response, false));
|
|
725
769
|
});
|
|
726
770
|
|
|
727
771
|
return response;
|
|
@@ -731,10 +775,8 @@ export class FeedsClient extends FeedsApi {
|
|
|
731
775
|
const response = await super.followBatch(request);
|
|
732
776
|
|
|
733
777
|
response.follows.forEach((follow) => {
|
|
734
|
-
const
|
|
735
|
-
|
|
736
|
-
handleFollowCreated.bind(feed)({ follow });
|
|
737
|
-
}
|
|
778
|
+
const feeds = this.findAllActiveFeedsByFid(follow.source_feed.feed);
|
|
779
|
+
feeds.forEach((f) => handleFollowCreated.bind(f)({ follow }, false));
|
|
738
780
|
});
|
|
739
781
|
|
|
740
782
|
return response;
|
|
@@ -744,10 +786,8 @@ export class FeedsClient extends FeedsApi {
|
|
|
744
786
|
const response = await super.unfollow(request);
|
|
745
787
|
|
|
746
788
|
[request.source, request.target].forEach((fid) => {
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
handleFollowDeleted.bind(feed)(response, false);
|
|
750
|
-
}
|
|
789
|
+
const feeds = this.findAllActiveFeedsByFid(fid);
|
|
790
|
+
feeds.forEach((f) => handleFollowDeleted.bind(f)(response, false));
|
|
751
791
|
});
|
|
752
792
|
|
|
753
793
|
return response;
|
|
@@ -760,10 +800,29 @@ export class FeedsClient extends FeedsApi {
|
|
|
760
800
|
connection_id: connectionId,
|
|
761
801
|
});
|
|
762
802
|
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
803
|
+
const feeds = this.findAllActiveFeedsByFid(
|
|
804
|
+
`${request.feed_group_id}:${request.feed_id}`,
|
|
805
|
+
);
|
|
806
|
+
feeds.forEach((f) => handleWatchStopped.bind(f)());
|
|
807
|
+
|
|
808
|
+
return response;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
async getOrCreateFeed(
|
|
812
|
+
request: GetOrCreateFeedRequest & {
|
|
813
|
+
feed_group_id: string;
|
|
814
|
+
feed_id: string;
|
|
815
|
+
connection_id?: string;
|
|
816
|
+
},
|
|
817
|
+
) {
|
|
818
|
+
const response = await super.getOrCreateFeed(request);
|
|
819
|
+
this.hydrateCapabilitiesCache([response.feed]);
|
|
820
|
+
|
|
821
|
+
if (request.watch) {
|
|
822
|
+
const feeds = this.findAllActiveFeedsByFid(
|
|
823
|
+
`${request.feed_group_id}:${request.feed_id}`,
|
|
824
|
+
);
|
|
825
|
+
feeds.forEach((f) => handleWatchStarted.bind(f)());
|
|
767
826
|
}
|
|
768
827
|
|
|
769
828
|
return response;
|
|
@@ -802,10 +861,60 @@ export class FeedsClient extends FeedsApi {
|
|
|
802
861
|
return feed;
|
|
803
862
|
};
|
|
804
863
|
|
|
805
|
-
private
|
|
806
|
-
return
|
|
864
|
+
private findAllActiveFeedsByActivityId(activityId: string) {
|
|
865
|
+
return [
|
|
866
|
+
...Object.values(this.activeFeeds),
|
|
867
|
+
...Object.values(this.activeActivities)
|
|
868
|
+
.filter((a) => !!getFeed.call(a))
|
|
869
|
+
.map((a) => getFeed.call(a)!),
|
|
870
|
+
].filter(
|
|
807
871
|
(feed) =>
|
|
808
872
|
feed.hasActivity(activityId) || feed.hasPinnedActivity(activityId),
|
|
809
873
|
);
|
|
810
874
|
}
|
|
875
|
+
|
|
876
|
+
private findAllActiveFeedsByFid(fid: string | undefined) {
|
|
877
|
+
if (!fid) return [];
|
|
878
|
+
|
|
879
|
+
const activeFeed = this.activeFeeds[fid];
|
|
880
|
+
|
|
881
|
+
return [
|
|
882
|
+
...(activeFeed ? [activeFeed] : []),
|
|
883
|
+
...Object.values(this.activeActivities)
|
|
884
|
+
.filter((a) => getFeed.call(a)?.feed === fid)
|
|
885
|
+
.map((a) => getFeed.call(a)!),
|
|
886
|
+
];
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* When updating from WS events we need a special logic:
|
|
891
|
+
* - Find active feeds that match a given fid.
|
|
892
|
+
* - Find active feed from activities where fid matches any of the feeds the activity is posted to.
|
|
893
|
+
*
|
|
894
|
+
* This logic is different from `findAllActiveFeedsByFid` which only checks the first feed an activity is posted to.
|
|
895
|
+
*
|
|
896
|
+
* @param fid
|
|
897
|
+
* @param activityId
|
|
898
|
+
* @returns
|
|
899
|
+
*/
|
|
900
|
+
private findAllActiveFeedsFromWSEvent(event: FeedsEvent) {
|
|
901
|
+
const fid = 'fid' in event ? event.fid : undefined;
|
|
902
|
+
|
|
903
|
+
if (!fid) return [];
|
|
904
|
+
|
|
905
|
+
const activeFeed = fid ? this.activeFeeds[fid] : undefined;
|
|
906
|
+
|
|
907
|
+
return [
|
|
908
|
+
...(activeFeed ? [activeFeed] : []),
|
|
909
|
+
...Object.values(this.activeActivities)
|
|
910
|
+
.filter((a) => {
|
|
911
|
+
const feed = getFeed.call(a);
|
|
912
|
+
return (
|
|
913
|
+
feed?.feed === fid ||
|
|
914
|
+
a.currentState.activity?.feeds.some((f) => f === fid)
|
|
915
|
+
);
|
|
916
|
+
})
|
|
917
|
+
.map((a) => getFeed.call(a)!),
|
|
918
|
+
];
|
|
919
|
+
}
|
|
811
920
|
}
|
|
@@ -23,6 +23,8 @@ import type {
|
|
|
23
23
|
CastPollVoteRequest,
|
|
24
24
|
CreateBlockListRequest,
|
|
25
25
|
CreateBlockListResponse,
|
|
26
|
+
CreateCollectionsRequest,
|
|
27
|
+
CreateCollectionsResponse,
|
|
26
28
|
CreateDeviceRequest,
|
|
27
29
|
CreateFeedsBatchRequest,
|
|
28
30
|
CreateFeedsBatchResponse,
|
|
@@ -36,6 +38,7 @@ import type {
|
|
|
36
38
|
DeleteActivityResponse,
|
|
37
39
|
DeleteBookmarkFolderResponse,
|
|
38
40
|
DeleteBookmarkResponse,
|
|
41
|
+
DeleteCollectionsResponse,
|
|
39
42
|
DeleteCommentReactionResponse,
|
|
40
43
|
DeleteCommentResponse,
|
|
41
44
|
DeleteFeedResponse,
|
|
@@ -90,6 +93,7 @@ import type {
|
|
|
90
93
|
QueryPollsResponse,
|
|
91
94
|
QueryUsersPayload,
|
|
92
95
|
QueryUsersResponse,
|
|
96
|
+
ReadCollectionsResponse,
|
|
93
97
|
RejectFeedMemberInviteRequest,
|
|
94
98
|
RejectFeedMemberInviteResponse,
|
|
95
99
|
RejectFollowRequest,
|
|
@@ -112,6 +116,8 @@ import type {
|
|
|
112
116
|
UpdateBookmarkFolderResponse,
|
|
113
117
|
UpdateBookmarkRequest,
|
|
114
118
|
UpdateBookmarkResponse,
|
|
119
|
+
UpdateCollectionsRequest,
|
|
120
|
+
UpdateCollectionsResponse,
|
|
115
121
|
UpdateCommentRequest,
|
|
116
122
|
UpdateCommentResponse,
|
|
117
123
|
UpdateFeedMembersRequest,
|
|
@@ -312,6 +318,7 @@ export class FeedsApi {
|
|
|
312
318
|
visibility: request?.visibility,
|
|
313
319
|
visibility_tag: request?.visibility_tag,
|
|
314
320
|
attachments: request?.attachments,
|
|
321
|
+
collection_refs: request?.collection_refs,
|
|
315
322
|
filter_tags: request?.filter_tags,
|
|
316
323
|
interest_tags: request?.interest_tags,
|
|
317
324
|
mentioned_user_ids: request?.mentioned_user_ids,
|
|
@@ -735,6 +742,7 @@ export class FeedsApi {
|
|
|
735
742
|
text: request?.text,
|
|
736
743
|
visibility: request?.visibility,
|
|
737
744
|
attachments: request?.attachments,
|
|
745
|
+
collection_refs: request?.collection_refs,
|
|
738
746
|
feeds: request?.feeds,
|
|
739
747
|
filter_tags: request?.filter_tags,
|
|
740
748
|
interest_tags: request?.interest_tags,
|
|
@@ -860,6 +868,84 @@ export class FeedsApi {
|
|
|
860
868
|
return { ...response.body, metadata: response.metadata };
|
|
861
869
|
}
|
|
862
870
|
|
|
871
|
+
async deleteCollections(request: {
|
|
872
|
+
collection_refs: string[];
|
|
873
|
+
}): Promise<StreamResponse<DeleteCollectionsResponse>> {
|
|
874
|
+
const queryParams = {
|
|
875
|
+
collection_refs: request?.collection_refs,
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
const response = await this.apiClient.sendRequest<
|
|
879
|
+
StreamResponse<DeleteCollectionsResponse>
|
|
880
|
+
>('DELETE', '/api/v2/feeds/collections', undefined, queryParams);
|
|
881
|
+
|
|
882
|
+
decoders.DeleteCollectionsResponse?.(response.body);
|
|
883
|
+
|
|
884
|
+
return { ...response.body, metadata: response.metadata };
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
async readCollections(request: {
|
|
888
|
+
collection_refs: string[];
|
|
889
|
+
}): Promise<StreamResponse<ReadCollectionsResponse>> {
|
|
890
|
+
const queryParams = {
|
|
891
|
+
collection_refs: request?.collection_refs,
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
const response = await this.apiClient.sendRequest<
|
|
895
|
+
StreamResponse<ReadCollectionsResponse>
|
|
896
|
+
>('GET', '/api/v2/feeds/collections', undefined, queryParams);
|
|
897
|
+
|
|
898
|
+
decoders.ReadCollectionsResponse?.(response.body);
|
|
899
|
+
|
|
900
|
+
return { ...response.body, metadata: response.metadata };
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
async updateCollections(
|
|
904
|
+
request: UpdateCollectionsRequest,
|
|
905
|
+
): Promise<StreamResponse<UpdateCollectionsResponse>> {
|
|
906
|
+
const body = {
|
|
907
|
+
collections: request?.collections,
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
const response = await this.apiClient.sendRequest<
|
|
911
|
+
StreamResponse<UpdateCollectionsResponse>
|
|
912
|
+
>(
|
|
913
|
+
'PATCH',
|
|
914
|
+
'/api/v2/feeds/collections',
|
|
915
|
+
undefined,
|
|
916
|
+
undefined,
|
|
917
|
+
body,
|
|
918
|
+
'application/json',
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
decoders.UpdateCollectionsResponse?.(response.body);
|
|
922
|
+
|
|
923
|
+
return { ...response.body, metadata: response.metadata };
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
async createCollections(
|
|
927
|
+
request: CreateCollectionsRequest,
|
|
928
|
+
): Promise<StreamResponse<CreateCollectionsResponse>> {
|
|
929
|
+
const body = {
|
|
930
|
+
collections: request?.collections,
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const response = await this.apiClient.sendRequest<
|
|
934
|
+
StreamResponse<CreateCollectionsResponse>
|
|
935
|
+
>(
|
|
936
|
+
'POST',
|
|
937
|
+
'/api/v2/feeds/collections',
|
|
938
|
+
undefined,
|
|
939
|
+
undefined,
|
|
940
|
+
body,
|
|
941
|
+
'application/json',
|
|
942
|
+
);
|
|
943
|
+
|
|
944
|
+
decoders.CreateCollectionsResponse?.(response.body);
|
|
945
|
+
|
|
946
|
+
return { ...response.body, metadata: response.metadata };
|
|
947
|
+
}
|
|
948
|
+
|
|
863
949
|
async getComments(request: {
|
|
864
950
|
object_id: string;
|
|
865
951
|
object_type: string;
|
|
@@ -191,6 +191,8 @@ decoders.ActivityResponse = (input?: Record<string, any>) => {
|
|
|
191
191
|
|
|
192
192
|
own_reactions: { type: 'FeedsReactionResponse', isSingle: false },
|
|
193
193
|
|
|
194
|
+
collections: { type: 'EnrichedCollectionResponse', isSingle: false },
|
|
195
|
+
|
|
194
196
|
reaction_groups: { type: 'ReactionGroupResponse', isSingle: false },
|
|
195
197
|
|
|
196
198
|
user: { type: 'UserResponse', isSingle: true },
|
|
@@ -616,6 +618,15 @@ decoders.ChannelResponse = (input?: Record<string, any>) => {
|
|
|
616
618
|
return decode(typeMappings, input);
|
|
617
619
|
};
|
|
618
620
|
|
|
621
|
+
decoders.CollectionResponse = (input?: Record<string, any>) => {
|
|
622
|
+
const typeMappings: TypeMapping = {
|
|
623
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
624
|
+
|
|
625
|
+
updated_at: { type: 'DatetimeType', isSingle: true },
|
|
626
|
+
};
|
|
627
|
+
return decode(typeMappings, input);
|
|
628
|
+
};
|
|
629
|
+
|
|
619
630
|
decoders.Command = (input?: Record<string, any>) => {
|
|
620
631
|
const typeMappings: TypeMapping = {
|
|
621
632
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -740,6 +751,13 @@ decoders.CreateBlockListResponse = (input?: Record<string, any>) => {
|
|
|
740
751
|
return decode(typeMappings, input);
|
|
741
752
|
};
|
|
742
753
|
|
|
754
|
+
decoders.CreateCollectionsResponse = (input?: Record<string, any>) => {
|
|
755
|
+
const typeMappings: TypeMapping = {
|
|
756
|
+
collections: { type: 'CollectionResponse', isSingle: false },
|
|
757
|
+
};
|
|
758
|
+
return decode(typeMappings, input);
|
|
759
|
+
};
|
|
760
|
+
|
|
743
761
|
decoders.CreateFeedsBatchResponse = (input?: Record<string, any>) => {
|
|
744
762
|
const typeMappings: TypeMapping = {
|
|
745
763
|
feeds: { type: 'FeedResponse', isSingle: false },
|
|
@@ -831,6 +849,15 @@ decoders.EgressRTMPResponse = (input?: Record<string, any>) => {
|
|
|
831
849
|
return decode(typeMappings, input);
|
|
832
850
|
};
|
|
833
851
|
|
|
852
|
+
decoders.EnrichedCollectionResponse = (input?: Record<string, any>) => {
|
|
853
|
+
const typeMappings: TypeMapping = {
|
|
854
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
855
|
+
|
|
856
|
+
updated_at: { type: 'DatetimeType', isSingle: true },
|
|
857
|
+
};
|
|
858
|
+
return decode(typeMappings, input);
|
|
859
|
+
};
|
|
860
|
+
|
|
834
861
|
decoders.EntityCreatorResponse = (input?: Record<string, any>) => {
|
|
835
862
|
const typeMappings: TypeMapping = {
|
|
836
863
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -1670,6 +1697,13 @@ decoders.ReactionResponse = (input?: Record<string, any>) => {
|
|
|
1670
1697
|
return decode(typeMappings, input);
|
|
1671
1698
|
};
|
|
1672
1699
|
|
|
1700
|
+
decoders.ReadCollectionsResponse = (input?: Record<string, any>) => {
|
|
1701
|
+
const typeMappings: TypeMapping = {
|
|
1702
|
+
collections: { type: 'CollectionResponse', isSingle: false },
|
|
1703
|
+
};
|
|
1704
|
+
return decode(typeMappings, input);
|
|
1705
|
+
};
|
|
1706
|
+
|
|
1673
1707
|
decoders.RejectFeedMemberInviteResponse = (input?: Record<string, any>) => {
|
|
1674
1708
|
const typeMappings: TypeMapping = {
|
|
1675
1709
|
member: { type: 'FeedMemberResponse', isSingle: true },
|
|
@@ -1893,6 +1927,13 @@ decoders.UpdateBookmarkResponse = (input?: Record<string, any>) => {
|
|
|
1893
1927
|
return decode(typeMappings, input);
|
|
1894
1928
|
};
|
|
1895
1929
|
|
|
1930
|
+
decoders.UpdateCollectionsResponse = (input?: Record<string, any>) => {
|
|
1931
|
+
const typeMappings: TypeMapping = {
|
|
1932
|
+
collections: { type: 'CollectionResponse', isSingle: false },
|
|
1933
|
+
};
|
|
1934
|
+
return decode(typeMappings, input);
|
|
1935
|
+
};
|
|
1936
|
+
|
|
1896
1937
|
decoders.UpdateCommentResponse = (input?: Record<string, any>) => {
|
|
1897
1938
|
const typeMappings: TypeMapping = {
|
|
1898
1939
|
comment: { type: 'CommentResponse', isSingle: true },
|