@amityco/ts-sdk 0.0.1-beta.36 → 0.0.1-beta.38

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 (279) hide show
  1. package/.eslintrc.json +3 -5
  2. package/dist/@types/core/errors.d.ts +1 -0
  3. package/dist/@types/core/errors.d.ts.map +1 -1
  4. package/dist/@types/core/events.d.ts +5 -0
  5. package/dist/@types/core/events.d.ts.map +1 -1
  6. package/dist/@types/domains/category.d.ts +7 -0
  7. package/dist/@types/domains/category.d.ts.map +1 -1
  8. package/dist/@types/domains/client.d.ts +21 -1
  9. package/dist/@types/domains/client.d.ts.map +1 -1
  10. package/dist/@types/domains/community.d.ts +12 -0
  11. package/dist/@types/domains/community.d.ts.map +1 -1
  12. package/dist/@types/global.d.ts +12 -0
  13. package/dist/@types/global.d.ts.map +1 -1
  14. package/dist/category/api/queryCategories.d.ts +1 -5
  15. package/dist/category/api/queryCategories.d.ts.map +1 -1
  16. package/dist/category/observers/index.d.ts +2 -0
  17. package/dist/category/observers/index.d.ts.map +1 -0
  18. package/dist/category/observers/liveCategories.d.ts +18 -0
  19. package/dist/category/observers/liveCategories.d.ts.map +1 -0
  20. package/dist/category/observers/tests/liveCategories.test.d.ts +2 -0
  21. package/dist/category/observers/tests/liveCategories.test.d.ts.map +1 -0
  22. package/dist/channel/api/tests/getChannels.test.d.ts +2 -0
  23. package/dist/channel/api/tests/getChannels.test.d.ts.map +1 -0
  24. package/dist/channel/api/tests/leaveChannel.test.d.ts +2 -0
  25. package/dist/channel/api/tests/leaveChannel.test.d.ts.map +1 -0
  26. package/dist/channel/observers/liveChannel.d.ts.map +1 -1
  27. package/dist/client/api/accessTokenExpiryWatcher.d.ts +7 -0
  28. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -0
  29. package/dist/client/api/activeUser.d.ts +1 -1
  30. package/dist/client/api/activeUser.d.ts.map +1 -1
  31. package/dist/client/api/connectClient.d.ts +1 -1
  32. package/dist/client/api/connectClient.d.ts.map +1 -1
  33. package/dist/client/api/createClient.d.ts +1 -1
  34. package/dist/client/api/createClient.d.ts.map +1 -1
  35. package/dist/client/api/disconnectClient.d.ts +0 -1
  36. package/dist/client/api/disconnectClient.d.ts.map +1 -1
  37. package/dist/client/api/getToken.d.ts +7 -5
  38. package/dist/client/api/getToken.d.ts.map +1 -1
  39. package/dist/client/api/index.d.ts +1 -0
  40. package/dist/client/api/index.d.ts.map +1 -1
  41. package/dist/client/api/renewal.d.ts +2 -0
  42. package/dist/client/api/renewal.d.ts.map +1 -0
  43. package/dist/client/api/setSessionState.d.ts +12 -0
  44. package/dist/client/api/setSessionState.d.ts.map +1 -0
  45. package/dist/client/api/terminateClient.d.ts +9 -0
  46. package/dist/client/api/terminateClient.d.ts.map +1 -0
  47. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts +2 -0
  48. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts.map +1 -0
  49. package/dist/client/api/tests/connectClient.test.d.ts +2 -0
  50. package/dist/client/api/tests/connectClient.test.d.ts.map +1 -0
  51. package/dist/client/api/tests/disconnectClient.test.d.ts +2 -0
  52. package/dist/client/api/tests/disconnectClient.test.d.ts.map +1 -0
  53. package/dist/client/api/tests/getToken.test.d.ts +2 -0
  54. package/dist/client/api/tests/getToken.test.d.ts.map +1 -0
  55. package/dist/client/api/tests/renewal.test.d.ts +2 -0
  56. package/dist/client/api/tests/renewal.test.d.ts.map +1 -0
  57. package/dist/client/api/tests/setSessionState.test.d.ts +2 -0
  58. package/dist/client/api/tests/setSessionState.test.d.ts.map +1 -0
  59. package/dist/client/api/tests/terminateClient.test.d.ts +2 -0
  60. package/dist/client/api/tests/terminateClient.test.d.ts.map +1 -0
  61. package/dist/client/events/index.d.ts +1 -0
  62. package/dist/client/events/index.d.ts.map +1 -1
  63. package/dist/client/events/onClientBanned.d.ts +1 -1
  64. package/dist/client/events/onClientBanned.d.ts.map +1 -1
  65. package/dist/client/events/onSessionStateChange.d.ts +17 -0
  66. package/dist/client/events/onSessionStateChange.d.ts.map +1 -0
  67. package/dist/client/events/onTokenExpired.d.ts +17 -0
  68. package/dist/client/events/onTokenExpired.d.ts.map +1 -0
  69. package/dist/client/events/onTokenTerminated.d.ts +11 -0
  70. package/dist/client/events/onTokenTerminated.d.ts.map +1 -0
  71. package/dist/client/events/tests/onSessionStateChange.test.d.ts +2 -0
  72. package/dist/client/events/tests/onSessionStateChange.test.d.ts.map +1 -0
  73. package/dist/client/events/tests/onTokenTerminated.test.d.ts +2 -0
  74. package/dist/client/events/tests/onTokenTerminated.test.d.ts.map +1 -0
  75. package/dist/client/utils/setClientToken.d.ts +19 -0
  76. package/dist/client/utils/setClientToken.d.ts.map +1 -0
  77. package/dist/comment/api/deleteComment.d.ts.map +1 -1
  78. package/dist/comment/api/getComment.d.ts.map +1 -1
  79. package/dist/comment/events/tests/onCommentDeleted.test.d.ts +2 -0
  80. package/dist/comment/events/tests/onCommentDeleted.test.d.ts.map +1 -0
  81. package/dist/comment/observers/index.d.ts +1 -0
  82. package/dist/comment/observers/index.d.ts.map +1 -1
  83. package/dist/comment/observers/liveComment.d.ts +21 -0
  84. package/dist/comment/observers/liveComment.d.ts.map +1 -0
  85. package/dist/comment/observers/tests/liveComment.test.d.ts +2 -0
  86. package/dist/comment/observers/tests/liveComment.test.d.ts.map +1 -0
  87. package/dist/community/api/queryCommunities.d.ts +1 -10
  88. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  89. package/dist/community/events/index.d.ts +1 -0
  90. package/dist/community/events/index.d.ts.map +1 -1
  91. package/dist/community/events/onCommunityUserChanged.d.ts +17 -0
  92. package/dist/community/events/onCommunityUserChanged.d.ts.map +1 -0
  93. package/dist/community/events/utils.d.ts +1 -0
  94. package/dist/community/events/utils.d.ts.map +1 -1
  95. package/dist/community/observers/index.d.ts +1 -0
  96. package/dist/community/observers/index.d.ts.map +1 -1
  97. package/dist/community/observers/liveCommunities.d.ts +20 -0
  98. package/dist/community/observers/liveCommunities.d.ts.map +1 -0
  99. package/dist/community/observers/tests/liveCommunities.test.d.ts +2 -0
  100. package/dist/community/observers/tests/liveCommunities.test.d.ts.map +1 -0
  101. package/dist/core/events.d.ts +3 -3
  102. package/dist/core/events.d.ts.map +1 -1
  103. package/dist/core/query/sorting.d.ts +6 -0
  104. package/dist/core/query/sorting.d.ts.map +1 -1
  105. package/dist/core/subscription.d.ts.map +1 -1
  106. package/dist/core/transports/http.d.ts +0 -5
  107. package/dist/core/transports/http.d.ts.map +1 -1
  108. package/dist/file/api/test/createImage.test.d.ts +2 -0
  109. package/dist/file/api/test/createImage.test.d.ts.map +1 -0
  110. package/dist/file/api/test/createVideo.test.d.ts +2 -0
  111. package/dist/file/api/test/createVideo.test.d.ts.map +1 -0
  112. package/dist/index.cjs.js +944 -332
  113. package/dist/index.d.ts +1 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.esm.js +937 -332
  116. package/dist/index.umd.js +4 -4
  117. package/dist/message/observers/liveMessage.d.ts.map +1 -1
  118. package/dist/post/observers/index.d.ts +1 -0
  119. package/dist/post/observers/index.d.ts.map +1 -1
  120. package/dist/post/observers/livePost.d.ts +21 -0
  121. package/dist/post/observers/livePost.d.ts.map +1 -0
  122. package/dist/post/observers/tests/livePost.test.d.ts +2 -0
  123. package/dist/post/observers/tests/livePost.test.d.ts.map +1 -0
  124. package/dist/stream/api/tests/createStream.test.d.ts +2 -0
  125. package/dist/stream/api/tests/createStream.test.d.ts.map +1 -0
  126. package/dist/stream/api/tests/deleteStream.test.d.ts +2 -0
  127. package/dist/stream/api/tests/deleteStream.test.d.ts.map +1 -0
  128. package/dist/stream/api/tests/getStream.test.d.ts +2 -0
  129. package/dist/stream/api/tests/getStream.test.d.ts.map +1 -0
  130. package/dist/subChannel/api/tests/createSubChannel.test.d.ts +2 -0
  131. package/dist/subChannel/api/tests/createSubChannel.test.d.ts.map +1 -0
  132. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts +2 -0
  133. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts.map +1 -0
  134. package/dist/subChannel/api/tests/getSubChannel.test.d.ts +2 -0
  135. package/dist/subChannel/api/tests/getSubChannel.test.d.ts.map +1 -0
  136. package/dist/subChannel/api/tests/getSubChannels.test.d.ts +2 -0
  137. package/dist/subChannel/api/tests/getSubChannels.test.d.ts.map +1 -0
  138. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts +2 -0
  139. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts.map +1 -0
  140. package/dist/subChannel/observers/liveSubChannel.d.ts.map +1 -1
  141. package/dist/user/api/tests/updateUser.test.d.ts +2 -0
  142. package/dist/user/api/tests/updateUser.test.d.ts.map +1 -0
  143. package/dist/user/observers/liveUser.d.ts.map +1 -1
  144. package/dist/utils/constants.d.ts +2 -0
  145. package/dist/utils/constants.d.ts.map +1 -1
  146. package/dist/utils/liveObject.d.ts +2 -0
  147. package/dist/utils/liveObject.d.ts.map +1 -0
  148. package/dist/utils/tests/client.d.ts.map +1 -1
  149. package/dist/utils/tests/dummy/category.d.ts +64 -0
  150. package/dist/utils/tests/dummy/category.d.ts.map +1 -0
  151. package/dist/utils/tests/dummy/channel.d.ts +50 -0
  152. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  153. package/dist/utils/tests/dummy/community.d.ts +132 -0
  154. package/dist/utils/tests/dummy/community.d.ts.map +1 -1
  155. package/dist/utils/tests/dummy/file.d.ts +3 -0
  156. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  157. package/dist/utils/tests/dummy/index.d.ts +3 -0
  158. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  159. package/dist/utils/tests/dummy/post.d.ts +2 -0
  160. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  161. package/dist/utils/tests/dummy/stream.d.ts +83 -0
  162. package/dist/utils/tests/dummy/stream.d.ts.map +1 -0
  163. package/dist/utils/tests/dummy/token.d.ts +11 -0
  164. package/dist/utils/tests/dummy/token.d.ts.map +1 -0
  165. package/dist/utils/tests/dummy/user.d.ts +18 -0
  166. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  167. package/dist/utils/tests/liveObject.test.d.ts +2 -0
  168. package/dist/utils/tests/liveObject.test.d.ts.map +1 -0
  169. package/package.json +4 -4
  170. package/src/@types/core/errors.ts +1 -0
  171. package/src/@types/core/events.ts +7 -0
  172. package/src/@types/domains/category.ts +13 -0
  173. package/src/@types/domains/client.ts +45 -1
  174. package/src/@types/domains/community.ts +25 -0
  175. package/src/@types/global.ts +19 -0
  176. package/src/category/api/queryCategories.ts +3 -5
  177. package/src/category/observers/index.ts +1 -0
  178. package/src/category/observers/liveCategories.ts +141 -0
  179. package/src/category/observers/tests/liveCategories.test.ts +147 -0
  180. package/src/channel/api/tests/createChannel.test.ts +30 -6
  181. package/src/channel/api/tests/getChannel.test.ts +3 -1
  182. package/src/channel/api/tests/getChannels.test.ts +97 -0
  183. package/src/channel/api/tests/joinChannel.test.ts +62 -3
  184. package/src/channel/api/tests/leaveChannel.test.ts +90 -0
  185. package/src/channel/api/tests/queryChannels.test.ts +38 -1
  186. package/src/channel/observers/liveChannel.ts +8 -80
  187. package/src/client/api/accessTokenExpiryWatcher.ts +85 -0
  188. package/src/client/api/activeUser.ts +1 -1
  189. package/src/client/api/connectClient.ts +105 -24
  190. package/src/client/api/createClient.ts +9 -1
  191. package/src/client/api/disconnectClient.ts +26 -2
  192. package/src/client/api/getToken.ts +6 -6
  193. package/src/client/api/index.ts +2 -0
  194. package/src/client/api/renewal.ts +74 -0
  195. package/src/client/api/setSessionState.ts +75 -0
  196. package/src/client/api/terminateClient.ts +20 -0
  197. package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +132 -0
  198. package/src/client/api/tests/connectClient.test.ts +84 -0
  199. package/src/client/api/tests/createClient.test.ts +8 -0
  200. package/src/client/api/tests/disconnectClient.test.ts +78 -0
  201. package/src/client/api/tests/getToken.test.ts +36 -0
  202. package/src/client/api/tests/renewal.test.ts +67 -0
  203. package/src/client/api/tests/setSessionState.test.ts +62 -0
  204. package/src/client/api/tests/terminateClient.test.ts +29 -0
  205. package/src/client/events/index.ts +2 -0
  206. package/src/client/events/onClientBanned.ts +12 -5
  207. package/src/client/events/onSessionStateChange.ts +31 -0
  208. package/src/client/events/onTokenExpired.ts +26 -0
  209. package/src/client/events/onTokenTerminated.ts +20 -0
  210. package/src/client/events/tests/onSessionStateChange.test.ts +37 -0
  211. package/src/client/events/tests/onTokenTerminated.test.ts +37 -0
  212. package/src/client/tests/connectClient.test.ts +6 -1
  213. package/src/client/utils/setClientToken.ts +39 -0
  214. package/src/comment/api/deleteComment.ts +5 -5
  215. package/src/comment/api/getComment.ts +8 -3
  216. package/src/comment/events/tests/onCommentDeleted.test.ts +27 -0
  217. package/src/comment/observers/index.ts +1 -0
  218. package/src/comment/observers/liveComment.ts +43 -0
  219. package/src/comment/observers/tests/liveComment.test.ts +95 -0
  220. package/src/community/api/queryCommunities.ts +3 -10
  221. package/src/community/api/test/addCommunityMember.test.ts +14 -2
  222. package/src/community/api/test/joinCommunity.test.ts +14 -2
  223. package/src/community/api/test/leaveCommunity.test.ts +11 -1
  224. package/src/community/api/test/removeCommunityMembers.test.ts +11 -1
  225. package/src/community/events/index.ts +1 -0
  226. package/src/community/events/onCommunityUserChanged.ts +20 -0
  227. package/src/community/events/test/onCommunityJoined.test.ts +1 -1
  228. package/src/community/events/test/onCommunityUserAdded.test.ts +1 -1
  229. package/src/community/events/test/onCommunityUserBanned.test.ts +1 -1
  230. package/src/community/events/test/onCommunityUserUnbaned.test.ts +1 -1
  231. package/src/community/events/test/utils.test.ts +52 -3
  232. package/src/community/events/utils.ts +49 -0
  233. package/src/community/observers/index.ts +1 -0
  234. package/src/community/observers/liveCommunities.ts +188 -0
  235. package/src/community/observers/tests/liveCommunities.test.ts +284 -0
  236. package/src/core/events.ts +5 -3
  237. package/src/core/query/sorting.ts +8 -0
  238. package/src/core/subscription.ts +3 -1
  239. package/src/core/transports/http.ts +52 -13
  240. package/src/core/transports/mqtt.ts +1 -1
  241. package/src/core/transports/test/http.test.ts +49 -60
  242. package/src/external/api/createUserToken.ts +2 -2
  243. package/src/file/api/createFile.ts +1 -1
  244. package/src/file/api/createImage.ts +1 -1
  245. package/src/file/api/createVideo.ts +1 -1
  246. package/src/file/api/test/createImage.test.ts +69 -0
  247. package/src/file/api/test/createVideo.test.ts +81 -0
  248. package/src/index.ts +1 -0
  249. package/src/message/observers/liveMessage.ts +11 -83
  250. package/src/message/tests/observers/liveMessage.test.ts +1 -143
  251. package/src/post/observers/index.ts +1 -0
  252. package/src/post/observers/livePost.ts +47 -0
  253. package/src/post/observers/tests/livePost.test.ts +97 -0
  254. package/src/stream/api/tests/createStream.test.ts +22 -0
  255. package/src/stream/api/tests/deleteStream.test.ts +50 -0
  256. package/src/stream/api/tests/getStream.test.ts +23 -0
  257. package/src/subChannel/api/tests/createSubChannel.test.ts +110 -0
  258. package/src/subChannel/api/tests/deleteSubChannel.test.ts +112 -0
  259. package/src/subChannel/api/tests/getSubChannel.test.ts +97 -0
  260. package/src/subChannel/api/tests/getSubChannels.test.ts +97 -0
  261. package/src/subChannel/api/tests/updateSubChannel.test.ts +86 -0
  262. package/src/subChannel/observers/liveSubChannel.ts +6 -56
  263. package/src/subChannel/observers/tests/liveSubChannel.test.ts +0 -82
  264. package/src/user/api/tests/updateUser.test.ts +60 -0
  265. package/src/user/observers/liveUser.ts +9 -61
  266. package/src/user/tests/observers/liveUser.test.ts +1 -154
  267. package/src/utils/constants.ts +2 -0
  268. package/src/utils/liveObject.ts +86 -0
  269. package/src/utils/tests/client.ts +18 -2
  270. package/src/utils/tests/dummy/category.ts +57 -0
  271. package/src/utils/tests/dummy/channel.ts +51 -1
  272. package/src/utils/tests/dummy/community.ts +94 -0
  273. package/src/utils/tests/dummy/file.ts +32 -0
  274. package/src/utils/tests/dummy/index.ts +4 -0
  275. package/src/utils/tests/dummy/post.ts +56 -45
  276. package/src/utils/tests/dummy/stream.ts +86 -0
  277. package/src/utils/tests/dummy/token.ts +12 -0
  278. package/src/utils/tests/dummy/user.ts +21 -0
  279. package/src/utils/tests/liveObject.test.ts +172 -0
