@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/client/api/enableUnreadCount.d.ts.map +1 -1
- package/dist/client/api/login.d.ts.map +1 -1
- package/dist/client/utils/markerSyncEngine.d.ts +1 -1
- package/dist/client/utils/markerSyncEngine.d.ts.map +1 -1
- package/dist/index.cjs.js +427 -316
- package/dist/index.esm.js +427 -316
- package/dist/index.umd.js +1 -1
- package/package.json +1 -1
- package/src/client/api/enableUnreadCount.ts +22 -0
- package/src/client/api/login.ts +4 -0
- package/src/client/utils/markerSyncEngine.ts +24 -3
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
|
-
|
|
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 (
|
|
10776
|
-
|
|
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
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
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
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
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
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
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
|
-
*
|
|
10796
|
-
*
|
|
10877
|
+
* @param token to be checked
|
|
10878
|
+
* @returns boolean indicating if token expires
|
|
10797
10879
|
*
|
|
10798
|
-
* @category
|
|
10880
|
+
* @category private
|
|
10799
10881
|
*/
|
|
10800
|
-
const
|
|
10801
|
-
|
|
10802
|
-
|
|
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
|
-
*
|
|
10886
|
+
* @param token to be checked
|
|
10887
|
+
* @returns boolean indicating if token is aboutToExpire
|
|
10808
10888
|
*
|
|
10809
|
-
* @category
|
|
10889
|
+
* @category private
|
|
10810
10890
|
*/
|
|
10811
|
-
const
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
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
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
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() {
|