@stream-io/feeds-client 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/@react-bindings/contexts/StreamSearchContext.d.ts +1 -1
  3. package/dist/@react-bindings/contexts/StreamSearchResultsContext.d.ts +1 -1
  4. package/dist/@react-bindings/hooks/search-state-hooks/useSearchQuery.d.ts +1 -1
  5. package/dist/@react-bindings/hooks/search-state-hooks/useSearchResult.d.ts +1 -1
  6. package/dist/@react-bindings/hooks/search-state-hooks/useSearchSources.d.ts +2 -2
  7. package/dist/@react-bindings/wrappers/StreamSearch.d.ts +1 -1
  8. package/dist/@react-bindings/wrappers/StreamSearchResults.d.ts +1 -1
  9. package/dist/index-react-bindings.browser.cjs +26 -8
  10. package/dist/index-react-bindings.browser.cjs.map +1 -1
  11. package/dist/index-react-bindings.browser.js +26 -8
  12. package/dist/index-react-bindings.browser.js.map +1 -1
  13. package/dist/index-react-bindings.node.cjs +26 -8
  14. package/dist/index-react-bindings.node.cjs.map +1 -1
  15. package/dist/index-react-bindings.node.js +26 -8
  16. package/dist/index-react-bindings.node.js.map +1 -1
  17. package/dist/index.browser.cjs +242 -170
  18. package/dist/index.browser.cjs.map +1 -1
  19. package/dist/index.browser.js +242 -171
  20. package/dist/index.browser.js.map +1 -1
  21. package/dist/index.d.ts +1 -5
  22. package/dist/index.node.cjs +242 -170
  23. package/dist/index.node.cjs.map +1 -1
  24. package/dist/index.node.js +242 -171
  25. package/dist/index.node.js.map +1 -1
  26. package/dist/src/common/{ActivitySearchSource.d.ts → search/ActivitySearchSource.d.ts} +3 -3
  27. package/dist/src/common/{BaseSearchSource.d.ts → search/BaseSearchSource.d.ts} +41 -35
  28. package/dist/src/common/{FeedSearchSource.d.ts → search/FeedSearchSource.d.ts} +3 -3
  29. package/dist/src/common/{SearchController.d.ts → search/SearchController.d.ts} +1 -3
  30. package/dist/src/common/{UserSearchSource.d.ts → search/UserSearchSource.d.ts} +4 -4
  31. package/dist/src/common/search/index.d.ts +6 -0
  32. package/dist/src/common/search/types.d.ts +22 -0
  33. package/dist/src/common/types.d.ts +1 -0
  34. package/dist/src/feed/event-handlers/activity/handle-activity-deleted.d.ts +5 -12
  35. package/dist/src/gen/models/index.d.ts +58 -26
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/index.ts +1 -5
  38. package/package.json +1 -1
  39. package/src/common/{ActivitySearchSource.ts → search/ActivitySearchSource.ts} +3 -3
  40. package/src/common/{BaseSearchSource.ts → search/BaseSearchSource.ts} +137 -69
  41. package/src/common/{FeedSearchSource.ts → search/FeedSearchSource.ts} +3 -3
  42. package/src/common/{SearchController.ts → search/SearchController.ts} +2 -7
  43. package/src/common/{UserSearchSource.ts → search/UserSearchSource.ts} +3 -3
  44. package/src/common/search/index.ts +6 -0
  45. package/src/common/search/types.ts +21 -0
  46. package/src/common/types.ts +2 -0
  47. package/src/feed/event-handlers/activity/activity-utils.test.ts +2 -2
  48. package/src/feed/event-handlers/activity/handle-activity-added.test.ts +86 -0
  49. package/src/feed/event-handlers/activity/handle-activity-deleted.test.ts +117 -0
  50. package/src/feed/event-handlers/activity/handle-activity-deleted.ts +8 -4
  51. package/src/feed/event-handlers/feed-member/handle-feed-member-added.test.ts +75 -0
  52. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.test.ts +82 -0
  53. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +19 -9
  54. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.test.ts +84 -0
  55. package/src/gen/feeds/FeedsApi.ts +6 -0
  56. package/src/gen/model-decoders/decoders.ts +13 -1
  57. package/src/gen/models/index.ts +90 -34
  58. package/src/test-utils/response-generators.ts +107 -0
  59. package/dist/src/test-utils/index.d.ts +0 -1
  60. package/dist/src/test-utils/response-generators.d.ts +0 -74
