@amityco/ts-sdk 7.5.3-d52ed38.0 → 7.5.3-d6ee46d.0

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/index.cjs.js CHANGED
@@ -9895,266 +9895,6 @@ const removeChannelMarkerCache = (channel) => {
9895
9895
  dropFromCache(['channelMarker', 'get', id], true);
9896
9896
  };
9897
9897
 
9898
- /* eslint-disable no-param-reassign */
9899
- /*
9900
- * declared earlier to accomodate case when logging in with a different user
9901
- * than the one already connected, in which case the existing subscriptions need
9902
- * to be cleared
9903
- */
9904
- let subscriptions = [];
9905
- async function runMqtt() {
9906
- await modifyMqttConnection();
9907
- }
9908
- /* begin_public_function
9909
- id: client.login
9910
- */
9911
- /**
9912
- * ```js
9913
- * import { login } from '@amityco/ts-sdk/client/api'
9914
- * const success = await login({
9915
- * userId: 'XYZ123456789',
9916
- * })
9917
- * ```
9918
- *
9919
- * Connects an {@link Amity.Client} instance to ASC servers
9920
- *
9921
- * @param params the connect parameters
9922
- * @param params.userId the user ID for the current session
9923
- * @param params.displayName the user's displayName for the current session
9924
- * @param params.deviceId Manual override of the user's device id (for device management)
9925
- * @param params.authToken The authentication token - necessary when network option is set to secure
9926
- * @returns a success boolean if connected
9927
- *
9928
- * @category Client API
9929
- * @async
9930
- */
9931
- const login = async (params, sessionHandler, config) => {
9932
- var _a;
9933
- const client = getActiveClient();
9934
- let unsubWatcher;
9935
- client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey, sessionState: client.sessionState }, params));
9936
- // if connecting to a different userId than the one that is connected currently
9937
- if (client.userId && client.userId !== params.userId) {
9938
- await logout();
9939
- // Remove subscription to ban and delete
9940
- subscriptions.forEach(fn => fn());
9941
- subscriptions = [];
9942
- }
9943
- // default values
9944
- const defaultDeviceId = await getDeviceId();
9945
- try {
9946
- const { users } = await setClientToken({
9947
- params: Object.assign(Object.assign({}, params), { displayName: params === null || params === void 0 ? void 0 : params.displayName, deviceId: (params === null || params === void 0 ? void 0 : params.deviceId) || defaultDeviceId }),
9948
- options: {
9949
- setAccessTokenCookie: true,
9950
- },
9951
- });
9952
- const user = users.find(u => u.userId === params.userId);
9953
- if (user == null) {
9954
- throw new ASCError(`${params.userId} has not been founded`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
9955
- }
9956
- if (user.isDeleted) {
9957
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
9958
- return false;
9959
- }
9960
- if (user.isGlobalBanned) {
9961
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
9962
- return false;
9963
- }
9964
- // FIXME: events are duplicated if connectClient is called few times without disconnectClient
9965
- // wire websocket events to our event emitter
9966
- proxyWebsocketEvents(client.ws, client.emitter);
9967
- (_a = client.ws) === null || _a === void 0 ? void 0 : _a.open();
9968
- client.userId = user.userId;
9969
- client.sessionHandler = sessionHandler;
9970
- /*
9971
- * Cannot push to subscriptions as watcher needs to continue working even if
9972
- * token expires
9973
- */
9974
- unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
9975
- setActiveUser(user);
9976
- }
9977
- catch (error) {
9978
- /*
9979
- * if getting token failed session state reverts to initial state when app
9980
- * is first launched
9981
- */
9982
- SessionWatcher$1.getInstance().setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
9983
- // pass error down tree so the calling function handle it
9984
- throw error;
9985
- }
9986
- if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
9987
- runMqtt();
9988
- }
9989
- await initializeMessagePreviewSetting();
9990
- if (subscriptions.length === 0) {
9991
- subscriptions.push(
9992
- // GLOBAL_BAN
9993
- onClientBanned((_) => {
9994
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
9995
- subscriptions.forEach(fn => fn());
9996
- unsubWatcher();
9997
- }), onTokenTerminated(_ => {
9998
- terminateClient();
9999
- subscriptions.forEach(fn => fn());
10000
- unsubWatcher();
10001
- }), onUserDeleted$2((user) => {
10002
- if (user.userId === client.userId) {
10003
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
10004
- subscriptions.forEach(fn => fn());
10005
- unsubWatcher();
10006
- }
10007
- }), onTokenExpired(state => {
10008
- SessionWatcher$1.getInstance().setSessionState(state);
10009
- logout();
10010
- subscriptions.forEach(fn => fn());
10011
- }),
10012
- // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
10013
- // the channel because currently backend can't handle this, so every time a user is banned from
10014
- // a channel or the channel is deleted the channel's unread count will not be reset to zero
10015
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
10016
- if (client.useLegacyUnreadCount) {
10017
- subscriptions.push(readReceiptSyncEngineOnLoginHandler());
10018
- }
10019
- else
10020
- subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
10021
- }
10022
- return true;
10023
- };
10024
- /* end_public_function */
10025
-
10026
- /* begin_public_function
10027
- id: client.renew_access_token
10028
- */
10029
- /*
10030
- * Renewal defintion accepted by SessionHandler interface
10031
- *
10032
- * Tech Spec:
10033
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
10034
- *
10035
- * @category private
10036
- */
10037
- const renewal = () => {
10038
- let tokenRenewed = false;
10039
- let renewTimeoutId;
10040
- const client = getActiveClient();
10041
- client.log('initiating access token renewal');
10042
- /*
10043
- * Renews a token if it is hasn't been renewed before. Also marks token as
10044
- * renewed once done
10045
- * Per instance of Renewal, only one renewal is allowed
10046
- */
10047
- const renewToken = async (authToken) => {
10048
- const { userId, displayName } = getActiveUser();
10049
- const deviceId = await getDeviceId();
10050
- const params = { userId, displayName, authToken, deviceId };
10051
- if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
10052
- await login(params, client.sessionHandler);
10053
- }
10054
- else {
10055
- // about to expire
10056
- await setClientToken({
10057
- params,
10058
- options: {
10059
- setAccessTokenCookie: true,
10060
- },
10061
- });
10062
- }
10063
- tokenRenewed = true;
10064
- if (renewTimeoutId)
10065
- clearTimeout(renewTimeoutId);
10066
- };
10067
- return {
10068
- renew: () => {
10069
- if (tokenRenewed) {
10070
- console.log("'renew' method can be called only once per renewal instance");
10071
- return;
10072
- }
10073
- renewToken();
10074
- },
10075
- renewWithAuthToken: (authToken) => {
10076
- if (tokenRenewed) {
10077
- console.log("'renewWithAuthToken' method can be called only once per renewal instance");
10078
- return;
10079
- }
10080
- renewToken(authToken);
10081
- },
10082
- unableToRetrieveAuthToken: () => {
10083
- renewTimeoutId = setTimeout(() => {
10084
- var _a;
10085
- (_a = client.sessionHandler) === null || _a === void 0 ? void 0 : _a.sessionWillRenewAccessToken(renewal());
10086
- }, ACCESS_TOKEN_WATCHER_INTERVAL);
10087
- },
10088
- };
10089
- };
10090
- /* end_public_function */
10091
-
10092
- const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
10093
- const COMPENSATED_DELAY = 5 * MINUTE;
10094
- /*
10095
- * a helper function to check if the token has expires
10096
- *
10097
- * @param token to be checked
10098
- * @returns boolean indicating if token expires
10099
- *
10100
- * @category private
10101
- */
10102
- const isExpired = (expiresAt) => Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
10103
- /*
10104
- * a helper function to check if the token is about to expire
10105
- *
10106
- * @param token to be checked
10107
- * @returns boolean indicating if token is aboutToExpire
10108
- *
10109
- * @category private
10110
- */
10111
- const isAboutToExpire = (params) => {
10112
- const { expiresAt, issuedAt } = params;
10113
- const expires = Date.parse(expiresAt);
10114
- const issued = Date.parse(issuedAt);
10115
- const now = Date.now();
10116
- const duration = expires - issued - COMPENSATED_DELAY;
10117
- const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
10118
- return now > aboutToExpireAt && now < expires;
10119
- };
10120
- /*
10121
- * Monitors time to expire of token and updates session state to aboutToExpire
10122
- *
10123
- * @returns intervalId to be cleared after trigger
10124
- *
10125
- * @category private
10126
- */
10127
- const accessTokenExpiryWatcher = (sessionHandler) => {
10128
- const interval = setInterval(() => {
10129
- const client = getActiveClient();
10130
- if (!client.token)
10131
- return;
10132
- const { issuedAt, expiresAt } = client.token;
10133
- if (isExpired(expiresAt)) {
10134
- /*
10135
- * the event handler will take care of updating session state
10136
- * Note, this will also clear the interval id, so this event will only be
10137
- * fired once
10138
- */
10139
- fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
10140
- /*
10141
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
10142
- *
10143
- * Why sechduled task?
10144
- * Since fireEvent is scheduled, it will be called
10145
- * after sessionHandler leading to an invalid state change from
10146
- * establishing to tokenExpired
10147
- */
10148
- scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
10149
- return;
10150
- }
10151
- if (isAboutToExpire({ expiresAt, issuedAt })) {
10152
- sessionHandler.sessionWillRenewAccessToken(renewal());
10153
- }
10154
- }, ACCESS_TOKEN_WATCHER_INTERVAL);
10155
- return () => clearInterval(interval);
10156
- };
10157
-
10158
9898
  const callbacks$9 = [];
