@stream-io/feeds-client 0.1.4 → 0.1.6

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 (62) hide show
  1. package/@react-bindings/hooks/client-state-hooks/index.ts +2 -0
  2. package/@react-bindings/hooks/feed-state-hooks/index.ts +7 -0
  3. package/@react-bindings/hooks/internal/index.ts +1 -0
  4. package/@react-bindings/hooks/util/index.ts +1 -0
  5. package/@react-bindings/index.ts +6 -3
  6. package/CHANGELOG.md +31 -0
  7. package/dist/@react-bindings/contexts/StreamFeedContext.d.ts +12 -0
  8. package/dist/@react-bindings/hooks/client-state-hooks/index.d.ts +2 -0
  9. package/dist/@react-bindings/hooks/client-state-hooks/useClientConnectedUser.d.ts +4 -0
  10. package/dist/@react-bindings/hooks/client-state-hooks/useWsConnectionState.d.ts +6 -0
  11. package/dist/@react-bindings/hooks/feed-state-hooks/index.d.ts +7 -0
  12. package/dist/@react-bindings/hooks/feed-state-hooks/useComments.d.ts +19 -0
  13. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedActivities.d.ts +11 -0
  14. package/dist/@react-bindings/hooks/feed-state-hooks/useFeedMetadata.d.ts +12 -0
  15. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowers.d.ts +16 -0
  16. package/dist/@react-bindings/hooks/feed-state-hooks/useFollowing.d.ts +16 -0
  17. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnCapabilities.d.ts +33 -0
  18. package/dist/@react-bindings/hooks/feed-state-hooks/useOwnFollows.d.ts +8 -0
  19. package/dist/@react-bindings/hooks/internal/index.d.ts +1 -0
  20. package/dist/@react-bindings/hooks/internal/useStableCallback.d.ts +25 -0
  21. package/dist/@react-bindings/hooks/util/index.d.ts +1 -0
  22. package/dist/@react-bindings/hooks/util/useReactionActions.d.ts +17 -0
  23. package/dist/@react-bindings/index.d.ts +5 -3
  24. package/dist/@react-bindings/wrappers/StreamFeed.d.ts +12 -0
  25. package/dist/index-react-bindings.browser.cjs +521 -210
  26. package/dist/index-react-bindings.browser.cjs.map +1 -1
  27. package/dist/index-react-bindings.browser.js +514 -212
  28. package/dist/index-react-bindings.browser.js.map +1 -1
  29. package/dist/index-react-bindings.node.cjs +521 -210
  30. package/dist/index-react-bindings.node.cjs.map +1 -1
  31. package/dist/index-react-bindings.node.js +514 -212
  32. package/dist/index-react-bindings.node.js.map +1 -1
  33. package/dist/index.browser.cjs +212 -106
  34. package/dist/index.browser.cjs.map +1 -1
  35. package/dist/index.browser.js +209 -107
  36. package/dist/index.browser.js.map +1 -1
  37. package/dist/index.node.cjs +212 -106
  38. package/dist/index.node.cjs.map +1 -1
  39. package/dist/index.node.js +209 -107
  40. package/dist/index.node.js.map +1 -1
  41. package/dist/src/Feed.d.ts +7 -3
  42. package/dist/src/FeedsClient.d.ts +6 -5
  43. package/dist/src/types.d.ts +7 -0
  44. package/dist/src/utils.d.ts +9 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +6 -2
  47. package/src/Feed.ts +214 -97
  48. package/src/FeedsClient.ts +22 -12
  49. package/src/common/ActivitySearchSource.ts +5 -5
  50. package/src/common/ApiClient.ts +1 -1
  51. package/src/common/FeedSearchSource.ts +1 -1
  52. package/src/common/Poll.ts +35 -10
  53. package/src/common/TokenManager.ts +2 -3
  54. package/src/common/UserSearchSource.ts +1 -1
  55. package/src/common/real-time/StableWSConnection.ts +4 -1
  56. package/src/state-updates/bookmark-utils.test.ts +134 -8
  57. package/src/state-updates/bookmark-utils.ts +17 -7
  58. package/src/types.ts +12 -1
  59. package/src/utils.ts +25 -1
  60. package/dist/@react-bindings/hooks/clientStateHooks.d.ts +0 -10
  61. package/dist/@react-bindings/hooks/useComments.d.ts +0 -12
  62. package/dist/@react-bindings/hooks/useOwnCapabilities.d.ts +0 -33
