@amityco/ts-sdk-react-native 7.27.2-60f0571.0 → 7.28.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 (195) hide show
  1. package/dist/@types/core/events.d.ts +5 -0
  2. package/dist/@types/core/events.d.ts.map +1 -1
  3. package/dist/@types/core/payload.d.ts +26 -0
  4. package/dist/@types/core/payload.d.ts.map +1 -1
  5. package/dist/@types/core/permissions.d.ts +10 -4
  6. package/dist/@types/core/permissions.d.ts.map +1 -1
  7. package/dist/@types/domains/analytics.d.ts +3 -1
  8. package/dist/@types/domains/analytics.d.ts.map +1 -1
  9. package/dist/@types/domains/channel.d.ts +5 -0
  10. package/dist/@types/domains/channel.d.ts.map +1 -1
  11. package/dist/@types/domains/client.d.ts +18 -0
  12. package/dist/@types/domains/client.d.ts.map +1 -1
  13. package/dist/@types/domains/comment.d.ts +27 -0
  14. package/dist/@types/domains/comment.d.ts.map +1 -1
  15. package/dist/@types/domains/community.d.ts +1 -0
  16. package/dist/@types/domains/community.d.ts.map +1 -1
  17. package/dist/@types/domains/curatedContent.d.ts +25 -0
  18. package/dist/@types/domains/curatedContent.d.ts.map +1 -0
  19. package/dist/@types/domains/pinnedMessage.d.ts +43 -0
  20. package/dist/@types/domains/pinnedMessage.d.ts.map +1 -0
  21. package/dist/@types/domains/post.d.ts +11 -0
  22. package/dist/@types/domains/post.d.ts.map +1 -1
  23. package/dist/@types/index.d.ts +3 -1
  24. package/dist/@types/index.d.ts.map +1 -1
  25. package/dist/analytic/service/analytic/AnalyticsEngine.d.ts +3 -0
  26. package/dist/analytic/service/analytic/AnalyticsEngine.d.ts.map +1 -1
  27. package/dist/analytic/service/analytic/AnalyticsEventCapturer.d.ts +3 -0
  28. package/dist/analytic/service/analytic/AnalyticsEventCapturer.d.ts.map +1 -1
  29. package/dist/channelRepository/api/createChannel.d.ts.map +1 -1
  30. package/dist/channelRepository/events/index.d.ts +2 -0
  31. package/dist/channelRepository/events/index.d.ts.map +1 -1
  32. package/dist/channelRepository/events/onChannelMemberRoleAdded.d.ts +22 -0
  33. package/dist/channelRepository/events/onChannelMemberRoleAdded.d.ts.map +1 -1
  34. package/dist/channelRepository/events/onChannelMemberRoleRemoved.d.ts +22 -0
  35. package/dist/channelRepository/events/onChannelMemberRoleRemoved.d.ts.map +1 -1
  36. package/dist/channelRepository/events/onChannelMessagePinned.d.ts +24 -0
  37. package/dist/channelRepository/events/onChannelMessagePinned.d.ts.map +1 -0
  38. package/dist/channelRepository/events/onChannelMessageUnpinned.d.ts +21 -0
  39. package/dist/channelRepository/events/onChannelMessageUnpinned.d.ts.map +1 -0
  40. package/dist/channelRepository/events/onChannelPinnedMessageDeleted.d.ts +12 -0
  41. package/dist/channelRepository/events/onChannelPinnedMessageDeleted.d.ts.map +1 -0
  42. package/dist/channelRepository/events/tests/onChannelMemberRoleAdded.test.d.ts +2 -0
  43. package/dist/channelRepository/events/tests/onChannelMemberRoleAdded.test.d.ts.map +1 -0
  44. package/dist/channelRepository/events/tests/onChannelMemberRoleRemoved.test.d.ts +2 -0
  45. package/dist/channelRepository/events/tests/onChannelMemberRoleRemoved.test.d.ts.map +1 -0
  46. package/dist/channelRepository/events/tests/onChannelMessagePinned.test.d.ts +2 -0
  47. package/dist/channelRepository/events/tests/onChannelMessagePinned.test.d.ts.map +1 -0
  48. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  49. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  50. package/dist/channelRepository/observers/getMyMembership.d.ts.map +1 -1
  51. package/dist/channelRepository/observers/searchChannels/SearchChannelLiveCollectionController.d.ts.map +1 -1
  52. package/dist/channelRepository/utils/applyChannelRolePayload.d.ts +21 -0
  53. package/dist/channelRepository/utils/applyChannelRolePayload.d.ts.map +1 -0
  54. package/dist/channelRepository/utils/index.d.ts +2 -0
  55. package/dist/channelRepository/utils/index.d.ts.map +1 -1
  56. package/dist/channelRepository/utils/tests/pinnedMessage.test.d.ts +2 -0
  57. package/dist/channelRepository/utils/tests/pinnedMessage.test.d.ts.map +1 -0
  58. package/dist/channelRepository/utils/updatePinnedMessageCache.d.ts +24 -0
  59. package/dist/channelRepository/utils/updatePinnedMessageCache.d.ts.map +1 -0
  60. package/dist/client/api/createClient.d.ts +5 -1
  61. package/dist/client/api/createClient.d.ts.map +1 -1
  62. package/dist/client/api/getSocialSettings.d.ts.map +1 -1
  63. package/dist/client/api/setupLoginSubscriptions.d.ts.map +1 -1
  64. package/dist/client/api/tests/getSocialSettings.test.d.ts +2 -0
  65. package/dist/client/api/tests/getSocialSettings.test.d.ts.map +1 -0
  66. package/dist/commentRepository/api/approveComment.d.ts +17 -0
  67. package/dist/commentRepository/api/approveComment.d.ts.map +1 -0
  68. package/dist/commentRepository/api/createComment.d.ts +12 -1
  69. package/dist/commentRepository/api/createComment.d.ts.map +1 -1
  70. package/dist/commentRepository/api/declineComment.d.ts +18 -0
  71. package/dist/commentRepository/api/declineComment.d.ts.map +1 -0
  72. package/dist/commentRepository/api/deleteComment.d.ts.map +1 -1
  73. package/dist/commentRepository/api/index.d.ts +2 -0
  74. package/dist/commentRepository/api/index.d.ts.map +1 -1
  75. package/dist/commentRepository/api/tests/approveComment.test.d.ts +2 -0
  76. package/dist/commentRepository/api/tests/approveComment.test.d.ts.map +1 -0
  77. package/dist/commentRepository/api/tests/createComment.optimistic.test.d.ts +2 -0
  78. package/dist/commentRepository/api/tests/createComment.optimistic.test.d.ts.map +1 -0
  79. package/dist/commentRepository/api/tests/declineComment.test.d.ts +2 -0
  80. package/dist/commentRepository/api/tests/declineComment.test.d.ts.map +1 -0
  81. package/dist/commentRepository/api/updateComment.d.ts.map +1 -1
  82. package/dist/commentRepository/events/index.d.ts +1 -0
  83. package/dist/commentRepository/events/index.d.ts.map +1 -1
  84. package/dist/commentRepository/events/onCommentApproved.d.ts +17 -0
  85. package/dist/commentRepository/events/onCommentApproved.d.ts.map +1 -0
  86. package/dist/commentRepository/events/tests/onCommentApproved.test.d.ts +2 -0
  87. package/dist/commentRepository/events/tests/onCommentApproved.test.d.ts.map +1 -0
  88. package/dist/commentRepository/events/tests/onCommentCreated.count.test.d.ts +2 -0
  89. package/dist/commentRepository/events/tests/onCommentCreated.count.test.d.ts.map +1 -0
  90. package/dist/commentRepository/events/utils.d.ts.map +1 -1
  91. package/dist/commentRepository/internalApi/getComment.d.ts.map +1 -1
  92. package/dist/commentRepository/observers/getComment.d.ts.map +1 -1
  93. package/dist/commentRepository/observers/getCommentReviewQueue/LiveCollectionController.d.ts +13 -0
  94. package/dist/commentRepository/observers/getCommentReviewQueue/LiveCollectionController.d.ts.map +1 -0
  95. package/dist/commentRepository/observers/getCommentReviewQueue/PaginationController.d.ts +5 -0
  96. package/dist/commentRepository/observers/getCommentReviewQueue/PaginationController.d.ts.map +1 -0
  97. package/dist/commentRepository/observers/getCommentReviewQueue/QueryStreamController.d.ts +15 -0
  98. package/dist/commentRepository/observers/getCommentReviewQueue/QueryStreamController.d.ts.map +1 -0
  99. package/dist/commentRepository/observers/getCommentReviewQueue.d.ts +22 -0
  100. package/dist/commentRepository/observers/getCommentReviewQueue.d.ts.map +1 -0
  101. package/dist/commentRepository/observers/getComments/CommentLiveCollectionController.d.ts +1 -1
  102. package/dist/commentRepository/observers/getComments/CommentLiveCollectionController.d.ts.map +1 -1
  103. package/dist/commentRepository/observers/getComments/CommentQueryStreamController.d.ts.map +1 -1
  104. package/dist/commentRepository/observers/getComments/enums.d.ts +1 -0
  105. package/dist/commentRepository/observers/getComments/enums.d.ts.map +1 -1
  106. package/dist/commentRepository/observers/index.d.ts +1 -0
  107. package/dist/commentRepository/observers/index.d.ts.map +1 -1
  108. package/dist/commentRepository/observers/tests/integrations/getCommentReviewQueue.integration.test.d.ts +2 -0
  109. package/dist/commentRepository/observers/tests/integrations/getCommentReviewQueue.integration.test.d.ts.map +1 -0
  110. package/dist/commentRepository/utils/approval.d.ts +49 -0
  111. package/dist/commentRepository/utils/approval.d.ts.map +1 -0
  112. package/dist/commentRepository/utils/payload.d.ts +6 -0
  113. package/dist/commentRepository/utils/payload.d.ts.map +1 -1
  114. package/dist/commentRepository/utils/tests/approval.test.d.ts +2 -0
  115. package/dist/commentRepository/utils/tests/approval.test.d.ts.map +1 -0
  116. package/dist/commentRepository/utils/tests/payload.test.d.ts +2 -0
  117. package/dist/commentRepository/utils/tests/payload.test.d.ts.map +1 -0
  118. package/dist/communityRepository/api/createCommunity.d.ts +1 -1
  119. package/dist/communityRepository/api/createCommunity.d.ts.map +1 -1
  120. package/dist/communityRepository/api/updateCommunity.d.ts +1 -1
  121. package/dist/communityRepository/api/updateCommunity.d.ts.map +1 -1
  122. package/dist/core/device.d.ts +1 -1
  123. package/dist/core/device.d.ts.map +1 -1
  124. package/dist/core/events.d.ts +3 -3
  125. package/dist/core/events.d.ts.map +1 -1
  126. package/dist/core/tests/device.test.d.ts +2 -0
  127. package/dist/core/tests/device.test.d.ts.map +1 -0
  128. package/dist/core/transports/http.d.ts.map +1 -1
  129. package/dist/core/transports/utils.d.ts +8 -0
  130. package/dist/core/transports/utils.d.ts.map +1 -1
  131. package/dist/curatedContentRepository/api/getPool.d.ts +2 -0
  132. package/dist/curatedContentRepository/api/getPool.d.ts.map +1 -0
  133. package/dist/curatedContentRepository/api/index.d.ts +2 -0
  134. package/dist/curatedContentRepository/api/index.d.ts.map +1 -0
  135. package/dist/curatedContentRepository/api/tests/getPool.test.d.ts +2 -0
  136. package/dist/curatedContentRepository/api/tests/getPool.test.d.ts.map +1 -0
  137. package/dist/curatedContentRepository/api/tests/integration/getPool.integration.test.d.ts +2 -0
  138. package/dist/curatedContentRepository/api/tests/integration/getPool.integration.test.d.ts.map +1 -0
  139. package/dist/curatedContentRepository/index.d.ts +2 -0
  140. package/dist/curatedContentRepository/index.d.ts.map +1 -0
  141. package/dist/index.cjs.js +1744 -479
  142. package/dist/index.d.ts +1 -0
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.esm.js +1719 -455
  145. package/dist/index.umd.js +1 -1
  146. package/dist/messagePreview/utils/getChannelMessagePreviewWithUser.d.ts +1 -0
  147. package/dist/messagePreview/utils/getChannelMessagePreviewWithUser.d.ts.map +1 -1
  148. package/dist/messageRepository/api/index.d.ts +2 -0
  149. package/dist/messageRepository/api/index.d.ts.map +1 -1
  150. package/dist/messageRepository/api/pinMessage.d.ts +29 -0
  151. package/dist/messageRepository/api/pinMessage.d.ts.map +1 -0
  152. package/dist/messageRepository/api/tests/pinMessage.test.d.ts +2 -0
  153. package/dist/messageRepository/api/tests/pinMessage.test.d.ts.map +1 -0
  154. package/dist/messageRepository/api/tests/unpinMessage.test.d.ts +2 -0
  155. package/dist/messageRepository/api/tests/unpinMessage.test.d.ts.map +1 -0
  156. package/dist/messageRepository/api/unpinMessage.d.ts +28 -0
  157. package/dist/messageRepository/api/unpinMessage.d.ts.map +1 -0
  158. package/dist/messageRepository/utils/refreshChannelPermissionsForMessage.d.ts +13 -0
  159. package/dist/messageRepository/utils/refreshChannelPermissionsForMessage.d.ts.map +1 -0
  160. package/dist/postRepository/utils/PostCommentCountEngine/ApproveTask.d.ts +16 -0
  161. package/dist/postRepository/utils/PostCommentCountEngine/ApproveTask.d.ts.map +1 -0
  162. package/dist/postRepository/utils/PostCommentCountEngine/PostCommentCountEngine.d.ts +25 -1
  163. package/dist/postRepository/utils/PostCommentCountEngine/PostCommentCountEngine.d.ts.map +1 -1
  164. package/dist/postRepository/utils/PostCommentCountEngine/postCommentCountEngineOnLoginHandler.d.ts +9 -0
  165. package/dist/postRepository/utils/PostCommentCountEngine/postCommentCountEngineOnLoginHandler.d.ts.map +1 -0
  166. package/dist/postRepository/utils/PostCommentCountEngine/tests/getLocalCommentCount.test.d.ts +2 -0
  167. package/dist/postRepository/utils/PostCommentCountEngine/tests/getLocalCommentCount.test.d.ts.map +1 -0
  168. package/dist/postRepository/utils/PostCommentCountEngine/tests/pendingAuthoredComments.test.d.ts +2 -0
  169. package/dist/postRepository/utils/PostCommentCountEngine/tests/pendingAuthoredComments.test.d.ts.map +1 -0
  170. package/dist/postRepository/utils/latestComments.d.ts +10 -0
  171. package/dist/postRepository/utils/latestComments.d.ts.map +1 -0
  172. package/dist/postRepository/utils/payload.d.ts.map +1 -1
  173. package/dist/postRepository/utils/tests/latestComments.test.d.ts +2 -0
  174. package/dist/postRepository/utils/tests/latestComments.test.d.ts.map +1 -0
  175. package/dist/postRepository/utils/tests/payload.test.d.ts +2 -0
  176. package/dist/postRepository/utils/tests/payload.test.d.ts.map +1 -0
  177. package/dist/utils/constants.d.ts +4 -0
  178. package/dist/utils/constants.d.ts.map +1 -1
  179. package/dist/utils/linkedObject/commentLinkedObject.d.ts.map +1 -1
  180. package/dist/utils/linkedObject/curatedContentTopicLinkedObject.d.ts +2 -0
  181. package/dist/utils/linkedObject/curatedContentTopicLinkedObject.d.ts.map +1 -0
  182. package/dist/utils/linkedObject/index.d.ts +1 -0
  183. package/dist/utils/linkedObject/index.d.ts.map +1 -1
  184. package/dist/utils/linkedObject/messageLinkedObject.d.ts.map +1 -1
  185. package/dist/utils/linkedObject/postLinkedObject.d.ts.map +1 -1
  186. package/dist/utils/linkedObject/tests/postLinkedObject.test.d.ts +2 -0
  187. package/dist/utils/linkedObject/tests/postLinkedObject.test.d.ts.map +1 -0
  188. package/dist/utils/tests/dummy/comment.d.ts +1 -0
  189. package/dist/utils/tests/dummy/comment.d.ts.map +1 -1
  190. package/dist/utils/tests/dummy/index.d.ts +1 -0
  191. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  192. package/dist/utils/tests/dummy/pinnedMessage.d.ts +2 -0
  193. package/dist/utils/tests/dummy/pinnedMessage.d.ts.map +1 -0
  194. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  195. package/package.json +3 -2
package/dist/index.cjs.js CHANGED
@@ -7,9 +7,10 @@ var mitt = require('mitt');
7
7
  var debug = require('debug');
8
8
  var axios = require('axios');
9
9
  var HttpAgent = require('agentkeepalive');
10
+ var uuid$1 = require('react-native-uuid');
10
11
  var mqtt = require('mqtt');
12
+ var uaParserJs = require('ua-parser-js');
11
13
  var AsyncStorage = require('@react-native-async-storage/async-storage');
12
- var uuid$1 = require('react-native-uuid');
13
14
  var jwtDecode = require('jwt-decode');
14
15
  var reactNative = require('react-native');
15
16
  var hash = require('object-hash');
@@ -39,9 +40,9 @@ var mitt__default = /*#__PURE__*/_interopDefaultLegacy(mitt);
39
40
  var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
40
41
  var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
41
42
  var HttpAgent__default = /*#__PURE__*/_interopDefaultLegacy(HttpAgent);
43
+ var uuid__default = /*#__PURE__*/_interopDefaultLegacy(uuid$1);
42
44
  var mqtt__default = /*#__PURE__*/_interopDefaultLegacy(mqtt);
43
45
  var AsyncStorage__default = /*#__PURE__*/_interopDefaultLegacy(AsyncStorage);
44
- var uuid__default = /*#__PURE__*/_interopDefaultLegacy(uuid$1);
45
46
  var jwtDecode__default = /*#__PURE__*/_interopDefaultLegacy(jwtDecode);
46
47
  var hash__default = /*#__PURE__*/_interopDefaultLegacy(hash);
47
48
  var Hls__default = /*#__PURE__*/_interopDefaultLegacy(Hls);
@@ -352,8 +353,8 @@ exports.AmityLiveViewerCountMode = void 0;
352
353
 
