@amityco/ts-sdk 7.13.1-e261145.0 → 7.14.0

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 (102) hide show
  1. package/dist/@types/domains/client.d.ts +10 -1
  2. package/dist/@types/domains/client.d.ts.map +1 -1
  3. package/dist/@types/domains/feed.d.ts +17 -1
  4. package/dist/@types/domains/feed.d.ts.map +1 -1
  5. package/dist/@types/domains/message.d.ts +1 -1
  6. package/dist/@types/domains/message.d.ts.map +1 -1
  7. package/dist/@types/domains/post.d.ts +5 -0
  8. package/dist/@types/domains/post.d.ts.map +1 -1
  9. package/dist/client/api/accessTokenExpiryWatcher.d.ts +1 -1
  10. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -1
  11. package/dist/client/api/index.d.ts +2 -0
  12. package/dist/client/api/index.d.ts.map +1 -1
  13. package/dist/client/api/isSameUserId.d.ts +2 -0
  14. package/dist/client/api/isSameUserId.d.ts.map +1 -0
  15. package/dist/client/api/login.d.ts.map +1 -1
  16. package/dist/client/api/loginAsBot.d.ts.map +1 -1
  17. package/dist/client/api/loginAsVisitor.d.ts.map +1 -1
  18. package/dist/client/api/loginWithAccessToken.d.ts +28 -0
  19. package/dist/client/api/loginWithAccessToken.d.ts.map +1 -0
  20. package/dist/client/api/logout.d.ts.map +1 -1
  21. package/dist/client/api/renewTokenWithHandler.d.ts +11 -0
  22. package/dist/client/api/renewTokenWithHandler.d.ts.map +1 -0
  23. package/dist/client/api/renewWithAccessToken.d.ts +2 -0
  24. package/dist/client/api/renewWithAccessToken.d.ts.map +1 -0
  25. package/dist/client/api/resumeSession.d.ts.map +1 -1
  26. package/dist/client/api/setAccessTokenHandler.d.ts +31 -0
  27. package/dist/client/api/setAccessTokenHandler.d.ts.map +1 -0
  28. package/dist/client/api/setupLoginSubscriptions.d.ts +11 -0
  29. package/dist/client/api/setupLoginSubscriptions.d.ts.map +1 -0
  30. package/dist/client/api/tests/loginWithAccessToken.test.d.ts +2 -0
  31. package/dist/client/api/tests/loginWithAccessToken.test.d.ts.map +1 -0
  32. package/dist/client/api/validateAccessToken.d.ts +11 -0
  33. package/dist/client/api/validateAccessToken.d.ts.map +1 -0
  34. package/dist/commentRepository/api/createComment.d.ts.map +1 -1
  35. package/dist/commentRepository/api/deleteComment.d.ts.map +1 -1
  36. package/dist/commentRepository/events/utils.d.ts.map +1 -1
  37. package/dist/core/subscription.d.ts +2 -2
  38. package/dist/core/subscription.d.ts.map +1 -1
  39. package/dist/feedRepository/index.d.ts +1 -1
  40. package/dist/feedRepository/index.d.ts.map +1 -1
  41. package/dist/feedRepository/observers/getCommunityFeed/LiveCollectionController.d.ts +13 -0
  42. package/dist/feedRepository/observers/getCommunityFeed/LiveCollectionController.d.ts.map +1 -0
  43. package/dist/feedRepository/observers/getCommunityFeed/PaginationController.d.ts +5 -0
  44. package/dist/feedRepository/observers/getCommunityFeed/PaginationController.d.ts.map +1 -0
  45. package/dist/feedRepository/observers/getCommunityFeed/QueryStreamController.d.ts +15 -0
  46. package/dist/feedRepository/observers/getCommunityFeed/QueryStreamController.d.ts.map +1 -0
  47. package/dist/feedRepository/observers/getCommunityFeed.d.ts +34 -0
  48. package/dist/feedRepository/observers/getCommunityFeed.d.ts.map +1 -0
  49. package/dist/feedRepository/observers/index.d.ts +1 -0
  50. package/dist/feedRepository/observers/index.d.ts.map +1 -1
  51. package/dist/feedRepository/observers/utils.d.ts.map +1 -1
  52. package/dist/index.cjs.js +996 -386
  53. package/dist/index.esm.js +980 -370
  54. package/dist/index.umd.js +3 -3
  55. package/dist/postRepository/events/utils.d.ts.map +1 -1
  56. package/dist/postRepository/observers/utils.d.ts.map +1 -1
  57. package/dist/postRepository/utils/PostCommentCountEngine/CommentChange.d.ts +11 -0
  58. package/dist/postRepository/utils/PostCommentCountEngine/CommentChange.d.ts.map +1 -0
  59. package/dist/postRepository/utils/PostCommentCountEngine/CreateTask.d.ts +8 -0
  60. package/dist/postRepository/utils/PostCommentCountEngine/CreateTask.d.ts.map +1 -0
  61. package/dist/postRepository/utils/PostCommentCountEngine/DeleteTask.d.ts +7 -0
  62. package/dist/postRepository/utils/PostCommentCountEngine/DeleteTask.d.ts.map +1 -0
  63. package/dist/postRepository/utils/PostCommentCountEngine/PostCommentCountEngine.d.ts +19 -0
  64. package/dist/postRepository/utils/PostCommentCountEngine/PostCommentCountEngine.d.ts.map +1 -0
  65. package/dist/postRepository/utils/PostCommentCountEngine/ResetTask.d.ts +8 -0
  66. package/dist/postRepository/utils/PostCommentCountEngine/ResetTask.d.ts.map +1 -0
  67. package/dist/postRepository/utils/payload.d.ts.map +1 -1
  68. package/package.json +3 -1
  69. package/dist/commentRepository/internalApi/createComment.d.ts +0 -2
  70. package/dist/commentRepository/internalApi/createComment.d.ts.map +0 -1
  71. package/dist/commentRepository/internalApi/deleteComment.d.ts +0 -2
  72. package/dist/commentRepository/internalApi/deleteComment.d.ts.map +0 -1
  73. package/dist/commentRepository/internalApi/flagComment.d.ts +0 -2
  74. package/dist/commentRepository/internalApi/flagComment.d.ts.map +0 -1
  75. package/dist/commentRepository/internalApi/hardDeleteComment.d.ts +0 -2
  76. package/dist/commentRepository/internalApi/hardDeleteComment.d.ts.map +0 -1
  77. package/dist/commentRepository/internalApi/isCommentFlaggedByMe.d.ts +0 -2
  78. package/dist/commentRepository/internalApi/isCommentFlaggedByMe.d.ts.map +0 -1
  79. package/dist/commentRepository/internalApi/queryComments.d.ts +0 -2
  80. package/dist/commentRepository/internalApi/queryComments.d.ts.map +0 -1
  81. package/dist/commentRepository/internalApi/softDeleteComment.d.ts +0 -2
  82. package/dist/commentRepository/internalApi/softDeleteComment.d.ts.map +0 -1
  83. package/dist/commentRepository/internalApi/tests/createComment.test.d.ts +0 -2
  84. package/dist/commentRepository/internalApi/tests/createComment.test.d.ts.map +0 -1
  85. package/dist/commentRepository/internalApi/tests/deleteComment.test.d.ts +0 -2
  86. package/dist/commentRepository/internalApi/tests/deleteComment.test.d.ts.map +0 -1
  87. package/dist/commentRepository/internalApi/tests/getCommentByIds.test.d.ts +0 -2
  88. package/dist/commentRepository/internalApi/tests/getCommentByIds.test.d.ts.map +0 -1
  89. package/dist/commentRepository/internalApi/tests/getComments.test.d.ts +0 -2
  90. package/dist/commentRepository/internalApi/tests/getComments.test.d.ts.map +0 -1
  91. package/dist/commentRepository/internalApi/tests/hardDeleteComment.test.d.ts +0 -2
  92. package/dist/commentRepository/internalApi/tests/hardDeleteComment.test.d.ts.map +0 -1
  93. package/dist/commentRepository/internalApi/tests/queryComments.test.d.ts +0 -2
  94. package/dist/commentRepository/internalApi/tests/queryComments.test.d.ts.map +0 -1
  95. package/dist/commentRepository/internalApi/tests/softDeleteComment.test.d.ts +0 -2
  96. package/dist/commentRepository/internalApi/tests/softDeleteComment.test.d.ts.map +0 -1
  97. package/dist/commentRepository/internalApi/tests/updateComment.test.d.ts +0 -2
  98. package/dist/commentRepository/internalApi/tests/updateComment.test.d.ts.map +0 -1
  99. package/dist/commentRepository/internalApi/unflagComment.d.ts +0 -2
  100. package/dist/commentRepository/internalApi/unflagComment.d.ts.map +0 -1
  101. package/dist/commentRepository/internalApi/updateComment.d.ts +0 -2
  102. package/dist/commentRepository/internalApi/updateComment.d.ts.map +0 -1
package/dist/index.cjs.js CHANGED
@@ -203,6 +203,12 @@ exports.FeedSourceEnum = void 0;
203
203
  FeedSourceEnum["Community"] = "community";
204
204
  FeedSourceEnum["User"] = "user";
205
205
  })(exports.FeedSourceEnum || (exports.FeedSourceEnum = {}));
206
+ exports.FeedTypeEnum = void 0;
207
+ (function (FeedTypeEnum) {
208
+ FeedTypeEnum["Reviewing"] = "reviewing";
209
+ FeedTypeEnum["Published"] = "published";
210
+ FeedTypeEnum["Declined"] = "declined";
211
+ })(exports.FeedTypeEnum || (exports.FeedTypeEnum = {}));
206
212
 
207
213
  exports.AmityEventType = void 0;