10159
9899
  let mainDisposer$8 = null;
10160
9900
  const dispose$9 = (cb) => {
@@ -10427,6 +10167,33 @@ const onChannelMemberRoleRemoved = (callback) => {
10427
10167
  return () => dispose(callback);
10428
10168
  };
10429
10169
 
10170
+ /**
10171
+ * ```js
10172
+ * import { onUserMarkerSync } from '@amityco/ts-sdk'
10173
+ * const dispose = onUserMarkerSync(UserMarker => {
10174
+ * // ...
10175
+ * })
10176
+ * ```
10177
+ *
10178
+ * Fired when an {@link Amity.UserMarker} has been sync
10179
+ *
10180
+ * @param callback The function to call when the event was fired
10181
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
10182
+ *
10183
+ * @category UserMarker Events
10184
+ */
10185
+ const onUserMarkerSync = (callback) => {
10186
+ const client = getActiveClient();
10187
+ const filter = (payload) => {
10188
+ const { userMarkers, userEntityMarkers: userEntityMarkersPayload, userFeedMarkers: userFeedMarkersPayload } = payload, rest = __rest(payload, ["userMarkers", "userEntityMarkers", "userFeedMarkers"]);
10189
+ const userEntityMarkers = convertChannelMarkerResponse(userEntityMarkersPayload);
10190
+ const userFeedMarker = convertSubChannelMarkerResponse(userFeedMarkersPayload);
10191
+ ingestInCache(Object.assign({ userMarkers, userEntityMarkers, userFeedMarker }, rest));
10192
+ callback(userMarkers[0]);
10193
+ };
10194
+ return createEventSubscriber(client, 'UserMarker/onUserMarkerSync', 'marker.user-sync', filter);
10195
+ };
10196
+
10430
10197
  /**
10431
10198
  * ```js
10432
10199
  * import { onFeedMarkerUpdated } from '@amityco/ts-sdk'
@@ -10698,11 +10465,52 @@ const markerSync = async (deviceLastSyncAt) => {
10698
10465
  };
10699
10466
  };
10700
10467
 
10468
+ const enableUnreadCount = () => {
10469
+ const client = getActiveClient();
10470
+ client.log('client/api/isUnreadCountEnabled', client.isUnreadCountEnabled);
10471
+ if (!client) {
10472
+ throw new ASCError('There is no active client', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "fatal" /* Amity.ErrorLevel.FATAL */);
10473
+ }
10474
+ if (client.isUnreadCountEnabled)
10475
+ return false;
10476
+ client.isUnreadCountEnabled = true;
10477
+ client.useLegacyUnreadCount = false;
10478
+ client.emitter.emit('unreadCountEnabled', true);
10479
+ return true;
10480
+ };
10481
+
10482
+ /**
10483
+ * ```js
10484
+ * import { onFeedMarkerUpdated } from '@amityco/ts-sdk'
10485
+ * const dispose = onFeedMarkerUpdated(feedMarker => {
10486
+ * // ...
10487
+ * })
10488
+ * ```
10489
+ *
10490
+ * Fired when an {@link Amity.UserFeedMarker} has been updated
10491
+ *
10492
+ * @param callback The function to call when the event was fired
10493
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
10494
+ *
10495
+ * @category FeedMarker Events
10496
+ */
10497
+ const onUserFeedMarkerUpdated = (callback) => {
10498
+ const client = getActiveClient();
10499
+ const filter = (payload) => {
10500
+ persistUnreadCountInfo(payload);
10501
+ payload.feedMarkers.forEach(feedMarker => {
10502
+ callback(feedMarker);
10503
+ });
10504
+ };
10505
+ return createEventSubscriber(client, 'feedMarker/onUserFeedMarkerUpdated', 'marker.userFeed-updated', filter);
10506
+ };
10507
+
10701
10508
  const SYNC_TRIGGER_INTERVAL_TIME = 2000;
