@stream-io/feeds-client 0.3.17 → 0.3.19

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 (33) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +27 -0
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/react-bindings.js +1 -1
  5. package/dist/es/index.mjs +2 -2
  6. package/dist/es/react-bindings.mjs +1 -1
  7. package/dist/{feeds-client-Bq_SWnZW.mjs → feeds-client-BseA5k3b.mjs} +69 -35
  8. package/dist/feeds-client-BseA5k3b.mjs.map +1 -0
  9. package/dist/{feeds-client-BGF3utPy.js → feeds-client-BwOGqhU9.js} +69 -35
  10. package/dist/feeds-client-BwOGqhU9.js.map +1 -0
  11. package/dist/types/feed/event-handlers/activity/handle-activity-updated.d.ts.map +1 -1
  12. package/dist/types/feed/event-handlers/activity-updater.d.ts.map +1 -1
  13. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-added.d.ts.map +1 -1
  14. package/dist/types/feed/event-handlers/bookmark/handle-bookmark-deleted.d.ts.map +1 -1
  15. package/dist/types/feed/feed.d.ts +1 -0
  16. package/dist/types/feed/feed.d.ts.map +1 -1
  17. package/dist/types/feeds-client/feeds-client.d.ts +6 -2
  18. package/dist/types/feeds-client/feeds-client.d.ts.map +1 -1
  19. package/dist/types/feeds-client/get-or-create-active-feed.d.ts +4 -0
  20. package/dist/types/feeds-client/get-or-create-active-feed.d.ts.map +1 -0
  21. package/package.json +1 -1
  22. package/src/feed/event-handlers/activity/handle-activity-added.ts +2 -2
  23. package/src/feed/event-handlers/activity/handle-activity-updated.ts +0 -11
  24. package/src/feed/event-handlers/activity-updater.ts +0 -8
  25. package/src/feed/event-handlers/bookmark/handle-bookmark-added.ts +2 -10
  26. package/src/feed/event-handlers/bookmark/handle-bookmark-deleted.ts +2 -10
  27. package/src/feed/event-handlers/bookmark/handle-bookmark-updated.ts +2 -2
  28. package/src/feed/event-handlers/follow/handle-follow-deleted.ts +7 -7
  29. package/src/feed/feed.ts +44 -1
  30. package/src/feeds-client/feeds-client.ts +37 -7
  31. package/src/feeds-client/get-or-create-active-feed.ts +12 -0
  32. package/dist/feeds-client-BGF3utPy.js.map +0 -1
  33. package/dist/feeds-client-Bq_SWnZW.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [0.3.19](https://github.com/GetStream/stream-feeds-js/compare/@stream-io/feeds-client-0.3.18...@stream-io/feeds-client-0.3.19) (2025-12-11)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * reactive state updates for follow/unfollow ([#188](https://github.com/GetStream/stream-feeds-js/issues/188)) ([841d436](https://github.com/GetStream/stream-feeds-js/commit/841d43605a5f47cc929b3865f6c13ad26dbbf4c0))
11
+
12
+ ## [0.3.18](https://github.com/GetStream/stream-feeds-js/compare/@stream-io/feeds-client-0.3.17...@stream-io/feeds-client-0.3.18) (2025-12-10)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * backfill current feed ([#187](https://github.com/GetStream/stream-feeds-js/issues/187)) ([e215250](https://github.com/GetStream/stream-feeds-js/commit/e215250141aae281464fcec6267934c9a1aecb11))
18
+
5
19
  ## [0.3.17](https://github.com/GetStream/stream-feeds-js/compare/@stream-io/feeds-client-0.3.16...@stream-io/feeds-client-0.3.17) (2025-12-08)
6
20
 
7
21
 
package/README.md CHANGED
@@ -1,9 +1,36 @@
1
+ # Official plain JS SDK and low-level client for Stream Feeds
1
2
 
3
+ Bring users together through personalized feeds, threaded discussions, and real-time updates that make every interaction feel meaningful.
2
4
 
5
+ ## **Quick Links**
3
6
 
7
+ - [Register](https://getstream.io/chat/trial/) to get an API key for Stream Feeds
8
+ - [React Sample apps](../../#react-sample-apps)
9
+ - [Docs](https://getstream.io/activity-feeds/docs/)
4
10
 
11
+ ## What is Stream?
5
12
 
13
+ Stream allows developers to rapidly deploy scalable feeds, chat messaging and video with an industry leading 99.999% uptime SLA guarantee.
6
14
 
15
+ Stream's Activity Feed V3 SDK enables teams of all sizes to build scalable activity feeds. The best place to get started is to follow the tutorial:
7
16
 
17
+ TODO
8
18
 
19
+ ## 👩‍💻 Free for Makers 👨‍💻
9
20
 
21
+ Stream is free for most side and hobby projects. To qualify, your project/company needs to have < 5 team members and < $10k in monthly revenue. Makers get $100 in monthly credit for feeds for free.
22
+
23
+ ## 💡 Supported Features 💡
24
+
25
+ Here are some of the features we support:
26
+
27
+ - **For-You feed**: Most modern apps combine a “For You” feed with a regular “Following” feed. With activity selectors you can:
28
+ - surface popular activities
29
+ - show activities near the user
30
+ - match activities to a user’s interests
31
+ - mix-and-match these selectors to build an engaging personalized feed.
32
+ - **Comments**: Voting, threading, images, URL previews, @mentions & notifications. Basically all the features of Reddit style commenting systems.
33
+ - **Advanced feed features**: Activity expiration • visibility controls • feed visibility levels • feed members • bookmarking • follow-approval flow • stories support.
34
+ - **Activity filtering**: Filter activity feeds with almost no hit to performance
35
+ - **Search & queries**: Activity search, **query activities**, and **query feeds** endpoints.
36
+ - **Modern essentials**: Permissions • OpenAPI spec • GDPR endpoints • realtime WebSocket events • push notifications • “own capabilities” API.
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const stateStore = require("@stream-io/state-store");
4
- const feedsClient = require("../feeds-client-BGF3utPy.js");
4
+ const feedsClient = require("../feeds-client-BwOGqhU9.js");
5
5
  const loggerInternal = require("@stream-io/logger");
6
6
  const ChannelOwnCapability = {
7
7
  BAN_CHANNEL_MEMBERS: "ban-channel-members",
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require$$0 = require("react");
4
4
  require("@stream-io/state-store");
5
- const feedsClient = require("../feeds-client-BGF3utPy.js");
5
+ const feedsClient = require("../feeds-client-BwOGqhU9.js");
6
6
  require("axios");
7
7
  var shim = { exports: {} };
8
8
  var useSyncExternalStoreShim_production = {};
package/dist/es/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { StateStore } from "@stream-io/state-store";
2
2
  export * from "@stream-io/state-store";
3
- import { d as debounce } from "../feeds-client-Bq_SWnZW.mjs";
4
- import { A, C, a, F, S, b, c, n, m, k, g, e, h, f, j, i, r, s, u, l } from "../feeds-client-Bq_SWnZW.mjs";
3
+ import { d as debounce } from "../feeds-client-BseA5k3b.mjs";
4
+ import { A, C, a, F, S, b, c, n, m, k, g, e, h, f, j, i, r, s, u, l } from "../feeds-client-BseA5k3b.mjs";
5
5
  import { LogLevelEnum } from "@stream-io/logger";
6
6
  const ChannelOwnCapability = {
7
7
  BAN_CHANNEL_MEMBERS: "ban-channel-members",
@@ -1,6 +1,6 @@
1
1
  import require$$0, { useCallback, useMemo, useState, useEffect, createContext, useContext, useRef } from "react";
2
2
  import "@stream-io/state-store";
3
- import { F as FeedsClient, g as isCommentResponse, c as checkHasAnotherPage } from "../feeds-client-Bq_SWnZW.mjs";
3
+ import { F as FeedsClient, g as isCommentResponse, c as checkHasAnotherPage } from "../feeds-client-BseA5k3b.mjs";
4
4
  import "axios";
5
5
  var shim = { exports: {} };
6
6
  var useSyncExternalStoreShim_production = {};
@@ -3914,7 +3914,7 @@ const getRateLimitFromResponseHeader = (response_headers) => {
3914
3914
  };
3915
3915
  return result;
3916
3916
  };
3917
- const version = "0.3.17";
3917
+ const version = "0.3.19";
3918
3918
  class ApiClient {
3919
3919
  constructor(apiKey, tokenManager, connectionIdManager, options) {
3920
3920
  this.apiKey = apiKey;
@@ -4857,10 +4857,10 @@ const updateStateFollowDeleted = (follow, currentState, currentFeedId, connected
4857
4857
  // Update FeedResponse fields, that has the new follower/following count
4858
4858
  ...follow.target_feed
4859
4859
  };
4860
- if (source.created_by.id === connectedUserId && currentState.own_follows !== void 0) {
4861
- newState.own_follows = currentState.own_follows.filter(
4860
+ if (source.created_by.id === connectedUserId) {
4861
+ newState.own_follows = currentState.own_follows ? currentState.own_follows.filter(
4862
4862
  (followItem) => followItem.source_feed.feed !== follow.source_feed.feed
4863
- );
4863
+ ) : [];
4864
4864
  }
4865
4865
  if (currentState.followers !== void 0) {
4866
4866
  newState.followers = currentState.followers.filter(
@@ -5279,13 +5279,10 @@ const sharedUpdateActivity$6 = ({
5279
5279
  if (eventBelongsToCurrentUser) {
5280
5280
  newOwnBookmarks = [...newOwnBookmarks, event.bookmark];
5281
5281
  }
5282
- if (!event.bookmark.activity.current_feed && event.bookmark.activity.feeds.length === 1 && currentActivity.current_feed) {
5283
- event.bookmark.activity.current_feed = currentActivity.current_feed;
5284
- }
5285
5282
  return {
5286
- ...event.bookmark.activity,
5287
- own_bookmarks: newOwnBookmarks,
5288
- own_reactions: currentActivity.own_reactions
5283
+ ...currentActivity,
5284
+ bookmark_count: event.bookmark.activity.bookmark_count,
5285
+ own_bookmarks: newOwnBookmarks
5289
5286
  };
5290
5287
  };
5291
5288
  const addBookmarkToActivities = (event, activities, eventBelongsToCurrentUser) => updateEntityInArray({
@@ -5355,13 +5352,10 @@ const sharedUpdateActivity$5 = ({
5355
5352
  (bookmark) => !isSameBookmark(bookmark, event.bookmark)
5356
5353
  );
5357
5354
  }
5358
- if (!event.bookmark.activity.current_feed && event.bookmark.activity.feeds.length === 1 && currentActivity.current_feed) {
5359
- event.bookmark.activity.current_feed = currentActivity.current_feed;
5360
- }
5361
5355
  return {
5362
- ...event.bookmark.activity,
5363
- own_bookmarks: newOwnBookmarks,
5364
- own_reactions: currentActivity.own_reactions
5356
+ ...currentActivity,
5357
+ bookmark_count: event.bookmark.activity.bookmark_count,
5358
+ own_bookmarks: newOwnBookmarks
5365
5359
  };
5366
5360
  };
5367
5361
  const removeBookmarkFromActivities = (event, activities, eventBelongsToCurrentUser) => updateEntityInArray({
@@ -5433,9 +5427,9 @@ const sharedUpdateActivity$4 = ({
5433
5427
  }
5434
5428
  }
5435
5429
  return {
5436
- ...event.bookmark.activity,
5437
- own_bookmarks: newOwnBookmarks,
5438
- own_reactions: currentActivity.own_reactions
5430
+ ...currentActivity,
5431
+ bookmark_count: event.bookmark.activity.bookmark_count,
5432
+ own_bookmarks: newOwnBookmarks
5439
5433
  };
5440
5434
  };
5441
5435
  const updateBookmarkInActivities = (event, activities, eventBelongsToCurrentUser) => updateEntityInArray({
@@ -5514,6 +5508,7 @@ function addActivitiesToState(newActivities, activities, position) {
5514
5508
  ...activities,
5515
5509
  ...position === "end" ? newActivitiesDeduplicated : []
5516
5510
  ];
5511
+ this.newActivitiesAdded(newActivitiesDeduplicated);
5517
5512
  result = { changed: true, activities: updatedActivities };
5518
5513
  }
5519
5514
  return result;
@@ -5593,9 +5588,6 @@ const updateActivity = ({
5593
5588
  currentActivity,
5594
5589
  newActivtiy
5595
5590
  }) => {
5596
- if (!newActivtiy.current_feed && newActivtiy.feeds.length === 1 && currentActivity.current_feed) {
5597
- newActivtiy.current_feed = currentActivity.current_feed;
5598
- }
5599
5591
  return {
5600
5592
  ...newActivtiy,
5601
5593
  own_reactions: currentActivity.own_reactions,
@@ -5645,12 +5637,6 @@ function handleActivityUpdated(payload, fromWs) {
5645
5637
  activities: currentActivities,
5646
5638
  pinned_activities: currentPinnedActivities
5647
5639
  } = this.currentState;
5648
- const currentActivity = currentActivities?.find(
5649
- (a) => a.id === payload.activity.id
5650
- );
5651
- if (!payload.activity.current_feed && payload.activity.feeds.length === 1 && currentActivity?.current_feed) {
5652
- payload.activity.current_feed = currentActivity.current_feed;
5653
- }
5654
5640
  const [result1, result2] = [
5655
5641
  this.hasActivity(payload.activity.id) ? updateActivityInState(payload, currentActivities) : void 0,
5656
5642
  updatePinnedActivityInState(payload, currentPinnedActivities)
@@ -6241,6 +6227,9 @@ const deepEqual = (x, y) => {
6241
6227
  return false;
6242
6228
  }
6243
6229
  };
6230
+ function getOrCreateActiveFeed(group, id, data, watch) {
6231
+ return this.getOrCreateActiveFeed(group, id, data, watch);
6232
+ }
6244
6233
  const _Feed = class _Feed extends FeedApi {
6245
6234
  constructor(client, groupId, id, data, watch = false, addNewActivitiesTo = "start", activityAddedEventFilter) {
6246
6235
  super(client, groupId, id);
@@ -6433,7 +6422,7 @@ const _Feed = class _Feed extends FeedApi {
6433
6422
  return nextState;
6434
6423
  });
6435
6424
  }
6436
- this.client.hydratePollCache(response.activities);
6425
+ this.newActivitiesAdded(response.activities);
6437
6426
  return response;
6438
6427
  } finally {
6439
6428
  this.state.partialNext({
@@ -6814,6 +6803,19 @@ const _Feed = class _Feed extends FeedApi {
6814
6803
  handleWSEvent(event) {
6815
6804
  const eventHandler = this.eventHandlers[event.type];
6816
6805
  if (eventHandler !== _Feed.noop) {
6806
+ if ("activity" in event && this.hasActivity(event.activity.id)) {
6807
+ const currentActivity = this.currentState.activities?.find(
6808
+ (a) => a.id === event.activity.id
6809
+ );
6810
+ if (event.activity.feeds.length > 1 && !event.activity.current_feed && currentActivity?.current_feed) {
6811
+ event.activity.current_feed = currentActivity.current_feed;
6812
+ }
6813
+ if (event.activity.feeds.length === 1 && event.activity.current_feed && currentActivity?.current_feed) {
6814
+ event.activity.current_feed.own_capabilities = currentActivity.current_feed.own_capabilities;
6815
+ event.activity.current_feed.own_follows = currentActivity.current_feed.own_follows;
6816
+ event.activity.current_feed.own_membership = currentActivity.current_feed.own_membership;
6817
+ }
6818
+ }
6817
6819
  eventHandler?.(event);
6818
6820
  }
6819
6821
  if (typeof eventHandler === "undefined") {
@@ -6821,6 +6823,18 @@ const _Feed = class _Feed extends FeedApi {
6821
6823
  }
6822
6824
  this.eventDispatcher.dispatch(event);
6823
6825
  }
6826
+ newActivitiesAdded(activities) {
6827
+ this.client.hydratePollCache(activities);
6828
+ activities.forEach((activity) => {
6829
+ if (activity.current_feed) {
6830
+ getOrCreateActiveFeed.bind(this.client)(
6831
+ activity.current_feed.group_id,
6832
+ activity.current_feed.id,
6833
+ activity.current_feed
6834
+ );
6835
+ }
6836
+ });
6837
+ }
6824
6838
  };
6825
6839
  _Feed.noop = () => {
6826
6840
  };
@@ -7365,8 +7379,7 @@ class FeedsClient extends FeedsApi {
7365
7379
  id,
7366
7380
  void 0,
7367
7381
  void 0,
7368
- options2?.addNewActivitiesTo,
7369
- options2?.activityAddedEventFilter
7382
+ options2
7370
7383
  );
7371
7384
  };
7372
7385
  this.activityWithStateUpdates = (id) => {
@@ -7384,20 +7397,30 @@ class FeedsClient extends FeedsApi {
7384
7397
  };
7385
7398
  this.eventDispatcher.dispatch(networkEvent);
7386
7399
  };
7387
- this.getOrCreateActiveFeed = (group, id, data, watch, addNewActivitiesTo, activityAddedEventFilter) => {
7400
+ this.getOrCreateActiveFeed = (group, id, data, watch, options2) => {
7388
7401
  const fid = `${group}:${id}`;
7402
+ let isCreated = false;
7389
7403
  if (!this.activeFeeds[fid]) {
7404
+ isCreated = true;
7390
7405
  this.activeFeeds[fid] = new Feed(
7391
7406
  this,
7392
7407
  group,
7393
7408
  id,
7394
7409
  data,
7395
7410
  watch,
7396
- addNewActivitiesTo,
7397
- activityAddedEventFilter
7411
+ options2?.addNewActivitiesTo,
7412
+ options2?.activityAddedEventFilter
7398
7413
  );
7399
7414
  }
7400
7415
  const feed = this.activeFeeds[fid];
7416
+ if (!isCreated && options2) {
7417
+ if (options2?.addNewActivitiesTo) {
7418
+ feed.addNewActivitiesTo = options2.addNewActivitiesTo;
7419
+ }
7420
+ if (options2?.activityAddedEventFilter) {
7421
+ feed.activityAddedEventFilter = options2.activityAddedEventFilter;
7422
+ }
7423
+ }
7401
7424
  if (!feed.currentState.watch) {
7402
7425
  if (data) handleFeedUpdated.call(feed, { feed: data });
7403
7426
  if (watch) handleWatchStarted.call(feed);
@@ -7669,6 +7692,17 @@ class FeedsClient extends FeedsApi {
7669
7692
  }
7670
7693
  return response;
7671
7694
  }
7695
+ async getFollowSuggestions(...params) {
7696
+ const response = await super.getFollowSuggestions(...params);
7697
+ response.suggestions.forEach((suggestion) => {
7698
+ this.getOrCreateActiveFeed(
7699
+ suggestion.group_id,
7700
+ suggestion.id,
7701
+ suggestion
7702
+ );
7703
+ });
7704
+ return response;
7705
+ }
7672
7706
  findAllActiveFeedsByActivityId(activityId) {
7673
7707
  return [
7674
7708
  ...Object.values(this.activeFeeds),
@@ -7750,4 +7784,4 @@ export {
7750
7784
  shouldUpdateState as s,
7751
7785
  uniqueArrayMerge as u
7752
7786
  };
7753
- //# sourceMappingURL=feeds-client-Bq_SWnZW.mjs.map
7787
+ //# sourceMappingURL=feeds-client-BseA5k3b.mjs.map