208
214
  (function (AmityEventType) {
@@ -239,8 +245,8 @@ exports.AmityEventOrderOption = void 0;
239
245
 
240
246
  function getVersion() {
241
247
  try {
242
- // the string ''v7.13.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
243
- return 'v7.13.0-cjs';
248
+ // the string ''v7.14.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
249
+ return 'v7.14.0-cjs';
244
250
  }
245
251
  catch (error) {
246
252
  return '__dev__';
@@ -1682,10 +1688,14 @@ const getLiveReactionTopic = (post) => {
1682
1688
  };
1683
1689
  const getRoomWatcherTopic = (room) => {
1684
1690
  const user = getCurrentUser();
1691
+ if (!user)
1692
+ return;
1685
1693
  return `${getNetworkId(user)}/room/${room._id}`;
1686
1694
  };
1687
1695
  const getRoomStreamerTopic = (room) => {
1688
1696
  const user = getCurrentUser();
1697
+ if (!user)
1698
+ return;
1689
1699
  return `${getNetworkId(user)}/room/${room.roomId}/streamer`;
1690
1700
  };
1691
1701
  function subscribeTopic(topic, callback) {
@@ -1780,13 +1790,13 @@ class NetworkActivitiesWatcher {
1780
1790
  this._listener.clear();
1781
1791
  }
1782
1792
  }
1783
- let instance$7;
1793
+ let instance$8;
1784
1794
  var NetworkActivitiesWatcher$1 = {
1785
1795
  getInstance: () => {
1786
- if (!instance$7) {
1787
- instance$7 = new NetworkActivitiesWatcher();
1796
+ if (!instance$8) {
1797
+ instance$8 = new NetworkActivitiesWatcher();
1788
1798
  }
1789
- return instance$7;
1799
+ return instance$8;
1790
1800
  },
1791
1801
  };
1792
1802
 
@@ -6838,13 +6848,13 @@ class SessionWatcher {
6838
6848
  this._listener.clear();
6839
6849
  }
6840
6850
  }
6841
- let instance$6;
6851
+ let instance$7;
6842
6852
  var SessionWatcher$1 = {
6843
6853
  getInstance: () => {
6844
- if (!instance$6) {
6845
- instance$6 = new SessionWatcher();
6854
+ if (!instance$7) {
6855
+ instance$7 = new SessionWatcher();
6846
6856
  }
6847
- return instance$6;
6857
+ return instance$7;
6848
6858
  },
6849
6859
  };
6850
6860
 
@@ -7421,6 +7431,108 @@ const setVisitorClientToken = async (params) => {
7421
7431
  return { accessToken, users, userType };
7422
7432
  };
7423
7433
 
7434
+ /* begin_public_function
7435
+ id: client.logout
7436
+ */
7437
+ /**
7438
+ * ```js
7439
+ * import { Client } from '@amityco/ts-sdk';
7440
+ * const success = await Client.logout()
7441
+ * ```
7442
+ *
7443
+ * Disconnects an {@link Amity.Client} instance from ASC servers
7444
+ *
7445
+ * @returns a success boolean if disconnected
7446
+ *
7447
+ * @category Client API
7448
+ * @async
7449
+ */
7450
+ const logout = async () => {
7451
+ var _a;
7452
+ const client = getActiveClient();
7453
+ client.log('client/api/disconnectClient');
7454
+ if (client.mqtt && client.mqtt.connected) {
7455
+ client.mqtt.disconnect();
7456
+ }
7457
+ /*
7458
+ * for cases when session state is terminated (example on ban) or token expired,
7459
+ * the terminating block will set session state to terminated or for the or
7460
+ * in the case of expired token the same happens
7461
+ *
7462
+ * establishing state also ignored in cases where accessTokenExpiryWatcher
7463
+ * calls renewal. There is a possibility that renewal will be called before
7464
+ * disconnectClient finishes execution
7465
+ *
7466
+ * IMPORTANT: call this before `emitter.all.clear()`, otherwise the session
7467
+ * event will never be triggered
7468
+ */
7469
+ if (client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */)
7470
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
7471
+ client.emitter.all.clear();
7472
+ (_a = client.mqtt) === null || _a === void 0 ? void 0 : _a.removeAllListeners();
7473
+ client.userId = undefined;
7474
+ client.token = undefined;
7475
+ client.loginType = undefined;
7476
+ client.http.defaults.headers.common.Authorization = '';
7477
+ client.http.defaults.metadata = {
7478
+ tokenExpiry: '',
7479
+ isGlobalBanned: false,
7480
+ isUserDeleted: false,
7481
+ };
7482
+ if (typeof document !== 'undefined') {
7483
+ document.cookie = '_ascSession=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
7484
+ }
7485
+ /*
7486
+ * Cache should be usable if tokenExpired
7487
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#SDK-usability-based-on-Session-State
7488
+ */
7489
+ if (client.sessionState !== "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.cache) {
7490
+ client.cache = { data: {} };
7491
+ }
7492
+ return true;
7493
+ };
7494
+ /* end_public_function */
7495
+
7496
+ /**
7497
+ * Terminates {@link Amity.Client} instance
7498
+ *
7499
+ *
7500
+ *
7501
+ * @category private
7502
+ */
7503
+ const terminateClient = (terminationReason) => {
7504
+ const client = getActiveClient();
7505
+ setSessionState("terminated" /* Amity.SessionStates.TERMINATED */, terminationReason);
7506
+ if (client.http.defaults.metadata) {
7507
+ if (terminationReason === "globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */)
7508
+ client.http.defaults.metadata.isGlobalBanned = true;
7509
+ if (terminationReason === "userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */)
7510
+ client.http.defaults.metadata.isUserDeleted = true;
7511
+ }
7512
+ client.sessionHandler = undefined;
7513
+ logout();
7514
+ };
7515
+
7516
+ let currentUserType = null;
7517
+ /* begin_public_function
7518
+ id: client.get_current_user_type
7519
+ */
7520
+ const getCurrentUserType = () => {
7521
+ if (!currentUserType) {
7522
+ throw new ASCError('Connect client first', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "fatal" /* Amity.ErrorLevel.FATAL */);
7523
+ }
7524
+ return currentUserType;
7525
+ };
7526
+ /* end_public_function */
7527
+ const setCurrentUserType = (userType) => {
7528
+ currentUserType = userType;
7529
+ };
7530
+
7531
+ const setCurrentUser = ({ user, userType, }) => {
7532
+ setActiveUser(user);
7533
+ setCurrentUserType(userType);
7534
+ };
7535
+
7424
7536
  const createUserEventSubscriber = (event, callback) => {
7425
7537
  const client = getActiveClient();
7426
7538
  const filter = (data) => {
@@ -7739,13 +7851,13 @@ class AnalyticsEngine {
7739
7851
  this._eventCapturer.resetAllBuckets();
7740
7852
  }
7741
7853
  }
7742
- let instance$5;
7854
+ let instance$6;
7743
7855
  var AnalyticsEngine$1 = {
7744
7856
  getInstance: () => {
7745
- if (!instance$5) {
7746
- instance$5 = new AnalyticsEngine();
7857
+ if (!instance$6) {
7858
+ instance$6 = new AnalyticsEngine();
7747
7859
  }
7748
- return instance$5;
7860
+ return instance$6;
7749
7861
  },
7750
7862
  };
7751
7863
 
@@ -7973,12 +8085,12 @@ class MessageReadReceiptSyncEngine {
7973
8085
  }
7974
8086
  }
7975
8087
  }
7976
- let instance$4 = null;
8088
+ let instance$5 = null;
7977
8089
  var ReadReceiptSyncEngine = {
7978
8090
  getInstance: () => {
7979
- if (!instance$4)
7980
- instance$4 = new MessageReadReceiptSyncEngine();
7981
- return instance$4;
8091
+ if (!instance$5)
8092
+ instance$5 = new MessageReadReceiptSyncEngine();
8093
+ return instance$5;
7982
8094
  },
7983
8095
  };
7984
8096
 
@@ -8232,12 +8344,12 @@ class LegacyMessageReadReceiptSyncEngine {
8232
8344
  }
8233
8345
  }
8234
8346
  }
8235
- let instance$3 = null;
8347
+ let instance$4 = null;
8236
8348
  var LegacyReadReceiptSyncEngine = {
8237
8349
  getInstance: () => {
8238
- if (!instance$3)
8239
- instance$3 = new LegacyMessageReadReceiptSyncEngine();
8240
- return instance$3;
8350
+ if (!instance$4)
8351
+ instance$4 = new LegacyMessageReadReceiptSyncEngine();
8352
+ return instance$4;
8241
8353
  },
8242
8354
  };
8243
8355
 
@@ -8483,12 +8595,12 @@ class ObjectResolverEngine {
8483
8595
  this.stopResolver();
8484
8596
  }
8485
8597
  }
8486
- let instance$2 = null;
8598
+ let instance$3 = null;
8487
8599
  var ObjectResolverEngine$1 = {
8488
8600
  getInstance: () => {
8489
- if (!instance$2)
8490
- instance$2 = new ObjectResolverEngine();
8491
- return instance$2;
8601
+ if (!instance$3)
8602
+ instance$3 = new ObjectResolverEngine();
8603
+ return instance$3;
8492
8604
  },
8493
8605
  };
8494
8606
 
@@ -8638,13 +8750,13 @@ class LiveReactionSyncEngine {
8638
8750
  this.stopReactionsSync();
8639
8751
  }
8640
8752
  }
8641
- let instance$1;
8753
+ let instance$2;
8642
8754
  var ReactionSyncEngine = {
8643
8755
  getInstance: () => {
8644
- if (!instance$1) {
8645
- instance$1 = new LiveReactionSyncEngine();
8756
+ if (!instance$2) {
8757
+ instance$2 = new LiveReactionSyncEngine();
8646
8758
  }
8647
- return instance$1;
8759
+ return instance$2;
8648
8760
  },
8649
8761
  };
8650
8762
 
@@ -8666,87 +8778,6 @@ var reactionSyncEngineOnLoginHandler = () => {
8666
8778
  };
8667
8779
  };
8668
8780
 
8669
- /* begin_public_function
8670
- id: client.logout
8671
- */
8672
- /**
8673
- * ```js
8674
- * import { Client } from '@amityco/ts-sdk';
8675
- * const success = await Client.logout()
8676
- * ```
8677
- *
8678
- * Disconnects an {@link Amity.Client} instance from ASC servers
8679
- *
8680
- * @returns a success boolean if disconnected
8681
- *
8682
- * @category Client API
8683
- * @async
8684
- */
8685
- const logout = async () => {
8686
- var _a;
8687
- const client = getActiveClient();
8688
- client.log('client/api/disconnectClient');
8689
- if (client.mqtt && client.mqtt.connected) {
8690
- client.mqtt.disconnect();
8691
- }
8692
- /*
8693
- * for cases when session state is terminated (example on ban) or token expired,
8694
- * the terminating block will set session state to terminated or for the or
8695
- * in the case of expired token the same happens
8696
- *
8697
- * establishing state also ignored in cases where accessTokenExpiryWatcher
8698
- * calls renewal. There is a possibility that renewal will be called before
8699
- * disconnectClient finishes execution
8700
- *
8701
- * IMPORTANT: call this before `emitter.all.clear()`, otherwise the session
8702
- * event will never be triggered
8703
- */
8704
- if (client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */)
8705
- setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
8706
- client.emitter.all.clear();
8707
- (_a = client.mqtt) === null || _a === void 0 ? void 0 : _a.removeAllListeners();
8708
- client.userId = undefined;
8709
- client.token = undefined;
8710
- client.http.defaults.headers.common.Authorization = '';
8711
- client.http.defaults.metadata = {
8712
- tokenExpiry: '',
8713
- isGlobalBanned: false,
8714
- isUserDeleted: false,
8715
- };
8716
- if (typeof document !== 'undefined') {
8717
- document.cookie = '_ascSession=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
8718
- }
8719
- /*
8720
- * Cache should be usable if tokenExpired
8721
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#SDK-usability-based-on-Session-State
8722
- */
8723
- if (client.sessionState !== "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.cache) {
8724
- client.cache = { data: {} };
8725
- }
8726
- return true;
8727
- };
8728
- /* end_public_function */
8729
-
8730
- /**
8731
- * Terminates {@link Amity.Client} instance
8732
- *
8733
- *
8734
- *
8735
- * @category private
8736
- */
8737
- const terminateClient = (terminationReason) => {
8738
- const client = getActiveClient();
8739
- setSessionState("terminated" /* Amity.SessionStates.TERMINATED */, terminationReason);
8740
- if (client.http.defaults.metadata) {
8741
- if (terminationReason === "globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */)
8742
- client.http.defaults.metadata.isGlobalBanned = true;
8743
- if (terminationReason === "userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */)
8744
- client.http.defaults.metadata.isUserDeleted = true;
8745
- }
8746
- client.sessionHandler = undefined;
8747
- logout();
8748
- };
8749
-
8750
8781
  const EVENTS = [
8751
8782
  'disconnected',
8752
8783
  'error',
@@ -8876,24 +8907,50 @@ const removeChannelMarkerCache = (channel) => {
8876
8907
  dropFromCache(['channelMarker', 'get', id], true);
8877
8908
  };
8878
8909
 
8879
- let currentUserType = null;
8880
- /* begin_public_function
8881
- id: client.get_current_user_type
8882
- */
8883
- const getCurrentUserType = () => {
8884
- if (!currentUserType) {
8885
- throw new ASCError('Connect client first', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "fatal" /* Amity.ErrorLevel.FATAL */);
8910
+ /**
8911
+ * Sets up all login-related event subscriptions
8912
+ * This includes handlers for user bans, deletions, token events, and various engine initializations
8913
+ *
8914
+ * @param unsubWatcher - The unsubscriber function for the access token expiry watcher
8915
+ * @returns Array of unsubscriber functions for all registered subscriptions
8916
+ *
8917
+ * @category private
8918
+ */
8919
+ const setupLoginSubscriptions = (unsubWatcher) => {
8920
+ const client = getActiveClient();
8921
+ const subscriptions = [];
8922
+ subscriptions.push(
8923
+ // GLOBAL_BAN
8924
+ onClientBanned((_) => {
8925
+ terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
8926
+ subscriptions.forEach(fn => fn());
8927
+ unsubWatcher();
8928
+ }), onTokenTerminated(_ => {
8929
+ terminateClient();
8930
+ subscriptions.forEach(fn => fn());
8931
+ unsubWatcher();
8932
+ }), onUserDeleted$2((user) => {
8933
+ if (user.userId === client.userId) {
8934
+ terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
8935
+ subscriptions.forEach(fn => fn());
8936
+ unsubWatcher();
8937
+ }
8938
+ }), onTokenExpired(state => {
8939
+ SessionWatcher$1.getInstance().setSessionState(state);
8940
+ logout();
8941
+ subscriptions.forEach(fn => fn());
8942
+ }),
8943
+ // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
8944
+ // the channel because currently backend can't handle this, so every time a user is banned from
8945
+ // a channel or the channel is deleted the channel's unread count will not be reset to zero
8946
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler());
8947
+ if (client.useLegacyUnreadCount) {
8948
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
8886
8949
  }
8887
- return currentUserType;
8888
- };
8889
- /* end_public_function */
8890
- const setCurrentUserType = (userType) => {
8891
- currentUserType = userType;
8892
- };
8893
-
8894
- const setCurrentUser = ({ user, userType, }) => {
8895
- setActiveUser(user);
8896
- setCurrentUserType(userType);
8950
+ else {
8951
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
8952
+ }
8953
+ return subscriptions;
8897
8954
  };
8898
8955
 
8899
8956
  /* eslint-disable no-param-reassign */
@@ -8902,8 +8959,8 @@ const setCurrentUser = ({ user, userType, }) => {
8902
8959
  * than the one already connected, in which case the existing subscriptions need
8903
8960
  * to be cleared
8904
8961
  */
8905
- let subscriptions$3 = [];
8906
- async function runMqtt$1() {
8962
+ let subscriptions$4 = [];
8963
+ async function runMqtt$2() {
8907
8964
  await modifyMqttConnection();
8908
8965
  }
8909
8966
  /* begin_public_function
@@ -8937,8 +8994,8 @@ const login = async (params, sessionHandler, config) => {
8937
8994
  if (client.userId && client.userId !== params.userId) {
8938
8995
  await logout();
8939
8996
  // Remove subscription to ban and delete
8940
- subscriptions$3.forEach(fn => fn());
8941
- subscriptions$3 = [];
8997
+ subscriptions$4.forEach(fn => fn());
8998
+ subscriptions$4 = [];
8942
8999
  }
8943
9000
  // default values
8944
9001
  const defaultDeviceId = await getDeviceId();
@@ -8963,11 +9020,12 @@ const login = async (params, sessionHandler, config) => {
8963
9020
  }
8964
9021
  client.userId = user.userId;
8965
9022
  client.sessionHandler = sessionHandler;
9023
+ client.loginType = 'userId';
8966
9024
  /*
8967
9025
  * Cannot push to subscriptions as watcher needs to continue working even if
8968
9026
  * token expires
8969
9027
  */
8970
- unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
9028
+ unsubWatcher = client.accessTokenExpiryWatcher();
8971
9029
  setCurrentUser({ user, userType });
8972
9030
  }
8973
9031
  catch (error) {
@@ -8980,40 +9038,11 @@ const login = async (params, sessionHandler, config) => {
8980
9038
  throw error;
8981
9039
  }
8982
9040
  if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
8983
- runMqtt$1();
9041
+ runMqtt$2();
8984
9042
  }
8985
9043
  await initializeMessagePreviewSetting();
8986
- if (subscriptions$3.length === 0) {
8987
- subscriptions$3.push(
8988
- // GLOBAL_BAN
8989
- onClientBanned((_) => {
8990
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
8991
- subscriptions$3.forEach(fn => fn());
8992
- unsubWatcher();
8993
- }), onTokenTerminated(_ => {
8994
- terminateClient();
8995
- subscriptions$3.forEach(fn => fn());
8996
- unsubWatcher();
8997
- }), onUserDeleted$2((user) => {
8998
- if (user.userId === client.userId) {
8999
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
9000
- subscriptions$3.forEach(fn => fn());
9001
- unsubWatcher();
9002
- }
9003
- }), onTokenExpired(state => {
9004
- SessionWatcher$1.getInstance().setSessionState(state);
9005
- logout();
9006
- subscriptions$3.forEach(fn => fn());
9007
- }),
9008
- // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
9009
- // the channel because currently backend can't handle this, so every time a user is banned from
9010
- // a channel or the channel is deleted the channel's unread count will not be reset to zero
9011
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler());
9012
- if (client.useLegacyUnreadCount) {
9013
- subscriptions$3.push(readReceiptSyncEngineOnLoginHandler());
9014
- }
9015
- else
9016
- subscriptions$3.push(legacyReadReceiptSyncEngineOnLoginHandler());
9044
+ if (subscriptions$4.length === 0) {
9045
+ subscriptions$4 = setupLoginSubscriptions(unsubWatcher);
9017
9046
  }
9018
9047
  return true;
9019
9048
  };
@@ -9025,7 +9054,7 @@ const login = async (params, sessionHandler, config) => {
9025
9054
  * than the one already connected, in which case the existing subscriptions need
9026
9055
  * to be cleared
9027
9056
  */
9028
- const subscriptions$2 = [];
9057
+ const subscriptions$3 = [];
9029
9058
  /* begin_public_function
9030
9059
  id: client.loginAsVisitor
9031
9060
  */
@@ -9068,11 +9097,12 @@ const loginAsVisitor = async (params) => {
9068
9097
  [user] = users;
9069
9098
  client.userId = user.userId;
9070
9099
  client.sessionHandler = params.sessionHandler;
9100
+ client.loginType = 'userId';
9071
9101
  /*
9072
9102
  * Cannot push to subscriptions as watcher needs to continue working even if
9073
9103
  * token expires
9074
9104
  */
9075
- unsubWatcher = client.accessTokenExpiryWatcher(params.sessionHandler);
9105
+ unsubWatcher = client.accessTokenExpiryWatcher();
9076
9106
  setCurrentUser({ user, userType });
9077
9107
  }
9078
9108
  catch (error) {
@@ -9085,16 +9115,16 @@ const loginAsVisitor = async (params) => {
9085
9115
  throw error;
9086
9116
  }
9087
9117
  await initializeMessagePreviewSetting();
9088
- if (subscriptions$2.length === 0) {
9118
+ if (subscriptions$3.length === 0) {
9089
9119
  // handling internal SDK events
9090
- subscriptions$2.push(onTokenTerminated(_ => {
9120
+ subscriptions$3.push(onTokenTerminated(_ => {
9091
9121
  terminateClient();
9092
- subscriptions$2.forEach(fn => fn());
9122
+ subscriptions$3.forEach(fn => fn());
9093
9123
  unsubWatcher();
9094
9124
  }), onTokenExpired(state => {
9095
9125
  SessionWatcher$1.getInstance().setSessionState(state);
9096
9126
  logout();
9097
- subscriptions$2.forEach(fn => fn());
9127
+ subscriptions$3.forEach(fn => fn());
9098
9128
  }));
9099
9129
  }
9100
9130
  return true;
@@ -9123,7 +9153,7 @@ const renewal = () => {
9123
9153
  * Per instance of Renewal, only one renewal is allowed
9124
9154
  */
9125
9155
  const renewToken = async (authToken) => {
9126
- const { userId, displayName } = getCurrentUser();
9156
+ const { userId, displayName } = getActiveUser();
9127
9157
  const deviceId = await getDeviceId();
9128
9158
  const params = { userId, displayName, authToken, deviceId };
9129
9159
  if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
@@ -9198,6 +9228,242 @@ const renewal = () => {
9198
9228
  };
9199
9229
  /* end_public_function */
9200
9230
 
9231
+ const validateAccessToken = async ({ token, userId }) => {
9232
+ const client = getActiveClient();
9233
+ // Validate token using sessions API
9234
+ await client.http.get('/api/v3/sessions', {
9235
+ headers: {
9236
+ Authorization: `Bearer ${token.accessToken}`,
9237
+ },
9238
+ });
9239
+ // Get user details
9240
+ const { data: { users }, } = await client.http.get(`/api/v3/users/${userId}`, {
9241
+ headers: {
9242
+ Authorization: `Bearer ${token.accessToken}`,
9243
+ },
9244
+ });
9245
+ const user = users.find((u) => u.userId === userId);
9246
+ client.http.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
9247
+ client.http.defaults.metadata = {
9248
+ tokenExpiry: token.expiresAt,
9249
+ isGlobalBanned: false,
9250
+ isUserDeleted: false,
9251
+ };
9252
+ client.upload.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
9253
+ client.upload.defaults.metadata = {
9254
+ tokenExpiry: token.expiresAt,
9255
+ isGlobalBanned: false,
9256
+ isUserDeleted: false,
9257
+ };
9258
+ client.token = token;
9259
+ return user;
9260
+ };
9261
+
9262
+ const isSameUserId = (token) => {
9263
+ var _a;
9264
+ const client = getActiveClient();
9265
+ const decoded = jwtDecode__default["default"](token);
9266
+ return ((_a = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _a === void 0 ? void 0 : _a.publicUserId) === client.userId;
9267
+ };
9268
+
9269
+ let subscriptions$2 = [];
9270
+ async function runMqtt$1() {
9271
+ await modifyMqttConnection();
9272
+ }
9273
+ /* begin_public_function
9274
+ id: client.loginWithAccessToken
9275
+ */
9276
+ /**
9277
+ * ```js
9278
+ * import { loginWithAccessToken } from '@amityco/ts-sdk'
9279
+ * const success = await loginWithAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...')
9280
+ * ```
9281
+ *
9282
+ * Authenticates a user using a pre-existing access token, allowing direct login without user credentials.
9283
+ * Designed for customers who manage access tokens on their own backend.
9284
+ *
9285
+ * @param accessToken JWT access token signed by customer's backend containing user identity
9286
+ * @returns true if authentication is successful
9287
+ *
9288
+ * @category Client API
9289
+ * @async
9290
+ */
9291
+ const loginWithAccessToken = async (accessToken) => {
9292
+ var _a, _b;
9293
+ const client = getActiveClient();
9294
+ let unsubWatcher;
9295
+ client.log('client/api/loginWithAccessToken', {
9296
+ apiKey: client.apiKey,
9297
+ sessionState: client.sessionState,
9298
+ });
9299
+ // Validate input
9300
+ if (!accessToken || typeof accessToken !== 'string' || accessToken.trim() === '') {
9301
+ throw new ASCError('Access token must be a non-empty string', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9302
+ }
9303
+ let decoded;
9304
+ try {
9305
+ decoded = jwtDecode__default["default"](accessToken);
9306
+ }
9307
+ catch (error) {
9308
+ throw new ASCError('Invalid access token format', 400100 /* Amity.ServerError.UNAUTHORIZED */, "error" /* Amity.ErrorLevel.ERROR */);
9309
+ }
9310
+ // Extract userId from token
9311
+ const userId = ((_a = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _a === void 0 ? void 0 : _a.publicUserId) || ((_b = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _b === void 0 ? void 0 : _b.userId);
9312
+ if (!userId) {
9313
+ throw new ASCError('Access token does not contain userId', 400100 /* Amity.ServerError.UNAUTHORIZED */, "error" /* Amity.ErrorLevel.ERROR */);
9314
+ }
9315
+ // Handle existing connected user
9316
+ if (client.userId) {
9317
+ const sameUser = isSameUserId(accessToken);
9318
+ if (!sameUser) {
9319
+ // Different user - do full logout
9320
+ await logout();
9321
+ }
9322
+ }
9323
+ try {
9324
+ // Set state to establishing
9325
+ setSessionState("establishing" /* Amity.SessionStates.ESTABLISHING */);
9326
+ // Prepare token object for validation
9327
+ const tokenObject = {
9328
+ accessToken,
9329
+ issuedAt: decoded.iat ? new Date(decoded.iat * 1000).toISOString() : new Date().toISOString(),
9330
+ expiresAt: new Date(decoded.exp * 1000).toISOString(),
9331
+ };
9332
+ // Validate token and get user
9333
+ const user = await validateAccessToken({
9334
+ token: tokenObject,
9335
+ userId,
9336
+ });
9337
+ if (user == null) {
9338
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
9339
+ throw new ASCError(`User ${userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9340
+ }
9341
+ if (user.isDeleted) {
9342
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
9343
+ throw new ASCError(`User ${userId} has been deleted`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9344
+ }
9345
+ if (user.isGlobalBanned) {
9346
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
9347
+ throw new ASCError(`User ${userId} is globally banned`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9348
+ }
9349
+ // Set userId and login method flag
9350
+ client.userId = user.userId;
9351
+ // Set login method flag to 'accessToken' in platform-specific login session
9352
+ client.loginType = 'accessToken';
9353
+ // This will be used by the access token handler to determine if token renewal should be invoked
9354
+ // Set active user
9355
+ setActiveUser(user);
9356
+ unsubWatcher = client.accessTokenExpiryWatcher();
9357
+ setSessionState("established" /* Amity.SessionStates.ESTABLISHED */);
9358
+ }
9359
+ catch (error) {
9360
+ // If error occurs, revert session state to not logged in
9361
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
9362
+ // Re-throw if it's already an ASCError
9363
+ if (error instanceof ASCError) {
9364
+ throw error;
9365
+ }
9366
+ // Wrap other errors
9367
+ throw new ASCError((error instanceof Error ? error.message : undefined) || 'Login with access token failed', 400100 /* Amity.ServerError.UNAUTHORIZED */, "error" /* Amity.ErrorLevel.ERROR */);
9368
+ }
9369
+ runMqtt$1();
9370
+ await initializeMessagePreviewSetting();
9371
+ if (subscriptions$2.length === 0) {
9372
+ subscriptions$2 = setupLoginSubscriptions(unsubWatcher);
9373
+ }
9374
+ return true;
9375
+ };
9376
+ /* end_public_function */
9377
+
9378
+ /* begin_public_function
9379
+ id: client.renew_with_accessToken
9380
+ */
9381
+ /*
9382
+ * Renewal defintion accepted by SessionHandler interface
9383
+ *
9384
+ * Tech Spec:
9385
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
9386
+ *
9387
+ * @category private
9388
+ */
9389
+ const renewWithAccessToken = async (accessToken) => {
9390
+ var _a, _b;
9391
+ const client = getActiveClient();
9392
+ client.log('initiating access token renewal');
9393
+ /*
9394
+ * Renews a token if it is hasn't been renewed before. Also marks token as
9395
+ * renewed once done
9396
+ * Per instance of Renewal, only one renewal is allowed
9397
+ */
9398
+ // Validate input
9399
+ if (!accessToken || typeof accessToken !== 'string' || accessToken.trim() === '') {
9400
+ throw new ASCError('Access token must be a non-empty string', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9401
+ }
9402
+ let decoded;
9403
+ try {
9404
+ decoded = jwtDecode__default["default"](accessToken);
9405
+ }
9406
+ catch (error) {
9407
+ throw new ASCError('Invalid access token format', 400100 /* Amity.ServerError.UNAUTHORIZED */, "error" /* Amity.ErrorLevel.ERROR */);
9408
+ }
9409
+ // Extract userId from token
9410
+ const userId = ((_a = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _a === void 0 ? void 0 : _a.publicUserId) || ((_b = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _b === void 0 ? void 0 : _b.userId);
9411
+ if (!userId) {
9412
+ throw new ASCError('Access token does not contain userId', 400100 /* Amity.ServerError.UNAUTHORIZED */, "error" /* Amity.ErrorLevel.ERROR */);
9413
+ }
9414
+ // Handle existing connected user
9415
+ if (client.userId) {
9416
+ const sameUser = isSameUserId(accessToken);
9417
+ if (!sameUser) {
9418
+ // Different user - do full logout
9419
+ await logout();
9420
+ }
9421
+ }
9422
+ const tokenObject = {
9423
+ accessToken,
9424
+ issuedAt: decoded.iat ? new Date(decoded.iat * 1000).toISOString() : new Date().toISOString(),
9425
+ expiresAt: new Date(decoded.exp * 1000).toISOString(),
9426
+ };
9427
+ if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
9428
+ await loginWithAccessToken(accessToken);
9429
+ }
9430
+ else {
9431
+ // about to expire
9432
+ await validateAccessToken({
9433
+ token: tokenObject,
9434
+ userId,
9435
+ });
9436
+ }
9437
+ };
9438
+ /* end_public_function */
9439
+
9440
+ /**
9441
+ * Helper function to renew access token using the accessTokenHandler
9442
+ * Handles error catching and logging
9443
+ *
9444
+ * @param useScheduledTask - Whether to wrap renewal in scheduleTask (for token expired case)
9445
+ * @category private
9446
+ */
9447
+ const renewTokenWithHandler = async ({ useScheduledTask = false, }) => {
9448
+ const client = getActiveClient();
9449
+ if (!client.userId || !client.accessTokenHandler) {
9450
+ return;
9451
+ }
9452
+ try {
9453
+ const newToken = await client.accessTokenHandler.onTokenRenew(client.userId);
9454
+ if (useScheduledTask) {
9455
+ scheduleTask(() => renewWithAccessToken(newToken));
9456
+ }
9457
+ else {
9458
+ renewWithAccessToken(newToken);
9459
+ }
9460
+ }
9461
+ catch (error) {
9462
+ client.log('Proactive token renewal failed, will retry when token expires', error);
9463
+ // Will fallback to expired token flow
9464
+ }
9465
+ };
9466
+
9201
9467
  const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
9202
9468
  const COMPENSATED_DELAY = 5 * MINUTE;
9203
9469
  /*
@@ -9233,10 +9499,11 @@ const isAboutToExpire = (params) => {
9233
9499
  *
9234
9500
  * @category private
9235
9501
  */
9236
- const accessTokenExpiryWatcher = (sessionHandler) => {
9237
- const interval = setInterval(() => {
9502
+ const accessTokenExpiryWatcher = () => {
9503
+ const interval = setInterval(async () => {
9238
9504
  const client = getActiveClient();
9239
- if (!client.token)
9505
+ const { sessionHandler, accessTokenHandler, loginType } = client;
9506
+ if (!client.token || !client.userId)
9240
9507
  return;
9241
9508
  const { issuedAt, expiresAt } = client.token;
9242
9509
  if (isExpired(expiresAt)) {
@@ -9247,18 +9514,38 @@ const accessTokenExpiryWatcher = (sessionHandler) => {
9247
9514
  */
9248
9515
  fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
9249
9516
  /*
9250
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
9251
- *
9252
- * Why sechduled task?
9253
- * Since fireEvent is scheduled, it will be called
9254
- * after sessionHandler leading to an invalid state change from
9255
- * establishing to tokenExpired
9517
+ * Check loginType to determine which handler to use:
9518
+ * - 'accessToken' = use accessTokenHandler
9519
+ * - 'userId' = use sessionHandler
9256
9520
  */
9257
- scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
9521
+ if (loginType === 'accessToken' && accessTokenHandler) {
9522
+ await renewTokenWithHandler({ useScheduledTask: false });
9523
+ }
9524
+ else if (loginType === 'userId' && sessionHandler) {
9525
+ /*
9526
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
9527
+ *
9528
+ * Why scheduled task?
9529
+ * Since fireEvent is scheduled, it will be called
9530
+ * after sessionHandler leading to an invalid state change from
9531
+ * establishing to tokenExpired
9532
+ */
9533
+ scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
9534
+ }
9258
9535
  return;
9259
9536
  }
9260
9537
  if (isAboutToExpire({ expiresAt, issuedAt })) {
9261
- sessionHandler.sessionWillRenewAccessToken(renewal());
9538
+ /*
9539
+ * Check loginType to determine which handler to use for proactive renewal:
9540
+ * - 'accessToken' = use accessTokenHandler
9541
+ * - 'userId' = use sessionHandler
9542
+ */
9543
+ if (loginType === 'accessToken' && accessTokenHandler) {
9544
+ await renewTokenWithHandler({ useScheduledTask: false });
9545
+ }
9546
+ else if (loginType === 'userId' && sessionHandler) {
9547
+ sessionHandler.sessionWillRenewAccessToken(renewal());
9548
+ }
9262
9549
  }
9263
9550
  }, ACCESS_TOKEN_WATCHER_INTERVAL);
9264
9551
  return () => clearInterval(interval);
@@ -9791,6 +10078,7 @@ const secureLogout = async () => {
9791
10078
  };
9792
10079
  /* end_public_function */
9793
10080
 
10081
+ /* eslint-disable no-param-reassign */
9794
10082
  /*
9795
10083
  * declared earlier to accomodate case when logging in with a different user
9796
10084
  * than the one already connected, in which case the existing subscriptions need
@@ -9800,38 +10088,6 @@ let subscriptions$1 = [];
9800
10088
  async function runMqtt() {
9801
10089
  await modifyMqttConnection();
9802
10090
  }
9803
- const isSameUserId = (token) => {
9804
- var _a;
9805
- const client = getActiveClient();
9806
- const decoded = jwtDecode__default["default"](token);
9807
- return ((_a = decoded === null || decoded === void 0 ? void 0 : decoded.user) === null || _a === void 0 ? void 0 : _a.publicUserId) === client.userId;
9808
- };
9809
- const validateAccessToken = async ({ token, userId }) => {
9810
- const client = getActiveClient();
9811
- // begin establishing session
9812
- setSessionState("establishing" /* Amity.SessionStates.ESTABLISHING */);
9813
- const { data: { users }, } = await client.http.get(`/api/v3/users/${userId}`, {
9814
- headers: {
9815
- Authorization: `Bearer ${token.accessToken}`,
9816
- },
9817
- });
9818
- const user = users.find((u) => u.userId === userId);
9819
- client.http.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
9820
- client.http.defaults.metadata = {
9821
- tokenExpiry: token.expiresAt,
9822
- isGlobalBanned: false,
9823
- isUserDeleted: false,
9824
- };
9825
- client.upload.defaults.headers.common.Authorization = `Bearer ${token.accessToken}`;
9826
- client.upload.defaults.metadata = {
9827
- tokenExpiry: token.expiresAt,
9828
- isGlobalBanned: false,
9829
- isUserDeleted: false,
9830
- };
9831
- client.token = token;
9832
- setSessionState("established" /* Amity.SessionStates.ESTABLISHED */);
9833
- return user;
9834
- };
9835
10091
  /* begin_public_function
9836
10092
  id: client.resumeSession
9837
10093
  */
@@ -9880,6 +10136,7 @@ const resumeSession = async (params, sessionHandler, config) => {
9880
10136
  }
9881
10137
  }
9882
10138
  try {
10139
+ setSessionState("establishing" /* Amity.SessionStates.ESTABLISHING */);
9883
10140
  const user = await validateAccessToken(params);
9884
10141
  if (user == null) {
9885
10142
  throw new ASCError(`${params.userId} has not been found`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
@@ -9986,13 +10243,13 @@ class GlobalFileAccessType {
9986
10243
  }
9987
10244
  }
9988
10245
  _GlobalFileAccessType_fileAccessType = new WeakMap();
9989
- let instance;
10246
+ let instance$1;
9990
10247
  var GlobalFileAccessType$1 = {
9991
10248
  getInstance: () => {
9992
- if (!instance) {
9993
- instance = new GlobalFileAccessType();
10249
+ if (!instance$1) {
10250
+ instance$1 = new GlobalFileAccessType();
9994
10251
  }
9995
- return instance;
10252
+ return instance$1;
9996
10253
  },
9997
10254
  };
9998
10255
 
@@ -10170,11 +10427,12 @@ const loginAsBot = async (params) => {
10170
10427
  [user] = users;
10171
10428
  client.userId = user.userId;
10172
10429
  client.sessionHandler = params.sessionHandler;
10430
+ client.loginType = 'userId';
10173
10431
  /*
10174
10432
  * Cannot push to subscriptions as watcher needs to continue working even if
10175
10433
  * token expires
10176
10434
  */
10177
- unsubWatcher = client.accessTokenExpiryWatcher(params.sessionHandler);
10435
+ unsubWatcher = client.accessTokenExpiryWatcher();
10178
10436
  setCurrentUser({ user, userType });
10179
10437
  }
10180
10438
  catch (error) {
@@ -10203,6 +10461,53 @@ const loginAsBot = async (params) => {
10203
10461
  };
10204
10462
  /* end_public_function */
10205
10463
 
10464
+ /* begin_public_function
10465
+ id: client.setAccessTokenHandler
10466
+ */
10467
+ /**
10468
+ * ```js
10469
+ * import { setAccessTokenHandler } from '@amityco/ts-sdk'
10470
+ *
10471
+ * const tokenHandler = {
10472
+ * async onTokenRenew() {
10473
+ * const response = await fetch('https://your-backend.com/api/refresh-token', {
10474
+ * method: 'POST',
10475
+ * credentials: 'include',
10476
+ * });
10477
+ * const data = await response.json();
10478
+ * return data.accessToken;
10479
+ * }
10480
+ * };
10481
+ *
10482
+ * setAccessTokenHandler(tokenHandler);
10483
+ * ```
10484
+ *
10485
+ * Registers a custom handler for managing access token renewal and expiration events.
10486
+ * This enables automatic token refresh and graceful handling of expired tokens.
10487
+ *
10488
+ * Must be called before loginWithAccessToken() to ensure the handler is available
10489
+ * when token expiry is detected.
10490
+ *
10491
+ * @param accessTokenHandler Handler object implementing token renewal callbacks
10492
+ * @returns void
10493
+ *
10494
+ * @category Client API
10495
+ */
10496
+ const setAccessTokenHandler = (accessTokenHandler) => {
10497
+ const client = getActiveClient();
10498
+ client.log('client/api/setAccessTokenHandler', {
10499
+ apiKey: client.apiKey,
10500
+ sessionState: client.sessionState,
10501
+ hasOnTokenRenew: typeof (accessTokenHandler === null || accessTokenHandler === void 0 ? void 0 : accessTokenHandler.onTokenRenew) === 'function',
10502
+ });
10503
+ // Validate handler has required method
10504
+ if (!accessTokenHandler || typeof accessTokenHandler.onTokenRenew !== 'function') {
10505
+ throw new Error('AccessTokenHandler must implement onTokenRenew() method');
10506
+ }
10507
+ // Register the handler
10508
+ client.accessTokenHandler = accessTokenHandler;
10509
+ };
10510
+
10206
10511
  /**
10207
10512
  * ```js
10208
10513
  * import { onChannelMarkerFetched } from '@amityco/ts-sdk'
@@ -10562,6 +10867,7 @@ var index$r = /*#__PURE__*/Object.freeze({
10562
10867
  setActiveUser: setActiveUser,
10563
10868
  createClient: createClient,
10564
10869
  login: login,
10870
+ loginWithAccessToken: loginWithAccessToken,
10565
10871
  logout: logout,
10566
10872
  secureLogout: secureLogout,
10567
10873
  resumeSession: resumeSession,
@@ -10580,6 +10886,7 @@ var index$r = /*#__PURE__*/Object.freeze({
10580
10886
  getCurrentUser: getCurrentUser,
10581
10887
  getCurrentUserType: getCurrentUserType,
10582
10888
  setCurrentUserType: setCurrentUserType,
10889
+ setAccessTokenHandler: setAccessTokenHandler,
10583
10890
  onConnectionError: onConnectionError,
10584
10891
  onClientDisconnected: onClientDisconnected,
10585
10892
  onClientBanned: onClientBanned,
@@ -12612,7 +12919,7 @@ const getWatchSessionStorage = () => {
12612
12919
  return storageInstance;
12613
12920
  };
12614
12921
 
12615
- const privateKey = "MIIEpQIBAAKCAQEAwAEc/oZgYIvKSUG/C3mONYLR4ZPgAjMEX4bJ+xqqakUDRtqlNO+eZs2blQ1Ko0DBkqPExyQezvjibH5W2UZBV5RaBTlTcNVKTToMBEGesAfaEcM3qUyQHxdbFYZv6P4sb14dcwxTQ8usmaV8ooiR1Fcaso5ZWYcZ8Hb46FbQ7OoVumsBtPWwfZ4f003o5VCl6AIM6lcLv9UDLlFVYhE+PeXpRHtfWlGqxMvqC9oinlwhL6nWv6VjQXW4nhcib72dPBzfHT7k/PMKto2SxALYdb68ENiAGuJLWi3AUHSyYCJK2w7wIlWfJUAI0v26ub10IpExr6D5QuW2577jjP93iwIDAQABAoIBAFWfqXhwIIatkFY+9Z1+ZcbDQimgsmMIsUiQaX6Lk7e0cxOj6czDlxYtVtaPiNtow2pLkjNkjkCqiP7tEHnwdK9DvylZOTa2R15NJpK3WLcTqVIGhsn/FL5owfvFah6zSsmXZParZm5zY9NZE03ALZhOB9/cz0e3kf/EbpfeL2mW7MApyiUt5i09ycchroOpcWp73ipIxvgigtZyUGFmsQicWhUs28F0D7w4Qfk76yG3nqXeb+BAMhCaIaa/k/aAxhiZG/ygEQWQrcC8gfe+jyicMAQPDEVS9YuUMGsLjIjKuVLZzp2xirQnhc2i2zVNEIvG6soprPOBEMQugzrtX5ECgYEA3b7KAbBIbDl1e4ZSCWhHdHkiWVZHaopsR/LhqDDNhXjWjq3AesgV6k0j9EdziMn/HmmOso0bz99GTV3JZf4A9ztTLumJlkHbdVtlgOqSjrFLj12rH9KXTheyIhWSpUmm8+WB1xasFbqpvJaGo7F3pd2Fqj1XR4mp5BO7c/t7LJ0CgYEA3aouEzXQ9THRKYocdfY69EI1Il1t/d/RSqqd9BxEjxBgxkM13ZiYIn/R4WW/nCUrlmhxG44Aa2Gob4Ahfsui2xKTg/g/3Zk/rAxAEGkfOLGoenaJMD41fH4wUq3FRYwkvnaMb9Hd6f/TlBHslIRa2NN58bSBGJCyBP2b59+2+EcCgYEAixDVRXvV37GlYUOa/XVdosk5Zoe6oDGRuQm0xbNdoUBoZvDHDvme7ONWEiQha/8qtVsD+CyQ7awcPfb8kK9c0bBt+bTS6d4BkTcxkEkMgtrkBVR8Nqfu5jXsLH4VCv4G61zbMhZw8+ut+az5YX2yCN7Frj9sFlxapMRPQmzMEe0CgYEAumsAzM8ZqNv4mAK65Mnr0rhLj1cbxcKRdUYACOgtEFQpzxN/HZnTeFAe5nx3pI3uFlRHq3DFEYnT6dHMWaJQmAULYpVIwMi9L6gtyJ9fzoI6uqMtxRDMUqKdaSsTGOY/kJ6KhQ/unXi1K3XXjR+yd1+C0q+HUm1+CYxvrZYLfskCgYEArsEy+IQOiqniJ0NE2vVUF+UK/IRZaic9YKcpov5Ot7Vvzm/MnnW4N1ljVskocETBWMmPUvNSExVjPebi+rxd8fa5kY8BJScPTzMFbunZn/wjtGdcM10qdlVQ9doG61A/9P3ezFKCfS4AvF/H/59LcSx2Bh28fp3/efiVIOpVd4Y=";
12922
+ const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHo80SecH7FuF2\nhFYnb+l26/VN8UMLXAQFLnxciNTEwkGVFMpdezlH8rU2HtUJL4RETogbAOLVY0XM\njs6sPn8G1nALmh9qeDpUtVqFOVtBHxEZ910TLOtQiunjqJKO5nWdqZ71EC3OFluR\niGQkO84BiIFbv37ub7xl3S8XarbtKoLcyVpkDHi+1wx1pgCAn6gtBUgckPL5NR8j\nLseabl3HAXQfhTCKo4tmOFM2Dxwl1IUMmIJrJg/aIU/U0tj/1Eoo7mG0JcNWX19l\nW3EecCbi0ncCJOrkUdwlBrcjaMayaX/ubEwyUeTGiLdyc4L3GRLHjyK8xgVNXRMH\nbZWJ2a5NAgMBAAECggEASxuE+35zTFO/XydKgmvIGcWL9FbgMlXb7Vcf0nBoG945\nbiz0NVc2paraIhJXc608xbYF3qLmtAE1MVBI0ORyRdBHNxY024l/6H6SH60Ed+uI\nM4ysp5ourY6Vj+DLwpdRiI9YDjqYAQDIUmhNxJP7XPhOMoZI6st+xZQBM34ic/bv\nAMSJm9OZphSp3+qXVkFZztr2mxD2EZSJJLYxi8BCdgM2qhazalbcJ6zDKHCZWVWm\n8RRxDGldyMb/237JxETzP40tAlzOZDmBAbUgEnurDJ93RVDIE3rbZUshwgeQd18a\nem096mWgvB1AIKYgsTAR3pw+V19YWAjq/glP6fz8wQKBgQD/oQq+ukKF0PRgBeM5\ngeTjSwsdGppQLmf5ndujvoiz/TpdjDEPu6R8kigQr1rG2t4K/yfdZoI8RdmJD1al\n3Q7N9hofooSy4rj6E3txzWZCHJjHad2cnCp/O26HiReGAl7wTcfTmNdiFHhZQzm5\nJBkvWAiwuvQMNfEbnXxw6/vIDwKBgQDH7fX8gsc77JLvAWgp1MaQN/sbqVb6JeT1\nFQfR8E/WFCSmzQBtNzd5KgYuCeelwr/8DyYytvN2BzCYZXp73gI1jF3YlW5jVn74\nOY6TwQ095digwo6Z0yuxopdIOApKgAkL9PRKgNrqAf3NAyMua6lOGifzjDojC3KU\nfylQmxMn4wKBgHp2B9O/H0dEBw5JQ8W0+JX6yWQz7mEjGiR2/1W+XXb8hQ1zr709\nw1r6Gb+EghRpnZ3fBpYGGbYOMFx8wKHM+N6qW3F0ReX8v2juFGE8aRSa5oYBrWzt\nU16Idjbv8hj84cZ1PJmdyvDtpYn9rpWHOZl4rxEbPvbqkIsOMyNVqdT5AoGAOSge\nmwIIU2le2FVeohbibXiToWTYKMuMmURZ5/r72AgKMmWJKbAPe+Q3wBG01/7FRBpQ\noU8Ma0HC8s6QJbliiEyIx9JwrJWd1vkdecBHONrtA4ibm/5zD2WcOllLF+FitLhi\n3qnX6+6F0IaFGFBPJrTzlv0P4dTz/OAdv52V7GECgYEA2TttOKBAqWllgOaZOkql\nLVMJVmgR7s6tLi1+cEP8ZcapV9aRbRzTAKXm4f8AEhtlG9F9kCOvHYCYGi6JaiWJ\nZkHjeex3T+eE6Di6y5Bm/Ift5jtVhJ4jCVwHOKTMej79NPUFTJfv8hCo29haBDv6\nRXFrv+T21KCcw8k3sJeJWWQ=\n-----END PRIVATE KEY-----";
12616
12923
  /*
12617
12924
  * The crypto algorithm used for importing key and signing string
12618
12925
  */
@@ -16937,33 +17244,186 @@ removeReaction.optimistically = (referenceType, referenceId, reactionName) => {
16937
17244
  return !((_d = reaction === null || reaction === void 0 ? void 0 : reaction.myReactions) === null || _d === void 0 ? void 0 : _d.includes(reactionName));
16938
17245
  };
16939
17246
 
16940
- const updateStreamReferences = (streams, streamId, postId) => {
16941
- if (!streamId)
16942
- return streams;
16943
- return streams.map(stream => stream.streamId === streamId
16944
- ? Object.assign(Object.assign({}, stream), { referenceType: 'post', referenceId: postId, postId }) : stream);
16945
- };
16946
- const preparePostPayload = (payload) => {
16947
- const { posts: postsData, postChildren, videoStreamings } = payload, postPayload = __rest(payload, ["posts", "postChildren", "videoStreamings"]);
16948
- // Unpack community payload by mapping payload field to postSetting value.
16949
- const communitiesWithPostSetting = addPostSetting({ communities: postPayload.communities });
16950
- // map users with community
16951
- const mappedCommunityUsers = postPayload.communityUsers.map(communityUser => {
16952
- const user = postPayload.users.find(user => user.userId === communityUser.userId);
16953
- return Object.assign(Object.assign({}, communityUser), { user });
16954
- });
16955
- const communityWithMembershipStatus = updateMembershipStatus(communitiesWithPostSetting, mappedCommunityUsers);
16956
- let mappedNewStream = [];
17247
+ class ResetTask {
17248
+ constructor(postId, latestCreatedAt, serverCommentCount) {
17249
+ this.postId = postId;
17250
+ this.latestCreatedAt = latestCreatedAt;
17251
+ this.serverCommentCount = serverCommentCount;
17252
+ }
17253
+ }
17254
+
17255
+ // Task to track comment creation
17256
+ class CreateTask {
17257
+ constructor(postId, commentId, createdAt) {
17258
+ this.postId = postId;
17259
+ this.commentId = commentId;
17260
+ this.createdAt = createdAt;
17261
+ }
17262
+ }
17263
+
17264
+ // Task to track comment deletion
17265
+ class DeleteTask {
17266
+ constructor(postId, commentId) {
17267
+ this.postId = postId;
17268
+ this.commentId = commentId;
17269
+ }
17270
+ }
17271
+
17272
+ class CommentChange {
17273
+ constructor(latestCreatedAt, serverCommentCount) {
17274
+ this.latestCommentCreatedAt = latestCreatedAt;
17275
+ this.serverCommentCount = serverCommentCount;
17276
+ this.createdCommentIds = new Set();
17277
+ this.deletedCommentIds = new Set();
17278
+ }
17279
+ }
17280
+
17281
+ class PostCommentCountEngine {
17282
+ constructor() {
17283
+ this.isProcessing = false;
17284
+ this.tasks = [];
17285
+ this.commentChangeTracker = new Map();
17286
+ }
17287
+ queueCommentChangeTask(task) {
17288
+ this.tasks.push(task);
17289
+ if (!this.isProcessing) {
17290
+ this.processCommentChangeTask();
17291
+ }
17292
+ }
17293
+ processCommentChangeTask() {
17294
+ if (this.isProcessing) {
17295
+ return;
17296
+ }
17297
+ this.isProcessing = true;
17298
+ if (this.tasks.length === 0) {
17299
+ this.isProcessing = false;
17300
+ return;
17301
+ }
17302
+ // Process in capped batches, coalescing updates
17303
+ const batch = this.tasks.splice(0, PostCommentCountEngine.BATCH_SIZE);
17304
+ const modifiedPostIds = new Set();
17305
+ batch.forEach(task => {
17306
+ let modified = false;
17307
+ if (task instanceof ResetTask) {
17308
+ modified = this.processResetTaskInternal(task);
17309
+ }
17310
+ else if (task instanceof CreateTask) {
17311
+ modified = this.processCreateTaskInternal(task);
17312
+ }
17313
+ else if (task instanceof DeleteTask) {
17314
+ modified = this.processDeleteTaskInternal(task);
17315
+ }
17316
+ if (modified) {
17317
+ modifiedPostIds.add(task.postId);
17318
+ }
17319
+ });
17320
+ // Publish one update per modified post
17321
+ modifiedPostIds.forEach(postId => {
17322
+ const count = this.computeCommentCount(postId);
17323
+ PostCommentCountEngine.publishUpdate(postId, count);
17324
+ });
17325
+ this.isProcessing = false;
17326
+ // Recurse if more tasks remain
17327
+ if (this.tasks.length > 0) {
17328
+ this.processCommentChangeTask();
17329
+ }
17330
+ }
17331
+ processResetTaskInternal(task) {
17332
+ // Always creates/overwrites tracker
17333
+ this.commentChangeTracker.set(task.postId, new CommentChange(task.latestCreatedAt, task.serverCommentCount));
17334
+ return true;
17335
+ }
17336
+ processCreateTaskInternal(task) {
17337
+ const tracker = this.commentChangeTracker.get(task.postId);
17338
+ if (!tracker)
17339
+ return false; // No tracker, skip
17340
+ if (tracker.createdCommentIds.has(task.commentId))
17341
+ return false; // Deduplication
17342
+ if (task.createdAt <= tracker.latestCommentCreatedAt)
17343
+ return false; // Timestamp filtering
17344
+ tracker.createdCommentIds.add(task.commentId);
17345
+ return true;
17346
+ }
17347
+ processDeleteTaskInternal(task) {
17348
+ const tracker = this.commentChangeTracker.get(task.postId);
17349
+ if (!tracker)
17350
+ return false; // No tracker, skip
17351
+ if (tracker.deletedCommentIds.has(task.commentId))
17352
+ return false; // Deduplication
17353
+ tracker.deletedCommentIds.add(task.commentId);
17354
+ return true;
17355
+ }
17356
+ computeCommentCount(postId) {
17357
+ const tracker = this.commentChangeTracker.get(postId);
17358
+ if (!tracker)
17359
+ return 0;
17360
+ const count = tracker.serverCommentCount + tracker.createdCommentIds.size - tracker.deletedCommentIds.size;
17361
+ return Math.max(0, count);
17362
+ }
17363
+ static publishUpdate(postId, newCount) {
17364
+ var _a;
17365
+ const queryKey = ['post', 'get', postId];
17366
+ mergeInCache(queryKey, {
17367
+ localCommentCount: newCount,
17368
+ });
17369
+ const postPayload = (_a = pullFromCache(queryKey)) === null || _a === void 0 ? void 0 : _a.data;
17370
+ if (!postPayload)
17371
+ return;
17372
+ fireEvent('local.post.updated', {
17373
+ posts: [postPayload],
17374
+ });
17375
+ }
17376
+ }
17377
+ PostCommentCountEngine.BATCH_SIZE = 50;
17378
+ let instance;
17379
+ var PostCommentCountEngine$1 = {
17380
+ getInstance: () => {
17381
+ if (!instance) {
17382
+ instance = new PostCommentCountEngine();
17383
+ }
17384
+ return instance;
17385
+ },
17386
+ };
17387
+
17388
+ const updateStreamReferences = (streams, streamId, postId) => {
17389
+ if (!streamId)
17390
+ return streams;
17391
+ return streams.map(stream => stream.streamId === streamId
17392
+ ? Object.assign(Object.assign({}, stream), { referenceType: 'post', referenceId: postId, postId }) : stream);
17393
+ };
17394
+ const preparePostPayload = (payload) => {
17395
+ const { posts: postsData, postChildren, videoStreamings } = payload, postPayload = __rest(payload, ["posts", "postChildren", "videoStreamings"]);
17396
+ // Unpack community payload by mapping payload field to postSetting value.
17397
+ const communitiesWithPostSetting = addPostSetting({ communities: postPayload.communities });
17398
+ // map users with community
17399
+ const mappedCommunityUsers = postPayload.communityUsers.map(communityUser => {
17400
+ const user = postPayload.users.find(user => user.userId === communityUser.userId);
17401
+ return Object.assign(Object.assign({}, communityUser), { user });
17402
+ });
17403
+ const communityWithMembershipStatus = updateMembershipStatus(communitiesWithPostSetting, mappedCommunityUsers);
17404
+ let mappedNewStream = [];
16957
17405
  // feed type
16958
17406
  const posts = postsData.map(post => {
16959
- var _a, _b;
17407
+ var _a, _b, _c, _d;
16960
17408
  const feedType = (_a = postPayload.feeds.find(feed => feed.feedId === post.feedId)) === null || _a === void 0 ? void 0 : _a.feedType;
16961
17409
  const childPosts = payload.postChildren.filter(children => children.parentPostId === post.postId);
16962
17410
  if (childPosts.length > 0 && isAmityLivestreamPost(childPosts[0])) {
16963
17411
  mappedNewStream = updateStreamReferences(videoStreamings, (_b = childPosts[0].data) === null || _b === void 0 ? void 0 : _b.streamId, post.postId);
16964
17412
  }
17413
+ // --- Computed Comment Count: ResetTask integration ---
17414
+ // Find all comments for this post (referenceType === 'post' && referenceId === postId)
17415
+ const allComments = (payload.comments || []).filter((c) => c.referenceType === 'post' && c.referenceId === post.postId);
17416
+ // Compute latestCreatedAt
17417
+ const latestCreatedAt = allComments.length === 0
17418
+ ? new Date().toISOString()
17419
+ : allComments
17420
+ .map(c => c.createdAt)
17421
+ .sort()
17422
+ .at(-1);
17423
+ // Queue ResetTask for this post
17424
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new ResetTask(post.postId, latestCreatedAt, (_c = post.commentsCount) !== null && _c !== void 0 ? _c : 0));
16965
17425
  return Object.assign(Object.assign({}, post), { childPosts,
16966
- feedType });
17426
+ feedType, localCommentCount: (_d = post.localCommentCount) !== null && _d !== void 0 ? _d : post.commentsCount });
16967
17427
  });
16968
17428
  return Object.assign(Object.assign({}, postPayload), { postChildren, videoStreamings: mappedNewStream, posts, communities: communityWithMembershipStatus, communityUsers: mappedCommunityUsers });
16969
17429
  };
@@ -17065,14 +17525,12 @@ const createLocalPostEventSubscriber = (event, callback) => {
17065
17525
  callback(payload.posts[0]);
17066
17526
  }
17067
17527
  else {
17068
- const data = preparePostPayload(payload);
17069
- const { communities } = data;
17070
- ingestInCache(data);
17528
+ const { communities } = payload;
17071
17529
  if ((communities === null || communities === void 0 ? void 0 : communities[0]) && !['local.post.updated'].includes(event)) {
17072
17530
  fireEvent('community.updated', {
17073
17531
  communities,
17074
17532
  categories: [],
17075
- communityUsers: data.communityUsers,
17533
+ communityUsers: payload.communityUsers,
17076
17534
  feeds: [],
17077
17535
  files: [],
17078
17536
  users: [],
@@ -17343,7 +17801,7 @@ const createCommentEventSubscriber = (event, callback) => {
17343
17801
  const createLocalCommentEventSubscriber = (event, callback) => {
17344
17802
  const client = getActiveClient();
17345
17803
  const filter = (payload) => {
17346
- var _a, _b;
17804
+ var _a, _b, _c, _d, _e;
17347
17805
  if (!client.cache) {
17348
17806
  // TODO: here we are missing specific properties here!
17349
17807
  callback(LinkedObject.comment(payload.comments[0]));
@@ -17383,7 +17841,13 @@ const createLocalCommentEventSubscriber = (event, callback) => {
17383
17841
  }
17384
17842
  }
17385
17843
  }
17386
- const queries = (_a = queryCache(['comment', 'query'])) === null || _a === void 0 ? void 0 : _a.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
17844
+ else {
17845
+ const postCacheKey = ['post', 'get', comments[0].referenceId];
17846
+ const postCache = (_a = pullFromCache(postCacheKey)) === null || _a === void 0 ? void 0 : _a.data;
17847
+ postCache === null || postCache === void 0 ? void 0 : postCache.comments.push((_b = comments[0]) === null || _b === void 0 ? void 0 : _b.commentId);
17848
+ pushToCache(postCacheKey, postCache);
17849
+ }
17850
+ const queries = (_c = queryCache(['comment', 'query'])) === null || _c === void 0 ? void 0 : _c.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
17387
17851
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
17388
17852
  }
17389
17853
  if (['local.comment.deleted'].includes(event)) {
@@ -17415,7 +17879,13 @@ const createLocalCommentEventSubscriber = (event, callback) => {
17415
17879
  }
17416
17880
  }
17417
17881
  }
17418
- const queries = (_b = queryCache(['comment', 'query'])) === null || _b === void 0 ? void 0 : _b.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
17882
+ else {
17883
+ const postCacheKey = ['post', 'get', comments[0].referenceId];
17884
+ const postCache = (_d = pullFromCache(postCacheKey)) === null || _d === void 0 ? void 0 : _d.data;
17885
+ const updatedPost = Object.assign(Object.assign({}, postCache), { comments: postCache === null || postCache === void 0 ? void 0 : postCache.comments.filter(commentId => { var _a; return commentId !== ((_a = comments[0]) === null || _a === void 0 ? void 0 : _a.commentId); }) });
17886
+ pushToCache(postCacheKey, updatedPost);
17887
+ }
17888
+ const queries = (_e = queryCache(['comment', 'query'])) === null || _e === void 0 ? void 0 : _e.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
17419
17889
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
17420
17890
  }
17421
17891
  callback(LinkedObject.comment(comment.data));
@@ -25125,7 +25595,6 @@ getCommentByIds.locally = (commentIds) => {
25125
25595
  * @async
25126
25596
  */
25127
25597
  const createComment = async (bundle) => {
25128
- var _a;
25129
25598
  const client = getActiveClient();
25130
25599
  client.log('comment/createComment', bundle);
25131
25600
  const { data } = await client.http.post('/api/v3/comments', bundle);
@@ -25137,22 +25606,7 @@ const createComment = async (bundle) => {
25137
25606
  if (client.cache)
25138
25607
  ingestInCache(data, { cachedAt });
25139
25608
  if (['post', 'content'].includes(bundle.referenceType)) {
25140
- const post = (_a = pullFromCache(['post', 'get', bundle.referenceId])) === null || _a === void 0 ? void 0 : _a.data;
25141
- if (post) {
25142
- post.commentsCount += 1;
25143
- fireEvent('local.post.updated', {
25144
- posts: [post],
25145
- categories: [],
25146
- comments: [],
25147
- communities: [],
25148
- communityUsers: data.communityUsers,
25149
- feeds: [],
25150
- files: data.files,
25151
- postChildren: [],
25152
- users: data.users,
25153
- videoStreamings: [],
25154
- });
25155
- }
25609
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new CreateTask(bundle.referenceId, comments[0].commentId, data.comments[0].createdAt));
25156
25610
  }
25157
25611
  else if (bundle.referenceType === 'story') {
25158
25612
  const storyIndex = pullFromCache([
@@ -25311,7 +25765,7 @@ getStoryByStoryId$1.locally = (storyId) => {
25311
25765
  * @async
25312
25766
  */
25313
25767
  const deleteComment = async (commentId, permanent = false) => {
25314
- var _a;
25768
+ var _a, _b;
25315
25769
  const client = getActiveClient();
25316
25770
  const comment = await getComment$2(commentId);
25317
25771
  // API-FIX: This endpoint has not been implemented yet.
@@ -25344,26 +25798,14 @@ const deleteComment = async (commentId, permanent = false) => {
25344
25798
  else {
25345
25799
  const post = (_a = pullFromCache(['post', 'get', comment.data.referenceId])) === null || _a === void 0 ? void 0 : _a.data;
25346
25800
  if (post) {
25347
- let removeCount;
25348
- if (!deleted.parentId) {
25349
- // NOTE: delete the parent comment will remove all children comments
25350
- removeCount = deleted.childrenNumber + 1;
25801
+ const engine = PostCommentCountEngine$1.getInstance();
25802
+ engine.queueCommentChangeTask(new DeleteTask(post.postId, commentId));
25803
+ if (!deleted.parentId && ((_b = deleted.children) === null || _b === void 0 ? void 0 : _b.length) > 0) {
25804
+ // NOTE: delete the parent comment will also remove all children comments
25805
+ deleted.children.forEach((childCommentId) => {
25806
+ engine.queueCommentChangeTask(new DeleteTask(post.postId, childCommentId));
25807
+ });
25351
25808
  }
25352
- else
25353
- removeCount = 1;
25354
- post.commentsCount -= removeCount;
25355
- fireEvent('local.post.updated', {
25356
- posts: [post],
25357
- categories: [],
25358
- comments: [],
25359
- communities: [],
25360
- communityUsers: [],
25361
- feeds: [],
25362
- files: [],
25363
- postChildren: [],
25364
- users: [],
25365
- videoStreamings: [],
25366
- });
25367
25809
  }
25368
25810
  }
25369
25811
  fireEvent('local.comment.deleted', {
@@ -25929,47 +26371,6 @@ var index$d = /*#__PURE__*/Object.freeze({
25929
26371
  getComments: getComments
25930
26372
  });
25931
26373
 
25932
- const getPost$1 = async (postId) => {
25933
- const client = getActiveClient();
25934
- client.log('post/getPost', postId);
25935
- isInTombstone('post', postId);
25936
- let payload;
25937
- try {
25938
- // API-FIX: endpoint should not be /list, parameters should be querystring.
25939
- const response = await client.http.get(`/api/v3/posts/${encodeURIComponent(postId)}`);
25940
- payload = response.data;
25941
- }
25942
- catch (error) {
25943
- if (checkIfShouldGoesToTombstone(error === null || error === void 0 ? void 0 : error.code)) {
25944
- pushToTombstone('post', postId);
25945
- }
25946
- throw error;
25947
- }
25948
- const data = prepareMembershipPayload(payload, 'communityUsers');
25949
- const cachedAt = client.cache && Date.now();
25950
- if (client.cache)
25951
- ingestInCache(data, { cachedAt });
25952
- const { posts } = data;
25953
- const result = posts.find(post => post.postId === postId);
25954
- return {
25955
- data: result,
25956
- cachedAt,
25957
- };
25958
- };
25959
- getPost$1.locally = (postId) => {
25960
- const client = getActiveClient();
25961
- client.log('post/getPost.locally', postId);
25962
- if (!client.cache)
25963
- return;
25964
- const cached = pullFromCache(['post', 'get', postId]);
25965
- if (!cached)
25966
- return;
25967
- return {
25968
- data: cached.data,
25969
- cachedAt: cached.cachedAt,
25970
- };
25971
- };
25972
-
25973
26374
  /**
25974
26375
  * ```js
25975
26376
  * import { onLocalPostDeleted } from '@amityco/ts-sdk'
@@ -26068,7 +26469,6 @@ const commentEventHandler$1 = (callback, eventHandler, cacheKey) => {
26068
26469
  const currentCollection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
26069
26470
  if (!currentCollection || !currentCollection.data.includes(comment.referenceId))
26070
26471
  return;
26071
- await getPost$1(comment.referenceId);
26072
26472
  callback(comment);
26073
26473
  });
26074
26474
  };
@@ -26076,12 +26476,8 @@ const generateCommentSubscriptions$1 = (cacheKey) => {
26076
26476
  const eventHandlers = [
26077
26477
  onCommentCreated,
26078
26478
  onCommentDeleted,
26079
- onCommentReactionAdded,
26080
- onCommentReactionRemoved,
26081
26479
  onCommentCreatedLocal,
26082
26480
  onCommentDeleteLocal,
26083
- onLocalCommentReactionAdded,
26084
- onLocalCommentReactionRemoved,
26085
26481
  ];
26086
26482
  return eventHandlers.map(handler => ({
26087
26483
  fn: convertEventPayload((callback) => commentEventHandler$1(callback, handler, cacheKey), 'referenceId', 'post'),
@@ -26445,6 +26841,47 @@ class UserFeedQueryStreamController extends QueryStreamController {
26445
26841
  }
26446
26842
  }
26447
26843
 
26844
+ const getPost$1 = async (postId) => {
26845
+ const client = getActiveClient();
26846
+ client.log('post/getPost', postId);
26847
+ isInTombstone('post', postId);
26848
+ let payload;
26849
+ try {
26850
+ // API-FIX: endpoint should not be /list, parameters should be querystring.
26851
+ const response = await client.http.get(`/api/v3/posts/${encodeURIComponent(postId)}`);
26852
+ payload = response.data;
26853
+ }
26854
+ catch (error) {
26855
+ if (checkIfShouldGoesToTombstone(error === null || error === void 0 ? void 0 : error.code)) {
26856
+ pushToTombstone('post', postId);
26857
+ }
26858
+ throw error;
26859
+ }
26860
+ const data = prepareMembershipPayload(payload, 'communityUsers');
26861
+ const cachedAt = client.cache && Date.now();
26862
+ if (client.cache)
26863
+ ingestInCache(data, { cachedAt });
26864
+ const { posts } = data;
26865
+ const result = posts.find(post => post.postId === postId);
26866
+ return {
26867
+ data: result,
26868
+ cachedAt,
26869
+ };
26870
+ };
26871
+ getPost$1.locally = (postId) => {
26872
+ const client = getActiveClient();
26873
+ client.log('post/getPost.locally', postId);
26874
+ if (!client.cache)
26875
+ return;
26876
+ const cached = pullFromCache(['post', 'get', postId]);
26877
+ if (!cached)
26878
+ return;
26879
+ return {
26880
+ data: cached.data,
26881
+ cachedAt: cached.cachedAt,
26882
+ };
26883
+ };
26884
+
26448
26885
  class UserFeedLiveCollectionController extends LiveCollectionController {
26449
26886
  constructor(query, callback) {
26450
26887
  const queryStreamId = hash__default["default"](query);
@@ -26578,12 +27015,240 @@ const getUserFeed = (params, callback, config) => {
26578
27015
  };
26579
27016
  /* end_public_function */
26580
27017
 
27018
+ class CommunityFeedPaginationController extends PaginationController {
27019
+ async getRequest(queryParams, token) {
27020
+ const { limit = COLLECTION_DEFAULT_PAGINATION_LIMIT, includeDeleted, communityId } = queryParams, params = __rest(queryParams, ["limit", "includeDeleted", "communityId"]);
27021
+ const options = token ? { token } : { limit };
27022
+ const { data: queryResponse } = await this.http.get(`/api/v5/posts`, {
27023
+ params: Object.assign(Object.assign({}, params), { targetId: communityId, targetType: 'community', isDeleted: inferIsDeleted(includeDeleted), matchingOnlyParentPost: true, options }),
27024
+ });
27025
+ return queryResponse;
27026
+ }
27027
+ }
27028
+
27029
+ class CommunityFeedQueryStreamController extends QueryStreamController {
27030
+ constructor(query, cacheKey, notifyChange, preparePayload) {
27031
+ super(query, cacheKey);
27032
+ this.notifyChange = notifyChange;
27033
+ this.preparePayload = preparePayload;
27034
+ }
27035
+ async saveToMainDB(response) {
27036
+ const processedPayload = await this.preparePayload(response);
27037
+ const client = getActiveClient();
27038
+ const cachedAt = client.cache && Date.now();
27039
+ if (client.cache) {
27040
+ ingestInCache(processedPayload, { cachedAt });
27041
+ }
27042
+ }
27043
+ appendToQueryStream(response, direction, refresh = false) {
27044
+ var _a, _b;
27045
+ if (refresh) {
27046
+ pushToCache(this.cacheKey, {
27047
+ data: response.posts.map(getResolver('post')),
27048
+ });
27049
+ }
27050
+ else {
27051
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27052
+ const posts = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
27053
+ pushToCache(this.cacheKey, Object.assign(Object.assign({}, collection), { data: [...new Set([...posts, ...response.posts.map(getResolver('post'))])] }));
27054
+ }
27055
+ }
27056
+ reactor(action) {
27057
+ return (post) => {
27058
+ var _a, _b;
27059
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27060
+ if (!collection)
27061
+ return;
27062
+ if (action === EnumPostActions.OnPostDeleted) {
27063
+ collection.data = collection.data.filter(postId => postId !== post.postId);
27064
+ }
27065
+ if (post.parentPostId && post.isDeleted) {
27066
+ const parentPost = (_b = pullFromCache([
27067
+ 'post',
27068
+ 'get',
27069
+ post.parentPostId,
27070
+ ])) === null || _b === void 0 ? void 0 : _b.data;
27071
+ if (!parentPost)
27072
+ return;
27073
+ parentPost.children = parentPost.children.filter(childId => childId !== post.postId);
27074
+ pushToCache(['post', 'get', parentPost.postId], parentPost);
27075
+ }
27076
+ if (action === EnumPostActions.OnPostDeclined) {
27077
+ collection.data = collection.data.filter(postId => postId !== post.postId);
27078
+ }
27079
+ if (action === EnumPostActions.OnPostCreated || action === EnumPostActions.OnPostApproved) {
27080
+ collection.data = [...new Set([post.postId, ...collection.data])];
27081
+ }
27082
+ pushToCache(this.cacheKey, collection);
27083
+ this.notifyChange({ origin: "event" /* Amity.LiveDataOrigin.EVENT */, loading: false });
27084
+ };
27085
+ }
27086
+ subscribeRTE(createSubscriber) {
27087
+ return createSubscriber.map(subscriber => subscriber.fn(this.reactor(subscriber.action)));
27088
+ }
27089
+ }
27090
+
27091
+ const commentEventHandler = (callback, eventHandler, cacheKey, resolveId) => {
27092
+ return eventHandler(async (comment) => {
27093
+ var _a;
27094
+ const currentCollection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27095
+ if (!currentCollection ||
27096
+ !currentCollection.data.includes(resolveId ? resolveId(comment.referenceId) : comment.referenceId))
27097
+ return;
27098
+ callback(comment);
27099
+ });
27100
+ };
27101
+ const generateCommentSubscriptions = ({ cacheKey, resolveId, }) => {
27102
+ const eventHandlers = [
27103
+ onCommentCreated,
27104
+ onCommentDeleted,
27105
+ onCommentCreatedLocal,
27106
+ onCommentDeleteLocal,
27107
+ ];
27108
+ return eventHandlers.map(handler => ({
27109
+ fn: convertEventPayload((callback) => commentEventHandler(callback, handler, cacheKey, resolveId), 'referenceId', 'post'),
27110
+ action: EnumPostActions.OnPostUpdated,
27111
+ }));
27112
+ };
27113
+ const getPostSubscription = (cacheKey) => {
27114
+ return [
27115
+ { fn: onPostCreated, action: EnumPostActions.OnPostCreated },
27116
+ { fn: onPostUpdated, action: EnumPostActions.OnPostUpdated },
27117
+ { fn: onPostUpdatedLocal, action: EnumPostActions.OnPostUpdated },
27118
+ { fn: onPostDeleted, action: EnumPostActions.OnPostDeleted },
27119
+ { fn: onPostFlagged, action: EnumPostActions.OnPostFlagged },
27120
+ { fn: onPostUnflagged, action: EnumPostActions.OnPostUnflagged },
27121
+ { fn: onPostApproved, action: EnumPostActions.OnPostApproved },
27122
+ { fn: onPostDeclined, action: EnumPostActions.OnPostDeclined },
27123
+ { fn: onPostReactionAdded, action: EnumPostActions.OnPostReactionAdded },
27124
+ { fn: onPostReactionRemoved, action: EnumPostActions.OnPostReactionRemoved },
27125
+ { fn: onLocalPostReactionAdded, action: EnumPostActions.OnPostReactionAdded },
27126
+ { fn: onLocalPostReactionRemoved, action: EnumPostActions.OnPostReactionRemoved },
27127
+ { fn: onLocalPostDeleted, action: EnumPostActions.OnPostDeleted },
27128
+ ...generateCommentSubscriptions({ cacheKey }),
27129
+ ];
27130
+ };
27131
+ const resolvePostIdsFromRooms = (rooms, posts) => {
27132
+ var _a;
27133
+ return ((_a = rooms
27134
+ .map(room => {
27135
+ const post = posts.find(post => post.postId === room.referenceId);
27136
+ return post ? getResolver('post')({ postId: post === null || post === void 0 ? void 0 : post.postId }) : undefined;
27137
+ })
27138
+ .filter(isNonNullable)) !== null && _a !== void 0 ? _a : []);
27139
+ };
27140
+
27141
+ class CommunityFeedLiveCollectionController extends LiveCollectionController {
27142
+ constructor(query, callback) {
27143
+ const queryStreamId = hash__default["default"](query);
27144
+ const cacheKey = ['communityFeed', 'collection', queryStreamId];
27145
+ const paginationController = new CommunityFeedPaginationController(query);
27146
+ super(paginationController, queryStreamId, cacheKey, callback);
27147
+ this.query = query;
27148
+ this.queryStreamController = new CommunityFeedQueryStreamController(this.query, this.cacheKey, this.notifyChange.bind(this), preparePostPayload);
27149
+ this.callback = callback.bind(this);
27150
+ this.loadPage({ initial: true });
27151
+ }
27152
+ setup() {
27153
+ var _a;
27154
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27155
+ if (!collection) {
27156
+ pushToCache(this.cacheKey, {
27157
+ data: [],
27158
+ params: {},
27159
+ });
27160
+ }
27161
+ }
27162
+ async persistModel(queryPayload) {
27163
+ await this.queryStreamController.saveToMainDB(queryPayload);
27164
+ }
27165
+ persistQueryStream({ response, direction, refresh, }) {
27166
+ this.queryStreamController.appendToQueryStream(response, direction, refresh);
27167
+ }
27168
+ startSubscription() {
27169
+ return this.queryStreamController.subscribeRTE(getPostSubscription(this.cacheKey));
27170
+ }
27171
+ notifyChange({ origin, loading, error }) {
27172
+ var _a, _b;
27173
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27174
+ if (!collection)
27175
+ return;
27176
+ const data = ((_b = collection.data
27177
+ .map(id => pullFromCache(['post', 'get', id]))
27178
+ .filter(isNonNullable)
27179
+ .map(({ data }) => data)) !== null && _b !== void 0 ? _b : []).map(LinkedObject.post);
27180
+ if (!this.shouldNotify(data) && origin === 'event')
27181
+ return;
27182
+ this.callback({
27183
+ onNextPage: () => this.loadPage({ direction: "next" /* Amity.LiveCollectionPageDirection.NEXT */ }),
27184
+ data,
27185
+ hasNextPage: !!this.paginationController.getNextToken(),
27186
+ loading,
27187
+ error,
27188
+ });
27189
+ }
27190
+ }
27191
+
27192
+ /* begin_public_function
27193
+ id: feed.query.community_feed
27194
+ */
27195
+ /**
27196
+ * ```js
27197
+ * import { FeedRepository } from '@amityco/ts-sdk'
27198
+ *
27199
+ * let posts = []
27200
+ * const unsubscribe = FeedRepository.getCommunityFeed({
27201
+ * communityId: 'community-id',
27202
+ * sortBy?: 'lastCreated' | 'firstCreated' | 'lastUpdated' | 'firstUpdated',
27203
+ * includeDeleted?: boolean,
27204
+ * feedType?: 'reviewing' | 'published' | 'declined',
27205
+ * tags?: string[],
27206
+ * includeMixedStructure?: boolean,
27207
+ * limit?: number,
27208
+ * }, response => processResponse(response))
27209
+ * ```
27210
+ *
27211
+ * Observe all mutations on a list of {@link Amity.Post} for a given community feed.
27212
+ *
27213
+ * @param params - Parameters for querying the community feed:
27214
+ * @param params.communityId The ID of the community (required)
27215
+ * @param params.sortBy The sorting order of the feed (optional)
27216
+ * @param params.includeDeleted Whether to include deleted posts (optional)
27217
+ * @param params.feedType The type of the feed: 'reviewing', 'published', or 'declined' (optional)
27218
+ * @param params.tags Array of tags to filter posts (optional)
27219
+ * @param params.includeMixedStructure Whether to include mixed structure posts (optional)
27220
+ * @param params.limit The maximum number of posts to retrieve (optional)
27221
+ * @param callback The function to call when new data are available
27222
+ * @param config Additional live collection configuration (optional)
27223
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the feed
27224
+ *
27225
+ * @category Posts Live Collection
27226
+ */
27227
+ const getCommunityFeed = (params, callback, config) => {
27228
+ const { log, cache } = getActiveClient();
27229
+ if (!cache) {
27230
+ console.log(ENABLE_CACHE_MESSAGE);
27231
+ }
27232
+ const timestamp = Date.now();
27233
+ log(`getCommunityFeed(tmpid: ${timestamp}) > listen`);
27234
+ const communityFeedLiveCollection = new CommunityFeedLiveCollectionController(params, callback);
27235
+ const disposers = communityFeedLiveCollection.startSubscription();
27236
+ const cacheKey = communityFeedLiveCollection.getCacheKey();
27237
+ disposers.push(() => dropFromCache(cacheKey));
27238
+ return () => {
27239
+ log(`getCommunityFeed(tmpid: ${timestamp}) > dispose`);
27240
+ disposers.forEach(fn => fn());
27241
+ };
27242
+ };
27243
+ /* end_public_function */
27244
+
26581
27245
  var index$c = /*#__PURE__*/Object.freeze({
26582
27246
  __proto__: null,
26583
27247
  queryGlobalFeed: queryGlobalFeed,
26584
27248
  getCustomRankingGlobalFeed: getCustomRankingGlobalFeed,
26585
27249
  getGlobalFeed: getGlobalFeed,
26586
- getUserFeed: getUserFeed
27250
+ getUserFeed: getUserFeed,
27251
+ getCommunityFeed: getCommunityFeed
26587
27252
  });
26588
27253
 
26589
27254
  /* begin_public_function
@@ -27329,61 +27994,6 @@ class PostQueryStreamController extends QueryStreamController {
27329
27994
  }
27330
27995
  }
27331
27996
 
27332
- const commentEventHandler = (callback, eventHandler, cacheKey, resolveId) => {
27333
- return eventHandler(async (comment) => {
27334
- var _a;
27335
- const currentCollection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27336
- if (!currentCollection ||
27337
- !currentCollection.data.includes(resolveId ? resolveId(comment.referenceId) : comment.referenceId))
27338
- return;
27339
- await getPost$1(comment.referenceId);
27340
- callback(comment);
27341
- });
27342
- };
27343
- const generateCommentSubscriptions = ({ cacheKey, resolveId, }) => {
27344
- const eventHandlers = [
27345
- onCommentCreated,
27346
- onCommentDeleted,
27347
- onCommentReactionAdded,
27348
- onCommentReactionRemoved,
27349
- onCommentCreatedLocal,
27350
- onCommentDeleteLocal,
27351
- onLocalCommentReactionAdded,
27352
- onLocalCommentReactionRemoved,
27353
- ];
27354
- return eventHandlers.map(handler => ({
27355
- fn: convertEventPayload((callback) => commentEventHandler(callback, handler, cacheKey, resolveId), 'referenceId', 'post'),
27356
- action: EnumPostActions.OnPostUpdated,
27357
- }));
27358
- };
27359
- const getPostSubscription = (cacheKey) => {
27360
- return [
27361
- { fn: onPostCreated, action: EnumPostActions.OnPostCreated },
27362
- { fn: onPostUpdated, action: EnumPostActions.OnPostUpdated },
27363
- { fn: onPostUpdatedLocal, action: EnumPostActions.OnPostUpdated },
27364
- { fn: onPostDeleted, action: EnumPostActions.OnPostDeleted },
27365
- { fn: onPostFlagged, action: EnumPostActions.OnPostFlagged },
27366
- { fn: onPostUnflagged, action: EnumPostActions.OnPostUnflagged },
27367
- { fn: onPostApproved, action: EnumPostActions.OnPostApproved },
27368
- { fn: onPostDeclined, action: EnumPostActions.OnPostDeclined },
27369
- { fn: onPostReactionAdded, action: EnumPostActions.OnPostReactionAdded },
27370
- { fn: onPostReactionRemoved, action: EnumPostActions.OnPostReactionRemoved },
27371
- { fn: onLocalPostReactionAdded, action: EnumPostActions.OnPostReactionAdded },
27372
- { fn: onLocalPostReactionRemoved, action: EnumPostActions.OnPostReactionRemoved },
27373
- { fn: onLocalPostDeleted, action: EnumPostActions.OnPostDeleted },
27374
- ...generateCommentSubscriptions({ cacheKey }),
27375
- ];
27376
- };
27377
- const resolvePostIdsFromRooms = (rooms, posts) => {
27378
- var _a;
27379
- return ((_a = rooms
27380
- .map(room => {
27381
- const post = posts.find(post => post.postId === room.referenceId);
27382
- return post ? getResolver('post')({ postId: post === null || post === void 0 ? void 0 : post.postId }) : undefined;
27383
- })
27384
- .filter(isNonNullable)) !== null && _a !== void 0 ? _a : []);
27385
- };
27386
-
27387
27997
  class PostLiveCollectionController extends LiveCollectionController {
27388
27998
  constructor(query, callback) {
27389
27999
  const queryStreamId = hash__default["default"](query);