@stream-io/feeds-client 0.1.0 → 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.
- package/@react-bindings/index.ts +13 -0
- package/CHANGELOG.md +31 -0
- package/dist/@react-bindings/contexts/StreamFeedsContext.d.ts +15 -0
- package/dist/@react-bindings/hooks/clientStateHooks.d.ts +10 -0
- package/dist/@react-bindings/hooks/useCreateFeedsClient.d.ts +13 -0
- package/dist/@react-bindings/hooks/useOwnCapabilities.d.ts +33 -0
- package/dist/@react-bindings/hooks/useStateStore.d.ts +1 -1
- package/dist/@react-bindings/index.d.ts +5 -0
- package/dist/@react-bindings/wrappers/StreamFeeds.d.ts +6 -0
- package/dist/index-react-bindings.browser.cjs +5462 -12
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +5457 -14
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +5462 -12
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +5457 -14
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +100 -31
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +100 -31
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +100 -31
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +100 -31
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +2 -2
- package/dist/src/FeedsClient.d.ts +8 -5
- package/dist/src/common/StateStore.d.ts +1 -0
- package/dist/src/common/real-time/StableWSConnection.d.ts +3 -3
- package/dist/src/gen/feeds/FeedsApi.d.ts +7 -1
- package/dist/src/gen/models/index.d.ts +41 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -6
- package/src/Feed.ts +22 -12
- package/src/FeedsClient.ts +24 -17
- package/src/common/StateStore.ts +30 -12
- package/src/common/utils.ts +1 -1
- package/src/gen/feeds/FeedsApi.ts +51 -0
- package/src/gen/model-decoders/decoders.ts +29 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +6 -0
- package/src/gen/models/index.ts +60 -0
- package/src/types.ts +4 -0
package/dist/index.node.cjs
CHANGED
|
@@ -261,6 +261,14 @@ decoders.BookmarkDeletedEvent = (input) => {
|
|
|
261
261
|
};
|
|
262
262
|
return decode(typeMappings, input);
|
|
263
263
|
};
|
|
264
|
+
decoders.BookmarkFolderDeletedEvent = (input) => {
|
|
265
|
+
const typeMappings = {
|
|
266
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
267
|
+
bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
|
|
268
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
269
|
+
};
|
|
270
|
+
return decode(typeMappings, input);
|
|
271
|
+
};
|
|
264
272
|
decoders.BookmarkFolderResponse = (input) => {
|
|
265
273
|
const typeMappings = {
|
|
266
274
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -268,6 +276,14 @@ decoders.BookmarkFolderResponse = (input) => {
|
|
|
268
276
|
};
|
|
269
277
|
return decode(typeMappings, input);
|
|
270
278
|
};
|
|
279
|
+
decoders.BookmarkFolderUpdatedEvent = (input) => {
|
|
280
|
+
const typeMappings = {
|
|
281
|
+
created_at: { type: 'DatetimeType', isSingle: true },
|
|
282
|
+
bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
|
|
283
|
+
received_at: { type: 'DatetimeType', isSingle: true },
|
|
284
|
+
};
|
|
285
|
+
return decode(typeMappings, input);
|
|
286
|
+
};
|
|
271
287
|
decoders.BookmarkResponse = (input) => {
|
|
272
288
|
const typeMappings = {
|
|
273
289
|
created_at: { type: 'DatetimeType', isSingle: true },
|
|
@@ -1227,6 +1243,12 @@ decoders.UpdateBlockListResponse = (input) => {
|
|
|
1227
1243
|
};
|
|
1228
1244
|
return decode(typeMappings, input);
|
|
1229
1245
|
};
|
|
1246
|
+
decoders.UpdateBookmarkFolderResponse = (input) => {
|
|
1247
|
+
const typeMappings = {
|
|
1248
|
+
bookmark_folder: { type: 'BookmarkFolderResponse', isSingle: true },
|
|
1249
|
+
};
|
|
1250
|
+
return decode(typeMappings, input);
|
|
1251
|
+
};
|
|
1230
1252
|
decoders.UpdateBookmarkResponse = (input) => {
|
|
1231
1253
|
const typeMappings = {
|
|
1232
1254
|
bookmark: { type: 'BookmarkResponse', isSingle: true },
|
|
@@ -1647,6 +1669,26 @@ class FeedsApi {
|
|
|
1647
1669
|
decoders.QueryBookmarkFoldersResponse?.(response.body);
|
|
1648
1670
|
return { ...response.body, metadata: response.metadata };
|
|
1649
1671
|
}
|
|
1672
|
+
async deleteBookmarkFolder(request) {
|
|
1673
|
+
const pathParams = {
|
|
1674
|
+
folder_id: request?.folder_id,
|
|
1675
|
+
};
|
|
1676
|
+
const response = await this.apiClient.sendRequest('DELETE', '/api/v2/feeds/bookmark_folders/{folder_id}', pathParams, undefined);
|
|
1677
|
+
decoders.DeleteBookmarkFolderResponse?.(response.body);
|
|
1678
|
+
return { ...response.body, metadata: response.metadata };
|
|
1679
|
+
}
|
|
1680
|
+
async updateBookmarkFolder(request) {
|
|
1681
|
+
const pathParams = {
|
|
1682
|
+
folder_id: request?.folder_id,
|
|
1683
|
+
};
|
|
1684
|
+
const body = {
|
|
1685
|
+
name: request?.name,
|
|
1686
|
+
custom: request?.custom,
|
|
1687
|
+
};
|
|
1688
|
+
const response = await this.apiClient.sendRequest('PATCH', '/api/v2/feeds/bookmark_folders/{folder_id}', pathParams, undefined, body, 'application/json');
|
|
1689
|
+
decoders.UpdateBookmarkFolderResponse?.(response.body);
|
|
1690
|
+
return { ...response.body, metadata: response.metadata };
|
|
1691
|
+
}
|
|
1650
1692
|
async queryBookmarks(request) {
|
|
1651
1693
|
const body = {
|
|
1652
1694
|
limit: request?.limit,
|
|
@@ -2323,14 +2365,9 @@ class StateStore {
|
|
|
2323
2365
|
let previouslySelectedValues;
|
|
2324
2366
|
const wrappedHandler = (nextValue) => {
|
|
2325
2367
|
const newlySelectedValues = selector(nextValue);
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
continue;
|
|
2330
|
-
hasUpdatedValues = true;
|
|
2331
|
-
break;
|
|
2332
|
-
}
|
|
2333
|
-
if (!hasUpdatedValues)
|
|
2368
|
+
// shallow comparison of previouslySelectedValues and newlySelectedValues
|
|
2369
|
+
const selectionsAreEqual = StateStore.doSelectionsEqual(previouslySelectedValues, newlySelectedValues);
|
|
2370
|
+
if (selectionsAreEqual)
|
|
2334
2371
|
return;
|
|
2335
2372
|
// save a copy of previouslySelectedValues before running
|
|
2336
2373
|
// handler - if previouslySelectedValues are set to
|
|
@@ -2361,7 +2398,7 @@ class StateStore {
|
|
|
2361
2398
|
? newValueOrPatch(this.value)
|
|
2362
2399
|
: newValueOrPatch;
|
|
2363
2400
|
// do not notify subscribers if the value hasn't changed
|
|
2364
|
-
if (newValue
|
|
2401
|
+
if (Object.is(newValue, this.value))
|
|
2365
2402
|
return;
|
|
2366
2403
|
this.preprocessors.forEach((preprocessor) => preprocessor(newValue, this.value));
|
|
2367
2404
|
const oldValue = this.value;
|
|
@@ -2378,6 +2415,19 @@ class StateStore {
|
|
|
2378
2415
|
this.handlers.delete(handler);
|
|
2379
2416
|
};
|
|
2380
2417
|
}
|
|
2418
|
+
static doSelectionsEqual(previouslySelectedValues, newlySelectedValues) {
|
|
2419
|
+
let selectionsAreEqual;
|
|
2420
|
+
if ((selectionsAreEqual = typeof previouslySelectedValues !== 'undefined')) {
|
|
2421
|
+
for (const key in newlySelectedValues) {
|
|
2422
|
+
if (Object.is(previouslySelectedValues[key], newlySelectedValues[key])) {
|
|
2423
|
+
continue;
|
|
2424
|
+
}
|
|
2425
|
+
selectionsAreEqual = false;
|
|
2426
|
+
break;
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
return selectionsAreEqual;
|
|
2430
|
+
}
|
|
2381
2431
|
/**
|
|
2382
2432
|
* Registers a preprocessor function that will be called before the state is updated.
|
|
2383
2433
|
*
|
|
@@ -2603,7 +2653,7 @@ function getRandomValuesWithMathRandom(bytes) {
|
|
|
2603
2653
|
}
|
|
2604
2654
|
}
|
|
2605
2655
|
const getRandomValues = (() => {
|
|
2606
|
-
if (typeof crypto?.getRandomValues !== 'undefined') {
|
|
2656
|
+
if (typeof crypto !== 'undefined' && typeof crypto?.getRandomValues !== 'undefined') {
|
|
2607
2657
|
return crypto.getRandomValues.bind(crypto);
|
|
2608
2658
|
}
|
|
2609
2659
|
else if (typeof msCrypto !== 'undefined') {
|
|
@@ -3612,6 +3662,8 @@ const eventDecoderMapping = {
|
|
|
3612
3662
|
'feeds.bookmark.added': (data) => decoders.BookmarkAddedEvent(data),
|
|
3613
3663
|
'feeds.bookmark.deleted': (data) => decoders.BookmarkDeletedEvent(data),
|
|
3614
3664
|
'feeds.bookmark.updated': (data) => decoders.BookmarkUpdatedEvent(data),
|
|
3665
|
+
'feeds.bookmark_folder.deleted': (data) => decoders.BookmarkFolderDeletedEvent(data),
|
|
3666
|
+
'feeds.bookmark_folder.updated': (data) => decoders.BookmarkFolderUpdatedEvent(data),
|
|
3615
3667
|
'feeds.comment.added': (data) => decoders.CommentAddedEvent(data),
|
|
3616
3668
|
'feeds.comment.deleted': (data) => decoders.CommentDeletedEvent(data),
|
|
3617
3669
|
'feeds.comment.reaction.added': (data) => decoders.CommentReactionAddedEvent(data),
|
|
@@ -4014,6 +4066,8 @@ class Feed extends FeedApi {
|
|
|
4014
4066
|
'feeds.bookmark.added': this.handleBookmarkAdded.bind(this),
|
|
4015
4067
|
'feeds.bookmark.deleted': this.handleBookmarkDeleted.bind(this),
|
|
4016
4068
|
'feeds.bookmark.updated': this.handleBookmarkUpdated.bind(this),
|
|
4069
|
+
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4070
|
+
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4017
4071
|
'feeds.comment.added': (event) => {
|
|
4018
4072
|
const { comment } = event;
|
|
4019
4073
|
const forId = comment.parent_id ?? comment.object_id;
|
|
@@ -4103,16 +4157,19 @@ class Feed extends FeedApi {
|
|
|
4103
4157
|
return;
|
|
4104
4158
|
// this feed followed someone
|
|
4105
4159
|
if (event.follow.source_feed.fid === this.fid) {
|
|
4106
|
-
|
|
4107
|
-
|
|
4160
|
+
this.state.next((currentState) => {
|
|
4161
|
+
const newState = {
|
|
4108
4162
|
...currentState,
|
|
4109
4163
|
...event.follow.source_feed,
|
|
4164
|
+
};
|
|
4165
|
+
if (currentState.following_pagination?.next === END_OF_LIST) {
|
|
4110
4166
|
// TODO: respect sort
|
|
4111
|
-
following
|
|
4167
|
+
newState.following = currentState.following
|
|
4112
4168
|
? currentState.following.concat(event.follow)
|
|
4113
|
-
: [event.follow]
|
|
4114
|
-
}
|
|
4115
|
-
|
|
4169
|
+
: [event.follow];
|
|
4170
|
+
}
|
|
4171
|
+
return newState;
|
|
4172
|
+
});
|
|
4116
4173
|
}
|
|
4117
4174
|
else if (
|
|
4118
4175
|
// someone followed this feed
|
|
@@ -4122,14 +4179,14 @@ class Feed extends FeedApi {
|
|
|
4122
4179
|
this.state.next((currentState) => {
|
|
4123
4180
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4124
4181
|
if (source.created_by.id === connectedUser?.id) {
|
|
4125
|
-
newState.own_follows =
|
|
4126
|
-
?
|
|
4182
|
+
newState.own_follows = currentState.own_follows
|
|
4183
|
+
? currentState.own_follows.concat(event.follow)
|
|
4127
4184
|
: [event.follow];
|
|
4128
4185
|
}
|
|
4129
4186
|
if (currentState.followers_pagination?.next === END_OF_LIST) {
|
|
4130
4187
|
// TODO: respect sort
|
|
4131
|
-
newState.followers =
|
|
4132
|
-
?
|
|
4188
|
+
newState.followers = currentState.followers
|
|
4189
|
+
? currentState.followers.concat(event.follow)
|
|
4133
4190
|
: [event.follow];
|
|
4134
4191
|
}
|
|
4135
4192
|
return newState;
|
|
@@ -4155,9 +4212,9 @@ class Feed extends FeedApi {
|
|
|
4155
4212
|
this.state.next((currentState) => {
|
|
4156
4213
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4157
4214
|
if (source.created_by.id === connectedUser?.id) {
|
|
4158
|
-
newState.own_follows =
|
|
4215
|
+
newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4159
4216
|
}
|
|
4160
|
-
newState.followers =
|
|
4217
|
+
newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4161
4218
|
return newState;
|
|
4162
4219
|
});
|
|
4163
4220
|
}
|
|
@@ -4259,6 +4316,9 @@ class Feed extends FeedApi {
|
|
|
4259
4316
|
const newComment = {
|
|
4260
4317
|
...newComments[commentIndex],
|
|
4261
4318
|
...commentCopy,
|
|
4319
|
+
// TODO: FIXME this should be handled by the backend
|
|
4320
|
+
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4321
|
+
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4262
4322
|
};
|
|
4263
4323
|
newComments[commentIndex] = newComment;
|
|
4264
4324
|
if (reaction.user.id === connectedUser?.id) {
|
|
@@ -5062,7 +5122,10 @@ class FeedsClient extends FeedsApi {
|
|
|
5062
5122
|
}, this.tokenManager, this.connectionIdManager, [decodeWSEvent]);
|
|
5063
5123
|
this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
|
|
5064
5124
|
const connectedEvent = await this.wsConnection.connect();
|
|
5065
|
-
this.state.partialNext({
|
|
5125
|
+
this.state.partialNext({
|
|
5126
|
+
connectedUser: connectedEvent?.me,
|
|
5127
|
+
isWsConnectionHealthy: this.wsConnection.isHealthy,
|
|
5128
|
+
});
|
|
5066
5129
|
}
|
|
5067
5130
|
catch (err) {
|
|
5068
5131
|
await this.disconnectUser();
|
|
@@ -5117,13 +5180,20 @@ class FeedsClient extends FeedsApi {
|
|
|
5117
5180
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
5118
5181
|
this.connectionIdManager.reset();
|
|
5119
5182
|
this.tokenManager.reset();
|
|
5120
|
-
this.state.partialNext({ connectedUser: undefined });
|
|
5183
|
+
this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
|
|
5121
5184
|
};
|
|
5122
5185
|
this.on = this.eventDispatcher.on;
|
|
5123
5186
|
this.off = this.eventDispatcher.off;
|
|
5124
5187
|
this.feed = (groupId, id) => {
|
|
5125
5188
|
return this.getOrCreateActiveFeed(groupId, id);
|
|
5126
5189
|
};
|
|
5190
|
+
this.updateNetworkConnectionStatus = (event) => {
|
|
5191
|
+
const networkEvent = {
|
|
5192
|
+
type: 'network.changed',
|
|
5193
|
+
online: event.type === 'online',
|
|
5194
|
+
};
|
|
5195
|
+
this.eventDispatcher.dispatch(networkEvent);
|
|
5196
|
+
};
|
|
5127
5197
|
this.getOrCreateActiveFeed = (group, id, data) => {
|
|
5128
5198
|
const fid = `${group}:${id}`;
|
|
5129
5199
|
if (this.activeFeeds[fid]) {
|
|
@@ -5135,15 +5205,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5135
5205
|
return feed;
|
|
5136
5206
|
}
|
|
5137
5207
|
};
|
|
5138
|
-
this.updateNetworkConnectionStatus = (event) => {
|
|
5139
|
-
const networkEvent = {
|
|
5140
|
-
type: 'network.changed',
|
|
5141
|
-
online: event.type === 'online',
|
|
5142
|
-
};
|
|
5143
|
-
this.eventDispatcher.dispatch(networkEvent);
|
|
5144
|
-
};
|
|
5145
5208
|
this.state = new StateStore({
|
|
5146
5209
|
connectedUser: undefined,
|
|
5210
|
+
isWsConnectionHealthy: false,
|
|
5147
5211
|
});
|
|
5148
5212
|
this.moderation = new ModerationClient(apiClient);
|
|
5149
5213
|
this.tokenManager = tokenManager;
|
|
@@ -5153,6 +5217,11 @@ class FeedsClient extends FeedsApi {
|
|
|
5153
5217
|
const fid = event.fid;
|
|
5154
5218
|
const feed = typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
|
|
5155
5219
|
switch (event.type) {
|
|
5220
|
+
case 'connection.changed': {
|
|
5221
|
+
const { online } = event;
|
|
5222
|
+
this.state.partialNext({ isWsConnectionHealthy: online });
|
|
5223
|
+
break;
|
|
5224
|
+
}
|
|
5156
5225
|
case 'feeds.feed.created': {
|
|
5157
5226
|
if (feed)
|
|
5158
5227
|
break;
|