@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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createStream.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deleteStream.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=getStream.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=createSubChannel.test.d.ts.map
@@ -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":"AAQA,eAAO,MAAM,MAAM,cAA4B,CAAC;AAEhD,eAAO,MAAM,aAAa,qBAgBzB,CAAC;AAEF,eAAO,MAAM,gBAAgB,qBAE5B,CAAC;;AAEF,wBAAkB"}
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,11 @@
1
+ export declare const sessionResponse: {
2
+ data: {
3
+ accessToken: string;
4
+ refreshToken: string;
5
+ issuedAt: Date;
6
+ expiresAt: Date;
7
+ users: Amity.User[];
8
+ files: never[];
9
+ };
10
+ };
11
+ //# sourceMappingURL=token.d.ts.map
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/ts-sdk",
3
- "version": "0.0.1-beta.36",
3
+ "version": "0.0.1-beta.37",
4
4
  "license": "CC-BY-ND-4.0",
5
5
  "author": "amity.co <developers@amity.co> (https://amity.co)",
6
6
  "description": "Amity Social Cloud Typescript SDK",
@@ -31,6 +31,7 @@ declare global {
31
31
  QUERY_IN_PROGRESS = 800170,
32
32
  CONNECTION_ERROR = 800210,
33
33
  DISCONNECTED = 800211,
34
+ TOKEN_EXPIRED = 800403,
34
35
  DISALOOW_UNSYNCED_OBJECT = 800800,
35
36
  }
36
37
 
@@ -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
- accessToken?: string;
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: {
@@ -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
+ };
@@ -1,6 +1,6 @@
1
1
  import { ASCError } from '~/core/errors';
2
2
 
3
- let activeUser: Pick<Amity.User, '_id' | 'userId' | 'path'> | null = null;
3
+ let activeUser: Pick<Amity.User, '_id' | 'userId' | 'path' | 'displayName'> | null = null;
4
4
 
5
5
  /**
6
6
  * for internal use
@@ -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 { setActiveUser } from './activeUser';
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
- client.log('client/api/connectClient', { apiKey: client.apiKey, ...params });
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
- // @ts-ignore: in that particular case, typing can be
52
- // ignored since we enforce default values just before.
53
- const { accessToken, users } = await getToken(params);
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
- // manually setup the token for http, ws transport
56
- client.http.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
57
- client.ws.io.opts.query = { token: accessToken };
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
- // FIXME: events are duplicated if connectClient is called few times without disconnectClient
60
- // wire websocket events to our event emitter
61
- proxyWebsocketEvents(client.ws, client.emitter);
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
- // TODO: in phase 2, this should not be necessary. we should have WS
64
- // to be connected "on demand" rather than "by default"
65
- await new Promise(resolve => {
66
- client.ws.once('connect', resolve);
67
- client.ws.open();
68
- });
97
+ client.userId = params.userId;
98
+
99
+ client.sessionHandler = sessionHandler;
69
100
 
70
- client.userId = params.userId;
71
- client.accessToken = accessToken;
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
- setActiveUser(users[0]);
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
- const subscriptions = [
83
- onClientBanned(() => {
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