package/dist/index.cjs.js CHANGED
@@ -7,7 +7,6 @@ var AsyncStorage = require('@react-native-async-storage/async-storage');
7
7
  var mitt = require('mitt');
8
8
  var debug = require('debug');
9
9
  var axios = require('axios');
10
- var qs = require('qs');
11
10
  var HttpAgent = require('agentkeepalive');
12
11
  var io = require('socket.io-client');
13
12
  var nativeIdGenerator = require('react-native-uuid');
@@ -18,7 +17,6 @@ var AsyncStorage__default = /*#__PURE__*/_interopDefaultLegacy(AsyncStorage);
18
17
  var mitt__default = /*#__PURE__*/_interopDefaultLegacy(mitt);
19
18
  var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
20
19
  var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
21
- var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
22
20
  var HttpAgent__default = /*#__PURE__*/_interopDefaultLegacy(HttpAgent);
23
21
  var io__default = /*#__PURE__*/_interopDefaultLegacy(io);
24
22
  var nativeIdGenerator__default = /*#__PURE__*/_interopDefaultLegacy(nativeIdGenerator);
@@ -1094,6 +1092,14 @@ const sortByDisplayName = ({ displayName: a }, { displayName: b }) => {
1094
1092
  return 0;
1095
1093
  return a < b ? -1 : 1;
1096
1094
  };
1095
+ /**
1096
+ * Alphabetic sorting of objects having a name
1097
+ */
1098
+ const sortByName = ({ name: a }, { name: b }) => {
1099
+ if (a === b)
1100
+ return 0;
1101
+ return a < b ? -1 : 1;
1102
+ };
1097
1103
  /**
1098
1104
  * Sorting a collection by their apparition order (oldest first)
1099
1105
  */
@@ -1140,6 +1146,9 @@ const WS_EVENTS = [
1140
1146
  'connect_error',
1141
1147
  'reconnect_error',
1142
1148
  'reconnect_failed',
1149
+ 'sessionStateChange',
1150
+ // for internal use by accessTokenExpiryWatcher
1151
+ 'tokenExpired',
1143
1152
  ];
