@amityco/ts-sdk 0.0.1-beta.8 → 0.0.1-beta.9

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 (244) hide show
  1. package/dist/@types/core/events.d.ts +63 -17
  2. package/dist/@types/core/events.d.ts.map +1 -1
  3. package/dist/@types/core/transport.d.ts +15 -0
  4. package/dist/@types/core/transport.d.ts.map +1 -1
  5. package/dist/@types/domains/client.d.ts +3 -0
  6. package/dist/@types/domains/client.d.ts.map +1 -1
  7. package/dist/@types/domains/comment.d.ts +1 -1
  8. package/dist/@types/domains/comment.d.ts.map +1 -1
  9. package/dist/@types/domains/community.d.ts +1 -1
  10. package/dist/@types/domains/community.d.ts.map +1 -1
  11. package/dist/@types/domains/group.d.ts +2 -2
  12. package/dist/@types/domains/group.d.ts.map +1 -1
  13. package/dist/@types/domains/partials.d.ts +3 -0
  14. package/dist/@types/domains/partials.d.ts.map +1 -1
  15. package/dist/@types/domains/post.d.ts +1 -1
  16. package/dist/@types/domains/post.d.ts.map +1 -1
  17. package/dist/@types/domains/user.d.ts +2 -1
  18. package/dist/@types/domains/user.d.ts.map +1 -1
  19. package/dist/client/api/connectClient.d.ts.map +1 -1
  20. package/dist/client/api/createClient.d.ts +2 -1
  21. package/dist/client/api/createClient.d.ts.map +1 -1
  22. package/dist/client/api/disconnectClient.d.ts.map +1 -1
  23. package/dist/client/api/getToken.d.ts +3 -1
  24. package/dist/client/api/getToken.d.ts.map +1 -1
  25. package/dist/comment/api/deleteComment.d.ts +1 -0
  26. package/dist/comment/api/deleteComment.d.ts.map +1 -1
  27. package/dist/comment/events/index.d.ts +4 -0
  28. package/dist/comment/events/index.d.ts.map +1 -1
  29. package/dist/comment/events/onCommentCreated.d.ts +1 -1
  30. package/dist/comment/events/onCommentCreated.d.ts.map +1 -1
  31. package/dist/comment/events/onCommentDeleted.d.ts +1 -1
  32. package/dist/comment/events/onCommentDeleted.d.ts.map +1 -1
  33. package/dist/comment/events/onCommentFlagged.d.ts +17 -0
  34. package/dist/comment/events/onCommentFlagged.d.ts.map +1 -0
  35. package/dist/comment/events/onCommentReactionAdded.d.ts +17 -0
  36. package/dist/comment/events/onCommentReactionAdded.d.ts.map +1 -0
  37. package/dist/comment/events/onCommentReactionRemoved.d.ts +17 -0
  38. package/dist/comment/events/onCommentReactionRemoved.d.ts.map +1 -0
  39. package/dist/comment/events/onCommentUnflagged.d.ts +17 -0
  40. package/dist/comment/events/onCommentUnflagged.d.ts.map +1 -0
  41. package/dist/comment/events/onCommentUpdated.d.ts +1 -1
  42. package/dist/comment/events/onCommentUpdated.d.ts.map +1 -1
  43. package/dist/comment/events/utils.d.ts +2 -0
  44. package/dist/comment/events/utils.d.ts.map +1 -0
  45. package/dist/comment/observers/observeComment.d.ts +1 -1
  46. package/dist/comment/observers/observeComment.d.ts.map +1 -1
  47. package/dist/comment/observers/observeComments.d.ts +5 -1
  48. package/dist/comment/observers/observeComments.d.ts.map +1 -1
  49. package/dist/community/events/index.d.ts +4 -0
  50. package/dist/community/events/index.d.ts.map +1 -1
  51. package/dist/community/events/onCommunityCreated.d.ts +2 -2
  52. package/dist/community/events/onCommunityCreated.d.ts.map +1 -1
  53. package/dist/community/events/onCommunityDeleted.d.ts +2 -2
  54. package/dist/community/events/onCommunityDeleted.d.ts.map +1 -1
  55. package/dist/community/events/onCommunityJoined.d.ts +3 -3
  56. package/dist/community/events/onCommunityJoined.d.ts.map +1 -1
  57. package/dist/community/events/onCommunityLeft.d.ts +3 -3
  58. package/dist/community/events/onCommunityLeft.d.ts.map +1 -1
  59. package/dist/community/events/onCommunityUpdated.d.ts +2 -2
  60. package/dist/community/events/onCommunityUpdated.d.ts.map +1 -1
  61. package/dist/community/events/onCommunityUserAdded.d.ts +17 -0
  62. package/dist/community/events/onCommunityUserAdded.d.ts.map +1 -0
  63. package/dist/community/events/onCommunityUserBanned.d.ts +17 -0
  64. package/dist/community/events/onCommunityUserBanned.d.ts.map +1 -0
  65. package/dist/community/events/onCommunityUserRemoved.d.ts +17 -0
  66. package/dist/community/events/onCommunityUserRemoved.d.ts.map +1 -0
  67. package/dist/community/events/onCommunityUserUnbanned.d.ts +17 -0
  68. package/dist/community/events/onCommunityUserUnbanned.d.ts.map +1 -0
  69. package/dist/community/events/utils.d.ts +3 -0
  70. package/dist/community/events/utils.d.ts.map +1 -0
  71. package/dist/community/observers/observeCommunity.d.ts +1 -1
  72. package/dist/community/observers/observeCommunity.d.ts.map +1 -1
  73. package/dist/core/cache/ingest.d.ts.map +1 -1
  74. package/dist/core/events.d.ts +4 -2
  75. package/dist/core/events.d.ts.map +1 -1
  76. package/dist/core/model/index.d.ts +1 -0
  77. package/dist/core/model/index.d.ts.map +1 -1
  78. package/dist/core/model/isMatch.d.ts +3 -0
  79. package/dist/core/model/isMatch.d.ts.map +1 -0
  80. package/dist/core/network.d.ts +11 -0
  81. package/dist/core/network.d.ts.map +1 -0
  82. package/dist/core/subscription.d.ts +14 -0
  83. package/dist/core/subscription.d.ts.map +1 -0
  84. package/dist/core/transports/http.d.ts +11 -0
  85. package/dist/core/transports/http.d.ts.map +1 -0
  86. package/dist/core/transports/index.d.ts +4 -0
  87. package/dist/core/transports/index.d.ts.map +1 -0
  88. package/dist/core/transports/mqtt.d.ts +17 -0
  89. package/dist/core/transports/mqtt.d.ts.map +1 -0
  90. package/dist/core/transports/utils.d.ts +13 -0
  91. package/dist/core/transports/utils.d.ts.map +1 -0
  92. package/dist/core/transports/ws.d.ts +27 -0
  93. package/dist/core/transports/ws.d.ts.map +1 -0
  94. package/dist/index.cjs.js +1208 -514
  95. package/dist/index.d.ts +1 -0
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.esm.js +1185 -515
  98. package/dist/index.umd.js +5 -3
  99. package/dist/post/api/deletePost.d.ts +1 -0
  100. package/dist/post/api/deletePost.d.ts.map +1 -1
  101. package/dist/post/events/index.d.ts +6 -0
  102. package/dist/post/events/index.d.ts.map +1 -1
  103. package/dist/post/events/onPostApproved.d.ts +17 -0
  104. package/dist/post/events/onPostApproved.d.ts.map +1 -0
  105. package/dist/post/events/onPostCreated.d.ts +1 -1
  106. package/dist/post/events/onPostCreated.d.ts.map +1 -1
  107. package/dist/post/events/onPostDeclined.d.ts +17 -0
  108. package/dist/post/events/onPostDeclined.d.ts.map +1 -0
  109. package/dist/post/events/onPostDeleted.d.ts +1 -1
  110. package/dist/post/events/onPostDeleted.d.ts.map +1 -1
  111. package/dist/post/events/onPostFlagged.d.ts +17 -0
  112. package/dist/post/events/onPostFlagged.d.ts.map +1 -0
  113. package/dist/post/events/onPostReactionAdded.d.ts +17 -0
  114. package/dist/post/events/onPostReactionAdded.d.ts.map +1 -0
  115. package/dist/post/events/onPostReactionRemoved.d.ts +17 -0
  116. package/dist/post/events/onPostReactionRemoved.d.ts.map +1 -0
  117. package/dist/post/events/onPostUnflagged.d.ts +17 -0
  118. package/dist/post/events/onPostUnflagged.d.ts.map +1 -0
  119. package/dist/post/events/onPostUpdated.d.ts +1 -1
  120. package/dist/post/events/onPostUpdated.d.ts.map +1 -1
  121. package/dist/post/events/utils.d.ts +2 -0
  122. package/dist/post/events/utils.d.ts.map +1 -0
  123. package/dist/post/observers/observePost.d.ts +1 -1
  124. package/dist/post/observers/observePost.d.ts.map +1 -1
  125. package/dist/post/observers/observePosts.d.ts +1 -1
  126. package/dist/post/observers/observePosts.d.ts.map +1 -1
  127. package/dist/reaction/events/onReactionAdded.d.ts +4 -2
  128. package/dist/reaction/events/onReactionAdded.d.ts.map +1 -1
  129. package/dist/reaction/events/onReactionRemoved.d.ts +4 -2
  130. package/dist/reaction/events/onReactionRemoved.d.ts.map +1 -1
  131. package/dist/reaction/utils/index.d.ts +1 -0
  132. package/dist/reaction/utils/index.d.ts.map +1 -1
  133. package/dist/reaction/utils/preparePayloadForCache.d.ts +3 -0
  134. package/dist/reaction/utils/preparePayloadForCache.d.ts.map +1 -0
  135. package/dist/report/api/createReport.d.ts.map +1 -1
  136. package/dist/report/api/deleteReport.d.ts.map +1 -1
  137. package/dist/user/events/index.d.ts +3 -0
  138. package/dist/user/events/index.d.ts.map +1 -1
  139. package/dist/user/events/onUserFlagCleared.d.ts +17 -0
  140. package/dist/user/events/onUserFlagCleared.d.ts.map +1 -0
  141. package/dist/user/events/onUserFlagged.d.ts +17 -0
  142. package/dist/user/events/onUserFlagged.d.ts.map +1 -0
  143. package/dist/user/events/onUserUnflagged.d.ts +17 -0
  144. package/dist/user/events/onUserUnflagged.d.ts.map +1 -0
  145. package/dist/user/events/onUserUpdated.d.ts +1 -1
  146. package/dist/user/events/onUserUpdated.d.ts.map +1 -1
  147. package/dist/user/events/utils.d.ts +2 -0
  148. package/dist/user/events/utils.d.ts.map +1 -0
  149. package/dist/user/observers/observeUser.d.ts +1 -1
  150. package/dist/user/observers/observeUser.d.ts.map +1 -1
  151. package/package.json +4 -1
  152. package/rollup.config.js +2 -2
  153. package/src/@types/core/events.ts +64 -23
  154. package/src/@types/core/transport.ts +14 -0
  155. package/src/@types/domains/client.ts +3 -0
  156. package/src/@types/domains/comment.ts +1 -0
  157. package/src/@types/domains/community.ts +1 -0
  158. package/src/@types/domains/group.ts +2 -2
  159. package/src/@types/domains/partials.ts +4 -0
  160. package/src/@types/domains/post.ts +1 -0
  161. package/src/@types/domains/user.ts +2 -0
  162. package/src/client/api/connectClient.ts +12 -2
  163. package/src/client/api/createClient.ts +7 -7
  164. package/src/client/api/disconnectClient.ts +5 -0
  165. package/src/client/api/getToken.ts +1 -1
  166. package/src/client/events/onConnectionError.ts +1 -1
  167. package/src/comment/api/createComment.ts +2 -2
  168. package/src/comment/api/deleteComment.ts +2 -2
  169. package/src/comment/api/updateComment.ts +1 -1
  170. package/src/comment/events/index.ts +6 -0
  171. package/src/comment/events/onCommentCreated.ts +4 -22
  172. package/src/comment/events/onCommentDeleted.ts +4 -22
  173. package/src/comment/events/onCommentFlagged.ts +21 -0
  174. package/src/comment/events/onCommentReactionAdded.ts +52 -0
  175. package/src/comment/events/onCommentReactionRemoved.ts +52 -0
  176. package/src/comment/events/onCommentUnflagged.ts +21 -0
  177. package/src/comment/events/onCommentUpdated.ts +4 -22
  178. package/src/comment/events/utils.ts +34 -0
  179. package/src/comment/observers/observeComment.ts +21 -7
  180. package/src/comment/observers/observeComments.ts +11 -3
  181. package/src/community/api/addCommunityMembers.ts +1 -1
  182. package/src/community/api/createCommunity.ts +1 -1
  183. package/src/community/api/deleteCommunity.ts +1 -1
  184. package/src/community/api/joinCommunity.ts +1 -1
  185. package/src/community/api/leaveCommunity.ts +1 -1
  186. package/src/community/api/removeCommunityMembers.ts +1 -1
  187. package/src/community/api/updateCommunity.ts +1 -1
  188. package/src/community/events/index.ts +5 -0
  189. package/src/community/events/onCommunityCreated.ts +5 -23
  190. package/src/community/events/onCommunityDeleted.ts +5 -23
  191. package/src/community/events/onCommunityJoined.ts +5 -23
  192. package/src/community/events/onCommunityLeft.ts +5 -23
  193. package/src/community/events/onCommunityUpdated.ts +5 -23
  194. package/src/community/events/onCommunityUserAdded.ts +19 -0
  195. package/src/community/events/onCommunityUserBanned.ts +19 -0
  196. package/src/community/events/onCommunityUserRemoved.ts +19 -0
  197. package/src/community/events/onCommunityUserUnbanned.ts +19 -0
  198. package/src/community/events/utils.ts +108 -0
  199. package/src/community/observers/observeCommunity.ts +23 -9
  200. package/src/core/cache/ingest.ts +19 -3
  201. package/src/core/events.ts +45 -4
  202. package/src/core/model/index.ts +1 -0
  203. package/src/core/model/isMatch.ts +12 -0
  204. package/src/core/network.ts +14 -0
  205. package/src/core/subscription.ts +75 -0
  206. package/src/core/transports/http.ts +63 -0
  207. package/src/core/transports/index.ts +3 -0
  208. package/src/core/transports/mqtt.ts +141 -0
  209. package/src/core/transports/utils.ts +25 -0
  210. package/src/core/transports/ws.ts +61 -0
  211. package/src/index.ts +1 -0
  212. package/src/post/api/createPost.ts +2 -2
  213. package/src/post/api/deletePost.ts +2 -2
  214. package/src/post/api/updatePost.ts +1 -1
  215. package/src/post/events/index.ts +9 -0
  216. package/src/post/events/onPostApproved.ts +19 -0
  217. package/src/post/events/onPostCreated.ts +4 -24
  218. package/src/post/events/onPostDeclined.ts +19 -0
  219. package/src/post/events/onPostDeleted.ts +4 -24
  220. package/src/post/events/onPostFlagged.ts +19 -0
  221. package/src/post/events/onPostReactionAdded.ts +50 -0
  222. package/src/post/events/onPostReactionRemoved.ts +50 -0
  223. package/src/post/events/onPostUnflagged.ts +19 -0
  224. package/src/post/events/onPostUpdated.ts +4 -24
  225. package/src/post/events/utils.ts +40 -0
  226. package/src/post/observers/observePost.ts +25 -7
  227. package/src/post/observers/observePosts.ts +12 -2
  228. package/src/reaction/events/onReactionAdded.ts +36 -15
  229. package/src/reaction/events/onReactionRemoved.ts +37 -14
  230. package/src/reaction/utils/dispatchReactable.ts +2 -2
  231. package/src/reaction/utils/index.ts +1 -0
  232. package/src/reaction/utils/preparePayloadForCache.ts +45 -0
  233. package/src/report/api/createReport.ts +5 -1
  234. package/src/report/api/deleteReport.ts +5 -1
  235. package/src/user/events/index.ts +4 -0
  236. package/src/user/events/onUserFlagCleared.ts +19 -0
  237. package/src/user/events/onUserFlagged.ts +19 -0
  238. package/src/user/events/onUserUnflagged.ts +19 -0
  239. package/src/user/events/onUserUpdated.ts +4 -24
  240. package/src/user/events/utils.ts +24 -0
  241. package/src/user/observers/observeUser.ts +11 -3
  242. package/dist/core/transports.d.ts +0 -49
  243. package/dist/core/transports.d.ts.map +0 -1
  244. package/src/core/transports.ts +0 -151
