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

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 (133) hide show
  1. package/dist/@types/core/errors.d.ts +1 -0
  2. package/dist/@types/core/errors.d.ts.map +1 -1
  3. package/dist/@types/core/events.d.ts +4 -0
  4. package/dist/@types/core/events.d.ts.map +1 -1
  5. package/dist/@types/domains/client.d.ts +21 -1
  6. package/dist/@types/domains/client.d.ts.map +1 -1
  7. package/dist/@types/global.d.ts +7 -0
  8. package/dist/@types/global.d.ts.map +1 -1
  9. package/dist/client/api/accessTokenExpiryWatcher.d.ts +4 -0
  10. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -0
  11. package/dist/client/api/activeUser.d.ts +1 -1
  12. package/dist/client/api/activeUser.d.ts.map +1 -1
  13. package/dist/client/api/connectClient.d.ts +1 -1
  14. package/dist/client/api/connectClient.d.ts.map +1 -1
  15. package/dist/client/api/createClient.d.ts +1 -1
  16. package/dist/client/api/createClient.d.ts.map +1 -1
  17. package/dist/client/api/disconnectClient.d.ts +0 -1
  18. package/dist/client/api/disconnectClient.d.ts.map +1 -1
  19. package/dist/client/api/getToken.d.ts +4 -4
  20. package/dist/client/api/index.d.ts +1 -0
  21. package/dist/client/api/index.d.ts.map +1 -1
  22. package/dist/client/api/renewal.d.ts +2 -0
  23. package/dist/client/api/renewal.d.ts.map +1 -0
  24. package/dist/client/api/setSessionState.d.ts +12 -0
  25. package/dist/client/api/setSessionState.d.ts.map +1 -0
  26. package/dist/client/api/terminateClient.d.ts +9 -0
  27. package/dist/client/api/terminateClient.d.ts.map +1 -0
  28. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts +2 -0
  29. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts.map +1 -0
  30. package/dist/client/api/tests/connectClient.test.d.ts +2 -0
  31. package/dist/client/api/tests/connectClient.test.d.ts.map +1 -0
  32. package/dist/client/api/tests/disconnectClient.test.d.ts +2 -0
  33. package/dist/client/api/tests/disconnectClient.test.d.ts.map +1 -0
  34. package/dist/client/api/tests/getToken.test.d.ts +2 -0
  35. package/dist/client/api/tests/getToken.test.d.ts.map +1 -0
  36. package/dist/client/api/tests/renewal.test.d.ts +2 -0
  37. package/dist/client/api/tests/renewal.test.d.ts.map +1 -0
  38. package/dist/client/api/tests/setSessionState.test.d.ts +2 -0
  39. package/dist/client/api/tests/setSessionState.test.d.ts.map +1 -0
  40. package/dist/client/api/tests/terminateClient.test.d.ts +2 -0
  41. package/dist/client/api/tests/terminateClient.test.d.ts.map +1 -0
  42. package/dist/client/events/index.d.ts +1 -0
  43. package/dist/client/events/index.d.ts.map +1 -1
  44. package/dist/client/events/onClientBanned.d.ts +1 -1
  45. package/dist/client/events/onClientBanned.d.ts.map +1 -1
  46. package/dist/client/events/onSessionStateChange.d.ts +17 -0
  47. package/dist/client/events/onSessionStateChange.d.ts.map +1 -0
  48. package/dist/client/events/onTokenExpired.d.ts +17 -0
  49. package/dist/client/events/onTokenExpired.d.ts.map +1 -0
  50. package/dist/client/events/onTokenTerminated.d.ts +11 -0
  51. package/dist/client/events/onTokenTerminated.d.ts.map +1 -0
  52. package/dist/client/events/tests/onSessionStateChange.test.d.ts +2 -0
  53. package/dist/client/events/tests/onSessionStateChange.test.d.ts.map +1 -0
  54. package/dist/client/events/tests/onTokenTerminated.test.d.ts +2 -0
  55. package/dist/client/events/tests/onTokenTerminated.test.d.ts.map +1 -0
  56. package/dist/client/utils/setClientToken.d.ts +19 -0
  57. package/dist/client/utils/setClientToken.d.ts.map +1 -0
  58. package/dist/comment/events/tests/onCommentDeleted.test.d.ts +2 -0
  59. package/dist/comment/events/tests/onCommentDeleted.test.d.ts.map +1 -0
  60. package/dist/core/events.d.ts +3 -3
  61. package/dist/core/events.d.ts.map +1 -1
  62. package/dist/core/subscription.d.ts.map +1 -1
  63. package/dist/core/transports/http.d.ts.map +1 -1
  64. package/dist/index.cjs.js +503 -137
  65. package/dist/index.esm.js +502 -138
  66. package/dist/index.umd.js +4 -4
  67. package/dist/stream/api/tests/createStream.test.d.ts +2 -0
  68. package/dist/stream/api/tests/createStream.test.d.ts.map +1 -0
  69. package/dist/stream/api/tests/deleteStream.test.d.ts +2 -0
  70. package/dist/stream/api/tests/deleteStream.test.d.ts.map +1 -0
  71. package/dist/stream/api/tests/getStream.test.d.ts +2 -0
  72. package/dist/stream/api/tests/getStream.test.d.ts.map +1 -0
  73. package/dist/subChannel/api/tests/createSubChannel.test.d.ts +2 -0
  74. package/dist/subChannel/api/tests/createSubChannel.test.d.ts.map +1 -0
  75. package/dist/utils/constants.d.ts +2 -0
  76. package/dist/utils/constants.d.ts.map +1 -1
  77. package/dist/utils/tests/client.d.ts.map +1 -1
  78. package/dist/utils/tests/dummy/index.d.ts +2 -0
  79. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  80. package/dist/utils/tests/dummy/stream.d.ts +83 -0
  81. package/dist/utils/tests/dummy/stream.d.ts.map +1 -0
  82. package/dist/utils/tests/dummy/subChannel.d.ts +20 -0
  83. package/dist/utils/tests/dummy/subChannel.d.ts.map +1 -1
  84. package/dist/utils/tests/dummy/token.d.ts +11 -0
  85. package/dist/utils/tests/dummy/token.d.ts.map +1 -0
  86. package/package.json +1 -1
  87. package/src/@types/core/errors.ts +1 -0
  88. package/src/@types/core/events.ts +6 -0
  89. package/src/@types/domains/client.ts +45 -1
  90. package/src/@types/global.ts +14 -0
  91. package/src/client/api/accessTokenExpiryWatcher.ts +83 -0
  92. package/src/client/api/activeUser.ts +1 -1
  93. package/src/client/api/connectClient.ts +105 -24
  94. package/src/client/api/createClient.ts +9 -1
  95. package/src/client/api/disconnectClient.ts +26 -2
  96. package/src/client/api/getToken.ts +6 -6
  97. package/src/client/api/index.ts +2 -0
  98. package/src/client/api/renewal.ts +74 -0
  99. package/src/client/api/setSessionState.ts +75 -0
  100. package/src/client/api/terminateClient.ts +20 -0
  101. package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +129 -0
  102. package/src/client/api/tests/connectClient.test.ts +84 -0
  103. package/src/client/api/tests/createClient.test.ts +8 -0
  104. package/src/client/api/tests/disconnectClient.test.ts +78 -0
  105. package/src/client/api/tests/getToken.test.ts +36 -0
  106. package/src/client/api/tests/renewal.test.ts +67 -0
  107. package/src/client/api/tests/setSessionState.test.ts +62 -0
  108. package/src/client/api/tests/terminateClient.test.ts +29 -0
  109. package/src/client/events/index.ts +2 -0
  110. package/src/client/events/onClientBanned.ts +12 -5
  111. package/src/client/events/onSessionStateChange.ts +31 -0
  112. package/src/client/events/onTokenExpired.ts +26 -0
  113. package/src/client/events/onTokenTerminated.ts +20 -0
  114. package/src/client/events/tests/onSessionStateChange.test.ts +37 -0
  115. package/src/client/events/tests/onTokenTerminated.test.ts +37 -0
  116. package/src/client/tests/connectClient.test.ts +6 -1
  117. package/src/client/utils/setClientToken.ts +39 -0
  118. package/src/comment/events/tests/onCommentDeleted.test.ts +27 -0
  119. package/src/core/events.ts +5 -3
  120. package/src/core/subscription.ts +3 -1
  121. package/src/core/transports/http.ts +36 -1
  122. package/src/core/transports/mqtt.ts +1 -1
  123. package/src/external/api/createUserToken.ts +2 -2
  124. package/src/stream/api/tests/createStream.test.ts +30 -0
  125. package/src/stream/api/tests/deleteStream.test.ts +48 -0
  126. package/src/stream/api/tests/getStream.test.ts +23 -0
  127. package/src/subChannel/api/tests/createSubChannel.test.ts +103 -0
  128. package/src/utils/constants.ts +2 -0
  129. package/src/utils/tests/client.ts +18 -2
  130. package/src/utils/tests/dummy/index.ts +3 -0
  131. package/src/utils/tests/dummy/stream.ts +86 -0
  132. package/src/utils/tests/dummy/subChannel.ts +22 -0
  133. package/src/utils/tests/dummy/token.ts +12 -0
