@amityco/ts-sdk 7.5.3-5f273be.0 → 7.5.3-69a90234.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.esm.js CHANGED
@@ -25987,6 +25987,266 @@ const removeChannelMarkerCache = (channel) => {
25987
25987
  dropFromCache(['channelMarker', 'get', id], true);
25988
25988
  };
25989
25989
 
25990
+ /* eslint-disable no-param-reassign */
25991
+ /*
25992
+ * declared earlier to accomodate case when logging in with a different user
25993
+ * than the one already connected, in which case the existing subscriptions need
25994
+ * to be cleared
25995
+ */
25996
+ let subscriptions = [];
25997
+ async function runMqtt() {
25998
+ await modifyMqttConnection();
25999
+ }
26000
+ /* begin_public_function
26001
+ id: client.login
26002
+ */
26003
+ /**
26004
+ * ```js
26005
+ * import { login } from '@amityco/ts-sdk/client/api'
26006
+ * const success = await login({
26007
+ * userId: 'XYZ123456789',
26008
+ * })
26009
+ * ```
26010
+ *
26011
+ * Connects an {@link Amity.Client} instance to ASC servers
26012
+ *
26013
+ * @param params the connect parameters
26014
+ * @param params.userId the user ID for the current session
26015
+ * @param params.displayName the user's displayName for the current session
26016
+ * @param params.deviceId Manual override of the user's device id (for device management)
26017
+ * @param params.authToken The authentication token - necessary when network option is set to secure
26018
+ * @returns a success boolean if connected
26019
+ *
26020
+ * @category Client API
26021
+ * @async
26022
+ */
26023
+ const login = async (params, sessionHandler, config) => {
26024
+ var _a;
26025
+ const client = getActiveClient();
26026
+ let unsubWatcher;
26027
+ client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey, sessionState: client.sessionState }, params));
26028
+ // if connecting to a different userId than the one that is connected currently
26029
+ if (client.userId && client.userId !== params.userId) {
26030
+ await logout();
26031
+ // Remove subscription to ban and delete
26032
+ subscriptions.forEach(fn => fn());
26033
+ subscriptions = [];
26034
+ }
26035
+ // default values
26036
+ const defaultDeviceId = await getDeviceId();
26037
+ try {
26038
+ const { users } = await setClientToken({
26039
+ 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 }),
26040
+ options: {
26041
+ setAccessTokenCookie: true,
26042
+ },
26043
+ });
26044
+ const user = users.find(u => u.userId === params.userId);
26045
+ if (user == null) {
26046
+ throw new ASCError(`${params.userId} has not been founded`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
26047
+ }
26048
+ if (user.isDeleted) {
26049
+ terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
26050
+ return false;
26051
+ }
26052
+ if (user.isGlobalBanned) {
26053
+ terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
26054
+ return false;
26055
+ }
26056
+ // FIXME: events are duplicated if connectClient is called few times without disconnectClient
26057
+ // wire websocket events to our event emitter
26058
+ proxyWebsocketEvents(client.ws, client.emitter);
26059
+ (_a = client.ws) === null || _a === void 0 ? void 0 : _a.open();
26060
+ client.userId = user.userId;
26061
+ client.sessionHandler = sessionHandler;
26062
+ /*
26063
+ * Cannot push to subscriptions as watcher needs to continue working even if
26064
+ * token expires
26065
+ */
26066
+ unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
26067
+ setActiveUser(user);
26068
+ }
26069
+ catch (error) {
26070
+ /*
26071
+ * if getting token failed session state reverts to initial state when app
26072
+ * is first launched
26073
+ */
26074
+ SessionWatcher$1.getInstance().setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
26075
+ // pass error down tree so the calling function handle it
26076
+ throw error;
26077
+ }
26078
+ if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
26079
+ runMqtt();
26080
+ }
26081
+ await initializeMessagePreviewSetting();
26082
+ if (subscriptions.length === 0) {
26083
+ subscriptions.push(
26084
+ // GLOBAL_BAN
26085
+ onClientBanned((_) => {
26086
+ terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
26087
+ subscriptions.forEach(fn => fn());
26088
+ unsubWatcher();
26089
+ }), onTokenTerminated(_ => {
26090
+ terminateClient();
26091
+ subscriptions.forEach(fn => fn());
26092
+ unsubWatcher();
26093
+ }), onUserDeleted$2((user) => {
26094
+ if (user.userId === client.userId) {
26095
+ terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
26096
+ subscriptions.forEach(fn => fn());
26097
+ unsubWatcher();
26098
+ }
26099
+ }), onTokenExpired(state => {
26100
+ SessionWatcher$1.getInstance().setSessionState(state);
26101
+ logout();
26102
+ subscriptions.forEach(fn => fn());
26103
+ }),
26104
+ // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
26105
+ // the channel because currently backend can't handle this, so every time a user is banned from
26106
+ // a channel or the channel is deleted the channel's unread count will not be reset to zero
26107
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
26108
+ if (client.useLegacyUnreadCount) {
26109
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
26110
+ }
26111
+ else
26112
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
26113
+ }
26114
+ return true;
26115
+ };
26116
+ /* end_public_function */
26117
+
26118
+ /* begin_public_function
26119
+ id: client.renew_access_token
26120
+ */
26121
+ /*
26122
+ * Renewal defintion accepted by SessionHandler interface
26123
+ *
26124
+ * Tech Spec:
26125
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
26126
+ *
26127
+ * @category private
26128
+ */
26129
+ const renewal = () => {
26130
+ let tokenRenewed = false;
26131
+ let renewTimeoutId;
26132
+ const client = getActiveClient();
26133
+ client.log('initiating access token renewal');
26134
+ /*
26135
+ * Renews a token if it is hasn't been renewed before. Also marks token as
26136
+ * renewed once done
26137
+ * Per instance of Renewal, only one renewal is allowed
26138
+ */
26139
+ const renewToken = async (authToken) => {
26140
+ const { userId, displayName } = getActiveUser();
26141
+ const deviceId = await getDeviceId();
26142
+ const params = { userId, displayName, authToken, deviceId };
26143
+ if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
26144
+ await login(params, client.sessionHandler);
26145
+ }
26146
+ else {
26147
+ // about to expire
26148
+ await setClientToken({
26149
+ params,
26150
+ options: {
26151
+ setAccessTokenCookie: true,
26152
+ },
26153
+ });
26154
+ }
26155
+ tokenRenewed = true;
26156
+ if (renewTimeoutId)
26157
+ clearTimeout(renewTimeoutId);
26158
+ };
26159
+ return {
26160
+ renew: () => {
26161
+ if (tokenRenewed) {
26162
+ console.log("'renew' method can be called only once per renewal instance");
26163
+ return;
26164
+ }
26165
+ renewToken();
26166
+ },
26167
+ renewWithAuthToken: (authToken) => {
26168
+ if (tokenRenewed) {
26169
+ console.log("'renewWithAuthToken' method can be called only once per renewal instance");
26170
+ return;
26171
+ }
26172
+ renewToken(authToken);
26173
+ },
26174
+ unableToRetrieveAuthToken: () => {
26175
+ renewTimeoutId = setTimeout(() => {
26176
+ var _a;
26177
+ (_a = client.sessionHandler) === null || _a === void 0 ? void 0 : _a.sessionWillRenewAccessToken(renewal());
26178
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
26179
+ },
26180
+ };
26181
+ };
26182
+ /* end_public_function */
26183
+
26184
+ const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
26185
+ const COMPENSATED_DELAY = 5 * MINUTE;
26186
+ /*
26187
+ * a helper function to check if the token has expires
26188
+ *
26189
+ * @param token to be checked
26190
+ * @returns boolean indicating if token expires
26191
+ *
26192
+ * @category private
26193
+ */
26194
+ const isExpired = (expiresAt) => Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
26195
+ /*
26196
+ * a helper function to check if the token is about to expire
26197
+ *
26198
+ * @param token to be checked
26199
+ * @returns boolean indicating if token is aboutToExpire
26200
+ *
26201
+ * @category private
26202
+ */
26203
+ const isAboutToExpire = (params) => {
26204
+ const { expiresAt, issuedAt } = params;
26205
+ const expires = Date.parse(expiresAt);
26206
+ const issued = Date.parse(issuedAt);
26207
+ const now = Date.now();
26208
+ const duration = expires - issued - COMPENSATED_DELAY;
26209
+ const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
26210
+ return now > aboutToExpireAt && now < expires;
26211
+ };
26212
+ /*
26213
+ * Monitors time to expire of token and updates session state to aboutToExpire
26214
+ *
26215
+ * @returns intervalId to be cleared after trigger
26216
+ *
26217
+ * @category private
26218
+ */
26219
+ const accessTokenExpiryWatcher = (sessionHandler) => {
26220
+ const interval = setInterval(() => {
26221
+ const client = getActiveClient();
26222
+ if (!client.token)
26223
+ return;
26224
+ const { issuedAt, expiresAt } = client.token;
26225
+ if (isExpired(expiresAt)) {
26226
+ /*
26227
+ * the event handler will take care of updating session state
26228
+ * Note, this will also clear the interval id, so this event will only be
26229
+ * fired once
26230
+ */
26231
+ fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
26232
+ /*
26233
+ * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
26234
+ *
26235
+ * Why sechduled task?
26236
+ * Since fireEvent is scheduled, it will be called
26237
+ * after sessionHandler leading to an invalid state change from
26238
+ * establishing to tokenExpired
26239
+ */
26240
+ scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
26241
+ return;
26242
+ }
26243
+ if (isAboutToExpire({ expiresAt, issuedAt })) {
26244
+ sessionHandler.sessionWillRenewAccessToken(renewal());
26245
+ }
26246
+ }, ACCESS_TOKEN_WATCHER_INTERVAL);
26247
+ return () => clearInterval(interval);
26248
+ };
26249
+
25990
26250
  const callbacks$9 = [];
25991
26251
  let mainDisposer$8 = null;
25992
26252
  const dispose$9 = (cb) => {
@@ -26259,33 +26519,6 @@ const onChannelMemberRoleRemoved = (callback) => {
26259
26519
  return () => dispose(callback);
26260
26520
  };
26261
26521
 
26262
- /**
26263
- * ```js
26264
- * import { onUserMarkerSync } from '@amityco/ts-sdk'
26265
- * const dispose = onUserMarkerSync(UserMarker => {
26266
- * // ...
26267
- * })
26268
- * ```
26269
- *
26270
- * Fired when an {@link Amity.UserMarker} has been sync
26271
- *
26272
- * @param callback The function to call when the event was fired
26273
- * @returns an {@link Amity.Unsubscriber} function to stop listening
26274
- *
26275
- * @category UserMarker Events
26276
- */
26277
- const onUserMarkerSync = (callback) => {
26278
- const client = getActiveClient();
26279
- const filter = (payload) => {
26280
- const { userMarkers, userEntityMarkers: userEntityMarkersPayload, userFeedMarkers: userFeedMarkersPayload } = payload, rest = __rest(payload, ["userMarkers", "userEntityMarkers", "userFeedMarkers"]);
26281
- const userEntityMarkers = convertChannelMarkerResponse(userEntityMarkersPayload);
26282
- const userFeedMarker = convertSubChannelMarkerResponse(userFeedMarkersPayload);
26283
- ingestInCache(Object.assign({ userMarkers, userEntityMarkers, userFeedMarker }, rest));
26284
- callback(userMarkers[0]);
26285
- };
26286
- return createEventSubscriber(client, 'UserMarker/onUserMarkerSync', 'marker.user-sync', filter);
26287
- };
26288
-
26289
26522
  /**
26290
26523
  * ```js
26291
26524
  * import { onFeedMarkerUpdated } from '@amityco/ts-sdk'
@@ -26557,52 +26790,11 @@ const markerSync = async (deviceLastSyncAt) => {
26557
26790
  };
26558
26791
  };
26559
26792
 
26560
- const enableUnreadCount = () => {
26561
- const client = getActiveClient();
26562
- client.log('client/api/isUnreadCountEnabled', client.isUnreadCountEnabled);
26563
- if (!client) {
26564
- throw new ASCError('There is no active client', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "fatal" /* Amity.ErrorLevel.FATAL */);
26565
- }
26566
- if (client.isUnreadCountEnabled)
26567
- return false;
26568
- client.isUnreadCountEnabled = true;
26569
- client.useLegacyUnreadCount = false;
26570
- client.emitter.emit('unreadCountEnabled', true);
26571
- return true;
26572
- };
26573
-
26574
- /**
26575
- * ```js
26576
- * import { onFeedMarkerUpdated } from '@amityco/ts-sdk'
26577
- * const dispose = onFeedMarkerUpdated(feedMarker => {
26578
- * // ...
26579
- * })
26580
- * ```
26581
- *
26582
- * Fired when an {@link Amity.UserFeedMarker} has been updated
26583
- *
26584
- * @param callback The function to call when the event was fired
26585
- * @returns an {@link Amity.Unsubscriber} function to stop listening
26586
- *
26587
- * @category FeedMarker Events
26588
- */
26589
- const onUserFeedMarkerUpdated = (callback) => {
26590
- const client = getActiveClient();
26591
- const filter = (payload) => {
26592
- persistUnreadCountInfo(payload);
26593
- payload.feedMarkers.forEach(feedMarker => {
26594
- callback(feedMarker);
26595
- });
26596
- };
26597
- return createEventSubscriber(client, 'feedMarker/onUserFeedMarkerUpdated', 'marker.userFeed-updated', filter);
26598
- };
26599
-
26600
26793
  const SYNC_TRIGGER_INTERVAL_TIME = 2000;
