@stream-io/feeds-client 0.1.9 → 0.1.11

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 (167) hide show
  1. package/@react-bindings/hooks/search-state-hooks/index.ts +3 -0
  2. package/@react-bindings/index.ts +5 -0
  3. package/CHANGELOG.md +20 -0
  4. package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +1 -1
  5. package/dist/@react-bindings/contexts/StreamFeedsContext.d.ts +1 -1
  6. package/dist/@react-bindings/contexts/StreamSearchContext.d.ts +12 -0
  7. package/dist/@react-bindings/contexts/StreamSearchResultsContext.d.ts +12 -0
  8. package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +1 -1
  9. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +1 -1
  10. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedMetadata.d.ts +1 -1
  11. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +1 -1
  12. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +1 -1
  13. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnCapabilities.d.ts +1 -1
  14. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +1 -1
  15. package/dist/@react-bindings/hooks/search-state-hooks/index.d.ts +3 -0
  16. package/dist/@react-bindings/hooks/search-state-hooks/useSearchQuery.d.ts +4 -0
  17. package/dist/@react-bindings/hooks/search-state-hooks/useSearchResult.d.ts +8 -0
  18. package/dist/@react-bindings/hooks/search-state-hooks/useSearchSources.d.ts +4 -0
  19. package/dist/@react-bindings/hooks/useCreateFeedsClient.d.ts +1 -1
  20. package/dist/@react-bindings/index.d.ts +5 -0
  21. package/dist/@react-bindings/wrappers/StreamFeed.d.ts +1 -1
  22. package/dist/@react-bindings/wrappers/StreamSearch.d.ts +12 -0
  23. package/dist/@react-bindings/wrappers/StreamSearchResults.d.ts +12 -0
  24. package/dist/index-react-bindings.browser.cjs +1669 -1529
  25. package/dist/index-react-bindings.browser.cjs.map +1 -1
  26. package/dist/index-react-bindings.browser.js +1661 -1530
  27. package/dist/index-react-bindings.browser.js.map +1 -1
  28. package/dist/index-react-bindings.node.cjs +1669 -1529
  29. package/dist/index-react-bindings.node.cjs.map +1 -1
  30. package/dist/index-react-bindings.node.js +1661 -1530
  31. package/dist/index-react-bindings.node.js.map +1 -1
  32. package/dist/index.browser.cjs +1615 -1640
  33. package/dist/index.browser.cjs.map +1 -1
  34. package/dist/index.browser.js +1613 -1641
  35. package/dist/index.browser.js.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.node.cjs +1615 -1640
  38. package/dist/index.node.cjs.map +1 -1
  39. package/dist/index.node.js +1613 -1641
  40. package/dist/index.node.js.map +1 -1
  41. package/dist/src/common/ActivitySearchSource.d.ts +1 -1
  42. package/dist/src/common/BaseSearchSource.d.ts +3 -1
  43. package/dist/src/common/FeedSearchSource.d.ts +7 -3
  44. package/dist/src/common/Poll.d.ts +1 -1
  45. package/dist/src/common/SearchController.d.ts +2 -0
  46. package/dist/src/common/UserSearchSource.d.ts +1 -1
  47. package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
  48. package/dist/src/feed/event-handlers/activity/handle-activity-added.d.ts +7 -0
  49. package/dist/src/feed/event-handlers/activity/handle-activity-deleted.d.ts +8 -0
  50. package/dist/src/feed/event-handlers/activity/handle-activity-reaction-added.d.ts +8 -0
  51. package/dist/src/feed/event-handlers/activity/handle-activity-reaction-deleted.d.ts +8 -0
  52. package/dist/src/feed/event-handlers/activity/handle-activity-removed-from-feed.d.ts +3 -0
  53. package/dist/src/feed/event-handlers/activity/handle-activity-updated.d.ts +8 -0
  54. package/dist/src/feed/event-handlers/activity/index.d.ts +6 -0
  55. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +8 -0
  56. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +9 -0
  57. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +8 -0
  58. package/dist/src/feed/event-handlers/bookmark/index.d.ts +3 -0
  59. package/dist/src/feed/event-handlers/comment/handle-comment-added.d.ts +3 -0
  60. package/dist/src/feed/event-handlers/comment/handle-comment-deleted.d.ts +3 -0
  61. package/dist/src/feed/event-handlers/comment/handle-comment-reaction.d.ts +3 -0
  62. package/dist/src/feed/event-handlers/comment/handle-comment-updated.d.ts +3 -0
  63. package/dist/src/feed/event-handlers/comment/index.d.ts +4 -0
  64. package/dist/src/feed/event-handlers/feed/handle-feed-updated.d.ts +3 -0
  65. package/dist/src/feed/event-handlers/feed/index.d.ts +1 -0
  66. package/dist/src/feed/event-handlers/feed-member/handle-feed-member-added.d.ts +3 -0
  67. package/dist/src/feed/event-handlers/feed-member/handle-feed-member-removed.d.ts +3 -0
  68. package/dist/src/feed/event-handlers/feed-member/handle-feed-member-updated.d.ts +3 -0
  69. package/dist/src/feed/event-handlers/feed-member/index.d.ts +3 -0
  70. package/dist/src/feed/event-handlers/follow/handle-follow-created.d.ts +7 -0
  71. package/dist/src/feed/event-handlers/follow/handle-follow-deleted.d.ts +7 -0
  72. package/dist/src/feed/event-handlers/follow/handle-follow-updated.d.ts +3 -0
  73. package/dist/src/feed/event-handlers/follow/index.d.ts +3 -0
  74. package/dist/src/feed/event-handlers/index.d.ts +7 -0
  75. package/dist/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.d.ts +3 -0
  76. package/dist/src/feed/event-handlers/notification-feed/index.d.ts +1 -0
  77. package/dist/src/{Feed.d.ts → feed/feed.d.ts} +15 -34
  78. package/dist/src/feed/index.d.ts +2 -0
  79. package/dist/src/{FeedsClient.d.ts → feeds-client.d.ts} +6 -5
  80. package/dist/src/gen/models/index.d.ts +5 -0
  81. package/dist/src/gen-imports.d.ts +1 -1
  82. package/dist/src/test-utils/index.d.ts +1 -0
  83. package/dist/src/test-utils/response-generators.d.ts +9 -0
  84. package/dist/src/types-internal.d.ts +7 -0
  85. package/dist/src/types.d.ts +1 -1
  86. package/dist/src/utils/check-has-another-page.d.ts +1 -0
  87. package/dist/src/utils/constants.d.ts +3 -0
  88. package/dist/src/utils/index.d.ts +5 -0
  89. package/dist/src/utils/state-update-queue.d.ts +6 -0
  90. package/dist/src/utils/type-assertions.d.ts +7 -0
  91. package/dist/src/utils/unique-array-merge.d.ts +1 -0
  92. package/dist/tsconfig.tsbuildinfo +1 -1
  93. package/index.ts +2 -2
  94. package/package.json +2 -1
  95. package/src/common/ActivitySearchSource.ts +6 -16
  96. package/src/common/BaseSearchSource.ts +9 -9
  97. package/src/common/FeedSearchSource.ts +22 -67
  98. package/src/common/Poll.ts +1 -1
  99. package/src/common/SearchController.ts +2 -0
  100. package/src/common/UserSearchSource.ts +10 -62
  101. package/src/{state-updates → feed/event-handlers/activity}/activity-reaction-utils.test.ts +12 -2
  102. package/src/{state-updates → feed/event-handlers/activity}/activity-utils.test.ts +3 -2
  103. package/src/{state-updates/activity-utils.ts → feed/event-handlers/activity/handle-activity-added.ts} +16 -36
  104. package/src/feed/event-handlers/activity/handle-activity-deleted.ts +30 -0
  105. package/src/feed/event-handlers/activity/handle-activity-reaction-added.ts +67 -0
  106. package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.ts +75 -0
  107. package/src/feed/event-handlers/activity/handle-activity-removed-from-feed.ts +16 -0
  108. package/src/feed/event-handlers/activity/handle-activity-updated.ts +47 -0
  109. package/src/feed/event-handlers/activity/index.ts +6 -0
  110. package/src/{state-updates → feed/event-handlers/bookmark}/bookmark-utils.test.ts +2 -2
  111. package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +63 -0
  112. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +84 -0
  113. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +76 -0
  114. package/src/feed/event-handlers/bookmark/index.ts +3 -0
  115. package/src/feed/event-handlers/comment/handle-comment-added.ts +38 -0
  116. package/src/feed/event-handlers/comment/handle-comment-deleted.ts +35 -0
  117. package/src/feed/event-handlers/comment/handle-comment-reaction.ts +61 -0
  118. package/src/feed/event-handlers/comment/handle-comment-updated.ts +35 -0
  119. package/src/feed/event-handlers/comment/index.ts +4 -0
  120. package/src/feed/event-handlers/feed/handle-feed-updated.ts +9 -0
  121. package/src/feed/event-handlers/feed/index.ts +1 -0
  122. package/src/feed/event-handlers/feed-member/handle-feed-member-added.ts +31 -0
  123. package/src/feed/event-handlers/feed-member/handle-feed-member-removed.ts +24 -0
  124. package/src/feed/event-handlers/feed-member/handle-feed-member-updated.ts +40 -0
  125. package/src/feed/event-handlers/feed-member/index.ts +3 -0
  126. package/src/feed/event-handlers/follow/handle-follow-created.test.ts +246 -0
  127. package/src/feed/event-handlers/follow/handle-follow-created.ts +93 -0
  128. package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +264 -0
  129. package/src/feed/event-handlers/follow/handle-follow-deleted.ts +95 -0
  130. package/src/feed/event-handlers/follow/handle-follow-updated.test.ts +174 -0
  131. package/src/feed/event-handlers/follow/handle-follow-updated.ts +88 -0
  132. package/src/feed/event-handlers/follow/index.ts +3 -0
  133. package/src/feed/event-handlers/index.ts +7 -0
  134. package/src/feed/event-handlers/notification-feed/handle-notification-feed-updated.ts +10 -0
  135. package/src/feed/event-handlers/notification-feed/index.ts +1 -0
  136. package/src/{Feed.ts → feed/feed.ts} +72 -483
  137. package/src/feed/index.ts +2 -0
  138. package/src/{FeedsClient.ts → feeds-client.ts} +26 -8
  139. package/src/gen/model-decoders/decoders.ts +7 -0
  140. package/src/gen/models/index.ts +10 -0
  141. package/src/gen-imports.ts +1 -1
  142. package/src/test-utils/index.ts +1 -0
  143. package/src/test-utils/response-generators.ts +102 -0
  144. package/src/types-internal.ts +11 -0
  145. package/src/types.ts +1 -1
  146. package/src/utils/check-has-another-page.ts +6 -0
  147. package/src/utils/constants.ts +3 -0
  148. package/src/utils/index.ts +5 -0
  149. package/src/{state-updates → utils}/state-update-queue.test.ts +6 -6
  150. package/src/utils/state-update-queue.ts +42 -0
  151. package/src/utils/type-assertions.ts +22 -0
  152. package/src/{utils.test.ts → utils/unique-array-merge.test.ts} +7 -3
  153. package/src/utils/unique-array-merge.ts +19 -0
  154. package/dist/src/state-updates/activity-reaction-utils.d.ts +0 -10
  155. package/dist/src/state-updates/activity-utils.d.ts +0 -13
  156. package/dist/src/state-updates/bookmark-utils.d.ts +0 -14
  157. package/dist/src/state-updates/follow-utils.d.ts +0 -19
  158. package/dist/src/state-updates/state-update-queue.d.ts +0 -15
  159. package/dist/src/utils.d.ts +0 -10
  160. package/src/state-updates/activity-reaction-utils.ts +0 -107
  161. package/src/state-updates/bookmark-utils.ts +0 -167
  162. package/src/state-updates/follow-utils.test.ts +0 -552
  163. package/src/state-updates/follow-utils.ts +0 -126
  164. package/src/state-updates/state-update-queue.ts +0 -35
  165. package/src/utils.ts +0 -48
  166. /package/dist/src/{ModerationClient.d.ts → moderation-client.d.ts} +0 -0
  167. /package/src/{ModerationClient.ts → moderation-client.ts} +0 -0
