@stream-io/feeds-client 0.1.1 → 0.1.2

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 (42) hide show
  1. package/@react-bindings/index.ts +13 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/@react-bindings/contexts/StreamFeedsContext.d.ts +15 -0
  4. package/dist/@react-bindings/hooks/clientStateHooks.d.ts +10 -0
  5. package/dist/@react-bindings/hooks/useCreateFeedsClient.d.ts +13 -0
  6. package/dist/@react-bindings/hooks/useStateStore.d.ts +1 -1
  7. package/dist/@react-bindings/index.d.ts +4 -0
  8. package/dist/@react-bindings/wrappers/StreamFeeds.d.ts +6 -0
  9. package/dist/index-react-bindings.browser.cjs +5388 -12
  10. package/dist/index-react-bindings.browser.cjs.map +1 -1
  11. package/dist/index-react-bindings.browser.js +5384 -14
  12. package/dist/index-react-bindings.browser.js.map +1 -1
  13. package/dist/index-react-bindings.node.cjs +5388 -12
  14. package/dist/index-react-bindings.node.cjs.map +1 -1
  15. package/dist/index-react-bindings.node.js +5384 -14
  16. package/dist/index-react-bindings.node.js.map +1 -1
  17. package/dist/index.browser.cjs +97 -31
  18. package/dist/index.browser.cjs.map +1 -1
  19. package/dist/index.browser.js +97 -31
  20. package/dist/index.browser.js.map +1 -1
  21. package/dist/index.node.cjs +97 -31
  22. package/dist/index.node.cjs.map +1 -1
  23. package/dist/index.node.js +97 -31
  24. package/dist/index.node.js.map +1 -1
  25. package/dist/src/Feed.d.ts +2 -2
  26. package/dist/src/FeedsClient.d.ts +8 -5
  27. package/dist/src/common/StateStore.d.ts +1 -0
  28. package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
  29. package/dist/src/gen/feeds/FeedsApi.d.ts +7 -1
  30. package/dist/src/gen/models/index.d.ts +41 -0
  31. package/dist/src/types.d.ts +2 -0
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +2 -6
  34. package/src/Feed.ts +19 -12
  35. package/src/FeedsClient.ts +24 -17
  36. package/src/common/StateStore.ts +30 -12
  37. package/src/common/utils.ts +1 -1
  38. package/src/gen/feeds/FeedsApi.ts +51 -0
  39. package/src/gen/model-decoders/decoders.ts +29 -0
  40. package/src/gen/model-decoders/event-decoder-mapping.ts +6 -0
  41. package/src/gen/models/index.ts +60 -0
  42. package/src/types.ts +4 -0
@@ -259,6 +259,14 @@ decoders.BookmarkDeletedEvent = (input) => {
259
259
  };
260
260
  return decode(typeMappings, input);
261
261
  };