@@ -20,7 +20,7 @@ export class ActivitySearchSource extends BaseSearchSource<ActivityResponse> {
20
20
  }
21
21
 
22
22
  protected async query(searchQuery: string) {
23
- const { connectedUser } = this.client.state.getLatestValue();
23
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
24
24
  if (!connectedUser) return { items: [] };
25
25
 
26
26
  const { activities: items, next } = await this.client.queryActivities({
@@ -39,8 +39,8 @@ export class ActivitySearchSource extends BaseSearchSource<ActivityResponse> {
39
39
  }
40
40
 
41
41
 
42
- // filter: {
43
- // 'feed.name': { $autocomplete: searchQuery }
44
- // 'feed.description': { $autocomplete: searchQuery }
45
- // 'created_by.name': { $autocomplete: searchQuery }
42
+ // filter: {
43
+ // 'feed.name': { $autocomplete: searchQuery }
44
+ // 'feed.description': { $autocomplete: searchQuery }
45
+ // 'created_by.name': { $autocomplete: searchQuery }
46
46
  // },
@@ -21,7 +21,7 @@ export class ApiClient {
21
21
  private readonly connectionIdManager: ConnectionIdManager,
22
22
  options?: FeedsClientOptions,
23
23
  ) {
24
- this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
24
+ this.baseUrl = options?.base_url ?? 'https://feeds.stream-io-api.com';
25
25
  this.timeout = options?.timeout ?? 3000;
26
26
  this.axiosInstance = axios.create({
27
27
  baseURL: this.baseUrl,
@@ -20,7 +20,7 @@ export class FeedSearchSource extends BaseSearchSource<Feed> {
20
20
  }
21
21
 
22
22
  protected async query(searchQuery: string) {
23
- const { connectedUser } = this.client.state.getLatestValue();
23
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
24
24
  if (!connectedUser) return { items: [] };
25
25
 
26
26
  // const channelFilters: ChannelFilters = {
@@ -36,7 +36,10 @@ const isPollVoteRemovedEvent = (
36
36
 
37
37
  export const isVoteAnswer = (vote: PollVote) => !!vote?.answer_text;
38
38
 
39
- export type PollAnswersQueryParams = QueryPollVotesRequest & { poll_id: string; user_id?: string };
39
+ export type PollAnswersQueryParams = QueryPollVotesRequest & {
40
+ poll_id: string;
41
+ user_id?: string;
42
+ };
40
43
 
41
44
  type OptionId = string;
42
45
 
@@ -66,7 +69,9 @@ export class StreamPoll {
66
69
  );
67
70
  }
68
71
 
69
- private readonly getInitialStateFromPollResponse = (poll: PollInitOptions['poll']) => {
72
+ private readonly getInitialStateFromPollResponse = (
73
+ poll: PollInitOptions['poll'],
74
+ ) => {
70
75
  const { own_votes, id, ...pollResponseForState } = poll;
71
76
  const { ownAnswer, ownVotes } = own_votes?.reduce<{
72
77
  ownVotes: PollVote[];
@@ -126,7 +131,9 @@ export class StreamPoll {
126
131
  if (event.poll?.id && event.poll.id !== this.id) return;
127
132
  if (!isPollVoteCastedEvent(event as WSEvent)) return;
128
133
  const currentState = this.data;
129
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
134
+ const isOwnVote =
135
+ event.poll_vote.user_id ===
136
+ this.client.state.getLatestValue().connected_user?.id;
130
137
  let latestAnswers = [...currentState.latest_answers];
131
138
  let ownAnswer = currentState.own_answer;
132
139
  const ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -153,7 +160,12 @@ export class StreamPoll {
153
160
  );
154
161
  }
155
162
 
156
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
163
+ const {
164
+ answers_count,
165
+ latest_votes_by_option,
166
+ vote_count,
167
+ vote_counts_by_option,
168
+ } = event.poll;
157
169
  this.state.partialNext({
158
170
  answers_count,
159
171
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -173,7 +185,9 @@ export class StreamPoll {
173
185
  if (event.poll?.id && event.poll.id !== this.id) return;
174
186
  if (!isPollVoteChangedEvent(event as WSEvent)) return;
175
187
  const currentState = this.data;
176
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
188
+ const isOwnVote =
189
+ event.poll_vote.user_id ===
190
+ this.client.state.getLatestValue().connected_user?.id;
177
191
  let latestAnswers = [...currentState.latest_answers];
178
192
  let ownAnswer = currentState.own_answer;
179
193
  let ownVotesByOptionId = currentState.own_votes_by_option_id;
@@ -227,7 +241,12 @@ export class StreamPoll {
227
241
  );
228
242
  }
229
243
 
230
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
244
+ const {
245
+ answers_count,
246
+ latest_votes_by_option,
247
+ vote_count,
248
+ vote_counts_by_option,
249
+ } = event.poll;
231
250
  this.state.partialNext({
232
251
  answers_count,
233
252
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -237,7 +256,7 @@ export class StreamPoll {
237
256
  latest_answers: latestAnswers,
238
257
  last_activity_at: new Date(event.created_at),
239
258
  own_answer: ownAnswer,
240
- own_votes_by_option_id:ownVotesByOptionId,
259
+ own_votes_by_option_id: ownVotesByOptionId,
241
260
  max_voted_option_ids: maxVotedOptionIds,
242
261
  });
243
262
  };
@@ -246,7 +265,9 @@ export class StreamPoll {
246
265
  if (event.poll?.id && event.poll.id !== this.id) return;
247
266
  if (!isPollVoteRemovedEvent(event as WSEvent)) return;
248
267
  const currentState = this.data;
249
- const isOwnVote = event.poll_vote.user_id === this.client.state.getLatestValue().connectedUser?.id;
268
+ const isOwnVote =
269
+ event.poll_vote.user_id ===
270
+ this.client.state.getLatestValue().connected_user?.id;
250
271
  let latestAnswers = [...currentState.latest_answers];
251
272
  let ownAnswer = currentState.own_answer;
252
273
  const ownVotesByOptionId = { ...currentState.own_votes_by_option_id };
@@ -265,12 +286,16 @@ export class StreamPoll {
265
286
  event.poll.vote_counts_by_option,
266
287
  );
267
288
  if (isOwnVote && event.poll_vote.option_id) {
268
-
269
289
  delete ownVotesByOptionId[event.poll_vote.option_id];
270
290
  }
271
291
  }
272
292
 
273
- const { answers_count, latest_votes_by_option, vote_count, vote_counts_by_option } = event.poll;
293
+ const {
294
+ answers_count,
295
+ latest_votes_by_option,
296
+ vote_count,
297
+ vote_counts_by_option,
298
+ } = event.poll;
274
299
  this.state.partialNext({
275
300
  answers_count,
276
301
  // @ts-expect-error Incompatibility between PollResponseData and Poll due to teams_role, remove when OpenAPI spec is fixed
@@ -1,4 +1,4 @@
1
- import { isFunction, retryInterval, sleep } from './utils';
1
+ import { isFunction, sleep } from './utils';
2
2
 
3
3
  /**
4
4
  * TokenManager
@@ -67,12 +67,11 @@ export class TokenManager {
67
67
  this.token = await tokenProvider();
68
68
  } catch (e) {
69
69
  const numberOfFailures = ++previousFailuresCount;
70
- await sleep(retryInterval(numberOfFailures));
70
+ await sleep(1000);
71
71
  if (numberOfFailures === 3) {
72
72
  this.loadTokenPromise = null;
73
73
  return reject(
74
74
  new Error(
75
-
76
75
  `Stream error: tried to get token ${numberOfFailures} times, but it failed with ${e}. Check your token provider`,
77
76
  { cause: e },
78
77
  ),
@@ -20,7 +20,7 @@ export class UserSearchSource extends BaseSearchSource<UserResponse> {
20
20
  }
21
21
 
22
22
  protected async query(searchQuery: string) {
23
- const { connectedUser } = this.client.state.getLatestValue();
23
+ const { connected_user: connectedUser } = this.client.state.getLatestValue();
24
24
  if (!connectedUser) return { items: [] };
25
25
 
26
26
  // const channelFilters: ChannelFilters = {
@@ -487,7 +487,10 @@ export class StableWSConnection {
487
487
  onmessage = (wsID: number, event: MessageEvent) => {
488
488
  if (this.wsID !== wsID) return;
489
489
 
490
- this._log('onmessage() - onmessage callback', { event, wsID });
490
+ this._log('onmessage() - onmessage callback', {
491
+ event: { ...event, data: JSON.parse(event.data) },
492
+ wsID,
493
+ });
491
494
  let data = typeof event.data === 'string' ? JSON.parse(event.data) : null;
492
495
  this.decoders.forEach((decode) => {
493
496
  data = decode(data);
@@ -37,6 +37,7 @@ const createMockActivity = (id: string): ActivityResponse => ({
37
37
  visibility: 'public',
38
38
  bookmark_count: 0,
39
39
  comment_count: 0,
40
+ reaction_count: 0,
40
41
  share_count: 0,
41
42
  attachments: [],
42
43
  comments: [],
@@ -181,6 +182,71 @@ describe('bookmark-utils', () => {
181
182
  expect(result.own_bookmarks).toHaveLength(1);
182
183
  expect(result.own_bookmarks[0]).toEqual(bookmark2);
183
184
  });
185
+
186
+ it('should correctly identify bookmarks by activity_id + folder_id + user_id', () => {
187
+ const activity = createMockActivity('activity1');
188
+ const user = createMockUser('user1');
189
+
190
+ // Create two bookmarks with same activity and user but different folders
191
+ const bookmark1 = {
192
+ ...createMockBookmark(user, activity),
193
+ folder: {
194
+ id: 'folder1',
195
+ name: 'Folder 1',
196
+ created_at: new Date(),
197
+ updated_at: new Date(),
198
+ custom: {},
199
+ },
200
+ };
201
+ const bookmark2 = {
202
+ ...createMockBookmark(user, activity),
203
+ folder: {
204
+ id: 'folder2',
205
+ name: 'Folder 2',
206
+ created_at: new Date(),
207
+ updated_at: new Date(),
208
+ custom: {},
209
+ },
210
+ };
211
+
212
+ activity.own_bookmarks = [bookmark1, bookmark2];
213
+
214
+ // Try to remove bookmark1
215
+ const event = createMockDeletedEvent(bookmark1);
216
+ const result = removeBookmarkFromActivity(event, activity, true);
217
+
218
+ expect(result.changed).toBe(true);
219
+ expect(result.own_bookmarks).toHaveLength(1);
220
+ expect(result.own_bookmarks[0]).toEqual(bookmark2);
221
+ });
222
+
223
+ it('should handle bookmarks without folders correctly', () => {
224
+ const activity = createMockActivity('activity1');
225
+ const user = createMockUser('user1');
226
+
227
+ // Create two bookmarks: one with folder, one without
228
+ const bookmarkWithFolder = {
229
+ ...createMockBookmark(user, activity),
230
+ folder: {
231
+ id: 'folder1',
232
+ name: 'Folder 1',
233
+ created_at: new Date(),
234
+ updated_at: new Date(),
235
+ custom: {},
236
+ },
237
+ };
238
+ const bookmarkWithoutFolder = createMockBookmark(user, activity);
239
+
240
+ activity.own_bookmarks = [bookmarkWithFolder, bookmarkWithoutFolder];
241
+
242
+ // Try to remove bookmark without folder
243
+ const event = createMockDeletedEvent(bookmarkWithoutFolder);
244
+ const result = removeBookmarkFromActivity(event, activity, true);
245
+
246
+ expect(result.changed).toBe(true);
247
+ expect(result.own_bookmarks).toHaveLength(1);
248
+ expect(result.own_bookmarks[0]).toEqual(bookmarkWithFolder);
249
+ });
184
250
  });
185
251
 
186
252
  describe('updateBookmarkInActivity', () => {
@@ -220,20 +286,80 @@ describe('bookmark-utils', () => {
220
286
  expect(result.own_bookmarks[0]).toEqual(bookmark); // unchanged
221
287
  });
222
288
 
223
- it('should not update bookmark if it does not exist', () => {
289
+ // Test for the bug: updating bookmarks with same activity_id but different folder_id
290
+ it('should correctly update bookmark by activity_id + folder_id + user_id', () => {
224
291
  const activity = createMockActivity('activity1');
225
292
  const user = createMockUser('user1');
226
- const bookmark = createMockBookmark(user, activity);
227
- activity.own_bookmarks = [bookmark];
228
293
 
229
- const differentUser = createMockUser('user2');
230
- const differentBookmark = createMockBookmark(differentUser, activity);
231
- const event = createMockUpdatedEvent(differentBookmark);
294
+ // Create two bookmarks with same activity and user but different folders
295
+ const bookmark1 = {
296
+ ...createMockBookmark(user, activity),
297
+ folder: {
298
+ id: 'folder1',
299
+ name: 'Folder 1',
300
+ created_at: new Date(),
301
+ updated_at: new Date(),
302
+ custom: {},
303
+ },
304
+ };
305
+ const bookmark2 = {
306
+ ...createMockBookmark(user, activity),
307
+ folder: {
308
+ id: 'folder2',
309
+ name: 'Folder 2',
310
+ created_at: new Date(),
311
+ updated_at: new Date(),
312
+ custom: {},
313
+ },
314
+ };
315
+
316
+ activity.own_bookmarks = [bookmark1, bookmark2];
317
+
318
+ // Update bookmark1
319
+ const updatedBookmark1 = {
320
+ ...bookmark1,
321
+ custom: { updated: true },
322
+ };
323
+ const event = createMockUpdatedEvent(updatedBookmark1);
232
324
  const result = updateBookmarkInActivity(event, activity, true);
233
325
 
234
326
  expect(result.changed).toBe(true);
235
- expect(result.own_bookmarks).toHaveLength(1);
236
- expect(result.own_bookmarks[0]).toEqual(bookmark); // unchanged
327
+ expect(result.own_bookmarks).toHaveLength(2);
328
+ expect(result.own_bookmarks).toContain(updatedBookmark1);
329
+ expect(result.own_bookmarks).toContain(bookmark2);
330
+ });
331
+
332
+ it('should handle updating bookmarks without folders correctly', () => {
333
+ const activity = createMockActivity('activity1');
334
+ const user = createMockUser('user1');
335
+
336
+ // Create two bookmarks: one with folder, one without
337
+ const bookmarkWithFolder = {
338
+ ...createMockBookmark(user, activity),
339
+ folder: {
340
+ id: 'folder1',
341
+ name: 'Folder 1',
342
+ created_at: new Date(),
343
+ updated_at: new Date(),
344
+ custom: {},
345
+ },
346
+ };
347
+ const bookmarkWithoutFolder = createMockBookmark(user, activity);
348
+
349
+ activity.own_bookmarks = [bookmarkWithFolder, bookmarkWithoutFolder];
350
+
351
+ // Update bookmark without folder
352
+ const updatedBookmarkWithoutFolder = {
353
+ ...bookmarkWithoutFolder,
354
+ custom: { updated: true },
355
+ };
356
+ const event = createMockUpdatedEvent(updatedBookmarkWithoutFolder);
357
+ const result = updateBookmarkInActivity(event, activity, true);
358
+
359
+ expect(result.changed).toBe(true);
360
+ expect(result.own_bookmarks).toHaveLength(2);
361
+ expect(result.own_bookmarks).toContain(bookmarkWithFolder);
362
+ expect(result.own_bookmarks).toContain(updatedBookmarkWithoutFolder);
237
363
  });
238
364
  });
239
365
 
@@ -3,9 +3,23 @@ import {
3
3
  BookmarkDeletedEvent,
4
4
  BookmarkUpdatedEvent,
5
5
  ActivityResponse,
6
+ BookmarkResponse,
6
7
  } from '../gen/models';
7
8
  import { UpdateStateResult } from '../types-internal';
8
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
+
9
23
  const updateActivityInActivities = (
10
24
  updatedActivity: ActivityResponse,
11
25
  activities: ActivityResponse[],
@@ -46,9 +60,7 @@ export const removeBookmarkFromActivity = (
46
60
  // Update own_bookmarks if the bookmark is from the current user
47
61
  const ownBookmarks = isCurrentUser
48
62
  ? (activity.own_bookmarks || []).filter(
49
- (bookmark) =>
50
- bookmark.user.id !== event.bookmark.user.id ||
51
- bookmark.activity.id !== event.bookmark.activity.id,
63
+ (bookmark) => !isSameBookmark(bookmark, event.bookmark),
52
64
  )
53
65
  : activity.own_bookmarks;
54
66
 
@@ -67,10 +79,8 @@ export const updateBookmarkInActivity = (
67
79
  // Update own_bookmarks if the bookmark is from the current user
68
80
  let ownBookmarks = activity.own_bookmarks || [];
69
81
  if (isCurrentUser) {
70
- const bookmarkIndex = ownBookmarks.findIndex(
71
- (bookmark) =>
72
- bookmark.user.id === event.bookmark.user.id &&
73
- bookmark.activity.id === event.bookmark.activity.id,
82
+ const bookmarkIndex = ownBookmarks.findIndex((bookmark) =>
83
+ isSameBookmark(bookmark, event.bookmark),
74
84
  );
75
85
  if (bookmarkIndex !== -1) {
76
86
  ownBookmarks = [...ownBookmarks];
package/src/types.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import { ConnectionChangedEvent } from './common/real-time/event-models';
2
2
  import { NetworkChangedEvent } from './common/types';
3
- import { PagerResponse, WSEvent } from './gen/models';
3
+ import {
4
+ PagerResponse,
5
+ WSEvent,
6
+ } from './gen/models';
7
+ import type {
8
+ ActivityResponse,
9
+ CommentResponse,
10
+ } from './gen/models';
4
11
  import { FeedsClient } from './FeedsClient';
5
12
 
6
13
  export type FeedsEvent = WSEvent | ConnectionChangedEvent | NetworkChangedEvent;
@@ -22,3 +29,7 @@ export type LoadingStates = {
22
29
  export type TokenOrProvider = string | TokenProvider;
23
30
 
24
31
  export type TokenProvider = () => Promise<string>;
32
+
33
+ export type StreamFile = File | { name: string, uri: string, type: string }
34
+
35
+ export type CommentParent = ActivityResponse | CommentResponse;
package/src/utils.ts CHANGED
@@ -1,4 +1,28 @@
1
- export const isImageFile = (file: File) => {
1
+ import { CommentParent, StreamFile } from './types';
2
+ import type { CommentResponse } from './gen/models';
3
+
4
+ export const isImageFile = (file: StreamFile) => {
2
5
  // photoshop files begin with 'image/'
3
6
  return file.type.startsWith('image/') && !file.type.endsWith('.photoshop');
4
7
  };
8
+
9
+ export const isVideoFile = (file: StreamFile) => {
10
+ return file.type.startsWith('video/');
11
+ };
12
+
13
+ export const checkHasAnotherPage = <T extends unknown | undefined>(
14
+ v: T,
15
+ cursor: string | undefined,
16
+ ) =>
17
+ (typeof v === 'undefined' && typeof cursor === 'undefined') ||
18
+ typeof cursor === 'string';
19
+
20
+ export const isCommentResponse = (
21
+ entity: CommentParent,
22
+ ): entity is CommentResponse => {
23
+ return typeof (entity as CommentResponse)?.object_id === 'string';
24
+ };
25
+
26
+ export const Constants = {
27
+ DEFAULT_COMMENT_PAGINATION: 'first',
28
+ } as const;
@@ -1,10 +0,0 @@
1
- /**
2
- * A React hook that returns the currently connected user on a `FeedsClient` instance and null otherwise.
3
- */
4
- export declare const useClientConnectedUser: () => import("../..").OwnUser | undefined;
5
- /**
6
- * A React hook that returns the websocket connection state of `FeedsClient`.
7
- */
8
- export declare const useWsConnectionState: () => {
9
- isHealthy: boolean | undefined;
10
- };
@@ -1,12 +0,0 @@
1
- import type { ActivityResponse, CommentResponse } from '../../src/gen/models';
2
- import type { Feed } from '../../src/Feed';
3
- export declare const useComments: (feed: Feed,
4
- /**
5
- * The parent (activity or comment) for which to fetch comments.
6
- */
7
- parent: ActivityResponse | CommentResponse) => {
8
- comments: CommentResponse[];
9
- comment_pagination: (import("../../src/gen/models").PagerResponse & import("../..").LoadingStates & {
10
- sort?: string;
11
- }) | undefined;
12
- };
@@ -1,33 +0,0 @@
1
- import type { Feed } from '../../src/Feed';
2
- export declare const useOwnCapabilities: (feed: Feed | undefined) => {
3
- canAddActivity: boolean;
4
- canAddActivityReaction: boolean;
5
- canAddComment: boolean;
6
- canAddCommentReaction: boolean;
7
- canBookmarkActivity: boolean;
8
- canCreateFeed: boolean;
9
- canDeleteBookmark: boolean;
10
- canDeleteComment: boolean;
11
- canDeleteFeed: boolean;
12
- canEditBookmark: boolean;
13
- canFollow: boolean;
14
- canRemoveActivity: boolean;
15
- canRemoveActivityReaction: boolean;
16
- canRemoveCommentReaction: boolean;
17
- canUnfollow: boolean;
18
- canUpdateFeed: boolean;
19
- canInviteFeed: boolean;
20
- canJoinFeed: boolean;
21
- canLeaveFeed: boolean;
22
- canManageFeedGroup: boolean;
23
- canMarkActivity: boolean;
24
- canPinActivity: boolean;
25
- canQueryFeedMembers: boolean;
26
- canQueryFollows: boolean;
27
- canReadActivities: boolean;
28
- canReadFeed: boolean;
29
- canUpdateActivity: boolean;
30
- canUpdateComment: boolean;
31
- canUpdateFeedFollowers: boolean;
32
- canUpdateFeedMembers: boolean;
33
- };