@@ -0,0 +1,62 @@
1
+ import { ASCError } from '~/core/errors';
2
+ import { getActiveClient } from '../activeClient';
3
+
4
+ import { connectClient, disconnectClient, pause } from '~/utils/tests';
5
+
6
+ import { setSessionState } from '../setSessionState';
7
+ import { onSessionStateChange } from '../../events';
8
+
9
+ describe('setSessionState', () => {
10
+ beforeEach(async () => {
11
+ await connectClient();
12
+ });
13
+
14
+ afterEach(async () => {
15
+ await disconnectClient();
16
+ });
17
+
18
+ test('it should set new session state', () => {
19
+ const client = getActiveClient();
20
+ const expected = Amity.SessionStates.NOT_LOGGED_IN;
21
+
22
+ setSessionState(expected);
23
+
24
+ expect(client.sessionState).toBe(expected);
25
+ });
26
+
27
+ test('it should return true if state changed successully', () => {
28
+ const expected = true;
29
+
30
+ const recieved = setSessionState(Amity.SessionStates.NOT_LOGGED_IN);
31
+
32
+ expect(recieved).toBe(expected);
33
+ });
34
+
35
+ test('it should fire event on state change', async () => {
36
+ const callback = jest.fn();
37
+
38
+ const expected = Amity.SessionStates.NOT_LOGGED_IN;
39
+ const unsub = onSessionStateChange(callback);
40
+
41
+ const recieved = setSessionState(expected);
42
+
43
+ // wait for event handler
44
+ await pause();
45
+
46
+ expect(recieved).toBe(true);
47
+ expect(callback).toHaveBeenCalledWith(expected);
48
+
49
+ unsub();
50
+ });
51
+
52
+ test('it should not allow invalid state change', async () => {
53
+ /*
54
+ * as state changes from established -> established are not possible, even
55
+ * for cases when logging in with already logged in user it should go to
56
+ * establishing first
57
+ */
58
+ const nextState = Amity.SessionStates.ESTABLISHED;
59
+
60
+ expect(setSessionState(nextState)).toBe(false);
61
+ });
62
+ });
@@ -0,0 +1,29 @@
1
+ import { client, connectClient } from '~/utils/tests';
2
+
3
+ import { terminateClient } from '../terminateClient';
4
+
5
+ const disconnect = () => setTimeout(() => client.ws.emit('disconnect'), 500);
6
+
7
+ describe('terminateClient', () => {
8
+ beforeAll(async () => {
9
+ await connectClient();
10
+ });
11
+
12
+ test('it should terminate client session', async () => {
13
+ disconnect().unref();
14
+
15
+ const expected = Amity.SessionStates.TERMINATED;
16
+
17
+ terminateClient();
18
+
19
+ expect(client.sessionState).toBe(expected);
20
+ });
21
+
22
+ test('it should clear sessionHandler', async () => {
23
+ disconnect().unref();
24
+
25
+ terminateClient();
26
+
27
+ expect(client.sessionHandler).toBeUndefined();
28
+ });
29
+ });
@@ -2,3 +2,5 @@ export * from './onConnectionError';
2
2
 