262
+ decoders.BookmarkFolderDeletedEvent = (input) => {
263
+ const typeMappings = {
264
+ created_at: { type: 'DatetimeType', isSingle: true },
265
+ bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
266
+ received_at: { type: 'DatetimeType', isSingle: true },
267
+ };
268
+ return decode(typeMappings, input);
269
+ };
262
270
  decoders.BookmarkFolderResponse = (input) => {
263
271
  const typeMappings = {
264
272
  created_at: { type: 'DatetimeType', isSingle: true },
@@ -266,6 +274,14 @@ decoders.BookmarkFolderResponse = (input) => {
266
274
  };
267
275
  return decode(typeMappings, input);
268
276
  };
277
+ decoders.BookmarkFolderUpdatedEvent = (input) => {
278
+ const typeMappings = {
279
+ created_at: { type: 'DatetimeType', isSingle: true },
280
+ bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
281
+ received_at: { type: 'DatetimeType', isSingle: true },
282
+ };
283
+ return decode(typeMappings, input);
284
+ };
269
285
  decoders.BookmarkResponse = (input) => {
270
286
  const typeMappings = {
271
287
  created_at: { type: 'DatetimeType', isSingle: true },
@@ -1225,6 +1241,12 @@ decoders.UpdateBlockListResponse = (input) => {
1225
1241
  };
1226
1242
  return decode(typeMappings, input);
1227
1243
  };
1244
+ decoders.UpdateBookmarkFolderResponse = (input) => {
1245
+ const typeMappings = {
1246
+ bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
1247
+ };
1248
+ return decode(typeMappings, input);
1249
+ };
1228
1250
  decoders.UpdateBookmarkResponse = (input) => {
1229
1251
  const typeMappings = {
1230
1252
  bookmark: { type: 'BookmarkResponse', isSingle: true },
@@ -1645,6 +1667,26 @@ class FeedsApi {
1645
1667
  decoders.QueryBookmarkFoldersResponse?.(response.body);
1646
1668
  return { ...response.body, metadata: response.metadata };
1647
1669
  }
1670
+ async deleteBookmarkFolder(request) {
1671
+ const pathParams = {
1672
+ folder_id: request?.folder_id,
1673
+ };
1674
+ const response = await this.apiClient.sendRequest('DELETE', '/api/v2/feeds/bookmark_folders/{folder_id}', pathParams, undefined);
1675
+ decoders.DeleteBookmarkFolderResponse?.(response.body);
1676
+ return { ...response.body, metadata: response.metadata };
1677
+ }
1678
+ async updateBookmarkFolder(request) {
1679
+ const pathParams = {
1680
+ folder_id: request?.folder_id,
1681
+ };
1682
+ const body = {
1683
+ name: request?.name,
1684
+ custom: request?.custom,
1685
+ };
1686
+ const response = await this.apiClient.sendRequest('PATCH', '/api/v2/feeds/bookmark_folders/{folder_id}', pathParams, undefined, body, 'application/json');
1687
+ decoders.UpdateBookmarkFolderResponse?.(response.body);
1688
+ return { ...response.body, metadata: response.metadata };
1689
+ }
1648
1690
  async queryBookmarks(request) {
1649
1691
  const body = {
1650
1692
  limit: request?.limit,
@@ -2321,14 +2363,9 @@ class StateStore {
2321
2363
  let previouslySelectedValues;
2322
2364
  const wrappedHandler = (nextValue) => {
2323
2365
  const newlySelectedValues = selector(nextValue);
2324
- let hasUpdatedValues = typeof previouslySelectedValues === 'undefined';
2325
- for (const key in previouslySelectedValues) {
2326
- if (previouslySelectedValues[key] === newlySelectedValues[key])
2327
- continue;
2328
- hasUpdatedValues = true;
2329
- break;
2330
- }
2331
- if (!hasUpdatedValues)
2366
+ // shallow comparison of previouslySelectedValues and newlySelectedValues
2367
+ const selectionsAreEqual = StateStore.doSelectionsEqual(previouslySelectedValues, newlySelectedValues);
2368
+ if (selectionsAreEqual)
2332
2369
  return;
2333
2370
  // save a copy of previouslySelectedValues before running
2334
2371
  // handler - if previouslySelectedValues are set to
@@ -2359,7 +2396,7 @@ class StateStore {
2359
2396
  ? newValueOrPatch(this.value)
2360
2397
  : newValueOrPatch;
2361
2398
  // do not notify subscribers if the value hasn't changed
2362
- if (newValue === this.value)
2399
+ if (Object.is(newValue, this.value))
2363
2400
  return;
2364
2401
  this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
2365
2402
  const oldValue = this.value;
@@ -2376,6 +2413,19 @@ class StateStore {
2376
2413
  this.handlers.delete(handler);
2377
2414
  };
2378
2415
  }
2416
+ static doSelectionsEqual(previouslySelectedValues, newlySelectedValues) {
2417
+ let selectionsAreEqual;
2418
+ if ((selectionsAreEqual = typeof previouslySelectedValues !== 'undefined')) {
2419
+ for (const key in newlySelectedValues) {
2420
+ if (Object.is(previouslySelectedValues[key], newlySelectedValues[key])) {
2421
+ continue;
2422
+ }
2423
+ selectionsAreEqual = false;
2424
+ break;
2425
+ }
2426
+ }
2427
+ return selectionsAreEqual;
2428
+ }
2379
2429
  /**
2380
2430
  * Registers a preprocessor function that will be called before the state is updated.
2381
2431
  *
@@ -2601,7 +2651,7 @@ function getRandomValuesWithMathRandom(bytes) {
2601
2651
  }
2602
2652
  }
2603
2653
  const getRandomValues = (() => {
2604
- if (typeof crypto?.getRandomValues !== 'undefined') {
2654
+ if (typeof crypto !== 'undefined' && typeof crypto?.getRandomValues !== 'undefined') {
2605
2655
  return crypto.getRandomValues.bind(crypto);
2606
2656
  }
2607
2657
  else if (typeof msCrypto !== 'undefined') {
@@ -3610,6 +3660,8 @@ const eventDecoderMapping = {
3610
3660
  'feeds.bookmark.added': (data) => decoders.BookmarkAddedEvent(data),
3611
3661
  'feeds.bookmark.deleted': (data) => decoders.BookmarkDeletedEvent(data),
3612
3662
  'feeds.bookmark.updated': (data) => decoders.BookmarkUpdatedEvent(data),
3663
+ 'feeds.bookmark_folder.deleted': (data) => decoders.BookmarkFolderDeletedEvent(data),
3664
+ 'feeds.bookmark_folder.updated': (data) => decoders.BookmarkFolderUpdatedEvent(data),
3613
3665
  'feeds.comment.added': (data) => decoders.CommentAddedEvent(data),
3614
3666
  'feeds.comment.deleted': (data) => decoders.CommentDeletedEvent(data),
3615
3667
  'feeds.comment.reaction.added': (data) => decoders.CommentReactionAddedEvent(data),
@@ -4012,6 +4064,8 @@ class Feed extends FeedApi {
4012
4064
  'feeds.bookmark.added': this.handleBookmarkAdded.bind(this),
4013
4065
  'feeds.bookmark.deleted': this.handleBookmarkDeleted.bind(this),
4014
4066
  'feeds.bookmark.updated': this.handleBookmarkUpdated.bind(this),
4067
+ 'feeds.bookmark_folder.deleted': Feed.noop,
4068
+ 'feeds.bookmark_folder.updated': Feed.noop,
4015
4069
  'feeds.comment.added': (event) => {
4016
4070
  const { comment } = event;
4017
4071
  const forId = comment.parent_id ?? comment.object_id;
@@ -4101,16 +4155,19 @@ class Feed extends FeedApi {
4101
4155
  return;
4102
4156
  // this feed followed someone
4103
4157
  if (event.follow.source_feed.fid === this.fid) {
4104
- if (this.currentState.following_pagination?.next === END_OF_LIST) {
4105
- this.state.next((currentState) => ({
4158
+ this.state.next((currentState) => {
4159
+ const newState = {
4106
4160
  ...currentState,
4107
4161
  ...event.follow.source_feed,
4162
+ };
4163
+ if (currentState.following_pagination?.next === END_OF_LIST) {
4108
4164
  // TODO: respect sort
4109
- following: currentState.following
4165
+ newState.following = currentState.following
4110
4166
  ? currentState.following.concat(event.follow)
4111
- : [event.follow],
4112
- }));
4113
- }
4167
+ : [event.follow];
4168
+ }
4169
+ return newState;
4170
+ });
4114
4171
  }
4115
4172
  else if (
4116
4173
  // someone followed this feed
@@ -4120,14 +4177,14 @@ class Feed extends FeedApi {
4120
4177
  this.state.next((currentState) => {
4121
4178
  const newState = { ...currentState, ...event.follow.target_feed };
4122
4179
  if (source.created_by.id === connectedUser?.id) {
4123
- newState.own_follows = newState.own_follows
4124
- ? newState.own_follows.concat(event.follow)
4180
+ newState.own_follows = currentState.own_follows
4181
+ ? currentState.own_follows.concat(event.follow)
4125
4182
  : [event.follow];
4126
4183
  }
4127
4184
  if (currentState.followers_pagination?.next === END_OF_LIST) {
4128
4185
  // TODO: respect sort
4129
- newState.followers = newState.followers
4130
- ? newState.followers.concat(event.follow)
4186
+ newState.followers = currentState.followers
4187
+ ? currentState.followers.concat(event.follow)
4131
4188
  : [event.follow];
4132
4189
  }
4133
4190
  return newState;
@@ -4153,9 +4210,9 @@ class Feed extends FeedApi {
4153
4210
  this.state.next((currentState) => {
4154
4211
  const newState = { ...currentState, ...event.follow.target_feed };
4155
4212
  if (source.created_by.id === connectedUser?.id) {
4156
- newState.own_follows = newState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
4213
+ newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
4157
4214
  }
4158
- newState.followers = newState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
4215
+ newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
4159
4216
  return newState;
4160
4217
  });
4161
4218
  }
@@ -5063,7 +5120,10 @@ class FeedsClient extends FeedsApi {
5063
5120
  }, this.tokenManager, this.connectionIdManager, [decodeWSEvent]);
5064
5121
  this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
5065
5122
  const connectedEvent = await this.wsConnection.connect();
5066
- this.state.partialNext({ connectedUser: connectedEvent?.me });
5123
+ this.state.partialNext({
5124
+ connectedUser: connectedEvent?.me,
5125
+ isWsConnectionHealthy: this.wsConnection.isHealthy,
5126
+ });
5067
5127
  }
5068
5128
  catch (err) {
5069
5129
  await this.disconnectUser();
@@ -5118,13 +5178,20 @@ class FeedsClient extends FeedsApi {
5118
5178
  removeConnectionEventListeners(this.updateNetworkConnectionStatus);
5119
5179
  this.connectionIdManager.reset();
5120
5180
  this.tokenManager.reset();
5121
- this.state.partialNext({ connectedUser: undefined });
5181
+ this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
5122
5182
  };
5123
5183
  this.on = this.eventDispatcher.on;
5124
5184
  this.off = this.eventDispatcher.off;
5125
5185
  this.feed = (groupId, id) => {
5126
5186
  return this.getOrCreateActiveFeed(groupId, id);
5127
5187
  };
5188
+ this.updateNetworkConnectionStatus = (event) => {
5189
+ const networkEvent = {
5190
+ type: 'network.changed',
5191
+ online: event.type === 'online',
5192
+ };
5193
+ this.eventDispatcher.dispatch(networkEvent);
5194
+ };
5128
5195
  this.getOrCreateActiveFeed = (group, id, data) => {
5129
5196
  const fid = `${group}:${id}`;
5130
5197
  if (this.activeFeeds[fid]) {
@@ -5136,15 +5203,9 @@ class FeedsClient extends FeedsApi {
5136
5203
  return feed;
5137
5204
  }
5138
5205
  };
5139
- this.updateNetworkConnectionStatus = (event) => {
5140
- const networkEvent = {
5141
- type: 'network.changed',
5142
- online: event.type === 'online',
5143
- };
5144
- this.eventDispatcher.dispatch(networkEvent);
5145
- };
5146
5206
  this.state = new StateStore({
5147
5207
  connectedUser: undefined,
5208
+ isWsConnectionHealthy: false,
5148
5209
  });
5149
5210
  this.moderation = new ModerationClient(apiClient);
5150
5211
  this.tokenManager = tokenManager;
@@ -5154,6 +5215,11 @@ class FeedsClient extends FeedsApi {
5154
5215
  const fid = event.fid;
5155
5216
  const feed = typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
5156
5217
  switch (event.type) {
5218
+ case 'connection.changed': {
5219
+ const { online } = event;
5220
+ this.state.partialNext({ isWsConnectionHealthy: online });
5221
+ break;
5222
+ }
5157
5223
  case 'feeds.feed.created': {
5158
5224
  if (feed)
5159
5225
  break;