@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
package/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- export * from './src/FeedsClient';
2
- export * from './src/Feed';
1
+ export * from './src/feeds-client';
2
+ export * from './src/feed/feed';
3
3
  export * from './src/gen/models';
4
4
  export * from './src/types';
5
5
  export * from './src/common/types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/feeds-client",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "./dist/index.node.js",
6
6
  "exports": {
@@ -67,6 +67,7 @@
67
67
  "@types/react": "^19.1.8",
68
68
  "@vitest/coverage-v8": "3.2.4",
69
69
  "dotenv": "^16.4.5",
70
+ "human-id": "^4.1.1",
70
71
  "react": "19.0.0",
71
72
  "rimraf": "^6.0.1",
72
73
  "rollup": "^4.24.0",
@@ -1,18 +1,12 @@
1
1
  import { BaseSearchSource } from './BaseSearchSource';
2
2
  import type { SearchSourceOptions } from './BaseSearchSource';
3
3
 
4
- import { FeedsClient } from '../FeedsClient';
4
+ import { FeedsClient } from '../feeds-client';
5
5
  import { ActivityResponse } from '../gen/models';
6
6
 
7
7
  export class ActivitySearchSource extends BaseSearchSource<ActivityResponse> {
8
8
  readonly type = 'activity' as const;
9
9
  private readonly client: FeedsClient;
10
- // messageSearchChannelFilters: ChannelFilters | undefined;
11
- // messageSearchFilters: MessageFilters | undefined;
12
- // messageSearchSort: SearchMessageSort | undefined;
13
- // channelQueryFilters: ChannelFilters | undefined;
14
- // channelQuerySort: ChannelSort | undefined;
15
- // channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
16
10
 
17
11
  constructor(client: FeedsClient, options?: SearchSourceOptions) {
18
12
  super(options);
@@ -20,12 +14,15 @@ export class ActivitySearchSource extends BaseSearchSource<ActivityResponse> {
20
14
  }
21
15
 
22
16
  protected async query(searchQuery: string) {
23
- const { connected_user: connectedUser } = this.client.state.getLatestValue();
17
+ const { connected_user: connectedUser } =
18
+ this.client.state.getLatestValue();
24
19
  if (!connectedUser) return { items: [] };
25
20
 
26
21
  const { activities: items, next } = await this.client.queryActivities({
27
22
  sort: [{ direction: -1, field: 'created_at' }],
28
- filter: { text: { $autocomplete: searchQuery } },
23
+ ...(!this.allowEmptySearchString || searchQuery.length > 0
24
+ ? { filter: { text: { $autocomplete: searchQuery } } }
25
+ : {}),
29
26
  limit: 10,
30
27
  next: this.next ?? undefined,
31
28
  });
@@ -37,10 +34,3 @@ export class ActivitySearchSource extends BaseSearchSource<ActivityResponse> {
37
34
  return items;
38
35
  }
39
36
  }
40
-
41
-
42
- // filter: {
43
- // 'feed.name': { $autocomplete: searchQuery }
44
- // 'feed.description': { $autocomplete: searchQuery }
45
- // 'created_by.name': { $autocomplete: searchQuery }
46
- // },
@@ -1,12 +1,10 @@
1
1
  import { StateStore } from './StateStore';
2
2
  import { debounce, type DebouncedFunc } from './utils';
3
3
 
4
- export type SearchSourceType =
5
- | 'channels'
6
- | 'users'
7
- | 'messages'
8
- | (string & {});
4
+ export type SearchSourceType = 'activity' | 'user' | 'feed' | (string & {});
5
+
9
6
  export type QueryReturnValue<T> = { items: T[]; next?: string | null };
7
+
10
8
  export type DebounceOptions = {
11
9
  debounceMs: number;
12
10
  };
@@ -14,7 +12,6 @@ type DebouncedExecQueryFunction = DebouncedFunc<
14
12
  (searchString?: string) => Promise<void>
15
13
  >;
16
14
 
17
-
18
15
  export interface SearchSource<T = any> {
19
16
  activate(): void;
20
17
 
@@ -46,7 +43,6 @@ export interface SearchSource<T = any> {
46
43
  readonly type: SearchSourceType;
47
44
  }
48
45
 
49
-
50
46
  export type SearchSourceState<T = any> = {
51
47
  hasNext: boolean;
52
48
  isActive: boolean;
@@ -61,24 +57,28 @@ export type SearchSourceOptions = {
61
57
  /** The number of milliseconds to debounce the search query. The default interval is 300ms. */
62
58
  debounceMs?: number;
63
59
  pageSize?: number;
60
+ allowEmptySearchString?: boolean;
64
61
  };
65
62
  const DEFAULT_SEARCH_SOURCE_OPTIONS: Required<SearchSourceOptions> = {
66
63
  debounceMs: 300,
67
64
  pageSize: 10,
65
+ allowEmptySearchString: false,
68
66
  } as const;
69
67
 
70
68
  export abstract class BaseSearchSource<T> implements SearchSource<T> {
71
69
  state: StateStore<SearchSourceState<T>>;
72
70
  protected pageSize: number;
71
+ protected allowEmptySearchString: boolean;
73
72
  abstract readonly type: SearchSourceType;
74
73
  protected searchDebounced!: DebouncedExecQueryFunction;
75
74
 
76
75
  protected constructor(options?: SearchSourceOptions) {
77
- const { debounceMs, pageSize } = {
76
+ const { debounceMs, pageSize, allowEmptySearchString } = {
78
77
  ...DEFAULT_SEARCH_SOURCE_OPTIONS,
79
78
  ...options,
80
79
  };
81
80
  this.pageSize = pageSize;
81
+ this.allowEmptySearchString = allowEmptySearchString;
82
82
  this.state = new StateStore<SearchSourceState<T>>(this.initialState);
83
83
  this.setDebounceOptions({ debounceMs });
84
84
  }
@@ -157,7 +157,7 @@ export abstract class BaseSearchSource<T> implements SearchSource<T> {
157
157
  this.isActive &&
158
158
  !this.isLoading &&
159
159
  (this.hasNext || hasNewSearchQuery) &&
160
- searchString
160
+ (this.allowEmptySearchString || searchString)
161
161
  );
162
162
  };
163
163
 
@@ -1,88 +1,43 @@
1
1
  import { BaseSearchSource } from './BaseSearchSource';
2
2
  import type { SearchSourceOptions } from './BaseSearchSource';
3
3
 
4
- import { FeedsClient } from '../FeedsClient';
5
- import { Feed } from '../Feed';
4
+ import { FeedsClient } from '../feeds-client';
5
+ import { Feed } from '../feed';
6
+
7
+ export type FeedSearchSourceOptions = SearchSourceOptions & {
8
+ groupId?: string;
9
+ };
6
10
 
7
11
  export class FeedSearchSource extends BaseSearchSource<Feed> {
8
12
  readonly type = 'feed' as const;
9
13
  private readonly client: FeedsClient;
10
- // messageSearchChannelFilters: ChannelFilters | undefined;
11
- // messageSearchFilters: MessageFilters | undefined;
12
- // messageSearchSort: SearchMessageSort | undefined;
13
- // channelQueryFilters: ChannelFilters | undefined;
14
- // channelQuerySort: ChannelSort | undefined;
15
- // channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
14
+ private readonly feedGroupId?: string | undefined;
16
15
 
17
- constructor(client: FeedsClient, options?: SearchSourceOptions) {
16
+ constructor(client: FeedsClient, options?: FeedSearchSourceOptions) {
18
17
  super(options);
19
18
  this.client = client;
19
+ this.feedGroupId = options?.groupId;
20
20
  }
21
21
 
22
22
  protected async query(searchQuery: string) {
23
- const { connected_user: connectedUser } = this.client.state.getLatestValue();
23
+ const { connected_user: connectedUser } =
24
+ this.client.state.getLatestValue();
24
25
  if (!connectedUser) return { items: [] };
25
26
 
26
- // const channelFilters: ChannelFilters = {
27
- // members: { $in: [this.client.userID] },
28
- // ...this.messageSearchChannelFilters,
29
- // } as ChannelFilters;
30
-
31
- // const messageFilters: MessageFilters = {
32
- // text: searchQuery,
33
- // type: 'regular', // FIXME: type: 'reply' resp. do not filter by type and allow to jump to a message in a thread - missing support
34
- // ...this.messageSearchFilters,
35
- // } as MessageFilters;
36
-
37
- // const sort: SearchMessageSort = {
38
- // created_at: -1,
39
- // ...this.messageSearchSort,
40
- // };
41
-
42
- // const options = {
43
- // limit: this.pageSize,
44
- // next: this.next,
45
- // sort,
46
- // } as SearchOptions;
47
-
48
- // const { next, results } = await this.client.search(
49
- // channelFilters,
50
- // messageFilters,
51
- // options,
52
- // );
53
- // const items = results.map(({ message }) => message);
54
-
55
- // const cids = Array.from(
56
- // items.reduce((acc, message) => {
57
- // if (message.cid && !this.client.activeChannels[message.cid])
58
- // acc.add(message.cid);
59
- // return acc;
60
- // }, new Set<string>()), // keep the cids unique
61
- // );
62
- // const allChannelsLoadedLocally = cids.length === 0;
63
- // if (!allChannelsLoadedLocally) {
64
- // await this.client.queryChannels(
65
- // {
66
- // cid: { $in: cids },
67
- // ...this.channelQueryFilters,
68
- // } as ChannelFilters,
69
- // {
70
- // last_message_at: -1,
71
- // ...this.channelQuerySort,
72
- // },
73
- // this.channelQueryOptions,
74
- // );
75
- // }
76
-
77
27
  const { feeds: items, next } = await this.client.queryFeeds({
78
28
  filter: {
79
- group_id: 'user',
80
- $or: [
81
- { name: { $autocomplete: searchQuery } },
82
- { description: { $autocomplete: searchQuery } },
83
- { 'created_by.name': { $autocomplete: searchQuery } },
84
- ],
29
+ ...(this.feedGroupId ? { group_id: this.feedGroupId } : {}),
30
+ ...(!this.allowEmptySearchString || searchQuery.length > 0
31
+ ? {
32
+ $or: [
33
+ { name: { $autocomplete: searchQuery } },
34
+ { description: { $autocomplete: searchQuery } },
35
+ { 'created_by.name': { $autocomplete: searchQuery } },
36
+ ],
37
+ }
38
+ : {}),
85
39
  },
40
+ next: this.next ?? undefined,
86
41
  });
87
42
 
88
43
  return { items, next };
@@ -1,5 +1,5 @@
1
1
  import { StateStore } from './StateStore';
2
- import type { FeedsClient } from '../FeedsClient';
2
+ import type { FeedsClient } from '../feeds-client';
3
3
  import type {
4
4
  PollVote,
5
5
  QueryPollVotesRequest,
@@ -23,6 +23,8 @@ export class SearchController {
23
23
  /**
24
24
  * Not intended for direct use by integrators, might be removed without notice resulting in
25
25
  * broken integrations.
26
+ *
27
+ * @internal
26
28
  */
27
29
  _internalState: StateStore<InternalSearchControllerState>;
28
30
  state: StateStore<SearchControllerState>;
@@ -1,18 +1,12 @@
1
1
  import { BaseSearchSource } from './BaseSearchSource';
2
2
  import type { SearchSourceOptions } from './BaseSearchSource';
3
3
 
4
- import { FeedsClient } from '../FeedsClient';
4
+ import { FeedsClient } from '../feeds-client';
5
5
  import { UserResponse } from '../gen/models';
6
6
 
7
7
  export class UserSearchSource extends BaseSearchSource<UserResponse> {
8
8
  readonly type = 'user' as const;
9
9
  private readonly client: FeedsClient;
10
- // messageSearchChannelFilters: ChannelFilters | undefined;
11
- // messageSearchFilters: MessageFilters | undefined;
12
- // messageSearchSort: SearchMessageSort | undefined;
13
- // channelQueryFilters: ChannelFilters | undefined;
14
- // channelQuerySort: ChannelSort | undefined;
15
- // channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
16
10
 
17
11
  constructor(client: FeedsClient, options?: SearchSourceOptions) {
18
12
  super(options);
@@ -20,66 +14,20 @@ export class UserSearchSource extends BaseSearchSource<UserResponse> {
20
14
  }
21
15
 
22
16
  protected async query(searchQuery: string) {
23
- const { connected_user: connectedUser } = this.client.state.getLatestValue();
17
+ const { connected_user: connectedUser } =
18
+ this.client.state.getLatestValue();
24
19
  if (!connectedUser) return { items: [] };
25
20
 
26
- // const channelFilters: ChannelFilters = {
27
- // members: { $in: [this.client.userID] },
28
- // ...this.messageSearchChannelFilters,
29
- // } as ChannelFilters;
30
-
31
- // const messageFilters: MessageFilters = {
32
- // text: searchQuery,
33
- // type: 'regular', // FIXME: type: 'reply' resp. do not filter by type and allow to jump to a message in a thread - missing support
34
- // ...this.messageSearchFilters,
35
- // } as MessageFilters;
36
-
37
- // const sort: SearchMessageSort = {
38
- // created_at: -1,
39
- // ...this.messageSearchSort,
40
- // };
41
-
42
- // const options = {
43
- // limit: this.pageSize,
44
- // next: this.next,
45
- // sort,
46
- // } as SearchOptions;
47
-
48
- // const { next, results } = await this.client.search(
49
- // channelFilters,
50
- // messageFilters,
51
- // options,
52
- // );
53
- // const items = results.map(({ message }) => message);
54
-
55
- // const cids = Array.from(
56
- // items.reduce((acc, message) => {
57
- // if (message.cid && !this.client.activeChannels[message.cid])
58
- // acc.add(message.cid);
59
- // return acc;
60
- // }, new Set<string>()), // keep the cids unique
61
- // );
62
- // const allChannelsLoadedLocally = cids.length === 0;
63
- // if (!allChannelsLoadedLocally) {
64
- // await this.client.queryChannels(
65
- // {
66
- // cid: { $in: cids },
67
- // ...this.channelQueryFilters,
68
- // } as ChannelFilters,
69
- // {
70
- // last_message_at: -1,
71
- // ...this.channelQuerySort,
72
- // },
73
- // this.channelQueryOptions,
74
- // );
75
- // }
76
-
77
21
  const { users: items } = await this.client.queryUsers({
78
22
  payload: {
79
23
  filter_conditions: {
80
- name: {
81
- $autocomplete: searchQuery,
82
- },
24
+ ...(!this.allowEmptySearchString || searchQuery.length > 0
25
+ ? {
26
+ name: {
27
+ $autocomplete: searchQuery,
28
+ },
29
+ }
30
+ : {}),
83
31
  },
84
32
  },
85
33
  });
@@ -4,13 +4,13 @@ import {
4
4
  ActivityReactionDeletedEvent,
5
5
  ActivityResponse,
6
6
  FeedsReactionResponse,
7
- } from '../gen/models';
7
+ } from '../../../gen/models';
8
8
  import {
9
9
  addReactionToActivity,
10
10
  removeReactionFromActivity,
11
11
  addReactionToActivities,
12
12
  removeReactionFromActivities,
13
- } from './activity-reaction-utils';
13
+ } from './';
14
14
 
15
15
  const createMockActivity = (id: string): ActivityResponse => ({
16
16
  id,
@@ -109,6 +109,7 @@ describe('activity-reaction-utils', () => {
109
109
  count: 1,
110
110
  first_reaction_at: reaction.created_at,
111
111
  last_reaction_at: reaction.created_at,
112
+ sum_scores: 0,
112
113
  },
113
114
  };
114
115
 
@@ -123,6 +124,7 @@ describe('activity-reaction-utils', () => {
123
124
  count: 1,
124
125
  first_reaction_at: reaction.created_at,
125
126
  last_reaction_at: reaction.created_at,
127
+ sum_scores: 0,
126
128
  });
127
129
  });
128
130
 
@@ -136,6 +138,7 @@ describe('activity-reaction-utils', () => {
136
138
  count: 1,
137
139
  first_reaction_at: reaction.created_at,
138
140
  last_reaction_at: reaction.created_at,
141
+ sum_scores: 0,
139
142
  },
140
143
  };
141
144
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -150,6 +153,7 @@ describe('activity-reaction-utils', () => {
150
153
  count: 1,
151
154
  first_reaction_at: reaction.created_at,
152
155
  last_reaction_at: reaction.created_at,
156
+ sum_scores: 0,
153
157
  });
154
158
  });
155
159
  });
@@ -165,6 +169,7 @@ describe('activity-reaction-utils', () => {
165
169
  count: 1,
166
170
  first_reaction_at: reaction.created_at,
167
171
  last_reaction_at: reaction.created_at,
172
+ sum_scores: 0,
168
173
  },
169
174
  };
170
175
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -196,6 +201,7 @@ describe('activity-reaction-utils', () => {
196
201
  count: 1,
197
202
  first_reaction_at: reaction.created_at,
198
203
  last_reaction_at: reaction.created_at,
204
+ sum_scores: 0,
199
205
  },
200
206
  };
201
207
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -230,6 +236,7 @@ describe('activity-reaction-utils', () => {
230
236
  count: 1,
231
237
  first_reaction_at: reaction.created_at,
232
238
  last_reaction_at: reaction.created_at,
239
+ sum_scores: 0,
233
240
  },
234
241
  };
235
242
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -253,6 +260,7 @@ describe('activity-reaction-utils', () => {
253
260
  count: 1,
254
261
  first_reaction_at: reaction.created_at,
255
262
  last_reaction_at: reaction.created_at,
263
+ sum_scores: 0,
256
264
  },
257
265
  };
258
266
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -274,6 +282,7 @@ describe('activity-reaction-utils', () => {
274
282
  count: 1,
275
283
  first_reaction_at: reaction.created_at,
276
284
  last_reaction_at: reaction.created_at,
285
+ sum_scores: 0,
277
286
  },
278
287
  };
279
288
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -296,6 +305,7 @@ describe('activity-reaction-utils', () => {
296
305
  count: 1,
297
306
  first_reaction_at: reaction.created_at,
298
307
  last_reaction_at: reaction.created_at,
308
+ sum_scores: 0,
299
309
  },
300
310
  };
301
311
  const event = createMockAddedEvent(reaction, eventActivity);
@@ -1,10 +1,10 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { ActivityResponse, FeedsReactionResponse } from '../gen/models';
2
+ import { ActivityResponse, FeedsReactionResponse } from '../../../gen/models';
3
3
  import {
4
4
  addActivitiesToState,
5
5
  updateActivityInState,
6
6
  removeActivityFromState,
7
- } from './activity-utils';
7
+ } from './';
8
8
 
9
9
  const createMockActivity = (id: string, text?: string): ActivityResponse =>
10
10
  ({
@@ -181,6 +181,7 @@ describe('activity-utils', () => {
181
181
  ];
182
182
  originalActivity.reaction_groups = {
183
183
  like: {
184
+ sum_scores: 0,
184
185
  count: 1,
185
186
  first_reaction_at: new Date(),
186
187
  last_reaction_at: new Date(),
@@ -1,5 +1,6 @@
1
- import { ActivityResponse } from '../gen/models';
2
- import { UpdateStateResult } from '../types-internal';
1
+ import { Feed } from '../../../feed';
2
+ import { ActivityResponse } from '../../../gen/models';
3
+ import { EventPayload, UpdateStateResult } from '../../../types-internal';
3
4
 
4
5
  export const addActivitiesToState = (
5
6
  newActivities: ActivityResponse[],
@@ -42,39 +43,18 @@ export const addActivitiesToState = (
42
43
  return result;
43
44
  };
44
45
 
45
- export const updateActivityInState = (
46
- updatedActivityResponse: ActivityResponse,
47
- activities: ActivityResponse[],
48
- ) => {
49
- const index = activities.findIndex(
50
- (a) => a.id === updatedActivityResponse.id,
46
+ export function handleActivityAdded(
47
+ this: Feed,
48
+ event: EventPayload<'feeds.activity.added'>,
49
+ ) {
50
+ const currentActivities = this.currentState.activities;
51
+ const result = addActivitiesToState(
52
+ [event.activity],
53
+ currentActivities,
54
+ 'start',
51
55
  );
52
- if (index !== -1) {
53
- const newActivities = [...activities];
54
- const activity = activities[index];
55
- newActivities[index] = {
56
- ...updatedActivityResponse,
57
- own_reactions: activity.own_reactions,
58
- own_bookmarks: activity.own_bookmarks,
59
- latest_reactions: activity.latest_reactions,
60
- reaction_groups: activity.reaction_groups,
61
- };
62
- return { changed: true, activities: newActivities };
63
- } else {
64
- return { changed: false, activities };
56
+ if (result.changed) {
57
+ this.client.hydratePollCache([event.activity]);
58
+ this.state.partialNext({ activities: result.activities });
65
59
  }
66
- };
67
-
68
- export const removeActivityFromState = (
69
- activityResponse: ActivityResponse,
70
- activities: ActivityResponse[],
71
- ) => {
72
- const index = activities.findIndex((a) => a.id === activityResponse.id);
73
- if (index !== -1) {
74
- const newActivities = [...activities];
75
- newActivities.splice(index, 1);
76
- return { changed: true, activities: newActivities };
77
- } else {
78
- return { changed: false, activities };
79
- }
80
- };
60
+ }
@@ -0,0 +1,30 @@
1
+ import type { Feed } from '../../../feed';
2
+ import type { ActivityResponse } from '../../../gen/models';
3
+ import type { EventPayload } from '../../../types-internal';
4
+
5
+ export const removeActivityFromState = (
6
+ activityResponse: ActivityResponse,
7
+ activities: ActivityResponse[],
8
+ ) => {
9
+ const index = activities.findIndex((a) => a.id === activityResponse.id);
10
+ if (index !== -1) {
11
+ const newActivities = [...activities];
12
+ newActivities.splice(index, 1);
13
+ return { changed: true, activities: newActivities };
14
+ } else {
15
+ return { changed: false, activities };
16
+ }
17
+ };
18
+
19
+ export function handleActivityDeleted(
20
+ this: Feed,
21
+ event: EventPayload<'feeds.activity.deleted'>,
22
+ ) {
23
+ const currentActivities = this.currentState.activities;
24
+ if (currentActivities) {
25
+ const result = removeActivityFromState(event.activity, currentActivities);
26
+ if (result.changed) {
27
+ this.state.partialNext({ activities: result.activities });
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,67 @@
1
+ import type { Feed } from '../../../feed';
2
+ import type {
3
+ ActivityReactionAddedEvent,
4
+ ActivityResponse,
5
+ } from '../../../gen/models';
6
+ import type { EventPayload, UpdateStateResult } from '../../../types-internal';
7
+
8
+ import { updateActivityInState } from './handle-activity-updated';
9
+
10
+ export const addReactionToActivity = (
11
+ event: ActivityReactionAddedEvent,
12
+ activity: ActivityResponse,
13
+ isCurrentUser: boolean,
14
+ ): UpdateStateResult<ActivityResponse> => {
15
+ // Update own_reactions if the reaction is from the current user
16
+ const ownReactions = [...(activity.own_reactions || [])];
17
+ if (isCurrentUser) {
18
+ ownReactions.push(event.reaction);
19
+ }
20
+
21
+ return {
22
+ ...activity,
23
+ own_reactions: ownReactions,
24
+ latest_reactions: event.activity.latest_reactions,
25
+ reaction_groups: event.activity.reaction_groups,
26
+ changed: true,
27
+ };
28
+ };
29
+
30
+ export const addReactionToActivities = (
31
+ event: ActivityReactionAddedEvent,
32
+ activities: ActivityResponse[] | undefined,
33
+ isCurrentUser: boolean,
34
+ ): UpdateStateResult<{ activities: ActivityResponse[] }> => {
35
+ if (!activities) {
36
+ return { changed: false, activities: [] };
37
+ }
38
+
39
+ const activityIndex = activities.findIndex((a) => a.id === event.activity.id);
40
+ if (activityIndex === -1) {
41
+ return { changed: false, activities };
42
+ }
43
+
44
+ const activity = activities[activityIndex];
45
+ const updatedActivity = addReactionToActivity(event, activity, isCurrentUser);
46
+ return updateActivityInState(updatedActivity, activities, true);
47
+ };
48
+
49
+ export function handleActivityReactionAdded(
50
+ this: Feed,
51
+ event: EventPayload<'feeds.activity.reaction.added'>,
52
+ ) {
53
+ const currentActivities = this.currentState.activities;
54
+ const connectedUser = this.client.state.getLatestValue().connected_user;
55
+ const isCurrentUser = Boolean(
56
+ connectedUser && event.reaction.user.id === connectedUser.id,
57
+ );
58
+
59
+ const result = addReactionToActivities(
60
+ event,
61
+ currentActivities,
62
+ isCurrentUser,
63
+ );
64
+ if (result.changed) {
65
+ this.state.partialNext({ activities: result.activities });
66
+ }
67
+ }