@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.
- package/dist/@types/core/errors.d.ts +1 -0
- package/dist/@types/core/errors.d.ts.map +1 -1
- package/dist/@types/core/events.d.ts +4 -0
- package/dist/@types/core/events.d.ts.map +1 -1
- package/dist/@types/domains/client.d.ts +21 -1
- package/dist/@types/domains/client.d.ts.map +1 -1
- package/dist/@types/global.d.ts +7 -0
- package/dist/@types/global.d.ts.map +1 -1
- package/dist/client/api/accessTokenExpiryWatcher.d.ts +4 -0
- package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -0
- package/dist/client/api/activeUser.d.ts +1 -1
- package/dist/client/api/activeUser.d.ts.map +1 -1
- package/dist/client/api/connectClient.d.ts +1 -1
- package/dist/client/api/connectClient.d.ts.map +1 -1
- package/dist/client/api/createClient.d.ts +1 -1
- package/dist/client/api/createClient.d.ts.map +1 -1
- package/dist/client/api/disconnectClient.d.ts +0 -1
- package/dist/client/api/disconnectClient.d.ts.map +1 -1
- package/dist/client/api/getToken.d.ts +4 -4
- package/dist/client/api/index.d.ts +1 -0
- package/dist/client/api/index.d.ts.map +1 -1
- package/dist/client/api/renewal.d.ts +2 -0
- package/dist/client/api/renewal.d.ts.map +1 -0
- package/dist/client/api/setSessionState.d.ts +12 -0
- package/dist/client/api/setSessionState.d.ts.map +1 -0
- package/dist/client/api/terminateClient.d.ts +9 -0
- package/dist/client/api/terminateClient.d.ts.map +1 -0
- package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts +2 -0
- package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts.map +1 -0
- package/dist/client/api/tests/connectClient.test.d.ts +2 -0
- package/dist/client/api/tests/connectClient.test.d.ts.map +1 -0
- package/dist/client/api/tests/disconnectClient.test.d.ts +2 -0
- package/dist/client/api/tests/disconnectClient.test.d.ts.map +1 -0
- package/dist/client/api/tests/getToken.test.d.ts +2 -0
- package/dist/client/api/tests/getToken.test.d.ts.map +1 -0
- package/dist/client/api/tests/renewal.test.d.ts +2 -0
- package/dist/client/api/tests/renewal.test.d.ts.map +1 -0
- package/dist/client/api/tests/setSessionState.test.d.ts +2 -0
- package/dist/client/api/tests/setSessionState.test.d.ts.map +1 -0
- package/dist/client/api/tests/terminateClient.test.d.ts +2 -0
- package/dist/client/api/tests/terminateClient.test.d.ts.map +1 -0
- package/dist/client/events/index.d.ts +1 -0
- package/dist/client/events/index.d.ts.map +1 -1
- package/dist/client/events/onClientBanned.d.ts +1 -1
- package/dist/client/events/onClientBanned.d.ts.map +1 -1
- package/dist/client/events/onSessionStateChange.d.ts +17 -0
- package/dist/client/events/onSessionStateChange.d.ts.map +1 -0
- package/dist/client/events/onTokenExpired.d.ts +17 -0
- package/dist/client/events/onTokenExpired.d.ts.map +1 -0
- package/dist/client/events/onTokenTerminated.d.ts +11 -0
- package/dist/client/events/onTokenTerminated.d.ts.map +1 -0
- package/dist/client/events/tests/onSessionStateChange.test.d.ts +2 -0
- package/dist/client/events/tests/onSessionStateChange.test.d.ts.map +1 -0
- package/dist/client/events/tests/onTokenTerminated.test.d.ts +2 -0
- package/dist/client/events/tests/onTokenTerminated.test.d.ts.map +1 -0
- package/dist/client/utils/setClientToken.d.ts +19 -0
- package/dist/client/utils/setClientToken.d.ts.map +1 -0
- package/dist/comment/events/tests/onCommentDeleted.test.d.ts +2 -0
- package/dist/comment/events/tests/onCommentDeleted.test.d.ts.map +1 -0
- package/dist/core/events.d.ts +3 -3
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/subscription.d.ts.map +1 -1
- package/dist/core/transports/http.d.ts.map +1 -1
- package/dist/index.cjs.js +503 -137
- package/dist/index.esm.js +502 -138
- package/dist/index.umd.js +4 -4
- package/dist/stream/api/tests/createStream.test.d.ts +2 -0
- package/dist/stream/api/tests/createStream.test.d.ts.map +1 -0
- package/dist/stream/api/tests/deleteStream.test.d.ts +2 -0
- package/dist/stream/api/tests/deleteStream.test.d.ts.map +1 -0
- package/dist/stream/api/tests/getStream.test.d.ts +2 -0
- package/dist/stream/api/tests/getStream.test.d.ts.map +1 -0
- package/dist/subChannel/api/tests/createSubChannel.test.d.ts +2 -0
- package/dist/subChannel/api/tests/createSubChannel.test.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/tests/client.d.ts.map +1 -1
- package/dist/utils/tests/dummy/index.d.ts +2 -0
- package/dist/utils/tests/dummy/index.d.ts.map +1 -1
- package/dist/utils/tests/dummy/stream.d.ts +83 -0
- package/dist/utils/tests/dummy/stream.d.ts.map +1 -0
- package/dist/utils/tests/dummy/subChannel.d.ts +20 -0
- package/dist/utils/tests/dummy/subChannel.d.ts.map +1 -1
- package/dist/utils/tests/dummy/token.d.ts +11 -0
- package/dist/utils/tests/dummy/token.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/@types/core/errors.ts +1 -0
- package/src/@types/core/events.ts +6 -0
- package/src/@types/domains/client.ts +45 -1
- package/src/@types/global.ts +14 -0
- package/src/client/api/accessTokenExpiryWatcher.ts +83 -0
- package/src/client/api/activeUser.ts +1 -1
- package/src/client/api/connectClient.ts +105 -24
- package/src/client/api/createClient.ts +9 -1
- package/src/client/api/disconnectClient.ts +26 -2
- package/src/client/api/getToken.ts +6 -6
- package/src/client/api/index.ts +2 -0
- package/src/client/api/renewal.ts +74 -0
- package/src/client/api/setSessionState.ts +75 -0
- package/src/client/api/terminateClient.ts +20 -0
- package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +129 -0
- package/src/client/api/tests/connectClient.test.ts +84 -0
- package/src/client/api/tests/createClient.test.ts +8 -0
- package/src/client/api/tests/disconnectClient.test.ts +78 -0
- package/src/client/api/tests/getToken.test.ts +36 -0
- package/src/client/api/tests/renewal.test.ts +67 -0
- package/src/client/api/tests/setSessionState.test.ts +62 -0
- package/src/client/api/tests/terminateClient.test.ts +29 -0
- package/src/client/events/index.ts +2 -0
- package/src/client/events/onClientBanned.ts +12 -5
- package/src/client/events/onSessionStateChange.ts +31 -0
- package/src/client/events/onTokenExpired.ts +26 -0
- package/src/client/events/onTokenTerminated.ts +20 -0
- package/src/client/events/tests/onSessionStateChange.test.ts +37 -0
- package/src/client/events/tests/onTokenTerminated.test.ts +37 -0
- package/src/client/tests/connectClient.test.ts +6 -1
- package/src/client/utils/setClientToken.ts +39 -0
- package/src/comment/events/tests/onCommentDeleted.test.ts +27 -0
- package/src/core/events.ts +5 -3
- package/src/core/subscription.ts +3 -1
- package/src/core/transports/http.ts +36 -1
- package/src/core/transports/mqtt.ts +1 -1
- package/src/external/api/createUserToken.ts +2 -2
- package/src/stream/api/tests/createStream.test.ts +30 -0
- package/src/stream/api/tests/deleteStream.test.ts +48 -0
- package/src/stream/api/tests/getStream.test.ts +23 -0
- package/src/subChannel/api/tests/createSubChannel.test.ts +103 -0
- package/src/utils/constants.ts +2 -0
- package/src/utils/tests/client.ts +18 -2
- package/src/utils/tests/dummy/index.ts +3 -0
- package/src/utils/tests/dummy/stream.ts +86 -0
- package/src/utils/tests/dummy/subChannel.ts +22 -0
- 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
|
+
});
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
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<
|
|
19
|
-
|
|
20
|
-
|
|
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(
|
|
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
|
+
});
|
package/src/core/events.ts
CHANGED
|
@@ -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
|
};
|
package/src/core/subscription.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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).
|
|
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 =
|
|
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/
|
|
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
|
+
});
|