@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.browser.js
CHANGED
|
@@ -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
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
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
|
|
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
|
-
|
|
4105
|
-
|
|
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
|
|
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 =
|
|
4124
|
-
?
|
|
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 =
|
|
4130
|
-
?
|
|
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 =
|
|
4213
|
+
newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4157
4214
|
}
|
|
4158
|
-
newState.followers =
|
|
4215
|
+
newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4159
4216
|
return newState;
|
|
4160
4217
|
});
|
|
4161
4218
|
}
|
|
@@ -4257,6 +4314,9 @@ class Feed extends FeedApi {
|
|
|
4257
4314
|
const newComment = {
|
|
4258
4315
|
...newComments[commentIndex],
|
|
4259
4316
|
...commentCopy,
|
|
4317
|
+
// TODO: FIXME this should be handled by the backend
|
|
4318
|
+
latest_reactions: commentCopy.latest_reactions ?? [],
|
|
4319
|
+
reaction_groups: commentCopy.reaction_groups ?? {},
|
|
4260
4320
|
};
|
|
4261
4321
|
newComments[commentIndex] = newComment;
|
|
4262
4322
|
if (reaction.user.id === connectedUser?.id) {
|
|
@@ -5060,7 +5120,10 @@ class FeedsClient extends FeedsApi {
|
|
|
5060
5120
|
}, this.tokenManager, this.connectionIdManager, [decodeWSEvent]);
|
|
5061
5121
|
this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
|
|
5062
5122
|
const connectedEvent = await this.wsConnection.connect();
|
|
5063
|
-
this.state.partialNext({
|
|
5123
|
+
this.state.partialNext({
|
|
5124
|
+
connectedUser: connectedEvent?.me,
|
|
5125
|
+
isWsConnectionHealthy: this.wsConnection.isHealthy,
|
|
5126
|
+
});
|
|
5064
5127
|
}
|
|
5065
5128
|
catch (err) {
|
|
5066
5129
|
await this.disconnectUser();
|
|
@@ -5115,13 +5178,20 @@ class FeedsClient extends FeedsApi {
|
|
|
5115
5178
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
5116
5179
|
this.connectionIdManager.reset();
|
|
5117
5180
|
this.tokenManager.reset();
|
|
5118
|
-
this.state.partialNext({ connectedUser: undefined });
|
|
5181
|
+
this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
|
|
5119
5182
|
};
|
|
5120
5183
|
this.on = this.eventDispatcher.on;
|
|
5121
5184
|
this.off = this.eventDispatcher.off;
|
|
5122
5185
|
this.feed = (groupId, id) => {
|
|
5123
5186
|
return this.getOrCreateActiveFeed(groupId, id);
|
|
5124
5187
|
};
|
|
5188
|
+
this.updateNetworkConnectionStatus = (event) => {
|
|
5189
|
+
const networkEvent = {
|
|
5190
|
+
type: 'network.changed',
|
|
5191
|
+
online: event.type === 'online',
|
|
5192
|
+
};
|
|
5193
|
+
this.eventDispatcher.dispatch(networkEvent);
|
|
5194
|
+
};
|
|
5125
5195
|
this.getOrCreateActiveFeed = (group, id, data) => {
|
|
5126
5196
|
const fid = `${group}:${id}`;
|
|
5127
5197
|
if (this.activeFeeds[fid]) {
|
|
@@ -5133,15 +5203,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5133
5203
|
return feed;
|
|
5134
5204
|
}
|
|
5135
5205
|
};
|
|
5136
|
-
this.updateNetworkConnectionStatus = (event) => {
|
|
5137
|
-
const networkEvent = {
|
|
5138
|
-
type: 'network.changed',
|
|
5139
|
-
online: event.type === 'online',
|
|
5140
|
-
};
|
|
5141
|
-
this.eventDispatcher.dispatch(networkEvent);
|
|
5142
|
-
};
|
|
5143
5206
|
this.state = new StateStore({
|
|
5144
5207
|
connectedUser: undefined,
|
|
5208
|
+
isWsConnectionHealthy: false,
|
|
5145
5209
|
});
|
|
5146
5210
|
this.moderation = new ModerationClient(apiClient);
|
|
5147
5211
|
this.tokenManager = tokenManager;
|
|
@@ -5151,6 +5215,11 @@ class FeedsClient extends FeedsApi {
|
|
|
5151
5215
|
const fid = event.fid;
|
|
5152
5216
|
const feed = typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
|
|
5153
5217
|
switch (event.type) {
|
|
5218
|
+
case 'connection.changed': {
|
|
5219
|
+
const { online } = event;
|
|
5220
|
+
this.state.partialNext({ isWsConnectionHealthy: online });
|
|
5221
|
+
break;
|
|
5222
|
+
}
|
|
5154
5223
|
case 'feeds.feed.created': {
|
|
5155
5224
|
if (feed)
|
|
5156
5225
|
break;
|