@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 @@
|
|
|
1
|
+
{"version":3,"file":"createStream.test.d.ts","sourceRoot":"","sources":["../../../../src/stream/api/tests/createStream.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deleteStream.test.d.ts","sourceRoot":"","sources":["../../../../src/stream/api/tests/deleteStream.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getStream.test.d.ts","sourceRoot":"","sources":["../../../../src/stream/api/tests/getStream.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSubChannel.test.d.ts","sourceRoot":"","sources":["../../../../src/subChannel/api/tests/createSubChannel.test.ts"],"names":[],"mappings":""}
|
|
@@ -4,4 +4,6 @@ export declare const ENABLE_CACHE_MESSAGE = "For using Live Collection feature y
|
|
|
4
4
|
export declare const LIVE_OBJECT_ENABLE_CACHE_MESSAGE = "For using Live Object feature you need to enable Cache!";
|
|
5
5
|
export declare const UNSYNCED_OBJECT_CACHED_AT_MESSAGE = "Observing unsynced object is not supported by Live Object.";
|
|
6
6
|
export declare const UNSYNCED_OBJECT_CACHED_AT_VALUE = -5;
|
|
7
|
+
export declare const MINUTE: number;
|
|
8
|
+
export declare const ACCESS_TOKEN_WATCHER_INTERVAL: number;
|
|
7
9
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mCAAmC,IAAI,CAAC;AACrD,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,WAAiC,CAAC;AACxF,eAAO,MAAM,oBAAoB,gEAAgE,CAAC;AAClG,eAAO,MAAM,gCAAgC,4DACc,CAAC;AAC5D,eAAO,MAAM,iCAAiC,+DACgB,CAAC;AAC/D,eAAO,MAAM,+BAA+B,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mCAAmC,IAAI,CAAC;AACrD,eAAO,MAAM,iCAAiC,EAAE,KAAK,CAAC,WAAiC,CAAC;AACxF,eAAO,MAAM,oBAAoB,gEAAgE,CAAC;AAClG,eAAO,MAAM,gCAAgC,4DACc,CAAC;AAC5D,eAAO,MAAM,iCAAiC,+DACgB,CAAC;AAC/D,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAClD,eAAO,MAAM,MAAM,QAAY,CAAC;AAChC,eAAO,MAAM,6BAA6B,QAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/client.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,MAAM,cAA4B,CAAC;AAKhD,eAAO,MAAM,aAAa,qBAuBzB,CAAC;AAEF,eAAO,MAAM,gBAAgB,qBAE5B,CAAC;;AAEF,wBAAkB"}
|
|
@@ -13,6 +13,8 @@ export * from './reaction';
|
|
|
13
13
|
export * from './channel';
|
|
14
14
|
export * from './subChannel';
|
|
15
15
|
export * from './message';
|
|
16
|
+
export * from './token';
|
|
16
17
|
export * from './member';
|
|
17
18
|
export * from './community';
|
|
19
|
+
export * from './stream';
|
|
18
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAA2B,CAAC;AAC7C,eAAO,MAAM,mBAAmB;;;CAAiC,CAAC;AAElE,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAE3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAE7B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAA2B,CAAC;AAC7C,eAAO,MAAM,mBAAmB;;;CAAiC,CAAC;AAElE,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AAEvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAE3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAE7B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAE5B,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export declare const streamResponse: {
|
|
2
|
+
data: {
|
|
3
|
+
videoStreamings: {
|
|
4
|
+
streamId: string;
|
|
5
|
+
userId: string;
|
|
6
|
+
thumbnailFileId: string;
|
|
7
|
+
title: string;
|
|
8
|
+
status: string;
|
|
9
|
+
isLive: boolean;
|
|
10
|
+
isDeleted: boolean;
|
|
11
|
+
description: string;
|
|
12
|
+
platform: {
|
|
13
|
+
name: string;
|
|
14
|
+
version: string;
|
|
15
|
+
};
|
|
16
|
+
startedAt: string;
|
|
17
|
+
endedAt: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
metadata: {};
|
|
21
|
+
resolution: string;
|
|
22
|
+
streamerUrl: {
|
|
23
|
+
url: string;
|
|
24
|
+
components: {
|
|
25
|
+
origin: string;
|
|
26
|
+
appName: string;
|
|
27
|
+
streamName: string;
|
|
28
|
+
query: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
recordings: {
|
|
32
|
+
flv: {
|
|
33
|
+
url: string;
|
|
34
|
+
duration: number;
|
|
35
|
+
startTime: number;
|
|
36
|
+
stopTime: number;
|
|
37
|
+
};
|
|
38
|
+
mp4: {
|
|
39
|
+
url: string;
|
|
40
|
+
duration: number;
|
|
41
|
+
startTime: number;
|
|
42
|
+
stopTime: number;
|
|
43
|
+
};
|
|
44
|
+
m3u8: {
|
|
45
|
+
url: string;
|
|
46
|
+
duration: number;
|
|
47
|
+
startTime: number;
|
|
48
|
+
stopTime: number;
|
|
49
|
+
};
|
|
50
|
+
}[];
|
|
51
|
+
watcherUrl: {
|
|
52
|
+
flv: {
|
|
53
|
+
url: string;
|
|
54
|
+
components: {
|
|
55
|
+
origin: string;
|
|
56
|
+
appName: string;
|
|
57
|
+
streamName: string;
|
|
58
|
+
query: string;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
hls: {
|
|
62
|
+
url: string;
|
|
63
|
+
components: {
|
|
64
|
+
origin: string;
|
|
65
|
+
appName: string;
|
|
66
|
+
streamName: string;
|
|
67
|
+
query: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
rtmp: {
|
|
71
|
+
url: string;
|
|
72
|
+
components: {
|
|
73
|
+
origin: string;
|
|
74
|
+
appName: string;
|
|
75
|
+
streamName: string;
|
|
76
|
+
query: string;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
}[];
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/stream.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqF1B,CAAC"}
|
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
export declare function generateRawSubChannel(params?: Partial<Amity.RawSubChannel>): Amity.RawSubChannel;
|
|
2
2
|
export declare function generateSubChannel(params?: Record<string, any>): Amity.SubChannel;
|
|
3
|
+
export declare const createSubChannelError400400: {
|
|
4
|
+
status: string;
|
|
5
|
+
message: string;
|
|
6
|
+
code: number;
|
|
7
|
+
data: {
|
|
8
|
+
detail: {
|
|
9
|
+
channelId: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export declare const createSubChannelError400301: {
|
|
14
|
+
status: string;
|
|
15
|
+
message: string;
|
|
16
|
+
code: number;
|
|
17
|
+
data: {
|
|
18
|
+
detail: {
|
|
19
|
+
channelId: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
3
23
|
//# sourceMappingURL=subChannel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subChannel.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/subChannel.ts"],"names":[],"mappings":"AAGA,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,aAAa,CAkBhG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAKjF"}
|
|
1
|
+
{"version":3,"file":"subChannel.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/subChannel.ts"],"names":[],"mappings":"AAGA,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,aAAa,CAkBhG;AAED,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU,CAKjF;AAED,eAAO,MAAM,2BAA2B;;;;;;;;;CASvC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;;;;CASvC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/token.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,eAAe;;;;;;;;;CAS3B,CAAC"}
|
package/package.json
CHANGED
|
@@ -39,6 +39,7 @@ declare global {
|
|
|
39
39
|
close: Error;
|
|
40
40
|
end: undefined;
|
|
41
41
|
reconnect: undefined;
|
|
42
|
+
'user.didGlobalBan': Amity.UserPayload;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
type MqttChannelUserEvents = {
|
|
@@ -149,6 +150,11 @@ declare global {
|
|
|
149
150
|
'local.message-feed.deleted': Amity.SubChannelPayload;
|
|
150
151
|
'poll.updated': Amity.PollPayload;
|
|
151
152
|
'poll.deleted': Amity.PollPayload;
|
|
153
|
+
|
|
154
|
+
sessionStateChange: Amity.SessionStates;
|
|
155
|
+
// used by accessTokenExpiryWatcher
|
|
156
|
+
tokenExpired: Amity.SessionStates.TOKEN_EXPIRED;
|
|
157
|
+
tokenTerminated: Amity.SessionStates.TERMINATED;
|
|
152
158
|
};
|
|
153
159
|
|
|
154
160
|
type Events = WsEvents & MqttEvents & MqttRTE & LocalEvents;
|
|
@@ -5,6 +5,27 @@ declare global {
|
|
|
5
5
|
namespace Amity {
|
|
6
6
|
type Logger = (topic: string, ...args: any[]) => void;
|
|
7
7
|
|
|
8
|
+
const enum SessionStates {
|
|
9
|
+
NOT_LOGGED_IN = 'notLoggedIn',
|
|
10
|
+
|
|
11
|
+
ESTABLISHING = 'establishing',
|
|
12
|
+
ESTABLISHED = 'established',
|
|
13
|
+
|
|
14
|
+
TOKEN_EXPIRED = 'tokenExpired',
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* Terminated is slightly different from NOT_LOGGED_IN:
|
|
18
|
+
*
|
|
19
|
+
* After established, upon receiving the termination code, the SDK will move to terminated.
|
|
20
|
+
* Unlike tokenExpired that users can regain SDK usability by giving an auth token.
|
|
21
|
+
* This state represents unrecoverable failures. The app must manually re-login with a valid user.
|
|
22
|
+
*
|
|
23
|
+
* For more details, please check tech spec:
|
|
24
|
+
* https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#terminated
|
|
25
|
+
*/
|
|
26
|
+
TERMINATED = 'terminated',
|
|
27
|
+
}
|
|
28
|
+
|
|
8
29
|
type Client = {
|
|
9
30
|
version: string;
|
|
10
31
|
|
|
@@ -14,14 +35,24 @@ declare global {
|
|
|
14
35
|
ws: SocketIOClient.Socket;
|
|
15
36
|
emitter: Emitter<Amity.Events>;
|
|
16
37
|
|
|
38
|
+
sessionState: Amity.SessionStates;
|
|
39
|
+
sessionHandler?: Amity.SessionHandler;
|
|
40
|
+
|
|
17
41
|
cache?: Amity.Cache;
|
|
18
42
|
|
|
19
43
|
apiKey?: string;
|
|
20
44
|
userId?: string;
|
|
21
|
-
|
|
45
|
+
|
|
46
|
+
token?: Omit<Amity.Tokens, 'refreshToken'>;
|
|
22
47
|
|
|
23
48
|
use: () => void;
|
|
24
49
|
|
|
50
|
+
accessTokenExpiryWatcher: (
|
|
51
|
+
expiresAt: Amity.Tokens['expiresAt'],
|
|
52
|
+
issuedAt: Amity.Tokens['issuedAt'],
|
|
53
|
+
sessionHandler: Amity.SessionHandler,
|
|
54
|
+
) => Amity.Unsubscriber;
|
|
55
|
+
|
|
25
56
|
getFeedSettings: () => Promise<Amity.FeedSettings>;
|
|
26
57
|
};
|
|
27
58
|
|
|
@@ -37,8 +68,21 @@ declare global {
|
|
|
37
68
|
type Tokens = {
|
|
38
69
|
accessToken: string;
|
|
39
70
|
refreshToken: string;
|
|
71
|
+
// issuedAt, expiresAt is in iso Date format
|
|
72
|
+
issuedAt: string;
|
|
73
|
+
expiresAt: string;
|
|
40
74
|
};
|
|
41
75
|
|
|
76
|
+
type AccessTokenRenewal = {
|
|
77
|
+
renew: () => void;
|
|
78
|
+
renewWithAuthToken: (authToken: string) => void;
|
|
79
|
+
unableToRetrieveAuthToken: () => void;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
interface SessionHandler {
|
|
83
|
+
sessionWillRenewAccessToken(renewal: AccessTokenRenewal): void;
|
|
84
|
+
}
|
|
85
|
+
|
|
42
86
|
type ChatSettings = {
|
|
43
87
|
enabled: boolean;
|
|
44
88
|
mention: {
|
package/src/@types/global.ts
CHANGED
|
@@ -28,3 +28,17 @@ declare global {
|
|
|
28
28
|
|
|
29
29
|
type ValueOf<T extends Record<any, any>> = T[keyof T];
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Extented to pass token expiry into request config, for internal use only.
|
|
34
|
+
* Since it's in the request config, it does not get sent for the server, and
|
|
35
|
+
* allows us to intercept the tokenExpiry value to check if the token has not
|
|
36
|
+
* expired & cancel the request if yes.
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
39
|
+
declare module 'axios' {
|
|
40
|
+
export interface AxiosRequestConfig {
|
|
41
|
+
// expires at iso string for access token
|
|
42
|
+
metadata?: { tokenExpiry: string };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { fireEvent } from '~/core/events';
|
|
2
|
+
import { scheduleTask } from '~/core/microtasks';
|
|
3
|
+
import { MINUTE, ACCESS_TOKEN_WATCHER_INTERVAL } from '~/utils/constants';
|
|
4
|
+
|
|
5
|
+
import { renewal } from './renewal';
|
|
6
|
+
|
|
7
|
+
const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
|
|
8
|
+
const COMPENSATED_DELAY = 5 * MINUTE;
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* a helper function to check if the token has expires
|
|
12
|
+
*
|
|
13
|
+
* @param token to be checked
|
|
14
|
+
* @returns boolean indicating if token expires
|
|
15
|
+
*
|
|
16
|
+
* @category private
|
|
17
|
+
*/
|
|
18
|
+
export const isExpired = (expiresAt: Amity.Tokens['expiresAt']): boolean =>
|
|
19
|
+
Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* a helper function to check if the token is about to expire
|
|
23
|
+
*
|
|
24
|
+
* @param token to be checked
|
|
25
|
+
* @returns boolean indicating if token is aboutToExpire
|
|
26
|
+
*
|
|
27
|
+
* @category private
|
|
28
|
+
*/
|
|
29
|
+
export const isAboutToExpire = (
|
|
30
|
+
expiresAt: Amity.Tokens['expiresAt'],
|
|
31
|
+
issuedAt: Amity.Tokens['issuedAt'],
|
|
32
|
+
): boolean => {
|
|
33
|
+
const expires = Date.parse(expiresAt);
|
|
34
|
+
const issued = Date.parse(issuedAt);
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
|
|
37
|
+
const duration = expires - issued - COMPENSATED_DELAY;
|
|
38
|
+
const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
|
|
39
|
+
|
|
40
|
+
return now > aboutToExpireAt && now < expires;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* Monitors time to expire of token and updates session state to aboutToExpire
|
|
45
|
+
*
|
|
46
|
+
* @returns intervalId to be cleared after trigger
|
|
47
|
+
*
|
|
48
|
+
* @category private
|
|
49
|
+
*/
|
|
50
|
+
export const accessTokenExpiryWatcher = (
|
|
51
|
+
expiresAt: Amity.Tokens['expiresAt'],
|
|
52
|
+
issuedAt: Amity.Tokens['issuedAt'],
|
|
53
|
+
sessionHandler: Amity.SessionHandler,
|
|
54
|
+
): Amity.Unsubscriber => {
|
|
55
|
+
const interval: ReturnType<typeof setInterval> = setInterval(() => {
|
|
56
|
+
if (isExpired(expiresAt)) {
|
|
57
|
+
/*
|
|
58
|
+
* the event handler will take care of updating session state
|
|
59
|
+
* Note, this will also clear the interval id, so this event will only be
|
|
60
|
+
* fired once
|
|
61
|
+
*/
|
|
62
|
+
fireEvent('tokenExpired', Amity.SessionStates.TOKEN_EXPIRED);
|
|
63
|
+
|
|
64
|
+
/*
|
|
65
|
+
* https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
|
|
66
|
+
*
|
|
67
|
+
* Why sechduled task?
|
|
68
|
+
* Since fireEvent is scheduled, it will be called
|
|
69
|
+
* after sessionHandler leading to an invalid state change from
|
|
70
|
+
* establishing to tokenExpired
|
|
71
|
+
*/
|
|
72
|
+
scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
|
|
73
|
+
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (isAboutToExpire(issuedAt, expiresAt)) {
|
|
78
|
+
sessionHandler.sessionWillRenewAccessToken(renewal());
|
|
79
|
+
}
|
|
80
|
+
}, ACCESS_TOKEN_WATCHER_INTERVAL);
|
|
81
|
+
|
|
82
|
+
return (): void => clearInterval(interval);
|
|
83
|
+
};
|
|
@@ -4,19 +4,34 @@ import { disconnectClient } from '~/client/api/disconnectClient';
|
|
|
4
4
|
import { getDeviceId } from '~/core/device';
|
|
5
5
|
import { proxyWebsocketEvents } from '~/core/events';
|
|
6
6
|
import {
|
|
7
|
+
getUserTopic,
|
|
7
8
|
getNetworkTopic,
|
|
8
9
|
getSmartFeedChannelTopic,
|
|
9
10
|
getSmartFeedMessageTopic,
|
|
10
11
|
getSmartFeedSubChannelTopic,
|
|
11
12
|
subscribeTopic,
|
|
12
13
|
} from '~/core/subscription';
|
|
14
|
+
|
|
13
15
|
import { onUserDeleted } from '~/user/events/onUserDeleted';
|
|
14
16
|
|
|
15
17
|
import { getActiveClient } from './activeClient';
|
|
16
|
-
import {
|
|
18
|
+
import { terminateClient } from './terminateClient';
|
|
19
|
+
import { setActiveUser, getActiveUser } from './activeUser';
|
|
20
|
+
|
|
21
|
+
import { setSessionState } from './setSessionState';
|
|
17
22
|
|
|
18
|
-
import { getToken } from './getToken';
|
|
19
23
|
import { onClientBanned } from '../events';
|
|
24
|
+
import { onTokenExpired } from '../events/onTokenExpired';
|
|
25
|
+
import { onTokenTerminated } from '../events/onTokenTerminated';
|
|
26
|
+
|
|
27
|
+
import { setClientToken } from '../utils/setClientToken';
|
|
28
|
+
|
|
29
|
+
/*
|
|
30
|
+
* declared earlier to accomodate case when logging in with a different user
|
|
31
|
+
* than the one already connected, in which case the existing subscriptions need
|
|
32
|
+
* to be cleared
|
|
33
|
+
*/
|
|
34
|
+
const subscriptions: Amity.Unsubscriber[] = [];
|
|
20
35
|
|
|
21
36
|
/**
|
|
22
37
|
* ```js
|
|
@@ -40,52 +55,118 @@ import { onClientBanned } from '../events';
|
|
|
40
55
|
*/
|
|
41
56
|
export const connectClient = async (
|
|
42
57
|
params: Amity.ConnectClientParams,
|
|
58
|
+
sessionHandler: Amity.SessionHandler,
|
|
43
59
|
config?: Amity.ConnectClientConfig,
|
|
44
60
|
): Promise<boolean> => {
|
|
45
61
|
const client = getActiveClient();
|
|
46
|
-
|
|
62
|
+
let unsubWatcher: Amity.Unsubscriber;
|
|
63
|
+
|
|
64
|
+
client.log('client/api/connectClient', {
|
|
65
|
+
apiKey: client.apiKey,
|
|
66
|
+
sessionState: client.sessionState,
|
|
67
|
+
...params,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// if connecting to a different userId than the one that is connected currently
|
|
71
|
+
if (client.userId && client.userId !== params.userId) {
|
|
72
|
+
await disconnectClient();
|
|
73
|
+
|
|
74
|
+
// Remove subscription to ban and delete
|
|
75
|
+
subscriptions.forEach(fn => fn());
|
|
76
|
+
}
|
|
47
77
|
|
|
48
78
|
// default values
|
|
49
79
|
params.deviceId ??= getDeviceId();
|
|
50
80
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
81
|
+
try {
|
|
82
|
+
// @ts-ignore: in that particular case, typing can be
|
|
83
|
+
// ignored since we enforce default values just before.
|
|
84
|
+
const { users } = await setClientToken(params);
|
|
54
85
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
86
|
+
// FIXME: events are duplicated if connectClient is called few times without disconnectClient
|
|
87
|
+
// wire websocket events to our event emitter
|
|
88
|
+
proxyWebsocketEvents(client.ws, client.emitter);
|
|
58
89
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
90
|
+
// TODO: in phase 2, this should not be necessary. we should have WS
|
|
91
|
+
// to be connected "on demand" rather than "by default"
|
|
92
|
+
await new Promise(resolve => {
|
|
93
|
+
client.ws.once('connect', resolve);
|
|
94
|
+
client.ws.open();
|
|
95
|
+
});
|
|
62
96
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
client.ws.once('connect', resolve);
|
|
67
|
-
client.ws.open();
|
|
68
|
-
});
|
|
97
|
+
client.userId = params.userId;
|
|
98
|
+
|
|
99
|
+
client.sessionHandler = sessionHandler;
|
|
69
100
|
|
|
70
|
-
|
|
71
|
-
|
|
101
|
+
/*
|
|
102
|
+
* Cannot push to subscriptions as watcher needs to continue working even if
|
|
103
|
+
* token expires
|
|
104
|
+
*/
|
|
105
|
+
unsubWatcher = client.accessTokenExpiryWatcher(
|
|
106
|
+
client.token?.issuedAt!,
|
|
107
|
+
client.token?.expiresAt!,
|
|
108
|
+
sessionHandler!,
|
|
109
|
+
);
|
|
72
110
|
|
|
73
|
-
|
|
111
|
+
setActiveUser(users[0]);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
/*
|
|
114
|
+
* if getting token failed session state reverts to initial state when app
|
|
115
|
+
* is first launched
|
|
116
|
+
*/
|
|
117
|
+
setSessionState(Amity.SessionStates.NOT_LOGGED_IN);
|
|
118
|
+
|
|
119
|
+
// pass error down tree so the calling function handle it
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
74
122
|
|
|
75
123
|
if (config?.disableRTE !== true) {
|
|
76
124
|
subscribeTopic(getNetworkTopic());
|
|
77
125
|
subscribeTopic(getSmartFeedChannelTopic());
|
|
78
126
|
subscribeTopic(getSmartFeedSubChannelTopic());
|
|
79
127
|
subscribeTopic(getSmartFeedMessageTopic());
|
|
128
|
+
// subscribing to user topic is necessary to handle ban event
|
|
129
|
+
subscribeTopic(getUserTopic(getActiveUser()));
|
|
80
130
|
}
|
|
81
131
|
|
|
82
|
-
|
|
83
|
-
|
|
132
|
+
subscriptions.push(
|
|
133
|
+
// GLOBAL_BAN
|
|
134
|
+
onClientBanned((_: Amity.UserPayload) => {
|
|
135
|
+
terminateClient();
|
|
136
|
+
|
|
137
|
+
subscriptions.forEach(fn => fn());
|
|
138
|
+
|
|
139
|
+
unsubWatcher();
|
|
140
|
+
}),
|
|
141
|
+
|
|
142
|
+
onTokenTerminated(_ => {
|
|
143
|
+
terminateClient();
|
|
144
|
+
|
|
145
|
+
subscriptions.forEach(fn => fn());
|
|
146
|
+
|
|
147
|
+
unsubWatcher();
|
|
148
|
+
}),
|
|
149
|
+
|
|
150
|
+
onUserDeleted((user: Amity.User) => {
|
|
151
|
+
if (user.userId === client.userId) {
|
|
152
|
+
terminateClient();
|
|
153
|
+
|
|
154
|
+
subscriptions.forEach(fn => fn());
|
|
155
|
+
|
|
156
|
+
unsubWatcher();
|
|
157
|
+
}
|
|
158
|
+
}),
|
|
159
|
+
|
|
160
|
+
onTokenExpired(state => {
|
|
161
|
+
setSessionState(state);
|
|
162
|
+
|
|
84
163
|
disconnectClient();
|
|
164
|
+
|
|
85
165
|
subscriptions.forEach(fn => fn());
|
|
86
166
|
}),
|
|
167
|
+
|
|
87
168
|
onUserDeleted(() => null),
|
|
88
|
-
|
|
169
|
+
);
|
|
89
170
|
|
|
90
171
|
return client.ws.connected;
|
|
91
172
|
};
|
|
@@ -14,6 +14,8 @@ import { createEventEmitter } from '~/core/events';
|
|
|
14
14
|
import { getActiveClient, setActiveClient } from './activeClient';
|
|
15
15
|
import { getFeedSettings } from './getFeedSettings';
|
|
16
16
|
|
|
17
|
+
import { accessTokenExpiryWatcher } from './accessTokenExpiryWatcher';
|
|
18
|
+
|
|
17
19
|
const DEFAULT_DEBUG_SESSION = 'amity';
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -27,7 +29,7 @@ const DEFAULT_DEBUG_SESSION = 'amity';
|
|
|
27
29
|
* @param apiKey for the {@link Amity.Client} instance
|
|
28
30
|
* @param apiRegion endpoint to connect to
|
|
29
31
|
* @param apiEndpoint custom endpoint in case you don't want to use a preset endpoint
|
|
30
|
-
* @param debugSession session's identifier for the client's logger instance
|
|
32
|
+
* @param param.debugSession session's identifier for the client's logger instance
|
|
31
33
|
* @returns A {@link Amity.Client} instance
|
|
32
34
|
*
|
|
33
35
|
* @category Client API
|
|
@@ -59,6 +61,9 @@ export const createClient = (
|
|
|
59
61
|
|
|
60
62
|
const emitter = createEventEmitter();
|
|
61
63
|
|
|
64
|
+
const sessionState = Amity.SessionStates.NOT_LOGGED_IN;
|
|
65
|
+
const sessionHandler = undefined;
|
|
66
|
+
|
|
62
67
|
const client = {
|
|
63
68
|
version: `${VERSION}`,
|
|
64
69
|
|
|
@@ -68,8 +73,11 @@ export const createClient = (
|
|
|
68
73
|
ws,
|
|
69
74
|
mqtt,
|
|
70
75
|
emitter,
|
|
76
|
+
accessTokenExpiryWatcher,
|
|
71
77
|
use: () => setActiveClient(client),
|
|
72
78
|
|
|
79
|
+
sessionState,
|
|
80
|
+
sessionHandler,
|
|
73
81
|
getFeedSettings,
|
|
74
82
|
};
|
|
75
83
|
|