@@ -3,15 +3,13 @@ import mitt from 'mitt'
3
3
  import { getActiveClient } from '~/client/api/activeClient'
4
4
 
5
5
  // need to sync up the list
6
- const EVENTS = [
6
+ const WS_EVENTS = [
7
7
  'disconnected',
8
8
  'error',
9
9
  'connect_error',
10
10
  'reconnect_error',
11
11
  'reconnect_failed',
12
12
 
13
- 'v3.user.didUpdate',
14
-
15
13
  'v3.channel.didUpdate',
16
14
  'v3.channel.didUpdate',
17
15
  'v3.channel.didJoin',
@@ -26,6 +24,16 @@ const EVENTS = [
26
24
  'v3.message.didDelete',
27
25
  ] as const
28
26
 
27
+ const MQTT_EVENTS = [
28
+ 'connect',
29
+ 'message',
30
+ 'disconnect',
31
+ 'error',
32
+ 'close',
33
+ 'end',
34
+ 'reconnect'
35
+ ] as const;
36
+
29
37
  /** @hidden */
30
38
  export const createEventEmitter = () => {
31
39
  return mitt<Amity.Events>()
@@ -42,11 +50,24 @@ export const createEventEmitter = () => {
42
50
  * @hidden
43
51
  */
44
52
  export const proxyWebsocketEvents = (ws: Amity.Client['ws'], emitter: Amity.Client['emitter']) => {
45
- EVENTS.forEach(event => {
53
+ WS_EVENTS.forEach(event => {
46
54
  ws.on(event, (param: Amity.Events[typeof event]) => emitter.emit(event, param))
47
55
  })
48
56
  }
49
57
 
58
+ export const proxyMqttEvents = (mqttClient: Amity.Client['mqtt'], emitter: Amity.Client['emitter']) => {
59
+ MQTT_EVENTS.forEach(event => {
60
+ mqttClient.on(event, (...params: any[]) => emitter.emit(event, params.length === 1 ? params[0] : params))
61
+ })
62
+
63
+ // @ts-ignore
64
+ mqttClient.on('message', (topic: string, payload: Buffer) => {
65
+ const message = JSON.parse(payload.toString());
66
+
67
+ emitter.emit(message.eventType, message.data)
68
+ })
69
+ }
70
+
50
71
  /**
51
72
  * Standardize the subscription of SSE through web sockets
52
73
  *
@@ -83,6 +104,26 @@ export const createEventSubscriber = <T extends keyof Amity.Events>(
83
104
  }
84
105
  }
85
106
 
107
+ export const createMqttMessageSubscriber = <T extends keyof Amity.Events>(
108
+ client: Amity.Client,
109
+ namespace: string,
110
+ event: string,
111
+ fn: (params: Object) => void,
112
+ ): Amity.Unsubscriber => {
113
+ return createEventSubscriber(
114
+ client,
115
+ namespace,
116
+ 'message',
117
+ ([topic, message]) => {
118
+ const payload = JSON.parse(message.toString());
119
+
120
+ if (payload.eventType === event) {
121
+ fn(payload.data);
122
+ }
123
+ }
124
+ )
125
+ }
126
+
86
127
  /**
87
128
  * Wrapper around dispatch event
88
129
  *
@@ -1,3 +1,4 @@
1
1
  export * from './identifyModel'
2
2
  export * from './idResolvers'
3
3
  export * from './toRecord'
4
+ export * from './isMatch'
@@ -0,0 +1,12 @@
1
+ import isMatchWith from 'lodash.ismatchwith'
2
+
3
+ /** @hidden */
4
+ export const isMatch =<T extends Amity.Domain>(model1: Amity.Model[T], model2: Amity.Model[T]) => {
5
+ const customizer = (oldValue: any, newValue: any, key: string | number | symbol) => {
6
+ if (key === 'syncedAt') {
7
+ return true
8
+ }
9
+ }
10
+
11
+ return isMatchWith(model1, model2, customizer)
12
+ }
@@ -0,0 +1,14 @@
1
+ export const API_ENDPOINT = {
2
+ EU: 'eu',
3
+ SG: 'sg',
4
+ US: 'us',
5
+ } as const
6
+
7
+ export enum UrlTemplate {
8
+ HTTP = 'https://api.{region}.amity.co',
9
+ MQTT = 'wss://sse.{region}.amity.co:443/mqtt',
10
+ }
11
+
12
+ export const getUrlFromTemplate = ( template: UrlTemplate, region: string ) => {
13
+ return template.replace( '{region}', region);
14
+ }
@@ -0,0 +1,75 @@
1
+ import { getActiveClient } from '~/client/api'
2
+ import { ASCError } from '~/core/errors'
3
+ import { proxyMqttEvents } from '~/core/events'
4
+
5
+ export enum SubscriptionLevels {
6
+ COMMUNITY = 'community',
7
+ POST = 'post',
8
+ COMMENT = 'comment',
9
+ POST_AND_COMMENT = 'post_and_comment',
10
+ USER = 'user',
11
+ }
12
+
13
+ const getCommunityUserTopic = (
14
+ { path }: Amity.Subscribable,
15
+ level?: SubscriptionLevels,
16
+ ): string => {
17
+ switch (level) {
18
+ case 'post':
19
+ return `${path}/post/+`;
20
+ case 'comment':
21
+ return `${path}/post/+/comment/+`;
22
+ case 'post_and_comment':
23
+ return `${path}/post/#`;
24
+ default:
25
+ return path;
26
+ }
27
+ };
28
+
29
+ export const getCommunityTopic = (
30
+ { path }: Amity.Subscribable,
31
+ level: Exclude<SubscriptionLevels, SubscriptionLevels.USER> = SubscriptionLevels.COMMUNITY,
32
+ ): string =>
33
+ getCommunityUserTopic({ path }, level)
34
+
35
+ export const getUserTopic = (
36
+ { path }: Amity.Subscribable,
37
+ level: Exclude<SubscriptionLevels, SubscriptionLevels.COMMUNITY> = SubscriptionLevels.USER,
38
+ ): string =>
39
+ getCommunityUserTopic({ path }, level)
40
+
41
+ export const getPostTopic = (
42
+ { path }: Amity.Subscribable,
43
+ level: SubscriptionLevels.POST | SubscriptionLevels.COMMENT = SubscriptionLevels.POST
44
+ ): string => {
45
+ switch (level) {
46
+ case 'comment':
47
+ return `${path}/comment/+`;
48
+ default:
49
+ return path;
50
+ }
51
+ };
52
+
53
+ export const getCommentTopic = ({ path }: Amity.Subscribable): string => {
54
+ return path;
55
+ };
56
+
57
+ let mqttAccessToken: string;
58
+ let mqttUserId: string;
59
+
60
+ export function subscribeTopic(
61
+ topic: string,
62
+ callback?: Amity.Listener<ASCError | void>
63
+ ): Amity.Unsubscriber {
64
+ const { mqtt, emitter, accessToken, user } = getActiveClient()
65
+
66
+ if (mqttAccessToken !== accessToken || mqttUserId !== user!._id) {
67
+ mqttAccessToken = accessToken!
68
+ mqttUserId = user!._id
69
+
70
+ mqtt.connect({ accessToken: accessToken!, userId: user!._id })
71
+ proxyMqttEvents(mqtt, emitter)
72
+ }
73
+
74
+ return mqtt.subscribe(topic, callback)
75
+ }
@@ -0,0 +1,63 @@
1
+ import axios from 'axios'
2
+ import HttpAgent, { HttpsAgent } from 'agentkeepalive'
3
+
4
+ import { unwrapPayload } from './utils'
5
+
6
+ /**
7
+ * Axios param serializer (for querystring)
8
+ * @hidden
9
+ */
10
+ const stringify = (params: object, prefix?: string): string => {
11
+ return Object.entries(params)
12
+ .filter(([, value]) => value !== undefined)
13
+ .map(([name, value]) => {
14
+ const key = prefix ? `${prefix}[${name}]` : name
15
+
16
+ if (Array.isArray(value)) {
17
+ return value.map(item => `${key}[]=${item}`).join('&')
18
+ } else if (typeof value !== 'object') {
19
+ return `${key}=${value}`
20
+ }
21
+
22
+ return stringify(value, prefix ?? name)
23
+ })
24
+ .join('&')
25
+ }
26
+
27
+ /**
28
+ * Creates a pre-configured axios instance
29
+ *
30
+ * @param endpoint The ASC rest api server's URL
31
+ * @returns A pre-configured axios instance
32
+ *
33
+ * @category Transport
34
+ * @hidden
35
+ */
36
+ export const createHttpTransport = (endpoint: string) => {
37
+ const options = {
38
+ maxSockets: 100,
39
+ maxFreeSockets: 10,
40
+ timeout: 60000,
41
+ freeSocketTimeout: 30000,
42
+ }
43
+
44
+ const instance = axios.create({
45
+ baseURL: endpoint,
46
+ httpAgent: new HttpAgent(options),
47
+ httpsAgent: new HttpsAgent(options),
48
+ paramsSerializer: stringify,
49
+ })
50
+
51
+ instance.interceptors.response.use(
52
+ (response) => response,
53
+ (error) => {
54
+ const { response } = error
55
+ console.error(response?.data ?? error)
56
+
57
+ if (response)
58
+ unwrapPayload(response.data)
59
+ }
60
+ )
61
+
62
+ return instance
63
+ }
@@ -0,0 +1,3 @@
1
+ export * from './http';
2
+ export * from './ws';
3
+ export * from './mqtt';
@@ -0,0 +1,141 @@
1
+ import mqtt, { MqttClient, IClientOptions, ISubscriptionGrant } from 'mqtt'
2
+ import { ASCError, ASCUnknownError } from '~/core/errors'
3
+
4
+ const QOS_FAILURE_CODE = 128
5
+
6
+ const RETRY_BASE_TIMEOUT = 1000;
7
+ const RETRY_COUNT_MAX = 10;
8
+
9
+ const enum MqttError {
10
+ IDENTIFIER_REJECTED = 2,
11
+ BAD_USERNAME_OR_PASSWORD = 4,
12
+ NOT_AUTHORIZED = 5,
13
+ }
14
+
15
+ export function getMqttOptions(params: { username: string, password: string, clientId?: string }): IClientOptions {
16
+ return {
17
+ clean: false, // keep subscriptions
18
+ clientId: `mqttjs_ + ${Math.random().toString(16).substr(2, 8)}`,
19
+ protocolId: 'MQTT',
20
+ protocolVersion: 4,
21
+ reconnectPeriod: 0, // disable auto reconnect
22
+ will: {
23
+ topic: 'WillMsg',
24
+ payload: 'Connection Closed abnormally..!',
25
+ qos: 0,
26
+ retain: false
27
+ },
28
+
29
+ ...params
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Creates a pre-configured socket.io instance
35
+ *
36
+ * @param endpoint The mqtt server's URL
37
+ * @returns A pre-configured (non-connected) mqtt client instance
38
+ *
39
+ * @category Transport
40
+ * @hidden
41
+ */
42
+ export const createMqttTransport = (endpoint: string): Amity.MqttClient => {
43
+ let mqttClient: MqttClient | void;
44
+ let retryCount = 0
45
+ let allowReconnection = true
46
+
47
+ async function connect(params: { accessToken: string, userId: string }): Promise<void> {
48
+ if (mqttClient) {
49
+ mqttClient.removeAllListeners();
50
+ mqttClient.end(true)
51
+ }
52
+
53
+ mqttClient = mqtt.connect(endpoint, getMqttOptions({ username: params.userId, password: params.accessToken }))
54
+
55
+ mqttClient.on('connect', () => {
56
+ retryCount = 0
57
+ allowReconnection = true
58
+ })
59
+
60
+ mqttClient.on('error', (error: Error & { code: number }) => {
61
+ switch (error.code) {
62
+ case MqttError.IDENTIFIER_REJECTED:
63
+ case MqttError.BAD_USERNAME_OR_PASSWORD:
64
+ case MqttError.NOT_AUTHORIZED:
65
+ allowReconnection = false
66
+ }
67
+ })
68
+
69
+ mqttClient.on('close', () => {
70
+ if (allowReconnection) {
71
+ reconnect()
72
+ }
73
+ })
74
+
75
+ return new Promise(resolve => mqttClient!.once('connect', () => resolve()))
76
+ }
77
+
78
+ const reconnect = () => {
79
+ setTimeout(() => {
80
+ retryCount = retryCount + 1
81
+ mqttClient!.reconnect()
82
+ }, RETRY_BASE_TIMEOUT * Math.pow(2, retryCount > RETRY_COUNT_MAX ? RETRY_COUNT_MAX : retryCount))
83
+ }
84
+
85
+ return {
86
+ connect,
87
+ async disconnect(): Promise<void> {
88
+ allowReconnection = false
89
+
90
+ if (this.connected) {
91
+ return new Promise(resolve => mqttClient?.end(true, undefined, () => resolve()))
92
+ }
93
+ },
94
+ get connected() {
95
+ return !!mqttClient?.connected
96
+ },
97
+ on<T extends keyof Amity.MqttEvents>(event: T, handler: (payload: Amity.MqttEvents[T]) => void) {
98
+ mqttClient?.on(event, handler)
99
+ },
100
+ once<T extends keyof Amity.MqttEvents>(event: T, handler: (payload: Amity.MqttEvents[T]) => void) {
101
+ mqttClient?.once(event, handler)
102
+ },
103
+ off<T extends keyof Amity.MqttEvents>(event: T, handler?: (payload: Amity.MqttEvents[T]) => void) {
104
+ if (handler !== undefined) {
105
+ mqttClient?.off(event, handler)
106
+ } else {
107
+ mqttClient?.removeAllListeners(event)
108
+ }
109
+ },
110
+ removeAllListeners() {
111
+ mqttClient?.removeAllListeners()
112
+ },
113
+ subscribe(topic: string, callback?: Amity.Listener<ASCError | void>): Amity.Unsubscriber {
114
+ const callbackWrapper = (error: Error, granted: ISubscriptionGrant[]) => {
115
+ if (error || granted[0].qos === QOS_FAILURE_CODE) {
116
+ const ascError = error
117
+ ? new ASCError(error.message, Amity.ClientError.UNKNOWN_ERROR, Amity.ErrorLevel.ERROR)
118
+ // TODO throw the actual error, once BE can tell us the actual error code
119
+ : new ASCUnknownError(Amity.ClientError.UNKNOWN_ERROR, Amity.ErrorLevel.ERROR)
120
+
121
+ console.error(`Failed to subscribe to topic ${topic}`, ascError)
122
+ callback?.(ascError)
123
+ } else {
124
+ console.log(`Subscribed to topic ${granted[0].topic}`)
125
+ callback?.()
126
+ }
127
+ }
128
+
129
+ if (mqttClient) {
130
+ mqttClient.subscribe(topic, { qos: 0 }, callbackWrapper)
131
+ } else {
132
+ callbackWrapper(new Error('No connection to broker'), []);
133
+ }
134
+
135
+ return () => mqttClient?.unsubscribe(topic)
136
+ },
137
+ unsubscribe(topic: string) {
138
+ mqttClient?.unsubscribe(topic)
139
+ }
140
+ }
141
+ }
@@ -0,0 +1,25 @@
1
+ import { ASCApiError, ASCUnknownError } from '~/core/errors'
2
+
3
+ /**
4
+ * Unwraps v3 server payload (for error handling and type extraction)
5
+ *
6
+ * @param response A typical "v3" response (related to backend's service strategy)
7
+ *
8
+ * @returns The data returned by the backend
9
+ * @throws An error related to backend's rejection
10
+ *
11
+ * @category Transport
12
+ * @hidden
13
+ */
14
+ export const unwrapPayload = <T>(response: Amity.Response<T>): T => {
15
+ if (response.status === 'success') {
16
+ return response.data
17
+ } else if (response.status === 'fail') {
18
+ throw new ASCUnknownError(response.code)
19
+ } else if (response.status === 'error') {
20
+ throw new ASCApiError(response.message, response.code, Amity.ErrorLevel.ERROR)
21
+ }
22
+
23
+ // unjust, but helps force uncast "T | undefined" to allow deconstruction without warnings
24
+ return undefined as unknown as T
25
+ }
@@ -0,0 +1,61 @@
1
+ import io from 'socket.io-client'
2
+ import { unwrapPayload } from './utils'
3
+
4
+ /**
5
+ * Creates a pre-configured socket.io instance
6
+ *
7
+ * @param endpoint The socket.io server's URL
8
+ * @returns A pre-configured (non-connected) socket.io client instance
9
+ *
10
+ * @category Transport
11
+ * @hidden
12
+ */
13
+ export const createWebsocketTransport = (endpoint: string) => {
14
+ const socket = io(endpoint, {
15
+ autoConnect: false,
16
+ reconnectionDelay: 2000,
17
+ transports: ['websocket'],
18
+ })
19
+
20
+ // FIXME: disconnectClient removes this listener and client can get global ban event
21
+ socket.on('disconnect', (reason: string) => {
22
+ if (reason === 'io server disconnect')
23
+ socket.connect()
24
+ })
25
+
26
+ return socket
27
+ }
28
+
29
+ /**
30
+ * Promisify a websocket event emission - resulting in a synchronous http-like XHR (ws legacy)
31
+ *
32
+ * @param client The current client for which to send the event with
33
+ * @param event The websocket event name
34
+ * @param data The event's payload
35
+ *
36
+ * @returns The data returned by the backend
37
+ * @throws An error related to backend's rejection
38
+ *
39
+ * @category Transport
40
+ * @async
41
+ * @hidden
42
+ */
43
+ export const synchronousWSCall = async <T>(
44
+ client: Amity.Client,
45
+ event: string,
46
+ data?: Object,
47
+ )=> {
48
+ const { ws } = client
49
+
50
+ const value = await new Promise<T | undefined>((resolve, reject) => {
51
+ ws.emit(event, data, (response: Amity.Response<T>) => {
52
+ try {
53
+ resolve(unwrapPayload(response))
54
+ } catch (error) {
55
+ reject(error)
56
+ }
57
+ })
58
+ })
59
+
60
+ return value
61
+ }
package/src/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from './version'
7
7
  export * from './core/query'
8
8
  export * from './core/cache'
9
9
  export * from './core/stores'
10
+ export * from './core/subscription'
10
11
 
11
12
  export * from './client/api'
12
13
  export * from './client/events'
@@ -41,8 +41,8 @@ export const createPost = async <T extends Amity.PostContentType | string>(
41
41
  decoratePayload(data)
42
42
  ingestInCache(data)
43
43
 
44
- fireEvent('v3.community.didUpdate', { communities: data.communities! })
45
- fireEvent('v3.post.didCreate', data)
44
+ fireEvent('community.updated', { communities: data.communities! })
45
+ fireEvent('post.created', data)
46
46
 
47
47
  const { posts } = data
48
48
  return posts[0]
@@ -44,13 +44,13 @@ export const deletePost = async (
44
44
  // later when realtime events covers that for us.
45
45
  if (post.targetType === 'community') {
46
46
  const community = await getCommunity(post.targetId);
47
- fireEvent('v3.community.didUpdate', { communities: [community] })
47
+ fireEvent('community.updated', { communities: [community] })
48
48
  }
49
49
 
50
50
  // to support hard deletion
51
51
  const deleted = { ...post, isDeleted: true }
52
52
 
53
- fireEvent('v3.post.didDelete', { posts: [deleted] })
53
+ fireEvent('post.deleted', { posts: [deleted] })
54
54
 
55
55
  if (permanent) {
56
56
  setTimeout(() => {
@@ -35,7 +35,7 @@ export const updatePost = async (
35
35
  decoratePayload(data)
36
36
  ingestInCache(data)
37
37
 
38
- fireEvent('v3.post.didUpdate', data)
38
+ fireEvent('post.updated', data)
39
39
 
40
40
  const { posts } = data
41
41
  return posts.find(post => post.postId === postId)!
@@ -1,3 +1,12 @@
1
1
  export * from './onPostCreated'
2
2
  export * from './onPostUpdated'
3
3
  export * from './onPostDeleted'
4
+
5
+ export * from './onPostApproved'
6
+ export * from './onPostDeclined'
7
+
8
+ export * from './onPostFlagged'
9
+ export * from './onPostUnflagged'
10
+
11
+ export * from './onPostReactionAdded'
12
+ export * from './onPostReactionRemoved'
@@ -0,0 +1,19 @@
1
+ import { createPostEventSubscriber } from './utils'
2
+
3
+ /**
4
+ * ```js
5
+ * import { onPostApproved } from '@amityco/ts-sdk'
6
+ * const dispose = onPostApproved(post => {
7
+ * // ...
8
+ * })
9
+ * ```
10
+ *
11
+ * Fired when a {@link Amity.Post} has been updated
12
+ *
13
+ * @param callback The function to call when the event was fired
14
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
15
+ *
16
+ * @category Post Events
17
+ */
18
+ export const onPostApproved = (callback: Amity.Listener<Amity.Post>): Amity.Unsubscriber =>
19
+ createPostEventSubscriber('post.approved', callback)
@@ -1,8 +1,4 @@
1
- import { getActiveClient } from '~/client/api'
2
- import { createEventSubscriber } from '~/core/events'
3
-
4
- import { decoratePayload } from '~/core/query'
5
- import { ingestInCache } from '~/core/cache'
1
+ import { createPostEventSubscriber } from './utils'
6
2
 
7
3
  /**
8
4
  * ```js
@@ -12,28 +8,12 @@ import { ingestInCache } from '~/core/cache'
12
8
  * })
13
9
  * ```
14
10
  *
15
- * Fired when an {@link Amity.Post} has been created
11
+ * Fired when {@link Amity.Post} has been created
16
12
  *
17
13
  * @param callback The function to call when the event was fired
18
14
  * @returns an {@link Amity.Unsubscriber} function to stop listening
19
15
  *
20
16
  * @category Post Events
21
17
  */
22
- export const onPostCreated = (
23
- callback: Amity.Listener<Amity.Post>
24
- ): Amity.Unsubscriber => {
25
- const client = getActiveClient()
26
-
27
- const filter = (payload: Amity.PostPayload) => {
28
- decoratePayload(payload)
29
- ingestInCache(payload)
30
- callback(payload.posts[0])
31
- }
32
-
33
- return createEventSubscriber(
34
- client,
35
- 'message/onPostCreated',
36
- 'v3.post.didCreate',
37
- filter
38
- )
39
- }
18
+ export const onPostCreated = (callback: Amity.Listener<Amity.Post>): Amity.Unsubscriber =>
19
+ createPostEventSubscriber('post.created', callback)
@@ -0,0 +1,19 @@
1
+ import { createPostEventSubscriber } from './utils'
2
+
3
+ /**
4
+ * ```js
5
+ * import { onPostDeclined } from '@amityco/ts-sdk'
6
+ * const dispose = onPostDeclined(post => {
7
+ * // ...
8
+ * })
9
+ * ```
10
+ *
11
+ * Fired when a {@link Amity.Post} has been updated
12
+ *
13
+ * @param callback The function to call when the event was fired
14
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
15
+ *
16
+ * @category Post Events
17
+ */
18
+ export const onPostDeclined = (callback: Amity.Listener<Amity.Post>): Amity.Unsubscriber =>
19
+ createPostEventSubscriber('post.declined', callback)
@@ -1,8 +1,4 @@
1
- import { getActiveClient } from '~/client/api'
2
- import { createEventSubscriber } from '~/core/events'
3
-
4
- import { decoratePayload } from '~/core/query'
5
- import { ingestInCache } from '~/core/cache'
1
+ import { createPostEventSubscriber } from './utils'
6
2
 
7
3
  /**
8
4
  * ```js
@@ -12,28 +8,12 @@ import { ingestInCache } from '~/core/cache'
12
8
  * })
13
9
  * ```
14
10
  *
15
- * Fired when an {@link Amity.Post} has been deleted
11
+ * Fired when a {@link Amity.Post} has been deleted
16
12
  *
17
13
  * @param callback The function to call when the event was fired
18
14
  * @returns an {@link Amity.Unsubscriber} function to stop listening
19
15
  *
20
16
  * @category Post Events
21
17
  */
22
- export const onPostDeleted = (
23
- callback: Amity.Listener<Amity.Post>
24
- ): Amity.Unsubscriber => {
25
- const client = getActiveClient()
26
-
27
- const filter = (payload: Amity.PostPayload) => {
28
- decoratePayload(payload)
29
- ingestInCache(payload)
30
- callback(payload.posts[0])
31
- }
32
-
33
- return createEventSubscriber(
34
- client,
35
- 'message/onPostDeleted',
36
- 'v3.post.didDelete',
37
- filter
38
- )
39
- }
18
+ export const onPostDeleted = (callback: Amity.Listener<Amity.Post>): Amity.Unsubscriber =>
19
+ createPostEventSubscriber('post.deleted', callback)