3
3
  export * from './onClientDisconnected';
4
4
  export * from './onClientBanned';
5
+
6
+ export * from './onSessionStateChange';
@@ -1,4 +1,6 @@
1
- import { onConnectionError } from './onConnectionError';
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { createEventSubscriber } from '~/core/events';
2
4
 
3
5
  /**
4
6
  * ```js
@@ -15,8 +17,13 @@ import { onConnectionError } from './onConnectionError';
15
17
  *
16
18
  * @category Client Events
17
19
  */
18
- export const onClientBanned = (callback: Amity.Listener<void>): Amity.Unsubscriber => {
19
- return onConnectionError(({ code }) => {
20
- code === Amity.ServerError.GLOBAL_BAN && callback();
21
- });
20
+ export const onClientBanned = (callback: Amity.Listener<Amity.UserPayload>): Amity.Unsubscriber => {
21
+ const client = getActiveClient();
22
+
23
+ return createEventSubscriber(
24
+ client,
25
+ `client/onConnectionError(user.didGlobalBan)`,
26
+ 'user.didGlobalBan',
27
+ callback,
28
+ );
22
29
  };
@@ -0,0 +1,31 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { createEventSubscriber } from '~/core/events';
4
+
5
+ /**
6
+ * ```js
7
+ * import { onSessionStateChange } from '@amityco/ts-sdk'
8
+ * const dispose = onSessionStateChange((state: Amity.SessionStates) => {
9
+ * // ...
10
+ * })
11
+ * ```
12
+ *
13
+ * Fired when any {@link Amity.Client} has a session state change
14
+ *
15
+ * @param callback The function to call when the event was fired
16
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
17
+ *
18
+ * @category Client Events
19
+ */
20
+ export const onSessionStateChange = (
21
+ callback: Amity.Listener<Amity.SessionStates>,
22
+ ): Amity.Unsubscriber => {
23
+ const client = getActiveClient();
24
+
25
+ return createEventSubscriber(
26
+ client,
27
+ `client/onSessionStateChange`,
28
+ 'sessionStateChange',
29
+ callback,
30
+ );
31
+ };
@@ -0,0 +1,26 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { createEventSubscriber } from '~/core/events';
4
+
5
+ /**
6
+ * ```js
7
+ * import { onTokenExpired } from '@amityco/ts-sdk'
8
+ * const dispose = onTokenExpired((state: Amity.SessionStates.TOKEN_EXPIRED) => {
9
+ * // ...
10
+ * })
11
+ * ```
12
+ *
13
+ * Fired when any {@link Amity.Client} session state has expired
14
+ *
15
+ * @param callback The function to call when the event was fired
16
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
17
+ *
18
+ * @category private
19
+ */
20
+ export const onTokenExpired = (
21
+ callback: Amity.Listener<Amity.SessionStates.TOKEN_EXPIRED>,
22
+ ): Amity.Unsubscriber => {
23
+ const client = getActiveClient();
24
+
25
+ return createEventSubscriber(client, `client/onTokenExpired`, 'tokenExpired', callback);
26
+ };
@@ -0,0 +1,20 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { createEventSubscriber } from '~/core/events';
4
+
5
+ /**
6
+ *
7
+ * Fired when any {@link Amity.Client} session state has terminated
8
+ *
9
+ * @param callback The function to call when the event was fired
10
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
11
+ *
12
+ * @category private
13
+ */
14
+ export const onTokenTerminated = (
15
+ callback: Amity.Listener<Amity.SessionStates.TERMINATED>,
16
+ ): Amity.Unsubscriber => {
17
+ const client = getActiveClient();
18
+
19
+ return createEventSubscriber(client, `client/onTokenTerminated`, 'tokenTerminated', callback);
20
+ };
@@ -0,0 +1,37 @@
1
+ import { client, connectClient, disconnectClient } from '~/utils/tests';
2
+
3
+ import { onSessionStateChange } from '../onSessionStateChange';
4
+
5
+ describe('onSessionStateChange', () => {
6
+ beforeAll(async () => {
7
+ await connectClient();
8
+ });
9
+
10
+ afterAll(async () => {
11
+ await disconnectClient();
12
+ });
13
+
14
+ test('it should call callback on event', () => {
15
+ const callback = jest.fn();
16
+ const expected = Amity.SessionStates.ESTABLISHED;
17
+
18
+ const unsub = onSessionStateChange(callback);
19
+ client.emitter.emit('sessionStateChange', expected);
20
+
21
+ expect(callback).toHaveBeenCalledWith(expected);
22
+
23
+ unsub();
24
+ });
25
+
26
+ test('it should not call callback if unsubscribed', () => {
27
+ const callback = jest.fn();
28
+ const state = Amity.SessionStates.ESTABLISHED;
29
+
30
+ const unsub = onSessionStateChange(callback);
31
+ unsub();
32
+
33
+ client.emitter.emit('sessionStateChange', state);
34
+
35
+ expect(callback).not.toHaveBeenCalled();
36
+ });
37
+ });
@@ -0,0 +1,37 @@
1
+ import { client, connectClient, disconnectClient } from '~/utils/tests';
2
+
3
+ import { onTokenTerminated } from '../onTokenTerminated';
4
+
5
+ describe('onTokenTerminated', () => {
6
+ beforeAll(async () => {
7
+ await connectClient();
8
+ });
9
+
10
+ afterAll(async () => {
11
+ await disconnectClient();
12
+ });
13
+
14
+ test('it should call callback on event', () => {
15
+ const callback = jest.fn();
16
+ const expected = Amity.SessionStates.TERMINATED;
17
+
18
+ const unsub = onTokenTerminated(callback);
19
+ client.emitter.emit('tokenTerminated', expected);
20
+
21
+ expect(callback).toHaveBeenCalledWith(expected);
22
+
23
+ unsub();
24
+ });
25
+
26
+ test('it should not call callback if unsubscribed', () => {
27
+ const callback = jest.fn();
28
+ const state = Amity.SessionStates.TERMINATED;
29
+
30
+ const unsub = onTokenTerminated(callback);
31
+ unsub();
32
+
33
+ client.emitter.emit('tokenTerminated', state);
34
+
35
+ expect(callback).not.toHaveBeenCalled();
36
+ });
37
+ });
@@ -4,6 +4,7 @@ import {
4
4
  getSmartFeedChannelTopic,
5
5
  getSmartFeedSubChannelTopic,
6
6
  getSmartFeedMessageTopic,
7
+ getUserTopic,
7
8
  subscribeTopic,
8
9
  } from '~/core/subscription';
9
10
 
@@ -12,6 +13,7 @@ jest.mock('~/core/subscription', () => ({
12
13
  ...jest.requireActual('~/core/subscription'),
13
14
  subscribeTopic: jest.fn(),
14
15
  getNetworkTopic: jest.fn(),
16
+ getUserTopic: jest.fn(),
15
17
  getSmartFeedChannelTopic: jest.fn(),
16
18
  getSmartFeedSubChannelTopic: jest.fn(),
17
19
  getSmartFeedMessageTopic: jest.fn(),
@@ -20,16 +22,19 @@ jest.mock('~/core/subscription', () => ({
20
22
  describe('connectClient', () => {
21
23
  test('should subscribe to network and smart feed topic', async () => {
22
24
  (getNetworkTopic as jest.Mock).mockReturnValue('network-topic');
25
+ (getUserTopic as jest.Mock).mockReturnValue('user-topic');
23
26
  (getSmartFeedChannelTopic as jest.Mock).mockReturnValue('smart-feed-channel-topic');
24
27
  (getSmartFeedSubChannelTopic as jest.Mock).mockReturnValue('smart-feed-sub-channel-topic');
25
28
  (getSmartFeedMessageTopic as jest.Mock).mockReturnValue('smart-feed-message-topic');
26
29
 
27
30
  await connectClient();
28
31
 
29
- expect(subscribeTopic).toBeCalledTimes(4);
32
+ expect(subscribeTopic).toBeCalledTimes(5);
33
+
30
34
  expect(subscribeTopic).toHaveBeenNthCalledWith(1, 'network-topic');
31
35
  expect(subscribeTopic).toHaveBeenNthCalledWith(2, 'smart-feed-channel-topic');
32
36
  expect(subscribeTopic).toHaveBeenNthCalledWith(3, 'smart-feed-sub-channel-topic');
33
37
  expect(subscribeTopic).toHaveBeenNthCalledWith(4, 'smart-feed-message-topic');
38
+ expect(subscribeTopic).toHaveBeenNthCalledWith(5, 'user-topic');
34
39
  });
35
40
  });
@@ -0,0 +1,39 @@
1
+ import { getActiveClient } from '../api/activeClient';
2
+ import { setSessionState } from '../api/setSessionState';
3
+ import { getToken } from '../api/getToken';
4
+
5
+ /**
6
+ * A util to set or refresh client token
7
+ *
8
+ * @param params.userId the user ID for the current session
9
+ * @param params.displayName the user's displayName for the current session
10
+ * @param params.deviceId Manual override of the user's device id (for device management)
11
+ * @param params.authToken The authentication token - necessary when network option is set to secure
12
+ * @returns token & user info
13
+ *
14
+ * @category private
15
+ * @async
16
+ */
17
+ export const setClientToken = async (params: Parameters<typeof getToken>) => {
18
+ const client = getActiveClient();
19
+ // begin establishing session
20
+ setSessionState(Amity.SessionStates.ESTABLISHING);
21
+
22
+ // @ts-ignore: in that particular case, typing can be
23
+ // ignored since we enforce default values just before.
24
+ const { accessToken, users, expiresAt, issuedAt, refreshToken } = await getToken(params);
25
+
26
+ // manually setup the token for http transport
27
+ client.http.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
28
+
29
+ client.http.defaults.metadata = { tokenExpiry: expiresAt };
30
+
31
+ // manually setup the token for ws transport
32
+ client.ws.io.opts.query = { token: accessToken };
33
+
34
+ client.token = { accessToken, issuedAt, expiresAt };
35
+
36
+ setSessionState(Amity.SessionStates.ESTABLISHED);
37
+
38
+ return { accessToken, users, refreshToken };
39
+ };
@@ -0,0 +1,27 @@
1
+ import { client, comment11, commentPayload } from '~/utils/tests';
2
+ import { onCommentDeleted } from '../onCommentDeleted';
3
+
4
+ describe('onCommentDeleted', () => {
5
+ test('it should call callback when comment have created', () => {
6
+ const callback = jest.fn();
7
+
8
+ const unsub = onCommentDeleted(callback);
9
+ client.emitter.emit('comment.deleted', commentPayload);
10
+
11
+ unsub();
12
+
13
+ expect(callback).toHaveBeenCalled();
14
+ expect(callback).toHaveBeenCalledWith(comment11);
15
+ });
16
+
17
+ test('it should return an unsubscriber', () => {
18
+ const callback = jest.fn();
19
+
20
+ const unsub = onCommentDeleted(callback);
21
+ unsub();
22
+
23
+ client.emitter.emit('comment.deleted', commentPayload);
24
+
25
+ expect(callback).not.toHaveBeenCalled();
26
+ });
27
+ });
@@ -12,6 +12,9 @@ const WS_EVENTS = [
12
12
  'connect_error',
13
13
  'reconnect_error',
14
14
  'reconnect_failed',
15
+ 'sessionStateChange',
16
+ // for internal use by accessTokenExpiryWatcher
17
+ 'tokenExpired',
15
18
  ] as const;
16
19
 
17
20
  const MQTT_EVENTS = [
@@ -22,6 +25,8 @@ const MQTT_EVENTS = [
22
25
  'close',
23
26
  'end',
24
27
  'reconnect',
28
+
29
+ 'user.didGlobalBan',
25
30
  ] as const;
26
31
 
27
32
  /** @hidden */
@@ -42,7 +47,6 @@ export const createEventEmitter = () => {
42
47
  export const proxyWebsocketEvents = (ws: Amity.Client['ws'], emitter: Amity.Client['emitter']) => {
43
48
  WS_EVENTS.forEach(event => {
44
49
  ws.on(event, (param: Amity.Events[typeof event]) => {
45
- console.log('ws', event, param);
46
50
  emitter.emit(event, param);
47
51
  });
48
52
  });
@@ -54,7 +58,6 @@ export const proxyMqttEvents = (
54
58
  ) => {
55
59
  MQTT_EVENTS.forEach(event => {
56
60
  mqttClient.on(event, (...params: any[]) => {
57
- console.log('mqtt', event, params);
58
61
  emitter.emit(event, params.length === 1 ? params[0] : params);
59
62
  });
60
63
  });
@@ -62,7 +65,6 @@ export const proxyMqttEvents = (
62
65
  // @ts-ignore
63
66
  mqttClient.on('message', (topic: string, payload: Buffer) => {
64
67
  const message = JSON.parse(payload.toString());
65
- console.log('mqtt message', message);
66
68
  emitter.emit(message.eventType, message.data);
67
69
  });
68
70
  };
@@ -127,7 +127,9 @@ export function subscribeTopic(
127
127
  topic: string,
128
128
  callback?: Amity.Listener<ASCError | void>,
129
129
  ): Amity.Unsubscriber {
130
- const { mqtt, emitter, accessToken } = getActiveClient();
130
+ const { mqtt, emitter, token } = getActiveClient();
131
+ const accessToken = token?.accessToken ?? '';
132
+
131
133
  const user = getActiveUser();
132
134
 
133
135
  if (mqttAccessToken !== accessToken || mqttUserId !== user._id) {
@@ -2,6 +2,9 @@ import axios from 'axios';
2
2
  import qs from 'qs';
3
3
  import HttpAgent, { HttpsAgent } from 'agentkeepalive';
4
4
 
5
+ import { ASCError } from '~/core/errors';
6
+
7
+ import { fireEvent } from '../events';
5
8
  import { unwrapPayload } from './utils';
6
9
 
7
10
  /**
@@ -36,6 +39,22 @@ export const createHttpTransport = (endpoint: string) => {
36
39
  paramsSerializer: stringify,
37
40
  });
38
41
 
42
+ instance.interceptors.request.use(config => {
43
+ // check global.ts for the extension of AxiosRequestConfig
44
+ const tokenExpiry = config.metadata?.tokenExpiry;
45
+
46
+ if (tokenExpiry) {
47
+ if (Date.now() >= Date.parse(tokenExpiry)) {
48
+ return {
49
+ ...config,
50
+ cancelToken: new axios.CancelToken(cancel => cancel('Token Expired')),
51
+ };
52
+ }
53
+ }
54
+
55
+ return config;
56
+ });
57
+
39
58
  instance.interceptors.response.use(
40
59
  response => response,
41
60
  error => {
@@ -43,7 +62,23 @@ export const createHttpTransport = (endpoint: string) => {
43
62
  // eslint-disable-next-line no-console
44
63
  console.error(response?.data ?? error);
45
64
 
46
- if (response) unwrapPayload(response.data);
65
+ // handle unauthorized request
66
+ if (response.data.code === Amity.ServerError.UNAUTHORIZED) {
67
+ fireEvent('tokenTerminated', Amity.SessionStates.TERMINATED);
68
+ }
69
+
70
+ // handle request cancellation
71
+ if (axios.isCancel(error)) {
72
+ fireEvent('tokenExpired', Amity.SessionStates.TOKEN_EXPIRED);
73
+
74
+ throw new ASCError(
75
+ 'Token expired',
76
+ Amity.ClientError.TOKEN_EXPIRED,
77
+ Amity.ErrorLevel.FATAL,
78
+ );
79
+ }
80
+
81
+ if (response?.data) unwrapPayload(response.data);
47
82
  },
48
83
  );
49
84
 
@@ -21,7 +21,7 @@ export function getMqttOptions(params: {
21
21
  }): IClientOptions {
22
22
  return {
23
23
  clean: false, // keep subscriptions
24
- clientId: `mqttjs_ + ${Math.random().toString(16).substr(2, 8)}`,
24
+ clientId: `mqttjs_ + ${Math.random().toString(16).substring(2, 10)}`,
25
25
  protocolId: 'MQTT',
26
26
  protocolVersion: 4,
27
27
  reconnectPeriod: 0, // disable auto reconnect
@@ -26,11 +26,11 @@ export const createUserToken = async (
26
26
  },
27
27
  ) => {
28
28
  const deviceId = getDeviceId();
29
- const deviceInfo = await getDeviceInfo();
29
+ const deviceInfo = getDeviceInfo();
30
30
  const http = createHttpTransport(computeUrl('http', apiRegion));
31
31
 
32
32
  const { data } = await http.post<Amity.Tokens>(
33
- '/api/v3/sessions',
33
+ '/api/v4/sessions',
34
34
  {
35
35
  ...params,
36
36
  deviceId,
@@ -0,0 +1,30 @@
1
+ import { getActiveClient } from '~/client/api';
2
+ import {
3
+ client,
4
+ connectClient,
5
+ disconnectClient,
6
+ streamResponse,
7
+ } from '~/utils/tests';
8
+ import { createStream } from '../createStream';
9
+
10
+ const bundle: Parameters<typeof createStream>[0] = {
11
+ title: 'my stream',
12
+ 'thumbnailFileId': streamResponse.data.videoStreamings[0].thumbnailFileId,
13
+ };
14
+
15
+ describe('createStream', () => {
16
+ beforeAll(connectClient);
17
+ afterAll(disconnectClient);
18
+
19
+ it('creates a stream and returns the new stream', async () => {
20
+ client.http.post = jest.fn().mockResolvedValueOnce(streamResponse);
21
+
22
+ const created = await createStream(bundle);
23
+
24
+ expect(getActiveClient().http.post).toHaveBeenCalledWith(
25
+ `/api/v3/video-streaming`,
26
+ bundle
27
+ );
28
+ expect(created.data).toEqual(streamResponse.data.videoStreamings[0]);
29
+ });
30
+ });
@@ -0,0 +1,48 @@
1
+ import { disableCache, enableCache, pullFromCache, pushToCache } from '~/cache/api';
2
+ import { client, connectClient, disconnectClient, streamResponse } from '~/utils/tests';
3
+
4
+ import { deleteStream } from '~/stream/api';
5
+
6
+ const STREAM_ID = streamResponse.data.videoStreamings[0].streamId;
7
+
8
+ const resolvedDeleteValue = {
9
+ data: {
10
+ success: true,
11
+ },
12
+ };
13
+
14
+ jest.mock('~/stream/api/getStream', () => ({
15
+ getStream: jest.fn(() => Promise.resolve(streamResponse.data.videoStreamings[0])),
16
+ }));
17
+
18
+ describe('deleteStream', () => {
19
+ beforeAll(connectClient);
20
+ afterAll(disconnectClient);
21
+
22
+ test('should return deleted stream', async () => {
23
+ client.http.delete = jest.fn().mockResolvedValueOnce(resolvedDeleteValue);
24
+
25
+ await expect(deleteStream(STREAM_ID)).resolves.toEqual(true);
26
+ });
27
+
28
+ test('should throw an error if request fails', async () => {
29
+ client.http.delete = jest.fn().mockRejectedValueOnce(new Error('error'));
30
+
31
+ await expect(deleteStream(STREAM_ID)).rejects.toThrow('error');
32
+ });
33
+
34
+ test('should update cache after deleted stream', async () => {
35
+ enableCache();
36
+ client.http.delete = jest.fn().mockResolvedValueOnce(resolvedDeleteValue);
37
+ pushToCache(['community', 'get', STREAM_ID], streamResponse.data.videoStreamings[0]);
38
+
39
+ await deleteStream(STREAM_ID);
40
+ const recieved = pullFromCache(['stream', 'get', STREAM_ID])?.data;
41
+
42
+ expect(recieved).toEqual(expect.objectContaining({
43
+ isDeleted: true
44
+ }));
45
+
46
+ disableCache();
47
+ });
48
+ });
@@ -0,0 +1,23 @@
1
+ import { enableCache } from '~/cache/api';
2
+ import { client, connectClient, disconnectClient, streamResponse } from '~/utils/tests';
3
+ import { getStream } from '~/stream/api';
4
+
5
+ const STREAM_ID = streamResponse.data.videoStreamings[0].streamId;
6
+
7
+ describe('getStream', () => {
8
+ beforeAll(connectClient);
9
+ afterAll(disconnectClient);
10
+
11
+ test('Should return the stream from backend', async () => {
12
+ enableCache();
13
+ client.http.get = jest.fn().mockResolvedValueOnce(streamResponse);
14
+ const { data } = await getStream(STREAM_ID);
15
+ expect(data).toEqual(streamResponse.data.videoStreamings[0]);
16
+ });
17
+
18
+ test('Should return stream from locally', () => {
19
+ const stream: ReturnType<typeof getStream.locally> = getStream.locally(STREAM_ID);
20
+
21
+ expect(stream?.data).toEqual(streamResponse.data.videoStreamings[0]);
22
+ });
23
+ });