@@ -0,0 +1,75 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { Feed } from '../../../feed';
3
+ import { FeedsClient } from '../../../feeds-client';
4
+ import { handleFeedMemberAdded } from './handle-feed-member-added';
5
+ import {
6
+ generateFeedResponse,
7
+ generateFeedMemberAddedEvent,
8
+ generateFeedMemberResponse,
9
+ generateOwnUser,
10
+ getHumanId,
11
+ } from '../../../test-utils/response-generators';
12
+
13
+ describe(handleFeedMemberAdded.name, () => {
14
+ let feed: Feed;
15
+ let client: FeedsClient;
16
+ let currentUserId: string;
17
+
18
+ beforeEach(() => {
19
+ client = new FeedsClient('mock-api-key');
20
+ currentUserId = getHumanId();
21
+ client.state.partialNext({
22
+ connected_user: generateOwnUser({ id: currentUserId }),
23
+ });
24
+ const feedResponse = generateFeedResponse({
25
+ id: 'main',
26
+ group_id: 'user',
27
+ created_by: { id: currentUserId },
28
+ });
29
+ feed = new Feed(
30
+ client,
31
+ feedResponse.group_id,
32
+ feedResponse.id,
33
+ feedResponse,
34
+ );
35
+ });
36
+
37
+ it('prepends to members if members array exists', () => {
38
+ const existingMember = generateFeedMemberResponse();
39
+ feed.state.partialNext({ members: [existingMember] });
40
+
41
+ const event = generateFeedMemberAddedEvent();
42
+
43
+ handleFeedMemberAdded.call(feed, event);
44
+
45
+ const stateAfter = feed.currentState;
46
+ expect(stateAfter.members).toHaveLength(2);
47
+ expect(stateAfter.members?.[0]).toBe(event.member);
48
+ });
49
+
50
+ it('does not create members array if it does not exist', () => {
51
+ const event = generateFeedMemberAddedEvent();
52
+
53
+ const stateBefore = feed.currentState;
54
+ expect(stateBefore.members).toBeUndefined();
55
+
56
+ handleFeedMemberAdded.call(feed, event);
57
+
58
+ const stateAfter = feed.currentState;
59
+ expect(stateAfter).toBe(stateBefore);
60
+ });
61
+
62
+ it('sets own_membership when the added member is the connected user', () => {
63
+ const event = generateFeedMemberAddedEvent({
64
+ member: { user: { id: currentUserId } },
65
+ });
66
+
67
+ const stateBefore = feed.currentState;
68
+ expect(stateBefore.own_membership).toBeUndefined();
69
+
70
+ handleFeedMemberAdded.call(feed, event);
71
+
72
+ const stateAfter = feed.currentState;
73
+ expect(stateAfter.own_membership).toBe(event.member);
74
+ });
75
+ });
@@ -0,0 +1,82 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { Feed } from '../../../feed';
3
+ import { FeedsClient } from '../../../feeds-client';
4
+ import { handleFeedMemberRemoved } from './handle-feed-member-removed';
5
+ import {
6
+ generateFeedResponse,
7
+ generateFeedMemberRemovedEvent,
8
+ generateFeedMemberResponse,
9
+ generateOwnUser,
10
+ getHumanId,
11
+ } from '../../../test-utils/response-generators';
12
+
13
+ describe(handleFeedMemberRemoved.name, () => {
14
+ let feed: Feed;
15
+ let client: FeedsClient;
16
+ let currentUserId: string;
17
+
18
+ beforeEach(() => {
19
+ client = new FeedsClient('mock-api-key');
20
+ currentUserId = getHumanId();
21
+ client.state.partialNext({
22
+ connected_user: generateOwnUser({ id: currentUserId }),
23
+ });
24
+ const feedResponse = generateFeedResponse({
25
+ id: 'main',
26
+ group_id: 'user',
27
+ created_by: { id: currentUserId },
28
+ });
29
+ feed = new Feed(
30
+ client,
31
+ feedResponse.group_id,
32
+ feedResponse.id,
33
+ feedResponse,
34
+ );
35
+ });
36
+
37
+ it('removes from members if present', () => {
38
+ const memberToRemove = generateFeedMemberResponse();
39
+ const memberToKeep = generateFeedMemberResponse();
40
+ feed.state.partialNext({ members: [memberToRemove, memberToKeep] });
41
+
42
+ const event = generateFeedMemberRemovedEvent({
43
+ member_id: memberToRemove.user.id,
44
+ });
45
+
46
+ handleFeedMemberRemoved.call(feed, event);
47
+
48
+ const stateAfter = feed.currentState;
49
+ expect(stateAfter.members).toHaveLength(1);
50
+ expect(stateAfter.members?.[0]).toBe(memberToKeep);
51
+ });
52
+
53
+ it('does not change state when members array is undefined', () => {
54
+ const event = generateFeedMemberRemovedEvent();
55
+
56
+ const stateBefore = feed.currentState;
57
+ expect(stateBefore.members).toBeUndefined();
58
+
59
+ handleFeedMemberRemoved.call(feed, event);
60
+
61
+ const stateAfter = feed.currentState;
62
+ expect(stateAfter).toBe(stateBefore);
63
+ });
64
+
65
+ it('deletes own_membership when the removed member is the connected user', () => {
66
+ const ownMember = generateFeedMemberResponse({
67
+ user: { id: currentUserId },
68
+ });
69
+ feed.state.partialNext({ own_membership: ownMember, members: [] });
70
+
71
+ const event = generateFeedMemberRemovedEvent({ member_id: currentUserId });
72
+
73
+ const stateBefore = feed.currentState;
74
+ expect(stateBefore.own_membership).toBe(ownMember);
75
+
76
+ handleFeedMemberRemoved.call(feed, event);
77
+
78
+ const stateAfter = feed.currentState;
79
+ expect(stateAfter.own_membership).toBeUndefined();
80
+ expect(stateAfter.members).toBe(stateBefore.members);
81
+ });
82
+ });
@@ -1,4 +1,4 @@
1
- import { Feed } from '../../../feed';
1
+ import { Feed, FeedState } from '../../../feed';
2
2
  import { EventPayload } from '../../../types-internal';