26601
- const ON_SUB_CHANNEL_DELETE_SYNC_TRIGGER_DELAY = 2000;
26602
26794
  let isSyncRunning = false;
26603
26795
  let disposers$1 = [];
26604
26796
  let isWaitingForResponse = false;
26605
- let isConsistentMode = true;
26797
+ const isConsistentMode = true;
26606
26798
  let deviceLastSyncAt = null;
26607
26799
  const getDeviceLastSyncAt = () => {
26608
26800
  if (deviceLastSyncAt == null) {
@@ -26617,12 +26809,6 @@ const saveDeviceLastSyncAt = (lastSyncAt) => {
26617
26809
  deviceLastSyncAt = lastSyncAt;
26618
26810
  }
26619
26811
  };
26620
- const fetchDeviceLastSyncAt = async () => {
26621
- const { data: userMarker } = await getUserMarker();
26622
- if (userMarker == null)
26623
- return;
26624
- saveDeviceLastSyncAt(new Date(userMarker.lastSyncAt));
26625
- };
26626
26812
  /**
26627
26813
  * list of conditions that make timer still trigger the syncing process.
26628
26814
  * If it's empty, it means sync is stopped.
@@ -26657,375 +26843,74 @@ const markerSyncTrigger = async () => {
26657
26843
  }
26658
26844
  if (events.length === 0) {
26659
26845
  // no event that require to call marker sync API
26660
- return;
26661
- }
26662
- try {
26663
- isWaitingForResponse = true;
26664
- // any past events are considered processed here.
26665
- // however during waiting for the response, RTE could add the new message event;
26666
- // which will make the engine trigger another call next round.
26667
- events = [];
26668
- const response = await markerSync(getDeviceLastSyncAt().toISOString());
26669
- const latestLastSyncAt = response.data.userMarkers.reduce((maxLastSyncAt, userMarker) => {
26670
- if (maxLastSyncAt == null ||
26671
- maxLastSyncAt.getTime() < new Date(userMarker.lastSyncAt).getTime()) {
26672
- return new Date(userMarker.lastSyncAt);
26673
- }
26674
- return maxLastSyncAt;
26675
- }, null);
26676
- saveDeviceLastSyncAt(latestLastSyncAt);
26677
- if (response.hasMore) {
26678
- events.push("has_more" /* Amity.MarkerSyncEvent.HAS_MORE */);
26679
- }
26680
- }
26681
- catch (_a) {
26682
- // prevent sync from stopping
26683
- }
26684
- finally {
26685
- if (isWaitingForResponse) {
26686
- isWaitingForResponse = false;
26687
- }
26688
- }
26689
- };
26690
- const registerEventListeners = () => {
26691
- if (disposers$1.length > 0) {
26692
- return;
26693
- }
26694
- // based on the tech spec design, we designed a fetch marker in case of these events
26695
- // - new message
26696
- // - create channel
26697
- // - remove channel
26698
- // - app going to online again after offline
26699
- disposers$1.push(onOnline(() => {
26700
- // should add RESUME to the event to trigger marker syncing again
26701
- events.push("resume" /* Amity.MarkerSyncEvent.RESUME */);
26702
- }), onMessageCreatedMqtt(message => {
26703
- // only conversation, community and broadcast types can sync
26704
- const client = getActiveClient();
26705
- if (isUnreadCountSupport$1(message) && message.creatorId !== client.userId)
26706
- events.push("new message" /* Amity.MarkerSyncEvent.NEW_MESSAGE */);
26707
- }), 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(() =>
26708
- /*
26709
- workaround: when receiving the event for sub-channel deletion,
26710
- before triggering marker update, the SDK will have to add a 2-second delay.
26711
- so that the unread count is calculated correctly.
26712
- */
26713
- 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 */)));
26714
- };
26715
- const unRegisterEventListeners = () => {
26716
- disposers$1.forEach(fn => fn());
26717
- disposers$1 = [];
26718
- };
26719
- const startMarkerSync = async () => {
26720
- await fetchDeviceLastSyncAt();
26721
- pushMarkerSyncEvent("start syncing" /* Amity.MarkerSyncEvent.START_SYNCING */);
26722
- isConsistentMode = true;
26723
- isSyncRunning = true;
26724
- registerEventListeners();
26725
- return unRegisterEventListeners;
26726
- };
26727
- /**
26728
- ```js
26729
- * import { startUnreadSync } from '@amityco/ts-sdk'
26730
- * startUnreadSync()
26731
- * ```
26732
- *
26733
- * start syncing to keep feed markers, channel markers and user makers cache
26734
- * update to the server.
26735
- *
26736
- * @category Marker API
26737
- */
26738
- const startUnreadSync = async () => {
26739
- await fetchDeviceLastSyncAt();
26740
- pushMarkerSyncEvent("start syncing" /* Amity.MarkerSyncEvent.START_SYNCING */);
26741
- enableUnreadCount();
26742
- isConsistentMode = false;
26743
- isSyncRunning = true;
26744
- registerEventListeners();
26745
- };
26746
- /**
26747
- ```js
26748
- * import { stopUnreadSync } from '@amityco/ts-sdk'
26749
- * stopUnreadSync()
26750
- * ```
26751
- *
26752
- * stop unread syncing
26753
- *
26754
- * @category Marker API
26755
- */
26756
- const stopUnreadSync = () => {
26757
- isSyncRunning = false;
26758
- setMarkerSyncEvents([]);
26759
- unRegisterEventListeners();
26760
- };
26761
- setIntervalTask(async () => {
26762
- if (!isSyncRunning)
26763
- return;
26764
- await markerSyncTrigger();
26765
- }, SYNC_TRIGGER_INTERVAL_TIME);
26766
- const getMarkerSyncConsistentMode = () => isConsistentMode;
26767
-
26768
- /* eslint-disable no-param-reassign */
26769
- /*
26770
- * declared earlier to accomodate case when logging in with a different user
26771
- * than the one already connected, in which case the existing subscriptions need
26772
- * to be cleared
26773
- */
26774
- let subscriptions = [];
26775
- async function runMqtt() {
26776
- await modifyMqttConnection();
26777
- }
26778
- /* begin_public_function
26779
- id: client.login
26780
- */
26781
- /**
26782
- * ```js
26783
- * import { login } from '@amityco/ts-sdk/client/api'
26784
- * const success = await login({
26785
- * userId: 'XYZ123456789',
26786
- * })
26787
- * ```
26788
- *
26789
- * Connects an {@link Amity.Client} instance to ASC servers
26790
- *
26791
- * @param params the connect parameters
26792
- * @param params.userId the user ID for the current session
26793
- * @param params.displayName the user's displayName for the current session
26794
- * @param params.deviceId Manual override of the user's device id (for device management)
26795
- * @param params.authToken The authentication token - necessary when network option is set to secure
26796
- * @returns a success boolean if connected
26797
- *
26798
- * @category Client API
26799
- * @async
26800
- */
26801
- const login = async (params, sessionHandler, config) => {
26802
- var _a;
26803
- const client = getActiveClient();
26804
- let unsubWatcher;
26805
- client.log('client/api/connectClient', Object.assign({ apiKey: client.apiKey, sessionState: client.sessionState }, params));
26806
- // if connecting to a different userId than the one that is connected currently
26807
- if (client.userId && client.userId !== params.userId) {
26808
- await logout();
26809
- // Remove subscription to ban and delete
26810
- subscriptions.forEach(fn => fn());
26811
- subscriptions = [];
26846
+ return;
26812
26847
  }
26813
- // default values
26814
- const defaultDeviceId = await getDeviceId();
26815
26848
  try {
26816
- const { users } = await setClientToken({
26817
- 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 }),
26818
- options: {
26819
- setAccessTokenCookie: true,
26820
- },
26821
- });
26822
- const user = users.find(u => u.userId === params.userId);
26823
- if (user == null) {
26824
- throw new ASCError(`${params.userId} has not been founded`, 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
26825
- }
26826
- if (user.isDeleted) {
26827
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
26828
- return false;
26829
- }
26830
- if (user.isGlobalBanned) {
26831
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
26832
- return false;
26849
+ isWaitingForResponse = true;
26850
+ // any past events are considered processed here.
26851
+ // however during waiting for the response, RTE could add the new message event;
26852
+ // which will make the engine trigger another call next round.
26853
+ events = [];
26854
+ const response = await markerSync(getDeviceLastSyncAt().toISOString());
26855
+ const latestLastSyncAt = response.data.userMarkers.reduce((maxLastSyncAt, userMarker) => {
26856
+ if (maxLastSyncAt == null ||
26857
+ maxLastSyncAt.getTime() < new Date(userMarker.lastSyncAt).getTime()) {
26858
+ return new Date(userMarker.lastSyncAt);
26859
+ }
26860
+ return maxLastSyncAt;
26861
+ }, null);
26862
+ saveDeviceLastSyncAt(latestLastSyncAt);
26863
+ if (response.hasMore) {
26864
+ events.push("has_more" /* Amity.MarkerSyncEvent.HAS_MORE */);
26833
26865
  }
26834
- // FIXME: events are duplicated if connectClient is called few times without disconnectClient
26835
- // wire websocket events to our event emitter
26836
- proxyWebsocketEvents(client.ws, client.emitter);
26837
- (_a = client.ws) === null || _a === void 0 ? void 0 : _a.open();
26838
- client.userId = user.userId;
26839
- client.sessionHandler = sessionHandler;
26840
- /*
26841
- * Cannot push to subscriptions as watcher needs to continue working even if
26842
- * token expires
26843
- */
26844
- unsubWatcher = client.accessTokenExpiryWatcher(sessionHandler);
26845
- setActiveUser(user);
26846
26866
  }
26847
- catch (error) {
26848
- /*
26849
- * if getting token failed session state reverts to initial state when app
26850
- * is first launched
26851
- */
26852
- SessionWatcher$1.getInstance().setSessionState("notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */);
26853
- // pass error down tree so the calling function handle it
26854
- throw error;
26855
- }
26856
- if ((config === null || config === void 0 ? void 0 : config.disableRTE) !== true) {
26857
- runMqtt();
26867
+ catch (_a) {
26868
+ // prevent sync from stopping
26858
26869
  }
26859
- await initializeMessagePreviewSetting();
26860
- if (subscriptions.length === 0) {
26861
- subscriptions.push(
26862
- // GLOBAL_BAN
26863
- onClientBanned((_) => {
26864
- terminateClient("globalBan" /* Amity.TokenTerminationReason.GLOBAL_BAN */);
26865
- subscriptions.forEach(fn => fn());
26866
- unsubWatcher();
26867
- }), onTokenTerminated(_ => {
26868
- terminateClient();
26869
- subscriptions.forEach(fn => fn());
26870
- unsubWatcher();
26871
- }), onUserDeleted$2((user) => {
26872
- if (user.userId === client.userId) {
26873
- terminateClient("userDeleted" /* Amity.TokenTerminationReason.USER_DELETED */);
26874
- subscriptions.forEach(fn => fn());
26875
- unsubWatcher();
26876
- }
26877
- }), onTokenExpired(state => {
26878
- SessionWatcher$1.getInstance().setSessionState(state);
26879
- logout();
26880
- subscriptions.forEach(fn => fn());
26881
- }),
26882
- // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
26883
- // the channel because currently backend can't handle this, so every time a user is banned from
26884
- // a channel or the channel is deleted the channel's unread count will not be reset to zero
26885
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
26886
- if (client.useLegacyUnreadCount) {
26887
- subscriptions.push(readReceiptSyncEngineOnLoginHandler());
26870
+ finally {
26871
+ if (isWaitingForResponse) {
26872
+ isWaitingForResponse = false;
26888
26873
  }
26889
- else
26890
- subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
26891
- const markerSyncUnsubscriber = await startMarkerSync();
26892
- subscriptions.push(markerSyncUnsubscriber);
26893
26874
  }
26894
- return true;
26895
26875
  };
26896
- /* end_public_function */
26897
-
26898
- /* begin_public_function
26899
- id: client.renew_access_token
26900
- */
26901
- /*
26902
- * Renewal defintion accepted by SessionHandler interface
26903
- *
26904
- * Tech Spec:
26905
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Session-Handler
26906
- *
26907
- * @category private
26908
- */
26909
- const renewal = () => {
26910
- let tokenRenewed = false;
26911
- let renewTimeoutId;
26912
- const client = getActiveClient();
26913
- client.log('initiating access token renewal');
26914
- /*
26915
- * Renews a token if it is hasn't been renewed before. Also marks token as
26916
- * renewed once done
26917
- * Per instance of Renewal, only one renewal is allowed
26918
- */
26919
- const renewToken = async (authToken) => {
26920
- const { userId, displayName } = getActiveUser();
26921
- const deviceId = await getDeviceId();
26922
- const params = { userId, displayName, authToken, deviceId };
26923
- if (client.sessionState === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */ && client.sessionHandler) {
26924
- await login(params, client.sessionHandler);
26925
- }
26926
- else {
26927
- // about to expire
26928
- await setClientToken({
26929
- params,
26930
- options: {
26931
- setAccessTokenCookie: true,
26932
- },
26933
- });
26934
- }
26935
- tokenRenewed = true;
26936
- if (renewTimeoutId)
26937
- clearTimeout(renewTimeoutId);
26938
- };
26939
- return {
26940
- renew: () => {
26941
- if (tokenRenewed) {
26942
- console.log("'renew' method can be called only once per renewal instance");
26943
- return;
26944
- }
26945
- renewToken();
26946
- },
26947
- renewWithAuthToken: (authToken) => {
26948
- if (tokenRenewed) {
26949
- console.log("'renewWithAuthToken' method can be called only once per renewal instance");
26950
- return;
26951
- }
26952
- renewToken(authToken);
26953
- },
26954
- unableToRetrieveAuthToken: () => {
26955
- renewTimeoutId = setTimeout(() => {
26956
- var _a;
26957
- (_a = client.sessionHandler) === null || _a === void 0 ? void 0 : _a.sessionWillRenewAccessToken(renewal());
26958
- }, ACCESS_TOKEN_WATCHER_INTERVAL);
26959
- },
26960
- };
26876
+ const unRegisterEventListeners = () => {
26877
+ disposers$1.forEach(fn => fn());
26878
+ disposers$1 = [];
26961
26879
  };
26962
- /* end_public_function */
26963
-
26964
- const ABOUT_TO_EXPIRE_THRESHOLD = 80 / 100;
26965
- const COMPENSATED_DELAY = 5 * MINUTE;
26966
- /*
26967
- * a helper function to check if the token has expires
26880
+ const startMarkerSync = async () => Promise.resolve();
26881
+ /**
26882
+ ```js
26883
+ * import { startUnreadSync } from '@amityco/ts-sdk'
26884
+ * startUnreadSync()
26885
+ * ```
26968
26886
  *
26969
- * @param token to be checked
26970
- * @returns boolean indicating if token expires
26887
+ * start syncing to keep feed markers, channel markers and user makers cache
26888
+ * update to the server.
26971
26889
  *
26972
- * @category private
26890
+ * @category Marker API
26973
26891
  */
26974
- const isExpired = (expiresAt) => Date.now() > Date.parse(expiresAt) - COMPENSATED_DELAY;
26975
- /*
26976
- * a helper function to check if the token is about to expire
26892
+ const startUnreadSync = async () => Promise.resolve();
26893
+ /**
26894
+ ```js
26895
+ * import { stopUnreadSync } from '@amityco/ts-sdk'
26896
+ * stopUnreadSync()
26897
+ * ```
26977
26898
  *
26978
- * @param token to be checked
26979
- * @returns boolean indicating if token is aboutToExpire
26899
+ * stop unread syncing
26980
26900
  *
26981
- * @category private
26901
+ * @category Marker API
26982
26902
  */
26983
- const isAboutToExpire = (params) => {
26984
- const { expiresAt, issuedAt } = params;
26985
- const expires = Date.parse(expiresAt);
26986
- const issued = Date.parse(issuedAt);
26987
- const now = Date.now();
26988
- const duration = expires - issued - COMPENSATED_DELAY;
26989
- const aboutToExpireAt = issued + duration * ABOUT_TO_EXPIRE_THRESHOLD;
26990
- return now > aboutToExpireAt && now < expires;
26903
+ const stopUnreadSync = () => {
26904
+ isSyncRunning = false;
26905
+ setMarkerSyncEvents([]);
26906
+ unRegisterEventListeners();
26991
26907
  };
26992
- /*
26993
- * Monitors time to expire of token and updates session state to aboutToExpire
26994
- *
26995
- * @returns intervalId to be cleared after trigger
26996
- *
26997
- * @category private
26998
- */
26999
- const accessTokenExpiryWatcher = (sessionHandler) => {
27000
- const interval = setInterval(() => {
27001
- const client = getActiveClient();
27002
- if (!client.token)
27003
- return;
27004
- const { issuedAt, expiresAt } = client.token;
27005
- if (isExpired(expiresAt)) {
27006
- /*
27007
- * the event handler will take care of updating session state
27008
- * Note, this will also clear the interval id, so this event will only be
27009
- * fired once
27010
- */
27011
- fireEvent('tokenExpired', "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */);
27012
- /*
27013
- * https://ekoapp.atlassian.net/wiki/spaces/UP/pages/2082537485/ASC+Core+-+Session+Management+3.0#Automatically-initiate-renewal-flow
27014
- *
27015
- * Why sechduled task?
27016
- * Since fireEvent is scheduled, it will be called
27017
- * after sessionHandler leading to an invalid state change from
27018
- * establishing to tokenExpired
27019
- */
27020
- scheduleTask(() => sessionHandler.sessionWillRenewAccessToken(renewal()));
27021
- return;
27022
- }
27023
- if (isAboutToExpire({ expiresAt, issuedAt })) {
27024
- sessionHandler.sessionWillRenewAccessToken(renewal());
27025
- }
27026
- }, ACCESS_TOKEN_WATCHER_INTERVAL);
27027
- return () => clearInterval(interval);
27028
- };
26908
+ setIntervalTask(async () => {
26909
+ if (!isSyncRunning)
26910
+ return;
26911
+ await markerSyncTrigger();
26912
+ }, SYNC_TRIGGER_INTERVAL_TIME);
26913
+ const getMarkerSyncConsistentMode = () => isConsistentMode;
27029
26914
 
27030
26915
  const DEFAULT_DEBUG_SESSION = 'amity';
27031
26916
  /**
@@ -27172,6 +27057,10 @@ const isConnected = () => {
27172
27057
  isWsConnected);
27173
27058
  };
27174
27059
 
27060
+ const enableUnreadCount = () => {
27061
+ return true;
27062
+ };
27063
+
27175
27064
  var _GlobalFileAccessType_fileAccessType;
27176
27065
  class GlobalFileAccessType {
27177
27066
  constructor() {
@@ -30357,7 +30246,7 @@ const prepareCommentFromFlaggedEvent = (payload) => {
30357
30246
  * @async
30358
30247
  * */
30359
30248
  const addReaction = async (referenceType, referenceId, reactionName) => {
30360
- var _a, _b;
30249
+ var _a, _b, _c;
30361
30250
  const client = getActiveClient();
30362
30251
  client.log('reaction/createReaction', {
30363
30252
  referenceId,
@@ -30378,9 +30267,9 @@ const addReaction = async (referenceType, referenceId, reactionName) => {
30378
30267
  'get',
30379
30268
  referenceId,
30380
30269
  ]);
30381
- if (!model)
30270
+ if (!model || ((_a = model.data.myReactions) === null || _a === void 0 ? void 0 : _a.includes(reactionName)))
30382
30271
  return true;
30383
- const updatedModel = Object.assign(Object.assign({}, model.data), { reactionsCount: model.data.reactionsCount + 1, myReactions: [...((_a = model.data.myReactions) !== null && _a !== void 0 ? _a : []), reactionName], reactions: Object.assign(Object.assign({}, model.data.reactions), { [reactionName]: ((_b = model.data.reactions[reactionName]) !== null && _b !== void 0 ? _b : 0) + 1 }) });
30272
+ const updatedModel = Object.assign(Object.assign({}, model.data), { reactionsCount: model.data.reactionsCount + 1, myReactions: [...((_b = model.data.myReactions) !== null && _b !== void 0 ? _b : []), reactionName], reactions: Object.assign(Object.assign({}, model.data.reactions), { [reactionName]: ((_c = model.data.reactions[reactionName]) !== null && _c !== void 0 ? _c : 0) + 1 }) });
30384
30273
  if (referenceType === 'comment') {
30385
30274
  fireEvent('local.comment.addReaction', {
30386
30275
  comment: updatedModel,