@stream-io/feeds-client 0.1.11 → 0.2.1

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 (87) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/index-react-bindings.browser.cjs +537 -331
  3. package/dist/index-react-bindings.browser.cjs.map +1 -1
  4. package/dist/index-react-bindings.browser.js +537 -331
  5. package/dist/index-react-bindings.browser.js.map +1 -1
  6. package/dist/index-react-bindings.node.cjs +537 -331
  7. package/dist/index-react-bindings.node.cjs.map +1 -1
  8. package/dist/index-react-bindings.node.js +537 -331
  9. package/dist/index-react-bindings.node.js.map +1 -1
  10. package/dist/index.browser.cjs +536 -329
  11. package/dist/index.browser.cjs.map +1 -1
  12. package/dist/index.browser.js +536 -330
  13. package/dist/index.browser.js.map +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.node.cjs +536 -329
  16. package/dist/index.node.cjs.map +1 -1
  17. package/dist/index.node.js +536 -330
  18. package/dist/index.node.js.map +1 -1
  19. package/dist/src/feed/event-handlers/activity/handle-activity-deleted.d.ts +12 -3
  20. package/dist/src/feed/event-handlers/activity/handle-activity-pinned.d.ts +3 -0
  21. package/dist/src/feed/event-handlers/activity/handle-activity-reaction-added.d.ts +10 -6
  22. package/dist/src/feed/event-handlers/activity/handle-activity-reaction-deleted.d.ts +10 -6
  23. package/dist/src/feed/event-handlers/activity/handle-activity-unpinned.d.ts +3 -0
  24. package/dist/src/feed/event-handlers/activity/handle-activity-updated.d.ts +7 -3
  25. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-added.d.ts +10 -6
  26. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts +10 -6
  27. package/dist/src/feed/event-handlers/bookmark/handle-bookmark-updated.d.ts +10 -6
  28. package/dist/src/feed/event-handlers/index.d.ts +1 -0
  29. package/dist/src/feed/event-handlers/watch/handle-watch-started.d.ts +2 -0
  30. package/dist/src/feed/event-handlers/watch/handle-watch-stopped.d.ts +2 -0
  31. package/dist/src/feed/event-handlers/watch/index.d.ts +2 -0
  32. package/dist/src/feed/feed.d.ts +4 -12
  33. package/dist/src/feeds-client/event-handlers/index.d.ts +1 -0
  34. package/dist/src/feeds-client/event-handlers/user/handle-user-updated.d.ts +3 -0
  35. package/dist/src/{feeds-client.d.ts → feeds-client/feeds-client.d.ts} +16 -16
  36. package/dist/src/feeds-client/index.d.ts +2 -0
  37. package/dist/src/gen/feeds/FeedsApi.d.ts +27 -23
  38. package/dist/src/gen/models/index.d.ts +198 -23
  39. package/dist/src/test-utils/response-generators.d.ts +46 -1
  40. package/dist/src/utils/index.d.ts +1 -0
  41. package/dist/src/utils/update-entity-in-array.d.ts +27 -0
  42. package/dist/tsconfig.tsbuildinfo +1 -1
  43. package/index.ts +1 -1
  44. package/package.json +2 -2
  45. package/src/feed/event-handlers/activity/activity-reaction-utils.test.ts +108 -96
  46. package/src/feed/event-handlers/activity/activity-utils.test.ts +84 -122
  47. package/src/feed/event-handlers/activity/handle-activity-deleted.ts +43 -10
  48. package/src/feed/event-handlers/activity/handle-activity-pinned.test.ts +60 -0
  49. package/src/feed/event-handlers/activity/handle-activity-pinned.ts +30 -0
  50. package/src/feed/event-handlers/activity/handle-activity-reaction-added.test.ts +157 -0
  51. package/src/feed/event-handlers/activity/handle-activity-reaction-added.ts +82 -40
  52. package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.test.ts +200 -0
  53. package/src/feed/event-handlers/activity/handle-activity-reaction-deleted.ts +89 -51
  54. package/src/feed/event-handlers/activity/handle-activity-unpinned.test.ts +94 -0
  55. package/src/feed/event-handlers/activity/handle-activity-unpinned.ts +30 -0
  56. package/src/feed/event-handlers/activity/handle-activity-updated.test.ts +115 -0
  57. package/src/feed/event-handlers/activity/handle-activity-updated.ts +73 -35
  58. package/src/feed/event-handlers/bookmark/bookmark-utils.test.ts +121 -109
  59. package/src/feed/event-handlers/bookmark/handle-bookmark-added.test.ts +178 -0
  60. package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +82 -39
  61. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.test.ts +188 -0
  62. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +86 -48
  63. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.test.ts +196 -0
  64. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +83 -44
  65. package/src/feed/event-handlers/follow/handle-follow-created.test.ts +16 -12
  66. package/src/feed/event-handlers/follow/handle-follow-created.ts +4 -7
  67. package/src/feed/event-handlers/follow/handle-follow-deleted.test.ts +19 -15
  68. package/src/feed/event-handlers/follow/handle-follow-deleted.ts +6 -6
  69. package/src/feed/event-handlers/follow/handle-follow-updated.ts +7 -10
  70. package/src/feed/event-handlers/index.ts +2 -1
  71. package/src/feed/event-handlers/watch/handle-watch-started.ts +5 -0
  72. package/src/feed/event-handlers/watch/handle-watch-stopped.ts +5 -0
  73. package/src/feed/event-handlers/watch/index.ts +2 -0
  74. package/src/feed/feed.ts +15 -33
  75. package/src/feeds-client/event-handlers/index.ts +1 -0
  76. package/src/feeds-client/event-handlers/user/handle-user-updated.test.ts +53 -0
  77. package/src/feeds-client/event-handlers/user/handle-user-updated.ts +28 -0
  78. package/src/{feeds-client.ts → feeds-client/feeds-client.ts} +48 -39
  79. package/src/feeds-client/index.ts +2 -0
  80. package/src/gen/feeds/FeedsApi.ts +164 -138
  81. package/src/gen/model-decoders/decoders.ts +28 -0
  82. package/src/gen/models/index.ts +349 -29
  83. package/src/gen/moderation/ModerationApi.ts +1 -0
  84. package/src/test-utils/response-generators.ts +270 -11
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/state-update-queue.ts +1 -1
  87. package/src/utils/update-entity-in-array.ts +51 -0
