@atlaskit/collab-provider 10.14.4 → 10.16.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/CHANGELOG.md +20 -0
- package/dist/cjs/channel.js +61 -0
- package/dist/cjs/participants/participants-helper.js +30 -19
- package/dist/cjs/participants/participants-service.js +42 -9
- package/dist/cjs/participants/participants-state.js +7 -3
- package/dist/cjs/provider/commit-step.js +1 -1
- package/dist/cjs/provider/index.js +9 -9
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/channel.js +57 -0
- package/dist/es2019/participants/participants-helper.js +30 -19
- package/dist/es2019/participants/participants-service.js +42 -9
- package/dist/es2019/participants/participants-state.js +5 -3
- package/dist/es2019/provider/commit-step.js +1 -1
- package/dist/es2019/provider/index.js +6 -8
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/channel.js +61 -0
- package/dist/esm/participants/participants-helper.js +30 -19
- package/dist/esm/participants/participants-service.js +42 -9
- package/dist/esm/participants/participants-state.js +7 -3
- package/dist/esm/provider/commit-step.js +1 -1
- package/dist/esm/provider/index.js +9 -9
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/channel.d.ts +16 -0
- package/dist/types/participants/participants-helper.d.ts +12 -0
- package/dist/types/participants/participants-service.d.ts +40 -5
- package/dist/types/participants/participants-state.d.ts +2 -2
- package/dist/types/provider/index.d.ts +4 -7
- package/dist/types/types.d.ts +7 -0
- package/dist/types-ts4.5/channel.d.ts +16 -0
- package/dist/types-ts4.5/participants/participants-helper.d.ts +12 -0
- package/dist/types-ts4.5/participants/participants-service.d.ts +40 -5
- package/dist/types-ts4.5/participants/participants-state.d.ts +2 -2
- package/dist/types-ts4.5/provider/index.d.ts +4 -7
- package/dist/types-ts4.5/types.d.ts +7 -0
- package/package.json +5 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/collab-provider
|
|
2
2
|
|
|
3
|
+
## 10.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#158254](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/158254)
|
|
8
|
+
[`9ce9448c0e11a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/9ce9448c0e11a) -
|
|
9
|
+
Add auto-close for Presence connections when window is in background
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
15
|
+
## 10.15.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- [#157909](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/157909)
|
|
20
|
+
[`384136c930190`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/384136c930190) -
|
|
21
|
+
Add support for initializing collab-provider with presenceActivity
|
|
22
|
+
|
|
3
23
|
## 10.14.4
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/cjs/channel.js
CHANGED
|
@@ -25,6 +25,8 @@ var _network = _interopRequireDefault(require("./connectivity/network"));
|
|
|
25
25
|
var _internalErrors = require("./errors/internal-errors");
|
|
26
26
|
var _ncsErrors = require("./errors/ncs-errors");
|
|
27
27
|
var _customErrors = require("./errors/custom-errors");
|
|
28
|
+
var _featureGateJsClient = _interopRequireDefault(require("@atlaskit/feature-gate-js-client"));
|
|
29
|
+
var _bindEventListener = require("bind-event-listener");
|
|
28
30
|
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
29
31
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
30
32
|
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
@@ -418,6 +420,40 @@ var Channel = exports.Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
418
420
|
(_this$socket3 = _this.socket) === null || _this$socket3 === void 0 || _this$socket3.connect();
|
|
419
421
|
}
|
|
420
422
|
});
|
|
423
|
+
/**
|
|
424
|
+
* Unbinds event listeners and timers used when handling connection auto-close when tab is hidden
|
|
425
|
+
*/
|
|
426
|
+
(0, _defineProperty2.default)(_this, "cleanupAutoDisconnect", function () {
|
|
427
|
+
_this.unbindVisibilityListener();
|
|
428
|
+
if (_this.disconnectTimer) {
|
|
429
|
+
clearTimeout(_this.disconnectTimer);
|
|
430
|
+
_this.disconnectTimer = undefined;
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
/**
|
|
434
|
+
* Cleanup the visiblitychange listener upon Collab Provider destroy
|
|
435
|
+
* Value set when the listener is binded in addVisiblityListener
|
|
436
|
+
*/
|
|
437
|
+
(0, _defineProperty2.default)(_this, "unbindVisibilityListener", function () {});
|
|
438
|
+
(0, _defineProperty2.default)(_this, "autoDisconnect", function (disconnectTimer, disconnectDelay) {
|
|
439
|
+
if (document.hidden) {
|
|
440
|
+
logger('visibilitychange: hidden');
|
|
441
|
+
return setTimeout(function () {
|
|
442
|
+
var _this$socket4;
|
|
443
|
+
logger('visibilitychange: closing connection');
|
|
444
|
+
(_this$socket4 = _this.socket) === null || _this$socket4 === void 0 || _this$socket4.close();
|
|
445
|
+
}, disconnectDelay || disconnectDelay === 0 ? disconnectDelay * 1000 : 60 * 1000);
|
|
446
|
+
} else {
|
|
447
|
+
var _this$socket5;
|
|
448
|
+
logger('visibilitychange: visible');
|
|
449
|
+
if (disconnectTimer) {
|
|
450
|
+
clearTimeout(disconnectTimer);
|
|
451
|
+
}
|
|
452
|
+
logger('visibilitychange: re-connecting');
|
|
453
|
+
(_this$socket5 = _this.socket) === null || _this$socket5 === void 0 || _this$socket5.connect();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
});
|
|
421
457
|
_this.config = config;
|
|
422
458
|
_this.analyticsHelper = analyticsHelper;
|
|
423
459
|
_this.initExperience = (0, _ufo.createDocInitExp)(_this.analyticsHelper);
|
|
@@ -651,6 +687,10 @@ var Channel = exports.Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
651
687
|
this.reconnectHelper = new _reconnectHelper.default();
|
|
652
688
|
// Fired upon a reconnection attempt error (from Socket.IO Manager)
|
|
653
689
|
this.socket.io.on('reconnect_error', this.onReconnectError);
|
|
690
|
+
|
|
691
|
+
// Automatic disconnect on tab background with delay, to keep presence UX accurate
|
|
692
|
+
// and reduce wasted connections. Reconnects upon tab becoming active again
|
|
693
|
+
this.addVisiblityListener();
|
|
654
694
|
}
|
|
655
695
|
|
|
656
696
|
// Ignored via go/ees005
|
|
@@ -775,11 +815,32 @@ var Channel = exports.Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
775
815
|
value: function isLimitExceeded(stepLimit, stepSizeLimit, maxStepSizeLimit) {
|
|
776
816
|
return stepLimit > 0 && this.stepCounter > stepLimit || stepSizeLimit > 0 && this.stepSizeCounter > stepSizeLimit || maxStepSizeLimit > 0 && this.maxStepSize > maxStepSizeLimit;
|
|
777
817
|
}
|
|
818
|
+
}, {
|
|
819
|
+
key: "addVisiblityListener",
|
|
820
|
+
value:
|
|
821
|
+
/**
|
|
822
|
+
* Adds an event listener for visibilitychange events to handle auto-disconnection if tab is in background
|
|
823
|
+
*/
|
|
824
|
+
function addVisiblityListener() {
|
|
825
|
+
var _FeatureGates$getExpe,
|
|
826
|
+
_this3 = this;
|
|
827
|
+
var disconnectDelay = (_FeatureGates$getExpe = _featureGateJsClient.default.getExperimentValue('platform_editor_connection_auto_disconnect_delay', 'delay', -1)) !== null && _FeatureGates$getExpe !== void 0 ? _FeatureGates$getExpe : -1;
|
|
828
|
+
var isAutoDisconnectEnabled = disconnectDelay >= 0;
|
|
829
|
+
if (isAutoDisconnectEnabled && this.config.isPresenceOnly) {
|
|
830
|
+
this.unbindVisibilityListener = (0, _bindEventListener.bind)(document, {
|
|
831
|
+
type: 'visibilitychange',
|
|
832
|
+
listener: function listener() {
|
|
833
|
+
_this3.disconnectTimer = _this3.autoDisconnect(_this3.disconnectTimer, disconnectDelay);
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
}
|
|
778
838
|
}, {
|
|
779
839
|
key: "disconnect",
|
|
780
840
|
value: function disconnect() {
|
|
781
841
|
var _this$network;
|
|
782
842
|
this.unsubscribeAll();
|
|
843
|
+
this.cleanupAutoDisconnect();
|
|
783
844
|
(_this$network = this.network) === null || _this$network === void 0 || _this$network.destroy();
|
|
784
845
|
this.network = null;
|
|
785
846
|
if (this.socket) {
|
|
@@ -49,13 +49,26 @@ var createParticipantFromPayload = exports.createParticipantFromPayload = /*#__P
|
|
|
49
49
|
return _ref.apply(this, arguments);
|
|
50
50
|
};
|
|
51
51
|
}();
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Will use the getUsers callback from batchProps to fetch users
|
|
55
|
+
*
|
|
56
|
+
* 1. Determine all the participants that need to be hydrated
|
|
57
|
+
* 2. Only fetch a subset of those participants based on batchSize
|
|
58
|
+
* 3. Of the users fetched, find all of those users' sessions and mark those entries as hydrated
|
|
59
|
+
*
|
|
60
|
+
* @param participantsState
|
|
61
|
+
* @param batchProps
|
|
62
|
+
* @returns
|
|
63
|
+
* @example
|
|
64
|
+
*/
|
|
52
65
|
var fetchParticipants = exports.fetchParticipants = /*#__PURE__*/function () {
|
|
53
66
|
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(participantsState, batchProps) {
|
|
54
67
|
var _batchProps$batchSize, batchSize, getUsers, participantsToHydrate, participants, aaids, users, hydratedParticipants;
|
|
55
68
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
56
69
|
while (1) switch (_context2.prev = _context2.next) {
|
|
57
70
|
case 0:
|
|
58
|
-
_batchProps$batchSize = batchProps.batchSize, batchSize = _batchProps$batchSize === void 0 ?
|
|
71
|
+
_batchProps$batchSize = batchProps.batchSize, batchSize = _batchProps$batchSize === void 0 ? DEFAULT_BATCH_FETCH_SIZE : _batchProps$batchSize, getUsers = batchProps.getUsers;
|
|
59
72
|
participantsToHydrate = participantsState.getUniqueParticipants({
|
|
60
73
|
isHydrated: false
|
|
61
74
|
});
|
|
@@ -81,24 +94,22 @@ var fetchParticipants = exports.fetchParticipants = /*#__PURE__*/function () {
|
|
|
81
94
|
return p.userId === user.userId;
|
|
82
95
|
}).forEach(function (participant) {
|
|
83
96
|
var sessionId = participant.sessionId;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
hydratedParticipants.push(hydratedParticipant);
|
|
101
|
-
}
|
|
97
|
+
var hydratedParticipant = {
|
|
98
|
+
name: user.name,
|
|
99
|
+
avatar: user.avatar,
|
|
100
|
+
email: user.email,
|
|
101
|
+
userId: user.userId,
|
|
102
|
+
isGuest: user.isGuest,
|
|
103
|
+
sessionId: sessionId,
|
|
104
|
+
lastActive: participant.lastActive,
|
|
105
|
+
clientId: participant.clientId,
|
|
106
|
+
permit: participant.permit,
|
|
107
|
+
presenceId: participant.presenceId,
|
|
108
|
+
presenceActivity: participant.presenceActivity,
|
|
109
|
+
isHydrated: true
|
|
110
|
+
};
|
|
111
|
+
participantsState.setBySessionId(sessionId, hydratedParticipant);
|
|
112
|
+
hydratedParticipants.push(hydratedParticipant);
|
|
102
113
|
});
|
|
103
114
|
});
|
|
104
115
|
return _context2.abrupt("return", hydratedParticipants);
|
|
@@ -33,6 +33,20 @@ var UNIDENTIFIED = 'unidentified';
|
|
|
33
33
|
* @param sendPresenceJoined Callback to Channel class
|
|
34
34
|
*/
|
|
35
35
|
var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function () {
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* @param analyticsHelper
|
|
39
|
+
* @param participantsState
|
|
40
|
+
* @param emit
|
|
41
|
+
* @param getUser
|
|
42
|
+
* @param batchProps
|
|
43
|
+
* @param channelBroadcast
|
|
44
|
+
* @param sendPresenceJoined
|
|
45
|
+
* @param getPresenceData
|
|
46
|
+
* @param setUserId
|
|
47
|
+
* @param getAIProviderActiveIds
|
|
48
|
+
* @example
|
|
49
|
+
*/
|
|
36
50
|
function ParticipantsService(analyticsHelper) {
|
|
37
51
|
var _this = this;
|
|
38
52
|
var participantsState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new _participantsState.ParticipantsState();
|
|
@@ -100,6 +114,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
100
114
|
/**
|
|
101
115
|
* Carries out 3 things: 1) enriches the participant with user data, 2) updates the participantsState, 3) emits the presence event
|
|
102
116
|
* @param payload Payload from incoming socket event
|
|
117
|
+
* @example
|
|
103
118
|
*/
|
|
104
119
|
(0, _defineProperty2.default)(this, "updateParticipantEager", /*#__PURE__*/function () {
|
|
105
120
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(payload) {
|
|
@@ -173,12 +188,15 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
173
188
|
* 3. If incoming participant is not new, update previous state with new values (timestamp, activity)
|
|
174
189
|
*
|
|
175
190
|
* @param payload Payload from incoming socket event
|
|
191
|
+
* @example
|
|
176
192
|
*/
|
|
177
193
|
(0, _defineProperty2.default)(this, "updateParticipantLazy", function (payload) {
|
|
178
194
|
var userId = payload.userId,
|
|
179
195
|
sessionId = payload.sessionId;
|
|
180
196
|
|
|
181
|
-
// anonymous users always skip hydration
|
|
197
|
+
// anonymous users always skip hydration but are marked as hydrated since we don't want to attempt to fetch data
|
|
198
|
+
// this can cause interesting behavior if batchProps.participantsLimit exists
|
|
199
|
+
// for example if limit = 5 and we've hydrated 5 real users and 2 anonymous users join, it'll look like we've hydrated 7 users
|
|
182
200
|
if (!userId || userId === UNIDENTIFIED) {
|
|
183
201
|
var _participant = _objectSpread(_objectSpread({}, payload), {}, {
|
|
184
202
|
lastActive: payload.timestamp,
|
|
@@ -223,10 +241,6 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
223
241
|
_this.emitPresence({
|
|
224
242
|
joined: [participant]
|
|
225
243
|
}, 'handling updated previous participant event');
|
|
226
|
-
// prevent running multiple debounces concurrently
|
|
227
|
-
if (!_this.currentlyPollingFetchUsers) {
|
|
228
|
-
void _this.batchFetchUsers();
|
|
229
|
-
}
|
|
230
244
|
});
|
|
231
245
|
(0, _defineProperty2.default)(this, "onParticipantUpdated", /*#__PURE__*/function () {
|
|
232
246
|
var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(payload) {
|
|
@@ -256,6 +270,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
256
270
|
/**
|
|
257
271
|
* Called when a participant leaves the session.
|
|
258
272
|
* We emit the `presence` event to update the active avatars in the editor.
|
|
273
|
+
* @param payload
|
|
274
|
+
* @example
|
|
259
275
|
*/
|
|
260
276
|
(0, _defineProperty2.default)(this, "onParticipantLeft", function (payload) {
|
|
261
277
|
var _payload$data;
|
|
@@ -311,6 +327,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
311
327
|
/**
|
|
312
328
|
* Updates when users were last active
|
|
313
329
|
* @param userIds Users in most recent steps
|
|
330
|
+
* @example
|
|
314
331
|
*/
|
|
315
332
|
(0, _defineProperty2.default)(this, "updateLastActive", function () {
|
|
316
333
|
var userIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
@@ -319,6 +336,9 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
319
336
|
/**
|
|
320
337
|
* Called when we receive a telepointer update from another
|
|
321
338
|
* participant.
|
|
339
|
+
* @param payload
|
|
340
|
+
* @param thisSessionId
|
|
341
|
+
* @example
|
|
322
342
|
*/
|
|
323
343
|
(0, _defineProperty2.default)(this, "onParticipantTelepointer", function (payload, thisSessionId) {
|
|
324
344
|
var sessionId = payload.sessionId,
|
|
@@ -344,6 +364,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
344
364
|
* Every 5 minutes (PARTICIPANT_UPDATE_INTERVAL), removes inactive participants and emits the update to other participants.
|
|
345
365
|
* Needs to be kicked off in the Provider.
|
|
346
366
|
* @param sessionId SessionId from provider's connection
|
|
367
|
+
* @example
|
|
347
368
|
*/
|
|
348
369
|
(0, _defineProperty2.default)(this, "startInactiveRemover", function (sessionId) {
|
|
349
370
|
clearTimeout(_this.participantUpdateTimeout);
|
|
@@ -400,6 +421,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
400
421
|
*
|
|
401
422
|
* if no {@link BatchProps#participantsLimit} is supplied
|
|
402
423
|
* 1. Fetch users until there are no more participants to hydrate
|
|
424
|
+
* @example
|
|
403
425
|
*/
|
|
404
426
|
(0, _defineProperty2.default)(this, "batchFetchUsers", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
|
|
405
427
|
var _this$batchProps, debounceTime, participantsLimit, size;
|
|
@@ -463,8 +485,9 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
463
485
|
/**
|
|
464
486
|
* We want to give some time for users to initially join before attempting to fetch users
|
|
465
487
|
* otherwise we'll always make at least 2 calls if there's more than 1 participant
|
|
488
|
+
* @example
|
|
466
489
|
*/
|
|
467
|
-
(0, _defineProperty2.default)(this, "
|
|
490
|
+
(0, _defineProperty2.default)(this, "initializeFirstBatchFetchUsers", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
|
|
468
491
|
return _regenerator.default.wrap(function _callee5$(_context5) {
|
|
469
492
|
while (1) switch (_context5.prev = _context5.next) {
|
|
470
493
|
case 0:
|
|
@@ -483,6 +506,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
483
506
|
})));
|
|
484
507
|
/**
|
|
485
508
|
* Keep list of participants up to date. Filter out inactive users etc.
|
|
509
|
+
* @param sessionId
|
|
510
|
+
* @example
|
|
486
511
|
*/
|
|
487
512
|
(0, _defineProperty2.default)(this, "filterInactive", function (sessionId) {
|
|
488
513
|
var now = Date.now();
|
|
@@ -500,6 +525,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
500
525
|
* Wrapper function to emit with error handling and analytics
|
|
501
526
|
* @param data Data to emit
|
|
502
527
|
* @param emit Emit function from Provider
|
|
528
|
+
* @param errorMessage
|
|
529
|
+
* @example
|
|
503
530
|
*/
|
|
504
531
|
(0, _defineProperty2.default)(this, "emitPresence", function (data, errorMessage) {
|
|
505
532
|
try {
|
|
@@ -518,6 +545,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
518
545
|
* Wrapper function to emit with error handling and analytics
|
|
519
546
|
* @param data Data to emit
|
|
520
547
|
* @param emit Emit function from Provider
|
|
548
|
+
* @param errorMessage
|
|
549
|
+
* @example
|
|
521
550
|
*/
|
|
522
551
|
(0, _defineProperty2.default)(this, "emitTelepointer", function (data, errorMessage) {
|
|
523
552
|
try {
|
|
@@ -530,6 +559,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
530
559
|
});
|
|
531
560
|
/**
|
|
532
561
|
* Used when the provider is disconnected or destroyed to prevent perpetual timers from continuously running
|
|
562
|
+
* @example
|
|
533
563
|
*/
|
|
534
564
|
(0, _defineProperty2.default)(this, "clearTimers", function () {
|
|
535
565
|
clearTimeout(_this.participantUpdateTimeout);
|
|
@@ -558,6 +588,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
558
588
|
* We keep track of participants internally, and emit the `presence` event to update
|
|
559
589
|
* the active avatars in the editor.
|
|
560
590
|
* This method will be triggered from backend to notify all participants to exchange presence
|
|
591
|
+
* @param payload
|
|
592
|
+
* @example
|
|
561
593
|
*/
|
|
562
594
|
(0, _defineProperty2.default)(this, "onPresenceJoined", function (payload) {
|
|
563
595
|
try {
|
|
@@ -575,6 +607,8 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
575
607
|
*
|
|
576
608
|
* This will send both a 'presence' event and a 'participant:updated' event.
|
|
577
609
|
* This updates both the avatars and the participants list.
|
|
610
|
+
* @param payload
|
|
611
|
+
* @example
|
|
578
612
|
*/
|
|
579
613
|
(0, _defineProperty2.default)(this, "onPresence", function (payload) {
|
|
580
614
|
try {
|
|
@@ -590,9 +624,6 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
590
624
|
(_this$analyticsHelper10 = _this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 || _this$analyticsHelper10.sendErrorEvent(error, 'Error while receiving presence');
|
|
591
625
|
}
|
|
592
626
|
});
|
|
593
|
-
/**
|
|
594
|
-
*
|
|
595
|
-
*/
|
|
596
627
|
(0, _defineProperty2.default)(this, "getParticipants", function () {
|
|
597
628
|
return _this.participantsState.getParticipants();
|
|
598
629
|
});
|
|
@@ -625,6 +656,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
625
656
|
/**
|
|
626
657
|
* Called on receiving steps, emits each step's telepointer
|
|
627
658
|
* @param steps Steps to extract telepointers from
|
|
659
|
+
* @example
|
|
628
660
|
*/
|
|
629
661
|
function emitTelepointersFromSteps(steps) {
|
|
630
662
|
var _this2 = this;
|
|
@@ -642,6 +674,7 @@ var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function ()
|
|
|
642
674
|
* Wrapper function to emit with error handling and analytics
|
|
643
675
|
* @param data Data to emit
|
|
644
676
|
* @param errorMessage Error message for analytics
|
|
677
|
+
* @example
|
|
645
678
|
*/
|
|
646
679
|
function emitPresenceActivityChange(data, errorMessage) {
|
|
647
680
|
try {
|
|
@@ -47,8 +47,8 @@ var ParticipantsState = exports.ParticipantsState = /*#__PURE__*/(0, _createClas
|
|
|
47
47
|
/**
|
|
48
48
|
* A user may contain multiple sessions, only return the unique users based on aaid.
|
|
49
49
|
* If multiple participants with same aaid exist, will return the most recent entry
|
|
50
|
-
* @param
|
|
51
|
-
* @
|
|
50
|
+
* @param filter additional filter to narrow down results
|
|
51
|
+
* @param filter.isHydrated
|
|
52
52
|
*/
|
|
53
53
|
(0, _defineProperty2.default)(this, "getUniqueParticipants", function (_ref) {
|
|
54
54
|
var _ref$isHydrated = _ref.isHydrated,
|
|
@@ -58,7 +58,11 @@ var ParticipantsState = exports.ParticipantsState = /*#__PURE__*/(0, _createClas
|
|
|
58
58
|
participants.forEach(function (p) {
|
|
59
59
|
if (!!p.isHydrated === isHydrated) {
|
|
60
60
|
var previous = uniqueParticipants.get(p.userId);
|
|
61
|
-
uniqueParticipants.set(p.userId, previous ? _objectSpread(_objectSpread({}, previous),
|
|
61
|
+
uniqueParticipants.set(p.userId, previous ? _objectSpread(_objectSpread({}, previous), {}, {
|
|
62
|
+
lastActive: p.lastActive,
|
|
63
|
+
sessionId: p.sessionId,
|
|
64
|
+
presenceActivity: p.presenceActivity
|
|
65
|
+
}) : p);
|
|
62
66
|
}
|
|
63
67
|
});
|
|
64
68
|
return (0, _toConsumableArray2.default)(uniqueParticipants.values());
|
|
@@ -74,7 +74,7 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
|
74
74
|
// - doesn't impact any indexes,
|
|
75
75
|
// - is setup for last write wins,
|
|
76
76
|
// - and is just a boolean -- so no real risk of data loss.
|
|
77
|
-
if (__livePage
|
|
77
|
+
if (__livePage) {
|
|
78
78
|
stepsWithClientAndUserId = stepsWithClientAndUserId.map(function (step) {
|
|
79
79
|
if (isExpandChangeStep(step)) {
|
|
80
80
|
// The title is also updated via this step, which we do want to send to the server.
|
|
@@ -152,7 +152,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
152
152
|
if (_this.config.getUser) {
|
|
153
153
|
throw new _customErrors.ProviderInitialisationError('Cannot supply getUser and batchProps together');
|
|
154
154
|
}
|
|
155
|
-
_this.participantsService.
|
|
155
|
+
_this.participantsService.initializeFirstBatchFetchUsers();
|
|
156
156
|
}
|
|
157
157
|
_this.disconnectedAt = undefined;
|
|
158
158
|
}).on('init', function (_ref3) {
|
|
@@ -330,9 +330,6 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
330
330
|
clearTimeout(_this.presenceUpdateTimeout);
|
|
331
331
|
_this.participantsService.clearTimers();
|
|
332
332
|
});
|
|
333
|
-
/**
|
|
334
|
-
*
|
|
335
|
-
*/
|
|
336
333
|
(0, _defineProperty2.default)(_this, "getParticipants", function () {
|
|
337
334
|
return _this.participantsService.getParticipants();
|
|
338
335
|
});
|
|
@@ -359,7 +356,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
359
356
|
while (1) switch (_context4.prev = _context4.next) {
|
|
360
357
|
case 0:
|
|
361
358
|
if (!_this.config.batchProps) {
|
|
362
|
-
_context4.next =
|
|
359
|
+
_context4.next = 5;
|
|
363
360
|
break;
|
|
364
361
|
}
|
|
365
362
|
_context4.next = 3;
|
|
@@ -367,8 +364,11 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
367
364
|
batchSize: (_props$fetchSize = props === null || props === void 0 ? void 0 : props.fetchSize) !== null && _props$fetchSize !== void 0 ? _props$fetchSize : _this.config.batchProps.batchSize
|
|
368
365
|
}));
|
|
369
366
|
case 3:
|
|
367
|
+
_context4.next = 6;
|
|
368
|
+
break;
|
|
369
|
+
case 5:
|
|
370
370
|
throw new Error('Must provide batch properties to use fetchMore');
|
|
371
|
-
case
|
|
371
|
+
case 6:
|
|
372
372
|
case "end":
|
|
373
373
|
return _context4.stop();
|
|
374
374
|
}
|
|
@@ -395,6 +395,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
395
395
|
_this.metadataService = new _metadataService.MetadataService(_this.emitCallback, _this.channel.sendMetadata);
|
|
396
396
|
_this.namespaceService = new _namespaceService.NamespaceService();
|
|
397
397
|
_this.presenceId = _this.config.presenceId;
|
|
398
|
+
_this.presenceActivity = _this.config.presenceActivity;
|
|
398
399
|
if (config.isPresenceOnly) {
|
|
399
400
|
// this check is specifically for the presence only
|
|
400
401
|
// This presence feature is only for the confluence view page & jira presence which do not need the document service or api
|
|
@@ -434,8 +435,8 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
434
435
|
/**
|
|
435
436
|
* Initialisation logic, called by the editor in the collab-edit plugin.
|
|
436
437
|
*
|
|
437
|
-
* @param {Object} options ...
|
|
438
438
|
* @param {Function} options.getState Function that returns the editor state, used to retrieve collab-edit properties and to interact with prosemirror-collab
|
|
439
|
+
* @param options.editorApi
|
|
439
440
|
* @param {SyncUpErrorFunction} options.onSyncUpError (Optional) Function that gets called when the sync of steps fails after retrying 30 times, used by Editor to log to analytics
|
|
440
441
|
* @throws {ProviderInitialisationError} Something went wrong during provider initialisation
|
|
441
442
|
*/
|
|
@@ -500,9 +501,8 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
500
501
|
// Only used for the presence - opts out of the document service and api service
|
|
501
502
|
}, {
|
|
502
503
|
key: "setupForPresenceOnly",
|
|
503
|
-
value: function setupForPresenceOnly(clientId
|
|
504
|
+
value: function setupForPresenceOnly(clientId) {
|
|
504
505
|
this.clientId = clientId;
|
|
505
|
-
this.presenceActivity = presenceActivity;
|
|
506
506
|
this.checkForCookies();
|
|
507
507
|
try {
|
|
508
508
|
if (!this.isChannelInitialized) {
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.version = exports.nextMajorVersion = exports.name = void 0;
|
|
7
7
|
var name = exports.name = "@atlaskit/collab-provider";
|
|
8
|
-
var version = exports.version = "10.
|
|
8
|
+
var version = exports.version = "10.16.0";
|
|
9
9
|
var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
|
|
10
10
|
return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
|
|
11
11
|
};
|
package/dist/es2019/channel.js
CHANGED
|
@@ -11,6 +11,8 @@ import Network from './connectivity/network';
|
|
|
11
11
|
import { INTERNAL_ERROR_CODE } from './errors/internal-errors';
|
|
12
12
|
import { NCS_ERROR_CODE } from './errors/ncs-errors';
|
|
13
13
|
import { NotConnectedError, NotInitializedError } from './errors/custom-errors';
|
|
14
|
+
import FeatureGates from '@atlaskit/feature-gate-js-client';
|
|
15
|
+
import { bind } from 'bind-event-listener';
|
|
14
16
|
const logger = createLogger('Channel', 'green');
|
|
15
17
|
export class Channel extends Emitter {
|
|
16
18
|
constructor(config, analyticsHelper) {
|
|
@@ -299,6 +301,40 @@ export class Channel extends Emitter {
|
|
|
299
301
|
(_this$socket3 = this.socket) === null || _this$socket3 === void 0 ? void 0 : _this$socket3.connect();
|
|
300
302
|
}
|
|
301
303
|
});
|
|
304
|
+
/**
|
|
305
|
+
* Unbinds event listeners and timers used when handling connection auto-close when tab is hidden
|
|
306
|
+
*/
|
|
307
|
+
_defineProperty(this, "cleanupAutoDisconnect", () => {
|
|
308
|
+
this.unbindVisibilityListener();
|
|
309
|
+
if (this.disconnectTimer) {
|
|
310
|
+
clearTimeout(this.disconnectTimer);
|
|
311
|
+
this.disconnectTimer = undefined;
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
/**
|
|
315
|
+
* Cleanup the visiblitychange listener upon Collab Provider destroy
|
|
316
|
+
* Value set when the listener is binded in addVisiblityListener
|
|
317
|
+
*/
|
|
318
|
+
_defineProperty(this, "unbindVisibilityListener", () => {});
|
|
319
|
+
_defineProperty(this, "autoDisconnect", (disconnectTimer, disconnectDelay) => {
|
|
320
|
+
if (document.hidden) {
|
|
321
|
+
logger('visibilitychange: hidden');
|
|
322
|
+
return setTimeout(() => {
|
|
323
|
+
var _this$socket4;
|
|
324
|
+
logger('visibilitychange: closing connection');
|
|
325
|
+
(_this$socket4 = this.socket) === null || _this$socket4 === void 0 ? void 0 : _this$socket4.close();
|
|
326
|
+
}, disconnectDelay || disconnectDelay === 0 ? disconnectDelay * 1000 : 60 * 1000);
|
|
327
|
+
} else {
|
|
328
|
+
var _this$socket5;
|
|
329
|
+
logger('visibilitychange: visible');
|
|
330
|
+
if (disconnectTimer) {
|
|
331
|
+
clearTimeout(disconnectTimer);
|
|
332
|
+
}
|
|
333
|
+
logger('visibilitychange: re-connecting');
|
|
334
|
+
(_this$socket5 = this.socket) === null || _this$socket5 === void 0 ? void 0 : _this$socket5.connect();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
302
338
|
this.config = config;
|
|
303
339
|
this.analyticsHelper = analyticsHelper;
|
|
304
340
|
this.initExperience = createDocInitExp(this.analyticsHelper);
|
|
@@ -480,6 +516,10 @@ export class Channel extends Emitter {
|
|
|
480
516
|
this.reconnectHelper = new ReconnectHelper();
|
|
481
517
|
// Fired upon a reconnection attempt error (from Socket.IO Manager)
|
|
482
518
|
this.socket.io.on('reconnect_error', this.onReconnectError);
|
|
519
|
+
|
|
520
|
+
// Automatic disconnect on tab background with delay, to keep presence UX accurate
|
|
521
|
+
// and reduce wasted connections. Reconnects upon tab becoming active again
|
|
522
|
+
this.addVisiblityListener();
|
|
483
523
|
}
|
|
484
524
|
|
|
485
525
|
// Ignored via go/ees005
|
|
@@ -546,9 +586,26 @@ export class Channel extends Emitter {
|
|
|
546
586
|
isLimitExceeded(stepLimit, stepSizeLimit, maxStepSizeLimit) {
|
|
547
587
|
return stepLimit > 0 && this.stepCounter > stepLimit || stepSizeLimit > 0 && this.stepSizeCounter > stepSizeLimit || maxStepSizeLimit > 0 && this.maxStepSize > maxStepSizeLimit;
|
|
548
588
|
}
|
|
589
|
+
/**
|
|
590
|
+
* Adds an event listener for visibilitychange events to handle auto-disconnection if tab is in background
|
|
591
|
+
*/
|
|
592
|
+
addVisiblityListener() {
|
|
593
|
+
var _FeatureGates$getExpe;
|
|
594
|
+
const disconnectDelay = (_FeatureGates$getExpe = FeatureGates.getExperimentValue('platform_editor_connection_auto_disconnect_delay', 'delay', -1)) !== null && _FeatureGates$getExpe !== void 0 ? _FeatureGates$getExpe : -1;
|
|
595
|
+
const isAutoDisconnectEnabled = disconnectDelay >= 0;
|
|
596
|
+
if (isAutoDisconnectEnabled && this.config.isPresenceOnly) {
|
|
597
|
+
this.unbindVisibilityListener = bind(document, {
|
|
598
|
+
type: 'visibilitychange',
|
|
599
|
+
listener: () => {
|
|
600
|
+
this.disconnectTimer = this.autoDisconnect(this.disconnectTimer, disconnectDelay);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}
|
|
549
605
|
disconnect() {
|
|
550
606
|
var _this$network;
|
|
551
607
|
this.unsubscribeAll();
|
|
608
|
+
this.cleanupAutoDisconnect();
|
|
552
609
|
(_this$network = this.network) === null || _this$network === void 0 ? void 0 : _this$network.destroy();
|
|
553
610
|
this.network = null;
|
|
554
611
|
if (this.socket) {
|
|
@@ -30,9 +30,22 @@ export const createParticipantFromPayload = async (payload, getUser) => {
|
|
|
30
30
|
};
|
|
31
31
|
return participant;
|
|
32
32
|
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Will use the getUsers callback from batchProps to fetch users
|
|
36
|
+
*
|
|
37
|
+
* 1. Determine all the participants that need to be hydrated
|
|
38
|
+
* 2. Only fetch a subset of those participants based on batchSize
|
|
39
|
+
* 3. Of the users fetched, find all of those users' sessions and mark those entries as hydrated
|
|
40
|
+
*
|
|
41
|
+
* @param participantsState
|
|
42
|
+
* @param batchProps
|
|
43
|
+
* @returns
|
|
44
|
+
* @example
|
|
45
|
+
*/
|
|
33
46
|
export const fetchParticipants = async (participantsState, batchProps) => {
|
|
34
47
|
const {
|
|
35
|
-
batchSize =
|
|
48
|
+
batchSize = DEFAULT_BATCH_FETCH_SIZE,
|
|
36
49
|
getUsers
|
|
37
50
|
} = batchProps;
|
|
38
51
|
const participantsToHydrate = participantsState.getUniqueParticipants({
|
|
@@ -54,24 +67,22 @@ export const fetchParticipants = async (participantsState, batchProps) => {
|
|
|
54
67
|
const {
|
|
55
68
|
sessionId
|
|
56
69
|
} = participant;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
hydratedParticipants.push(hydratedParticipant);
|
|
74
|
-
}
|
|
70
|
+
const hydratedParticipant = {
|
|
71
|
+
name: user.name,
|
|
72
|
+
avatar: user.avatar,
|
|
73
|
+
email: user.email,
|
|
74
|
+
userId: user.userId,
|
|
75
|
+
isGuest: user.isGuest,
|
|
76
|
+
sessionId,
|
|
77
|
+
lastActive: participant.lastActive,
|
|
78
|
+
clientId: participant.clientId,
|
|
79
|
+
permit: participant.permit,
|
|
80
|
+
presenceId: participant.presenceId,
|
|
81
|
+
presenceActivity: participant.presenceActivity,
|
|
82
|
+
isHydrated: true
|
|
83
|
+
};
|
|
84
|
+
participantsState.setBySessionId(sessionId, hydratedParticipant);
|
|
85
|
+
hydratedParticipants.push(hydratedParticipant);
|
|
75
86
|
});
|
|
76
87
|
});
|
|
77
88
|
return hydratedParticipants;
|