10509
+ const ON_SUB_CHANNEL_DELETE_SYNC_TRIGGER_DELAY = 2000;
10702
10510
  let isSyncRunning = false;
10703
10511
  let disposers$1 = [];
10704
10512
  let isWaitingForResponse = false;
10705
- const isConsistentMode = true;
10513
+ let isConsistentMode = true;
10706
10514
  let deviceLastSyncAt = null;
10707
10515
  const getDeviceLastSyncAt = () => {
10708
10516
  if (deviceLastSyncAt == null) {
@@ -10717,6 +10525,12 @@ const saveDeviceLastSyncAt = (lastSyncAt) => {
10717
10525
  deviceLastSyncAt = lastSyncAt;
10718
10526
  }
10719
10527
  };
10528
+ const fetchDeviceLastSyncAt = async () => {
10529
+ const { data: userMarker } = await getUserMarker();
10530
+ if (userMarker == null)
10531
+ return;
10532
+ saveDeviceLastSyncAt(new Date(userMarker.lastSyncAt));
10533
+ };
10720
10534
  /**
10721
10535
  * list of conditions that make timer still trigger the syncing process.
10722
10536
  * If it's empty, it means sync is stopped.
@@ -10754,71 +10568,372 @@ const markerSyncTrigger = async () => {
10754
10568
  return;
10755
10569
  }
10756
10570
  try {
10757
- isWaitingForResponse = true;
10758
- // any past events are considered processed here.
10759
- // however during waiting for the response, RTE could add the new message event;
10760
- // which will make the engine trigger another call next round.
10761
- events = [];
10762
- const response = await markerSync(getDeviceLastSyncAt().toISOString());
10763
- const latestLastSyncAt = response.data.userMarkers.reduce((maxLastSyncAt, userMarker) => {
10764
- if (maxLastSyncAt == null ||
10765
- maxLastSyncAt.getTime() < new Date(userMarker.lastSyncAt).getTime()) {
10766
- return new Date(userMarker.lastSyncAt);
10767
- }
10768
- return maxLastSyncAt;
10769
- }, null);
10770
- saveDeviceLastSyncAt(latestLastSyncAt);
10771
- if (response.hasMore) {
10772
- events.push("has_more" /* Amity.MarkerSyncEvent.HAS_MORE */);
10571
+ isWaitingForResponse = true;
10572
+ // any past events are considered processed here.
10573
+ // however during waiting for the response, RTE could add the new message event;
10574
+ // which will make the engine trigger another call next round.
10575
+ events = [];
10576
+ const response = await markerSync(getDeviceLastSyncAt().toISOString());
10577
+ const latestLastSyncAt = response.data.userMarkers.reduce((maxLastSyncAt, userMarker) => {
10578
+ if (maxLastSyncAt == null ||
10579
+ maxLastSyncAt.getTime() < new Date(userMarker.lastSyncAt).getTime()) {
10580
+ return new Date(userMarker.lastSyncAt);
10581
+ }
10582
+ return maxLastSyncAt;
10583
+ }, null);
10584
+ saveDeviceLastSyncAt(latestLastSyncAt);
10585
+ if (response.hasMore) {
10586
+ events.push("has_more" /* Amity.MarkerSyncEvent.HAS_MORE */);
10587
+ }
10588
+ }
10589
+ catch (_a) {
10590
+ // prevent sync from stopping
10591
+ }
10592
+ finally {
10593
+ if (isWaitingForResponse) {
10594
+ isWaitingForResponse = false;
10595
+ }
10596
+ }
10597
+ };
10598
+ const registerEventListeners = () => {
10599
+ if (disposers$1.length > 0) {
10600
+ return;
10601
+ }
10602
+ // based on the tech spec design, we designed a fetch marker in case of these events
10603
+ // - new message
10604
+ // - create channel
10605
+ // - remove channel
10606
+ // - app going to online again after offline
10607
+ disposers$1.push(onOnline(() => {
10608
+ // should add RESUME to the event to trigger marker syncing again
10609
+ events.push("resume" /* Amity.MarkerSyncEvent.RESUME */);
10610
+ }), onMessageCreatedMqtt(message => {
10611
+ // only conversation, community and broadcast types can sync
10612
+ const client = getActiveClient();
10613
+ if (isUnreadCountSupport$1(message) && message.creatorId !== client.userId)
10614
+ events.push("new message" /* Amity.MarkerSyncEvent.NEW_MESSAGE */);
10615
+ }), onChannelCreated(() => events.push("subchannel is created" /* Amity.MarkerSyncEvent.CHANNEL_CREATED */)), onChannelDeleted(() => events.push("subchannel is deleted" /* Amity.MarkerSyncEvent.CHANNEL_DELETED */)), onChannelJoined(() => events.push("subchannel is joined" /* Amity.MarkerSyncEvent.CHANNEL_JOINED */)), onChannelLeft(() => events.push("subchannel is left" /* Amity.MarkerSyncEvent.CHANNEL_LEFT */)), onSubChannelCreated(() => events.push("subchannel is created" /* Amity.MarkerSyncEvent.SUB_CHANNEL_CREATED */)), onSubChannelDeleted(() =>
10616
+ /*
10617
+ workaround: when receiving the event for sub-channel deletion,
10618
+ before triggering marker update, the SDK will have to add a 2-second delay.
10619
+ so that the unread count is calculated correctly.
10620
+ */
10621
+ setTimeout(() => events.push("subchannel is deleted" /* Amity.MarkerSyncEvent.SUBCHANNEL_IS_DELETED */), ON_SUB_CHANNEL_DELETE_SYNC_TRIGGER_DELAY)), onFeedMarkerUpdated(() => events.push("feed marker updated" /* Amity.MarkerSyncEvent.MARKER_UPDATED */)), onUserMarkerSync(() => events.push("feed marker updated" /* Amity.MarkerSyncEvent.MARKER_UPDATED */)), onUserFeedMarkerUpdated(() => events.push("feed marker updated" /* Amity.MarkerSyncEvent.MARKER_UPDATED */)));
10622
+ };
10623
+ const unRegisterEventListeners = () => {
10624
+ disposers$1.forEach(fn => fn());
10625
+ disposers$1 = [];
10626
+ };
10627
+ const startMarkerSync = async () => {
10628
+ await fetchDeviceLastSyncAt();
10629
+ pushMarkerSyncEvent("start syncing" /* Amity.MarkerSyncEvent.START_SYNCING */);
10630
+ isConsistentMode = true;
10631
+ isSyncRunning = true;
10632
+ registerEventListeners();
10633
+ return unRegisterEventListeners;
10634
+ };
10635
+ /**
10636
+ ```js
10637
+ * import { startUnreadSync } from '@amityco/ts-sdk'
10638
+ * startUnreadSync()
10639
+ * ```
10640
+ *
10641
+ * start syncing to keep feed markers, channel markers and user makers cache
10642
+ * update to the server.
10643
+ *
10644
+ * @category Marker API
10645
+ */
10646
+ const startUnreadSync = async () => {
10647
+ await fetchDeviceLastSyncAt();
10648
+ pushMarkerSyncEvent("start syncing" /* Amity.MarkerSyncEvent.START_SYNCING */);
10649
+ enableUnreadCount();
10650
+ isConsistentMode = false;
10651
+ isSyncRunning = true;
10652
+ registerEventListeners();
10653
+ };
10654
+ /**
10655
+ ```js
10656
+ * import { stopUnreadSync } from '@amityco/ts-sdk'
10657
+ * stopUnreadSync()
10658
+ * ```
10659
+ *
10660
+ * stop unread syncing
10661
+ *
10662
+ * @category Marker API
10663
+ */
10664
+ const stopUnreadSync = () => {
10665
+ isSyncRunning = false;
10666
+ setMarkerSyncEvents([]);
10667
+ unRegisterEventListeners();
10668
+ };
10669
+ setIntervalTask(async () => {
10670
+ if (!isSyncRunning)
10671
+ return;
10672
+ await markerSyncTrigger();
10673
+ }, SYNC_TRIGGER_INTERVAL_TIME);
10674
+ const getMarkerSyncConsistentMode = () => isConsistentMode;
10675
+
10676
+ /* eslint-disable no-param-reassign */
10677
+ /*
10678
+ * declared earlier to accomodate case when logging in with a different user
10679
+ * than the one already connected, in which case the existing subscriptions need
10680
+ * to be cleared
10681
+ */
10682
+ let subscriptions = [];
10683
+ async function runMqtt() {
10684
+ await modifyMqttConnection();
10685
+ }
10686
+ /* begin_public_function
10687
+ id: client.login
10688
+ */
10689
+ /**
10690
+ * ```js
10691
+ * import { login } from '@amityco/ts-sdk/client/api'
10692
+ * const success = await login({
10693
+ * userId: 'XYZ123456789',
10694
+ * })
10695
+ * ```
10696
+ *
10697
+ * Connects an {@link Amity.Client} instance to ASC servers
10698
+ *
10699
+ * @param params the connect parameters
10700
+ * @param params.userId the user ID for the current session
10701
+ * @param params.displayName the user's displayName for the current session
10702
+ * @param params.deviceId Manual override of the user's device id (for device management)
10703
+ * @param params.authToken The authentication token - necessary when network option is set to secure
10704
+ * @returns a success boolean if connected
10705
+ *
10706
+ * @category Client API
10707
+ * @async
10708
+ */
10709
+ const login = async (params, sessionHandler, config) => {
10710
+ var _a;
10711
+ const client = getActiveClient();
10712
+ let unsubWatcher;
10713
+ client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey, sessionState: client.sessionState }, params));
10714
+ // if connecting to a different userId than the one that is connected currently
10715
+ if (client.userId && client.userId !== params.userId) {
10716
+ await logout();
10717
+ // Remove subscription to ban and delete
10718
+ subscriptions.forEach(fn => fn());
10719
+ subscriptions = [];
10720
+ }
10721
+ // default values
10722
+ const defaultDeviceId = await getDeviceId();
10723
+ try {
10724
+ const { users } = await setClientToken({
10725
+ params: Object.assign(Object.assign({}, params), { displayName: params === null || params === void 0 ? void 0 : params.displayName, deviceId: (params === null || params === void 0 ? void 0 : params.deviceId) || defaultDeviceId }),
10726
+ options: {
10727
+ setAccessTokenCookie: true,
10728
+ },
10729
+ });
10730
+ const user = users.find(u => u.userId === params.userId);
10731
+ if (user == null) {
10732
+ throw new ASCError(`${params.userId} has not been founded`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
10733
+ }
10734
+ if (user.isDeleted) {
10735
+ terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
10736
+ return false;
10737
+ }
10738
+ if (user.isGlobalBanned) {
10739
+ terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
10740
+ return false;
10773
10741
  }
10742
+ // FIXME: events are duplicated if connectClient is called few times without disconnectClient
10743
+ // wire websocket events to our event emitter
10744
+ proxyWebsocketEvents(client.ws, client.emitter);
10745
+ (_a = client.ws) === null || _a === void 0 ? void 0 : _a.open();
10746
+ client.userId = user.userId;
10747
+ client.sessionHandler = sessionHandler;
10748
+ /*
10749
+ * Cannot push to subscriptions as watcher needs to continue working even if
10750
+ * token expires
10751
+ */
10752
+ unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
10753
+ setActiveUser(user);
10774
10754
  }
10775
- catch (_a) {
10776
- // prevent sync from stopping
10755
+ catch (error) {
10756
+ /*
10757
+ * if getting token failed session state reverts to initial state when app
10758
+ * is first launched
10759
+ */
10760
+ SessionWatcher$1.getInstance().setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
10761
+ // pass error down tree so the calling function handle it
10762
+ throw error;
10777
10763
  }
10778
- finally {
10779
- if (isWaitingForResponse) {
10780
- isWaitingForResponse = false;
10764
+ if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
10765
+ runMqtt();
10766
+ }
10767
+ await initializeMessagePreviewSetting();
10768
+ if (subscriptions.length === 0) {
10769
+ subscriptions.push(
10770
+ // GLOBAL_BAN
10771
+ onClientBanned((_) => {
10772
+ terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
10773
+ subscriptions.forEach(fn => fn());
10774
+ unsubWatcher();
10775
+ }), onTokenTerminated(_ => {
10776
+ terminateClient();
10777
+ subscriptions.forEach(fn => fn());
10778
+ unsubWatcher();
10779
+ }), onUserDeleted$2((user) => {
10780
+ if (user.userId === client.userId) {
10781
+ terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
10782
+ subscriptions.forEach(fn => fn());
10783
+ unsubWatcher();
10784
+ }
10785
+ }), onTokenExpired(state => {
10786
+ SessionWatcher$1.getInstance().setSessionState(state);
10787
+ logout();
10788
+ subscriptions.forEach(fn => fn());
10789
+ }),
10790
+ // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
10791
+ // the channel because currently backend can't handle this, so every time a user is banned from
10792
+ // a channel or the channel is deleted the channel's unread count will not be reset to zero
10793
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
10794
+ if (client.useLegacyUnreadCount) {
10795
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
10781
10796
  }
10797
+ else
10798
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
10799
+ const markerSyncUnsubscriber = await startMarkerSync();
10800
+ subscriptions.push(markerSyncUnsubscriber);
10782
10801
  }
10802
+ return true;
10783
10803
  };
10784
- const unRegisterEventListeners = () => {
10785
- disposers$1.forEach(fn => fn());
10786
- disposers$1 = [];
10804
+ /* end_public_function */
10805
+
10806
+ /* begin_public_function
10807
+ id: client.renew_access_token
10808
+ */
10809
+ /*
10810
+ * Renewal defintion accepted by SessionHandler interface
10811
+ *
10812
+ * Tech Spec:
10813
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
10814
+ *
10815
+ * @category private
10816
+ */
10817
+ const renewal = () => {
10818
+ let tokenRenewed = false;
10819
+ let renewTimeoutId;
10820
+ const client = getActiveClient();
10821
+ client.log('initiating access token renewal');
10822
+ /*
10823
+ * Renews a token if it is hasn't been renewed before. Also marks token as
10824
+ * renewed once done
10825
+ * Per instance of Renewal, only one renewal is allowed
10826
+ */
10827
+ const renewToken = async (authToken) => {
10828
+ const { userId, displayName } = getActiveUser();
10829
+ const deviceId = await getDeviceId();
10830
+ const params = { userId, displayName, authToken, deviceId };
10831
+ if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
10832
+ await login(params, client.sessionHandler);
10833
+ }
10834
+ else {
10835
+ // about to expire
10836
+ await setClientToken({
10837
+ params,
10838
+ options: {
10839
+ setAccessTokenCookie: true,
10840
+ },
10841
+ });
10842
+ }
10843
+ tokenRenewed = true;
10844
+ if (renewTimeoutId)
10845
+ clearTimeout(renewTimeoutId);
10846
+ };
10847
+ return {
10848
+ renew: () => {
10849
+ if (tokenRenewed) {
10850
+ console.log("'renew' method can be called only once per renewal instance");
10851
+ return;
10852
+ }
10853
+ renewToken();
10854
+ },
10855
+ renewWithAuthToken: (authToken) => {
10856
+ if (tokenRenewed) {
10857
+ console.log("'renewWithAuthToken' method can be called only once per renewal instance");
10858
+ return;
10859
+ }
10860
+ renewToken(authToken);
10861
+ },
10862
+ unableToRetrieveAuthToken: () => {
10863
+ renewTimeoutId = setTimeout(() => {
10864
+ var _a;
10865
+ (_a = client.sessionHandler) === null || _a === void 0 ? void 0 : _a.sessionWillRenewAccessToken(renewal());
10866
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
10867
+ },
10868
+ };
10787
10869
  };
10788
- const startMarkerSync = async () => Promise.resolve();
10789
- /**
10790
- ```js
10791
- * import { startUnreadSync } from '@amityco/ts-sdk'
10792
- * startUnreadSync()
10793
- * ```
10870
+ /* end_public_function */
10871
+
10872
+ const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
10873
+ const COMPENSATED_DELAY = 5 * MINUTE;
10874
+ /*
10875
+ * a helper function to check if the token has expires
10794
10876
  *
10795
- * start syncing to keep feed markers, channel markers and user makers cache
10796
- * update to the server.
10877
+ * @param token to be checked
10878
+ * @returns boolean indicating if token expires
10797
10879
  *
10798
- * @category Marker API
10880
+ * @category private
10799
10881
  */
10800
- const startUnreadSync = async () => Promise.resolve();
10801
- /**
10802
- ```js
10803
- * import { stopUnreadSync } from '@amityco/ts-sdk'
10804
- * stopUnreadSync()
10805
- * ```
10882
+ const isExpired = (expiresAt) => Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
10883
+ /*
10884
+ * a helper function to check if the token is about to expire
10806
10885
  *
10807
- * stop unread syncing
10886
+ * @param token to be checked
10887
+ * @returns boolean indicating if token is aboutToExpire
10808
10888
  *
10809
- * @category Marker API
10889
+ * @category private
10810
10890
  */
10811
- const stopUnreadSync = () => {
10812
- isSyncRunning = false;
10813
- setMarkerSyncEvents([]);
10814
- unRegisterEventListeners();
10891
+ const isAboutToExpire = (params) => {
10892
+ const { expiresAt, issuedAt } = params;
10893
+ const expires = Date.parse(expiresAt);
10894
+ const issued = Date.parse(issuedAt);
10895
+ const now = Date.now();
10896
+ const duration = expires - issued - COMPENSATED_DELAY;
10897
+ const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
10898
+ return now > aboutToExpireAt && now < expires;
10815
10899
  };
10816
- setIntervalTask(async () => {
10817
- if (!isSyncRunning)
10818
- return;
10819
- await markerSyncTrigger();
10820
- }, SYNC_TRIGGER_INTERVAL_TIME);
10821
- const getMarkerSyncConsistentMode = () => isConsistentMode;
10900
+ /*
10901
+ * Monitors time to expire of token and updates session state to aboutToExpire
10902
+ *
10903
+ * @returns intervalId to be cleared after trigger
10904
+ *
10905
+ * @category private
10906
+ */
10907
+ const accessTokenExpiryWatcher = (sessionHandler) => {
10908
+ const interval = setInterval(() => {
10909
+ const client = getActiveClient();
10910
+ if (!client.token)
10911
+ return;
10912
+ const { issuedAt, expiresAt } = client.token;
10913
+ if (isExpired(expiresAt)) {
10914
+ /*
10915
+ * the event handler will take care of updating session state
10916
+ * Note, this will also clear the interval id, so this event will only be
10917
+ * fired once
10918
+ */
10919
+ fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
10920
+ /*
10921
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
10922
+ *
10923
+ * Why sechduled task?
10924
+ * Since fireEvent is scheduled, it will be called
10925
+ * after sessionHandler leading to an invalid state change from
10926
+ * establishing to tokenExpired
10927
+ */
10928
+ scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
10929
+ return;
10930
+ }
10931
+ if (isAboutToExpire({ expiresAt, issuedAt })) {
10932
+ sessionHandler.sessionWillRenewAccessToken(renewal());
10933
+ }
10934
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
10935
+ return () => clearInterval(interval);
10936
+ };
10822
10937
 
10823
10938
  const DEFAULT_DEBUG_SESSION = 'amity';
10824
10939
  /**
@@ -10965,10 +11080,6 @@ const isConnected = () => {
10965
11080
  isWsConnected);
10966
11081
  };
10967
11082
 
10968
- const enableUnreadCount = () => {
10969
- return true;
10970
- };
10971
-
10972
11083
  var _GlobalFileAccessType_fileAccessType;
10973
11084
  class GlobalFileAccessType {
10974
11085
  constructor() {