package/src/feed/feed.ts CHANGED
@@ -8,10 +8,10 @@ import {
8
8
  ActivityResponse,
9
9
  CommentResponse,
10
10
  PagerResponse,
11
- SingleFollowRequest,
12
11
  QueryFeedMembersRequest,
13
12
  SortParamRequest,
14
13
  ThreadedCommentResponse,
14
+ FollowRequest,
15
15
  } from '../gen/models';
16
16
  import { StreamResponse } from '../gen-imports';
17
17
  import { StateStore } from '../common/StateStore';
@@ -205,7 +205,7 @@ export class Feed extends FeedApi {
205
205
  ) {
206
206
  super(client, groupId, id);
207
207
  this.state = new StateStore<FeedState>({
208
- fid: `${groupId}:${id}`,
208
+ feed: `${groupId}:${id}`,
209
209
  group_id: groupId,
210
210
  id,
211
211
  ...(data ?? {}),
@@ -219,7 +219,7 @@ export class Feed extends FeedApi {
219
219
 
220
220
  protected readonly client: FeedsClient;
221
221
 
222
- get fid() {
222
+ get feed() {
223
223
  return `${this.group}:${this.id}`;
224
224
  }
225
225
 
@@ -270,7 +270,7 @@ export class Feed extends FeedApi {
270
270
  this.stateUpdateQueue.clear();
271
271
  const responseCopy: Partial<
272
272
  StreamResponse<GetOrCreateFeedResponse>['feed'] &
273
- StreamResponse<GetOrCreateFeedResponse>
273
+ StreamResponse<Omit<GetOrCreateFeedResponse, 'feed'>>
274
274
  > = {
275
275
  ...response,
276
276
  ...response.feed,
@@ -316,24 +316,6 @@ export class Feed extends FeedApi {
316
316
  }
317
317
  }
318
318
 
319
- /**
320
- * @internal
321
- */
322
- handleWatchStopped() {
323
- this.state.partialNext({
324
- watch: false,
325
- });
326
- }
327
-
328
- /**
329
- * @internal
330
- */
331
- handleWatchStarted() {
332
- this.state.partialNext({
333
- watch: true,
334
- });
335
- }
336
-
337
319
  /**
338
320
  * Returns index of the provided comment object.
339
321
  */
@@ -569,7 +551,7 @@ export class Feed extends FeedApi {
569
551
  base: () =>
570
552
  this.client.getCommentReplies({
571
553
  ...request,
572
- comment_id: comment.id,
554
+ id: comment.id,
573
555
  // use known sort first (prevents broken pagination)
574
556
  sort,
575
557
  next: currentNextCursor,
@@ -623,7 +605,7 @@ export class Feed extends FeedApi {
623
605
  currentState[type],
624
606
  follows,
625
607
  (follow) =>
626
- `${follow.source_feed.fid}-${follow.target_feed.fid}`,
608
+ `${follow.source_feed.feed}-${follow.target_feed.feed}`,
627
609
  ),
628
610
  [paginationKey]: {
629
611
  ...currentState[paginationKey],
@@ -734,7 +716,7 @@ export class Feed extends FeedApi {
734
716
  */
735
717
  async queryFollowers(request: Omit<QueryFollowsRequest, 'filter'>) {
736
718
  const filter: QueryFollowsRequest['filter'] = {
737
- target_feed: this.fid,
719
+ target_feed: this.feed,
738
720
  };
739
721
 
740
722
  const response = await this.client.queryFollows({
@@ -752,7 +734,7 @@ export class Feed extends FeedApi {
752
734
  */
753
735
  async queryFollowing(request: Omit<QueryFollowsRequest, 'filter'>) {
754
736
  const filter: QueryFollowsRequest['filter'] = {
755
- source_feed: this.fid,
737
+ source_feed: this.feed,
756
738
  };
757
739
 
758
740
  const response = await this.client.queryFollows({
@@ -765,13 +747,13 @@ export class Feed extends FeedApi {
765
747
 
766
748
  async follow(
767
749
  feedOrFid: Feed | string,
768
- options?: Omit<SingleFollowRequest, 'source' | 'target'>,
750
+ options?: Omit<FollowRequest, 'source' | 'target'>,
769
751
  ) {
770
- const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
752
+ const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.feed;
771
753
 
772
754
  const response = await this.client.follow({
773
755
  ...options,
774
- source: this.fid,
756
+ source: this.feed,
775
757
  target: fid,
776
758
  });
777
759
 
@@ -779,10 +761,10 @@ export class Feed extends FeedApi {
779
761
  }
780
762
 
781
763
  async unfollow(feedOrFid: Feed | string) {
782
- const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.fid;
764
+ const fid = typeof feedOrFid === 'string' ? feedOrFid : feedOrFid.feed;
783
765
 
784
766
  const response = await this.client.unfollow({
785
- source: this.fid,
767
+ source: this.feed,
786
768
  target: fid,
787
769
  });
788
770
 
@@ -807,10 +789,10 @@ export class Feed extends FeedApi {
807
789
  });
808
790
  }
809
791
 
810
- addActivity(request: Omit<ActivityRequest, 'fids'>) {
792
+ addActivity(request: Omit<ActivityRequest, 'feeds'>) {
811
793
  return this.feedsApi.addActivity({
812
794
  ...request,
813
- fids: [this.fid],
795
+ feeds: [this.feed],
814
796
  });
815
797
  }
816
798
 
@@ -0,0 +1 @@
1
+ export * from './user/handle-user-updated';
@@ -0,0 +1,53 @@
1
+ import { describe, it, beforeEach, expect } from 'vitest';
2
+
3
+ import { FeedsClient, handleUserUpdated } from '../..';
4
+ import { generateOwnUser, generateUserResponse } from '../../../test-utils';
5
+ import { EventPayload } from '../../../types-internal';
6
+
7
+ describe('handleUserUpdated', () => {
8
+ let feedsClient: FeedsClient;
9
+
10
+ beforeEach(() => {
11
+ feedsClient = new FeedsClient('mock-api-key');
12
+ const connectedUser = generateOwnUser();
13
+
14
+ feedsClient.state.partialNext({ connected_user: connectedUser });
15
+ });
16
+
17
+ it('should update the connected user in the state', () => {
18
+ const stateBefore = feedsClient.state.getLatestValue();
19
+
20
+ const event: EventPayload<'user.updated'> = {
21
+ type: 'user.updated',
22
+ created_at: new Date(),
23
+ custom: {},
24
+ user: {
25
+ ...generateUserResponse(),
26
+ ...stateBefore.connected_user!,
27
+ },
28
+ };
29
+
30
+ handleUserUpdated.call(feedsClient, event);
31
+
32
+ const stateAfter = feedsClient.state.getLatestValue();
33
+
34
+ expect(stateAfter.connected_user).toMatchObject({ name: event.user.name });
35
+ });
36
+
37
+ it('should not update the connected user if the incoming event contains other user', () => {
38
+ const event: EventPayload<'user.updated'> = {
39
+ type: 'user.updated',
40
+ created_at: new Date(),
41
+ custom: {},
42
+ user: generateUserResponse(),
43
+ };
44
+
45
+ const stateBefore = feedsClient.state.getLatestValue();
46
+
47
+ handleUserUpdated.call(feedsClient, event);
48
+
49
+ const stateAfter = feedsClient.state.getLatestValue();
50
+
51
+ expect(stateAfter.connected_user).toBe(stateBefore.connected_user);
52
+ });
53
+ });
@@ -0,0 +1,28 @@
1
+ import type { EventPayload } from '../../../types-internal';
2
+ import type { FeedsClient, FeedsClientState } from '../../feeds-client';
3
+
4
+ export function handleUserUpdated(
5
+ this: FeedsClient,
6
+ event: EventPayload<'user.updated'>,
7
+ ) {
8
+ this.state.next((currentState) => {
9
+ let newState: FeedsClientState | undefined;
10
+
11
+ const { connected_user } = currentState;
12
+
13
+ if (connected_user && connected_user.id === event.user.id) {
14
+ newState ??= {
15
+ ...currentState,
16
+ };
17
+
18
+ newState.connected_user = {
19
+ ...connected_user,
20
+ ...event.user,
21
+ };
22
+ }
23
+
24
+ // TODO: update other users in user map (if/once applicable)
25
+
26
+ return newState ?? currentState;
27
+ });
28
+ }
@@ -1,46 +1,49 @@
1
- import { FeedsApi } from './gen/feeds/FeedsApi';
1
+ import { FeedsApi } from '../gen/feeds/FeedsApi';
2
2
  import {
3
3
  ActivityResponse,
4
4
  FeedResponse,
5
5
  FileUploadRequest,
6
6
  FollowBatchRequest,
7
+ FollowRequest,
7
8
  ImageUploadRequest,
8
9
  OwnUser,
9
10
  PollResponse,
10
11
  PollVotesResponse,
11
12
  QueryFeedsRequest,
12
13
  QueryPollVotesRequest,
13
- SingleFollowRequest,
14
14
  UpdateFollowRequest,
15
15
  UserRequest,
16
16
  WSEvent,
17
- } from './gen/models';
18
- import { FeedsEvent, StreamFile, TokenOrProvider } from './types';
19
- import { StateStore } from './common/StateStore';
20
- import { TokenManager } from './common/TokenManager';
21
- import { ConnectionIdManager } from './common/ConnectionIdManager';
22
- import { StableWSConnection } from './common/real-time/StableWSConnection';
23
- import { EventDispatcher } from './common/EventDispatcher';
24
- import { ApiClient } from './common/ApiClient';
17
+ } from '../gen/models';
18
+ import { FeedsEvent, StreamFile, TokenOrProvider } from '../types';
19
+ import { StateStore } from '../common/StateStore';
20
+ import { TokenManager } from '../common/TokenManager';
21
+ import { ConnectionIdManager } from '../common/ConnectionIdManager';
22
+ import { StableWSConnection } from '../common/real-time/StableWSConnection';
23
+ import { EventDispatcher } from '../common/EventDispatcher';
24
+ import { ApiClient } from '../common/ApiClient';
25
25
  import {
26
26
  addConnectionEventListeners,
27
27
  removeConnectionEventListeners,
28
28
  streamDevToken,
29
- } from './common/utils';
30
- import { decodeWSEvent } from './gen/model-decoders/event-decoder-mapping';
29
+ } from '../common/utils';
30
+ import { decodeWSEvent } from '../gen/model-decoders/event-decoder-mapping';
31
31
  import {
32
32
  FeedsClientOptions,
33
33
  NetworkChangedEvent,
34
34
  StreamResponse,
35
- } from './common/types';
36
- import { ModerationClient } from './moderation-client';
37
- import { StreamPoll } from './common/Poll';
35
+ } from '../common/types';
36
+ import { ModerationClient } from '../moderation-client';
37
+ import { StreamPoll } from '../common/Poll';
38
38
  import {
39
39
  Feed,
40
40
  handleFollowCreated,
41
41
  handleFollowDeleted,
42
42
  handleFollowUpdated,
43
- } from './feed';
43
+ handleWatchStarted,
44
+ handleWatchStopped,
45
+ } from '../feed';
46
+ import { handleUserUpdated } from './event-handlers';
44
47
 
45
48
  export type FeedsClientState = {
46
49
  connected_user: OwnUser | undefined;
@@ -107,7 +110,7 @@ export class FeedsClient extends FeedsApi {
107
110
  }
108
111
  } else {
109
112
  for (const activeFeed of Object.values(this.activeFeeds)) {
110
- activeFeed.handleWatchStopped();
113
+ handleWatchStopped.bind(activeFeed)();
111
114
  }
112
115
  }
113
116
  break;
@@ -194,6 +197,10 @@ export class FeedsClient extends FeedsApi {
194
197
 
195
198
  break;
196
199
  }
200
+ case 'user.updated': {
201
+ handleUserUpdated.call(this, event);
202
+ break;
203
+ }
197
204
  default: {
198
205
  feed?.handleWSEvent(event as unknown as WSEvent);
199
206
  }
@@ -344,7 +351,7 @@ export class FeedsClient extends FeedsApi {
344
351
  };
345
352
 
346
353
  async queryFeeds(request?: QueryFeedsRequest) {
347
- const response = await this.feedsQueryFeeds(request);
354
+ const response = await this._queryFeeds(request);
348
355
 
349
356
  const feeds = response.feeds.map((f) =>
350
357
  this.getOrCreateActiveFeed(f.group_id, f.id, f, request?.watch),
@@ -372,30 +379,32 @@ export class FeedsClient extends FeedsApi {
372
379
  async updateFollow(request: UpdateFollowRequest) {
373
380
  const response = await super.updateFollow(request);
374
381
 
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
- );
382
+ [
383
+ response.follow.source_feed.feed,
384
+ response.follow.target_feed.feed,
385
+ ].forEach((fid) => {
386
+ const feed = this.activeFeeds[fid];
387
+ if (feed) {
388
+ handleFollowUpdated.bind(feed)(response);
389
+ }
390
+ });
383
391
 
384
392
  return response;
385
393
  }
386
394
 
387
395
  // For follow API endpoints we update the state after HTTP response to allow queryFeeds with watch: false
388
- async follow(request: SingleFollowRequest) {
396
+ async follow(request: FollowRequest) {
389
397
  const response = await super.follow(request);
390
398
 
391
- [response.follow.source_feed.fid, response.follow.target_feed.fid].forEach(
392
- (fid) => {
393
- const feed = this.activeFeeds[fid];
394
- if (feed) {
395
- handleFollowCreated.bind(feed)(response);
396
- }
397
- },
398
- );
399
+ [
400
+ response.follow.source_feed.feed,
401
+ response.follow.target_feed.feed,
402
+ ].forEach((fid) => {
403
+ const feed = this.activeFeeds[fid];
404
+ if (feed) {
405
+ handleFollowCreated.bind(feed)(response);
406
+ }
407
+ });
399
408
 
400
409
  return response;
401
410
  }
@@ -404,7 +413,7 @@ export class FeedsClient extends FeedsApi {
404
413
  const response = await super.followBatch(request);
405
414
 
406
415
  response.follows.forEach((follow) => {
407
- const feed = this.activeFeeds[follow.source_feed.fid];
416
+ const feed = this.activeFeeds[follow.source_feed.feed];
408
417
  if (feed) {
409
418
  handleFollowCreated.bind(feed)({ follow });
410
419
  }
@@ -413,7 +422,7 @@ export class FeedsClient extends FeedsApi {
413
422
  return response;
414
423
  }
415
424
 
416
- async unfollow(request: SingleFollowRequest) {
425
+ async unfollow(request: FollowRequest) {
417
426
  const response = await super.unfollow(request);
418
427
 
419
428
  [request.source, request.target].forEach((fid) => {
@@ -436,7 +445,7 @@ export class FeedsClient extends FeedsApi {
436
445
  const feed =
437
446
  this.activeFeeds[`${request.feed_group_id}:${request.feed_id}`];
438
447
  if (feed) {
439
- feed.handleWatchStopped();
448
+ handleWatchStopped.bind(feed)();
440
449
  }
441
450
 
442
451
  return response;
@@ -452,7 +461,7 @@ export class FeedsClient extends FeedsApi {
452
461
  if (this.activeFeeds[fid]) {
453
462
  const feed = this.activeFeeds[fid];
454
463
  if (watch && !feed.currentState.watch) {
455
- feed.handleWatchStarted();
464
+ handleWatchStarted.bind(feed)();
456
465
  }
457
466
  return feed;
458
467
  } else {
@@ -0,0 +1,2 @@
1
+ export * from './feeds-client';
2
+ export * from './event-handlers';