@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
@@ -11,6 +11,7 @@ import {
11
11
  QueryFeedsRequest,
12
12
  QueryPollVotesRequest,
13
13
  SingleFollowRequest,
14
+ UpdateFollowRequest,
14
15
  UserRequest,
15
16
  WSEvent,
16
17
  } from './gen/models';
@@ -27,14 +28,19 @@ import {
27
28
  streamDevToken,
28
29
  } from './common/utils';
29
30
  import { decodeWSEvent } from './gen/model-decoders/event-decoder-mapping';
30
- import { Feed } from './Feed';
31
31
  import {
32
32
  FeedsClientOptions,
33
33
  NetworkChangedEvent,
34
34
  StreamResponse,
35
35
  } from './common/types';
36
- import { ModerationClient } from './ModerationClient';
36
+ import { ModerationClient } from './moderation-client';
37
37
  import { StreamPoll } from './common/Poll';
38
+ import {
39
+ Feed,
40
+ handleFollowCreated,
41
+ handleFollowDeleted,
42
+ handleFollowUpdated,
43
+ } from './feed';
38
44
 
39
45
  export type FeedsClientState = {
40
46
  connected_user: OwnUser | undefined;
@@ -363,6 +369,21 @@ export class FeedsClient extends FeedsApi {
363
369
  this.eventDispatcher.dispatch(networkEvent);
364
370
  };
365
371
 
372
+ async updateFollow(request: UpdateFollowRequest) {
373
+ const response = await super.updateFollow(request);
374
+
375
+ [response.follow.source_feed.fid, response.follow.target_feed.fid].forEach(
376
+ (fid) => {
377
+ const feed = this.activeFeeds[fid];
378
+ if (feed) {
379
+ handleFollowUpdated.bind(feed)(response);
380
+ }
381
+ },
382
+ );
383
+
384
+ return response;
385
+ }
386
+
366
387
  // For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
367
388
  async follow(request: SingleFollowRequest) {
368
389
  const response = await super.follow(request);
@@ -371,7 +392,7 @@ export class FeedsClient extends FeedsApi {
371
392
  (fid) => {
372
393
  const feed = this.activeFeeds[fid];
373
394
  if (feed) {
374
- feed.handleFollowCreated(response.follow);
395
+ handleFollowCreated.bind(feed)(response);
375
396
  }
376
397
  },
377
398
  );
@@ -385,7 +406,7 @@ export class FeedsClient extends FeedsApi {
385
406
  response.follows.forEach((follow) => {
386
407
  const feed = this.activeFeeds[follow.source_feed.fid];
387
408
  if (feed) {
388
- feed.handleFollowCreated(follow);
409
+ handleFollowCreated.bind(feed)({ follow });
389
410
  }
390
411
  });
391
412
 
@@ -398,10 +419,7 @@ export class FeedsClient extends FeedsApi {
398
419
  [request.source, request.target].forEach((fid) => {
399
420
  const feed = this.activeFeeds[fid];
400
421
  if (feed) {
401
- feed.handleFollowDeleted({
402
- source_feed: { fid: request.source },
403
- target_feed: { fid: request.target },
404
- });
422
+ handleFollowDeleted.bind(feed)(response);
405
423
  }
406
424
  });
407
425
 
@@ -1709,6 +1709,13 @@ decoders.ThreadedCommentResponse = (input?: Record<string, any>) => {
1709
1709
  return decode(typeMappings, input);
1710
1710
  };
1711
1711
 
1712
+ decoders.UnfollowResponse = (input?: Record<string, any>) => {
1713
+ const typeMappings: TypeMapping = {
1714
+ follow: { type: 'FollowResponse', isSingle: true },
1715
+ };
1716
+ return decode(typeMappings, input);
1717
+ };
1718
+
1712
1719
  decoders.UnpinActivityResponse = (input?: Record<string, any>) => {
1713
1720
  const typeMappings: TypeMapping = {
1714
1721
  activity: { type: 'ActivityResponse', isSingle: true },
@@ -4752,12 +4752,20 @@ export interface ReviewQueueItem {
4752
4752
 
4753
4753
  bans: Ban[];
4754
4754
 
4755
+ flag_labels: string[];
4756
+
4757
+ flag_types: string[];
4758
+
4755
4759
  flags: Flag[];
4756
4760
 
4757
4761
  languages: string[];
4758
4762
 
4763
+ reporter_ids: string[];
4764
+
4759
4765
  teams: string[];
4760
4766
 
4767
+ archived_at: NullTime;
4768
+
4761
4769
  completed_at: NullTime;
4762
4770
 
4763
4771
  reviewed_at: NullTime;
@@ -5348,6 +5356,8 @@ export interface UnblockUsersResponse {
5348
5356
 
5349
5357
  export interface UnfollowResponse {
5350
5358
  duration: string;
5359
+
5360
+ follow: FollowResponse;
5351
5361
  }
5352
5362
 
5353
5363
  export interface UnpinActivityResponse {
@@ -1,3 +1,3 @@
1
1
  export type { ApiClient } from './common/ApiClient';
2
2
  export type { StreamResponse } from './common/types';
3
- export { FeedsClient as FeedsApi } from './FeedsClient';
3
+ export { FeedsClient as FeedsApi } from './feeds-client';
@@ -0,0 +1 @@
1
+ export * from './response-generators';
@@ -0,0 +1,102 @@
1
+ import {
2
+ FeedResponse,
3
+ FollowResponse,
4
+ OwnUser,
5
+ OwnUserResponse,
6
+ UserResponse,
7
+ } from '../gen/models';
8
+ import { humanId } from 'human-id';
9
+
10
+ export const getHumanId = () => humanId({ capitalize: false, separator: '-' });
11
+
12
+ export const generateUserResponse = (
13
+ overrides: Partial<UserResponse> = {},
14
+ ): UserResponse => ({
15
+ id: `user-${getHumanId()}`,
16
+ created_at: new Date(),
17
+ updated_at: new Date(),
18
+ banned: false,
19
+ language: 'en',
20
+ online: false,
21
+ role: 'user',
22
+ blocked_user_ids: [],
23
+ teams: [],
24
+ custom: {},
25
+ ...overrides,
26
+ });
27
+
28
+ export const generateOwnUserResponse = (
29
+ overrides: Partial<OwnUserResponse> = {},
30
+ ): OwnUserResponse => ({
31
+ ...generateUserResponse({
32
+ id: `own-user-${getHumanId()}`,
33
+ }),
34
+ invisible: false,
35
+ total_unread_count: 0,
36
+ unread_channels: 0,
37
+ unread_count: 0,
38
+ unread_threads: 0,
39
+ channel_mutes: [],
40
+ devices: [],
41
+ mutes: [],
42
+ ...overrides,
43
+ });
44
+
45
+ export const generateOwnUser = (overrides: Partial<OwnUser> = {}): OwnUser => ({
46
+ ...generateOwnUserResponse(),
47
+ devices: [],
48
+ mutes: [],
49
+ total_unread_count_by_team: {},
50
+ ...overrides,
51
+ });
52
+
53
+ export const generateFeedResponse = (
54
+ overrides: Omit<Partial<FeedResponse>, 'created_by' | 'fid'> & {
55
+ created_by?: Partial<UserResponse>;
56
+ } = {},
57
+ ): FeedResponse => {
58
+ const id = overrides.id || `feed-${getHumanId()}`;
59
+ const groupId = overrides.group_id || 'user';
60
+ const fid = `${groupId}:${id}`;
61
+ const createdBy = generateUserResponse(overrides.created_by);
62
+ const description = humanId({
63
+ addAdverb: true,
64
+ adjectiveCount: 4,
65
+ });
66
+ const name = humanId();
67
+
68
+ return {
69
+ id,
70
+ group_id: groupId,
71
+ created_at: new Date(),
72
+ updated_at: new Date(),
73
+ description,
74
+ fid,
75
+ follower_count: 0,
76
+ following_count: 0,
77
+ member_count: 0,
78
+ name,
79
+ pin_count: 0,
80
+ custom: {},
81
+ ...overrides,
82
+ created_by: createdBy,
83
+ };
84
+ };
85
+
86
+ export const generateFollowResponse = (
87
+ overrides: Partial<FollowResponse> = {},
88
+ ): FollowResponse => {
89
+ const sourceFeedResponse = generateFeedResponse();
90
+ const targetFeedResponse = generateFeedResponse();
91
+
92
+ return {
93
+ created_at: new Date(),
94
+ updated_at: new Date(),
95
+ follower_role: 'user',
96
+ push_preference: 'all',
97
+ status: 'accepted',
98
+ source_feed: sourceFeedResponse,
99
+ target_feed: targetFeedResponse,
100
+ ...overrides,
101
+ };
102
+ };
@@ -1,5 +1,16 @@
1
+ import { WSEvent } from './gen/models';
2
+
1
3
  export type UpdateStateResult<T> = T & {
2
4
  changed: boolean;
3
5
  };
4
6
 
5
7
  export type FromArray<T> = T extends Array<infer L> ? L : never;
8
+
9
+ export type EventPayload<T extends WSEvent['type']> = Extract<
10
+ WSEvent,
11
+ { type: T }
12
+ >;
13
+
14
+ export type PartializeAllBut<T, K extends keyof T> = Pick<T, K> & {
15
+ [key in K]?: T[key];
16
+ };
package/src/types.ts CHANGED
@@ -8,7 +8,7 @@ import type {
8
8
  ActivityResponse,
9
9
  CommentResponse,
10
10
  } from './gen/models';
11
- import { FeedsClient } from './FeedsClient';
11
+ import { FeedsClient } from './feeds-client';
12
12
 
13
13
  export type FeedsEvent = WSEvent | ConnectionChangedEvent | NetworkChangedEvent;
14
14
  export type ActivityIdOrCommentId = string;
@@ -0,0 +1,6 @@
1
+ export const checkHasAnotherPage = <T extends unknown | undefined>(
2
+ v: T,
3
+ cursor: string | undefined,
4
+ ) =>
5
+ (typeof v === 'undefined' && typeof cursor === 'undefined') ||
6
+ typeof cursor === 'string';
@@ -0,0 +1,3 @@
1
+ export const Constants = {
2
+ DEFAULT_COMMENT_PAGINATION: 'first',
3
+ } as const;
@@ -0,0 +1,5 @@
1
+ export * from './check-has-another-page';
2
+ export * from './unique-array-merge';
3
+ export * from './constants';
4
+ export * from './type-assertions';
5
+ export * from './state-update-queue';
@@ -6,7 +6,7 @@ describe('state-update-queue', () => {
6
6
  describe('shouldUpdateState', () => {
7
7
  it('should return true when watch is false', () => {
8
8
  const result = shouldUpdateState({
9
- stateUpdateId: 'test-id',
9
+ stateUpdateQueueId: 'test-id',
10
10
  stateUpdateQueue: new Set(['other-id']),
11
11
  watch: false,
12
12
  });
@@ -14,11 +14,11 @@ describe('state-update-queue', () => {
14
14
  expect(result).toBe(true);
15
15
  });
16
16
 
17
- it('should return true when watch is true but stateUpdateId is not in queue', () => {
17
+ it('should return true when watch is true but queueId is not in queue', () => {
18
18
  const stateUpdateQueue = new Set(['other-id-1', 'other-id-2']);
19
19
 
20
20
  const result = shouldUpdateState({
21
- stateUpdateId: 'test-id',
21
+ stateUpdateQueueId: 'test-id',
22
22
  stateUpdateQueue: stateUpdateQueue,
23
23
  watch: true,
24
24
  });
@@ -27,11 +27,11 @@ describe('state-update-queue', () => {
27
27
  expect(result).toBe(true);
28
28
  });
29
29
 
30
- it('should return false and remove stateUpdateId from queue when watch is true and stateUpdateId is in queue', () => {
30
+ it('should return false and remove queueId from queue when watch is true and queueId is in queue', () => {
31
31
  const stateUpdateQueue = new Set(['test-id', 'other-id']);
32
32
 
33
33
  const result = shouldUpdateState({
34
- stateUpdateId: 'test-id',
34
+ stateUpdateQueueId: 'test-id',
35
35
  stateUpdateQueue,
36
36
  watch: true,
37
37
  });
@@ -42,7 +42,7 @@ describe('state-update-queue', () => {
42
42
 
43
43
  it('should handle empty queue when watch is true', () => {
44
44
  const result = shouldUpdateState({
45
- stateUpdateId: 'test-id',
45
+ stateUpdateQueueId: 'test-id',
46
46
  stateUpdateQueue: new Set(),
47
47
  watch: true,
48
48
  });
@@ -0,0 +1,42 @@
1
+ import { isFollowResponse } from './type-assertions';
2
+
3
+ export const shouldUpdateState = ({
4
+ stateUpdateQueueId,
5
+ stateUpdateQueue,
6
+ watch,
7
+ }: {
8
+ stateUpdateQueueId: string;
9
+ stateUpdateQueue: Set<string>;
10
+ watch: boolean;
11
+ }) => {
12
+ if (!watch) {
13
+ return true;
14
+ }
15
+
16
+ if (watch && stateUpdateQueue.has(stateUpdateQueueId)) {
17
+ stateUpdateQueue.delete(stateUpdateQueueId);
18
+ return false;
19
+ }
20
+
21
+ stateUpdateQueue.add(stateUpdateQueueId);
22
+ return true;
23
+ };
24
+
25
+ export function getStateUpdateQueueId(
26
+ data: object,
27
+ prefix?: 'deleted' | 'updated' | 'created' | (string & {}),
28
+ ) {
29
+ if (isFollowResponse(data)) {
30
+ const toJoin = [data.source_feed.fid, data.target_feed.fid];
31
+ if (prefix) {
32
+ toJoin.unshift(prefix);
33
+ }
34
+ return toJoin.join('-');
35
+ }
36
+ // else if (isMemberResponse(data)) {
37
+ // }
38
+
39
+ throw new Error(
40
+ `Cannot create state update queueId for data: ${JSON.stringify(data)}`,
41
+ );
42
+ }
@@ -0,0 +1,22 @@
1
+ import { CommentResponse, FollowResponse } from '../gen/models';
2
+ import { StreamFile } from '../types';
3
+ import { CommentParent } from '../types';
4
+
5
+ export const isFollowResponse = (data: object): data is FollowResponse => {
6
+ return 'source_feed' in data && 'target_feed' in data;
7
+ };
8
+
9
+ export const isCommentResponse = (
10
+ entity: CommentParent,
11
+ ): entity is CommentResponse => {
12
+ return typeof (entity as CommentResponse)?.object_id === 'string';
13
+ };
14
+
15
+ export const isImageFile = (file: StreamFile) => {
16
+ // photoshop files begin with 'image/'
17
+ return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
18
+ };
19
+
20
+ export const isVideoFile = (file: StreamFile) => {
21
+ return file.type.startsWith('video/');
22
+ };
@@ -1,9 +1,9 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
 
3
- import { uniqueArrayMerge } from './utils';
3
+ import { uniqueArrayMerge } from './unique-array-merge';
4
4
 
5
5
  describe('utils', () => {
6
- describe('uniqueMerge', () => {
6
+ describe(uniqueArrayMerge.name, () => {
7
7
  it('should merge arrays with unique objects based on key', () => {
8
8
  const existingArray = [
9
9
  { id: '1', name: 'Alice' },
@@ -123,7 +123,11 @@ describe('utils', () => {
123
123
  email: string;
124
124
  }) => item.email;
125
125
 
126
- const result = uniqueArrayMerge(existingArray, arrayToMerge, getKeyByEmail);
126
+ const result = uniqueArrayMerge(
127
+ existingArray,
128
+ arrayToMerge,
129
+ getKeyByEmail,
130
+ );
127
131
 
128
132
  expect(result).toEqual([
129
133
  { id: '1', name: 'Alice', email: 'alice@example.com' },
@@ -0,0 +1,19 @@
1
+ export const uniqueArrayMerge = <T>(
2
+ existingArray: T[],
3
+ arrayToMerge: T[],
4
+ getKey: (v: T) => string,
5
+ ) => {
6
+ const existing = new Set<string>();
7
+
8
+ existingArray.forEach((value) => {
9
+ const key = getKey(value);
10
+ existing.add(key);
11
+ });
12
+
13
+ const filteredArrayToMerge = arrayToMerge.filter((value) => {
14
+ const key = getKey(value);
15
+ return !existing.has(key);
16
+ });
17
+
18
+ return existingArray.concat(filteredArrayToMerge);
19
+ };
@@ -1,10 +0,0 @@
1
- import { ActivityReactionAddedEvent, ActivityReactionDeletedEvent, ActivityResponse } from '../gen/models';
2
- import { UpdateStateResult } from '../types-internal';
3
- export declare const addReactionToActivity: (event: ActivityReactionAddedEvent, activity: ActivityResponse, isCurrentUser: boolean) => UpdateStateResult<ActivityResponse>;
4
- export declare const removeReactionFromActivity: (event: ActivityReactionDeletedEvent, activity: ActivityResponse, isCurrentUser: boolean) => UpdateStateResult<ActivityResponse>;
5
- export declare const addReactionToActivities: (event: ActivityReactionAddedEvent, activities: ActivityResponse[] | undefined, isCurrentUser: boolean) => UpdateStateResult<{
6
- activities: ActivityResponse[];
7
- }>;
8
- export declare const removeReactionFromActivities: (event: ActivityReactionDeletedEvent, activities: ActivityResponse[] | undefined, isCurrentUser: boolean) => UpdateStateResult<{
9
- activities: ActivityResponse[];
10
- }>;
@@ -1,13 +0,0 @@
1
- import { ActivityResponse } from '../gen/models';
2
- import { UpdateStateResult } from '../types-internal';
3
- export declare const addActivitiesToState: (newActivities: ActivityResponse[], activities: ActivityResponse[] | undefined, position: "start" | "end") => UpdateStateResult<{
4
- activities: ActivityResponse[];
5
- }>;
6
- export declare const updateActivityInState: (updatedActivityResponse: ActivityResponse, activities: ActivityResponse[]) => {
7
- changed: boolean;
8
- activities: ActivityResponse[];
9
- };
10
- export declare const removeActivityFromState: (activityResponse: ActivityResponse, activities: ActivityResponse[]) => {
11
- changed: boolean;
12
- activities: ActivityResponse[];
13
- };
@@ -1,14 +0,0 @@
1
- import { BookmarkAddedEvent, BookmarkDeletedEvent, BookmarkUpdatedEvent, ActivityResponse } from '../gen/models';
2
- import { UpdateStateResult } from '../types-internal';
3
- export declare const addBookmarkToActivity: (event: BookmarkAddedEvent, activity: ActivityResponse, isCurrentUser: boolean) => UpdateStateResult<ActivityResponse>;
4
- export declare const removeBookmarkFromActivity: (event: BookmarkDeletedEvent, activity: ActivityResponse, isCurrentUser: boolean) => UpdateStateResult<ActivityResponse>;
5
- export declare const updateBookmarkInActivity: (event: BookmarkUpdatedEvent, activity: ActivityResponse, isCurrentUser: boolean) => UpdateStateResult<ActivityResponse>;
6
- export declare const addBookmarkToActivities: (event: BookmarkAddedEvent, activities: ActivityResponse[] | undefined, isCurrentUser: boolean) => UpdateStateResult<{
7
- activities: ActivityResponse[];
8
- }>;
9
- export declare const removeBookmarkFromActivities: (event: BookmarkDeletedEvent, activities: ActivityResponse[] | undefined, isCurrentUser: boolean) => UpdateStateResult<{
10
- activities: ActivityResponse[];
11
- }>;
12
- export declare const updateBookmarkInActivities: (event: BookmarkUpdatedEvent, activities: ActivityResponse[] | undefined, isCurrentUser: boolean) => UpdateStateResult<{
13
- activities: ActivityResponse[];
14
- }>;
@@ -1,19 +0,0 @@
1
- import { FeedState } from '../Feed';
2
- import { FollowResponse } from '../gen/models';
3
- import { UpdateStateResult } from '../types-internal';
4
- export declare const handleFollowCreated: (follow: FollowResponse, currentState: FeedState, currentFeedId: string, connectedUserId?: string) => UpdateStateResult<{
5
- data: FeedState;
6
- }>;
7
- export declare const handleFollowDeleted: (follow: FollowResponse | {
8
- source_feed: {
9
- fid: string;
10
- };
11
- target_feed: {
12
- fid: string;
13
- };
14
- }, currentState: FeedState, currentFeedId: string, connectedUserId?: string) => UpdateStateResult<{
15
- data: FeedState;
16
- }>;
17
- export declare const handleFollowUpdated: (currentState: FeedState) => UpdateStateResult<{
18
- data: FeedState;
19
- }>;
@@ -1,15 +0,0 @@
1
- import { FollowResponse } from '../gen/models';
2
- export declare const shouldUpdateState: ({ stateUpdateId, stateUpdateQueue, watch, }: {
3
- stateUpdateId: string;
4
- stateUpdateQueue: Set<string>;
5
- watch: boolean;
6
- }) => boolean;
7
- export declare const getStateUpdateQueueIdForFollow: (follow: FollowResponse) => string;
8
- export declare const getStateUpdateQueueIdForUnfollow: (follow: FollowResponse | {
9
- source_feed: {
10
- fid: string;
11
- };
12
- target_feed: {
13
- fid: string;
14
- };
15
- }) => string;
@@ -1,10 +0,0 @@
1
- import { CommentParent, StreamFile } from './types';
2
- import type { CommentResponse } from './gen/models';
3
- export declare const isImageFile: (file: StreamFile) => boolean;
4
- export declare const isVideoFile: (file: StreamFile) => boolean;
5
- export declare const checkHasAnotherPage: <T extends unknown | undefined>(v: T, cursor: string | undefined) => boolean;
6
- export declare const isCommentResponse: (entity: CommentParent) => entity is CommentResponse;
7
- export declare const Constants: {
8
- readonly DEFAULT_COMMENT_PAGINATION: "first";
9
- };
10
- export declare const uniqueArrayMerge: <T>(existingArray: T[], arrayToMerge: T[], getKey: (v: T) => string) => T[];
@@ -1,107 +0,0 @@
1
- import {
2
- ActivityReactionAddedEvent,
3
- ActivityReactionDeletedEvent,
4
- ActivityResponse,
5
- } from '../gen/models';
6
- import { UpdateStateResult } from '../types-internal';
7
-
8
- const updateActivityInActivities = (
9
- updatedActivity: ActivityResponse,
10
- activities: ActivityResponse[],
11
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
12
- const index = activities.findIndex((a) => a.id === updatedActivity.id);
13
- if (index !== -1) {
14
- const newActivities = [...activities];
15
- newActivities[index] = updatedActivity;
16
- return { changed: true, activities: newActivities };
17
- } else {
18
- return { changed: false, activities };
19
- }
20
- };
21
-
22
- export const addReactionToActivity = (
23
- event: ActivityReactionAddedEvent,
24
- activity: ActivityResponse,
25
- isCurrentUser: boolean,
26
- ): UpdateStateResult<ActivityResponse> => {
27
- // Update own_reactions if the reaction is from the current user
28
- const ownReactions = [...(activity.own_reactions || [])];
29
- if (isCurrentUser) {
30
- ownReactions.push(event.reaction);
31
- }
32
-
33
- return {
34
- ...activity,
35
- own_reactions: ownReactions,
36
- latest_reactions: event.activity.latest_reactions,
37
- reaction_groups: event.activity.reaction_groups,
38
- changed: true,
39
- };
40
- };
41
-
42
- export const removeReactionFromActivity = (
43
- event: ActivityReactionDeletedEvent,
44
- activity: ActivityResponse,
45
- isCurrentUser: boolean,
46
- ): UpdateStateResult<ActivityResponse> => {
47
- // Update own_reactions if the reaction is from the current user
48
- const ownReactions = isCurrentUser
49
- ? (activity.own_reactions || []).filter(
50
- (r) =>
51
- !(
52
- r.type === event.reaction.type &&
53
- r.user.id === event.reaction.user.id
54
- ),
55
- )
56
- : activity.own_reactions;
57
-
58
- return {
59
- ...activity,
60
- own_reactions: ownReactions,
61
- latest_reactions: event.activity.latest_reactions,
62
- reaction_groups: event.activity.reaction_groups,
63
- changed: true,
64
- };
65
- };
66
-
67
- export const addReactionToActivities = (
68
- event: ActivityReactionAddedEvent,
69
- activities: ActivityResponse[] | undefined,
70
- isCurrentUser: boolean,
71
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
72
- if (!activities) {
73
- return { changed: false, activities: [] };
74
- }
75
-
76
- const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
77
- if (activityIndex === -1) {
78
- return { changed: false, activities };
79
- }
80
-
81
- const activity = activities[activityIndex];
82
- const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
83
- return updateActivityInActivities(updatedActivity, activities);
84
- };
85
-
86
- export const removeReactionFromActivities = (
87
- event: ActivityReactionDeletedEvent,
88
- activities: ActivityResponse[] | undefined,
89
- isCurrentUser: boolean,
90
- ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
91
- if (!activities) {
92
- return { changed: false, activities: [] };
93
- }
94
-
95
- const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
96
- if (activityIndex === -1) {
97
- return { changed: false, activities };
98
- }
99
-
100
- const activity = activities[activityIndex];
101
- const updatedActivity = removeReactionFromActivity(
102
- event,
103
- activity,
104
- isCurrentUser,
105
- );
106
- return updateActivityInActivities(updatedActivity, activities);
107
- };