@@ -1,167 +0,0 @@
1
- import {
2
- BookmarkAddedEvent,
3
- BookmarkDeletedEvent,
4
- BookmarkUpdatedEvent,
5
- ActivityResponse,
6
- BookmarkResponse,
7
- } from '../gen/models';
8
- import { UpdateStateResult } from '../types-internal';
9
-
10
- // Helper function to check if two bookmarks are the same
11
- // A bookmark is identified by activity_id + folder_id + user_id
12
- const isSameBookmark = (
13
- bookmark1: BookmarkResponse,
14
- bookmark2: BookmarkResponse,
15
- ): boolean => {
16
- return (
17
- bookmark1.user.id === bookmark2.user.id &&
18
- bookmark1.activity.id === bookmark2.activity.id &&
19
- bookmark1.folder?.id === bookmark2.folder?.id
20
- );
21
- };
22
-
23
- const updateActivityInActivities = (
24
- updatedActivity: ActivityResponse,
25
- activities: ActivityResponse[],
26
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
27
- const index = activities.findIndex((a) => a.id === updatedActivity.id);
28
- if (index !== -1) {
29
- const newActivities = [...activities];
30
- newActivities[index] = updatedActivity;
31
- return { changed: true, activities: newActivities };
32
- } else {
33
- return { changed: false, activities };
34
- }
35
- };
36
-
37
- export const addBookmarkToActivity = (
38
- event: BookmarkAddedEvent,
39
- activity: ActivityResponse,
40
- isCurrentUser: boolean,
41
- ): UpdateStateResult<ActivityResponse> => {
42
- // Update own_bookmarks if the bookmark is from the current user
43
- const ownBookmarks = [...(activity.own_bookmarks || [])];
44
- if (isCurrentUser) {
45
- ownBookmarks.push(event.bookmark);
46
- }
47
-
48
- return {
49
- ...activity,
50
- own_bookmarks: ownBookmarks,
51
- changed: true,
52
- };
53
- };
54
-
55
- export const removeBookmarkFromActivity = (
56
- event: BookmarkDeletedEvent,
57
- activity: ActivityResponse,
58
- isCurrentUser: boolean,
59
- ): UpdateStateResult<ActivityResponse> => {
60
- // Update own_bookmarks if the bookmark is from the current user
61
- const ownBookmarks = isCurrentUser
62
- ? (activity.own_bookmarks || []).filter(
63
- (bookmark) => !isSameBookmark(bookmark, event.bookmark),
64
- )
65
- : activity.own_bookmarks;
66
-
67
- return {
68
- ...activity,
69
- own_bookmarks: ownBookmarks,
70
- changed: true,
71
- };
72
- };
73
-
74
- export const updateBookmarkInActivity = (
75
- event: BookmarkUpdatedEvent,
76
- activity: ActivityResponse,
77
- isCurrentUser: boolean,
78
- ): UpdateStateResult<ActivityResponse> => {
79
- // Update own_bookmarks if the bookmark is from the current user
80
- let ownBookmarks = activity.own_bookmarks || [];
81
- if (isCurrentUser) {
82
- const bookmarkIndex = ownBookmarks.findIndex((bookmark) =>
83
- isSameBookmark(bookmark, event.bookmark),
84
- );
85
- if (bookmarkIndex !== -1) {
86
- ownBookmarks = [...ownBookmarks];
87
- ownBookmarks[bookmarkIndex] = event.bookmark;
88
- }
89
- }
90
-
91
- return {
92
- ...activity,
93
- own_bookmarks: ownBookmarks,
94
- changed: true,
95
- };
96
- };
97
-
98
- export const addBookmarkToActivities = (
99
- event: BookmarkAddedEvent,
100
- activities: ActivityResponse[] | undefined,
101
- isCurrentUser: boolean,
102
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
103
- if (!activities) {
104
- return { changed: false, activities: [] };
105
- }
106
-
107
- const activityIndex = activities.findIndex(
108
- (a) => a.id === event.bookmark.activity.id,
109
- );
110
- if (activityIndex === -1) {
111
- return { changed: false, activities };
112
- }
113
-
114
- const activity = activities[activityIndex];
115
- const updatedActivity = addBookmarkToActivity(event, activity, isCurrentUser);
116
- return updateActivityInActivities(updatedActivity, activities);
117
- };
118
-
119
- export const removeBookmarkFromActivities = (
120
- event: BookmarkDeletedEvent,
121
- activities: ActivityResponse[] | undefined,
122
- isCurrentUser: boolean,
123
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
124
- if (!activities) {
125
- return { changed: false, activities: [] };
126
- }
127
-
128
- const activityIndex = activities.findIndex(
129
- (a) => a.id === event.bookmark.activity.id,
130
- );
131
- if (activityIndex === -1) {
132
- return { changed: false, activities };
133
- }
134
-
135
- const activity = activities[activityIndex];
136
- const updatedActivity = removeBookmarkFromActivity(
137
- event,
138
- activity,
139
- isCurrentUser,
140
- );
141
- return updateActivityInActivities(updatedActivity, activities);
142
- };
143
-
144
- export const updateBookmarkInActivities = (
145
- event: BookmarkUpdatedEvent,
146
- activities: ActivityResponse[] | undefined,
147
- isCurrentUser: boolean,
148
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
149
- if (!activities) {
150
- return { changed: false, activities: [] };
151
- }
152
-
153
- const activityIndex = activities.findIndex(
154
- (a) => a.id === event.bookmark.activity.id,
155
- );
156
- if (activityIndex === -1) {
157
- return { changed: false, activities };
158
- }
159
-
160
- const activity = activities[activityIndex];
161
- const updatedActivity = updateBookmarkInActivity(
162
- event,
163
- activity,
164
- isCurrentUser,
165
- );
166
- return updateActivityInActivities(updatedActivity, activities);
167
- };
@@ -1,552 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
-
3
- import {
4
- handleFollowCreated,
5
- handleFollowDeleted,
6
- handleFollowUpdated,
7
- } from './follow-utils';
8
- import { FollowResponse, FeedResponse, UserResponse } from '../gen/models';
9
- import { FeedState } from '../Feed';
10
-
11
- describe('follow-utils', () => {
12
- const mockUser: UserResponse = {
13
- id: 'user-1',
14
- created_at: new Date(),
15
- updated_at: new Date(),
16
- banned: false,
17
- language: 'en',
18
- online: false,
19
- role: 'user',
20
- blocked_user_ids: [],
21
- teams: [],
22
- custom: {},
23
- };
24
-
25
- const mockFeed: FeedResponse = {
26
- id: 'feed-1',
27
- group_id: 'user',
28
- created_at: new Date(),
29
- updated_at: new Date(),
30
- description: 'Test feed',
31
- fid: 'user:feed-1',
32
- follower_count: 0,
33
- following_count: 0,
34
- member_count: 0,
35
- name: 'Test Feed',
36
- pin_count: 0,
37
- created_by: mockUser,
38
- custom: {},
39
- };
40
-
41
- const mockFollow: FollowResponse = {
42
- created_at: new Date(),
43
- updated_at: new Date(),
44
- follower_role: 'user',
45
- push_preference: 'all',
46
- status: 'accepted',
47
- source_feed: {
48
- ...mockFeed,
49
- id: 'source-feed',
50
- fid: 'user:source-feed',
51
- created_by: mockUser,
52
- },
53
- target_feed: {
54
- ...mockFeed,
55
- id: 'target-feed',
56
- fid: 'user:target-feed',
57
- created_by: mockUser,
58
- },
59
- };
60
-
61
- describe('handleFollowCreated', () => {
62
- it('should return unchanged state for non-accepted follows', () => {
63
- const follow: FollowResponse = {
64
- ...mockFollow,
65
- status: 'pending',
66
- };
67
-
68
- // @ts-expect-error - we're not testing the full state here
69
- const currentState: FeedState = {
70
- followers: [],
71
- following: [],
72
- };
73
-
74
- const result = handleFollowCreated(
75
- follow,
76
- currentState,
77
- 'user:feed-1',
78
- 'user-1',
79
- );
80
-
81
- expect(result.changed).toBe(false);
82
- });
83
-
84
- it('should handle when this feed follows someone', () => {
85
- const follow: FollowResponse = {
86
- ...mockFollow,
87
- source_feed: {
88
- ...mockFeed,
89
- id: 'feed-x',
90
- fid: 'user:feed-x',
91
- created_by: {
92
- ...mockUser,
93
- id: 'user-x',
94
- },
95
- following_count: 1,
96
- },
97
- target_feed: {
98
- ...mockFeed,
99
- id: 'other-feed',
100
- fid: 'user:other-feed',
101
- created_by: mockUser,
102
- },
103
- };
104
-
105
- // @ts-expect-error - we're not testing the full state here
106
- const currentState: FeedState = {
107
- following: [],
108
- following_count: 0,
109
- };
110
-
111
- const result = handleFollowCreated(
112
- follow,
113
- currentState,
114
- 'user:feed-x',
115
- 'user-1',
116
- );
117
-
118
- expect(result.changed).toBe(true);
119
- expect(result.data.following).toHaveLength(1);
120
- expect(result.data.following?.[0]).toEqual(follow);
121
- expect(result.data).toMatchObject(follow.source_feed);
122
- expect(result.data.own_follows).toBeUndefined();
123
- expect(result.data.following_count).toEqual(1);
124
- });
125
-
126
- it('should handle when someone follows this feed', () => {
127
- const follow: FollowResponse = {
128
- ...mockFollow,
129
- source_feed: {
130
- ...mockFeed,
131
- id: 'other-feed',
132
- fid: 'user:other-feed',
133
- created_by: {
134
- ...mockUser,
135
- id: 'other-user',
136
- },
137
- },
138
- target_feed: {
139
- ...mockFeed,
140
- id: 'feed-1',
141
- fid: 'user:feed-1',
142
- created_by: mockUser,
143
- follower_count: 1,
144
- },
145
- };
146
-
147
- // @ts-expect-error - we're not testing the full state here
148
- const currentState: FeedState = {
149
- followers: [],
150
- follower_count: 0,
151
- };
152
-
153
- const result = handleFollowCreated(
154
- follow,
155
- currentState,
156
- 'user:feed-1',
157
- 'user-1',
158
- );
159
-
160
- expect(result.changed).toBe(true);
161
- expect(result.data.followers).toHaveLength(1);
162
- expect(result.data.followers?.[0]).toEqual(follow);
163
- expect(result.data).toMatchObject(follow.target_feed);
164
- expect(result.data.own_follows).toBeUndefined();
165
- expect(result.data.follower_count).toEqual(1);
166
- });
167
-
168
- it('should add to own_follows when connected user is the source', () => {
169
- const follow: FollowResponse = {
170
- ...mockFollow,
171
- source_feed: {
172
- ...mockFeed,
173
- id: 'feed-1',
174
- fid: 'user:feed-1',
175
- created_by: { ...mockUser, id: 'user-1' },
176
- },
177
- target_feed: {
178
- ...mockFeed,
179
- id: 'feed-x',
180
- fid: 'user:feed-x',
181
- created_by: {
182
- ...mockUser,
183
- id: 'user-x',
184
- },
185
- },
186
- };
187
-
188
- // @ts-expect-error - we're not testing the full state here
189
- const currentState: FeedState = {
190
- followers: [],
191
- own_follows: [],
192
- };
193
-
194
- const result = handleFollowCreated(
195
- follow,
196
- currentState,
197
- 'user:feed-x',
198
- 'user-1',
199
- );
200
-
201
- expect(result.changed).toBe(true);
202
- expect(result.data.own_follows).toHaveLength(1);
203
- expect(result.data.own_follows?.[0]).toEqual(follow);
204
- });
205
-
206
- it('should not update followers/following when they are undefined', () => {
207
- const follow: FollowResponse = {
208
- ...mockFollow,
209
- source_feed: {
210
- ...mockFeed,
211
- id: 'other-feed',
212
- fid: 'user:other-feed',
213
- created_by: mockUser,
214
- },
215
- target_feed: {
216
- ...mockFeed,
217
- id: 'feed-1',
218
- fid: 'user:feed-1',
219
- created_by: mockUser,
220
- },
221
- };
222
-
223
- // @ts-expect-error - we're not testing the full state here
224
- const currentState: FeedState = {
225
- followers: undefined,
226
- following: undefined,
227
- own_follows: undefined,
228
- };
229
-
230
- const result = handleFollowCreated(
231
- follow,
232
- currentState,
233
- 'user:feed-1',
234
- 'user-1',
235
- );
236
-
237
- expect(result.changed).toBe(true);
238
- expect(result.data.followers).toBeUndefined();
239
- expect(result.data).toMatchObject(follow.target_feed);
240
- });
241
-
242
- it('should add new followers to the top of existing arrays', () => {
243
- const existingFollow: FollowResponse = {
244
- ...mockFollow,
245
- source_feed: {
246
- ...mockFeed,
247
- id: 'existing-feed',
248
- fid: 'user:existing-feed',
249
- created_by: mockUser,
250
- },
251
- };
252
-
253
- const follow: FollowResponse = {
254
- ...mockFollow,
255
- source_feed: {
256
- ...mockFeed,
257
- id: 'other-feed',
258
- fid: 'user:other-feed',
259
- created_by: mockUser,
260
- },
261
- target_feed: {
262
- ...mockFeed,
263
- id: 'feed-1',
264
- fid: 'user:feed-1',
265
- created_by: mockUser,
266
- },
267
- };
268
-
269
- // @ts-expect-error - we're not testing the full state here
270
- const currentState: FeedState = {
271
- followers: [existingFollow],
272
- following: undefined,
273
- own_follows: undefined,
274
- };
275
-
276
- const result = handleFollowCreated(
277
- follow,
278
- currentState,
279
- 'user:feed-1',
280
- 'user-1',
281
- );
282
-
283
- expect(result.changed).toBe(true);
284
- expect(result.data.followers).toHaveLength(2);
285
- expect(result.data.followers?.[0]).toEqual(follow);
286
- expect(result.data.followers?.[1]).toEqual(existingFollow);
287
- });
288
- });
289
-
290
- describe('handleFollowDeleted', () => {
291
- it('should handle when this feed unfollows someone', () => {
292
- const existingFollow: FollowResponse = {
293
- ...mockFollow,
294
- source_feed: {
295
- ...mockFeed,
296
- id: 'feed-1',
297
- fid: 'user:feed-1',
298
- created_by: mockUser,
299
- },
300
- target_feed: {
301
- ...mockFeed,
302
- id: 'other-feed',
303
- fid: 'user:other-feed',
304
- created_by: mockUser,
305
- },
306
- };
307
-
308
- const follow: FollowResponse = existingFollow;
309
-
310
- // @ts-expect-error - we're not testing the full state here
311
- const currentState: FeedState = {
312
- following: [existingFollow],
313
- following_count: 1,
314
- };
315
-
316
- const result = handleFollowDeleted(
317
- follow,
318
- currentState,
319
- 'user:feed-1',
320
- 'user-1',
321
- );
322
-
323
- expect(result.changed).toBe(true);
324
- expect(result.data.following).toHaveLength(0);
325
- expect(result.data).toMatchObject(follow.source_feed);
326
- });
327
-
328
- it('should handle when someone unfollows this feed', () => {
329
- const existingFollow: FollowResponse = {
330
- ...mockFollow,
331
- source_feed: {
332
- ...mockFeed,
333
- id: 'other-feed',
334
- fid: 'user:other-feed',
335
- created_by: {
336
- ...mockUser,
337
- id: 'other-user',
338
- },
339
- },
340
- target_feed: {
341
- ...mockFeed,
342
- id: 'feed-1',
343
- fid: 'user:feed-1',
344
- created_by: mockUser,
345
- },
346
- };
347
-
348
- const follow: FollowResponse = existingFollow;
349
-
350
- // @ts-expect-error - we're not testing the full state here
351
- const currentState: FeedState = {
352
- followers: [existingFollow],
353
- own_follows: [existingFollow],
354
- following_count: 1,
355
- };
356
-
357
- const result = handleFollowDeleted(
358
- follow,
359
- currentState,
360
- 'user:feed-1',
361
- 'user-1',
362
- );
363
-
364
- expect(result.changed).toBe(true);
365
- expect(result.data.followers).toHaveLength(0);
366
- expect(result.data.own_follows).toEqual(currentState.own_follows);
367
- expect(result.data).toMatchObject(follow.target_feed);
368
- });
369
-
370
- it('should only remove own_follows when connected user is the source', () => {
371
- const existingFollow: FollowResponse = {
372
- ...mockFollow,
373
- source_feed: {
374
- ...mockFeed,
375
- id: 'other-feed',
376
- fid: 'user:other-feed',
377
- created_by: { ...mockUser, id: 'user-1' },
378
- },
379
- target_feed: {
380
- ...mockFeed,
381
- id: 'feed-1',
382
- fid: 'user:feed-1',
383
- created_by: mockUser,
384
- },
385
- };
386
-
387
- const follow: FollowResponse = existingFollow;
388
-
389
- // @ts-expect-error - we're not testing the full state here
390
- const currentState: FeedState = {
391
- followers: [existingFollow],
392
- own_follows: [existingFollow],
393
- following_count: 1,
394
- };
395
-
396
- const result = handleFollowDeleted(
397
- follow,
398
- currentState,
399
- 'user:feed-1',
400
- 'user-1',
401
- );
402
-
403
- expect(result.changed).toBe(true);
404
- expect(result.data.followers).toHaveLength(0);
405
- expect(result.data.own_follows).toHaveLength(0);
406
- });
407
-
408
- it('should not remove own_follows when connected user is not the source', () => {
409
- const existingFollow: FollowResponse = {
410
- ...mockFollow,
411
- source_feed: {
412
- ...mockFeed,
413
- id: 'other-feed',
414
- fid: 'user:other-feed',
415
- created_by: { ...mockUser, id: 'other-user' },
416
- },
417
- target_feed: {
418
- ...mockFeed,
419
- id: 'feed-1',
420
- fid: 'user:feed-1',
421
- created_by: mockUser,
422
- },
423
- };
424
-
425
- const follow: FollowResponse = existingFollow;
426
-
427
- // @ts-expect-error - we're not testing the full state here
428
- const currentState: FeedState = {
429
- followers: [existingFollow],
430
- own_follows: [existingFollow],
431
- };
432
-
433
- const result = handleFollowDeleted(
434
- follow,
435
- currentState,
436
- 'user:feed-1',
437
- 'user-1',
438
- );
439
-
440
- expect(result.changed).toBe(true);
441
- expect(result.data.followers).toHaveLength(0);
442
- expect(result.data.own_follows).toHaveLength(1); // Should remain unchanged
443
- });
444
-
445
- it('should not update followers/following when they are undefined in delete', () => {
446
- const existingFollow: FollowResponse = {
447
- ...mockFollow,
448
- source_feed: {
449
- ...mockFeed,
450
- id: 'other-feed',
451
- fid: 'user:other-feed',
452
- created_by: mockUser,
453
- },
454
- target_feed: {
455
- ...mockFeed,
456
- id: 'feed-1',
457
- fid: 'user:feed-1',
458
- created_by: mockUser,
459
- },
460
- };
461
-
462
- const follow: FollowResponse = existingFollow;
463
-
464
- // @ts-expect-error - we're not testing the full state here
465
- const currentState: FeedState = {
466
- followers: undefined,
467
- own_follows: undefined,
468
- };
469
-
470
- const result = handleFollowDeleted(
471
- follow,
472
- currentState,
473
- 'user:feed-1',
474
- 'user-1',
475
- );
476
-
477
- expect(result.changed).toBe(true);
478
- expect(result.data.followers).toBeUndefined();
479
- expect(result.data.own_follows).toBeUndefined();
480
- expect(result.data).toMatchObject(follow.target_feed);
481
- });
482
-
483
- it('should filter out the correct follow by target feed id', () => {
484
- const followToRemove: FollowResponse = {
485
- ...mockFollow,
486
- source_feed: {
487
- ...mockFeed,
488
- id: 'feed-1',
489
- fid: 'user:feed-1',
490
- created_by: mockUser,
491
- },
492
- target_feed: {
493
- ...mockFeed,
494
- id: 'target-to-remove',
495
- fid: 'user:target-to-remove',
496
- created_by: mockUser,
497
- },
498
- };
499
-
500
- const followToKeep: FollowResponse = {
501
- ...mockFollow,
502
- source_feed: {
503
- ...mockFeed,
504
- id: 'feed-1',
505
- fid: 'user:feed-1',
506
- created_by: mockUser,
507
- },
508
- target_feed: {
509
- ...mockFeed,
510
- id: 'target-to-keep',
511
- fid: 'user:target-to-keep',
512
- created_by: mockUser,
513
- },
514
- };
515
-
516
- const follow: FollowResponse = followToRemove;
517
-
518
- // @ts-expect-error - we're not testing the full state here
519
- const currentState: FeedState = {
520
- following: [followToRemove, followToKeep],
521
- following_count: 2,
522
- };
523
-
524
- const result = handleFollowDeleted(
525
- follow,
526
- currentState,
527
- 'user:feed-1',
528
- 'user-1',
529
- );
530
-
531
- expect(result.changed).toBe(true);
532
- expect(result.data.following).toHaveLength(1);
533
- expect(result.data.following?.[0]).toEqual(followToKeep);
534
- });
535
- });
536
-
537
- describe('handleFollowUpdated', () => {
538
- // TODO: not yet implemented
539
- it.skip('should return unchanged state (no-op)', () => {
540
- // @ts-expect-error - we're not testing the full state here
541
- const currentState: FeedState = {
542
- followers: [],
543
- following: [],
544
- following_count: 0,
545
- };
546
-
547
- const result = handleFollowUpdated(currentState);
548
-
549
- expect(result.changed).toBe(false);
550
- });
551
- });
552
- });