3
3
 
4
4
  export function handleFeedMemberRemoved(
@@ -8,17 +8,27 @@ export function handleFeedMemberRemoved(
8
8
  const { connected_user: connectedUser } = this.client.state.getLatestValue();
9
9
 
10
10
  this.state.next((currentState) => {
11
- const newState = {
12
- ...currentState,
13
- members: currentState.members?.filter(
14
- (member) => member.user.id !== event.user?.id,
15
- ),
16
- };
11
+ let newState: FeedState | undefined;
17
12
 
18
- if (connectedUser?.id === event.member_id) {
13
+ if (typeof currentState.members !== 'undefined') {
14
+ const filtered = currentState.members.filter(
15
+ (member) => member.user.id !== event.member_id,
16
+ );
17
+
18
+ if (filtered.length !== currentState.members.length) {
19
+ newState ??= { ...currentState };
20
+ newState.members = filtered;
21
+ }
22
+ }
23
+
24
+ if (
25
+ connectedUser?.id === event.member_id &&
26
+ typeof currentState.own_membership !== 'undefined'
27
+ ) {
28
+ newState ??= { ...currentState };
19
29
  delete newState.own_membership;
20
30
  }
21
31
 
22
- return newState;
32
+ return newState ?? currentState;
23
33
  });
24
34
  }
@@ -0,0 +1,84 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { Feed } from '../../../feed';
3
+ import { FeedsClient } from '../../../feeds-client';
4
+ import { handleFeedMemberUpdated } from './handle-feed-member-updated';
5
+ import {
6
+ generateFeedResponse,
7
+ generateFeedMemberUpdatedEvent,
8
+ generateFeedMemberResponse,
9
+ generateOwnUser,
10
+ getHumanId,
11
+ } from '../../../test-utils/response-generators';
12
+
13
+ describe(handleFeedMemberUpdated.name, () => {
14
+ let feed: Feed;
15
+ let client: FeedsClient;
16
+ let currentUserId: string;
17
+
18
+ beforeEach(() => {
19
+ client = new FeedsClient('mock-api-key');
20
+ currentUserId = getHumanId();
21
+ client.state.partialNext({
22
+ connected_user: generateOwnUser({ id: currentUserId }),
23
+ });
24
+ const feedResponse = generateFeedResponse({
25
+ id: 'main',
26
+ group_id: 'user',
27
+ created_by: { id: currentUserId },
28
+ });
29
+ feed = new Feed(
30
+ client,
31
+ feedResponse.group_id,
32
+ feedResponse.id,
33
+ feedResponse,
34
+ );
35
+ });
36
+
37
+ it('updates an existing member in members array', () => {
38
+ const member1 = generateFeedMemberResponse();
39
+ const member2 = generateFeedMemberResponse();
40
+ feed.state.partialNext({ members: [member1, member2] });
41
+
42
+ const event = generateFeedMemberUpdatedEvent({
43
+ member: { user: { id: member1.user.id }, role: 'admin' },
44
+ });
45
+
46
+ handleFeedMemberUpdated.call(feed, event);
47
+
48
+ const stateAfter = feed.currentState;
49
+ expect(stateAfter.members).toHaveLength(2);
50
+ expect(stateAfter.members?.[0]).toBe(event.member);
51
+ expect(stateAfter.members?.[1]).toBe(member2);
52
+ });
53
+
54
+ it('does not modify members when target is not present', () => {
55
+ const existingMember = generateFeedMemberResponse();
56
+ feed.state.partialNext({ members: [existingMember] });
57
+
58
+ const event = generateFeedMemberUpdatedEvent();
59
+
60
+ const stateBefore = feed.currentState;
61
+ handleFeedMemberUpdated.call(feed, event);
62
+
63
+ const stateAfter = feed.currentState;
64
+ expect(stateAfter).toBe(stateBefore);
65
+ });
66
+
67
+ it('sets own_membership when the updated member is the connected user', () => {
68
+ const event = generateFeedMemberUpdatedEvent({
69
+ member: {
70
+ user: { id: currentUserId },
71
+ role: 'owner',
72
+ status: 'member',
73
+ },
74
+ });
75
+
76
+ const stateBefore = feed.currentState;
77
+ expect(stateBefore.own_membership).toBeUndefined();
78
+
79
+ handleFeedMemberUpdated.call(feed, event);
80
+
81
+ const stateAfter = feed.currentState;
82
+ expect(stateAfter.own_membership).toBe(event.member);
83
+ });
84
+ });
@@ -578,6 +578,7 @@ export class FeedsApi {
578
578
  const body = {
579
579
  type: request?.type,
580
580
  create_notification_activity: request?.create_notification_activity,
581
+ skip_push: request?.skip_push,
581
582
  custom: request?.custom,
582
583
  };
583
584
 
@@ -888,6 +889,7 @@ export class FeedsApi {
888
889
  object_type: request?.object_type,
889
890
  create_notification_activity: request?.create_notification_activity,
890
891
  parent_id: request?.parent_id,
892
+ skip_push: request?.skip_push,
891
893
  attachments: request?.attachments,
892
894
  mentioned_user_ids: request?.mentioned_user_ids,
893
895
  custom: request?.custom,
@@ -1003,6 +1005,7 @@ export class FeedsApi {
1003
1005
  };
1004
1006
  const body = {
1005
1007
  comment: request?.comment,
1008
+ skip_push: request?.skip_push,
1006
1009
  custom: request?.custom,
1007
1010
  };
1008
1011
 
@@ -1031,6 +1034,7 @@ export class FeedsApi {
1031
1034
  const body = {
1032
1035
  type: request?.type,
1033
1036
  create_notification_activity: request?.create_notification_activity,
1037
+ skip_push: request?.skip_push,
1034
1038
  custom: request?.custom,
1035
1039
  };
1036
1040
 
@@ -1554,6 +1558,7 @@ export class FeedsApi {
1554
1558
  create_notification_activity: request?.create_notification_activity,
1555
1559
  follower_role: request?.follower_role,
1556
1560
  push_preference: request?.push_preference,
1561
+ skip_push: request?.skip_push,
1557
1562
  custom: request?.custom,
1558
1563
  };
1559
1564
 
@@ -1581,6 +1586,7 @@ export class FeedsApi {
1581
1586
  target: request?.target,
1582
1587
  create_notification_activity: request?.create_notification_activity,
1583
1588
  push_preference: request?.push_preference,
1589
+ skip_push: request?.skip_push,
1584
1590
  custom: request?.custom,
1585
1591
  };
1586
1592
 
@@ -6,7 +6,7 @@ export const decoders: Record<string, Decoder> = {};
6
6
 
7
7
  const decodeDatetimeType = (input: number | string) =>
8
8
  typeof input === 'number'
9
- ? new Date(Math.floor(input / 1e6))
9
+ ? new Date(Math.floor(input / 1000000))
10
10
  : new Date(input);
11
11
 
12
12
  decoders.DatetimeType = decodeDatetimeType;
@@ -584,6 +584,8 @@ decoders.CommentAddedEvent = (input?: Record<string, any>) => {
584
584
  const typeMappings: TypeMapping = {
585
585
  created_at: { type: 'DatetimeType', isSingle: true },
586
586
 
587
+ activity: { type: 'ActivityResponse', isSingle: true },
588
+
587
589
  comment: { type: 'CommentResponse', isSingle: true },
588
590
 
589
591
  received_at: { type: 'DatetimeType', isSingle: true },
@@ -606,6 +608,8 @@ decoders.CommentReactionAddedEvent = (input?: Record<string, any>) => {
606
608
  const typeMappings: TypeMapping = {
607
609
  created_at: { type: 'DatetimeType', isSingle: true },
608
610
 
611
+ activity: { type: 'ActivityResponse', isSingle: true },
612
+
609
613
  comment: { type: 'CommentResponse', isSingle: true },
610
614
 
611
615
  reaction: { type: 'FeedsReactionResponse', isSingle: true },
@@ -632,6 +636,8 @@ decoders.CommentReactionUpdatedEvent = (input?: Record<string, any>) => {
632
636
  const typeMappings: TypeMapping = {
633
637
  created_at: { type: 'DatetimeType', isSingle: true },
634
638
 
639
+ activity: { type: 'ActivityResponse', isSingle: true },
640
+
635
641
  comment: { type: 'CommentResponse', isSingle: true },
636
642
 
637
643
  reaction: { type: 'FeedsReactionResponse', isSingle: true },
@@ -1128,6 +1134,8 @@ decoders.Message = (input?: Record<string, any>) => {
1128
1134
 
1129
1135
  thread_participants: { type: 'User', isSingle: false },
1130
1136
 
1137
+ member: { type: 'ChannelMember', isSingle: true },
1138
+
1131
1139
  pinned_by: { type: 'User', isSingle: true },
1132
1140
 
1133
1141
  poll: { type: 'Poll', isSingle: true },
@@ -1214,6 +1222,10 @@ decoders.ModerationCustomActionEvent = (input?: Record<string, any>) => {
1214
1222
 
1215
1223
  decoders.ModerationFlagResponse = (input?: Record<string, any>) => {
1216
1224
  const typeMappings: TypeMapping = {
1225
+ created_at: { type: 'DatetimeType', isSingle: true },
1226
+
1227
+ updated_at: { type: 'DatetimeType', isSingle: true },
1228
+
1217
1229
  review_queue_item: { type: 'ReviewQueueItemResponse', isSingle: true },
1218
1230
 
1219
1231
  user: { type: 'UserResponse', isSingle: true },