1144
1153
  const MQTT_EVENTS = [
1145
1154
  'connect',
@@ -1149,6 +1158,7 @@ const MQTT_EVENTS = [
1149
1158
  'close',
1150
1159
  'end',
1151
1160
  'reconnect',
1161
+ 'user.didGlobalBan',
1152
1162
  ];
1153
1163
  /** @hidden */
1154
1164
  const createEventEmitter = () => {
@@ -1167,7 +1177,6 @@ const createEventEmitter = () => {
1167
1177
  const proxyWebsocketEvents = (ws, emitter) => {
1168
1178
  WS_EVENTS.forEach(event => {
1169
1179
  ws.on(event, (param) => {
1170
- console.log('ws', event, param);
1171
1180
  emitter.emit(event, param);
1172
1181
  });
1173
1182
  });
@@ -1175,14 +1184,12 @@ const proxyWebsocketEvents = (ws, emitter) => {
1175
1184
  const proxyMqttEvents = (mqttClient, emitter) => {
1176
1185
  MQTT_EVENTS.forEach(event => {
1177
1186
  mqttClient.on(event, (...params) => {
1178
- console.log('mqtt', event, params);
1179
1187
  emitter.emit(event, params.length === 1 ? params[0] : params);
1180
1188
  });
1181
1189
  });
1182
1190
  // @ts-ignore
1183
1191
  mqttClient.on('message', (topic, payload) => {
1184
1192
  const message = JSON.parse(payload.toString());
1185
- console.log('mqtt message', message);
1186
1193
  emitter.emit(message.eventType, message.data);
1187
1194
  });
1188
1195
  };
@@ -1325,7 +1332,9 @@ const getSmartFeedMessageTopic = () => {
1325
1332
  let mqttAccessToken;
1326
1333
  let mqttUserId;
1327
1334
  function subscribeTopic(topic, callback) {
1328
- const { mqtt, emitter, accessToken } = getActiveClient();
1335
+ var _a;
1336
+ const { mqtt, emitter, token } = getActiveClient();
1337
+ const accessToken = (_a = token === null || token === void 0 ? void 0 : token.accessToken) !== null && _a !== void 0 ? _a : '';
1329
1338
  const user = getActiveUser();
1330
1339
  if (mqttAccessToken !== accessToken || mqttUserId !== user._id) {
1331
1340
  mqttAccessToken = accessToken;
@@ -1394,13 +1403,6 @@ const unwrapPayload = (response) => {
1394
1403
  return undefined;
1395
1404
  };
1396
1405
 
1397
- /**
1398
- * Axios param serializer (for querystring)
1399
- * @hidden
1400
- */
1401
- const stringify = (params) => {
1402
- return qs__default["default"].stringify(params, { arrayFormat: 'brackets' });
1403
- };
1404
1406
  /**
1405
1407
  * Creates a pre-configured axios instance
1406
1408
  *
@@ -1421,15 +1423,47 @@ const createHttpTransport = (endpoint) => {
1421
1423
  baseURL: endpoint,
1422
1424
  httpAgent: new HttpAgent__default["default"](options),
1423
1425
  httpsAgent: new HttpAgent.HttpsAgent(options),
1424
- paramsSerializer: stringify,
1426
+ /*
1427
+ * If paramSerializer is required, use the serialize option to stringify
1428
+ * params. The encode option will pass complex params as string only whereas
1429
+ * the serialize option will pass params in the format Record<string, any>
1430
+ *
1431
+ * For more details:
1432
+ * https://github.com/axios/axios#request-config
1433
+ */
1425
1434
  });
1426
- instance.interceptors.response.use(response => response, error => {
1435
+ instance.interceptors.request.use(config => {
1427
1436
  var _a;
1437
+ // check global.ts for the extension of AxiosRequestConfig
1438
+ const tokenExpiry = (_a = config.metadata) === null || _a === void 0 ? void 0 : _a.tokenExpiry;
1439
+ if (tokenExpiry) {
1440
+ if (Date.now() >= Date.parse(tokenExpiry)) {
1441
+ return Object.assign(Object.assign({}, config), { cancelToken: new axios__default["default"].CancelToken(cancel => cancel('Token Expired')) });
1442
+ }
1443
+ }
1444
+ return config;
1445
+ });
1446
+ instance.interceptors.response.use(response => response, error => {
1447
+ var _a, _b;
1428
1448
  const { response } = error;
1429
- // eslint-disable-next-line no-console
1430
- console.error((_a = response === null || response === void 0 ? void 0 : response.data) !== null && _a !== void 0 ? _a : error);
1431
- if (response)
1432
- unwrapPayload(response.data);
1449
+ // handle unauthorized request
1450
+ if (response.data.code === 400100 /* Amity.ServerError.UNAUTHORIZED */) {
1451
+ fireEvent('tokenTerminated', "terminated" /* Amity.SessionStates.TERMINATED */);
1452
+ }
1453
+ // handle request cancellation
1454
+ if (axios__default["default"].isCancel(error)) {
1455
+ fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
1456
+ throw new ASCError('Token expired', 800403 /* Amity.ClientError.TOKEN_EXPIRED */, "fatal" /* Amity.ErrorLevel.FATAL */);
1457
+ }
1458
+ // if it's an error with status in the response payload,
1459
+ // then it's an expected error.
1460
+ if ((_a = response === null || response === void 0 ? void 0 : response.data) === null || _a === void 0 ? void 0 : _a.status) {
1461
+ unwrapPayload(response === null || response === void 0 ? void 0 : response.data);
1462
+ }
1463
+ // unexpected error.
1464
+ else {
1465
+ throw new Error((_b = response === null || response === void 0 ? void 0 : response.data) !== null && _b !== void 0 ? _b : error);
1466
+ }
1433
1467
  });
1434
1468
  return instance;
1435
1469
  };
@@ -20163,7 +20197,7 @@ var MqttError;
20163
20197
  MqttError[MqttError["NOT_AUTHORIZED"] = 5] = "NOT_AUTHORIZED";
20164
20198
  })(MqttError || (MqttError = {}));
20165
20199
  function getMqttOptions(params) {
20166
- return Object.assign({ clean: false, clientId: `mqttjs_ + ${Math.random().toString(16).substr(2, 8)}`, protocolId: 'MQTT', protocolVersion: 4, reconnectPeriod: 0, will: {
20200
+ return Object.assign({ clean: false, clientId: `mqttjs_ + ${Math.random().toString(16).substring(2, 10)}`, protocolId: 'MQTT', protocolVersion: 4, reconnectPeriod: 0, will: {
20167
20201
  topic: 'WillMsg',
20168
20202
  payload: 'Connection Closed abnormally..!',
20169
20203
  qos: 0,
@@ -20294,54 +20328,153 @@ const getFeedSettings = async () => {
20294
20328
  }));
20295
20329
  };
20296
20330
 
20297
- const DEFAULT_DEBUG_SESSION = 'amity';
20331
+ const COLLECTION_DEFAULT_PAGINATION_LIMIT = 5;
20332
+ const COLLECTION_DEFAULT_CACHING_POLICY = 'cache_then_server';
20333
+ const ENABLE_CACHE_MESSAGE = 'For using Live Collection feature you need to enable Cache!';
20334
+ const LIVE_OBJECT_ENABLE_CACHE_MESSAGE = 'For using Live Object feature you need to enable Cache!';
20335
+ const UNSYNCED_OBJECT_CACHED_AT_MESSAGE = 'Observing unsynced object is not supported by Live Object.';
20336
+ const UNSYNCED_OBJECT_CACHED_AT_VALUE = -5;
20337
+ const MINUTE = 60 * 1000;
20338
+ const ACCESS_TOKEN_WATCHER_INTERVAL = 10 * MINUTE;
20339
+
20340
+ // TODO: find a way to uniquely identify the device
20341
+ /** @hidden */
20342
+ const VERSION = '11.0.0';
20343
+ /** @hidden */
20344
+ const getDeviceId = () => {
20345
+ // here maybe put some auto detection of the device id based on if it's react or not?
20346
+ // anyhow we let consumer branch out if they want, but it doesn't mean we shouldn't try to be nice
20347
+ // and do things automatically
20348
+ // https://www.npmjs.com/package/react-native-device-info#getuniqueid
20349
+ // how to make sure that the react native package will not be included when build is for web
20350
+ return `ascWebSdk#${Math.random().toString(16)}`;
20351
+ };
20352
+ /** @hidden */
20353
+ const getDeviceModel = () => {
20354
+ var _a, _b;
20355
+ if ((_a = safeProcess.versions) === null || _a === void 0 ? void 0 : _a.node)
20356
+ return safeProcess.versions.node;
20357
+ if (navigator)
20358
+ return `${navigator.product.toLowerCase()}#${(_b = navigator.userAgent) !== null && _b !== void 0 ? _b : 'unknown_agent'}`;
20359
+ return 'unknown_model';
20360
+ };
20361
+ /** @hidden */
20362
+ const getDeviceInfo = () => {
20363
+ const model = getDeviceModel();
20364
+ return {
20365
+ version: VERSION,
20366
+ // TODO: replace with: kind: process.versions ? 'node' : 'web', when backend has fixed this
20367
+ kind: 'web',
20368
+ model,
20369
+ };
20370
+ };
20371
+
20372
+ /*
20373
+ * Session States cannot be set arbitarily.
20374
+ * These are the possible new states based on the current state
20375
+ * Check tech spec for details:
20376
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-State
20377
+ */
20378
+ const sessisonStateTransitions = {
20379
+ // notLoggedIn -> establishing
20380
+ ["notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */]: ["establishing" /* Amity.SessionStates.ESTABLISHING */],
20381
+ // terminated -> establishing
20382
+ ["terminated" /* Amity.SessionStates.TERMINATED */]: ["establishing" /* Amity.SessionStates.ESTABLISHING */],
20383
+ // establishing -> notLoggedIn, established
20384
+ ["establishing" /* Amity.SessionStates.ESTABLISHING */]: [
20385
+ "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */,
20386
+ "established" /* Amity.SessionStates.ESTABLISHED */,
20387
+ ],
20388
+ /*
20389
+ * established -> notLoggedIn, terminated, tokenExpired, establishing (for
20390
+ * cases when logging in same user)
20391
+ */
20392
+ ["established" /* Amity.SessionStates.ESTABLISHED */]: [
20393
+ "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */,
20394
+ "terminated" /* Amity.SessionStates.TERMINATED */,
20395
+ "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */,
20396
+ "establishing" /* Amity.SessionStates.ESTABLISHING */,
20397
+ ],
20398
+ // tokenExpired -> establishing
20399
+ ["tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */]: ["establishing" /* Amity.SessionStates.ESTABLISHING */],
20400
+ };
20401
+ const isValidStateChange = (prevState, nextState) => {
20402
+ return sessisonStateTransitions[prevState].includes(nextState);
20403
+ };
20298
20404
  /**
20299
- * ```js
20300
- * import { createClient } from '@amityco/ts-sdk'
20301
- * const client = createClient(apiKey, 'https://asc.server/', 'myClient')
20302
- * ```
20405
+ * Checks if a {@link Amity.Client} instance is connected to ASC servers
20303
20406
  *
20304
- * Creates a new {@link Amity.Client} instance
20305
20407
  *
20306
- * @param apiKey for the {@link Amity.Client} instance
20307
- * @param apiRegion endpoint to connect to
20308
- * @param apiEndpoint custom endpoint in case you don't want to use a preset endpoint
20309
- * @param debugSession session's identifier for the client's logger instance
20310
- * @returns A {@link Amity.Client} instance
20408
+ * @param state the new session state
20409
+ * @returns a success boolean if connected
20410
+ *
20411
+ * @category private
20412
+ */
20413
+ const setSessionState = (state) => {
20414
+ const client = getActiveClient();
20415
+ client.log('client/api/setSessionState', state);
20416
+ const { sessionState: prevState } = client;
20417
+ if (prevState === state)
20418
+ return false;
20419
+ // check if transition is valid
20420
+ if (!isValidStateChange(prevState, state)) {
20421
+ throw new ASCError(`Session state cannot change from ${prevState} to ${state}`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
20422
+ }
20423
+ client.sessionState = state;
20424
+ fireEvent('sessionStateChange', state);
20425
+ return true;
20426
+ };
20427
+
20428
+ /**
20429
+ * Retrieves a pair of {@link Amity.Tokens} necessary for connection
20430
+ *
20431
+ * @param params.userId The userId to use to issue a token
20432
+ * @param params.displayName The user's displayName
20433
+ * @param params.deviceId The user's device Id (can be manually set for native users)
20434
+ * @param params.authToken The authentication token - necessary when network option is set to secure
20435
+ * @return The accessToken for the given userId
20311
20436
  *
20312
20437
  * @category Client API
20313
- * */
20314
- const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, } = {}) => {
20315
- var _a, _b;
20316
- const log = createLogger(debugSession);
20317
- log('client/api/createClient', {
20318
- apiKey: apiKey.replace(/.{5}$/g, 'xxxxx'),
20319
- apiRegion,
20438
+ * @hidden
20439
+ */
20440
+ const getToken = async (params) => {
20441
+ const client = getActiveClient();
20442
+ client.log('client/api/getToken', params);
20443
+ const deviceInfo = getDeviceInfo();
20444
+ const { data } = await client.http.post('/api/v3/sessions', Object.assign(Object.assign({}, params), { deviceInfo }), {
20445
+ // @ts-ignore
20446
+ headers: { 'X-API-Key': client.apiKey },
20320
20447
  });
20321
- const httpEndpoint = (_a = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.http) !== null && _a !== void 0 ? _a : computeUrl('http', apiRegion);
20322
- const mqttEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _b !== void 0 ? _b : computeUrl('mqtt', apiRegion);
20323
- const http = createHttpTransport(httpEndpoint);
20324
- const ws = createWebsocketTransport(httpEndpoint);
20325
- const mqtt = createMqttTransport(mqttEndpoint);
20326
- const emitter = createEventEmitter();
20327
- const client = {
20328
- version: `${VERSION$1}`,
20329
- apiKey,
20330
- log,
20331
- http,
20332
- ws,
20333
- mqtt,
20334
- emitter,
20335
- use: () => setActiveClient(client),
20336
- getFeedSettings,
20337
- };
20338
- try {
20339
- return getActiveClient();
20340
- }
20341
- catch (_c) {
20342
- setActiveClient(client);
20343
- }
20344
- return client;
20448
+ return data;
20449
+ };
20450
+
20451
+ /**
20452
+ * A util to set or refresh client token
20453
+ *
20454
+ * @param params.userId the user ID for the current session
20455
+ * @param params.displayName the user's displayName for the current session
20456
+ * @param params.deviceId Manual override of the user's device id (for device management)
20457
+ * @param params.authToken The authentication token - necessary when network option is set to secure
20458
+ * @returns token & user info
20459
+ *
20460
+ * @category private
20461
+ * @async
20462
+ */
20463
+ const setClientToken = async (params) => {
20464
+ const client = getActiveClient();
20465
+ // begin establishing session
20466
+ setSessionState("establishing" /* Amity.SessionStates.ESTABLISHING */);
20467
+ // @ts-ignore: in that particular case, typing can be
20468
+ // ignored since we enforce default values just before.
20469
+ const { accessToken, users, expiresAt, issuedAt, refreshToken } = await getToken(params);
20470
+ // manually setup the token for http transport
20471
+ client.http.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
20472
+ client.http.defaults.metadata = { tokenExpiry: expiresAt };
20473
+ // manually setup the token for ws transport
20474
+ client.ws.io.opts.query = { token: accessToken };
20475
+ client.token = { accessToken, issuedAt, expiresAt };
20476
+ setSessionState("established" /* Amity.SessionStates.ESTABLISHED */);
20477
+ return { accessToken, users, refreshToken };
20345
20478
  };
20346
20479
 
20347
20480
  /**
@@ -20352,7 +20485,6 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
20352
20485
  *
20353
20486
  * Disconnects an {@link Amity.Client} instance from ASC servers
20354
20487
  *
20355
- * @param client The {@link Amity.Client} instance to disconnect
20356
20488
  * @returns a success boolean if disconnected
20357
20489
  *
20358
20490
  * @category Client API
@@ -20371,42 +20503,30 @@ const disconnectClient = async () => {
20371
20503
  client.ws.removeAllListeners();
20372
20504
  client.mqtt.removeAllListeners();
20373
20505
  client.userId = undefined;
20374
- client.accessToken = undefined;
20506
+ client.token = undefined;
20507
+ client.http.defaults.headers.common.Authorization = '';
20508
+ client.ws.io.opts.query = { token: '' };
20509
+ /*
20510
+ * for cases when session state is terminated (example on ban) or token expired,
20511
+ * the terminating block will set session state to terminated or for the or
20512
+ * in the case of expired token the same happens
20513
+ *
20514
+ * establishing state also ignored in cases where accessTokenExpiryWatcher
20515
+ * calls renewal. There is a possibility that renewal will be called before
20516
+ * disconnectClient finishes execution
20517
+ */
20518
+ if (client.sessionState === "established" /* Amity.SessionStates.ESTABLISHED */)
20519
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
20520
+ /*
20521
+ * Cache should be usable if tokenExpired
20522
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#SDK-usability-based-on-Session-State
20523
+ */
20524
+ if (client.sessionState !== "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.cache) {
20525
+ client.cache = { data: {} };
20526
+ }
20375
20527
  return !client.ws.connected;
20376
20528
  };
20377
20529
 
20378
- // TODO: find a way to uniquely identify the device
20379
- /** @hidden */
20380
- const VERSION = '11.0.0';
20381
- /** @hidden */
20382
- const getDeviceId = () => {
20383
- // here maybe put some auto detection of the device id based on if it's react or not?
20384
- // anyhow we let consumer branch out if they want, but it doesn't mean we shouldn't try to be nice
20385
- // and do things automatically
20386
- // https://www.npmjs.com/package/react-native-device-info#getuniqueid
20387
- // how to make sure that the react native package will not be included when build is for web
20388
- return `ascWebSdk#${Math.random().toString(16)}`;
20389
- };
20390
- /** @hidden */
20391
- const getDeviceModel = () => {
20392
- var _a, _b;
20393
- if ((_a = safeProcess.versions) === null || _a === void 0 ? void 0 : _a.node)
20394
- return safeProcess.versions.node;
20395
- if (navigator)
20396
- return `${navigator.product.toLowerCase()}#${(_b = navigator.userAgent) !== null && _b !== void 0 ? _b : 'unknown_agent'}`;
20397
- return 'unknown_model';
20398
- };
20399
- /** @hidden */
20400
- const getDeviceInfo = () => {
20401
- const model = getDeviceModel();
20402
- return {
20403
- version: VERSION,
20404
- // TODO: replace with: kind: process.versions ? 'node' : 'web', when backend has fixed this
20405
- kind: 'web',
20406
- model,
20407
- };
20408
- };
20409
-
20410
20530
  /**
20411
20531
  * Ingest a payload (v3) into the cache
20412
20532
  *
@@ -20458,26 +20578,17 @@ const createUserEventSubscriber = (event, callback) => {
20458
20578
  const onUserDeleted = (callback) => createUserEventSubscriber('user.deleted', callback);
20459
20579
 
20460
20580
  /**
20461
- * Retrieves a pair of {@link Amity.Tokens} necessary for connection
20581
+ * Terminates {@link Amity.Client} instance
20462
20582
  *
20463
- * @param userId The userId to use to issue a token
20464
- * @param displayName The user's displayName
20465
- * @param deviceId The user's device Id (can be manually set for native users)
20466
- * @param authToken The authentication token - necessary when network option is set to secure
20467
- * @return The accessToken for the given userId
20468
20583
  *
20469
- * @category Client API
20470
- * @hidden
20584
+ *
20585
+ * @category private
20471
20586
  */
20472
- const getToken = async (params) => {
20587
+ const terminateClient = () => {
20473
20588
  const client = getActiveClient();
20474
- client.log('client/api/getToken', params);
20475
- const deviceInfo = await getDeviceInfo();
20476
- const { data } = await client.http.post('/v1/device', Object.assign(Object.assign({}, params), { deviceInfo }), {
20477
- // @ts-ignore
20478
- headers: { 'X-API-Key': client.apiKey },
20479
- });
20480
- return data;
20589
+ setSessionState("terminated" /* Amity.SessionStates.TERMINATED */);
20590
+ client.sessionHandler = undefined;
20591
+ disconnectClient();
20481
20592
  };
20482
20593
 
20483
20594
  const EVENTS = [
@@ -20552,12 +20663,71 @@ const onClientDisconnected = (callback) => {
20552
20663
  * @category Client Events
20553
20664
  */
20554
20665
  const onClientBanned = (callback) => {
20555
- return onConnectionError(({ code }) => {
20556
- code === 400312 /* Amity.ServerError.GLOBAL_BAN */ && callback();
20557
- });
20666
+ const client = getActiveClient();
20667
+ return createEventSubscriber(client, `client/onConnectionError(user.didGlobalBan)`, 'user.didGlobalBan', callback);
20668
+ };
20669
+
20670
+ /**
20671
+ * ```js
20672
+ * import { onSessionStateChange } from '@amityco/ts-sdk'
20673
+ * const dispose = onSessionStateChange((state: Amity.SessionStates) => {
20674
+ * // ...
20675
+ * })
20676
+ * ```
20677
+ *
20678
+ * Fired when any {@link Amity.Client} has a session state change
20679
+ *
20680
+ * @param callback The function to call when the event was fired
20681
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
20682
+ *
20683
+ * @category Client Events
20684
+ */
20685
+ const onSessionStateChange = (callback) => {
20686
+ const client = getActiveClient();
20687
+ return createEventSubscriber(client, `client/onSessionStateChange`, 'sessionStateChange', callback);
20688
+ };
20689
+
20690
+ /**
20691
+ * ```js
20692
+ * import { onTokenExpired } from '@amityco/ts-sdk'
20693
+ * const dispose = onTokenExpired((state: Amity.SessionStates.TOKEN_EXPIRED) => {
20694
+ * // ...
20695
+ * })
20696
+ * ```
20697
+ *
20698
+ * Fired when any {@link Amity.Client} session state has expired
20699
+ *
20700
+ * @param callback The function to call when the event was fired
20701
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
20702
+ *
20703
+ * @category private
20704
+ */
20705
+ const onTokenExpired = (callback) => {
20706
+ const client = getActiveClient();
20707
+ return createEventSubscriber(client, `client/onTokenExpired`, 'tokenExpired', callback);
20708
+ };
20709
+
20710
+ /**
20711
+ *
20712
+ * Fired when any {@link Amity.Client} session state has terminated
20713
+ *
20714
+ * @param callback The function to call when the event was fired
20715
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
20716
+ *
20717
+ * @category private
20718
+ */
20719
+ const onTokenTerminated = (callback) => {
20720
+ const client = getActiveClient();
20721
+ return createEventSubscriber(client, `client/onTokenTerminated`, 'tokenTerminated', callback);
20558
20722
  };
20559
20723
 
20560
20724
  /* eslint-disable no-param-reassign */
20725
+ /*
20726
+ * declared earlier to accomodate case when logging in with a different user
20727
+ * than the one already connected, in which case the existing subscriptions need
20728
+ * to be cleared
20729
+ */
20730
+ const subscriptions = [];
20561
20731
  /**
20562
20732
  * ```js
20563
20733
  * import { connectClient } from '@amityco/ts-sdk/client/api'
@@ -20578,46 +20748,259 @@ const onClientBanned = (callback) => {
20578
20748
  * @category Client API
20579
20749
  * @async
20580
20750
  */
20581
- const connectClient = async (params, config) => {
20582
- var _a;
20751
+ const connectClient = async (params, sessionHandler, config) => {
20752
+ var _a, _b, _c;
20583
20753
  const client = getActiveClient();
20584
- client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey }, params));
20754
+ let unsubWatcher;
20755
+ client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey, sessionState: client.sessionState }, params));
20756
+ // if connecting to a different userId than the one that is connected currently
20757
+ if (client.userId && client.userId !== params.userId) {
20758
+ await disconnectClient();
20759
+ // Remove subscription to ban and delete
20760
+ subscriptions.forEach(fn => fn());
20761
+ }
20585
20762
  // default values
20586
20763
  (_a = params.deviceId) !== null && _a !== void 0 ? _a : (params.deviceId = getDeviceId());
20587
- // @ts-ignore: in that particular case, typing can be
20588
- // ignored since we enforce default values just before.
20589
- const { accessToken, users } = await getToken(params);
20590
- // manually setup the token for http, ws transport
20591
- client.http.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
20592
- client.ws.io.opts.query = { token: accessToken };
20593
- // FIXME: events are duplicated if connectClient is called few times without disconnectClient
20594
- // wire websocket events to our event emitter
20595
- proxyWebsocketEvents(client.ws, client.emitter);
20596
- // TODO: in phase 2, this should not be necessary. we should have WS
20597
- // to be connected "on demand" rather than "by default"
20598
- await new Promise(resolve => {
20599
- client.ws.once('connect', resolve);
20600
- client.ws.open();
20601
- });
20602
- client.userId = params.userId;
20603
- client.accessToken = accessToken;
20604
- setActiveUser(users[0]);
20605
- if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
20606
- subscribeTopic(getNetworkTopic());
20607
- subscribeTopic(getSmartFeedChannelTopic());
20608
- subscribeTopic(getSmartFeedSubChannelTopic());
20764
+ try {
20765
+ // @ts-ignore: in that particular case, typing can be
20766
+ // ignored since we enforce default values just before.
20767
+ const { users } = await setClientToken(params);
20768
+ // FIXME: events are duplicated if connectClient is called few times without disconnectClient
20769
+ // wire websocket events to our event emitter
20770
+ proxyWebsocketEvents(client.ws, client.emitter);
20771
+ // TODO: in phase 2, this should not be necessary. we should have WS
20772
+ // to be connected "on demand" rather than "by default"
20773
+ await new Promise(resolve => {
20774
+ client.ws.once('connect', resolve);
20775
+ client.ws.open();
20776
+ });
20777
+ client.userId = params.userId;
20778
+ client.sessionHandler = sessionHandler;
20779
+ /*
20780
+ * Cannot push to subscriptions as watcher needs to continue working even if
20781
+ * token expires
20782
+ */
20783
+ unsubWatcher = client.accessTokenExpiryWatcher((_b = client.token) === null || _b === void 0 ? void 0 : _b.issuedAt, (_c = client.token) === null || _c === void 0 ? void 0 : _c.expiresAt, sessionHandler);
20784
+ setActiveUser(users[0]);
20785
+ }
20786
+ catch (error) {
20787
+ /*
20788
+ * if getting token failed session state reverts to initial state when app
20789
+ * is first launched
20790
+ */
20791
+ setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
20792
+ // pass error down tree so the calling function handle it
20793
+ throw error;
20794
+ }
20795
+ if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
20796
+ subscribeTopic(getNetworkTopic());
20797
+ subscribeTopic(getSmartFeedChannelTopic());
20798
+ subscribeTopic(getSmartFeedSubChannelTopic());
20609
20799
  subscribeTopic(getSmartFeedMessageTopic());
20800
+ // subscribing to user topic is necessary to handle ban event
20801
+ subscribeTopic(getUserTopic(getActiveUser()));
20610
20802
  }
20611
- const subscriptions = [
20612
- onClientBanned(() => {
20613
- disconnectClient();
20803
+ subscriptions.push(
20804
+ // GLOBAL_BAN
20805
+ onClientBanned((_) => {
20806
+ terminateClient();
20807
+ subscriptions.forEach(fn => fn());
20808
+ unsubWatcher();
20809
+ }), onTokenTerminated(_ => {
20810
+ terminateClient();
20811
+ subscriptions.forEach(fn => fn());
20812
+ unsubWatcher();
20813
+ }), onUserDeleted((user) => {
20814
+ if (user.userId === client.userId) {
20815
+ terminateClient();
20614
20816
  subscriptions.forEach(fn => fn());
20615
- }),
20616
- onUserDeleted(() => null),
20617
- ];
20817
+ unsubWatcher();
20818
+ }
20819
+ }), onTokenExpired(state => {
20820
+ setSessionState(state);
20821
+ disconnectClient();
20822
+ subscriptions.forEach(fn => fn());
20823
+ }), onUserDeleted(() => null));
20618
20824
  return client.ws.connected;
20619
20825
  };
20620
20826
 
20827
+ /*
20828
+ * Renewal defintion accepted by SessionHandler interface
20829
+ *
20830
+ * Tech Spec:
20831
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
20832
+ *
20833
+ * @category private
20834
+ */
20835
+ const renewal = () => {
20836
+ let tokenRenewed = false;
20837
+ let renewTimeoutId;
20838
+ const client = getActiveClient();
20839
+ client.log('initiating access token renewal');
20840
+ /*
20841
+ * Renews a token if it is hasn't been renewed before. Also marks token as
20842
+ * renewed once done
20843
+ * Per instance of Renewal, only one renewal is allowed
20844
+ */
20845
+ const renewToken = async (authToken) => {
20846
+ const { userId, displayName } = getActiveUser();
20847
+ const deviceId = getDeviceId();
20848
+ const params = { userId, displayName, authToken, deviceId };
20849
+ if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
20850
+ // sessionHandler will never be empty when renewal is instantiatied
20851
+ await connectClient(params, client.sessionHandler);
20852
+ }
20853
+ else {
20854
+ // about to expire
20855
+ // @ts-ignore: in that particular case, typing can be
20856
+ // ignored since we enforce default values just before.
20857
+ await setClientToken(params);
20858
+ }
20859
+ tokenRenewed = true;
20860
+ if (renewTimeoutId)
20861
+ clearTimeout(renewTimeoutId);
20862
+ };
20863
+ return {
20864
+ renew: () => {
20865
+ if (tokenRenewed) {
20866
+ console.log("'renew' method can be called only once per renewal instance");
20867
+ return;
20868
+ }
20869
+ renewToken();
20870
+ },
20871
+ renewWithAuthToken: (authToken) => {
20872
+ if (tokenRenewed) {
20873
+ console.log("'renewWithAuthToken' method can be called only once per renewal instance");
20874
+ return;
20875
+ }
20876
+ renewToken(authToken);
20877
+ },
20878
+ unableToRetrieveAuthToken: () => {
20879
+ renewTimeoutId = setTimeout(() => {
20880
+ var _a;
20881
+ (_a = client.sessionHandler) === null || _a === void 0 ? void 0 : _a.sessionWillRenewAccessToken(renewal());
20882
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
20883
+ },
20884
+ };
20885
+ };
20886
+
20887
+ const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
20888
+ const COMPENSATED_DELAY = 5 * MINUTE;
20889
+ /*
20890
+ * a helper function to check if the token has expires
20891
+ *
20892
+ * @param token to be checked
20893
+ * @returns boolean indicating if token expires
20894
+ *
20895
+ * @category private
20896
+ */
20897
+ const isExpired = (expiresAt) => Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
20898
+ /*
20899
+ * a helper function to check if the token is about to expire
20900
+ *
20901
+ * @param token to be checked
20902
+ * @returns boolean indicating if token is aboutToExpire
20903
+ *
20904
+ * @category private
20905
+ */
20906
+ const isAboutToExpire = (params) => {
20907
+ const { expiresAt, issuedAt } = params;
20908
+ const expires = Date.parse(expiresAt);
20909
+ const issued = Date.parse(issuedAt);
20910
+ const now = Date.now();
20911
+ const duration = expires - issued - COMPENSATED_DELAY;
20912
+ const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
20913
+ return now > aboutToExpireAt && now < expires;
20914
+ };
20915
+ /*
20916
+ * Monitors time to expire of token and updates session state to aboutToExpire
20917
+ *
20918
+ * @returns intervalId to be cleared after trigger
20919
+ *
20920
+ * @category private
20921
+ */
20922
+ const accessTokenExpiryWatcher = (expiresAt, issuedAt, sessionHandler) => {
20923
+ const interval = setInterval(() => {
20924
+ if (isExpired(expiresAt)) {
20925
+ /*
20926
+ * the event handler will take care of updating session state
20927
+ * Note, this will also clear the interval id, so this event will only be
20928
+ * fired once
20929
+ */
20930
+ fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
20931
+ /*
20932
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
20933
+ *
20934
+ * Why sechduled task?
20935
+ * Since fireEvent is scheduled, it will be called
20936
+ * after sessionHandler leading to an invalid state change from
20937
+ * establishing to tokenExpired
20938
+ */
20939
+ scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
20940
+ return;
20941
+ }
20942
+ if (isAboutToExpire({ expiresAt, issuedAt })) {
20943
+ sessionHandler.sessionWillRenewAccessToken(renewal());
20944
+ }
20945
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
20946
+ return () => clearInterval(interval);
20947
+ };
20948
+
20949
+ const DEFAULT_DEBUG_SESSION = 'amity';
20950
+ /**
20951
+ * ```js
20952
+ * import { createClient } from '@amityco/ts-sdk'
20953
+ * const client = createClient(apiKey, 'https://asc.server/', 'myClient')
20954
+ * ```
20955
+ *
20956
+ * Creates a new {@link Amity.Client} instance
20957
+ *
20958
+ * @param apiKey for the {@link Amity.Client} instance
20959
+ * @param apiRegion endpoint to connect to
20960
+ * @param apiEndpoint custom endpoint in case you don't want to use a preset endpoint
20961
+ * @param param.debugSession session's identifier for the client's logger instance
20962
+ * @returns A {@link Amity.Client} instance
20963
+ *
20964
+ * @category Client API
20965
+ * */
20966
+ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, } = {}) => {
20967
+ var _a, _b;
20968
+ const log = createLogger(debugSession);
20969
+ log('client/api/createClient', {
20970
+ apiKey: apiKey.replace(/.{5}$/g, 'xxxxx'),
20971
+ apiRegion,
20972
+ });
20973
+ const httpEndpoint = (_a = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.http) !== null && _a !== void 0 ? _a : computeUrl('http', apiRegion);
20974
+ const mqttEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _b !== void 0 ? _b : computeUrl('mqtt', apiRegion);
20975
+ const http = createHttpTransport(httpEndpoint);
20976
+ const ws = createWebsocketTransport(httpEndpoint);
20977
+ const mqtt = createMqttTransport(mqttEndpoint);
20978
+ const emitter = createEventEmitter();
20979
+ const sessionState = "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */;
20980
+ const sessionHandler = undefined;
20981
+ const client = {
20982
+ version: `${VERSION$1}`,
20983
+ apiKey,
20984
+ log,
20985
+ http,
20986
+ ws,
20987
+ mqtt,
20988
+ emitter,
20989
+ accessTokenExpiryWatcher,
20990
+ use: () => setActiveClient(client),
20991
+ sessionState,
20992
+ sessionHandler,
20993
+ getFeedSettings,
20994
+ };
20995
+ try {
20996
+ return getActiveClient();
20997
+ }
20998
+ catch (_c) {
20999
+ setActiveClient(client);
21000
+ }
21001
+ return client;
21002
+ };
21003
+
20621
21004
  /**
20622
21005
  * ```js
20623
21006
  * import { isConnected } from '@amityco/ts-sdk'
@@ -21027,12 +21410,57 @@ const onUserUnflagged = (callback) => createUserEventSubscriber('user.unflagged'
21027
21410
  */
21028
21411
  const onUserFlagCleared = (callback) => createUserEventSubscriber('user.flagCleared', callback);
21029
21412
 
21030
- const COLLECTION_DEFAULT_PAGINATION_LIMIT = 5;
21031
- const COLLECTION_DEFAULT_CACHING_POLICY = 'cache_then_server';
21032
- const ENABLE_CACHE_MESSAGE = 'For using Live Collection feature you need to enable Cache!';
21033
- const LIVE_OBJECT_ENABLE_CACHE_MESSAGE = 'For using Live Object feature you need to enable Cache!';
21034
- const UNSYNCED_OBJECT_CACHED_AT_MESSAGE = 'Observing unsynced object is not supported by Live Object.';
21035
- const UNSYNCED_OBJECT_CACHED_AT_VALUE = -5;
21413
+ const liveObject = (id, callback, key, fetcher, eventHandlers) => {
21414
+ const { cache } = getActiveClient();
21415
+ if (!cache) {
21416
+ console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
21417
+ }
21418
+ let model;
21419
+ let isUnsyncedModel = false; // for messages
21420
+ const disposers = [];
21421
+ const dispatcher = (data) => {
21422
+ model = data.data;
21423
+ callback(data);
21424
+ };
21425
+ const realtimeRouter = (eventModel) => {
21426
+ if (id !== eventModel[key]) {
21427
+ return;
21428
+ }
21429
+ if (model && !hasUpdates(model, eventModel)) {
21430
+ return;
21431
+ }
21432
+ dispatcher({ loading: false, data: eventModel, origin: 'event' });
21433
+ };
21434
+ const onFetch = () => {
21435
+ // @ts-ignore
21436
+ const query = createQuery(fetcher, id, true);
21437
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
21438
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
21439
+ dispatcher({
21440
+ // @ts-ignore
21441
+ data,
21442
+ origin,
21443
+ loading: false,
21444
+ error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
21445
+ });
21446
+ isUnsyncedModel = true;
21447
+ disposers.forEach(fn => fn());
21448
+ }
21449
+ else if (!isUnsyncedModel) {
21450
+ // @ts-ignore
21451
+ dispatcher({ loading, data, origin, error });
21452
+ }
21453
+ if (error) {
21454
+ disposers.forEach(fn => fn());
21455
+ }
21456
+ });
21457
+ };
21458
+ disposers.push(...eventHandlers.map(fn => fn(realtimeRouter)));
21459
+ onFetch();
21460
+ return () => {
21461
+ disposers.forEach(fn => fn());
21462
+ };
21463
+ };
21036
21464
 
21037
21465
  /**
21038
21466
  * ```js
@@ -21071,42 +21499,14 @@ const onUserFetched = (callback) => createUserEventSubscriber('user.fetched', ca
21071
21499
  * @category Message Live Object
21072
21500
  */
21073
21501
  const liveUser = (userId, callback) => {
21074
- const { log, cache } = getActiveClient();
21075
- const timestamp = Date.now();
21076
- log(`liveUser(tmpid: ${timestamp}) > listen`);
21077
- if (!cache) {
21078
- console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
21079
- }
21080
- let user;
21081
- const disposers = [];
21082
- const dispatcher = (data) => {
21083
- user = data.data;
21084
- callback(data);
21085
- };
21086
- const realtimeRouter = (eventUser) => {
21087
- if (userId !== eventUser.userId) {
21088
- return;
21089
- }
21090
- if (user && !hasUpdates(user, eventUser)) {
21091
- return;
21092
- }
21093
- dispatcher({ loading: false, data: eventUser, origin: 'event' });
21094
- };
21095
- const onFetch = () => {
21096
- const query = createQuery(getUser, userId, true);
21097
- runQuery(query, ({ loading, data, error, origin }) => {
21098
- dispatcher({ loading, data, origin, error });
21099
- if (error) {
21100
- disposers.forEach(fn => fn());
21101
- }
21102
- });
21103
- };
21104
- disposers.push(onUserFetched(realtimeRouter), onUserUpdated(realtimeRouter), onUserDeleted(realtimeRouter), onUserFlagged(realtimeRouter), onUserUnflagged(realtimeRouter), onUserFlagCleared(realtimeRouter));
21105
- onFetch();
21106
- return () => {
21107
- log(`liveUser(tmpid: ${timestamp}) > dispose`);
21108
- disposers.forEach(fn => fn());
21109
- };
21502
+ return liveObject(userId, callback, 'userId', getUser, [
21503
+ onUserFetched,
21504
+ onUserUpdated,
21505
+ onUserDeleted,
21506
+ onUserFlagged,
21507
+ onUserUnflagged,
21508
+ onUserFlagCleared,
21509
+ ]);
21110
21510
  };
21111
21511
 
21112
21512
  /**
@@ -21230,7 +21630,7 @@ const createFile = async (formData, onProgress) => {
21230
21630
  : { 'content-type': 'multipart/form-data' };
21231
21631
  const { data } = await client.http.post('/api/v4/files', formData, {
21232
21632
  headers,
21233
- onUploadProgress({ loaded, total }) {
21633
+ onUploadProgress({ loaded, total = 100 }) {
21234
21634
  onProgress && onProgress(Math.round((loaded * 100) / total));
21235
21635
  },
21236
21636
  });
@@ -21309,7 +21709,7 @@ const createVideo = async (formData, feedType, onProgress) => {
21309
21709
  : { 'content-type': 'multipart/form-data' };
21310
21710
  const { data } = await client.http.post('/api/v4/videos', formData, {
21311
21711
  headers,
21312
- onUploadProgress({ loaded, total }) {
21712
+ onUploadProgress({ loaded, total = 100 }) {
21313
21713
  onProgress && onProgress(Math.round((loaded * 100) / total));
21314
21714
  },
21315
21715
  });
@@ -21350,7 +21750,7 @@ const createImage = async (formData, onProgress) => {
21350
21750
  : { 'content-type': 'multipart/form-data' };
21351
21751
  const { data } = await client.http.post('/api/v4/images', formData, {
21352
21752
  headers,
21353
- onUploadProgress({ loaded, total }) {
21753
+ onUploadProgress({ loaded, total = 100 }) {
21354
21754
  onProgress && onProgress(Math.round((loaded * 100) / total));
21355
21755
  },
21356
21756
  });
@@ -23329,6 +23729,7 @@ getComments.locally = (commentIds) => {
23329
23729
  const getComment = async (commentId) => {
23330
23730
  const client = getActiveClient();
23331
23731
  client.log('comment/getComment', commentId);
23732
+ isInTombstone('comment', commentId);
23332
23733
  let data;
23333
23734
  try {
23334
23735
  // API-FIX: endpoint should not be /list, parameters should be querystring.
@@ -23336,8 +23737,8 @@ const getComment = async (commentId) => {
23336
23737
  data = response.data;
23337
23738
  }
23338
23739
  catch (error) {
23339
- if ((error === null || error === void 0 ? void 0 : error.code) === 400400 /* Amity.ServerError.ITEM_NOT_FOUND */) {
23340
- dropFromCache(['comment', 'get', commentId], true);
23740
+ if (checkIfShouldGoesToTombstone(error === null || error === void 0 ? void 0 : error.code)) {
23741
+ pushToTombstone('comment', commentId);
23341
23742
  }
23342
23743
  throw error;
23343
23744
  }
@@ -23471,9 +23872,7 @@ const deleteComment = async (commentId, permanent = false) => {
23471
23872
  fireEvent('post.updated', { posts: [post.data] });
23472
23873
  fireEvent('comment.deleted', { comments: [deleted] });
23473
23874
  if (permanent) {
23474
- setTimeout(() => {
23475
- dropFromCache(['comment', 'get', commentId], true);
23476
- }, 0);
23875
+ scheduleTask(() => pushToTombstone('comment', commentId));
23477
23876
  }
23478
23877
  else {
23479
23878
  upsertInCache(['comment', 'get', commentId], { isDeleted: true });
@@ -25896,55 +26295,13 @@ const onMessageReactionRemoved = (callback) => {
25896
26295
  * @category Message Live Object
25897
26296
  */
25898
26297
  const liveChannel = (channelId, callback) => {
25899
- const { log, cache } = getActiveClient();
25900
- const timestamp = Date.now();
25901
- log(`liveChannel(tmpid: ${timestamp}) > listen`);
25902
- if (!cache) {
25903
- console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
25904
- }
25905
- let channel;
25906
- let isUnsyncedObject = false;
25907
- const disposers = [];
25908
- const dispatcher = (data) => {
25909
- channel = data.data;
25910
- callback(data);
25911
- };
25912
- const realtimeRouter = (eventChannel) => {
25913
- if (channelId !== eventChannel.channelId) {
25914
- return;
25915
- }
25916
- if (channel && !hasUpdates(channel, eventChannel)) {
25917
- return;
25918
- }
25919
- dispatcher({ loading: false, data: eventChannel, origin: 'event' });
25920
- };
25921
- const onFetch = () => {
25922
- const query = createQuery(getChannel, channelId);
25923
- runQuery(query, ({ loading, data, error, origin, cachedAt }) => {
25924
- if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
25925
- dispatcher({
25926
- data,
25927
- origin,
25928
- loading: false,
25929
- error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
25930
- });
25931
- isUnsyncedObject = true;
25932
- disposers.forEach(fn => fn());
25933
- }
25934
- else if (!isUnsyncedObject) {
25935
- dispatcher({ loading, data, origin, error });
25936
- }
25937
- if (error) {
25938
- disposers.forEach(fn => fn());
25939
- }
25940
- });
25941
- };
25942
- disposers.push(onChannelUpdated(realtimeRouter), onChannelDeleted(realtimeRouter), onChannelJoined(realtimeRouter), onChannelMuted(realtimeRouter), onMessageCreated(() => null));
25943
- onFetch();
25944
- return () => {
25945
- log(`liveChannel(tmpid: ${timestamp}) > dispose`);
25946
- disposers.forEach(fn => fn());
25947
- };
26298
+ return liveObject(channelId, callback, 'channelId', getChannel, [
26299
+ onChannelUpdated,
26300
+ onChannelDeleted,
26301
+ onChannelJoined,
26302
+ onChannelMuted,
26303
+ () => onMessageCreated(() => null), // watch unread count
26304
+ ]);
25948
26305
  };
25949
26306
 
25950
26307
  /**
@@ -26605,42 +26962,11 @@ const onSubChannelFetched = (callback) => {
26605
26962
  * @category SubChannel Live Object
26606
26963
  */
26607
26964
  const liveSubChannel = (subChannelId, callback) => {
26608
- const { log, cache } = getActiveClient();
26609
- const timestamp = Date.now();
26610
- log(`liveSubChannel(tmpid: ${timestamp}) > listen`);
26611
- if (!cache) {
26612
- console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
26613
- }
26614
- let subChannel;
26615
- const disposers = [];
26616
- const dispatcher = (data) => {
26617
- subChannel = data.data;
26618
- callback(data);
26619
- };
26620
- const realtimeRouter = (eventSubChannel) => {
26621
- if (subChannelId !== eventSubChannel.subChannelId) {
26622
- return;
26623
- }
26624
- if (subChannel && !hasUpdates(subChannel, eventSubChannel)) {
26625
- return;
26626
- }
26627
- dispatcher({ loading: false, data: eventSubChannel, origin: 'event' });
26628
- };
26629
- const onFetch = () => {
26630
- const query = createQuery(getSubChannel, subChannelId);
26631
- runQuery(query, ({ error, data, loading, origin }) => {
26632
- dispatcher({ error, data, loading, origin });
26633
- if (error) {
26634
- disposers.forEach(fn => fn());
26635
- }
26636
- });
26637
- };
26638
- disposers.push(onSubChannelFetched(realtimeRouter), onSubChannelUpdated(realtimeRouter), onSubChannelDeleted(realtimeRouter));
26639
- onFetch();
26640
- return () => {
26641
- log(`liveSubChannel(tmpid: ${timestamp}) > dispose`);
26642
- disposers.forEach(fn => fn());
26643
- };
26965
+ return liveObject(subChannelId, callback, 'subChannelId', getSubChannel, [
26966
+ onSubChannelFetched,
26967
+ onSubChannelUpdated,
26968
+ onSubChannelDeleted,
26969
+ ]);
26644
26970
  };
26645
26971
 
26646
26972
  /**
@@ -26771,55 +27097,16 @@ const onMessageFetched = (callback) => {
26771
27097
  * @category Message Live Object
26772
27098
  */
26773
27099
  const liveMessage = (messageId, callback) => {
26774
- const { log, cache } = getActiveClient();
26775
- const timestamp = Date.now();
26776
- log(`liveMessage(tmpid: ${timestamp}) > listen`);
26777
- if (!cache) {
26778
- console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
26779
- }
26780
- let message;
26781
- let isUnsyncedObject = false;
26782
- const disposers = [];
26783
- const dispatcher = (data) => {
26784
- message = data.data;
26785
- callback(data);
26786
- };
26787
- const realtimeRouter = (eventMessage) => {
26788
- if (messageId !== eventMessage.messageId) {
26789
- return;
26790
- }
26791
- if (message && !hasUpdates(message, eventMessage)) {
26792
- return;
26793
- }
26794
- dispatcher({ loading: false, data: eventMessage, origin: 'event' });
26795
- };
26796
- const onFetch = () => {
26797
- const query = createQuery(getMessage, messageId, true);
26798
- runQuery(query, ({ loading, data, error, origin, cachedAt }) => {
26799
- if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
26800
- dispatcher({
26801
- data,
26802
- origin,
26803
- loading: false,
26804
- error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
26805
- });
26806
- isUnsyncedObject = true;
26807
- disposers.forEach(fn => fn());
26808
- }
26809
- else if (!isUnsyncedObject) {
26810
- dispatcher({ loading, data, origin, error });
26811
- }
26812
- if (error) {
26813
- disposers.forEach(fn => fn());
26814
- }
26815
- });
26816
- };
26817
- disposers.push(onMessageFetched(realtimeRouter), onMessageUpdated(realtimeRouter), onMessageDeleted(realtimeRouter), onMessageFlagged(realtimeRouter), onMessageUnflagged(realtimeRouter), onMessageFlagCleared(realtimeRouter), onMessageReactionAdded(realtimeRouter), onMessageReactionRemoved(realtimeRouter));
26818
- onFetch();
26819
- return () => {
26820
- log(`liveMessage(tmpid: ${timestamp}) > dispose`);
26821
- disposers.forEach(fn => fn());
26822
- };
27100
+ return liveObject(messageId, callback, 'messageId', getMessage, [
27101
+ onMessageFetched,
27102
+ onMessageUpdated,
27103
+ onMessageDeleted,
27104
+ onMessageFlagged,
27105
+ onMessageUnflagged,
27106
+ onMessageFlagCleared,
27107
+ onMessageReactionAdded,
27108
+ onMessageReactionRemoved,
27109
+ ]);
26823
27110
  };
26824
27111
 
26825
27112
  /**
@@ -27020,6 +27307,30 @@ const createCommunityEventSubscriber = (event, callback) => {
27020
27307
  };
27021
27308
  return createEventSubscriber(client, event, event, filter);
27022
27309
  };
27310
+ /*
27311
+ * verifies membership status
27312
+ */
27313
+ function isMember(membership) {
27314
+ return membership !== 'none';
27315
+ }
27316
+ /*
27317
+ * checks if currently logged in user is part of the community
27318
+ */
27319
+ function isCurrentUserPartOfCommunity(c, m) {
27320
+ const { userId } = getActiveUser();
27321
+ return c.communityId === m.communityId && m.userId === userId;
27322
+ }
27323
+ /*
27324
+ * For mqtt events server will not send user specific data as it's broadcasted
27325
+ * to multiple users. Althought this can be calculated, it's not scalable. Hence
27326
+ * the client SDK needs to calculate this info
27327
+ */
27328
+ function updateMembershipStatus(communities, communityUsers) {
27329
+ return communities.map(c => {
27330
+ const isJoined = communityUsers.some(m => isCurrentUserPartOfCommunity(c, m) && isMember(m.communityMembership));
27331
+ return Object.assign(Object.assign({}, c), { isJoined });
27332
+ });
27333
+ }
27023
27334
  function hasPermission(member, payload, permission) {
27024
27335
  if (member.permissions.some(x => x === permission)) {
27025
27336
  return true;
@@ -27050,7 +27361,15 @@ const createCommunityMemberEventSubscriber = (event, callback) => {
27050
27361
  const client = getActiveClient();
27051
27362
  const filter = (payload) => {
27052
27363
  const communityPayload = unpackCommunityPayload(payload);
27364
+ const { communities } = communityPayload;
27053
27365
  const preparedPayload = prepareMembershipPayload(communityPayload, 'communityUsers');
27366
+ const { communityUsers } = preparedPayload;
27367
+ /*
27368
+ * community.isJoined is not part of the communityMembership payload, and needs
27369
+ * to be calculated based on the communityMembership value
27370
+ */
27371
+ const communitiesWithMembership = updateMembershipStatus(communities, communityUsers);
27372
+ preparedPayload.communities = communitiesWithMembership;
27054
27373
  if (!client.cache) {
27055
27374
  // TODO: here we are missing specific properties here!
27056
27375
  callback(preparedPayload.communities[0], getEventRelatedMember(event, preparedPayload));
@@ -27192,6 +27511,23 @@ const onCommunityUserAdded = (callback) => createCommunityMemberEventSubscriber(
27192
27511
  */
27193
27512
  const onCommunityUserRemoved = (callback) => createCommunityMemberEventSubscriber('community.userRemoved', callback);
27194
27513
 
27514
+ /**
27515
+ * ```js
27516
+ * import { onCommunityUserChanged } from '@amityco/ts-sdk'
27517
+ * const dispose = onCommunityUserChanged((community, member) => {
27518
+ * // ...
27519
+ * })
27520
+ * ```
27521
+ *
27522
+ * Fired when a user has been added or removed from a {@link Amity.Community}
27523
+ *
27524
+ * @param callback The function to call when the event was fired
27525
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
27526
+ *
27527
+ * @category Community Events
27528
+ */
27529
+ const onCommunityUserChanged = (callback) => createCommunityMemberEventSubscriber('community.userChanged', callback);
27530
+
27195
27531
  /**
27196
27532
  * ```js
27197
27533
  * import { onCommunityUserBanned } from '@amityco/ts-sdk'
@@ -27270,6 +27606,122 @@ const observeCommunity = (communityId, callback) => {
27270
27606
  };
27271
27607
  };
27272
27608
 
27609
+ /**
27610
+ * ```js
27611
+ * import { liveCommunities } from '@amityco/ts-sdk'
27612
+ *
27613
+ * let communities = []
27614
+ * const unsub = liveCommunities({
27615
+ * displayName: Amity.Community['displayName'],
27616
+ * }, response => merge(communities, response.data))
27617
+ * ```
27618
+ *
27619
+ * Observe all mutations on a list of {@link Amity.Community}s
27620
+ *
27621
+ * @param params for querying communities
27622
+ * @param callback the function to call when new data are available
27623
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the communities
27624
+ *
27625
+ * @category Community Live Collection
27626
+ */
27627
+ const liveCommunities = (params, callback, config) => {
27628
+ const { log, cache } = getActiveClient();
27629
+ if (!cache) {
27630
+ console.log(ENABLE_CACHE_MESSAGE);
27631
+ }
27632
+ const timestamp = Date.now();
27633
+ log(`liveCommunities(tmpid: ${timestamp}) > listen`);
27634
+ const { limit: queryLimit } = params, queryParams = __rest(params, ["limit"]);
27635
+ const limit = queryLimit !== null && queryLimit !== void 0 ? queryLimit : COLLECTION_DEFAULT_PAGINATION_LIMIT;
27636
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config !== null && config !== void 0 ? config : {};
27637
+ const disposers = [];
27638
+ const cacheKey = ['community', 'collection', {}];
27639
+ const responder = (data) => {
27640
+ var _a, _b;
27641
+ let communities = (_a = data.data
27642
+ .map(communityId => pullFromCache(['community', 'get', communityId]))
27643
+ .filter(Boolean)
27644
+ .map(({ data }) => data)) !== null && _a !== void 0 ? _a : [];
27645
+ communities = filterByPropEquality(communities, 'isDeleted', params.isDeleted);
27646
+ communities = filterByPropEquality(communities, 'displayName', params.displayName);
27647
+ if (params.categoryId) {
27648
+ communities = communities.filter(c => { var _a; return (_a = c.categoryIds) === null || _a === void 0 ? void 0 : _a.includes(params.categoryId); });
27649
+ }
27650
+ if (params.tags) {
27651
+ communities = communities.filter(c => { var _a; return (_a = c.tags) === null || _a === void 0 ? void 0 : _a.some(t => { var _a; return (_a = params.tags) === null || _a === void 0 ? void 0 : _a.includes(t); }); });
27652
+ }
27653
+ if (params.membership === 'member') {
27654
+ communities = filterByPropEquality(communities, 'isJoined', true);
27655
+ }
27656
+ if (params.membership === 'notMember') {
27657
+ communities = filterByPropEquality(communities, 'isJoined', false);
27658
+ }
27659
+ const sortBy = params.sortBy || 'lastCreated';
27660
+ if (sortBy === 'lastCreated' || sortBy === 'firstCreated') {
27661
+ communities = communities.sort(sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated);
27662
+ }
27663
+ /*
27664
+ * The server returns communities with empty | null displayName's first before
27665
+ * returning sorted list of communities with displayNames
27666
+ *
27667
+ * This section needs to be updated as displayNames can be null as well
27668
+ */
27669
+ if (sortBy === 'displayName') {
27670
+ communities = communities
27671
+ // this needs to be aligned with the backend data type
27672
+ .map(c => (c.displayName ? c : Object.assign(Object.assign({}, c), { displayName: '' })))
27673
+ // @ts-ignore
27674
+ .sort(sortByDisplayName);
27675
+ }
27676
+ callback({
27677
+ onNextPage: onFetch,
27678
+ data: communities,
27679
+ hasNextPage: !!((_b = data.params) === null || _b === void 0 ? void 0 : _b.page),
27680
+ loading: data.loading,
27681
+ error: data.error,
27682
+ });
27683
+ };
27684
+ const realtimeRouter = (_) => (community) => {
27685
+ var _a;
27686
+ const collection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27687
+ if (!collection)
27688
+ return;
27689
+ /*
27690
+ * Simply update collection and let responder decide what to do with data
27691
+ */
27692
+ collection.data = [...new Set([community.communityId, ...collection.data])];
27693
+ pushToCache(cacheKey, collection);
27694
+ responder(collection);
27695
+ };
27696
+ const onFetch = () => {
27697
+ var _a, _b, _c;
27698
+ const collection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27699
+ const communities = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
27700
+ if (communities.length > 0 && !(collection === null || collection === void 0 ? void 0 : collection.params.page))
27701
+ return;
27702
+ const query = createQuery(queryCommunities, Object.assign(Object.assign({}, queryParams), { page: (_c = collection === null || collection === void 0 ? void 0 : collection.params.page) !== null && _c !== void 0 ? _c : { limit } }));
27703
+ runQuery(query, ({ data: result, error, loading, nextPage: page }) => {
27704
+ const data = {
27705
+ loading,
27706
+ error,
27707
+ params: { page },
27708
+ data: communities,
27709
+ };
27710
+ if (result) {
27711
+ data.data = [...new Set([...communities, ...result.map(getResolver('community'))])];
27712
+ }
27713
+ pushToCache(cacheKey, data);
27714
+ responder(data);
27715
+ }, queryOptions(policy));
27716
+ };
27717
+ disposers.push(onCommunityCreated(realtimeRouter()), onCommunityDeleted(realtimeRouter()), onCommunityUpdated(realtimeRouter()), onCommunityJoined(realtimeRouter()), onCommunityLeft(realtimeRouter()), onCommunityUserChanged(realtimeRouter()));
27718
+ onFetch();
27719
+ return () => {
27720
+ log(`liveCommunities(tmpid: ${timestamp}) > dispose`);
27721
+ disposers.forEach(fn => fn());
27722
+ };
27723
+ };
27724
+
27273
27725
  /**
27274
27726
  * ```js
27275
27727
  * import { queryCategories } from '@amityco/ts-sdk'
@@ -27398,6 +27850,96 @@ getCategory.locally = (categoryId) => {
27398
27850
  };
27399
27851
  };
27400
27852
 
27853
+ /**
27854
+ * ```js
27855
+ * import { liveCategories } from '@amityco/ts-sdk'
27856
+ *
27857
+ * let categories = []
27858
+ * const unsub = liveCategories({}, response => merge(categories, response.data))
27859
+ * ```
27860
+ *
27861
+ * Observe all mutations on a list of {@link Amity.Category}s
27862
+ *
27863
+ * @param params for querying categories
27864
+ * @param callback the function to call when new data are available
27865
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the categories
27866
+ *
27867
+ * @category Category Live Collection
27868
+ */
27869
+ const liveCategories = (params, callback, config) => {
27870
+ const { log, cache } = getActiveClient();
27871
+ if (!cache) {
27872
+ console.log(ENABLE_CACHE_MESSAGE);
27873
+ }
27874
+ const timestamp = Date.now();
27875
+ log(`liveCategories(tmpid: ${timestamp}) > listen`);
27876
+ const { limit: queryLimit } = params, queryParams = __rest(params, ["limit"]);
27877
+ const limit = queryLimit !== null && queryLimit !== void 0 ? queryLimit : COLLECTION_DEFAULT_PAGINATION_LIMIT;
27878
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config !== null && config !== void 0 ? config : {};
27879
+ const disposers = [];
27880
+ const cacheKey = ['category', 'collection', {}];
27881
+ const responder = (data) => {
27882
+ var _a, _b;
27883
+ let categories = (_a = data.data
27884
+ .map(categoryId => pullFromCache(['category', 'get', categoryId]))
27885
+ .filter(Boolean)
27886
+ .map(({ data }) => data)) !== null && _a !== void 0 ? _a : [];
27887
+ categories = filterByPropEquality(categories, 'isDeleted', params.isDeleted);
27888
+ switch (params.sortBy) {
27889
+ case 'firstCreated':
27890
+ categories = categories.sort(sortByFirstCreated);
27891
+ break;
27892
+ case 'lastCreated':
27893
+ categories = categories.sort(sortByLastCreated);
27894
+ break;
27895
+ default:
27896
+ categories = categories.sort(sortByName);
27897
+ }
27898
+ callback({
27899
+ onNextPage: onFetch,
27900
+ data: categories,
27901
+ hasNextPage: !!((_b = data.params) === null || _b === void 0 ? void 0 : _b.page),
27902
+ loading: data.loading,
27903
+ error: data.error,
27904
+ });
27905
+ };
27906
+ /*
27907
+ * const realtimeRouter = () => {
27908
+ * @TODO: At the time of creating this method category does not have any
27909
+ * observers
27910
+ *};
27911
+ */
27912
+ const onFetch = () => {
27913
+ var _a, _b, _c;
27914
+ const collection = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
27915
+ const categories = (_b = collection === null || collection === void 0 ? void 0 : collection.data) !== null && _b !== void 0 ? _b : [];
27916
+ if (categories.length > 0 && !(collection === null || collection === void 0 ? void 0 : collection.params.page))
27917
+ return;
27918
+ const query = createQuery(queryCategories, Object.assign(Object.assign({}, queryParams), { page: (_c = collection === null || collection === void 0 ? void 0 : collection.params.page) !== null && _c !== void 0 ? _c : { limit } }));
27919
+ runQuery(query, ({ data: result, error, loading, nextPage: page }) => {
27920
+ const data = {
27921
+ loading,
27922
+ error,
27923
+ params: { page },
27924
+ data: categories,
27925
+ };
27926
+ if (result) {
27927
+ data.data = [...new Set([...categories, ...result.map(getResolver('category'))])];
27928
+ }
27929
+ pushToCache(cacheKey, data);
27930
+ responder(data);
27931
+ }, queryOptions(policy));
27932
+ };
27933
+ disposers.push(() => {
27934
+ // @TODO -> update once observers added
27935
+ });
27936
+ onFetch();
27937
+ return () => {
27938
+ log(`liveCategories(tmpid: ${timestamp}) > dispose`);
27939
+ disposers.forEach(fn => fn());
27940
+ };
27941
+ };
27942
+
27401
27943
  /**
27402
27944
  * ```js
27403
27945
  * import { queryGlobalFeed } from '@amityco/ts-sdk'
@@ -28322,6 +28864,38 @@ const observePost = (postId, callback, policy = 'cache_then_server') => {
28322
28864
  };
28323
28865
  };
28324
28866
 
28867
+ /**
28868
+ * ```js
28869
+ * import { livePost } from '@amityco/ts-sdk';
28870
+ *
28871
+ * let post;
28872
+ *
28873
+ * const unsubscribe = livePost(postId, response => {
28874
+ * post = response.data;
28875
+ * });
28876
+ * ```
28877
+ *
28878
+ * Observe all mutation on a given {@link Amity.Post}
28879
+ *
28880
+ * @param postId the ID of the message to observe
28881
+ * @param callback the function to call when new data are available
28882
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the sub channel
28883
+ *
28884
+ * @category Post Live Object
28885
+ */
28886
+ const livePost = (postId, callback) => {
28887
+ return liveObject(postId, callback, 'postId', getPost, [
28888
+ onPostApproved,
28889
+ onPostDeclined,
28890
+ onPostDeleted,
28891
+ onPostFlagged,
28892
+ onPostReactionAdded,
28893
+ onPostReactionRemoved,
28894
+ onPostUnflagged,
28895
+ onPostUpdated,
28896
+ ]);
28897
+ };
28898
+
28325
28899
  /**
28326
28900
  * ```js
28327
28901
  * import { livePosts } from '@amityco/ts-sdk'
@@ -28517,6 +29091,36 @@ const observeComment = (commentId, callback, policy = 'cache_then_server') => {
28517
29091
  };
28518
29092
  };
28519
29093
 
29094
+ /**
29095
+ * ```js
29096
+ * import { liveComment } from '@amityco/ts-sdk';
29097
+ *
29098
+ * let comment;
29099
+ *
29100
+ * const unsubscribe = liveComment(commentId, response => {
29101
+ * comment = response.data;
29102
+ * });
29103
+ * ```
29104
+ *
29105
+ * Observe all mutation on a given {@link Amity.Comment}
29106
+ *
29107
+ * @param commentId the ID of the comment to observe
29108
+ * @param callback the function to call when new data are available
29109
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the comment
29110
+ *
29111
+ * @category Comment Live Object
29112
+ */
29113
+ const liveComment = (commentId, callback) => {
29114
+ return liveObject(commentId, callback, 'commentId', getComment, [
29115
+ onCommentDeleted,
29116
+ onCommentFlagged,
29117
+ onCommentReactionAdded,
29118
+ onCommentReactionRemoved,
29119
+ onCommentUnflagged,
29120
+ onCommentUpdated,
29121
+ ]);
29122
+ };
29123
+
28520
29124
  /**
28521
29125
  * ```js
28522
29126
  * import { liveComments } from '@amityco/ts-sdk'
@@ -29195,9 +29799,9 @@ const onStreamRecorded = (callback) => {
29195
29799
  */
29196
29800
  const createUserToken = async (apiKey, apiRegion, params) => {
29197
29801
  const deviceId = getDeviceId();
29198
- const deviceInfo = await getDeviceInfo();
29802
+ const deviceInfo = getDeviceInfo();
29199
29803
  const http = createHttpTransport(computeUrl('http', apiRegion));
29200
- const { data } = await http.post('/api/v3/sessions', Object.assign(Object.assign({}, params), { deviceId, deviceInfo: Object.assign(Object.assign({}, deviceInfo), { model: 'token management API on TS-SDK' }) }), { headers: { 'X-API-Key': apiKey } });
29804
+ const { data } = await http.post('/api/v4/sessions', Object.assign(Object.assign({}, params), { deviceId, deviceInfo: Object.assign(Object.assign({}, deviceInfo), { model: 'token management API on TS-SDK' }) }), { headers: { 'X-API-Key': apiKey } });
29201
29805
  return { accessToken: data.accessToken };
29202
29806
  };
29203
29807
 
@@ -29314,14 +29918,18 @@ exports.joinChannel = joinChannel;
29314
29918
  exports.joinCommunity = joinCommunity;
29315
29919
  exports.leaveChannel = leaveChannel;
29316
29920
  exports.leaveCommunity = leaveCommunity;
29921
+ exports.liveCategories = liveCategories;
29317
29922
  exports.liveChannel = liveChannel;
29318
29923
  exports.liveChannelMembers = liveChannelMembers;
29319
29924
  exports.liveChannels = liveChannels;
29925
+ exports.liveComment = liveComment;
29320
29926
  exports.liveComments = liveComments;
29927
+ exports.liveCommunities = liveCommunities;
29321
29928
  exports.liveFollowers = liveFollowers;
29322
29929
  exports.liveFollowings = liveFollowings;
29323
29930
  exports.liveMessage = liveMessage;
29324
29931
  exports.liveMessages = liveMessages;
29932
+ exports.livePost = livePost;
29325
29933
  exports.livePosts = livePosts;
29326
29934
  exports.liveReactions = liveReactions;
29327
29935
  exports.liveSubChannel = liveSubChannel;
@@ -29369,6 +29977,7 @@ exports.onCommunityLeft = onCommunityLeft;
29369
29977
  exports.onCommunityUpdated = onCommunityUpdated;
29370
29978
  exports.onCommunityUserAdded = onCommunityUserAdded;
29371
29979
  exports.onCommunityUserBanned = onCommunityUserBanned;
29980
+ exports.onCommunityUserChanged = onCommunityUserChanged;
29372
29981
  exports.onCommunityUserRemoved = onCommunityUserRemoved;
29373
29982
  exports.onCommunityUserUnbanned = onCommunityUserUnbanned;
29374
29983
  exports.onConnectionError = onConnectionError;
@@ -29401,6 +30010,7 @@ exports.onReactionAdded = onReactionAdded;
29401
30010
  exports.onReactionRemoved = onReactionRemoved;
29402
30011
  exports.onReactorAdded = onReactorAdded;
29403
30012
  exports.onReactorRemoved = onReactorRemoved;
30013
+ exports.onSessionStateChange = onSessionStateChange;
29404
30014
  exports.onStreamRecorded = onStreamRecorded;
29405
30015
  exports.onStreamStarted = onStreamStarted;
29406
30016
  exports.onStreamStopped = onStreamStopped;
@@ -29439,6 +30049,7 @@ exports.removeChannelMembersRole = removeChannelMembersRole;
29439
30049
  exports.removeCommunityMembers = removeCommunityMembers;
29440
30050
  exports.removeCommunityMembersRoles = removeCommunityMembersRoles;
29441
30051
  exports.removeReaction = removeReaction;
30052
+ exports.renewal = renewal;
29442
30053
  exports.restoreCache = restoreCache;
29443
30054
  exports.runQuery = runQuery;
29444
30055
  exports.sortByChannelSegment = sortByChannelSegment;
@@ -29446,6 +30057,7 @@ exports.sortByDisplayName = sortByDisplayName;
29446
30057
  exports.sortByFirstCreated = sortByFirstCreated;
29447
30058
  exports.sortByLastActivity = sortByLastActivity;
29448
30059
  exports.sortByLastCreated = sortByLastCreated;
30060
+ exports.sortByName = sortByName;
29449
30061
  exports.sortBySegmentNumber = sortBySegmentNumber;
29450
30062
  exports.startReading = startReading;
29451
30063
  exports.stopReading = stopReading;