@stream-io/feeds-client 0.1.4 → 0.1.5
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/client-state-hooks/index.ts +2 -0
- package/@react-bindings/hooks/feed-state-hooks/index.ts +5 -0
- package/@react-bindings/hooks/internal/index.ts +1 -0
- package/@react-bindings/hooks/util/index.ts +1 -0
- package/@react-bindings/index.ts +6 -3
- package/CHANGELOG.md +16 -0
- package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +12 -0
- package/dist/@react-bindings/hooks/client-state-hooks/index.d.ts +2 -0
- package/dist/@react-bindings/hooks/client-state-hooks/useClientConnectedUser.d.ts +4 -0
- package/dist/@react-bindings/hooks/client-state-hooks/useWsConnectionState.d.ts +6 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/index.d.ts +5 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +19 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +11 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +16 -0
- package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +16 -0
- package/dist/@react-bindings/hooks/{useOwnCapabilities.d.ts → feed-state-hooks/useOwnCapabilities.d.ts} +2 -2
- package/dist/@react-bindings/hooks/internal/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/internal/useStableCallback.d.ts +25 -0
- package/dist/@react-bindings/hooks/util/index.d.ts +1 -0
- package/dist/@react-bindings/hooks/util/useReactionActions.d.ts +17 -0
- package/dist/@react-bindings/index.d.ts +5 -3
- package/dist/@react-bindings/wrappers/StreamFeed.d.ts +12 -0
- package/dist/index-react-bindings.browser.cjs +451 -183
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +446 -185
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +451 -183
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +446 -185
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +167 -72
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +164 -73
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +167 -72
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +164 -73
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +7 -3
- package/dist/src/FeedsClient.d.ts +4 -3
- package/dist/src/types.d.ts +7 -0
- package/dist/src/utils.d.ts +9 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/Feed.ts +200 -89
- package/src/FeedsClient.ts +8 -3
- package/src/common/real-time/StableWSConnection.ts +4 -1
- package/src/types.ts +12 -1
- package/src/utils.ts +25 -1
- package/dist/@react-bindings/hooks/clientStateHooks.d.ts +0 -10
- package/dist/@react-bindings/hooks/useComments.d.ts +0 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/feeds-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"packageManager": "yarn@3.2.4",
|
|
5
5
|
"main": "./dist/index.node.js",
|
|
6
6
|
"exports": {
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@rollup/plugin-replace": "^6.0.1",
|
|
63
63
|
"@rollup/plugin-typescript": "^12.1.0",
|
|
64
|
+
"@stream-io/node-sdk": "https://github.com/GetStream/stream-node.git#feeds-api",
|
|
64
65
|
"@types/react": "^19.1.8",
|
|
65
66
|
"dotenv": "^16.4.5",
|
|
66
67
|
"react": "19.0.0",
|
package/src/Feed.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
BookmarkAddedEvent,
|
|
15
15
|
BookmarkDeletedEvent,
|
|
16
16
|
BookmarkUpdatedEvent,
|
|
17
|
+
QueryFeedMembersRequest,
|
|
18
|
+
SortParamRequest,
|
|
17
19
|
} from './gen/models';
|
|
18
20
|
import { Patch, StateStore } from './common/StateStore';
|
|
19
21
|
import { EventDispatcher } from './common/EventDispatcher';
|
|
@@ -43,6 +45,7 @@ import type {
|
|
|
43
45
|
PagerResponseWithLoadingStates,
|
|
44
46
|
} from './types';
|
|
45
47
|
import type { FromArray } from './types-internal';
|
|
48
|
+
import { checkHasAnotherPage, Constants } from './utils';
|
|
46
49
|
|
|
47
50
|
export type FeedState = Omit<
|
|
48
51
|
Partial<GetOrCreateFeedResponse & FeedResponse>,
|
|
@@ -103,16 +106,15 @@ export type FeedState = Omit<
|
|
|
103
106
|
| undefined
|
|
104
107
|
>;
|
|
105
108
|
|
|
106
|
-
followers_pagination?: LoadingStates & { sort?:
|
|
109
|
+
followers_pagination?: LoadingStates & { sort?: SortParamRequest[] };
|
|
107
110
|
|
|
108
|
-
following_pagination?: LoadingStates & { sort?:
|
|
111
|
+
following_pagination?: LoadingStates & { sort?: SortParamRequest[] };
|
|
112
|
+
|
|
113
|
+
member_pagination?: LoadingStates & { sort?: SortParamRequest[] };
|
|
109
114
|
|
|
110
115
|
last_get_or_create_request_config?: GetOrCreateFeedRequest;
|
|
111
116
|
};
|
|
112
117
|
|
|
113
|
-
const END_OF_LIST = 'eol' as const;
|
|
114
|
-
const DEFAULT_COMMENT_PAGINATION = 'first' as const;
|
|
115
|
-
|
|
116
118
|
type EventHandlerByEventType = {
|
|
117
119
|
[Key in NonNullable<WSEvent['type']>]: Key extends Extract<
|
|
118
120
|
WSEvent,
|
|
@@ -221,7 +223,10 @@ export class Feed extends FeedApi {
|
|
|
221
223
|
|
|
222
224
|
if (
|
|
223
225
|
entityState?.pagination?.sort === 'last' &&
|
|
224
|
-
|
|
226
|
+
!checkHasAnotherPage(
|
|
227
|
+
entityState.comments,
|
|
228
|
+
entityState?.pagination.next,
|
|
229
|
+
)
|
|
225
230
|
) {
|
|
226
231
|
newComments.unshift(comment);
|
|
227
232
|
} else if (entityState?.pagination?.sort === 'first') {
|
|
@@ -320,7 +325,12 @@ export class Feed extends FeedApi {
|
|
|
320
325
|
...event.follow.source_feed,
|
|
321
326
|
};
|
|
322
327
|
|
|
323
|
-
if (
|
|
328
|
+
if (
|
|
329
|
+
!checkHasAnotherPage(
|
|
330
|
+
currentState.following,
|
|
331
|
+
currentState.following_pagination?.next,
|
|
332
|
+
)
|
|
333
|
+
) {
|
|
324
334
|
// TODO: respect sort
|
|
325
335
|
newState.following = currentState.following
|
|
326
336
|
? currentState.following.concat(event.follow)
|
|
@@ -345,7 +355,12 @@ export class Feed extends FeedApi {
|
|
|
345
355
|
: [event.follow];
|
|
346
356
|
}
|
|
347
357
|
|
|
348
|
-
if (
|
|
358
|
+
if (
|
|
359
|
+
!checkHasAnotherPage(
|
|
360
|
+
currentState.followers,
|
|
361
|
+
currentState.followers_pagination?.next,
|
|
362
|
+
)
|
|
363
|
+
) {
|
|
349
364
|
// TODO: respect sort
|
|
350
365
|
newState.followers = currentState.followers
|
|
351
366
|
? currentState.followers.concat(event.follow)
|
|
@@ -400,49 +415,87 @@ export class Feed extends FeedApi {
|
|
|
400
415
|
this.handleCommentReactionEvent.bind(this),
|
|
401
416
|
'feeds.comment.reaction.updated': Feed.noop,
|
|
402
417
|
'feeds.feed_member.added': (event) => {
|
|
403
|
-
const {
|
|
404
|
-
|
|
405
|
-
// do not add a member if the pagination has reached the end of the list
|
|
406
|
-
if (this.currentState.member_pagination?.next !== END_OF_LIST) return;
|
|
418
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
407
419
|
|
|
408
420
|
this.state.next((currentState) => {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
421
|
+
let newState: FeedState | undefined;
|
|
422
|
+
|
|
423
|
+
if (
|
|
424
|
+
!checkHasAnotherPage(
|
|
425
|
+
currentState.members,
|
|
426
|
+
currentState.member_pagination?.next,
|
|
427
|
+
)
|
|
428
|
+
) {
|
|
429
|
+
newState ??= {
|
|
430
|
+
...currentState,
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
newState.members = newState.members?.concat(event.member) ?? [
|
|
434
|
+
event.member,
|
|
435
|
+
];
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
439
|
+
newState ??= {
|
|
440
|
+
...currentState,
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
newState.own_membership = event.member;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return newState ?? currentState;
|
|
416
447
|
});
|
|
417
448
|
},
|
|
418
449
|
'feeds.feed_member.removed': (event) => {
|
|
450
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
451
|
+
|
|
419
452
|
this.state.next((currentState) => {
|
|
420
|
-
|
|
453
|
+
const newState = {
|
|
421
454
|
...currentState,
|
|
422
455
|
members: currentState.members?.filter(
|
|
423
456
|
(member) => member.user.id !== event.user?.id,
|
|
424
457
|
),
|
|
425
458
|
};
|
|
459
|
+
|
|
460
|
+
if (connectedUser?.id === event.member_id) {
|
|
461
|
+
delete newState.own_membership;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return newState;
|
|
426
465
|
});
|
|
427
466
|
},
|
|
428
467
|
'feeds.feed_member.updated': (event) => {
|
|
468
|
+
const { connectedUser } = this.client.state.getLatestValue();
|
|
469
|
+
|
|
429
470
|
this.state.next((currentState) => {
|
|
430
471
|
const memberIndex =
|
|
431
472
|
currentState.members?.findIndex(
|
|
432
473
|
(member) => member.user.id === event.member.user.id,
|
|
433
474
|
) ?? -1;
|
|
434
475
|
|
|
476
|
+
let newState: FeedState | undefined;
|
|
477
|
+
|
|
435
478
|
if (memberIndex !== -1) {
|
|
479
|
+
// if there's an index, there's a member to update
|
|
436
480
|
const newMembers = [...currentState.members!];
|
|
437
481
|
newMembers[memberIndex] = event.member;
|
|
438
482
|
|
|
439
|
-
|
|
483
|
+
newState ??= {
|
|
484
|
+
...currentState,
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
newState.members = newMembers;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (connectedUser?.id === event.member.user.id) {
|
|
491
|
+
newState ??= {
|
|
440
492
|
...currentState,
|
|
441
|
-
members: newMembers,
|
|
442
493
|
};
|
|
494
|
+
|
|
495
|
+
newState.own_membership = event.member;
|
|
443
496
|
}
|
|
444
497
|
|
|
445
|
-
return currentState;
|
|
498
|
+
return newState ?? currentState;
|
|
446
499
|
});
|
|
447
500
|
},
|
|
448
501
|
// the poll events should be removed from here
|
|
@@ -614,38 +667,6 @@ export class Feed extends FeedApi {
|
|
|
614
667
|
...responseCopy,
|
|
615
668
|
};
|
|
616
669
|
|
|
617
|
-
// if there is no next cursor, set it to END_OF_LIST
|
|
618
|
-
// request has to have a limit set for this to work
|
|
619
|
-
if (
|
|
620
|
-
(request?.followers_pagination?.limit ?? 0) > 0 &&
|
|
621
|
-
typeof nextState.followers_pagination?.next === 'undefined'
|
|
622
|
-
) {
|
|
623
|
-
nextState.followers_pagination = {
|
|
624
|
-
...nextState.followers_pagination,
|
|
625
|
-
next: END_OF_LIST,
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
if (
|
|
630
|
-
(request?.following_pagination?.limit ?? 0) > 0 &&
|
|
631
|
-
typeof nextState.following_pagination?.next === 'undefined'
|
|
632
|
-
) {
|
|
633
|
-
nextState.following_pagination = {
|
|
634
|
-
...nextState.following_pagination,
|
|
635
|
-
next: END_OF_LIST,
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
if (
|
|
640
|
-
(request?.member_pagination?.limit ?? 0) > 0 &&
|
|
641
|
-
typeof nextState.member_pagination?.next === 'undefined'
|
|
642
|
-
) {
|
|
643
|
-
nextState.member_pagination = {
|
|
644
|
-
...nextState.member_pagination,
|
|
645
|
-
next: END_OF_LIST,
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
670
|
if (!request?.followers_pagination?.limit) {
|
|
650
671
|
delete nextState.followers;
|
|
651
672
|
}
|
|
@@ -796,6 +817,8 @@ export class Feed extends FeedApi {
|
|
|
796
817
|
sort: string;
|
|
797
818
|
base: () => Promise<PagerResponse & { comments: CommentResponse[] }>;
|
|
798
819
|
}) {
|
|
820
|
+
let error: unknown;
|
|
821
|
+
|
|
799
822
|
try {
|
|
800
823
|
this.state.next((currentState) => ({
|
|
801
824
|
...currentState,
|
|
@@ -811,7 +834,7 @@ export class Feed extends FeedApi {
|
|
|
811
834
|
},
|
|
812
835
|
}));
|
|
813
836
|
|
|
814
|
-
const { next: newNextCursor
|
|
837
|
+
const { next: newNextCursor, comments } = await base();
|
|
815
838
|
|
|
816
839
|
this.state.next((currentState) => {
|
|
817
840
|
const newPagination = {
|
|
@@ -840,9 +863,8 @@ export class Feed extends FeedApi {
|
|
|
840
863
|
},
|
|
841
864
|
};
|
|
842
865
|
});
|
|
843
|
-
} catch (
|
|
844
|
-
|
|
845
|
-
// TODO: figure out how to handle errorss
|
|
866
|
+
} catch (e) {
|
|
867
|
+
error = e;
|
|
846
868
|
} finally {
|
|
847
869
|
this.state.next((currentState) => ({
|
|
848
870
|
...currentState,
|
|
@@ -858,6 +880,10 @@ export class Feed extends FeedApi {
|
|
|
858
880
|
},
|
|
859
881
|
}));
|
|
860
882
|
}
|
|
883
|
+
|
|
884
|
+
if (error) {
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
861
887
|
}
|
|
862
888
|
|
|
863
889
|
public async loadNextPageActivityComments(
|
|
@@ -866,15 +892,22 @@ export class Feed extends FeedApi {
|
|
|
866
892
|
Omit<GetCommentsRequest, 'object_id' | 'object_type' | 'next'>
|
|
867
893
|
>,
|
|
868
894
|
) {
|
|
869
|
-
const
|
|
870
|
-
this.currentState.comments_by_entity_id[activity.id]
|
|
871
|
-
const
|
|
872
|
-
const
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
895
|
+
const currentEntityState =
|
|
896
|
+
this.currentState.comments_by_entity_id[activity.id];
|
|
897
|
+
const currentPagination = currentEntityState?.pagination;
|
|
898
|
+
const currentNextCursor = currentPagination?.next;
|
|
899
|
+
const currentSort = currentPagination?.sort;
|
|
900
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
901
|
+
|
|
902
|
+
const sort =
|
|
903
|
+
currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
904
|
+
|
|
905
|
+
if (
|
|
906
|
+
isLoading ||
|
|
907
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)
|
|
908
|
+
) {
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
878
911
|
|
|
879
912
|
await this.loadNextPageComments({
|
|
880
913
|
forId: activity.id,
|
|
@@ -894,15 +927,22 @@ export class Feed extends FeedApi {
|
|
|
894
927
|
comment: CommentResponse,
|
|
895
928
|
request?: Partial<Omit<GetCommentsRepliesRequest, 'comment_id' | 'next'>>,
|
|
896
929
|
) {
|
|
897
|
-
const
|
|
898
|
-
this.currentState.comments_by_entity_id[comment.id]
|
|
899
|
-
const
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
930
|
+
const currentEntityState =
|
|
931
|
+
this.currentState.comments_by_entity_id[comment.id];
|
|
932
|
+
const currentPagination = currentEntityState?.pagination;
|
|
933
|
+
const currentNextCursor = currentPagination?.next;
|
|
934
|
+
const currentSort = currentPagination?.sort;
|
|
935
|
+
const isLoading = currentPagination?.loading_next_page;
|
|
936
|
+
|
|
937
|
+
const sort =
|
|
938
|
+
currentSort ?? request?.sort ?? Constants.DEFAULT_COMMENT_PAGINATION;
|
|
939
|
+
|
|
940
|
+
if (
|
|
941
|
+
isLoading ||
|
|
942
|
+
!checkHasAnotherPage(currentEntityState?.comments, currentNextCursor)
|
|
943
|
+
) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
906
946
|
|
|
907
947
|
await this.loadNextPageComments({
|
|
908
948
|
forId: comment.id,
|
|
@@ -911,7 +951,10 @@ export class Feed extends FeedApi {
|
|
|
911
951
|
...request,
|
|
912
952
|
comment_id: comment.id,
|
|
913
953
|
// use known sort first (prevents broken pagination)
|
|
914
|
-
sort:
|
|
954
|
+
sort:
|
|
955
|
+
currentSort ??
|
|
956
|
+
request?.sort ??
|
|
957
|
+
Constants.DEFAULT_COMMENT_PAGINATION,
|
|
915
958
|
next: currentNextCursor,
|
|
916
959
|
}),
|
|
917
960
|
parentId: comment.parent_id ?? comment.object_id,
|
|
@@ -921,15 +964,20 @@ export class Feed extends FeedApi {
|
|
|
921
964
|
|
|
922
965
|
private async loadNextPageFollows(
|
|
923
966
|
type: 'followers' | 'following',
|
|
924
|
-
request: Pick<QueryFollowsRequest, 'limit'>,
|
|
967
|
+
request: Pick<QueryFollowsRequest, 'limit' | 'sort'>,
|
|
925
968
|
) {
|
|
926
969
|
const paginationKey = `${type}_pagination` as const;
|
|
927
970
|
const method = `query${capitalize(type)}` as const;
|
|
928
971
|
|
|
972
|
+
const currentFollows = this.currentState[type];
|
|
929
973
|
const currentNextCursor = this.currentState[paginationKey]?.next;
|
|
930
974
|
const isLoading = this.currentState[paginationKey]?.loading_next_page;
|
|
975
|
+
const sort = this.currentState[paginationKey]?.sort ?? request.sort;
|
|
976
|
+
let error: unknown;
|
|
931
977
|
|
|
932
|
-
if (isLoading || currentNextCursor
|
|
978
|
+
if (isLoading || !checkHasAnotherPage(currentFollows, currentNextCursor)) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
933
981
|
|
|
934
982
|
try {
|
|
935
983
|
this.state.next((currentState) => {
|
|
@@ -942,12 +990,11 @@ export class Feed extends FeedApi {
|
|
|
942
990
|
};
|
|
943
991
|
});
|
|
944
992
|
|
|
945
|
-
const { next: newNextCursor
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
);
|
|
993
|
+
const { next: newNextCursor, follows } = await this[method]({
|
|
994
|
+
...request,
|
|
995
|
+
next: currentNextCursor,
|
|
996
|
+
sort,
|
|
997
|
+
});
|
|
951
998
|
|
|
952
999
|
this.state.next((currentState) => ({
|
|
953
1000
|
...currentState,
|
|
@@ -957,11 +1004,11 @@ export class Feed extends FeedApi {
|
|
|
957
1004
|
[paginationKey]: {
|
|
958
1005
|
...currentState[paginationKey],
|
|
959
1006
|
next: newNextCursor,
|
|
1007
|
+
sort,
|
|
960
1008
|
},
|
|
961
1009
|
}));
|
|
962
|
-
} catch (
|
|
963
|
-
|
|
964
|
-
// TODO: figure out how to handle errorss
|
|
1010
|
+
} catch (e) {
|
|
1011
|
+
error = e;
|
|
965
1012
|
} finally {
|
|
966
1013
|
this.state.next((currentState) => {
|
|
967
1014
|
return {
|
|
@@ -973,6 +1020,10 @@ export class Feed extends FeedApi {
|
|
|
973
1020
|
};
|
|
974
1021
|
});
|
|
975
1022
|
}
|
|
1023
|
+
|
|
1024
|
+
if (error) {
|
|
1025
|
+
throw error;
|
|
1026
|
+
}
|
|
976
1027
|
}
|
|
977
1028
|
|
|
978
1029
|
async loadNextPageFollowers(request: Pick<QueryFollowsRequest, 'limit'>) {
|
|
@@ -983,6 +1034,66 @@ export class Feed extends FeedApi {
|
|
|
983
1034
|
await this.loadNextPageFollows('following', request);
|
|
984
1035
|
}
|
|
985
1036
|
|
|
1037
|
+
async loadNextPageMembers(
|
|
1038
|
+
request: Omit<QueryFeedMembersRequest, 'next' | 'prev'>,
|
|
1039
|
+
) {
|
|
1040
|
+
const currentMembers = this.currentState.members;
|
|
1041
|
+
const currentNextCursor = this.currentState.member_pagination?.next;
|
|
1042
|
+
const isLoading = this.currentState.member_pagination?.loading_next_page;
|
|
1043
|
+
const sort = this.currentState.member_pagination?.sort ?? request.sort;
|
|
1044
|
+
let error: unknown;
|
|
1045
|
+
|
|
1046
|
+
if (isLoading || !checkHasAnotherPage(currentMembers, currentNextCursor)) {
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
try {
|
|
1051
|
+
this.state.next((currentState) => ({
|
|
1052
|
+
...currentState,
|
|
1053
|
+
member_pagination: {
|
|
1054
|
+
...currentState.member_pagination,
|
|
1055
|
+
loading_next_page: true,
|
|
1056
|
+
},
|
|
1057
|
+
}));
|
|
1058
|
+
|
|
1059
|
+
const { next: newNextCursor, members } =
|
|
1060
|
+
await this.client.queryFeedMembers({
|
|
1061
|
+
...request,
|
|
1062
|
+
sort,
|
|
1063
|
+
feed_id: this.id,
|
|
1064
|
+
feed_group_id: this.group,
|
|
1065
|
+
next: currentNextCursor,
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
this.state.next((currentState) => ({
|
|
1069
|
+
...currentState,
|
|
1070
|
+
members: currentState.members
|
|
1071
|
+
? currentState.members.concat(members)
|
|
1072
|
+
: members,
|
|
1073
|
+
member_pagination: {
|
|
1074
|
+
...currentState.member_pagination,
|
|
1075
|
+
next: newNextCursor,
|
|
1076
|
+
// set sort if not defined yet
|
|
1077
|
+
sort: currentState.member_pagination?.sort ?? request.sort,
|
|
1078
|
+
},
|
|
1079
|
+
}));
|
|
1080
|
+
} catch (e) {
|
|
1081
|
+
error = e;
|
|
1082
|
+
} finally {
|
|
1083
|
+
this.state.next((currentState) => ({
|
|
1084
|
+
...currentState,
|
|
1085
|
+
member_pagination: {
|
|
1086
|
+
...currentState.member_pagination,
|
|
1087
|
+
loading_next_page: false,
|
|
1088
|
+
},
|
|
1089
|
+
}));
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (error) {
|
|
1093
|
+
throw error;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
986
1097
|
/**
|
|
987
1098
|
* Method which queries followers of this feed (feeds which target this feed).
|
|
988
1099
|
*
|
package/src/FeedsClient.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
UserRequest,
|
|
13
13
|
WSEvent,
|
|
14
14
|
} from './gen/models';
|
|
15
|
-
import { FeedsEvent, TokenOrProvider } from './types';
|
|
15
|
+
import { FeedsEvent, StreamFile, TokenOrProvider } from './types';
|
|
16
16
|
import { StateStore } from './common/StateStore';
|
|
17
17
|
import { TokenManager } from './common/TokenManager';
|
|
18
18
|
import { ConnectionIdManager } from './common/ConnectionIdManager';
|
|
@@ -22,6 +22,7 @@ import { ApiClient } from './common/ApiClient';
|
|
|
22
22
|
import {
|
|
23
23
|
addConnectionEventListeners,
|
|
24
24
|
removeConnectionEventListeners,
|
|
25
|
+
streamDevToken,
|
|
25
26
|
} from './common/utils';
|
|
26
27
|
import { decodeWSEvent } from './gen/model-decoders/event-decoder-mapping';
|
|
27
28
|
import { Feed } from './Feed';
|
|
@@ -243,6 +244,10 @@ export class FeedsClient extends FeedsApi {
|
|
|
243
244
|
}
|
|
244
245
|
};
|
|
245
246
|
|
|
247
|
+
devToken = (userId: string) => {
|
|
248
|
+
return streamDevToken(userId);
|
|
249
|
+
};
|
|
250
|
+
|
|
246
251
|
closePoll = async (request: {
|
|
247
252
|
poll_id: string;
|
|
248
253
|
}): Promise<StreamResponse<PollResponse>> => {
|
|
@@ -255,7 +260,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
255
260
|
};
|
|
256
261
|
|
|
257
262
|
// @ts-expect-error API spec says file should be a string
|
|
258
|
-
uploadFile = (request: Omit<FileUploadRequest, 'file'> & { file:
|
|
263
|
+
uploadFile = (request: Omit<FileUploadRequest, 'file'> & { file: StreamFile }) => {
|
|
259
264
|
return super.uploadFile({
|
|
260
265
|
// @ts-expect-error API spec says file should be a string
|
|
261
266
|
file: request.file,
|
|
@@ -264,7 +269,7 @@ export class FeedsClient extends FeedsApi {
|
|
|
264
269
|
|
|
265
270
|
// @ts-expect-error API spec says file should be a string
|
|
266
271
|
uploadImage = (
|
|
267
|
-
request: Omit<ImageUploadRequest, 'file'> & { file:
|
|
272
|
+
request: Omit<ImageUploadRequest, 'file'> & { file: StreamFile },
|
|
268
273
|
) => {
|
|
269
274
|
return super.uploadImage({
|
|
270
275
|
// @ts-expect-error API spec says file should be a string
|
|
@@ -487,7 +487,10 @@ export class StableWSConnection {
|
|
|
487
487
|
onmessage = (wsID: number, event: MessageEvent) => {
|
|
488
488
|
if (this.wsID !== wsID) return;
|
|
489
489
|
|
|
490
|
-
this._log('onmessage() - onmessage callback', {
|
|
490
|
+
this._log('onmessage() - onmessage callback', {
|
|
491
|
+
event: { ...event, data: JSON.parse(event.data) },
|
|
492
|
+
wsID,
|
|
493
|
+
});
|
|
491
494
|
let data = typeof event.data === 'string' ? JSON.parse(event.data) : null;
|
|
492
495
|
this.decoders.forEach((decode) => {
|
|
493
496
|
data = decode(data);
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { ConnectionChangedEvent } from './common/real-time/event-models';
|
|
2
2
|
import { NetworkChangedEvent } from './common/types';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
PagerResponse,
|
|
5
|
+
WSEvent,
|
|
6
|
+
} from './gen/models';
|
|
7
|
+
import type {
|
|
8
|
+
ActivityResponse,
|
|
9
|
+
CommentResponse,
|
|
10
|
+
} from './gen/models';
|
|
4
11
|
import { FeedsClient } from './FeedsClient';
|
|
5
12
|
|
|
6
13
|
export type FeedsEvent = WSEvent | ConnectionChangedEvent | NetworkChangedEvent;
|
|
@@ -22,3 +29,7 @@ export type LoadingStates = {
|
|
|
22
29
|
export type TokenOrProvider = string | TokenProvider;
|
|
23
30
|
|
|
24
31
|
export type TokenProvider = () => Promise<string>;
|
|
32
|
+
|
|
33
|
+
export type StreamFile = File | { name: string, uri: string, type: string }
|
|
34
|
+
|
|
35
|
+
export type CommentParent = ActivityResponse | CommentResponse;
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import { CommentParent, StreamFile } from './types';
|
|
2
|
+
import type { CommentResponse } from './gen/models';
|
|
3
|
+
|
|
4
|
+
export const isImageFile = (file: StreamFile) => {
|
|
2
5
|
// photoshop files begin with 'image/'
|
|
3
6
|
return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
|
|
4
7
|
};
|
|
8
|
+
|
|
9
|
+
export const isVideoFile = (file: StreamFile) => {
|
|
10
|
+
return file.type.startsWith('video/');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const checkHasAnotherPage = <T extends unknown | undefined>(
|
|
14
|
+
v: T,
|
|
15
|
+
cursor: string | undefined,
|
|
16
|
+
) =>
|
|
17
|
+
(typeof v === 'undefined' && typeof cursor === 'undefined') ||
|
|
18
|
+
typeof cursor === 'string';
|
|
19
|
+
|
|
20
|
+
export const isCommentResponse = (
|
|
21
|
+
entity: CommentParent,
|
|
22
|
+
): entity is CommentResponse => {
|
|
23
|
+
return typeof (entity as CommentResponse)?.object_id === 'string';
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Constants = {
|
|
27
|
+
DEFAULT_COMMENT_PAGINATION: 'first',
|
|
28
|
+
} as const;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
|
|
3
|
-
*/
|
|
4
|
-
export declare const useClientConnectedUser: () => import("../..").OwnUser | undefined;
|
|
5
|
-
/**
|
|
6
|
-
* A React hook that returns the websocket connection state of `FeedsClient`.
|
|
7
|
-
*/
|
|
8
|
-
export declare const useWsConnectionState: () => {
|
|
9
|
-
isHealthy: boolean | undefined;
|
|
10
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { ActivityResponse, CommentResponse } from '../../src/gen/models';
|
|
2
|
-
import type { Feed } from '../../src/Feed';
|
|
3
|
-
export declare const useComments: (feed: Feed,
|
|
4
|
-
/**
|
|
5
|
-
* The parent (activity or comment) for which to fetch comments.
|
|
6
|
-
*/
|
|
7
|
-
parent: ActivityResponse | CommentResponse) => {
|
|
8
|
-
comments: CommentResponse[];
|
|
9
|
-
comment_pagination: (import("../../src/gen/models").PagerResponse & import("../..").LoadingStates & {
|
|
10
|
-
sort?: string;
|
|
11
|
-
}) | undefined;
|
|
12
|
-
};
|