353
354
  function getVersion() {
354
355
  try {
355
- // the string ''v7.27.1-cjs'' should be replaced by actual value by @rollup/plugin-replace
356
- return 'v7.27.1-cjs';
356
+ // the string ''v7.28.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
357
+ return 'v7.28.0-cjs';
357
358
  }
358
359
  catch (error) {
359
360
  return '__dev__';
@@ -362,6 +363,7 @@ function getVersion() {
362
363
  const VERSION = getVersion();
363
364
 
364
365
  const COLLECTION_DEFAULT_PAGINATION_LIMIT = 5;
366
+ const LATEST_COMMENTS_LIMIT = 5;
365
367
  const COLLECTION_DEFAULT_PAGINATION_SIZE = 20;
366
368
  const COLLECTION_DEFAULT_CACHING_POLICY = 'cache_then_server';
367
369
  const ENABLE_CACHE_MESSAGE = 'For using Live Collection feature you need to enable Cache!';
@@ -377,7 +379,11 @@ const YEAR = 365 * DAY;
377
379
  const ACCESS_TOKEN_WATCHER_INTERVAL = 10 * MINUTE;
378
380
  const API_ENDPOINTS = {
379
381
  forYouFeed: '/api/v1/feeds/for-you',
382
+ commentReviewQueue: (communityId) => `/api/v3/communities/${encodeURIComponent(communityId)}/comments/review-queue`,
380
383
  };
384
+ // The review-queue route defaults to 10, not the SDK-wide page size, and caps at 100
385
+ const COMMENT_REVIEW_QUEUE_DEFAULT_PAGINATION_SIZE = 10;
386
+ const COMMENT_REVIEW_QUEUE_MAX_PAGINATION_SIZE = 100;
381
387
 
382
388
  // cache constants
383
389
  const CACHE_KEY_GET = 'get';
@@ -1986,6 +1992,8 @@ function computeUrl(type, region) {
1986
1992
  return URLS[type].replace('{region}', region);
1987
1993
  }
1988
1994
 
1995
+ const uuid = () => uuid__default["default"].v4().toString();
1996
+
1989
1997
  /**
1990
1998
  * Unwraps v3 server payload (for error handling and type extraction)
1991
1999
  *
@@ -2010,6 +2018,24 @@ const unwrapPayload = (response) => {
2010
2018
  // unjust, but helps force uncast "T | undefined" to allow deconstruction without warnings
2011
2019
  return undefined;
2012
2020
  };
2021
+ /**
2022
+ * Builds a hex string of `bytes` length from the SDK's uuid helper (a v4 UUID is
2023
+ * 16 bytes / 32 hex chars once hyphens are removed) — avoids a new crypto dependency.
2024
+ */
2025
+ const randomHex = (bytes) => {
2026
+ let hex = '';
2027
+ while (hex.length < bytes * 2)
2028
+ hex += uuid().replace(/-/g, '');
2029
+ return hex.slice(0, bytes * 2);
2030
+ };
2031
+ /**
2032
+ * W3C Trace Context `traceparent`: `version-<16-byte trace-id>-<8-byte span-id>-<flags>`.
2033
+ * The SDK is the trace originator, so it mints a fresh trace + span id per request; flags `01` = sampled.
2034
+ *
2035
+ * @category Transport
2036
+ * @hidden
2037
+ */
2038
+ const generateTraceparent = () => `00-${randomHex(16)}-${randomHex(8)}-01`;
2013
2039
 
2014
2040
  class NetworkActivitiesWatcher {
2015
2041
  constructor() {
@@ -2134,6 +2160,10 @@ const createHttpTransport = (endpoint) => {
2134
2160
  });
2135
2161
  instance.defaults.withCredentials = false;
2136
2162
  instance.interceptors.request.use(config => {
2163
+ // Request tracing — set on every outbound request (login included), never persisted.
2164
+ // Must run before the session-url early-return below so /api/v5/sessions carries them too.
2165
+ config.headers.set('x-request-id', uuid());
2166
+ config.headers.set('traceparent', generateTraceparent());
2137
2167
  // do not check expiration for token creation url
2138
2168
  if (config.url === '/api/v5/sessions') {
2139
2169
  return config;
@@ -2177,20 +2207,28 @@ const createHttpTransport = (endpoint) => {
2177
2207
  });
2178
2208
  return response;
2179
2209
  }, error => {
2180
- var _a, _b, _c;
2210
+ var _a, _b, _c, _d;
2181
2211
  const { response } = error;
2182
2212
  // handle unauthorized request
2183
2213
  if ((response === null || response === void 0 ? void 0 : response.data.code) === 400100 /* Amity.ServerError.UNAUTHORIZED */) {
2184
2214
  fireEvent('tokenTerminated', "terminated" /* Amity.SessionStates.TERMINATED */);
2185
2215
  }
2216
+ // handle globally banned user. The realtime `user.didGlobalBan` event can be missed
2217
+ // (e.g. MQTT dropped before delivery), so mirror the 400100 handling above and fire
2218
+ // the same virtual event the login subscriptions already listen to. That terminates
2219
+ // the session with `TokenTerminationReason.GLOBAL_BAN` and notifies `onClientBanned`
2220
+ // consumers, instead of leaving the session `established` with a revoked token.
2221
+ if (((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.code) === 400312 /* Amity.ServerError.GLOBAL_BAN */) {
2222
+ fireEvent('user.didGlobalBan', { users: [], files: [] });
2223
+ }
2186
2224
  // handle visitor daily usage limit exceeded
2187
- if (((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.code) === 400323 /* Amity.ServerError.VISITOR_USAGE_LIMIT_EXCEEDED */) {
2225
+ if (((_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.code) === 400323 /* Amity.ServerError.VISITOR_USAGE_LIMIT_EXCEEDED */) {
2188
2226
  throttledFireVisitorUsageLimit();
2189
2227
  throw new ASCError('Visitor usage limit exceeded', 400323 /* Amity.ServerError.VISITOR_USAGE_LIMIT_EXCEEDED */, "error" /* Amity.ErrorLevel.ERROR */);
2190
2228
  }
2191
2229
  // if it's an error with status in the response payload,
2192
2230
  // then it's an expected error.
2193
- if ((_b = response === null || response === void 0 ? void 0 : response.data) === null || _b === void 0 ? void 0 : _b.status) {
2231
+ if ((_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.status) {
2194
2232
  unwrapPayload(response === null || response === void 0 ? void 0 : response.data);
2195
2233
  }
2196
2234
  // as on request cancellation error is returned
@@ -2198,7 +2236,7 @@ const createHttpTransport = (endpoint) => {
2198
2236
  throw error;
2199
2237
  }
2200
2238
  // unexpected error.
2201
- throw new Error((_c = response === null || response === void 0 ? void 0 : response.data) !== null && _c !== void 0 ? _c : error);
2239
+ throw new Error((_d = response === null || response === void 0 ? void 0 : response.data) !== null && _d !== void 0 ? _d : error);
2202
2240
  });
2203
2241
  instance.defaults.paramsSerializer = {
2204
2242
  encode: params => encodeURIComponent(params),
@@ -2404,8 +2442,6 @@ const getItem = async (key) => {
2404
2442
  });
2405
2443
  };
2406
2444
 
2407
- const uuid = () => uuid__default["default"].v4().toString();
2408
-
2409
2445
  // TODO: find a way to uniquely identify the device
2410
2446
  let tabIndex = 0;
2411
2447
  // This logic is running on browser only
@@ -2465,22 +2501,60 @@ const getMQTTClientId = async (userId) => {
2465
2501
  };
2466
2502
  /** @hidden */
2467
2503
  const getDeviceModel = () => {
2468
- var _a, _b;
2504
+ var _a;
2469
2505
  if ((_a = safeProcess.versions) === null || _a === void 0 ? void 0 : _a.node)
2470
2506
  return safeProcess.versions.node;
2471
- if (navigator)
2472
- return `${navigator.product.toLowerCase()}#${(_b = navigator.userAgent) !== null && _b !== void 0 ? _b : 'unknown_agent'}`;
2473
- return 'unknown_model';
2507
+ return undefined;
2508
+ };
2509
+ const hasNavigator = () => typeof navigator !== 'undefined' && !!navigator;
2510
+ const getLocale = () => (hasNavigator() ? navigator.language : undefined);
2511
+ const getTimezone = () => {
2512
+ try {
2513
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
2514
+ }
2515
+ catch (_a) {
2516
+ return undefined;
2517
+ }
2518
+ };
2519
+ const getNetworkType = () => {
2520
+ var _a;
2521
+ if (!hasNavigator())
2522
+ return undefined;
2523
+ return (_a = navigator.connection) === null || _a === void 0 ? void 0 : _a.effectiveType;
2524
+ };
2525
+ const isNode = () => { var _a; return !!((_a = safeProcess.versions) === null || _a === void 0 ? void 0 : _a.node); };
2526
+ const parseUserAgent = () => {
2527
+ if (!hasNavigator() || !navigator.userAgent)
2528
+ return {};
2529
+ const { os, browser, device } = new uaParserJs.UAParser(navigator.userAgent).getResult();
2530
+ const result = {};
2531
+ if (os.name)
2532
+ result.osName = os.name;
2533
+ if (os.version)
2534
+ result.osVersion = os.version;
2535
+ if (browser.name)
2536
+ result.browserName = browser.name;
2537
+ if (browser.version)
2538
+ result.browserVersion = browser.version;
2539
+ if (device.type === 'tablet')
2540
+ result.deviceType = 'tablet';
2541
+ else if (device.type === 'mobile')
2542
+ result.deviceType = 'mobile';
2543
+ else
2544
+ result.deviceType = 'desktop';
2545
+ return result;
2474
2546
  };
2475
2547
  /** @hidden */
2476
2548
  const getDeviceInfo = () => {
2477
- const model = getDeviceModel();
2478
- return {
2479
- // TODO: replace with: kind: process.versions ? 'node' : 'web', when backend has fixed this
2480
- kind: 'web',
2481
- model,
2482
- sdkVersion: VERSION,
2483
- };
2549
+ var _a;
2550
+ let client;
2551
+ try {
2552
+ client = getActiveClient();
2553
+ }
2554
+ catch (_b) {
2555
+ client = undefined;
2556
+ }
2557
+ return Object.assign({ kind: isNode() ? 'node' : 'web', model: getDeviceModel(), sdkVersion: VERSION, product: (_a = client === null || client === void 0 ? void 0 : client.product) !== null && _a !== void 0 ? _a : 'sdk', uikitVersion: client === null || client === void 0 ? void 0 : client.uikitVersion, appId: client === null || client === void 0 ? void 0 : client.appId, appVersion: client === null || client === void 0 ? void 0 : client.appVersion, locale: getLocale(), timezone: getTimezone(), networkType: getNetworkType() }, parseUserAgent());
2484
2558
  };
2485
2559
 
2486
2560
  /* eslint-disable no-console */
@@ -3921,6 +3995,95 @@ const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpd
3921
3995
  channelUsers });
3922
3996
  };
3923
3997
 
3998
+ const channelCacheKey = (channel) => [
3999
+ 'channel',
4000
+ 'get',
4001
+ getResolver('channel')(channel),
4002
+ ];
4003
+ /**
4004
+ * Find a cached channel by any of its ids (internal, public, or `channelId`).
4005
+ *
4006
+ * The channel cache is keyed by the channel internal id (see `idResolvers.channel`), but
4007
+ * realtime payloads reference channels by different ids: pin events carry the **public**
4008
+ * id, messages carry `channelId`. Try the cheap direct lookup first, then scan.
4009
+ */
4010
+ const findCachedChannelByAnyId = (id) => {
4011
+ var _a, _b, _c;
4012
+ if (!id)
4013
+ return undefined;
4014
+ const direct = (_a = pullFromCache(['channel', 'get', id])) === null || _a === void 0 ? void 0 : _a.data;
4015
+ if (direct)
4016
+ return direct;
4017
+ return (_c = (_b = queryCache(['channel', 'get'])) === null || _b === void 0 ? void 0 : _b.find(({ data }) => data.channelInternalId === id || data.channelPublicId === id || data.channelId === id)) === null || _c === void 0 ? void 0 : _c.data;
4018
+ };
4019
+ /**
4020
+ * Resolve the cached channel a `channel.messagePinned` / `channel.messageUnpinned` event
4021
+ * refers to. `data.channelId` is the channel public id; a pinned message body (present on
4022
+ * `messagePinned` only) also carries the internal id, which is the direct cache key.
4023
+ */
4024
+ const findCachedChannelForPin = (payload) => {
4025
+ var _a, _b;
4026
+ return (_b = findCachedChannelByAnyId((_a = payload.pinnedMessage) === null || _a === void 0 ? void 0 : _a.channelId)) !== null && _b !== void 0 ? _b : findCachedChannelByAnyId(payload.channelId);
4027
+ };
4028
+ /**
4029
+ * Write a new pin snapshot (or `null` to clear) on a cached channel and ingest any
4030
+ * users delivered with it (the pin author and the message author), so the banner can
4031
+ * render a byline without a second fetch.
4032
+ *
4033
+ * Every `messagePinned` payload is a full snapshot — "this is the pin now" — so the last
4034
+ * one received always wins; there is no merging with the previous pin.
4035
+ */
4036
+ const updatePinnedMessageCache = (channel, pinnedMessage, users) => {
4037
+ if (users && users.length > 0) {
4038
+ ingestInCache({ users: users.map(convertRawUserToInternalUser) });
4039
+ }
4040
+ const updated = Object.assign(Object.assign({}, channel), { pinnedMessage });
4041
+ pushToCache(channelCacheKey(channel), updated);
4042
+ return updated;
4043
+ };
4044
+
4045
+ /**
4046
+ * Applies a `channel.roleAdded` / `channel.roleRemoved` realtime payload to the cache.
4047
+ *
4048
+ * The event names every member the role request affected together with the
4049
+ * roles and channel-scoped permissions each of them is left holding. That is a
4050
+ * full state, not a delta, so it is written straight over the cached membership.
4051
+ *
4052
+ * Members the SDK has not fetched yet are skipped: the payload does not carry
4053
+ * enough to build a full {@link Amity.Membership} and the live collections only
4054
+ * emit rows that already exist in cache.
4055
+ *
4056
+ * @param payload the `data` of the realtime event
4057
+ * @returns the refreshed channel (when resolvable) and the updated cached memberships
4058
+ *
4059
+ * @hidden
4060
+ */
4061
+ const applyChannelRolePayload = (payload) => {
4062
+ var _a, _b, _c;
4063
+ const { channelId, users = [], channels = [] } = payload;
4064
+ const rawChannel = (_a = channels.find(channel => channel.channelId === channelId)) !== null && _a !== void 0 ? _a : channels[0];
4065
+ let channel;
4066
+ if (rawChannel) {
4067
+ const channelKey = ['channel', 'get', getResolver('channel')(rawChannel)];
4068
+ // the role event does not touch message previews, keep whatever preview is cached
4069
+ const converted = convertFromRaw(rawChannel, { isMessagePreviewUpdated: false });
4070
+ upsertInCache(channelKey, converted);
4071
+ channel = (_c = (_b = pullFromCache(channelKey)) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : converted;
4072
+ }
4073
+ const members = [];
4074
+ users.forEach(({ userId, roles, permissions }) => {
4075
+ var _a, _b, _c;
4076
+ const memberKey = ['channelUsers', 'get', getResolver('channelUsers')({ channelId, userId })];
4077
+ const cached = (_a = pullFromCache(memberKey)) === null || _a === void 0 ? void 0 : _a.data;
4078
+ if (!cached)
4079
+ return;
4080
+ const updated = Object.assign(Object.assign({}, cached), { roles, permissions });
4081
+ pushToCache(memberKey, updated);
4082
+ members.push((_c = (_b = pullFromCache(memberKey)) === null || _b === void 0 ? void 0 : _b.data) !== null && _c !== void 0 ? _c : updated);
4083
+ });
4084
+ return { channel, members };
4085
+ };
4086
+
3924
4087
  /**
3925
4088
  * ```js
3926
4089
  * import { getSubChannelMarkers } from '@amityco/ts-sdk-react-native'
@@ -4106,32 +4269,6 @@ const channelMemberLinkedObject = (channelMember) => {
4106
4269
  } });
4107
4270
  };
4108
4271
 
4109
- /**
4110
- *
4111
- * get current user's membership data
4112
- *
4113
- * @returns the {@link Amity.Membership<'channel'>} objects
4114
- *
4115
- * @category Channel API
4116
- * @async
4117
- */
4118
- const getMyMembership$1 = (channelId) => {
4119
- const client = getActiveClient();
4120
- client.log('channel/getMyMembership.locally');
4121
- const cacheChannelUser = pullFromCache([
4122
- 'channelUsers',
4123
- 'get',
4124
- `${channelId}#${client.userId}`,
4125
- ]);
4126
- if (!cacheChannelUser) {
4127
- throw new ASCApiError('Item not found!', 400400 /* Amity.ServerError.ITEM_NOT_FOUND */, "error" /* Amity.ErrorLevel.ERROR */);
4128
- }
4129
- return {
4130
- data: cacheChannelUser.data,
4131
- cachedAt: cacheChannelUser.cachedAt,
4132
- };
4133
- };
4134
-
4135
4272
  /**
4136
4273
  * ```js
4137
4274
  * import { isEqual } from '~/utils/isEqual'
@@ -4202,55 +4339,81 @@ function isEqual(x, y) {
4202
4339
  }));
4203
4340
  }
4204
4341
 
4205
- const callbacks$c = [];
4342
+ /**
4343
+ *
4344
+ * get current user's membership data
4345
+ *
4346
+ * @returns the {@link Amity.Membership<'channel'>} objects
4347
+ *
4348
+ * @category Channel API
4349
+ * @async
4350
+ */
4351
+ const getMyMembership$1 = (channelId) => {
4352
+ const client = getActiveClient();
4353
+ client.log('channel/getMyMembership.locally');
4354
+ const cacheChannelUser = pullFromCache([
4355
+ 'channelUsers',
4356
+ 'get',
4357
+ `${channelId}#${client.userId}`,
4358
+ ]);
4359
+ if (!cacheChannelUser) {
4360
+ throw new ASCApiError('Item not found!', 400400 /* Amity.ServerError.ITEM_NOT_FOUND */, "error" /* Amity.ErrorLevel.ERROR */);
4361
+ }
4362
+ return {
4363
+ data: cacheChannelUser.data,
4364
+ cachedAt: cacheChannelUser.cachedAt,
4365
+ };
4366
+ };
4367
+
4368
+ const callbacks$e = [];
4206
4369
  let mainDisposer$b = null;
4207
- const dispose$c = (cb) => {
4208
- const index = callbacks$c.indexOf(cb);
4370
+ const dispose$e = (cb) => {
4371
+ const index = callbacks$e.indexOf(cb);
4209
4372
  if (index > -1) {
4210
- callbacks$c.splice(index, 1);
4373
+ callbacks$e.splice(index, 1);
4211
4374
  }
4212
- if (callbacks$c.length === 0) {
4375
+ if (callbacks$e.length === 0) {
4213
4376
  mainDisposer$b === null || mainDisposer$b === void 0 ? void 0 : mainDisposer$b();
4214
4377
  }
4215
4378
  };
4216
4379
  const onChannelCreated = (callback) => {
4217
- if (callbacks$c.length === 0) {
4380
+ if (callbacks$e.length === 0) {
4218
4381
  const client = getActiveClient();
4219
4382
  const filter = async (payload) => {
4220
4383
  const data = await prepareChannelPayload(payload);
4221
4384
  ingestInCache(data);
4222
- callbacks$c.forEach(cb => cb(data.channels[0]));
4385
+ callbacks$e.forEach(cb => cb(data.channels[0]));
4223
4386
  };
4224
4387
  mainDisposer$b = createEventSubscriber(client, 'onChannelCreated', 'channel.created', filter);
4225
4388
  }
4226
- callbacks$c.push(callback);
4227
- return () => dispose$c(callback);
4389
+ callbacks$e.push(callback);
4390
+ return () => dispose$e(callback);
4228
4391
  };
4229
4392
 
4230
- const callbacks$b = [];
4231
- const mainDisposers = [];
4232
- const dispose$b = (cb) => {
4233
- const index = callbacks$b.indexOf(cb);
4393
+ const callbacks$d = [];
4394
+ const mainDisposers$2 = [];
4395
+ const dispose$d = (cb) => {
4396
+ const index = callbacks$d.indexOf(cb);
4234
4397
  if (index > -1) {
4235
- callbacks$b.splice(index, 1);
4398
+ callbacks$d.splice(index, 1);
4236
4399
  }
4237
- if (callbacks$b.length === 0) {
4238
- mainDisposers.forEach(fn => fn());
4400
+ if (callbacks$d.length === 0) {
4401
+ mainDisposers$2.forEach(fn => fn());
4239
4402
  }
4240
4403
  };
4241
4404
  const onChannelUpdated = (callback) => {
4242
4405
  const client = getActiveClient();
4243
- if (callbacks$b.length === 0) {
4406
+ if (callbacks$d.length === 0) {
4244
4407
  const filter = async (payload) => {
4245
4408
  const data = await prepareChannelPayload(payload);
4246
4409
  ingestInCache(data);
4247
- callbacks$b.forEach(cb => cb(data.channels[0]));
4410
+ callbacks$d.forEach(cb => cb(data.channels[0]));
4248
4411
  };
4249
- mainDisposers.push(createEventSubscriber(client, 'onChannelUpdated', 'channel.updated', filter));
4250
- mainDisposers.push(createEventSubscriber(client, 'onChannelUpdated', 'local.channel.updated', payload => callbacks$b.forEach(cb => cb(payload.channels[0]))));
4412
+ mainDisposers$2.push(createEventSubscriber(client, 'onChannelUpdated', 'channel.updated', filter));
4413
+ mainDisposers$2.push(createEventSubscriber(client, 'onChannelUpdated', 'local.channel.updated', payload => callbacks$d.forEach(cb => cb(payload.channels[0]))));
4251
4414
  }
4252
- callbacks$b.push(callback);
4253
- return () => dispose$b(callback);
4415
+ callbacks$d.push(callback);
4416
+ return () => dispose$d(callback);
4254
4417
  };
4255
4418
 
4256
4419
  const addFlagIsDeletedSubChannelUnreadByChannelId = (channelId) => {
@@ -4273,19 +4436,19 @@ const deleteChannelUnreadByChannelId = (channelId) => {
4273
4436
  }
4274
4437
  };
4275
4438
 
4276
- const callbacks$a = [];
4439
+ const callbacks$c = [];
4277
4440
  let mainDisposer$a = null;
4278
- const dispose$a = (cb) => {
4279
- const index = callbacks$a.indexOf(cb);
4441
+ const dispose$c = (cb) => {
4442
+ const index = callbacks$c.indexOf(cb);
4280
4443
  if (index > -1) {
4281
- callbacks$a.splice(index, 1);
4444
+ callbacks$c.splice(index, 1);
4282
4445
  }
4283
- if (callbacks$a.length === 0) {
4446
+ if (callbacks$c.length === 0) {
4284
4447
  mainDisposer$a === null || mainDisposer$a === void 0 ? void 0 : mainDisposer$a();
4285
4448
  }
4286
4449
  };
4287
4450
  const onChannelDeleted = (callback) => {
4288
- if (callbacks$a.length === 0) {
4451
+ if (callbacks$c.length === 0) {
4289
4452
  const client = getActiveClient();
4290
4453
  const filter = async (payload) => {
4291
4454
  const data = await prepareChannelPayload(payload);
@@ -4305,53 +4468,53 @@ const onChannelDeleted = (callback) => {
4305
4468
  }
4306
4469
  });
4307
4470
  ingestInCache(data);
4308
- callbacks$a.forEach(cb => cb(data.channels[0]));
4471
+ callbacks$c.forEach(cb => cb(data.channels[0]));
4309
4472
  };
4310
4473
  mainDisposer$a = createEventSubscriber(client, 'onChannelDeleted', 'channel.deleted', filter);
4311
4474
  }
4312
- callbacks$a.push(callback);
4313
- return () => dispose$a(callback);
4475
+ callbacks$c.push(callback);
4476
+ return () => dispose$c(callback);
4314
4477
  };
4315
4478
 
4316
- const callbacks$9 = [];
4479
+ const callbacks$b = [];
4317
4480
  let mainDisposer$9 = null;
4318
- const dispose$9 = (cb) => {
4319
- const index = callbacks$9.indexOf(cb);
4481
+ const dispose$b = (cb) => {
4482
+ const index = callbacks$b.indexOf(cb);
4320
4483
  if (index > -1) {
4321
- callbacks$9.splice(index, 1);
4484
+ callbacks$b.splice(index, 1);
4322
4485
  }
4323
- if (callbacks$9.length === 0) {
4486
+ if (callbacks$b.length === 0) {
4324
4487
  mainDisposer$9 === null || mainDisposer$9 === void 0 ? void 0 : mainDisposer$9();
4325
4488
  }
4326
4489
  };
4327
4490
  const onChannelJoined = (callback) => {
4328
- if (callbacks$9.length === 0) {
4491
+ if (callbacks$b.length === 0) {
4329
4492
  const client = getActiveClient();
4330
4493
  const filter = async (payload) => {
4331
4494
  const preparedPayload = await prepareChannelPayload(payload);
4332
4495
  const { channels, channelUsers } = preparedPayload;
4333
4496
  ingestInCache(preparedPayload);
4334
- callbacks$9.forEach(cb => cb(channels[0], channelUsers[0]));
4497
+ callbacks$b.forEach(cb => cb(channels[0], channelUsers[0]));
4335
4498
  };
4336
4499
  mainDisposer$9 = createEventSubscriber(client, 'onChannelJoined', 'channel.joined', filter);
4337
4500
  }
4338
- callbacks$9.push(callback);
4339
- return () => dispose$9(callback);
4501
+ callbacks$b.push(callback);
4502
+ return () => dispose$b(callback);
4340
4503
  };
4341
4504
 
4342
- const callbacks$8 = [];
4505
+ const callbacks$a = [];
4343
4506
  let mainDisposer$8 = null;
4344
- const dispose$8 = (cb) => {
4345
- const index = callbacks$8.indexOf(cb);
4507
+ const dispose$a = (cb) => {
4508
+ const index = callbacks$a.indexOf(cb);
4346
4509
  if (index > -1) {
4347
- callbacks$8.splice(index, 1);
4510
+ callbacks$a.splice(index, 1);
4348
4511
  }
4349
- if (callbacks$8.length === 0) {
4512
+ if (callbacks$a.length === 0) {
4350
4513
  mainDisposer$8 === null || mainDisposer$8 === void 0 ? void 0 : mainDisposer$8();
4351
4514
  }
4352
4515
  };
4353
4516
  const onChannelLeft = (callback) => {
4354
- if (callbacks$8.length === 0) {
4517
+ if (callbacks$a.length === 0) {
4355
4518
  const client = getActiveClient();
4356
4519
  const filter = async (payload) => {
4357
4520
  const { userId } = getActiveClient();
@@ -4375,27 +4538,27 @@ const onChannelLeft = (callback) => {
4375
4538
  }
4376
4539
  const { channels, channelUsers } = preparedPayload;
4377
4540
  ingestInCache(preparedPayload);
4378
- callbacks$8.forEach(cb => cb(channels[0], channelUsers[0]));
4541
+ callbacks$a.forEach(cb => cb(channels[0], channelUsers[0]));
4379
4542
  };
4380
4543
  mainDisposer$8 = createEventSubscriber(client, 'onChannelLeft', 'channel.left', filter);
4381
4544
  }
4382
- callbacks$8.push(callback);
4383
- return () => dispose$8(callback);
4545
+ callbacks$a.push(callback);
4546
+ return () => dispose$a(callback);
4384
4547
  };
4385
4548
 
4386
- const callbacks$7 = [];
4549
+ const callbacks$9 = [];
4387
4550
  let mainDisposer$7 = null;
4388
- const dispose$7 = (cb) => {
4389
- const index = callbacks$7.indexOf(cb);
4551
+ const dispose$9 = (cb) => {
4552
+ const index = callbacks$9.indexOf(cb);
4390
4553
  if (index > -1) {
4391
- callbacks$7.splice(index, 1);
4554
+ callbacks$9.splice(index, 1);
4392
4555
  }
4393
- if (callbacks$7.length === 0) {
4556
+ if (callbacks$9.length === 0) {
4394
4557
  mainDisposer$7 === null || mainDisposer$7 === void 0 ? void 0 : mainDisposer$7();
4395
4558
  }
4396
4559
  };
4397
4560
  const onChannelSetMuted = (callback) => {
4398
- if (callbacks$7.length === 0) {
4561
+ if (callbacks$9.length === 0) {
4399
4562
  const client = getActiveClient();
4400
4563
  const filter = async (payload) => {
4401
4564
  var _a;
@@ -4410,24 +4573,124 @@ const onChannelSetMuted = (callback) => {
4410
4573
  payload.channelId,
4411
4574
  ])) === null || _a === void 0 ? void 0 : _a.data;
4412
4575
  if (channel) {
4413
- callbacks$7.forEach(cb => cb(channel));
4576
+ callbacks$9.forEach(cb => cb(channel));
4414
4577
  }
4415
4578
  };
4416
4579
  mainDisposer$7 = createEventSubscriber(client, 'onChannelMute', 'channel.setMuted', filter);
4417
4580
  }
4581
+ callbacks$9.push(callback);
4582
+ return () => dispose$9(callback);
4583
+ };
4584
+
4585
+ const callbacks$8 = [];
4586
+ let mainDisposer$6 = null;
4587
+ const dispose$8 = (cb) => {
4588
+ const index = callbacks$8.indexOf(cb);
4589
+ if (index > -1) {
4590
+ callbacks$8.splice(index, 1);
4591
+ }
4592
+ if (callbacks$8.length === 0) {
4593
+ mainDisposer$6 === null || mainDisposer$6 === void 0 ? void 0 : mainDisposer$6();
4594
+ }
4595
+ };
4596
+ /* begin_public_function
4597
+ id: channel.event.message_pinned
4598
+ */
4599
+ /**
4600
+ * ```js
4601
+ * import { onChannelMessagePinned } from '@amityco/ts-sdk'
4602
+ * const dispose = onChannelMessagePinned(channel => {
4603
+ * // channel.pinnedMessage is the new pin
4604
+ * })
4605
+ * ```
4606
+ *
4607
+ * Fired when a message is pinned in a channel (the `channel.messagePinned` realtime
4608
+ * event). Pinning a different message while one is already pinned emits a single
4609
+ * `messagePinned` carrying the replacement — treat every payload as a full snapshot.
4610
+ *
4611
+ * The updated channel is written to cache before the callback runs, so
4612
+ * `ChannelRepository.getChannel` observers see `channel.pinnedMessage` change.
4613
+ *
4614
+ * @param callback The function to call when the event was fired
4615
+ * @returns an {@link Amity.Unsubscriber} function to run when willing to stop listening
4616
+ *
4617
+ * @category Channel Events
4618
+ */
4619
+ const onChannelMessagePinned = (callback) => {
4620
+ if (callbacks$8.length === 0) {
4621
+ const client = getActiveClient();
4622
+ const filter = (payload) => {
4623
+ var _a;
4624
+ const channel = findCachedChannelForPin(payload);
4625
+ if (!channel)
4626
+ return;
4627
+ const updated = updatePinnedMessageCache(channel, (_a = payload.pinnedMessage) !== null && _a !== void 0 ? _a : null, payload.users);
4628
+ callbacks$8.forEach(cb => cb(updated));
4629
+ };
4630
+ mainDisposer$6 = createEventSubscriber(client, 'onChannelMessagePinned', 'channel.messagePinned', filter);
4631
+ }
4632
+ callbacks$8.push(callback);
4633
+ return () => dispose$8(callback);
4634
+ };
4635
+ /* end_public_function */
4636
+
4637
+ const callbacks$7 = [];
4638
+ let mainDisposer$5 = null;
4639
+ const dispose$7 = (cb) => {
4640
+ const index = callbacks$7.indexOf(cb);
4641
+ if (index > -1) {
4642
+ callbacks$7.splice(index, 1);
4643
+ }
4644
+ if (callbacks$7.length === 0) {
4645
+ mainDisposer$5 === null || mainDisposer$5 === void 0 ? void 0 : mainDisposer$5();
4646
+ }
4647
+ };
4648
+ /* begin_public_function
4649
+ id: channel.event.message_unpinned
4650
+ */
4651
+ /**
4652
+ * ```js
4653
+ * import { onChannelMessageUnpinned } from '@amityco/ts-sdk'
4654
+ * const dispose = onChannelMessageUnpinned(channel => {
4655
+ * // channel.pinnedMessage is now null
4656
+ * })
4657
+ * ```
4658
+ *
4659
+ * Fired when a channel's pinned message is removed (the `channel.messageUnpinned`
4660
+ * realtime event) — either by an explicit unpin or automatically by the server when the
4661
+ * pinned message is deleted or its author is banned from the channel / globally.
4662
+ *
4663
+ * @param callback The function to call when the event was fired
4664
+ * @returns an {@link Amity.Unsubscriber} function to run when willing to stop listening
4665
+ *
4666
+ * @category Channel Events
4667
+ */
4668
+ const onChannelMessageUnpinned = (callback) => {
4669
+ if (callbacks$7.length === 0) {
4670
+ const client = getActiveClient();
4671
+ const filter = (payload) => {
4672
+ const channel = findCachedChannelForPin(payload);
4673
+ if (!channel)
4674
+ return;
4675
+ const updated = updatePinnedMessageCache(channel, null);
4676
+ callbacks$7.forEach(cb => cb(updated));
4677
+ };
4678
+ mainDisposer$5 = createEventSubscriber(client, 'onChannelMessageUnpinned', 'channel.messageUnpinned', filter);
4679
+ }
4418
4680
  callbacks$7.push(callback);
4419
4681
  return () => dispose$7(callback);
4420
4682
  };
4683
+ /* end_public_function */
4421
4684
 
4422
4685
  const callbacks$6 = [];
4423
- let mainDisposer$6 = null;
4686
+ let mainDisposer$4 = null;
4424
4687
  const dispose$6 = (cb) => {
4425
4688
  const index = callbacks$6.indexOf(cb);
4426
4689
  if (index > -1) {
4427
4690
  callbacks$6.splice(index, 1);
4428
4691
  }
4429
4692
  if (callbacks$6.length === 0) {
4430
- mainDisposer$6 === null || mainDisposer$6 === void 0 ? void 0 : mainDisposer$6();
4693
+ mainDisposer$4 === null || mainDisposer$4 === void 0 ? void 0 : mainDisposer$4();
4431
4694
  }
4432
4695
  };
4433
4696
  const onChannelMemberAdded = (callback) => {
@@ -4439,21 +4702,21 @@ const onChannelMemberAdded = (callback) => {
4439
4702
  ingestInCache(preparedPayload);
4440
4703
  callbacks$6.forEach(cb => cb(channels[0], channelUsers.find(cu => cu.membership === 'member')));
4441
4704
  };
4442
- mainDisposer$6 = createEventSubscriber(client, 'onChannelMemberAdded', 'channel.membersAdded', filter);
4705
+ mainDisposer$4 = createEventSubscriber(client, 'onChannelMemberAdded', 'channel.membersAdded', filter);
4443
4706
  }
4444
4707
  callbacks$6.push(callback);
4445
4708
  return () => dispose$6(callback);
4446
4709
  };
4447
4710
 
4448
4711
  const callbacks$5 = [];
4449
- let mainDisposer$5 = null;
4712
+ let mainDisposer$3 = null;
4450
4713
  const dispose$5 = (cb) => {
4451
4714
  const index = callbacks$5.indexOf(cb);
4452
4715
  if (index > -1) {
4453
4716
  callbacks$5.splice(index, 1);
4454
4717
  }
4455
4718
  if (callbacks$5.length === 0) {
4456
- mainDisposer$5 === null || mainDisposer$5 === void 0 ? void 0 : mainDisposer$5();
4719
+ mainDisposer$3 === null || mainDisposer$3 === void 0 ? void 0 : mainDisposer$3();
4457
4720
  }
4458
4721
  };
4459
4722
  const onChannelMemberRemoved = (callback) => {
@@ -4465,21 +4728,21 @@ const onChannelMemberRemoved = (callback) => {
4465
4728
  ingestInCache(preparedPayload);
4466
4729
  callbacks$5.forEach(cb => cb(channels[0], channelUsers[0]));
4467
4730
  };
4468
- mainDisposer$5 = createEventSubscriber(client, 'onChannelMemberRemoved', 'channel.membersRemoved', filter);
4731
+ mainDisposer$3 = createEventSubscriber(client, 'onChannelMemberRemoved', 'channel.membersRemoved', filter);
4469
4732
  }
4470
4733
  callbacks$5.push(callback);
4471
4734
  return () => dispose$5(callback);
4472
4735
  };
4473
4736
 
4474
4737
  const callbacks$4 = [];
4475
- let mainDisposer$4 = null;
4738
+ let mainDisposer$2 = null;
4476
4739
  const dispose$4 = (cb) => {
4477
4740
  const index = callbacks$4.indexOf(cb);
4478
4741
  if (index > -1) {
4479
4742
  callbacks$4.splice(index, 1);
4480
4743
  }
4481
4744
  if (callbacks$4.length === 0) {
4482
- mainDisposer$4 === null || mainDisposer$4 === void 0 ? void 0 : mainDisposer$4();
4745
+ mainDisposer$2 === null || mainDisposer$2 === void 0 ? void 0 : mainDisposer$2();
4483
4746
  }
4484
4747
  };
4485
4748
  const onChannelMemberBanned = (callback) => {
@@ -4499,20 +4762,20 @@ const onChannelMemberBanned = (callback) => {
4499
4762
  ingestInCache(preparedPayload);
4500
4763
  callbacks$4.forEach(cb => cb(channels[0], channelUsers.find(cu => cu.membership === 'banned')));
4501
4764
  };
4502
- mainDisposer$4 = createEventSubscriber(client, 'onChannelMemberBanned', 'channel.banned', filter);
4765
+ mainDisposer$2 = createEventSubscriber(client, 'onChannelMemberBanned', 'channel.banned', filter);
4503
4766
  callbacks$4.push(callback);
4504
4767
  return () => dispose$4(callback);
4505
4768
  };
4506
4769
 
4507
4770
  const callbacks$3 = [];
4508
- let mainDisposer$3 = null;
4771
+ let mainDisposer$1 = null;
4509
4772
  const dispose$3 = (cb) => {
4510
4773
  const index = callbacks$3.indexOf(cb);
4511
4774
  if (index > -1) {
4512
4775
  callbacks$3.splice(index, 1);
4513
4776
  }
4514
4777
  if (callbacks$3.length === 0) {
4515
- mainDisposer$3 === null || mainDisposer$3 === void 0 ? void 0 : mainDisposer$3();
4778
+ mainDisposer$1 === null || mainDisposer$1 === void 0 ? void 0 : mainDisposer$1();
4516
4779
  }
4517
4780
  };
4518
4781
  const onChannelMemberUnbanned = (callback) => {
@@ -4524,59 +4787,127 @@ const onChannelMemberUnbanned = (callback) => {
4524
4787
  ingestInCache(preparedPayload);
4525
4788
  callbacks$3.forEach(cb => cb(channels[0], channelUsers.find(cu => cu.membership === 'none')));
4526
4789
  };
4527
- mainDisposer$3 = createEventSubscriber(client, 'onChannelMemberUnbanned', 'channel.unbanned', filter);
4790
+ mainDisposer$1 = createEventSubscriber(client, 'onChannelMemberUnbanned', 'channel.unbanned', filter);
4528
4791
  }
4529
4792
  callbacks$3.push(callback);
4530
4793
  return () => dispose$3(callback);
4531
4794
  };
4532
4795
 
4533
4796
  const callbacks$2 = [];
4534
- let mainDisposer$2 = null;
4797
+ const mainDisposers$1 = [];
4535
4798
  const dispose$2 = (cb) => {
4536
4799
  const index = callbacks$2.indexOf(cb);
4537
4800
  if (index > -1) {
4538
4801
  callbacks$2.splice(index, 1);
4539
4802
  }
4540
4803
  if (callbacks$2.length === 0) {
4541
- mainDisposer$2 === null || mainDisposer$2 === void 0 ? void 0 : mainDisposer$2();
4804
+ mainDisposers$1.forEach(fn => fn());
4805
+ mainDisposers$1.length = 0;
4542
4806
  }
4543
4807
  };
4808
+ /* begin_public_function
4809
+ id: channel.event.member_role_added
4810
+ */
4811
+ /**
4812
+ * ```js
4813
+ * import { onChannelMemberRoleAdded } from '@amityco/ts-sdk'
4814
+ * const dispose = onChannelMemberRoleAdded((channel, member) => {
4815
+ * // member.roles and member.permissions are the member's resulting state
4816
+ * })
4817
+ * ```
4818
+ *
4819
+ * Fired when a role is added to a member of a {@link Amity.Channel}, either by the
4820
+ * local `ChannelRepository.Moderation.addRole` call or by the `channel.roleAdded` realtime
4821
+ * event coming from any client or the admin console.
4822
+ *
4823
+ * The realtime event reaches every subscriber of the channel topic (see `getChannelTopic`),
4824
+ * not only the actor or the affected members. It carries the affected members' resulting
4825
+ * channel roles and channel-scoped permissions, which are written to cache before the
4826
+ * callback runs. The callback is invoked once per affected member already held in cache.
4827
+ *
4828
+ * @param callback The function to call when the event was fired
4829
+ * @returns an {@link Amity.Unsubscriber} function to run when willing to stop listening
4830
+ *
4831
+ * @category Channel Events
4832
+ */
4544
4833
  const onChannelMemberRoleAdded = (callback) => {
4545
4834
  if (callbacks$2.length === 0) {
4546
4835
  const client = getActiveClient();
4547
- const filter = async (payload) => {
4836
+ const onLocal = async (payload) => {
4548
4837
  const { channels, channelUsers } = payload;
4549
4838
  callbacks$2.forEach(cb => cb(channels[0], channelUsers.find(channelUser => channelUser.membership === 'member')));
4550
4839
  };
4551
- mainDisposer$2 = createEventSubscriber(client, 'onChannelMemberRoleAdded', 'local.channel-moderator.role-added', filter);
4840
+ const onRealtime = (payload) => {
4841
+ const { channel, members } = applyChannelRolePayload(payload);
4842
+ if (!channel)
4843
+ return;
4844
+ members.forEach(member => callbacks$2.forEach(cb => cb(channel, member)));
4845
+ };
4846
+ mainDisposers$1.push(createEventSubscriber(client, 'onChannelMemberRoleAdded', 'local.channel-moderator.role-added', onLocal));
4847
+ mainDisposers$1.push(createEventSubscriber(client, 'onChannelMemberRoleAdded', 'channel.roleAdded', onRealtime));
4552
4848
  }
4553
4849
  callbacks$2.push(callback);
4554
4850
  return () => dispose$2(callback);
4555
4851
  };
4852
+ /* end_public_function */
4556
4853
 
4557
4854
  const callbacks$1 = [];
4558
- let mainDisposer$1 = null;
4855
+ const mainDisposers = [];
4559
4856
  const dispose$1 = (cb) => {
4560
4857
  const index = callbacks$1.indexOf(cb);
4561
4858
  if (index > -1) {
4562
4859
  callbacks$1.splice(index, 1);
4563
4860
  }
4564
4861
  if (callbacks$1.length === 0) {
4565
- mainDisposer$1 === null || mainDisposer$1 === void 0 ? void 0 : mainDisposer$1();
4862
+ mainDisposers.forEach(fn => fn());
4863
+ mainDisposers.length = 0;
4566
4864
  }
4567
4865
  };
4866
+ /* begin_public_function
4867
+ id: channel.event.member_role_removed
4868
+ */
4869
+ /**
4870
+ * ```js
4871
+ * import { onChannelMemberRoleRemoved } from '@amityco/ts-sdk'
4872
+ * const dispose = onChannelMemberRoleRemoved((channel, member) => {
4873
+ * // member.roles and member.permissions are the member's resulting state
4874
+ * })
4875
+ * ```
4876
+ *
4877
+ * Fired when a role is removed from a member of a {@link Amity.Channel}, either by the
4878
+ * local `ChannelRepository.Moderation.removeRole` call or by the `channel.roleRemoved` realtime
4879
+ * event coming from any client or the admin console.
4880
+ *
4881
+ * The realtime event reaches every subscriber of the channel topic (see `getChannelTopic`),
4882
+ * not only the actor or the affected members. It carries the affected members' resulting
4883
+ * channel roles and channel-scoped permissions, which are written to cache before the
4884
+ * callback runs. The callback is invoked once per affected member already held in cache.
4885
+ *
4886
+ * @param callback The function to call when the event was fired
4887
+ * @returns an {@link Amity.Unsubscriber} function to run when willing to stop listening
4888
+ *
4889
+ * @category Channel Events
4890
+ */
4568
4891
  const onChannelMemberRoleRemoved = (callback) => {
4569
4892
  if (callbacks$1.length === 0) {
4570
4893
  const client = getActiveClient();
4571
- const filter = async (payload) => {
4894
+ const onLocal = async (payload) => {
4572
4895
  const { channels, channelUsers } = payload;
4573
4896
  callbacks$1.forEach(cb => cb(channels[0], channelUsers.find(channelUser => channelUser.membership === 'member')));
4574
4897
  };
4575
- mainDisposer$1 = createEventSubscriber(client, 'onChannelMemberRoleRemoved', 'local.channel-moderator.role-removed', filter);
4898
+ const onRealtime = (payload) => {
4899
+ const { channel, members } = applyChannelRolePayload(payload);
4900
+ if (!channel)
4901
+ return;
4902
+ members.forEach(member => callbacks$1.forEach(cb => cb(channel, member)));
4903
+ };
4904
+ mainDisposers.push(createEventSubscriber(client, 'onChannelMemberRoleRemoved', 'local.channel-moderator.role-removed', onLocal));
4905
+ mainDisposers.push(createEventSubscriber(client, 'onChannelMemberRoleRemoved', 'channel.roleRemoved', onRealtime));
4576
4906
  }
4577
4907
  callbacks$1.push(callback);
4578
4908
  return () => dispose$1(callback);
4579
4909
  };
4910
+ /* end_public_function */
4580
4911
 
4581
4912
  /**
4582
4913
  * Fired when a {@link Amity.Channel} has been archived by the active user.
@@ -4700,6 +5031,8 @@ const getMyMembership = (channelId, callback) => {
4700
5031
  disposers.push(onChannelMemberBanned(realtimeRouter));
4701
5032
  disposers.push(onChannelMemberUnbanned(realtimeRouter));
4702
5033
  disposers.push(onChannelSetUserMuted(realtimeRouter));
5034
+ disposers.push(onChannelMemberRoleAdded(realtimeRouter));
5035
+ disposers.push(onChannelMemberRoleRemoved(realtimeRouter));
4703
5036
  onFetch();
4704
5037
  return () => {
4705
5038
  disposers.forEach(fn => fn());
@@ -5093,7 +5426,9 @@ const initializeMessagePreviewSetting = async () => {
5093
5426
  const getSocialSettings = async () => {
5094
5427
  const client = getActiveClient();
5095
5428
  const { data } = await client.http.get(`/api/v3/network-settings/social`);
5096
- return data.socialNetworkSetting;
5429
+ return Object.assign(Object.assign({}, data.socialNetworkSetting), {
5430
+ // Networks that never set the comment edit switch allow the edit
5431
+ isAllowEditCommentWhenReviewingEnabled: data.socialNetworkSetting.isAllowEditCommentWhenReviewingEnabled });
5097
5432
  };
5098
5433
 
5099
5434
  /**
@@ -5779,6 +6114,32 @@ class AnalyticsEventCapturer {
5779
6114
  activityType: "view" /* Amity.AnalyticEventActivityType.View */,
5780
6115
  });
5781
6116
  }
6117
+ markCuratedContentWidgetAsViewed(topicId) {
6118
+ this.markAs({
6119
+ uniqueId: `curatedContentWidget.${topicId}`,
6120
+ contentId: topicId,
6121
+ contentType: "curated_content_widget" /* Amity.AnalyticEventContentType.CuratedContentWidget */,
6122
+ activityType: "view" /* Amity.AnalyticEventActivityType.View */,
6123
+ });
6124
+ }
6125
+ markCuratedContentPostAsViewed(postId, topicId) {
6126
+ this.markAs({
6127
+ uniqueId: `curatedContentPost.${postId}.view`,
6128
+ contentId: postId,
6129
+ contentType: "curated_content_post" /* Amity.AnalyticEventContentType.CuratedContentPost */,
6130
+ activityType: "view" /* Amity.AnalyticEventActivityType.View */,
6131
+ metadata: { topicId },
6132
+ });
6133
+ }
6134
+ markCuratedContentPostAsClicked(postId, topicId) {
6135
+ this.markAs({
6136
+ uniqueId: `curatedContentPost.${postId}.click`,
6137
+ contentId: postId,
6138
+ contentType: "curated_content_post" /* Amity.AnalyticEventContentType.CuratedContentPost */,
6139
+ activityType: "linkClicked" /* Amity.AnalyticEventActivityType.Click */,
6140
+ metadata: { topicId },
6141
+ });
6142
+ }
5782
6143
  markPostAsMeaningfullyViewed(postId, feedRenderPosition) {
5783
6144
  var _a;
5784
6145
  const cached = (_a = pullFromCache(['feedMetadata', 'get', postId])) === null || _a === void 0 ? void 0 : _a.data;
@@ -5942,6 +6303,24 @@ class AnalyticsEngine {
5942
6303
  this._eventCapturer.markPostAsViewed(postId);
5943
6304
  }
5944
6305
  }
6306
+ markCuratedContentWidgetAsViewed(topicId) {
6307
+ if (this._client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */ ||
6308
+ this._client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
6309
+ this._eventCapturer.markCuratedContentWidgetAsViewed(topicId);
6310
+ }
6311
+ }
6312
+ markCuratedContentPostAsViewed(postId, topicId) {
6313
+ if (this._client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */ ||
6314
+ this._client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
6315
+ this._eventCapturer.markCuratedContentPostAsViewed(postId, topicId);
6316
+ }
6317
+ }
6318
+ markCuratedContentPostAsClicked(postId, topicId) {
6319
+ if (this._client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */ ||
6320
+ this._client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
6321
+ this._eventCapturer.markCuratedContentPostAsClicked(postId, topicId);
6322
+ }
6323
+ }
5945
6324
  markPostAsMeaningfullyViewed(postId, feedRenderPosition) {
5946
6325
  if (this._client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */ ||
5947
6326
  this._client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
@@ -7368,6 +7747,265 @@ class CursorController {
7368
7747
  }
7369
7748
  }
7370
7749
 
7750
+ class ResetTask {
7751
+ constructor(postId, latestCreatedAt, serverCommentCount) {
7752
+ this.postId = postId;
7753
+ this.latestCreatedAt = latestCreatedAt;
7754
+ this.serverCommentCount = serverCommentCount;
7755
+ }
7756
+ }
7757
+
7758
+ // Task to track comment creation
7759
+ class CreateTask {
7760
+ constructor(postId, commentId, createdAt) {
7761
+ this.postId = postId;
7762
+ this.commentId = commentId;
7763
+ this.createdAt = createdAt;
7764
+ }
7765
+ }
7766
+
7767
+ /**
7768
+ * A pending comment was approved and now counts publicly. Unlike `CreateTask` it carries no
7769
+ * `createdAt` and bypasses the age guard on purpose: the comment was written before the last post
7770
+ * payload (so its `createdAt` is old) but entered the server count only now. Same rule as iOS.
7771
+ *
7772
+ * Accepted trade-off (plan 40 §9): if a `ResetTask` that already includes this comment lands
7773
+ * between the approve response and the late `comment.approved` event, the count reads +1 until
7774
+ * the next server sync — the same self-correcting drift accepted for stale deletes.
7775
+ */
7776
+ class ApproveTask {
7777
+ constructor(postId, commentId) {
7778
+ this.postId = postId;
7779
+ this.commentId = commentId;
7780
+ }
7781
+ }
7782
+
7783
+ // Task to track comment deletion
7784
+ class DeleteTask {
7785
+ constructor(postId, commentId) {
7786
+ this.postId = postId;
7787
+ this.commentId = commentId;
7788
+ }
7789
+ }
7790
+
7791
+ class CommentChange {
7792
+ constructor(latestCreatedAt, serverCommentCount) {
7793
+ this.latestCommentCreatedAt = latestCreatedAt;
7794
+ this.serverCommentCount = serverCommentCount;
7795
+ this.createdCommentIds = new Set();
7796
+ this.deletedCommentIds = new Set();
7797
+ }
7798
+ }
7799
+
7800
+ class PostCommentCountEngine {
7801
+ constructor() {
7802
+ this.isProcessing = false;
7803
+ this.tasks = [];
7804
+ this.commentChangeTracker = new Map();
7805
+ // Ids of the LOGGED-IN USER's own pending comments, per post. Survives ResetTask, so the
7806
+ // author's +1 does not vanish on the next post refresh; emptied only when the comment leaves
7807
+ // the pending state (approval hands it to createdCommentIds, decline/delete drops it).
7808
+ this.pendingAuthoredCommentIds = new Map();
7809
+ }
7810
+ queueCommentChangeTask(task) {
7811
+ this.tasks.push(task);
7812
+ if (!this.isProcessing) {
7813
+ this.processCommentChangeTask();
7814
+ }
7815
+ }
7816
+ addPendingAuthoredComment(postId, commentId, { publish = true } = {}) {
7817
+ var _a;
7818
+ const ids = (_a = this.pendingAuthoredCommentIds.get(postId)) !== null && _a !== void 0 ? _a : new Set();
7819
+ if (ids.has(commentId))
7820
+ return;
7821
+ ids.add(commentId);
7822
+ this.pendingAuthoredCommentIds.set(postId, ids);
7823
+ if (publish)
7824
+ this.publishIfTracked(postId);
7825
+ }
7826
+ removePendingAuthoredComment(postId, commentId, { publish = true } = {}) {
7827
+ const ids = this.pendingAuthoredCommentIds.get(postId);
7828
+ if (!(ids === null || ids === void 0 ? void 0 : ids.delete(commentId)))
7829
+ return false;
7830
+ if (ids.size === 0)
7831
+ this.pendingAuthoredCommentIds.delete(postId);
7832
+ if (publish)
7833
+ this.publishIfTracked(postId);
7834
+ return true;
7835
+ }
7836
+ /** Whether a post payload has seeded this post; without one every count is `0`. */
7837
+ hasTracker(postId) {
7838
+ return this.commentChangeTracker.has(postId);
7839
+ }
7840
+ isPendingAuthoredComment(postId, commentId) {
7841
+ var _a, _b;
7842
+ return (_b = (_a = this.pendingAuthoredCommentIds.get(postId)) === null || _a === void 0 ? void 0 : _a.has(commentId)) !== null && _b !== void 0 ? _b : false;
7843
+ }
7844
+ // Drops every per-post state. Called on logout / user switch.
7845
+ reset() {
7846
+ this.tasks = [];
7847
+ this.commentChangeTracker.clear();
7848
+ this.pendingAuthoredCommentIds.clear();
7849
+ }
7850
+ publishIfTracked(postId) {
7851
+ // Without a tracker there is no server figure to add to; the next ResetTask picks it up.
7852
+ if (!this.commentChangeTracker.has(postId))
7853
+ return;
7854
+ PostCommentCountEngine.publishUpdate(postId, this.getLocalCommentCount(postId, true));
7855
+ }
7856
+ processCommentChangeTask() {
7857
+ if (this.isProcessing) {
7858
+ return;
7859
+ }
7860
+ this.isProcessing = true;
7861
+ if (this.tasks.length === 0) {
7862
+ this.isProcessing = false;
7863
+ return;
7864
+ }
7865
+ // Process in capped batches, coalescing updates
7866
+ const batch = this.tasks.splice(0, PostCommentCountEngine.BATCH_SIZE);
7867
+ const modifiedPostIds = new Set();
7868
+ batch.forEach(task => {
7869
+ let modified = false;
7870
+ if (task instanceof ResetTask) {
7871
+ modified = this.processResetTaskInternal(task);
7872
+ }
7873
+ else if (task instanceof CreateTask) {
7874
+ modified = this.processCreateTaskInternal(task);
7875
+ }
7876
+ else if (task instanceof ApproveTask) {
7877
+ modified = this.processApproveTaskInternal(task);
7878
+ }
7879
+ else if (task instanceof DeleteTask) {
7880
+ modified = this.processDeleteTaskInternal(task);
7881
+ }
7882
+ if (modified) {
7883
+ modifiedPostIds.add(task.postId);
7884
+ }
7885
+ });
7886
+ // Publish one update per modified post
7887
+ modifiedPostIds.forEach(postId => {
7888
+ PostCommentCountEngine.publishUpdate(postId, this.getLocalCommentCount(postId, true));
7889
+ });
7890
+ this.isProcessing = false;
7891
+ // Recurse if more tasks remain
7892
+ if (this.tasks.length > 0) {
7893
+ this.processCommentChangeTask();
7894
+ }
7895
+ }
7896
+ processResetTaskInternal(task) {
7897
+ // Always creates/overwrites tracker
7898
+ this.commentChangeTracker.set(task.postId, new CommentChange(task.latestCreatedAt, task.serverCommentCount));
7899
+ return true;
7900
+ }
7901
+ processCreateTaskInternal(task) {
7902
+ // The comment is public now: the author-local +1 hands over to the normal path, so the
7903
+ // count stays put instead of moving twice.
7904
+ const wasPendingAuthored = this.removePendingAuthoredComment(task.postId, task.commentId, {
7905
+ publish: false,
7906
+ });
7907
+ const tracker = this.commentChangeTracker.get(task.postId);
7908
+ if (!tracker)
7909
+ return false; // No tracker, skip
7910
+ if (tracker.deletedCommentIds.delete(task.commentId))
7911
+ return true; // Re-approval cancels the earlier removal
7912
+ if (tracker.createdCommentIds.has(task.commentId))
7913
+ return wasPendingAuthored; // Deduplication
7914
+ if (task.createdAt <= tracker.latestCommentCreatedAt)
7915
+ return wasPendingAuthored; // Timestamp filtering
7916
+ tracker.createdCommentIds.add(task.commentId);
7917
+ return true;
7918
+ }
7919
+ processApproveTaskInternal(task) {
7920
+ // The comment is public now: the author-local +1 hands over to the normal path, so the
7921
+ // count stays put instead of moving twice.
7922
+ const wasPendingAuthored = this.removePendingAuthoredComment(task.postId, task.commentId, {
7923
+ publish: false,
7924
+ });
7925
+ const tracker = this.commentChangeTracker.get(task.postId);
7926
+ if (!tracker)
7927
+ return false; // No tracker, skip
7928
+ if (tracker.deletedCommentIds.delete(task.commentId))
7929
+ return true; // Re-approval cancels the earlier re-review removal
7930
+ if (tracker.createdCommentIds.has(task.commentId))
7931
+ return wasPendingAuthored; // Approve response and comment.approved event dedupe by id
7932
+ // No timestamp filtering: approval is the moment the comment enters the count, not createdAt
7933
+ tracker.createdCommentIds.add(task.commentId);
7934
+ return true;
7935
+ }
7936
+ processDeleteTaskInternal(task) {
7937
+ const tracker = this.commentChangeTracker.get(task.postId);
7938
+ if (!tracker)
7939
+ return false; // No tracker, skip
7940
+ if (tracker.deletedCommentIds.has(task.commentId))
7941
+ return false; // Deduplication
7942
+ tracker.deletedCommentIds.add(task.commentId);
7943
+ return true;
7944
+ }
7945
+ /**
7946
+ * The count as this session sees it: the last server figure plus the local delta.
7947
+ *
7948
+ * `includePending` adds the logged-in user's own pending comments — the author's view. A
7949
+ * pending id is added only while the public delta does not already count it, so a comment
7950
+ * present in both sets counts once: a `comment.created` that arrives pending after the
7951
+ * `comment.approved` hand-over adds nothing, while an approved comment sent back to review
7952
+ * (created, deleted and pending all hold its id) keeps the author's +1.
7953
+ *
7954
+ * `0` for a post no payload has seeded yet; callers fall back to the post's own figure.
7955
+ */
7956
+ getLocalCommentCount(postId, includePending = false) {
7957
+ var _a;
7958
+ const tracker = this.commentChangeTracker.get(postId);
7959
+ if (!tracker)
7960
+ return 0;
7961
+ const publicDelta = tracker.createdCommentIds.size - tracker.deletedCommentIds.size;
7962
+ if (!includePending)
7963
+ return Math.max(0, tracker.serverCommentCount + publicDelta);
7964
+ let pendingExtra = 0;
7965
+ (_a = this.pendingAuthoredCommentIds.get(postId)) === null || _a === void 0 ? void 0 : _a.forEach(commentId => {
7966
+ const countedPublicly = tracker.createdCommentIds.has(commentId) && !tracker.deletedCommentIds.has(commentId);
7967
+ if (!countedPublicly)
7968
+ pendingExtra += 1;
7969
+ });
7970
+ return Math.max(0, tracker.serverCommentCount + publicDelta + pendingExtra);
7971
+ }
7972
+ static publishUpdate(postId, newCount) {
7973
+ var _a;
7974
+ const queryKey = ['post', 'get', postId];
7975
+ mergeInCache(queryKey, {
7976
+ localCommentCount: newCount,
7977
+ });
7978
+ const postPayload = (_a = pullFromCache(queryKey)) === null || _a === void 0 ? void 0 : _a.data;
7979
+ if (!postPayload)
7980
+ return;
7981
+ fireEvent('local.post.updated', {
7982
+ posts: [postPayload],
7983
+ });
7984
+ }
7985
+ }
7986
+ PostCommentCountEngine.BATCH_SIZE = 50;
7987
+ let instance$1;
7988
+ var PostCommentCountEngine$1 = {
7989
+ getInstance: () => {
7990
+ if (!instance$1) {
7991
+ instance$1 = new PostCommentCountEngine();
7992
+ }
7993
+ return instance$1;
7994
+ },
7995
+ };
7996
+
7997
+ /**
7998
+ * Comment-count state is per user — in particular the ids of the logged-in user's own pending
7999
+ * comments — so it must not survive a logout or a user switch.
8000
+ *
8001
+ * @category private
8002
+ */
8003
+ const postCommentCountEngineOnLoginHandler = () => onSessionStateChange(state => {
8004
+ if (state === "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */ || state === "terminated" /* Amity.SessionStates.TERMINATED */) {
8005
+ PostCommentCountEngine$1.getInstance().reset();
8006
+ }
8007
+ });
8008
+
7371
8009
  const EVENTS = [
7372
8010
  'disconnected',
7373
8011
  'error',
@@ -7557,7 +8195,7 @@ const setupLoginSubscriptions = (unsubWatcher) => {
7557
8195
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
7558
8196
  // the channel because currently backend can't handle this, so every time a user is banned from
7559
8197
  // a channel or the channel is deleted the channel's unread count will not be reset to zero
7560
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler(), blockedUserSyncEngineOnLoginHandler(), blockingUserSyncEngineOnLoginHandler(), blockRealtimeOnLoginHandler(), resetAutoSubscriptionsOnLogout(), CursorController.clearOnLogout());
8198
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler(), reactionSyncEngineOnLoginHandler(), blockedUserSyncEngineOnLoginHandler(), blockingUserSyncEngineOnLoginHandler(), blockRealtimeOnLoginHandler(), resetAutoSubscriptionsOnLogout(), CursorController.clearOnLogout(), postCommentCountEngineOnLoginHandler());
7561
8199
  if (client.useLegacyUnreadCount) {
7562
8200
  subscriptions.push(readReceiptSyncEngineOnLoginHandler());
7563
8201
  }
@@ -8613,7 +9251,7 @@ const DEFAULT_DEBUG_SESSION = 'amity';
8613
9251
  *
8614
9252
  * @category Client API
8615
9253
  * */
8616
- const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, prefixDeviceIdKey, rteEnabled = true, } = {}) => {
9254
+ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, prefixDeviceIdKey, rteEnabled = true, product, uikitVersion, appId, appVersion, } = {}) => {
8617
9255
  var _a, _b, _c;
8618
9256
  const log = createLogger(debugSession);
8619
9257
  log('client/api/createClient', {
@@ -8642,6 +9280,10 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
8642
9280
  const useLegacyUnreadCount = true;
8643
9281
  const client = {
8644
9282
  version: `${VERSION}`,
9283
+ product,
9284
+ uikitVersion,
9285
+ appId,
9286
+ appVersion,
8645
9287
  apiKey,
8646
9288
  /*
8647
9289
  * SDK Components
@@ -8903,13 +9545,13 @@ class GlobalFileAccessType {
8903
9545
  }
8904
9546
  }
8905
9547
  _GlobalFileAccessType_fileAccessType = new WeakMap();
8906
- let instance$1;
9548
+ let instance;
8907
9549
  var GlobalFileAccessType$1 = {
8908
9550
  getInstance: () => {
8909
- if (!instance$1) {
8910
- instance$1 = new GlobalFileAccessType();
9551
+ if (!instance) {
9552
+ instance = new GlobalFileAccessType();
8911
9553
  }
8912
- return instance$1;
9554
+ return instance;
8913
9555
  },
8914
9556
  };
8915
9557
 
@@ -9768,7 +10410,7 @@ const getUserUnread = (callback) => {
9768
10410
  };
9769
10411
  };
9770
10412
 
9771
- var index$s = /*#__PURE__*/Object.freeze({
10413
+ var index$t = /*#__PURE__*/Object.freeze({
9772
10414
  __proto__: null,
9773
10415
  getActiveClient: getActiveClient,
9774
10416
  getActiveUser: getActiveUser,
@@ -10997,7 +11639,7 @@ const getMyFollowInfo = (callback) => {
10997
11639
  };
10998
11640
  /* end_public_function */
10999
11641
 
11000
- var index$r = /*#__PURE__*/Object.freeze({
11642
+ var index$s = /*#__PURE__*/Object.freeze({
11001
11643
  __proto__: null,
11002
11644
  blockUser: blockUser,
11003
11645
  unBlockUser: unBlockUser,
@@ -12338,6 +12980,16 @@ const createChannel = async (bundle) => {
12338
12980
  /* c8 ignore next */
12339
12981
  isPublic: (bundle === null || bundle === void 0 ? void 0 : bundle.type) === 'community' ? isPublic : undefined }));
12340
12982
  }
12983
+ // Fire the event locally, the same way createCommunity and createPost do.
12984
+ // Without it a running getChannels collection never inserts the new channel:
12985
+ // its query stream controller inserts an id only on OnCreate / OnJoin /
12986
+ // OnResolveChannel / OnUnarchived, and the first sent message arrives as an
12987
+ // OnUpdate, which only re-notifies. Reusing the MQTT event name means the
12988
+ // already-wired onChannelCreated -> OnCreate path does the insert, so the
12989
+ // list updates without a re-query. onChannelCreated re-runs
12990
+ // prepareChannelPayload + ingestInCache itself, so this is idempotent with
12991
+ // the ingest below.
12992
+ fireEvent('channel.created', payload.data);
12341
12993
  const data = await prepareChannelPayload(payload.data);
12342
12994
  const cachedAt = client.cache && Date.now();
12343
12995
  if (client.cache)
@@ -12509,8 +13161,32 @@ const streamLinkedObject = (stream) => {
12509
13161
  } });
12510
13162
  };
12511
13163
 
13164
+ const KNOWN_APPROVAL_STATUSES = [
13165
+ "pending" /* Amity.CommentApprovalStatusEnum.Pending */,
13166
+ "approved" /* Amity.CommentApprovalStatusEnum.Approved */,
13167
+ "rejected" /* Amity.CommentApprovalStatusEnum.Rejected */,
13168
+ ];
13169
+ /**
13170
+ * The server sends `approvalStatus` only while a comment is held for review or after it was
13171
+ * rejected. Absent, `null`, or an unrecognised value all resolve to `approved` — never to
13172
+ * `pending`, which would mark every comment written before the feature as unpublished.
13173
+ */
13174
+ const resolveCommentApprovalStatus = (approvalStatus) => {
13175
+ if (approvalStatus && KNOWN_APPROVAL_STATUSES.includes(approvalStatus)) {
13176
+ return approvalStatus;
13177
+ }
13178
+ return "approved" /* Amity.CommentApprovalStatusEnum.Approved */;
13179
+ };
13180
+ const prepareComment = (comment) => (Object.assign(Object.assign(Object.assign({}, (comment.hasOwnProperty('myReactions') ? {} : { myReactions: [] })), comment), { approvalStatus: resolveCommentApprovalStatus(comment.approvalStatus) }));
13181
+ function prepareCommentPayload(commentPayload) {
13182
+ const { comments, commentChildren } = commentPayload;
13183
+ return Object.assign(Object.assign(Object.assign({}, commentPayload), { comments: comments.map(prepareComment) }), (commentChildren ? { commentChildren: commentChildren.map(prepareComment) } : {}));
13184
+ }
13185
+
12512
13186
  const commentLinkedObject = (comment) => {
12513
- return Object.assign(Object.assign({}, comment), { get target() {
13187
+ return Object.assign(Object.assign({}, comment), {
13188
+ // Non-optional on the public model: absent on the wire means approved
13189
+ approvalStatus: resolveCommentApprovalStatus(comment.approvalStatus), get target() {
12514
13190
  const commentTypes = {
12515
13191
  type: comment.targetType,
12516
13192
  };
@@ -12718,7 +13394,7 @@ const getWatchSessionStorage = () => {
12718
13394
  return storageInstance;
12719
13395
  };
12720
13396
 
12721
- const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAARz+hmBgi8pJ\nQb8LeY41gtHhk+ACMwRfhsn7GqpqRQNG2qU0755mzZuVDUqjQMGSo8THJB7O+OJs\nflbZRkFXlFoFOVNw1UpNOgwEQZ6wB9oRwzepTJAfF1sVhm/o/ixvXh1zDFNDy6yZ\npXyiiJHUVxqyjllZhxnwdvjoVtDs6hW6awG09bB9nh/TTejlUKXoAgzqVwu/1QMu\nUVViET495elEe19aUarEy+oL2iKeXCEvqda/pWNBdbieFyJvvZ08HN8dPuT88wq2\njZLEAth1vrwQ2IAa4ktaLcBQdLJgIkrbDvAiVZ8lQAjS/bq5vXQikTGvoPlC5bbn\nvuOM/3eLAgMBAAECggEAVZ+peHAghq2QVj71nX5lxsNCKaCyYwixSJBpfouTt7Rz\nE6PpzMOXFi1W1o+I22jDakuSM2SOQKqI/u0QefB0r0O/KVk5NrZHXk0mkrdYtxOp\nUgaGyf8UvmjB+8VqHrNKyZdk9qtmbnNj01kTTcAtmE4H39zPR7eR/8Rul94vaZbs\nwCnKJS3mLT3JxyGug6lxanveKkjG+CKC1nJQYWaxCJxaFSzbwXQPvDhB+TvrIbee\npd5v4EAyEJohpr+T9oDGGJkb/KARBZCtwLyB976PKJwwBA8MRVL1i5QwawuMiMq5\nUtnOnbGKtCeFzaLbNU0Qi8bqyims84EQxC6DOu1fkQKBgQDdvsoBsEhsOXV7hlIJ\naEd0eSJZVkdqimxH8uGoMM2FeNaOrcB6yBXqTSP0R3OIyf8eaY6yjRvP30ZNXcll\n/gD3O1Mu6YmWQdt1W2WA6pKOsUuPXasf0pdOF7IiFZKlSabz5YHXFqwVuqm8loaj\nsXel3YWqPVdHiankE7tz+3ssnQKBgQDdqi4TNdD1MdEpihx19jr0QjUiXW3939FK\nqp30HESPEGDGQzXdmJgif9HhZb+cJSuWaHEbjgBrYahvgCF+y6LbEpOD+D/dmT+s\nDEAQaR84sah6dokwPjV8fjBSrcVFjCS+doxv0d3p/9OUEeyUhFrY03nxtIEYkLIE\n/Zvn37b4RwKBgQCLENVFe9XfsaVhQ5r9dV2iyTlmh7qgMZG5CbTFs12hQGhm8McO\n+Z7s41YSJCFr/yq1WwP4LJDtrBw99vyQr1zRsG35tNLp3gGRNzGQSQyC2uQFVHw2\np+7mNewsfhUK/gbrXNsyFnDz6635rPlhfbII3sWuP2wWXFqkxE9CbMwR7QKBgQC6\nawDMzxmo2/iYArrkyevSuEuPVxvFwpF1RgAI6C0QVCnPE38dmdN4UB7mfHekje4W\nVEercMURidPp0cxZolCYBQtilUjAyL0vqC3In1/Ogjq6oy3FEMxSop1pKxMY5j+Q\nnoqFD+6deLUrddeNH7J3X4LSr4dSbX4JjG+tlgt+yQKBgQCuwTL4hA6KqeInQ0Ta\n9VQX5Qr8hFlqJz1gpymi/k63tW/Ob8yedbg3WWNWyShwRMFYyY9S81ITFWM95uL6\nvF3x9rmRjwElJw9PMwVu6dmf/CO0Z1wzXSp2VVD12gbrUD/0/d7MUoJ9LgC8X8f/\nn0txLHYGHbx+nf95+JUg6lV3hg==\n-----END PRIVATE KEY-----";
13397
+ 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-----";
12722
13398
  /*
12723
13399
  * The crypto algorithm used for importing key and signing string
12724
13400
  */
@@ -13161,6 +13837,122 @@ const fileLinkedObject = (file) => {
13161
13837
  return file;
13162
13838
  };
13163
13839
 
13840
+ const isCommentPending = (comment) => resolveCommentApprovalStatus(comment.approvalStatus) === "pending" /* Amity.CommentApprovalStatusEnum.Pending */;
13841
+ const isCommentApproved = (comment) => resolveCommentApprovalStatus(comment.approvalStatus) === "approved" /* Amity.CommentApprovalStatusEnum.Approved */;
13842
+ // Only post and content references feed PostCommentCountEngine; story counts live on the story.
13843
+ const isCountedReference = (comment) => ['post', 'content'].includes(comment.referenceType);
13844
+ const isAuthoredByCurrentUser = (comment) => comment.userId === getActiveClient().userId;
13845
+ /**
13846
+ * Whether a comment on this reference would be held for review, read from the cached post's
13847
+ * community. `true` when that cannot be known — the post or its community is not cached yet.
13848
+ * A pending guess that turns out approved is corrected by the response and the comment then
13849
+ * enters the list; an approved guess that turns out pending has already been shown in a public
13850
+ * list with nothing to take it back out. Only shapes the optimistic object — the server
13851
+ * response is the authority on the actual status.
13852
+ */
13853
+ const isCommentApprovalRequired = (bundle) => {
13854
+ var _a, _b;
13855
+ // Only comments on community posts are gated; every other reference is known-off
13856
+ if (bundle.referenceType !== 'post')
13857
+ return false;
13858
+ const post = (_a = pullFromCache(['post', 'get', bundle.referenceId])) === null || _a === void 0 ? void 0 : _a.data;
13859
+ if (!post)
13860
+ return true;
13861
+ // A user-feed post is known-off
13862
+ if (post.targetType !== 'community')
13863
+ return false;
13864
+ const community = (_b = pullFromCache([
13865
+ 'community',
13866
+ 'get',
13867
+ post.targetId,
13868
+ ])) === null || _b === void 0 ? void 0 : _b.data;
13869
+ if (!community)
13870
+ return true;
13871
+ return community.needApprovalOnCommentCreation === true;
13872
+ };
13873
+ /**
13874
+ * An approved comment arrived over realtime: one `CreateTask` carrying its own `createdAt`, so
13875
+ * the timestamp filter skips anything the last post payload already counted. The author's own
13876
+ * comment reaches here as an echo too; the engine de-duplicates it by id against the task the
13877
+ * create response queued.
13878
+ */
13879
+ const applyCommentCreatedCount = (comment) => {
13880
+ if (!isCountedReference(comment))
13881
+ return;
13882
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new CreateTask(comment.referenceId, comment.commentId, comment.createdAt));
13883
+ };
13884
+ /**
13885
+ * The author's own pending comment counts in their view only. Recorded as separate engine state
13886
+ * so it survives a post refresh (`ResetTask`).
13887
+ */
13888
+ const recordPendingAuthoredComment = (comment, options) => {
13889
+ if (!isCountedReference(comment) || !isAuthoredByCurrentUser(comment))
13890
+ return;
13891
+ PostCommentCountEngine$1.getInstance().addPendingAuthoredComment(comment.referenceId, comment.commentId, options);
13892
+ };
13893
+ /**
13894
+ * A pending comment was declined or deleted: it was never in the server count, so no
13895
+ * `DeleteTask` — only the author-local +1 goes away.
13896
+ */
13897
+ const releasePendingAuthoredComment = (comment) => {
13898
+ if (!isCountedReference(comment))
13899
+ return;
13900
+ PostCommentCountEngine$1.getInstance().removePendingAuthoredComment(comment.referenceId, comment.commentId);
13901
+ };
13902
+ /**
13903
+ * Reveal: exactly one `ApproveTask`. The engine de-duplicates by comment id, so the approve
13904
+ * response and the `comment.approved` event may both call this. `ApproveTask` bypasses the age
13905
+ * guard on purpose — the comment was written before the last server sync but enters the public
13906
+ * count now — matching the iOS `ApproveTask` (plan 40 §9, guard off for approve).
13907
+ */
13908
+ const applyCommentApprovedCount = (comment) => {
13909
+ if (!isCountedReference(comment))
13910
+ return;
13911
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new ApproveTask(comment.referenceId, comment.commentId));
13912
+ };
13913
+ /**
13914
+ * Re-review: an approved comment edited back to pending leaves the public count once. The
13915
+ * author keeps their own +1 through the pending set, so their count does not move.
13916
+ */
13917
+ const applyCommentReReviewCount = (comment) => {
13918
+ if (!isCountedReference(comment))
13919
+ return;
13920
+ recordPendingAuthoredComment(comment, { publish: false });
13921
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new DeleteTask(comment.referenceId, comment.commentId));
13922
+ };
13923
+ /** Adds a reply to its cached parent's `children` (and count) once. */
13924
+ const linkCommentToParent = (comment) => {
13925
+ var _a;
13926
+ if (!comment.parentId)
13927
+ return;
13928
+ const parentKey = ['comment', 'get', comment.parentId];
13929
+ const parent = (_a = pullFromCache(parentKey)) === null || _a === void 0 ? void 0 : _a.data;
13930
+ if (!parent || parent.children.includes(comment.commentId))
13931
+ return;
13932
+ pushToCache(parentKey, Object.assign(Object.assign({}, parent), { childrenNumber: parent.childrenNumber + 1, children: [...new Set([...parent.children, comment.commentId])] }));
13933
+ };
13934
+ /** Removes a reply from its cached parent's `children` (and count) once. */
13935
+ const unlinkCommentFromParent = (comment) => {
13936
+ var _a;
13937
+ if (!comment.parentId)
13938
+ return;
13939
+ const parentKey = ['comment', 'get', comment.parentId];
13940
+ const parent = (_a = pullFromCache(parentKey)) === null || _a === void 0 ? void 0 : _a.data;
13941
+ if (!parent || !parent.children.includes(comment.commentId))
13942
+ return;
13943
+ pushToCache(parentKey, Object.assign(Object.assign({}, parent), { childrenNumber: parent.childrenNumber - 1, children: parent.children.filter(id => id !== comment.commentId) }));
13944
+ };
13945
+
13946
+ /**
13947
+ * The server's list is oldest → newest, so the newest ids are the last ones. Kept unique so the
13948
+ * create response, the local event and the realtime echo cannot each add the same comment.
13949
+ */
13950
+ const capLatestCommentIds = (commentIds) => [...new Set(commentIds)].slice(-LATEST_COMMENTS_LIMIT);
13951
+ /** A comment belongs in the post preview only while it is cached, not deleted and public. */
13952
+ const isPreviewableComment = (comment) => comment !== undefined && !comment.isDeleted && isCommentApproved(comment);
13953
+ /** The post's preview list after one of the user's own top-level comments is created. */
13954
+ const appendLatestCommentId = (post, commentId) => { var _a; return capLatestCommentIds([...((_a = post.comments) !== null && _a !== void 0 ? _a : []), commentId]); };
13955
+
13164
13956
  const postLinkedObject = (post) => {
13165
13957
  return shallowClone(post, {
13166
13958
  childrenPosts: post.children
@@ -13184,19 +13976,13 @@ const postLinkedObject = (post) => {
13184
13976
  get latestComments() {
13185
13977
  if (!post.comments)
13186
13978
  return [];
13187
- return (post.comments
13188
- .map(commentId => {
13189
- var _a;
13190
- const commentCached = (_a = pullFromCache([
13191
- 'comment',
13192
- 'get',
13193
- commentId,
13194
- ])) === null || _a === void 0 ? void 0 : _a.data;
13195
- if (!commentCached)
13196
- return null;
13197
- return commentLinkedObject(commentCached);
13198
- })
13199
- .filter(Boolean) || []);
13979
+ // Same rule as the server's own list and as iOS: deleted and non-public comments are
13980
+ // dropped first, then the newest LATEST_COMMENTS_LIMIT remain
13981
+ return post.comments
13982
+ .map(commentId => { var _a; return (_a = pullFromCache(['comment', 'get', commentId])) === null || _a === void 0 ? void 0 : _a.data; })
13983
+ .filter(isPreviewableComment)
13984
+ .slice(-LATEST_COMMENTS_LIMIT)
13985
+ .map(commentLinkedObject);
13200
13986
  },
13201
13987
  get creator() {
13202
13988
  // The id is checked for a value, not just for presence: a payload can
@@ -13209,6 +13995,15 @@ const postLinkedObject = (post) => {
13209
13995
  return undefined;
13210
13996
  return userLinkedObject(cacheData.data);
13211
13997
  },
13998
+ getLocalCommentCount(includePending = false) {
13999
+ var _a;
14000
+ const engine = PostCommentCountEngine$1.getInstance();
14001
+ // Before any payload has seeded the engine for this post there is no tracker; the
14002
+ // post's own figure is the best answer then.
14003
+ return engine.hasTracker(post.postId)
14004
+ ? engine.getLocalCommentCount(post.postId, includePending)
14005
+ : (_a = post.localCommentCount) !== null && _a !== void 0 ? _a : post.commentsCount;
14006
+ },
13212
14007
  get targetCommunity() {
13213
14008
  var _a;
13214
14009
  if (!post.targetId)
@@ -13573,7 +14368,8 @@ const messageLinkedObject = (message) => {
13573
14368
  },
13574
14369
  get creator() {
13575
14370
  var _a;
13576
- return (_a = pullFromCache(['user', 'get', message.creatorId])) === null || _a === void 0 ? void 0 : _a.data;
14371
+ const creator = (_a = pullFromCache(['user', 'get', message.creatorId])) === null || _a === void 0 ? void 0 : _a.data;
14372
+ return creator ? userLinkedObject(creator) : undefined;
13577
14373
  }, markRead: () => markReadMessage(message), addReaction: (reactionName) => addReactionToMessage(reactionName, message), removeReaction: (reactionName) => removeReactionToMessage(reactionName, message) });
13578
14374
  };
13579
14375
 
@@ -14234,6 +15030,22 @@ const eventLinkedObject = (event) => {
14234
15030
  } });
14235
15031
  };
14236
15032
 
15033
+ const curatedContentTopicLinkedObject = (topic) => {
15034
+ return shallowClone(topic, {
15035
+ analytics: {
15036
+ markAsViewed: () => {
15037
+ AnalyticsEngine$1.getInstance().markCuratedContentWidgetAsViewed(topic.topicId);
15038
+ },
15039
+ markPostAsViewed: (postId) => {
15040
+ AnalyticsEngine$1.getInstance().markCuratedContentPostAsViewed(postId, topic.topicId);
15041
+ },
15042
+ markPostClick: (postId) => {
15043
+ AnalyticsEngine$1.getInstance().markCuratedContentPostAsClicked(postId, topic.topicId);
15044
+ },
15045
+ },
15046
+ });
15047
+ };
15048
+
14237
15049
  const LinkedObject = {
14238
15050
  file: fileLinkedObject,
14239
15051
  ad: adLinkedObject,
@@ -14258,6 +15070,7 @@ const LinkedObject = {
14258
15070
  eventResponse: eventResponseLinkedObject,
14259
15071
  product: productLinkedObject,
14260
15072
  poll: pollLinkedObject,
15073
+ curatedContentTopic: curatedContentTopicLinkedObject,
14261
15074
  };
14262
15075
 
14263
15076
  /* begin_public_function
@@ -15580,9 +16393,9 @@ var AmityUserSearchMatchType;
15580
16393
  AmityUserSearchMatchType["PARTIAL"] = "partial";
15581
16394
  })(AmityUserSearchMatchType || (AmityUserSearchMatchType = {}));
15582
16395
 
15583
- var index$q = /*#__PURE__*/Object.freeze({
16396
+ var index$r = /*#__PURE__*/Object.freeze({
15584
16397
  __proto__: null,
15585
- Relationship: index$r,
16398
+ Relationship: index$s,
15586
16399
  getUserByIds: getUserByIds,
15587
16400
  updateUser: updateUser,
15588
16401
  flagUser: flagUser,
@@ -15990,7 +16803,7 @@ const uploadAudio = async (formData, onProgress) => {
15990
16803
  };
15991
16804
  /* end_public_function */
15992
16805
 
15993
- var index$p = /*#__PURE__*/Object.freeze({
16806
+ var index$q = /*#__PURE__*/Object.freeze({
15994
16807
  __proto__: null,
15995
16808
  getFile: getFile,
15996
16809
  uploadFile: uploadFile,
@@ -16183,147 +16996,6 @@ getMessage$1.locally = (messageId) => {
16183
16996
  };
16184
16997
  };
16185
16998
 
16186
- class ResetTask {
16187
- constructor(postId, latestCreatedAt, serverCommentCount) {
16188
- this.postId = postId;
16189
- this.latestCreatedAt = latestCreatedAt;
16190
- this.serverCommentCount = serverCommentCount;
16191
- }
16192
- }
16193
-
16194
- // Task to track comment creation
16195
- class CreateTask {
16196
- constructor(postId, commentId, createdAt) {
16197
- this.postId = postId;
16198
- this.commentId = commentId;
16199
- this.createdAt = createdAt;
16200
- }
16201
- }
16202
-
16203
- // Task to track comment deletion
16204
- class DeleteTask {
16205
- constructor(postId, commentId) {
16206
- this.postId = postId;
16207
- this.commentId = commentId;
16208
- }
16209
- }
16210
-
16211
- class CommentChange {
16212
- constructor(latestCreatedAt, serverCommentCount) {
16213
- this.latestCommentCreatedAt = latestCreatedAt;
16214
- this.serverCommentCount = serverCommentCount;
16215
- this.createdCommentIds = new Set();
16216
- this.deletedCommentIds = new Set();
16217
- }
16218
- }
16219
-
16220
- class PostCommentCountEngine {
16221
- constructor() {
16222
- this.isProcessing = false;
16223
- this.tasks = [];
16224
- this.commentChangeTracker = new Map();
16225
- }
16226
- queueCommentChangeTask(task) {
16227
- this.tasks.push(task);
16228
- if (!this.isProcessing) {
16229
- this.processCommentChangeTask();
16230
- }
16231
- }
16232
- processCommentChangeTask() {
16233
- if (this.isProcessing) {
16234
- return;
16235
- }
16236
- this.isProcessing = true;
16237
- if (this.tasks.length === 0) {
16238
- this.isProcessing = false;
16239
- return;
16240
- }
16241
- // Process in capped batches, coalescing updates
16242
- const batch = this.tasks.splice(0, PostCommentCountEngine.BATCH_SIZE);
16243
- const modifiedPostIds = new Set();
16244
- batch.forEach(task => {
16245
- let modified = false;
16246
- if (task instanceof ResetTask) {
16247
- modified = this.processResetTaskInternal(task);
16248
- }
16249
- else if (task instanceof CreateTask) {
16250
- modified = this.processCreateTaskInternal(task);
16251
- }
16252
- else if (task instanceof DeleteTask) {
16253
- modified = this.processDeleteTaskInternal(task);
16254
- }
16255
- if (modified) {
16256
- modifiedPostIds.add(task.postId);
16257
- }
16258
- });
16259
- // Publish one update per modified post
16260
- modifiedPostIds.forEach(postId => {
16261
- const count = this.computeCommentCount(postId);
16262
- PostCommentCountEngine.publishUpdate(postId, count);
16263
- });
16264
- this.isProcessing = false;
16265
- // Recurse if more tasks remain
16266
- if (this.tasks.length > 0) {
16267
- this.processCommentChangeTask();
16268
- }
16269
- }
16270
- processResetTaskInternal(task) {
16271
- // Always creates/overwrites tracker
16272
- this.commentChangeTracker.set(task.postId, new CommentChange(task.latestCreatedAt, task.serverCommentCount));
16273
- return true;
16274
- }
16275
- processCreateTaskInternal(task) {
16276
- const tracker = this.commentChangeTracker.get(task.postId);
16277
- if (!tracker)
16278
- return false; // No tracker, skip
16279
- if (tracker.createdCommentIds.has(task.commentId))
16280
- return false; // Deduplication
16281
- if (task.createdAt <= tracker.latestCommentCreatedAt)
16282
- return false; // Timestamp filtering
16283
- tracker.createdCommentIds.add(task.commentId);
16284
- return true;
16285
- }
16286
- processDeleteTaskInternal(task) {
16287
- const tracker = this.commentChangeTracker.get(task.postId);
16288
- if (!tracker)
16289
- return false; // No tracker, skip
16290
- if (tracker.deletedCommentIds.has(task.commentId))
16291
- return false; // Deduplication
16292
- tracker.deletedCommentIds.add(task.commentId);
16293
- return true;
16294
- }
16295
- computeCommentCount(postId) {
16296
- const tracker = this.commentChangeTracker.get(postId);
16297
- if (!tracker)
16298
- return 0;
16299
- const count = tracker.serverCommentCount + tracker.createdCommentIds.size - tracker.deletedCommentIds.size;
16300
- return Math.max(0, count);
16301
- }
16302
- static publishUpdate(postId, newCount) {
16303
- var _a;
16304
- const queryKey = ['post', 'get', postId];
16305
- mergeInCache(queryKey, {
16306
- localCommentCount: newCount,
16307
- });
16308
- const postPayload = (_a = pullFromCache(queryKey)) === null || _a === void 0 ? void 0 : _a.data;
16309
- if (!postPayload)
16310
- return;
16311
- fireEvent('local.post.updated', {
16312
- posts: [postPayload],
16313
- });
16314
- }
16315
- }
16316
- PostCommentCountEngine.BATCH_SIZE = 50;
16317
- let instance;
16318
- var PostCommentCountEngine$1 = {
16319
- getInstance: () => {
16320
- if (!instance) {
16321
- instance = new PostCommentCountEngine();
16322
- }
16323
- return instance;
16324
- },
16325
- };
16326
-
16327
16999
  const updateStreamReferences = (streams, streamId, postId) => {
16328
17000
  if (!streamId)
16329
17001
  return streams;
@@ -16343,7 +17015,7 @@ const preparePostPayload = (payload) => {
16343
17015
  let mappedNewStream = [];
16344
17016
  // feed type
16345
17017
  const posts = postsData.map(post => {
16346
- var _a, _b, _c, _d;
17018
+ var _a, _b, _c;
16347
17019
  const feedType = (_a = postPayload.feeds.find(feed => feed.feedId === post.feedId)) === null || _a === void 0 ? void 0 : _a.feedType;
16348
17020
  const childPosts = payload.postChildren.filter(children => children.parentPostId === post.postId);
16349
17021
  if (childPosts.length > 0 && isAmityLivestreamPost(childPosts[0])) {
@@ -16362,7 +17034,11 @@ const preparePostPayload = (payload) => {
16362
17034
  // Queue ResetTask for this post
16363
17035
  PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new ResetTask(post.postId, latestCreatedAt, (_c = post.commentsCount) !== null && _c !== void 0 ? _c : 0));
16364
17036
  return Object.assign(Object.assign({}, post), { childPosts,
16365
- feedType, localCommentCount: (_d = post.localCommentCount) !== null && _d !== void 0 ? _d : post.commentsCount, pinnedProductId: post === null || post === void 0 ? void 0 : post.pinnedProductId });
17037
+ feedType,
17038
+ // The ResetTask above has just seeded the engine, so this is the server figure plus the
17039
+ // author's own pending comments. Reading `post.commentsCount` here instead would overwrite
17040
+ // that +1 in the cache on every refresh, since the ingest that follows merges this object.
17041
+ localCommentCount: PostCommentCountEngine$1.getInstance().getLocalCommentCount(post.postId, true), pinnedProductId: post === null || post === void 0 ? void 0 : post.pinnedProductId });
16366
17042
  });
16367
17043
  return Object.assign(Object.assign({}, postPayload), { postChildren, videoStreamings: mappedNewStream, posts, communities: communityWithMembershipStatus, communityUsers: mappedCommunityUsers });
16368
17044
  };
@@ -17115,62 +17791,67 @@ const onPostReactionRemoved = (callback) => {
17115
17791
  return createEventSubscriber(client, 'post.removeReaction', 'post.removeReaction', filter);
17116
17792
  };
17117
17793
 
17794
+ /**
17795
+ * `comment.created` fires while a comment is still pending, so delivery is not visibility. The
17796
+ * two side effects that make a comment public — the parent link that feeds the reply list and
17797
+ * the comment-count task — are gated here; `comment.approved` is the only reveal signal, and a
17798
+ * decline arrives as `comment.deleted`.
17799
+ */
17800
+ const applyApprovalSideEffects = (event, comment, previous) => {
17801
+ switch (event) {
17802
+ case 'comment.created':
17803
+ if (isCommentPending(comment)) {
17804
+ recordPendingAuthoredComment(comment);
17805
+ }
17806
+ else {
17807
+ linkCommentToParent(comment);
17808
+ applyCommentCreatedCount(comment);
17809
+ }
17810
+ break;
17811
+ case 'comment.approved':
17812
+ linkCommentToParent(comment);
17813
+ applyCommentApprovedCount(comment);
17814
+ break;
17815
+ case 'comment.updated':
17816
+ // An effective edit in a gated community sends an approved comment back for review
17817
+ if (isCommentPending(comment) && previous && isCommentApproved(previous)) {
17818
+ unlinkCommentFromParent(comment);
17819
+ applyCommentReReviewCount(comment);
17820
+ }
17821
+ break;
17822
+ case 'comment.deleted':
17823
+ unlinkCommentFromParent(comment);
17824
+ // A pending comment was never counted, so its deletion (or decline) moves no count
17825
+ if (previous && isCommentPending(previous))
17826
+ releasePendingAuthoredComment(comment);
17827
+ break;
17828
+ }
17829
+ };
17118
17830
  const createCommentEventSubscriber = (event, callback) => {
17119
17831
  const client = getActiveClient();
17120
17832
  const filter = (payload) => {
17121
- var _a;
17833
+ var _a, _b;
17122
17834
  if (!client.cache) {
17123
17835
  // TODO: here we are missing specific properties here!
17124
17836
  callback(LinkedObject.comment(payload.comments[0]));
17125
17837
  }
17126
17838
  else {
17127
- const processed = ['comment.flagged', 'comment.unflagged'].includes(event)
17839
+ const flagged = ['comment.flagged', 'comment.unflagged'].includes(event)
17128
17840
  ? prepareCommentFromFlaggedEvent(payload)
17129
17841
  : payload;
17130
- // NOTE: The event data should be merge with existing cache rather than replace it
17131
- ingestInCache(processed, undefined, false);
17842
+ // Resolve `approvalStatus` before the merge: an absent value means approved and has to
17843
+ // overwrite a cached `pending`, which a plain merge would leave in place.
17844
+ const processed = prepareCommentPayload(flagged);
17132
17845
  const { comments } = processed;
17133
17846
  if (comments.length > 0) {
17134
- const comment = pullFromCache([
17135
- 'comment',
17136
- 'get',
17137
- comments[0].commentId,
17138
- ]);
17139
- if (['comment.created'].includes(event)) {
17140
- if (comments[0].parentId) {
17141
- const parentComment = pullFromCache([
17142
- 'comment',
17143
- 'get',
17144
- comments[0].parentId,
17145
- ]);
17146
- if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
17147
- // Skip to update parent childComment if current comment already exists
17148
- if (!parentComment.data.children.includes(comments[0].commentId)) {
17149
- pushToCache(['comment', 'get', comments[0].parentId], Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber + 1, children: [...new Set([...parentComment.data.children, comments[0].commentId])] }));
17150
- }
17151
- }
17152
- }
17153
- }
17847
+ const commentKey = ['comment', 'get', comments[0].commentId];
17848
+ const previous = (_a = pullFromCache(commentKey)) === null || _a === void 0 ? void 0 : _a.data;
17849
+ // NOTE: The event data should be merge with existing cache rather than replace it
17850
+ ingestInCache(processed, undefined, false);
17851
+ const comment = pullFromCache(commentKey);
17852
+ applyApprovalSideEffects(event, comment.data, previous);
17154
17853
  if (['comment.deleted'].includes(event)) {
17155
- if (comments[0].parentId) {
17156
- const parentComment = pullFromCache([
17157
- 'comment',
17158
- 'get',
17159
- comments[0].parentId,
17160
- ]);
17161
- if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
17162
- // Remove deleted comment in parent childComment if still exists
17163
- if (parentComment.data.children.includes(comments[0].commentId)) {
17164
- const newParentComment = Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber - 1, children: [
17165
- ...new Set([
17166
- ...parentComment.data.children.filter(id => id !== comments[0].commentId),
17167
- ]),
17168
- ] });
17169
- pushToCache(['comment', 'get', comments[0].parentId], newParentComment);
17170
- }
17171
- }
17172
- }
17173
- 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; });
17854
+ 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; });
17174
17855
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
17175
17856
  }
17176
17857
  callback(LinkedObject.comment(comment.data));
@@ -17182,13 +17863,13 @@ const createCommentEventSubscriber = (event, callback) => {
17182
17863
  const createLocalCommentEventSubscriber = (event, callback) => {
17183
17864
  const client = getActiveClient();
17184
17865
  const filter = (payload) => {
17185
- var _a, _b, _c, _d, _e;
17866
+ var _a, _b, _c, _d;
17186
17867
  if (!client.cache) {
17187
17868
  // TODO: here we are missing specific properties here!
17188
17869
  callback(LinkedObject.comment(payload.comments[0]));
17189
17870
  }
17190
17871
  else {
17191
- const processed = payload;
17872
+ const processed = prepareCommentPayload(payload);
17192
17873
  ingestInCache(processed);
17193
17874
  const { comments } = processed;
17194
17875
  if (comments.length > 0) {
@@ -17197,7 +17878,9 @@ const createLocalCommentEventSubscriber = (event, callback) => {
17197
17878
  'get',
17198
17879
  comments[0].commentId,
17199
17880
  ]);
17200
- if (['local.comment.created'].includes(event)) {
17881
+ // A pending comment is persisted for its author but never linked into the public
17882
+ // surfaces (parent reply list, post comment list)
17883
+ if (['local.comment.created'].includes(event) && isCommentApproved(comments[0])) {
17201
17884
  if (comments[0].parentId) {
17202
17885
  const parentComment = pullFromCache([
17203
17886
  'comment',
@@ -17226,11 +17909,11 @@ const createLocalCommentEventSubscriber = (event, callback) => {
17226
17909
  const postCacheKey = ['post', 'get', comments[0].referenceId];
17227
17910
  const postCache = (_a = pullFromCache(postCacheKey)) === null || _a === void 0 ? void 0 : _a.data;
17228
17911
  if (postCache) {
17229
- const updatedPostCache = Object.assign(Object.assign({}, postCache), { comments: [...postCache.comments, (_b = comments[0]) === null || _b === void 0 ? void 0 : _b.commentId] });
17912
+ const updatedPostCache = Object.assign(Object.assign({}, postCache), { comments: appendLatestCommentId(postCache, comments[0].commentId) });
17230
17913
  pushToCache(postCacheKey, updatedPostCache);
17231
17914
  }
17232
17915
  }
17233
- 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; });
17916
+ 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; });
17234
17917
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
17235
17918
  }
17236
17919
  if (['local.comment.deleted'].includes(event)) {
@@ -17264,13 +17947,13 @@ const createLocalCommentEventSubscriber = (event, callback) => {
17264
17947
  }
17265
17948
  else {
17266
17949
  const postCacheKey = ['post', 'get', comments[0].referenceId];
17267
- const postCache = (_d = pullFromCache(postCacheKey)) === null || _d === void 0 ? void 0 : _d.data;
17950
+ const postCache = (_c = pullFromCache(postCacheKey)) === null || _c === void 0 ? void 0 : _c.data;
17268
17951
  if (postCache) {
17269
17952
  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); }) });
17270
17953
  pushToCache(postCacheKey, updatedPost);
17271
17954
  }
17272
17955
  }
17273
- 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; });
17956
+ const queries = (_d = queryCache(['comment', 'query'])) === null || _d === void 0 ? void 0 : _d.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
17274
17957
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
17275
17958
  }
17276
17959
  callback(LinkedObject.comment(comment.data));
@@ -17331,6 +18014,23 @@ const onCommentUpdated = (callback) => createCommentEventSubscriber('comment.upd
17331
18014
  */
17332
18015
  const onCommentDeleted = (callback) => createCommentEventSubscriber('comment.deleted', callback);
17333
18016
 
18017
+ /**
18018
+ * ```js
18019
+ * import { onCommentApproved } from '@amityco/ts-sdk'
18020
+ * const dispose = onCommentApproved(comment => {
18021
+ * // ...
18022
+ * })
18023
+ * ```
18024
+ *
18025
+ * Fired when a {@link Amity.InternalComment} held for review has been approved
18026
+ *
18027
+ * @param callback The function to call when the event was fired
18028
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
18029
+ *
18030
+ * @category Comment Events
18031
+ */
18032
+ const onCommentApproved = (callback) => createCommentEventSubscriber('comment.approved', callback);
18033
+
17334
18034
  /**
17335
18035
  * ```js
17336
18036
  * import { onCommentFlagged } from '@amityco/ts-sdk-react-native'
@@ -17963,7 +18663,7 @@ const getReactions$1 = (params, callback, config) => {
17963
18663
  };
17964
18664
  /* end_public_function */
17965
18665
 
17966
- var index$o = /*#__PURE__*/Object.freeze({
18666
+ var index$p = /*#__PURE__*/Object.freeze({
17967
18667
  __proto__: null,
17968
18668
  addReaction: addReaction,
17969
18669
  removeReaction: removeReaction,
@@ -17974,17 +18674,6 @@ var index$o = /*#__PURE__*/Object.freeze({
17974
18674
  getReactions: getReactions$1
17975
18675
  });
17976
18676
 
17977
- function prepareCommentPayload(commentPayload) {
17978
- const { comments } = commentPayload;
17979
- return Object.assign(Object.assign({}, commentPayload), { comments: comments.map(comment => {
17980
- if (comment.hasOwnProperty('myReactions'))
17981
- return comment;
17982
- // Sometimes `myReactions` field will not come with BE response because that field is empty
17983
- // We need to put it with an empty array manually to make it show up in client side
17984
- return Object.assign({ myReactions: [] }, comment);
17985
- }) });
17986
- }
17987
-
17988
18677
  const createMessageReport = async ({ client, referenceId, }) => {
17989
18678
  const { data: payload } = await client.http.post(`/api/v5/messages/${encodeURIComponent(referenceId)}/flags`);
17990
18679
  if (client.cache) {
@@ -18448,20 +19137,20 @@ const getArchivedChannelIds = async () => {
18448
19137
 
18449
19138
  /**
18450
19139
  * ```js
18451
- * import { onMessageUpdated } from '@amityco/ts-sdk-react-native'
18452
- * const dispose = onMessageUpdated(message => {
19140
+ * import { onMessageDeleted } from '@amityco/ts-sdk-react-native'
19141
+ * const dispose = onMessageDeleted(message => {
18453
19142
  * // ...
18454
19143
  * })
18455
19144
  * ```
18456
19145
  *
18457
- * Fired when an {@link Amity.Message} has been updated
19146
+ * Fired when an {@link Amity.Message} was deleted
18458
19147
  *
18459
19148
  * @param callback The function to call when the event was fired
18460
19149
  * @returns an {@link Amity.Unsubscriber} function to stop listening
18461
19150
  *
18462
19151
  * @category Message Events
18463
19152
  */
18464
- const onMessageUpdated = (callback) => {
19153
+ const onMessageDeleted = (callback) => {
18465
19154
  const client = getActiveClient();
18466
19155
  const filter = async (rawPayload) => {
18467
19156
  const payload = await prepareMessagePayload(rawPayload);
@@ -18469,30 +19158,48 @@ const onMessageUpdated = (callback) => {
18469
19158
  callback(payload.messages[0]);
18470
19159
  };
18471
19160
  const disposers = [
18472
- createEventSubscriber(client, 'onMessageUpdated', 'message.updated', filter),
18473
- createEventSubscriber(client, 'onMessageUpdated', 'local.message.updated', payload => callback(payload.messages[0])),
19161
+ createEventSubscriber(client, 'message/onMessageDeleted', 'message.deleted', filter),
19162
+ createEventSubscriber(client, 'message/onMessageDeleted', 'local.message.deleted', payload => callback(payload.messages[0])),
18474
19163
  ];
18475
19164
  return () => {
18476
19165
  disposers.forEach(fn => fn());
18477
19166
  };
18478
19167
  };
18479
19168
 
19169
+ /**
19170
+ * Defensive clear of `channel.pinnedMessage` when the pinned message itself is deleted.
19171
+ *
19172
+ * The server also emits `channel.messageUnpinned` in this case, but realtime events are
19173
+ * fire-and-forget and their order is not guaranteed. Clearing on `message.deleted`
19174
+ * (MQTT or local) makes the banner disappear even if the unpin event is lost; the
19175
+ * server's own `messageUnpinned` then becomes a no-op.
19176
+ *
19177
+ * Internal — wired into the `getChannel` live object; not exported publicly.
19178
+ */
19179
+ const onChannelPinnedMessageDeleted = (callback) => onMessageDeleted(message => {
19180
+ var _a;
19181
+ const channel = findCachedChannelByAnyId(message.channelId);
19182
+ if (!channel || ((_a = channel.pinnedMessage) === null || _a === void 0 ? void 0 : _a.messageId) !== message.messageId)
19183
+ return;
19184
+ callback(updatePinnedMessageCache(channel, null));
19185
+ });
19186
+
18480
19187
  /**
18481
19188
  * ```js
18482
- * import { onMessageDeleted } from '@amityco/ts-sdk-react-native'
18483
- * const dispose = onMessageDeleted(message => {
19189
+ * import { onMessageUpdated } from '@amityco/ts-sdk-react-native'
19190
+ * const dispose = onMessageUpdated(message => {
18484
19191
  * // ...
18485
19192
  * })
18486
19193
  * ```
18487
19194
  *
18488
- * Fired when an {@link Amity.Message} was deleted
19195
+ * Fired when an {@link Amity.Message} has been updated
18489
19196
  *
18490
19197
  * @param callback The function to call when the event was fired
18491
19198
  * @returns an {@link Amity.Unsubscriber} function to stop listening
18492
19199
  *
18493
19200
  * @category Message Events
18494
19201
  */
18495
- const onMessageDeleted = (callback) => {
19202
+ const onMessageUpdated = (callback) => {
18496
19203
  const client = getActiveClient();
18497
19204
  const filter = async (rawPayload) => {
18498
19205
  const payload = await prepareMessagePayload(rawPayload);
@@ -18500,8 +19207,8 @@ const onMessageDeleted = (callback) => {
18500
19207
  callback(payload.messages[0]);
18501
19208
  };
18502
19209
  const disposers = [
18503
- createEventSubscriber(client, 'message/onMessageDeleted', 'message.deleted', filter),
18504
- createEventSubscriber(client, 'message/onMessageDeleted', 'local.message.deleted', payload => callback(payload.messages[0])),
19210
+ createEventSubscriber(client, 'onMessageUpdated', 'message.updated', filter),
19211
+ createEventSubscriber(client, 'onMessageUpdated', 'local.message.updated', payload => callback(payload.messages[0])),
18505
19212
  ];
18506
19213
  return () => {
18507
19214
  disposers.forEach(fn => fn());
@@ -19082,6 +19789,132 @@ softDeleteMessage.optimistically = (messageId) => {
19082
19789
  };
19083
19790
  /* end_public_function */
19084
19791
 
19792
+ /**
19793
+ * Fire-and-forget refresh of `channelUsers[...].permissions` for the channel a
19794
+ * message belongs to. Used by `pinMessage` / `unpinMessage` on `403` so the next
19795
+ * `hasPermission(PIN_MESSAGE).channel(channelId)` reflects a revoked role
19796
+ * ([`pinMessage` REQ-010](../../@types/../..) / [`unpinMessage` REQ-008](../../@types/../..)).
19797
+ *
19798
+ * The API only receives a `messageId`, so the channel is resolved through the
19799
+ * local cache: first the message row, then any cached channel whose current pin
19800
+ * is that message. When nothing matches the refresh is skipped — the next
19801
+ * channel read picks up the fresh permissions anyway.
19802
+ */
19803
+ const refreshChannelPermissionsForMessage = (messageId) => {
19804
+ var _a, _b, _c;
19805
+ const cachedMessage = (_a = getMessage$1.locally(messageId)) === null || _a === void 0 ? void 0 : _a.data;
19806
+ let channelId = cachedMessage === null || cachedMessage === void 0 ? void 0 : cachedMessage.channelId;
19807
+ if (!channelId) {
19808
+ channelId = (_c = (_b = queryCache(['channel', 'get'])) === null || _b === void 0 ? void 0 : _b.find(({ data }) => { var _a; return ((_a = data.pinnedMessage) === null || _a === void 0 ? void 0 : _a.messageId) === messageId; })) === null || _c === void 0 ? void 0 : _c.data.channelId;
19809
+ }
19810
+ if (!channelId)
19811
+ return;
19812
+ getChannel$1(channelId).catch(() => {
19813
+ /* silent per spec; UIKit renders no error toast */
19814
+ });
19815
+ };
19816
+
19817
+ /* begin_public_function
19818
+ id: message.pin
19819
+ */
19820
+ /**
19821
+ * ```js
19822
+ * import { MessageRepository } from '@amityco/ts-sdk'
19823
+ * const channel = await MessageRepository.pinMessage(messageId)
19824
+ * console.log(channel.pinnedMessage)
19825
+ * ```
19826
+ *
19827
+ * Pins a {@link Amity.Message} in its livestream (`live`) channel. A channel holds at
19828
+ * most one pinned message: pinning a different message replaces the current pin in a
19829
+ * single step — no unpin is needed first. Pinning the message that is already pinned is
19830
+ * rejected by the server (400).
19831
+ *
19832
+ * The caller must hold the `PIN_MESSAGE` permission in the channel (or be an admin with
19833
+ * `ModerateChannel`). The server also rejects pinning a deleted message, a message whose
19834
+ * author is banned from the channel or globally banned, and pinning in any channel type
19835
+ * other than `live`. On any error the pin state is left unchanged.
19836
+ *
19837
+ * The response is the affected channel; it is ingested into cache and fires
19838
+ * `local.channel.updated`, so `ChannelRepository.getChannel` observers update without
19839
+ * waiting for the `channel.messagePinned` realtime event.
19840
+ *
19841
+ * @param messageId the **internal** ID of the {@link Amity.Message} to pin
19842
+ * @returns the updated {@link Amity.Channel}, with `pinnedMessage` set
19843
+ *
19844
+ * @category Message API
19845
+ * @async
19846
+ */
19847
+ const pinMessage = async (messageId) => {
19848
+ const client = getActiveClient();
19849
+ client.log('message/pinMessage', messageId);
19850
+ let payload;
19851
+ try {
19852
+ ({ data: payload } = await client.http.post(`/api/v5/messages/${encodeURIComponent(messageId)}/pin`));
19853
+ }
19854
+ catch (error) {
19855
+ if ((error === null || error === void 0 ? void 0 : error.code) === 400301 /* Amity.ServerError.PERMISSION_DENIED */) {
19856
+ refreshChannelPermissionsForMessage(messageId);
19857
+ }
19858
+ throw error;
19859
+ }
19860
+ const data = await prepareChannelPayload(payload);
19861
+ if (client.cache)
19862
+ ingestInCache(data);
19863
+ fireEvent('local.channel.updated', data);
19864
+ return constructChannelObject(data.channels[0]);
19865
+ };
19866
+ /* end_public_function */
19867
+
19868
+ /* begin_public_function
19869
+ id: message.unpin
19870
+ */
19871
+ /**
19872
+ * ```js
19873
+ * import { MessageRepository } from '@amityco/ts-sdk'
19874
+ * const channel = await MessageRepository.unpinMessage(messageId)
19875
+ * console.log(channel.pinnedMessage) // null
19876
+ * ```
19877
+ *
19878
+ * Removes the pin from a {@link Amity.Message}. `messageId` must be the message that is
19879
+ * **currently** pinned in its channel; otherwise the server answers 400 — this is
19880
+ * deliberate, so a stale client cannot clear a pin that someone else has since replaced.
19881
+ * On that error, re-read the channel (or rely on the `channel.messagePinned` event) to
19882
+ * get the current pin.
19883
+ *
19884
+ * The caller must hold the `PIN_MESSAGE` permission in the channel (or be an admin with
19885
+ * `ModerateChannel`). Unpinning is allowed regardless of channel type and stream state.
19886
+ *
19887
+ * The response is the affected channel; it is ingested into cache and fires
19888
+ * `local.channel.updated`, so `ChannelRepository.getChannel` observers update without
19889
+ * waiting for the `channel.messageUnpinned` realtime event.
19890
+ *
19891
+ * @param messageId the **internal** ID of the currently pinned {@link Amity.Message}
19892
+ * @returns the updated {@link Amity.Channel}, with `pinnedMessage` cleared
19893
+ *
19894
+ * @category Message API
19895
+ * @async
19896
+ */
19897
+ const unpinMessage = async (messageId) => {
19898
+ const client = getActiveClient();
19899
+ client.log('message/unpinMessage', messageId);
19900
+ let payload;
19901
+ try {
19902
+ ({ data: payload } = await client.http.delete(`/api/v5/messages/${encodeURIComponent(messageId)}/pin`));
19903
+ }
19904
+ catch (error) {
19905
+ if ((error === null || error === void 0 ? void 0 : error.code) === 400301 /* Amity.ServerError.PERMISSION_DENIED */) {
19906
+ refreshChannelPermissionsForMessage(messageId);
19907
+ }
19908
+ throw error;
19909
+ }
19910
+ const data = await prepareChannelPayload(payload);
19911
+ if (client.cache)
19912
+ ingestInCache(data);
19913
+ fireEvent('local.channel.updated', data);
19914
+ return constructChannelObject(data.channels[0]);
19915
+ };
19916
+ /* end_public_function */
19917
+
19085
19918
  /**
19086
19919
  * ```js
19087
19920
  * import { MessageRepository } from '@amityco/ts-sdk-react-native'
@@ -19978,13 +20811,15 @@ const searchMessage = (params, callback) => {
19978
20811
  };
19979
20812
  /* end_public_function */
19980
20813
 
19981
- var index$n = /*#__PURE__*/Object.freeze({
20814
+ var index$o = /*#__PURE__*/Object.freeze({
19982
20815
  __proto__: null,
19983
20816
  createMessage: createMessage,
19984
20817
  updateMessage: updateMessage,
19985
20818
  editMessage: editMessage,
19986
20819
  deleteMessage: deleteMessage,
19987
20820
  softDeleteMessage: softDeleteMessage,
20821
+ pinMessage: pinMessage,
20822
+ unpinMessage: unpinMessage,
19988
20823
  markAsDelivered: markAsDelivered,
19989
20824
  getReadUsers: getReadUsers,
19990
20825
  getDeliveredUsers: getDeliveredUsers,
@@ -20514,7 +21349,7 @@ const stopMessageReceiptSync = (subChannelId) => {
20514
21349
  };
20515
21350
  /* end_public_function */
20516
21351
 
20517
- var index$m = /*#__PURE__*/Object.freeze({
21352
+ var index$n = /*#__PURE__*/Object.freeze({
20518
21353
  __proto__: null,
20519
21354
  getSubChannelByIds: getSubChannels$1,
20520
21355
  createSubChannel: createSubChannel,
@@ -20621,7 +21456,12 @@ const getChannel = (channelId, callback) => {
20621
21456
  onChannelMemberRemoved,
20622
21457
  onChannelMemberBanned,
20623
21458
  onChannelMemberUnbanned,
21459
+ onChannelMemberRoleAdded,
21460
+ onChannelMemberRoleRemoved,
20624
21461
  onChannelSetMuted,
21462
+ onChannelMessagePinned,
21463
+ onChannelMessageUnpinned,
21464
+ onChannelPinnedMessageDeleted,
20625
21465
  convertEventPayload(onChannelMarkerFetched, 'entityId', 'channel'),
20626
21466
  convertEventPayload(onChannelMarkerUpdated, 'entityId', 'channel'),
20627
21467
  convertEventPayload((callback) => {
@@ -21247,6 +22087,14 @@ class ChannelLiveCollectionController extends LiveCollectionController {
21247
22087
  return;
21248
22088
  if (messagePreviewSetting ===
21249
22089
  "message-preview-not-include-deleted" /* Amity.MessagePreviewSetting.MESSAGE_PREVIEW_NOT_INCLUDE_DELETED */) {
22090
+ // The replacement preview the server sends back is an OLDER
22091
+ // message than the one just deleted, and
22092
+ // updateChannelMessagePreviewCache drops any preview that is not
22093
+ // newer than what is cached — so without clearing the entry
22094
+ // first the refetch is a no-op and the channel keeps showing the
22095
+ // deleted message. getChannel's own live object already does
22096
+ // this; the live collections did not.
22097
+ dropFromCache(['messagePreviewChannel', 'get', message.channelId]);
21250
22098
  await getChannel$1(message.channelId);
21251
22099
  }
21252
22100
  callback(message);
@@ -21971,6 +22819,14 @@ class SearchChannelLiveCollectionController extends LiveCollectionController {
21971
22819
  return;
21972
22820
  if (messagePreviewSetting ===
21973
22821
  "message-preview-not-include-deleted" /* Amity.MessagePreviewSetting.MESSAGE_PREVIEW_NOT_INCLUDE_DELETED */) {
22822
+ // The replacement preview the server sends back is an OLDER
22823
+ // message than the one just deleted, and
22824
+ // updateChannelMessagePreviewCache drops any preview that is not
22825
+ // newer than what is cached — so without clearing the entry
22826
+ // first the refetch is a no-op and the channel keeps showing the
22827
+ // deleted message. getChannel's own live object already does
22828
+ // this; the live collections did not.
22829
+ dropFromCache(['messagePreviewChannel', 'get', message.channelId]);
21974
22830
  await getChannel$1(message.channelId);
21975
22831
  }
21976
22832
  callback(message);
@@ -22465,7 +23321,7 @@ const searchMembers$1 = (params, callback, config) => {
22465
23321
  };
22466
23322
  /* end_public_function */
22467
23323
 
22468
- var index$l = /*#__PURE__*/Object.freeze({
23324
+ var index$m = /*#__PURE__*/Object.freeze({
22469
23325
  __proto__: null,
22470
23326
  addMembers: addMembers$1,
22471
23327
  removeMembers: removeMembers$1,
@@ -22687,7 +23543,7 @@ const unmuteMembers = async (channelId, userIds) => {
22687
23543
  };
22688
23544
  /* end_public_function */
22689
23545
 
22690
- var index$k = /*#__PURE__*/Object.freeze({
23546
+ var index$l = /*#__PURE__*/Object.freeze({
22691
23547
  __proto__: null,
22692
23548
  addRole: addRole,
22693
23549
  removeRole: removeRole,
@@ -22697,10 +23553,10 @@ var index$k = /*#__PURE__*/Object.freeze({
22697
23553
  unmuteMembers: unmuteMembers
22698
23554
  });
22699
23555
 
22700
- var index$j = /*#__PURE__*/Object.freeze({
23556
+ var index$k = /*#__PURE__*/Object.freeze({
22701
23557
  __proto__: null,
22702
- Membership: index$l,
22703
- Moderation: index$k,
23558
+ Membership: index$m,
23559
+ Moderation: index$l,
22704
23560
  getChannelByIds: getChannelByIds$1,
22705
23561
  createChannel: createChannel,
22706
23562
  updateChannel: updateChannel,
@@ -22718,6 +23574,8 @@ var index$j = /*#__PURE__*/Object.freeze({
22718
23574
  onChannelJoined: onChannelJoined,
22719
23575
  onChannelLeft: onChannelLeft,
22720
23576
  onChannelSetMuted: onChannelSetMuted,
23577
+ onChannelMessagePinned: onChannelMessagePinned,
23578
+ onChannelMessageUnpinned: onChannelMessageUnpinned,
22721
23579
  onChannelMemberAdded: onChannelMemberAdded,
22722
23580
  onChannelMemberRemoved: onChannelMemberRemoved,
22723
23581
  onChannelMemberBanned: onChannelMemberBanned,
@@ -22735,7 +23593,11 @@ var index$j = /*#__PURE__*/Object.freeze({
22735
23593
  isUnreadCountSupport: isUnreadCountSupport,
22736
23594
  convertFromRaw: convertFromRaw,
22737
23595
  preUpdateChannelCache: preUpdateChannelCache,
22738
- prepareChannelPayload: prepareChannelPayload
23596
+ prepareChannelPayload: prepareChannelPayload,
23597
+ findCachedChannelByAnyId: findCachedChannelByAnyId,
23598
+ findCachedChannelForPin: findCachedChannelForPin,
23599
+ updatePinnedMessageCache: updatePinnedMessageCache,
23600
+ applyChannelRolePayload: applyChannelRolePayload
22739
23601
  });
22740
23602
 
22741
23603
  const saveCommunityUsers = (communities, communityUsers) => {
@@ -24129,7 +24991,7 @@ const searchMembers = (params, callback, config) => {
24129
24991
  };
24130
24992
  /* end_public_function */
24131
24993
 
24132
- var index$i = /*#__PURE__*/Object.freeze({
24994
+ var index$j = /*#__PURE__*/Object.freeze({
24133
24995
  __proto__: null,
24134
24996
  addMembers: addMembers,
24135
24997
  removeMembers: removeMembers,
@@ -25380,7 +26242,7 @@ const unbanMembers = async (communityId, userIds) => {
25380
26242
  };
25381
26243
  /* end_public_function */
25382
26244
 
25383
- var index$h = /*#__PURE__*/Object.freeze({
26245
+ var index$i = /*#__PURE__*/Object.freeze({
25384
26246
  __proto__: null,
25385
26247
  addRoles: addRoles,
25386
26248
  removeRoles: removeRoles,
@@ -25388,10 +26250,10 @@ var index$h = /*#__PURE__*/Object.freeze({
25388
26250
  unbanMembers: unbanMembers
25389
26251
  });
25390
26252
 
25391
- var index$g = /*#__PURE__*/Object.freeze({
26253
+ var index$h = /*#__PURE__*/Object.freeze({
25392
26254
  __proto__: null,
25393
- Moderation: index$h,
25394
- Membership: index$i,
26255
+ Moderation: index$i,
26256
+ Membership: index$j,
25395
26257
  getCommunityByIds: getCommunities$1,
25396
26258
  createCommunity: createCommunity,
25397
26259
  updateCommunity: updateCommunity,
@@ -25628,7 +26490,7 @@ const getCategories = (params, callback, config) => {
25628
26490
  };
25629
26491
  /* end_public_function */
25630
26492
 
25631
- var index$f = /*#__PURE__*/Object.freeze({
26493
+ var index$g = /*#__PURE__*/Object.freeze({
25632
26494
  __proto__: null,
25633
26495
  getCategory: getCategory,
25634
26496
  getCategories: getCategories
@@ -25927,6 +26789,11 @@ const createCommentOptimistic = (bundle) => {
25927
26789
  targetType: 'community',
25928
26790
  dataType: 'text',
25929
26791
  syncState: "syncing" /* Amity.SyncState.Syncing */,
26792
+ // In a gated community the optimistic object stays out of public collections until the
26793
+ // response settles the status; the author's own view still updates through the local event
26794
+ approvalStatus: isCommentApprovalRequired(bundle)
26795
+ ? "pending" /* Amity.CommentApprovalStatusEnum.Pending */
26796
+ : "approved" /* Amity.CommentApprovalStatusEnum.Approved */,
25930
26797
  };
25931
26798
  const cachedAt = UNSYNCED_OBJECT_CACHED_AT_VALUE;
25932
26799
  pushToCache(['comment', 'get', comment.commentId], comment, { cachedAt });
@@ -25943,32 +26810,57 @@ const createCommentOptimistic = (bundle) => {
25943
26810
  * ```js
25944
26811
  * import { CommentRepository } from '@amityco/ts-sdk-react-native'
25945
26812
  * const newComment = await CommentRepository.createComment(bundle)
26813
+ *
26814
+ * // Server-confirmed only: nothing is shown until the request succeeds
26815
+ * const confirmed = await CommentRepository.createComment(bundle, false)
25946
26816
  * ```
25947
26817
  *
25948
26818
  * Creates an {@link Amity.Comment}
25949
26819
  *
26820
+ * With `isOptimistic` (the default) a local comment appears at once with `syncState: 'syncing'`,
26821
+ * moves to `'synced'` when the server confirms it and to `'error'` if the request fails, so the
26822
+ * caller can offer a retry. With `isOptimistic: false` nothing is created locally until the
26823
+ * server answers: on success the comment arrives already `'synced'`; on failure no comment
26824
+ * entity exists anywhere and the promise rejects.
26825
+ *
25950
26826
  * @param bundle The data necessary to create a new {@link Amity.Comment}
26827
+ * @param isOptimistic Show a local comment before the server confirms it. Default `true`.
26828
+ * Ignored when the client cache is disabled, since there is nowhere to hold the local comment.
25951
26829
  * @returns The newly created {@link Amity.Comment}
25952
26830
  *
25953
26831
  * @category Comment API
25954
26832
  * @async
25955
26833
  */
25956
- const createComment = async (bundle) => {
26834
+ const createComment = async (bundle, isOptimistic = true) => {
25957
26835
  const client = getActiveClient();
25958
- client.log('comment/createComment', bundle);
25959
- const optimisticData = createCommentOptimistic(bundle);
26836
+ client.log('comment/createComment', Object.assign(Object.assign({}, bundle), { isOptimistic }));
26837
+ // Without a local comment the server assigns the id; with one, the same id travels through the
26838
+ // optimistic object, the response and every realtime event so each step recognises it.
26839
+ const optimisticData = isOptimistic ? createCommentOptimistic(bundle) : undefined;
25960
26840
  const commentId = optimisticData === null || optimisticData === void 0 ? void 0 : optimisticData.commentId;
25961
26841
  try {
25962
- const { data } = await client.http.post('/api/v3/comments', Object.assign(Object.assign({}, bundle), { commentId }));
25963
- const { comments } = data;
26842
+ const { data: payload } = await client.http.post('/api/v3/comments', Object.assign(Object.assign({}, bundle), { commentId }));
25964
26843
  // BE always returns an array of comments If it got record 0 from BE it might have a problem on creation logic
25965
- if (comments.length === 0)
26844
+ if (payload.comments.length === 0)
25966
26845
  throw new Error('Comment not created');
26846
+ // Absent `approvalStatus` means approved; the result is the only source of the status.
26847
+ // The confirmed comment is written as `synced` so the cache itself tells the two states apart
26848
+ // (a local-event subscriber is not guaranteed to be listening).
26849
+ const prepared = prepareCommentPayload(payload);
26850
+ const data = Object.assign(Object.assign({}, prepared), { comments: prepared.comments.map(comment => comment.commentId === (commentId !== null && commentId !== void 0 ? commentId : comment.commentId)
26851
+ ? Object.assign(Object.assign({}, comment), { syncState: "synced" /* Amity.SyncState.Synced */ }) : comment) });
26852
+ const { comments } = data;
25967
26853
  const cachedAt = client.cache && Date.now();
25968
26854
  if (client.cache)
25969
26855
  ingestInCache(data, { cachedAt });
25970
26856
  if (['post', 'content'].includes(bundle.referenceType)) {
25971
- PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new CreateTask(bundle.referenceId, comments[0].commentId, data.comments[0].createdAt));
26857
+ if (isCommentPending(comments[0])) {
26858
+ // Not counted for anyone else until approved; the author sees their own +1
26859
+ recordPendingAuthoredComment(comments[0]);
26860
+ }
26861
+ else {
26862
+ PostCommentCountEngine$1.getInstance().queueCommentChangeTask(new CreateTask(bundle.referenceId, comments[0].commentId, comments[0].createdAt));
26863
+ }
25972
26864
  }
25973
26865
  else if (bundle.referenceType === 'story') {
25974
26866
  const storyIndex = pullFromCache([
@@ -25989,9 +26881,9 @@ const createComment = async (bundle) => {
25989
26881
  categories: [],
25990
26882
  comments,
25991
26883
  communities: [],
25992
- communityUsers: data.communityUsers,
25993
- files: data.files,
25994
- users: data.users,
26884
+ communityUsers: payload.communityUsers,
26885
+ files: payload.files,
26886
+ users: payload.users,
25995
26887
  });
25996
26888
  }
25997
26889
  }
@@ -25999,9 +26891,9 @@ const createComment = async (bundle) => {
25999
26891
  fireEvent('local.comment.created', {
26000
26892
  comments: [Object.assign(Object.assign({}, comments[0]), { syncState: "synced" /* Amity.SyncState.Synced */ })],
26001
26893
  commentChildren: data.commentChildren,
26002
- users: data.users,
26003
- files: data.files,
26004
- communityUsers: data.communityUsers,
26894
+ users: payload.users,
26895
+ files: payload.files,
26896
+ communityUsers: payload.communityUsers,
26005
26897
  });
26006
26898
  return {
26007
26899
  data: LinkedObject.comment(comments[0]),
@@ -26009,9 +26901,17 @@ const createComment = async (bundle) => {
26009
26901
  };
26010
26902
  }
26011
26903
  catch (e) {
26904
+ // Only a local comment has anything to mark as failed; a server-confirmed-only create leaves
26905
+ // no entity behind
26012
26906
  if (optimisticData) {
26907
+ const failed = Object.assign(Object.assign({}, optimisticData), { syncState: "error" /* Amity.SyncState.Error */ });
26908
+ // Write the failure to the cache directly: the local event below only reaches pages that
26909
+ // observe comments, and the caller's retry UI reads the cached state
26910
+ pushToCache(['comment', 'get', failed.commentId], failed, {
26911
+ cachedAt: UNSYNCED_OBJECT_CACHED_AT_VALUE,
26912
+ });
26013
26913
  fireEvent('local.comment.created', {
26014
- comments: [Object.assign(Object.assign({}, optimisticData), { syncState: "error" /* Amity.SyncState.Error */ })],
26914
+ comments: [failed],
26015
26915
  commentChildren: [],
26016
26916
  users: [],
26017
26917
  files: [],
@@ -26044,16 +26944,26 @@ const createComment = async (bundle) => {
26044
26944
  * @async
26045
26945
  */
26046
26946
  const updateComment = async (commentId, patch) => {
26947
+ var _a;
26047
26948
  const client = getActiveClient();
26048
26949
  client.log('user/updateComment', patch);
26049
- const { data } = await client.http.put(`/api/v3/comments/${encodeURIComponent(commentId)}`, patch);
26950
+ const previous = (_a = pullFromCache(['comment', 'get', commentId])) === null || _a === void 0 ? void 0 : _a.data;
26951
+ const { data: payload } = await client.http.put(`/api/v3/comments/${encodeURIComponent(commentId)}`, patch);
26952
+ const data = prepareCommentPayload(payload);
26953
+ const updated = data.comments.find(comment => comment.commentId === commentId);
26050
26954
  const cachedAt = client.cache && Date.now();
26051
26955
  if (client.cache)
26052
26956
  ingestInCache(data, { cachedAt });
26053
- fireEvent('comment.updated', data);
26054
- const { comments } = data;
26957
+ // An effective edit in a gated community sends the comment back for review: it leaves the
26958
+ // public reply list and the public count once. The `comment.updated` event below removes it
26959
+ // from the comment collections; the realtime echo finds it already pending and does nothing.
26960
+ if (isCommentPending(updated) && previous && isCommentApproved(previous)) {
26961
+ unlinkCommentFromParent(updated);
26962
+ applyCommentReReviewCount(updated);
26963
+ }
26964
+ fireEvent('comment.updated', payload);
26055
26965
  return {
26056
- data: LinkedObject.comment(comments.find(comment => comment.commentId === commentId)),
26966
+ data: LinkedObject.comment(updated),
26057
26967
  cachedAt,
26058
26968
  };
26059
26969
  };
@@ -26193,7 +27103,13 @@ const deleteComment = async (commentId, permanent = false) => {
26193
27103
  const post = (_b = pullFromCache(['post', 'get', comment.data.referenceId])) === null || _b === void 0 ? void 0 : _b.data;
26194
27104
  if (post) {
26195
27105
  const engine = PostCommentCountEngine$1.getInstance();
26196
- engine.queueCommentChangeTask(new DeleteTask(post.postId, commentId));
27106
+ if (isCommentPending(comment.data)) {
27107
+ // Never counted for anyone else; only the author's own +1 goes away
27108
+ engine.removePendingAuthoredComment(post.postId, commentId);
27109
+ }
27110
+ else {
27111
+ engine.queueCommentChangeTask(new DeleteTask(post.postId, commentId));
27112
+ }
26197
27113
  if (!deleted.parentId && ((_c = deleted.children /* c8 ignore next */) === null || _c === void 0 ? void 0 : _c.length) > 0) {
26198
27114
  // NOTE: delete the parent comment will also remove all children comments
26199
27115
  deleted.children.forEach((childCommentId) => {
@@ -26263,6 +27179,109 @@ const hardDeleteComment = async (commentId) => {
26263
27179
  };
26264
27180
  /* end_public_function */
26265
27181
 
27182
+ /* begin_public_function
27183
+ id: comment.approve
27184
+ */
27185
+ /**
27186
+ * ```js
27187
+ * import { CommentRepository } from '@amityco/ts-sdk'
27188
+ *
27189
+ * const { data: comment } = await CommentRepository.approveComment('commentId')
27190
+ * ```
27191
+ *
27192
+ * Approves a {@link Amity.Comment} held for review, making it visible to everyone
27193
+ *
27194
+ * @param commentId The {@link Amity.Comment} ID to be approved
27195
+ * @return The {@link Amity.Comment} that was approved
27196
+ *
27197
+ * @category Comment API
27198
+ * @async
27199
+ */
27200
+ const approveComment = async (commentId) => {
27201
+ const client = getActiveClient();
27202
+ client.log('comment/approveComment', commentId);
27203
+ // No request body, and nothing is revealed before the server confirms
27204
+ const { data: payload } = await client.http.post(`/api/v3/comments/${encodeURIComponent(commentId)}/approve`);
27205
+ const data = prepareCommentPayload(prepareMembershipPayload(payload, 'communityUsers'));
27206
+ const approved = data.comments.find(comment => comment.commentId === commentId);
27207
+ const cachedAt = client.cache && Date.now();
27208
+ if (client.cache)
27209
+ ingestInCache(data, { cachedAt });
27210
+ // The reveal path: parent link and exactly one count task. Applied here so it does not depend
27211
+ // on an observer being open; the event below and the realtime `comment.approved` that follows
27212
+ // find the work done and reconcile by comment id (collection insert, queue removal).
27213
+ linkCommentToParent(approved);
27214
+ applyCommentApprovedCount(approved);
27215
+ fireEvent('comment.approved', payload);
27216
+ return {
27217
+ data: LinkedObject.comment(approved),
27218
+ cachedAt,
27219
+ };
27220
+ };
27221
+ /* end_public_function */
27222
+
27223
+ // Rejected is terminal and implies deleted
27224
+ const markRejected = (comment) => (Object.assign(Object.assign({}, comment), { approvalStatus: "rejected" /* Amity.CommentApprovalStatusEnum.Rejected */, isDeleted: true }));
27225
+ /* begin_public_function
27226
+ id: comment.decline
27227
+ */
27228
+ /**
27229
+ * ```js
27230
+ * import { CommentRepository } from '@amityco/ts-sdk'
27231
+ *
27232
+ * const { data: comment } = await CommentRepository.declineComment('commentId', 'Off-topic')
27233
+ * ```
27234
+ *
27235
+ * Declines a {@link Amity.Comment} held for review. A declined comment is also a deleted comment
27236
+ *
27237
+ * @param commentId The {@link Amity.Comment} ID to be declined
27238
+ * @param reason Optional reviewer's note, at most 250 characters, kept for the moderation record only
27239
+ * @return The {@link Amity.Comment} that was declined
27240
+ *
27241
+ * @category Comment API
27242
+ * @async
27243
+ */
27244
+ const declineComment = async (commentId, reason) => {
27245
+ var _a, _b, _c, _d, _e, _f;
27246
+ const client = getActiveClient();
27247
+ client.log('comment/declineComment', commentId, reason);
27248
+ // Read before the request: the fallback when the response carries no comment
27249
+ const cached = (_a = pullFromCache(['comment', 'get', commentId])) === null || _a === void 0 ? void 0 : _a.data;
27250
+ // `reason` is surfaced to nobody; the key is absent from the body when the caller gives none
27251
+ const { data: payload } = await client.http.post(`/api/v3/comments/${encodeURIComponent(commentId)}/decline`, reason ? { reason } : undefined);
27252
+ // The BE contract (PDT-5135 §3) states the response body for approve only; for decline the
27253
+ // standard comment payload is assumed. Ingest whatever came back, and when the body carries no
27254
+ // comment fall back to the cached one so the delete path below still runs.
27255
+ const returned = (_b = payload === null || payload === void 0 ? void 0 : payload.comments) === null || _b === void 0 ? void 0 : _b.some(comment => comment.commentId === commentId);
27256
+ if (!returned && !cached)
27257
+ throw new Error('Comment not found after decline');
27258
+ const comments = returned
27259
+ ? payload.comments.map(comment => comment.commentId === commentId ? markRejected(comment) : comment)
27260
+ : [markRejected(cached)];
27261
+ const declined = {
27262
+ comments,
27263
+ commentChildren: (_c = payload === null || payload === void 0 ? void 0 : payload.commentChildren) !== null && _c !== void 0 ? _c : [],
27264
+ users: (_d = payload === null || payload === void 0 ? void 0 : payload.users) !== null && _d !== void 0 ? _d : [],
27265
+ files: (_e = payload === null || payload === void 0 ? void 0 : payload.files) !== null && _e !== void 0 ? _e : [],
27266
+ communityUsers: (_f = payload === null || payload === void 0 ? void 0 : payload.communityUsers) !== null && _f !== void 0 ? _f : [],
27267
+ };
27268
+ // There is no `comment.declined` event: the existing delete path drops the comment from every
27269
+ // collection and the review queue, and moves no count because a pending comment was never counted.
27270
+ const data = prepareCommentPayload(prepareMembershipPayload(declined, 'communityUsers'));
27271
+ const rejected = data.comments.find(comment => comment.commentId === commentId);
27272
+ const cachedAt = client.cache && Date.now();
27273
+ if (client.cache)
27274
+ ingestInCache(data, { cachedAt });
27275
+ unlinkCommentFromParent(rejected);
27276
+ releasePendingAuthoredComment(rejected);
27277
+ fireEvent('comment.deleted', declined);
27278
+ return {
27279
+ data: LinkedObject.comment(rejected),
27280
+ cachedAt,
27281
+ };
27282
+ };
27283
+ /* end_public_function */
27284
+
26266
27285
  /* begin_public_function
26267
27286
  id: comment.flag
26268
27287
  */
@@ -26348,6 +27367,7 @@ const isCommentFlaggedByMe = async (commentId) => {
26348
27367
  /* end_public_function */
26349
27368
 
26350
27369
  const getComment$1 = async (commentId) => {
27370
+ var _a;
26351
27371
  const client = getActiveClient();
26352
27372
  client.log('comment/getComment', commentId);
26353
27373
  isInTombstone('comment', commentId);
@@ -26358,7 +27378,11 @@ const getComment$1 = async (commentId) => {
26358
27378
  data = response.data;
26359
27379
  }
26360
27380
  catch (error) {
26361
- if (checkIfShouldGoesToTombstone(error === null || error === void 0 ? void 0 : error.code)) {
27381
+ // A pending comment answers 404 to anyone but its author and reviewers. That is a
27382
+ // visibility answer, not a deletion — never tombstone a comment known to be pending.
27383
+ const cached = (_a = pullFromCache(['comment', 'get', commentId])) === null || _a === void 0 ? void 0 : _a.data;
27384
+ const isKnownPending = !!cached && isCommentPending(cached);
27385
+ if (!isKnownPending && checkIfShouldGoesToTombstone(error === null || error === void 0 ? void 0 : error.code)) {
26362
27386
  pushToTombstone('comment', commentId);
26363
27387
  }
26364
27388
  throw error;
@@ -26485,6 +27509,7 @@ const onLocalCommentReactionRemoved = (callback) => {
26485
27509
  */
26486
27510
  const getComment = (commentId, callback) => {
26487
27511
  return liveObject(commentId, callback, 'commentId', getComment$1, [
27512
+ onCommentApproved,
26488
27513
  onCommentDeleteLocal,
26489
27514
  onCommentDeleted,
26490
27515
  onCommentFlagged,
@@ -26498,28 +27523,31 @@ const getComment = (commentId, callback) => {
26498
27523
  };
26499
27524
  /* end_public_function */
26500
27525
 
26501
- class CommentPaginationController extends PaginationController {
26502
- async getRequest(queryParams, token) {
26503
- var _a;
26504
- const { pageSize, limit, includeDeleted } = queryParams, params = __rest(queryParams, ["pageSize", "limit", "includeDeleted"]);
26505
- const effectiveLimit = (_a = pageSize !== null && pageSize !== void 0 ? pageSize : limit) !== null && _a !== void 0 ? _a : COLLECTION_DEFAULT_PAGINATION_LIMIT;
26506
- const baseOptions = {
26507
- type: params.sortBy || queryParams.limit || queryParams.pageSize ? 'pagination' : undefined,
26508
- };
26509
- const options = token
26510
- ? Object.assign(Object.assign({}, baseOptions), { token }) : Object.assign(Object.assign({}, baseOptions), { pageSize: effectiveLimit, limit: effectiveLimit });
26511
- const { data: queryResponse } = await this.http.get(`/api/v3/comments`, {
26512
- params: Object.assign(Object.assign({}, params), { isDeleted: inferIsDeleted(includeDeleted), options }),
26513
- });
26514
- return queryResponse;
26515
- }
26516
- }
27526
+ /**
27527
+ * ```js
27528
+ * import { onCommentCreated } from '@amityco/ts-sdk-react-native'
27529
+ * const dispose = onCommentCreated(comment => {
27530
+ * // ...
27531
+ * })
27532
+ * ```
27533
+ *
27534
+ * Fired when a {@link Amity.InternalComment} has been created
27535
+ *
27536
+ * @param callback The function to call when the event was fired
27537
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
27538
+ *
27539
+ * @category Comment Events
27540
+ */
27541
+ const onCommentCreatedLocal = (callback) => {
27542
+ return createLocalCommentEventSubscriber('local.comment.created', callback);
27543
+ };
26517
27544
 
26518
27545
  var EnumCommentActions;
26519
27546
  (function (EnumCommentActions) {
26520
27547
  EnumCommentActions["OnCommentCreated"] = "onCommentCreated";
26521
27548
  EnumCommentActions["OnCommentUpdated"] = "onCommentUpdated";
26522
27549
  EnumCommentActions["OnCommentDeleted"] = "onCommentDeleted";
27550
+ EnumCommentActions["OnCommentApproved"] = "onCommentApproved";
26523
27551
  EnumCommentActions["OnCommentFlagged"] = "onCommentFlagged";
26524
27552
  EnumCommentActions["OnCommentUnflagged"] = "onCommentUnflagged";
26525
27553
  EnumCommentActions["OnCommentReactionAdded"] = "onCommentReactionAdded";
@@ -26542,15 +27570,17 @@ class CommentQueryStreamController extends QueryStreamController {
26542
27570
  }
26543
27571
  appendToQueryStream(response, direction, refresh = false) {
26544
27572
  var _a, _b;
27573
+ // The public list is approved-only even when the server widens the read for a reviewer
27574
+ const commentIds = response.comments.filter(isCommentApproved).map(getResolver('comment'));
26545
27575
  if (refresh) {
26546
27576
  pushToCache(this.cacheKey, {
26547
- data: response.comments.map(getResolver('comment')),
27577
+ data: commentIds,
26548
27578
  });
26549
27579
  }
26550
27580
  else {
26551
27581
  const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
26552
27582
  const comments = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
26553
- pushToCache(this.cacheKey, Object.assign(Object.assign({}, collection), { data: [...new Set([...comments, ...response.comments.map(getResolver('comment'))])] }));
27583
+ pushToCache(this.cacheKey, Object.assign(Object.assign({}, collection), { data: [...new Set([...comments, ...commentIds])] }));
26554
27584
  }
26555
27585
  }
26556
27586
  reactor(action) {
@@ -26569,8 +27599,19 @@ class CommentQueryStreamController extends QueryStreamController {
26569
27599
  return;
26570
27600
  }
26571
27601
  if (action === EnumCommentActions.OnCommentCreated) {
27602
+ // A pending comment reaches clients over realtime before anyone may see it: persist
27603
+ // only, no insert and no emit. `comment.approved` is the reveal signal.
27604
+ if (!isCommentApproved(comment))
27605
+ return;
26572
27606
  collection.data = [...new Set([comment.commentId, ...collection.data])];
26573
27607
  }
27608
+ if (action === EnumCommentActions.OnCommentApproved) {
27609
+ collection.data = [...new Set([comment.commentId, ...collection.data])];
27610
+ }
27611
+ // An effective edit in a gated community returns the comment to review: it leaves the list
27612
+ if (action === EnumCommentActions.OnCommentUpdated && isCommentPending(comment)) {
27613
+ collection.data = collection.data.filter(commentId => commentId !== comment.commentId);
27614
+ }
26574
27615
  pushToCache(this.cacheKey, collection);
26575
27616
  this.notifyChange({ origin: "event" /* Amity.LiveDataOrigin.EVENT */, loading: false });
26576
27617
  };
@@ -26580,24 +27621,22 @@ class CommentQueryStreamController extends QueryStreamController {
26580
27621
  }
26581
27622
  }
26582
27623
 
26583
- /**
26584
- * ```js
26585
- * import { onCommentCreated } from '@amityco/ts-sdk-react-native'
26586
- * const dispose = onCommentCreated(comment => {
26587
- * // ...
26588
- * })
26589
- * ```
26590
- *
26591
- * Fired when a {@link Amity.InternalComment} has been created
26592
- *
26593
- * @param callback The function to call when the event was fired
26594
- * @returns an {@link Amity.Unsubscriber} function to stop listening
26595
- *
26596
- * @category Comment Events
26597
- */
26598
- const onCommentCreatedLocal = (callback) => {
26599
- return createLocalCommentEventSubscriber('local.comment.created', callback);
26600
- };
27624
+ class CommentPaginationController extends PaginationController {
27625
+ async getRequest(queryParams, token) {
27626
+ var _a;
27627
+ const { pageSize, limit, includeDeleted } = queryParams, params = __rest(queryParams, ["pageSize", "limit", "includeDeleted"]);
27628
+ const effectiveLimit = (_a = pageSize !== null && pageSize !== void 0 ? pageSize : limit) !== null && _a !== void 0 ? _a : COLLECTION_DEFAULT_PAGINATION_LIMIT;
27629
+ const baseOptions = {
27630
+ type: params.sortBy || queryParams.limit || queryParams.pageSize ? 'pagination' : undefined,
27631
+ };
27632
+ const options = token
27633
+ ? Object.assign(Object.assign({}, baseOptions), { token }) : Object.assign(Object.assign({}, baseOptions), { pageSize: effectiveLimit, limit: effectiveLimit });
27634
+ const { data: queryResponse } = await this.http.get(`/api/v3/comments`, {
27635
+ params: Object.assign(Object.assign({}, params), { isDeleted: inferIsDeleted(includeDeleted), options }),
27636
+ });
27637
+ return queryResponse;
27638
+ }
27639
+ }
26601
27640
 
26602
27641
  class CommentLiveCollectionController extends LiveCollectionController {
26603
27642
  constructor(query, callback) {
@@ -26633,6 +27672,7 @@ class CommentLiveCollectionController extends LiveCollectionController {
26633
27672
  { fn: onCommentCreated, action: EnumCommentActions.OnCommentCreated },
26634
27673
  { fn: onCommentUpdated, action: EnumCommentActions.OnCommentUpdated },
26635
27674
  { fn: onCommentDeleted, action: EnumCommentActions.OnCommentDeleted },
27675
+ { fn: onCommentApproved, action: EnumCommentActions.OnCommentApproved },
26636
27676
  { fn: onCommentFlagged, action: EnumCommentActions.OnCommentFlagged },
26637
27677
  { fn: onCommentUnflagged, action: EnumCommentActions.OnCommentUnflagged },
26638
27678
  { fn: onCommentReactionAdded, action: EnumCommentActions.OnCommentReactionAdded },
@@ -26666,7 +27706,8 @@ class CommentLiveCollectionController extends LiveCollectionController {
26666
27706
  });
26667
27707
  }
26668
27708
  applyFilter(data) {
26669
- let comments = data;
27709
+ // Approved-only, for every caller including the author of a pending comment
27710
+ let comments = data.filter(isCommentApproved);
26670
27711
  if (!this.query.includeDeleted) {
26671
27712
  comments = filterByPropEquality(comments, 'isDeleted', false);
26672
27713
  }
@@ -26754,7 +27795,202 @@ const getComments = (params, callback, config) => {
26754
27795
  };
26755
27796
  /* end_public_function */
26756
27797
 
26757
- var index$e = /*#__PURE__*/Object.freeze({
27798
+ class CommentReviewQueuePaginationController extends PaginationController {
27799
+ async getRequest(queryParams, token) {
27800
+ const { communityId, limit } = queryParams, params = __rest(queryParams, ["communityId", "limit"]);
27801
+ // The route defaults to 10, not the SDK-wide 20, and rejects anything above 100
27802
+ const effectiveLimit = Math.min(limit !== null && limit !== void 0 ? limit : COMMENT_REVIEW_QUEUE_DEFAULT_PAGINATION_SIZE, COMMENT_REVIEW_QUEUE_MAX_PAGINATION_SIZE);
27803
+ // Token paging only. The route also accepts options[skip], but offset paging over a queue that
27804
+ // drains from the front skips items, so the SDK never sends it.
27805
+ const options = token ? { token } : { limit: effectiveLimit };
27806
+ const { data: queryResponse } = await this.http.get(API_ENDPOINTS.commentReviewQueue(communityId), {
27807
+ params: Object.assign(Object.assign({}, params), { options }),
27808
+ });
27809
+ return queryResponse;
27810
+ }
27811
+ }
27812
+
27813
+ class CommentReviewQueueQueryStreamController extends QueryStreamController {
27814
+ constructor(query, cacheKey, notifyChange) {
27815
+ super(query, cacheKey);
27816
+ this.notifyChange = notifyChange;
27817
+ }
27818
+ async saveToMainDB(response) {
27819
+ const processedPayload = prepareCommentPayload(response);
27820
+ const client = getActiveClient();
27821
+ const cachedAt = client.cache && Date.now();
27822
+ if (client.cache) {
27823
+ ingestInCache(processedPayload, { cachedAt });
27824
+ }
27825
+ }
27826
+ appendToQueryStream(response, direction, refresh = false) {
27827
+ var _a, _b;
27828
+ // Server order is queue-entry order, oldest first. Keep it: later pages append, nothing
27829
+ // re-sorts by createdAt (the two diverge on re-review).
27830
+ const commentIds = response.comments.map(getResolver('comment'));
27831
+ if (refresh) {
27832
+ pushToCache(this.cacheKey, {
27833
+ data: commentIds,
27834
+ });
27835
+ }
27836
+ else {
27837
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27838
+ const comments = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
27839
+ pushToCache(this.cacheKey, Object.assign(Object.assign({}, collection), { data: [...new Set([...comments, ...commentIds])] }));
27840
+ }
27841
+ }
27842
+ matchesQuery(comment) {
27843
+ return (comment.targetType === 'community' &&
27844
+ comment.targetId === this.query.communityId &&
27845
+ (!this.query.postId || comment.referenceId === this.query.postId));
27846
+ }
27847
+ reactor(action) {
27848
+ return (comment) => {
27849
+ var _a;
27850
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27851
+ if (!collection || !this.matchesQuery(comment))
27852
+ return;
27853
+ const isQueued = collection.data.includes(comment.commentId);
27854
+ // A date-filtered queue is the server's to shape; live events only remove from it
27855
+ const acceptsLiveInserts = !this.query.startDate && !this.query.endDate;
27856
+ switch (action) {
27857
+ case EnumCommentActions.OnCommentCreated:
27858
+ case EnumCommentActions.OnCommentUpdated:
27859
+ if (isCommentPending(comment) && !comment.isDeleted) {
27860
+ if (isQueued || !acceptsLiveInserts)
27861
+ return;
27862
+ // Enters (or, after an edit, re-enters) the queue at the end
27863
+ collection.data = [...collection.data, comment.commentId];
27864
+ }
27865
+ else {
27866
+ if (!isQueued)
27867
+ return;
27868
+ collection.data = collection.data.filter(commentId => commentId !== comment.commentId);
27869
+ }
27870
+ break;
27871
+ case EnumCommentActions.OnCommentApproved:
27872
+ case EnumCommentActions.OnCommentDeleted:
27873
+ if (!isQueued)
27874
+ return;
27875
+ collection.data = collection.data.filter(commentId => commentId !== comment.commentId);
27876
+ break;
27877
+ default:
27878
+ return;
27879
+ }
27880
+ pushToCache(this.cacheKey, collection);
27881
+ this.notifyChange({ origin: "event" /* Amity.LiveDataOrigin.EVENT */, loading: false });
27882
+ };
27883
+ }
27884
+ subscribeRTE(createSubscriber) {
27885
+ return createSubscriber.map(subscriber => subscriber.fn(this.reactor(subscriber.action)));
27886
+ }
27887
+ }
27888
+
27889
+ class CommentReviewQueueLiveCollectionController extends LiveCollectionController {
27890
+ constructor(query, callback) {
27891
+ const queryStreamId = hash__default["default"](query);
27892
+ const cacheKey = ['commentReviewQueue', 'collection', queryStreamId];
27893
+ const paginationController = new CommentReviewQueuePaginationController(query);
27894
+ super(paginationController, queryStreamId, cacheKey, callback);
27895
+ this.query = query;
27896
+ this.queryStreamController = new CommentReviewQueueQueryStreamController(this.query, this.cacheKey, this.notifyChange.bind(this));
27897
+ this.callback = callback.bind(this);
27898
+ this.loadPage({ initial: true });
27899
+ }
27900
+ setup() {
27901
+ var _a;
27902
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27903
+ if (!collection) {
27904
+ pushToCache(this.cacheKey, {
27905
+ data: [],
27906
+ params: {},
27907
+ });
27908
+ }
27909
+ }
27910
+ async persistModel(queryPayload) {
27911
+ await this.queryStreamController.saveToMainDB(queryPayload);
27912
+ }
27913
+ persistQueryStream({ response, direction, refresh, }) {
27914
+ this.queryStreamController.appendToQueryStream(response, direction, refresh);
27915
+ }
27916
+ startSubscription() {
27917
+ // No `comment.declined` exists: a decline arrives as `comment.deleted`
27918
+ return this.queryStreamController.subscribeRTE([
27919
+ { fn: onCommentCreated, action: EnumCommentActions.OnCommentCreated },
27920
+ { fn: onCommentUpdated, action: EnumCommentActions.OnCommentUpdated },
27921
+ { fn: onCommentApproved, action: EnumCommentActions.OnCommentApproved },
27922
+ { fn: onCommentDeleted, action: EnumCommentActions.OnCommentDeleted },
27923
+ { fn: onCommentDeleteLocal, action: EnumCommentActions.OnCommentDeleted },
27924
+ ]);
27925
+ }
27926
+ notifyChange({ origin, loading, error }) {
27927
+ var _a;
27928
+ // A caller who lost REVIEW_COMMUNITY_COMMENT must not keep reading stale pending content
27929
+ if ((error === null || error === void 0 ? void 0 : error.code) === 400301 /* Amity.ServerError.PERMISSION_DENIED */) {
27930
+ pushToCache(this.cacheKey, { data: [], params: {} });
27931
+ }
27932
+ const collection = (_a = pullFromCache(this.cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27933
+ if (!collection)
27934
+ return;
27935
+ const data = collection.data
27936
+ .map(id => pullFromCache(['comment', 'get', id]))
27937
+ .filter(isNonNullable)
27938
+ .map(({ data }) => data)
27939
+ .filter(comment => isCommentPending(comment) && !comment.isDeleted)
27940
+ .map(LinkedObject.comment);
27941
+ if (!this.shouldNotify(data) && origin === 'event')
27942
+ return;
27943
+ this.callback({
27944
+ onNextPage: () => this.loadPage({ direction: "next" /* Amity.LiveCollectionPageDirection.NEXT */ }),
27945
+ data,
27946
+ hasNextPage: !!this.paginationController.getNextToken(),
27947
+ loading,
27948
+ error,
27949
+ });
27950
+ }
27951
+ }
27952
+
27953
+ /* begin_public_function
27954
+ id: comment.review_queue
27955
+ */
27956
+ /**
27957
+ * ```js
27958
+ * import { CommentRepository } from '@amityco/ts-sdk'
27959
+ *
27960
+ * const unsub = CommentRepository.getCommentReviewQueue(
27961
+ * { communityId: 'communityId' },
27962
+ * ({ data: comments, hasNextPage, onNextPage }) => {
27963
+ * // every comment is awaiting review
27964
+ * },
27965
+ * )
27966
+ * ```
27967
+ *
27968
+ * Observe the {@link Amity.Comment} list awaiting moderator review in a community, oldest first
27969
+ *
27970
+ * @param params the community to read the queue of, optionally narrowed to one post and a date range
27971
+ * @param callback the function to call when new data are available
27972
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the queue
27973
+ *
27974
+ * @category Comments Live Collection
27975
+ */
27976
+ const getCommentReviewQueue = (params, callback) => {
27977
+ const { log, cache } = getActiveClient();
27978
+ if (!cache)
27979
+ console.log(ENABLE_CACHE_MESSAGE);
27980
+ const timestamp = Date.now();
27981
+ log(`getCommentReviewQueue(tmpid: ${timestamp}) > listen`);
27982
+ const commentReviewQueueLiveCollection = new CommentReviewQueueLiveCollectionController(params, callback);
27983
+ const disposers = commentReviewQueueLiveCollection.startSubscription();
27984
+ const cacheKey = commentReviewQueueLiveCollection.getCacheKey();
27985
+ disposers.push(() => dropFromCache(cacheKey));
27986
+ return () => {
27987
+ log(`getCommentReviewQueue(tmpid: ${timestamp}) > dispose`);
27988
+ disposers.forEach(fn => fn());
27989
+ };
27990
+ };
27991
+ /* end_public_function */
27992
+
27993
+ var index$f = /*#__PURE__*/Object.freeze({
26758
27994
  __proto__: null,
26759
27995
  getCommentByIds: getCommentByIds,
26760
27996
  createComment: createComment,
@@ -26762,18 +27998,22 @@ var index$e = /*#__PURE__*/Object.freeze({
26762
27998
  deleteComment: deleteComment,
26763
27999
  softDeleteComment: softDeleteComment,
26764
28000
  hardDeleteComment: hardDeleteComment,
28001
+ approveComment: approveComment,
28002
+ declineComment: declineComment,
26765
28003
  flagComment: flagComment,
26766
28004
  unflagComment: unflagComment,
26767
28005
  isCommentFlaggedByMe: isCommentFlaggedByMe,
26768
28006
  onCommentCreated: onCommentCreated,
26769
28007
  onCommentUpdated: onCommentUpdated,
26770
28008
  onCommentDeleted: onCommentDeleted,
28009
+ onCommentApproved: onCommentApproved,
26771
28010
  onCommentFlagged: onCommentFlagged,
26772
28011
  onCommentUnflagged: onCommentUnflagged,
26773
28012
  onCommentReactionAdded: onCommentReactionAdded,
26774
28013
  onCommentReactionRemoved: onCommentReactionRemoved,
26775
28014
  getComment: getComment,
26776
- getComments: getComments
28015
+ getComments: getComments,
28016
+ getCommentReviewQueue: getCommentReviewQueue
26777
28017
  });
26778
28018
 
26779
28019
  /**
@@ -28023,7 +29263,7 @@ const getForYouFeed = (callback) => {
28023
29263
  };
28024
29264
  /* end_public_function */
28025
29265
 
28026
- var index$d = /*#__PURE__*/Object.freeze({
29266
+ var index$e = /*#__PURE__*/Object.freeze({
28027
29267
  __proto__: null,
28028
29268
  queryGlobalFeed: queryGlobalFeed,
28029
29269
  getCustomRankingGlobalFeed: getCustomRankingGlobalFeed,
@@ -31168,7 +32408,7 @@ const getRooms = (params, callback, config) => {
31168
32408
  };
31169
32409
  /* end_public_function */
31170
32410
 
31171
- var index$c = /*#__PURE__*/Object.freeze({
32411
+ var index$d = /*#__PURE__*/Object.freeze({
31172
32412
  __proto__: null,
31173
32413
  createRoom: createRoom,
31174
32414
  updateRoom: updateRoom,
@@ -31467,7 +32707,7 @@ const getCommunityLiveRoomPosts = (params, callback, config) => {
31467
32707
  };
31468
32708
  /* end_public_function */
31469
32709
 
31470
- var index$b = /*#__PURE__*/Object.freeze({
32710
+ var index$c = /*#__PURE__*/Object.freeze({
31471
32711
  __proto__: null,
31472
32712
  getPostByIds: getPostByIds,
31473
32713
  createPost: createPost,
@@ -32075,7 +33315,7 @@ const getStreams = (params, callback, config) => {
32075
33315
  };
32076
33316
  /* end_public_function */
32077
33317
 
32078
- var index$a = /*#__PURE__*/Object.freeze({
33318
+ var index$b = /*#__PURE__*/Object.freeze({
32079
33319
  __proto__: null,
32080
33320
  createStream: createStream,
32081
33321
  updateStream: updateStream,
@@ -32378,7 +33618,7 @@ const stopHeartbeat = (roomId) => {
32378
33618
  };
32379
33619
  /* end_public_function */
32380
33620
 
32381
- var index$9 = /*#__PURE__*/Object.freeze({
33621
+ var index$a = /*#__PURE__*/Object.freeze({
32382
33622
  __proto__: null,
32383
33623
  getRoomOnlineUsers: getRoomOnlineUsers,
32384
33624
  getRoomUserCount: getRoomUserCount,
@@ -32689,7 +33929,7 @@ const getPoll = (pollId, callback) => {
32689
33929
  };
32690
33930
  /* end_public_function */
32691
33931
 
32692
- var index$8 = /*#__PURE__*/Object.freeze({
33932
+ var index$9 = /*#__PURE__*/Object.freeze({
32693
33933
  __proto__: null,
32694
33934
  createPoll: createPoll,
32695
33935
  closePoll: closePoll,
@@ -32993,7 +34233,7 @@ const getPlayer = async (parameters) => {
32993
34233
  return video;
32994
34234
  };
32995
34235
 
32996
- var index$7 = /*#__PURE__*/Object.freeze({
34236
+ var index$8 = /*#__PURE__*/Object.freeze({
32997
34237
  __proto__: null,
32998
34238
  getPlayer: getPlayer
32999
34239
  });
@@ -34165,7 +35405,7 @@ const getGlobalStoryTargets = (params, callback, config) => {
34165
35405
  };
34166
35406
  };
34167
35407
 
34168
- var index$6 = /*#__PURE__*/Object.freeze({
35408
+ var index$7 = /*#__PURE__*/Object.freeze({
34169
35409
  __proto__: null,
34170
35410
  createImageStory: createImageStory,
34171
35411
  createVideoStory: createVideoStory,
@@ -34202,7 +35442,7 @@ const getNetworkAds = async () => {
34202
35442
  };
34203
35443
  };
34204
35444
 
34205
- var index$5 = /*#__PURE__*/Object.freeze({
35445
+ var index$6 = /*#__PURE__*/Object.freeze({
34206
35446
  __proto__: null,
34207
35447
  getNetworkAds: getNetworkAds
34208
35448
  });
@@ -34593,7 +35833,7 @@ const markTraySeen = async (lastSeenAt) => {
34593
35833
  };
34594
35834
  /* end_public_function */
34595
35835
 
34596
- var index$4 = /*#__PURE__*/Object.freeze({
35836
+ var index$5 = /*#__PURE__*/Object.freeze({
34597
35837
  __proto__: null,
34598
35838
  getNotificationTraySeen: getNotificationTraySeen,
34599
35839
  getNotificationTrayItems: getNotificationTrayItems,
@@ -34895,7 +36135,7 @@ const getInvitations = (params, callback) => {
34895
36135
  };
34896
36136
  };
34897
36137
 
34898
- var index$3 = /*#__PURE__*/Object.freeze({
36138
+ var index$4 = /*#__PURE__*/Object.freeze({
34899
36139
  __proto__: null,
34900
36140
  cancelInvitation: cancelInvitation,
34901
36141
  onLocalInvitationCreated: onLocalInvitationCreated,
@@ -35044,7 +36284,7 @@ const getReactions = (postId, callback) => {
35044
36284
  };
35045
36285
  };
35046
36286
 
35047
- var index$2 = /*#__PURE__*/Object.freeze({
36287
+ var index$3 = /*#__PURE__*/Object.freeze({
35048
36288
  __proto__: null,
35049
36289
  createReaction: createReaction,
35050
36290
  onLiveReactionCreated: onLiveReactionCreated,
@@ -35527,7 +36767,7 @@ const getMyEvents = (params, callback, config) => {
35527
36767
  };
35528
36768
  };
35529
36769
 
35530
- var index$1 = /*#__PURE__*/Object.freeze({
36770
+ var index$2 = /*#__PURE__*/Object.freeze({
35531
36771
  __proto__: null,
35532
36772
  createEvent: createEvent,
35533
36773
  updateEvent: updateEvent,
@@ -35754,12 +36994,36 @@ const searchProducts = (params, callback, config) => {
35754
36994
  };
35755
36995
  /* end_public_function */
35756
36996
 
35757
- var index = /*#__PURE__*/Object.freeze({
36997
+ var index$1 = /*#__PURE__*/Object.freeze({
35758
36998
  __proto__: null,
35759
36999
  getProduct: getProduct,
35760
37000
  searchProducts: searchProducts
35761
37001
  });
35762
37002
 
37003
+ const getPool = async (topicId, limit) => {
37004
+ const client = getActiveClient();
37005
+ if (!topicId)
37006
+ throw new ASCError('topicId must not be empty', 800110 /* Amity.ClientError.INVALID_PARAMETERS */, "error" /* Amity.ErrorLevel.ERROR */);
37007
+ if (limit !== undefined && (limit < 1 || limit > 100))
37008
+ throw new ASCError('limit must be between 1 and 100', 800110 /* Amity.ClientError.INVALID_PARAMETERS */, "error" /* Amity.ErrorLevel.ERROR */);
37009
+ const { data } = await client.http.get('/api/v5/curated-content/pool', { params: { topicId, limit } });
37010
+ const { topic } = data, payload = __rest(data, ["topic"]);
37011
+ const processedPayload = preparePostPayload(payload);
37012
+ const cachedAt = client.cache && Date.now();
37013
+ if (client.cache) {
37014
+ ingestInCache(processedPayload, { cachedAt });
37015
+ }
37016
+ return {
37017
+ topic: LinkedObject.curatedContentTopic(topic),
37018
+ posts: processedPayload.posts.map(LinkedObject.post),
37019
+ };
37020
+ };
37021
+
37022
+ var index = /*#__PURE__*/Object.freeze({
37023
+ __proto__: null,
37024
+ getPool: getPool
37025
+ });
37026
+
35763
37027
  /**
35764
37028
  * Helper class for managing product tags per media attachment.
35765
37029
  *
@@ -35808,39 +37072,40 @@ class AmityAttachmentProductTags {
35808
37072
  }
35809
37073
 
35810
37074
  exports.API_REGIONS = API_REGIONS;
35811
- exports.AdRepository = index$5;
37075
+ exports.AdRepository = index$6;
35812
37076
  exports.AmityAttachmentProductTags = AmityAttachmentProductTags;
35813
- exports.CategoryRepository = index$f;
35814
- exports.ChannelRepository = index$j;
35815
- exports.Client = index$s;
35816
- exports.CommentRepository = index$e;
37077
+ exports.CategoryRepository = index$g;
37078
+ exports.ChannelRepository = index$k;
37079
+ exports.Client = index$t;
37080
+ exports.CommentRepository = index$f;
35817
37081
  exports.CommunityPostSettingMaps = CommunityPostSettingMaps;
35818
37082
  exports.CommunityPostSettings = CommunityPostSettings;
35819
- exports.CommunityRepository = index$g;
37083
+ exports.CommunityRepository = index$h;
35820
37084
  exports.ContentFeedType = ContentFeedType;
37085
+ exports.CuratedContentRepository = index;
35821
37086
  exports.DefaultCommunityPostSetting = DefaultCommunityPostSetting;
35822
- exports.EventRepository = index$1;
35823
- exports.FeedRepository = index$d;
35824
- exports.FileRepository = index$p;
37087
+ exports.EventRepository = index$2;
37088
+ exports.FeedRepository = index$e;
37089
+ exports.FileRepository = index$q;
35825
37090
  exports.FileType = FileType;
35826
37091
  exports.GET_WATCHER_URLS = GET_WATCHER_URLS;
35827
- exports.InvitationRepository = index$3;
35828
- exports.LiveReactionRepository = index$2;
35829
- exports.LiveStreamPlayer = index$7;
37092
+ exports.InvitationRepository = index$4;
37093
+ exports.LiveReactionRepository = index$3;
37094
+ exports.LiveStreamPlayer = index$8;
35830
37095
  exports.MessageContentType = MessageContentType;
35831
- exports.MessageRepository = index$n;
35832
- exports.PollRepository = index$8;
37096
+ exports.MessageRepository = index$o;
37097
+ exports.PollRepository = index$9;
35833
37098
  exports.PostContentType = PostContentType;
35834
- exports.PostRepository = index$b;
37099
+ exports.PostRepository = index$c;
35835
37100
  exports.PostStructureType = PostStructureType;
35836
- exports.ProductRepository = index;
35837
- exports.ReactionRepository = index$o;
35838
- exports.RoomPresenceRepository = index$9;
35839
- exports.RoomRepository = index$c;
35840
- exports.StoryRepository = index$6;
35841
- exports.StreamRepository = index$a;
35842
- exports.SubChannelRepository = index$m;
35843
- exports.UserRepository = index$q;
37101
+ exports.ProductRepository = index$1;
37102
+ exports.ReactionRepository = index$p;
37103
+ exports.RoomPresenceRepository = index$a;
37104
+ exports.RoomRepository = index$d;
37105
+ exports.StoryRepository = index$7;
37106
+ exports.StreamRepository = index$b;
37107
+ exports.SubChannelRepository = index$n;
37108
+ exports.UserRepository = index$r;
35844
37109
  exports.VERSION = VERSION;
35845
37110
  exports.VideoResolution = VideoResolution;
35846
37111
  exports.VideoSize = VideoSize;
@@ -35902,7 +37167,7 @@ exports.isPaged = isPaged;
35902
37167
  exports.isReportedByMe = isReportedByMe;
35903
37168
  exports.isSkip = isSkip;
35904
37169
  exports.mergeInCache = mergeInCache;
35905
- exports.notificationTray = index$4;
37170
+ exports.notificationTray = index$5;
35906
37171
  exports.onChannelMarkerFetched = onChannelMarkerFetched;
35907
37172
  exports.onFeedMarkerFetched = onFeedMarkerFetched;
35908
37173
  exports.onFeedMarkerUpdated = onFeedMarkerUpdated;