@stream-io/feeds-client 0.1.1 → 0.1.3
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 -1
- 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/useStateStore.d.ts +1 -1
- package/dist/@react-bindings/index.d.ts +4 -0
- package/dist/@react-bindings/wrappers/StreamFeeds.d.ts +6 -0
- package/dist/index-react-bindings.browser.cjs +5411 -12
- package/dist/index-react-bindings.browser.cjs.map +1 -1
- package/dist/index-react-bindings.browser.js +5407 -14
- package/dist/index-react-bindings.browser.js.map +1 -1
- package/dist/index-react-bindings.node.cjs +5411 -12
- package/dist/index-react-bindings.node.cjs.map +1 -1
- package/dist/index-react-bindings.node.js +5407 -14
- package/dist/index-react-bindings.node.js.map +1 -1
- package/dist/index.browser.cjs +125 -36
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +125 -36
- package/dist/index.browser.js.map +1 -1
- package/dist/index.node.cjs +125 -36
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.js +125 -36
- package/dist/index.node.js.map +1 -1
- package/dist/src/Feed.d.ts +4 -2
- package/dist/src/FeedsClient.d.ts +9 -5
- package/dist/src/common/ApiClient.d.ts +1 -0
- 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 +33 -15
- package/src/FeedsClient.ts +37 -17
- package/src/common/ApiClient.ts +10 -3
- 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.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') {
|
|
@@ -3493,7 +3543,10 @@ class ApiClient {
|
|
|
3493
3543
|
const encodedBody = requestContentType === 'multipart/form-data' ? new FormData() : body;
|
|
3494
3544
|
if (requestContentType === 'multipart/form-data') {
|
|
3495
3545
|
Object.keys(body).forEach((key) => {
|
|
3496
|
-
|
|
3546
|
+
const value = body[key];
|
|
3547
|
+
if (value != null) {
|
|
3548
|
+
encodedBody.append(key, value);
|
|
3549
|
+
}
|
|
3497
3550
|
});
|
|
3498
3551
|
}
|
|
3499
3552
|
try {
|
|
@@ -3502,8 +3555,11 @@ class ApiClient {
|
|
|
3502
3555
|
method,
|
|
3503
3556
|
headers,
|
|
3504
3557
|
params: queryParams,
|
|
3505
|
-
paramsSerializer: params => this.queryParamsStringify(params),
|
|
3558
|
+
paramsSerializer: (params) => this.queryParamsStringify(params),
|
|
3506
3559
|
data: encodedBody,
|
|
3560
|
+
timeout:
|
|
3561
|
+
// multipart/form-data requests should not have a timeout allowing ample time for file uploads
|
|
3562
|
+
requestContentType === 'multipart/form-data' ? 0 : this.timeout,
|
|
3507
3563
|
});
|
|
3508
3564
|
const metadata = this.getRequestMetadata(client_request_id, response);
|
|
3509
3565
|
return { body: response.data, metadata };
|
|
@@ -3567,9 +3623,9 @@ class ApiClient {
|
|
|
3567
3623
|
};
|
|
3568
3624
|
};
|
|
3569
3625
|
this.baseUrl = options?.base_url ?? 'https://video.stream-io-api.com';
|
|
3626
|
+
this.timeout = options?.timeout ?? 3000;
|
|
3570
3627
|
this.axiosInstance = axios.create({
|
|
3571
3628
|
baseURL: this.baseUrl,
|
|
3572
|
-
timeout: options?.timeout ?? 3000,
|
|
3573
3629
|
});
|
|
3574
3630
|
}
|
|
3575
3631
|
get webSocketBaseUrl() {
|
|
@@ -3610,6 +3666,8 @@ const eventDecoderMapping = {
|
|
|
3610
3666
|
'feeds.bookmark.added': (data) => decoders.BookmarkAddedEvent(data),
|
|
3611
3667
|
'feeds.bookmark.deleted': (data) => decoders.BookmarkDeletedEvent(data),
|
|
3612
3668
|
'feeds.bookmark.updated': (data) => decoders.BookmarkUpdatedEvent(data),
|
|
3669
|
+
'feeds.bookmark_folder.deleted': (data) => decoders.BookmarkFolderDeletedEvent(data),
|
|
3670
|
+
'feeds.bookmark_folder.updated': (data) => decoders.BookmarkFolderUpdatedEvent(data),
|
|
3613
3671
|
'feeds.comment.added': (data) => decoders.CommentAddedEvent(data),
|
|
3614
3672
|
'feeds.comment.deleted': (data) => decoders.CommentDeletedEvent(data),
|
|
3615
3673
|
'feeds.comment.reaction.added': (data) => decoders.CommentReactionAddedEvent(data),
|
|
@@ -4012,6 +4070,8 @@ class Feed extends FeedApi {
|
|
|
4012
4070
|
'feeds.bookmark.added': this.handleBookmarkAdded.bind(this),
|
|
4013
4071
|
'feeds.bookmark.deleted': this.handleBookmarkDeleted.bind(this),
|
|
4014
4072
|
'feeds.bookmark.updated': this.handleBookmarkUpdated.bind(this),
|
|
4073
|
+
'feeds.bookmark_folder.deleted': Feed.noop,
|
|
4074
|
+
'feeds.bookmark_folder.updated': Feed.noop,
|
|
4015
4075
|
'feeds.comment.added': (event) => {
|
|
4016
4076
|
const { comment } = event;
|
|
4017
4077
|
const forId = comment.parent_id ?? comment.object_id;
|
|
@@ -4101,16 +4161,19 @@ class Feed extends FeedApi {
|
|
|
4101
4161
|
return;
|
|
4102
4162
|
// this feed followed someone
|
|
4103
4163
|
if (event.follow.source_feed.fid === this.fid) {
|
|
4104
|
-
|
|
4105
|
-
|
|
4164
|
+
this.state.next((currentState) => {
|
|
4165
|
+
const newState = {
|
|
4106
4166
|
...currentState,
|
|
4107
4167
|
...event.follow.source_feed,
|
|
4168
|
+
};
|
|
4169
|
+
if (currentState.following_pagination?.next === END_OF_LIST) {
|
|
4108
4170
|
// TODO: respect sort
|
|
4109
|
-
following
|
|
4171
|
+
newState.following = currentState.following
|
|
4110
4172
|
? currentState.following.concat(event.follow)
|
|
4111
|
-
: [event.follow]
|
|
4112
|
-
}
|
|
4113
|
-
|
|
4173
|
+
: [event.follow];
|
|
4174
|
+
}
|
|
4175
|
+
return newState;
|
|
4176
|
+
});
|
|
4114
4177
|
}
|
|
4115
4178
|
else if (
|
|
4116
4179
|
// someone followed this feed
|
|
@@ -4120,14 +4183,14 @@ class Feed extends FeedApi {
|
|
|
4120
4183
|
this.state.next((currentState) => {
|
|
4121
4184
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4122
4185
|
if (source.created_by.id === connectedUser?.id) {
|
|
4123
|
-
newState.own_follows =
|
|
4124
|
-
?
|
|
4186
|
+
newState.own_follows = currentState.own_follows
|
|
4187
|
+
? currentState.own_follows.concat(event.follow)
|
|
4125
4188
|
: [event.follow];
|
|
4126
4189
|
}
|
|
4127
4190
|
if (currentState.followers_pagination?.next === END_OF_LIST) {
|
|
4128
4191
|
// TODO: respect sort
|
|
4129
|
-
newState.followers =
|
|
4130
|
-
?
|
|
4192
|
+
newState.followers = currentState.followers
|
|
4193
|
+
? currentState.followers.concat(event.follow)
|
|
4131
4194
|
: [event.follow];
|
|
4132
4195
|
}
|
|
4133
4196
|
return newState;
|
|
@@ -4153,9 +4216,9 @@ class Feed extends FeedApi {
|
|
|
4153
4216
|
this.state.next((currentState) => {
|
|
4154
4217
|
const newState = { ...currentState, ...event.follow.target_feed };
|
|
4155
4218
|
if (source.created_by.id === connectedUser?.id) {
|
|
4156
|
-
newState.own_follows =
|
|
4219
|
+
newState.own_follows = currentState.own_follows?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4157
4220
|
}
|
|
4158
|
-
newState.followers =
|
|
4221
|
+
newState.followers = currentState.followers?.filter((follow) => follow.source_feed.fid !== event.follow.source_feed.fid);
|
|
4159
4222
|
return newState;
|
|
4160
4223
|
});
|
|
4161
4224
|
}
|
|
@@ -4282,6 +4345,12 @@ class Feed extends FeedApi {
|
|
|
4282
4345
|
};
|
|
4283
4346
|
});
|
|
4284
4347
|
}
|
|
4348
|
+
async synchronize() {
|
|
4349
|
+
const { last_get_or_create_request_config } = this.state.getLatestValue();
|
|
4350
|
+
if (last_get_or_create_request_config?.watch) {
|
|
4351
|
+
await this.getOrCreate(last_get_or_create_request_config);
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4285
4354
|
async getOrCreate(request) {
|
|
4286
4355
|
if (this.currentState.is_loading_activities) {
|
|
4287
4356
|
throw new Error('Only one getOrCreate call is allowed at a time');
|
|
@@ -4347,6 +4416,7 @@ class Feed extends FeedApi {
|
|
|
4347
4416
|
if (!request?.following_pagination?.limit) {
|
|
4348
4417
|
delete nextState.following;
|
|
4349
4418
|
}
|
|
4419
|
+
nextState.last_get_or_create_request_config = request;
|
|
4350
4420
|
return nextState;
|
|
4351
4421
|
});
|
|
4352
4422
|
}
|
|
@@ -4633,7 +4703,7 @@ class Feed extends FeedApi {
|
|
|
4633
4703
|
}
|
|
4634
4704
|
async getNextPage() {
|
|
4635
4705
|
const currentState = this.currentState;
|
|
4636
|
-
|
|
4706
|
+
return await this.getOrCreate({
|
|
4637
4707
|
member_pagination: {
|
|
4638
4708
|
limit: 0,
|
|
4639
4709
|
},
|
|
@@ -4644,8 +4714,8 @@ class Feed extends FeedApi {
|
|
|
4644
4714
|
limit: 0,
|
|
4645
4715
|
},
|
|
4646
4716
|
next: currentState.next,
|
|
4717
|
+
limit: currentState.last_get_or_create_request_config?.limit ?? 20,
|
|
4647
4718
|
});
|
|
4648
|
-
return response;
|
|
4649
4719
|
}
|
|
4650
4720
|
addActivity(request) {
|
|
4651
4721
|
return this.feedsApi.addActivity({
|
|
@@ -5048,6 +5118,7 @@ class FeedsClient extends FeedsApi {
|
|
|
5048
5118
|
super(apiClient);
|
|
5049
5119
|
this.eventDispatcher = new EventDispatcher();
|
|
5050
5120
|
this.activeFeeds = {};
|
|
5121
|
+
this.healthyConnectionChangedEventCount = 0;
|
|
5051
5122
|
this.pollFromState = (id) => this.polls_by_id.get(id);
|
|
5052
5123
|
this.connectUser = async (user, tokenProvider) => {
|
|
5053
5124
|
if (this.state.getLatestValue().connectedUser !== undefined ||
|
|
@@ -5063,7 +5134,10 @@ class FeedsClient extends FeedsApi {
|
|
|
5063
5134
|
}, this.tokenManager, this.connectionIdManager, [decodeWSEvent]);
|
|
5064
5135
|
this.wsConnection.on('all', (event) => this.eventDispatcher.dispatch(event));
|
|
5065
5136
|
const connectedEvent = await this.wsConnection.connect();
|
|
5066
|
-
this.state.partialNext({
|
|
5137
|
+
this.state.partialNext({
|
|
5138
|
+
connectedUser: connectedEvent?.me,
|
|
5139
|
+
isWsConnectionHealthy: this.wsConnection.isHealthy,
|
|
5140
|
+
});
|
|
5067
5141
|
}
|
|
5068
5142
|
catch (err) {
|
|
5069
5143
|
await this.disconnectUser();
|
|
@@ -5118,13 +5192,20 @@ class FeedsClient extends FeedsApi {
|
|
|
5118
5192
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
5119
5193
|
this.connectionIdManager.reset();
|
|
5120
5194
|
this.tokenManager.reset();
|
|
5121
|
-
this.state.partialNext({ connectedUser: undefined });
|
|
5195
|
+
this.state.partialNext({ connectedUser: undefined, isWsConnectionHealthy: false });
|
|
5122
5196
|
};
|
|
5123
5197
|
this.on = this.eventDispatcher.on;
|
|
5124
5198
|
this.off = this.eventDispatcher.off;
|
|
5125
5199
|
this.feed = (groupId, id) => {
|
|
5126
5200
|
return this.getOrCreateActiveFeed(groupId, id);
|
|
5127
5201
|
};
|
|
5202
|
+
this.updateNetworkConnectionStatus = (event) => {
|
|
5203
|
+
const networkEvent = {
|
|
5204
|
+
type: 'network.changed',
|
|
5205
|
+
online: event.type === 'online',
|
|
5206
|
+
};
|
|
5207
|
+
this.eventDispatcher.dispatch(networkEvent);
|
|
5208
|
+
};
|
|
5128
5209
|
this.getOrCreateActiveFeed = (group, id, data) => {
|
|
5129
5210
|
const fid = `${group}:${id}`;
|
|
5130
5211
|
if (this.activeFeeds[fid]) {
|
|
@@ -5136,15 +5217,9 @@ class FeedsClient extends FeedsApi {
|
|
|
5136
5217
|
return feed;
|
|
5137
5218
|
}
|
|
5138
5219
|
};
|
|
5139
|
-
this.updateNetworkConnectionStatus = (event) => {
|
|
5140
|
-
const networkEvent = {
|
|
5141
|
-
type: 'network.changed',
|
|
5142
|
-
online: event.type === 'online',
|
|
5143
|
-
};
|
|
5144
|
-
this.eventDispatcher.dispatch(networkEvent);
|
|
5145
|
-
};
|
|
5146
5220
|
this.state = new StateStore({
|
|
5147
5221
|
connectedUser: undefined,
|
|
5222
|
+
isWsConnectionHealthy: false,
|
|
5148
5223
|
});
|
|
5149
5224
|
this.moderation = new ModerationClient(apiClient);
|
|
5150
5225
|
this.tokenManager = tokenManager;
|
|
@@ -5154,6 +5229,20 @@ class FeedsClient extends FeedsApi {
|
|
|
5154
5229
|
const fid = event.fid;
|
|
5155
5230
|
const feed = typeof fid === 'string' ? this.activeFeeds[fid] : undefined;
|
|
5156
5231
|
switch (event.type) {
|
|
5232
|
+
case 'connection.changed': {
|
|
5233
|
+
const { online } = event;
|
|
5234
|
+
this.state.partialNext({ isWsConnectionHealthy: online });
|
|
5235
|
+
if (online) {
|
|
5236
|
+
this.healthyConnectionChangedEventCount++;
|
|
5237
|
+
// we skip the first event as we could potentially be querying twice
|
|
5238
|
+
if (this.healthyConnectionChangedEventCount > 1) {
|
|
5239
|
+
for (const activeFeed of Object.values(this.activeFeeds)) {
|
|
5240
|
+
activeFeed.synchronize();
|
|
5241
|
+
}
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
5244
|
+
break;
|
|
5245
|
+
}
|
|
5157
5246
|
case 'feeds.feed.created': {
|
|
5158
5247
|
if (feed)
|
|
5159
5248
|
break;
|