@atlaskit/collab-provider 22.0.2 → 22.1.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 +35 -0
- package/afm-cc/tsconfig.json +3 -0
- package/dist/cjs/provider/index.js +23 -5
- package/dist/cjs/provider/sleep-detector.js +58 -0
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/provider/index.js +23 -5
- package/dist/es2019/provider/sleep-detector.js +37 -0
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/provider/index.js +23 -5
- package/dist/esm/provider/sleep-detector.js +51 -0
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/provider/index.d.ts +2 -0
- package/dist/types/provider/sleep-detector.d.ts +10 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @atlaskit/collab-provider
|
|
2
2
|
|
|
3
|
+
## 22.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`83cf312c45f2f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/83cf312c45f2f) -
|
|
8
|
+
Detect process suspension on reconnect so catchup runs after a device wakes from sleep, where
|
|
9
|
+
`disconnectedAt` is only stamped once the process resumes. Behind
|
|
10
|
+
`collab_check_sleep_detection_experiment`, read through `@atlaskit/platform-feature-experiments`.
|
|
11
|
+
|
|
12
|
+
`@atlaskit/collab-provider` adds no public API. `SleepDetector` is internal: it is not reachable
|
|
13
|
+
from the `.`, `./provider`, `./socket-io-provider`, `./types` or `./version-wrapper` entry points
|
|
14
|
+
and does not appear in `report.api.md`. The provider constructs and drives it internally, so
|
|
15
|
+
consumers need no migration and no call sites change.
|
|
16
|
+
|
|
17
|
+
`@atlaskit/tmp-editor-statsig` drops `collab_bypass_out_of_sync_period_experiment` from
|
|
18
|
+
`editorExperimentsConfig`, which is part of its typed surface. The key had no call sites outside
|
|
19
|
+
`@atlaskit/collab-provider`, which no longer reads it, so no consumer migration is expected in
|
|
20
|
+
practice. Any remaining caller must move to the new experiment:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// before
|
|
24
|
+
if (expValEquals('collab_bypass_out_of_sync_period_experiment', 'isEnabled', true, false)) {
|
|
25
|
+
// catch up regardless of how long the client was offline
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// after
|
|
29
|
+
if (isExperimentEnabled('collab_check_sleep_detection_experiment')) {
|
|
30
|
+
// catch up when a suspension of at least OUT_OF_SYNC_PERIOD was detected
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies
|
|
37
|
+
|
|
3
38
|
## 22.0.2
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
package/afm-cc/tsconfig.json
CHANGED
|
@@ -17,6 +17,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
17
17
|
var _uuid = require("uuid");
|
|
18
18
|
var _emitter = require("../emitter");
|
|
19
19
|
var _channel = require("../channel");
|
|
20
|
+
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
20
21
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
21
22
|
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
22
23
|
var _utils = require("../helpers/utils");
|
|
@@ -36,6 +37,7 @@ var _api = require("../api/api");
|
|
|
36
37
|
var _performance = require("../analytics/performance");
|
|
37
38
|
var _nullApi = require("../api/null-api");
|
|
38
39
|
var _getOfflineStepsLength = require("./get-offline-steps-length");
|
|
40
|
+
var _sleepDetector = require("./sleep-detector");
|
|
39
41
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
40
42
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
41
43
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
@@ -66,6 +68,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
66
68
|
// It determines if the provider should initialize immediately and will only be true if:
|
|
67
69
|
// the feature flag is enabled and the initial draft fetched from NCS is also passed in the config.
|
|
68
70
|
(0, _defineProperty2.default)(_this, "isBufferingEnabled", false);
|
|
71
|
+
(0, _defineProperty2.default)(_this, "sleepDetector", new _sleepDetector.SleepDetector());
|
|
69
72
|
// Local IDs of active AI Providers
|
|
70
73
|
(0, _defineProperty2.default)(_this, "aiProviderActiveIds", []);
|
|
71
74
|
/**
|
|
@@ -151,12 +154,10 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
151
154
|
});
|
|
152
155
|
}
|
|
153
156
|
// If already initialized, `connected` means reconnected
|
|
154
|
-
var
|
|
155
|
-
if (
|
|
156
|
-
// Offline longer than `OUT_OF_SYNC_PERIOD`
|
|
157
|
-
shouldBypassOutOfSyncGracePeriod || Date.now() - _this.disconnectedAt >= OUT_OF_SYNC_PERIOD)) {
|
|
157
|
+
var offlineDuration = initialized ? _this.getOutOfSyncDuration() : undefined;
|
|
158
|
+
if (offlineDuration !== undefined) {
|
|
158
159
|
_this.documentService.throttledCatchupv2(_const.CatchupEventReason.RECONNECTED, {
|
|
159
|
-
disconnectionPeriodSeconds: Math.floor(
|
|
160
|
+
disconnectionPeriodSeconds: Math.floor(offlineDuration / 1000),
|
|
160
161
|
offlineStepsLength: (0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true) ? (0, _getOfflineStepsLength.getOfflineStepsLength)(_this.documentService.getUnconfirmedSteps(), _this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
161
162
|
offlineReplaceStepsLength: (0, _experiments.editorExperiment)('platform_editor_offline_editing_web', true) ? (0, _getOfflineStepsLength.getOfflineReplaceStepsLength)(_this.documentService.getUnconfirmedSteps(), _this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
162
163
|
unconfirmedStepsLength: unconfirmedStepsLength
|
|
@@ -179,6 +180,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
179
180
|
_this.participantsService.initializeFirstBatchFetchUsers();
|
|
180
181
|
}
|
|
181
182
|
_this.disconnectedAt = undefined;
|
|
183
|
+
_this.sleepDetector.reset();
|
|
182
184
|
}).on('init', function (_ref3) {
|
|
183
185
|
var doc = _ref3.doc,
|
|
184
186
|
version = _ref3.version,
|
|
@@ -266,6 +268,20 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
266
268
|
(0, _defineProperty2.default)(_this, "getAIProviderActiveIds", function () {
|
|
267
269
|
return _this.aiProviderActiveIds;
|
|
268
270
|
});
|
|
271
|
+
(0, _defineProperty2.default)(_this, "getOutOfSyncDuration", function () {
|
|
272
|
+
if (!_this.disconnectedAt) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
var disconnectedDuration = Date.now() - _this.disconnectedAt;
|
|
276
|
+
if (disconnectedDuration >= OUT_OF_SYNC_PERIOD) {
|
|
277
|
+
return disconnectedDuration;
|
|
278
|
+
}
|
|
279
|
+
var sleepDuration = _this.sleepDetector.getSleepDuration();
|
|
280
|
+
if (sleepDuration >= OUT_OF_SYNC_PERIOD && (0, _isExperimentEnabled.isExperimentEnabled)('collab_check_sleep_detection_experiment')) {
|
|
281
|
+
return sleepDuration;
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
});
|
|
269
285
|
// Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
|
|
270
286
|
(0, _defineProperty2.default)(_this, "onDisconnected", function (_ref5) {
|
|
271
287
|
var reason = _ref5.reason;
|
|
@@ -453,6 +469,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
453
469
|
logger('Intervally sendStepsFromCurrentState');
|
|
454
470
|
_this.documentService.sendStepsFromCurrentState(true, undefined);
|
|
455
471
|
}, 5000);
|
|
472
|
+
_this.sleepDetector.start();
|
|
456
473
|
return _this;
|
|
457
474
|
}
|
|
458
475
|
(0, _inherits2.default)(Provider, _Emitter);
|
|
@@ -713,6 +730,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
713
730
|
clearInterval(this.sendStepsTimer);
|
|
714
731
|
this.sendStepsTimer = undefined;
|
|
715
732
|
}
|
|
733
|
+
this.sleepDetector.stop();
|
|
716
734
|
} catch (error) {
|
|
717
735
|
var _this$analyticsHelper10;
|
|
718
736
|
(_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 || _this$analyticsHelper10.sendErrorEvent(error, 'Error while shutting down the collab provider');
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.SleepDetector = void 0;
|
|
8
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
11
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
12
|
+
var TICK_INTERVAL = 1000;
|
|
13
|
+
var GAP_HISTORY_SIZE = 20;
|
|
14
|
+
var SleepDetector = exports.SleepDetector = /*#__PURE__*/function () {
|
|
15
|
+
function SleepDetector() {
|
|
16
|
+
var _this = this;
|
|
17
|
+
(0, _classCallCheck2.default)(this, SleepDetector);
|
|
18
|
+
(0, _defineProperty2.default)(this, "lastTickAt", Date.now());
|
|
19
|
+
(0, _defineProperty2.default)(this, "gaps", []);
|
|
20
|
+
(0, _defineProperty2.default)(this, "tick", function () {
|
|
21
|
+
var now = Date.now();
|
|
22
|
+
_this.gaps.push(now - _this.lastTickAt);
|
|
23
|
+
if (_this.gaps.length > GAP_HISTORY_SIZE) {
|
|
24
|
+
_this.gaps.shift();
|
|
25
|
+
}
|
|
26
|
+
_this.lastTickAt = now;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return (0, _createClass2.default)(SleepDetector, [{
|
|
30
|
+
key: "start",
|
|
31
|
+
value: function start() {
|
|
32
|
+
if (this.sentinel) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.reset();
|
|
36
|
+
this.sentinel = setInterval(this.tick, TICK_INTERVAL);
|
|
37
|
+
}
|
|
38
|
+
}, {
|
|
39
|
+
key: "stop",
|
|
40
|
+
value: function stop() {
|
|
41
|
+
if (this.sentinel) {
|
|
42
|
+
clearInterval(this.sentinel);
|
|
43
|
+
this.sentinel = undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, {
|
|
47
|
+
key: "reset",
|
|
48
|
+
value: function reset() {
|
|
49
|
+
this.gaps = [];
|
|
50
|
+
this.lastTickAt = Date.now();
|
|
51
|
+
}
|
|
52
|
+
}, {
|
|
53
|
+
key: "getSleepDuration",
|
|
54
|
+
value: function getSleepDuration() {
|
|
55
|
+
return this.gaps.length ? Math.max.apply(Math, (0, _toConsumableArray2.default)(this.gaps)) : 0;
|
|
56
|
+
}
|
|
57
|
+
}]);
|
|
58
|
+
}();
|
|
@@ -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 = "22.0.
|
|
8
|
+
var version = exports.version = "22.0.2";
|
|
9
9
|
var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
|
|
10
10
|
return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
|
|
11
11
|
};
|
|
@@ -3,6 +3,7 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
4
|
import { Emitter } from '../emitter';
|
|
5
5
|
import { Channel } from '../channel';
|
|
6
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
6
7
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
7
8
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
8
9
|
import { createLogger, logObfuscatedSteps } from '../helpers/utils';
|
|
@@ -22,6 +23,7 @@ import { Api } from '../api/api';
|
|
|
22
23
|
import { shouldTelepointerBeSampled } from '../analytics/performance';
|
|
23
24
|
import { NullApi } from '../api/null-api';
|
|
24
25
|
import { getOfflineStepsLength, getOfflineReplaceStepsLength } from './get-offline-steps-length';
|
|
26
|
+
import { SleepDetector } from './sleep-detector';
|
|
25
27
|
const logger = createLogger('Provider', 'black');
|
|
26
28
|
const OUT_OF_SYNC_PERIOD = 3 * 1000; // 3 seconds
|
|
27
29
|
|
|
@@ -45,6 +47,7 @@ export class Provider extends Emitter {
|
|
|
45
47
|
// It determines if the provider should initialize immediately and will only be true if:
|
|
46
48
|
// the feature flag is enabled and the initial draft fetched from NCS is also passed in the config.
|
|
47
49
|
_defineProperty(this, "isBufferingEnabled", false);
|
|
50
|
+
_defineProperty(this, "sleepDetector", new SleepDetector());
|
|
48
51
|
// Local IDs of active AI Providers
|
|
49
52
|
_defineProperty(this, "aiProviderActiveIds", []);
|
|
50
53
|
/**
|
|
@@ -131,12 +134,10 @@ export class Provider extends Emitter {
|
|
|
131
134
|
});
|
|
132
135
|
}
|
|
133
136
|
// If already initialized, `connected` means reconnected
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
// Offline longer than `OUT_OF_SYNC_PERIOD`
|
|
137
|
-
shouldBypassOutOfSyncGracePeriod || Date.now() - this.disconnectedAt >= OUT_OF_SYNC_PERIOD)) {
|
|
137
|
+
const offlineDuration = initialized ? this.getOutOfSyncDuration() : undefined;
|
|
138
|
+
if (offlineDuration !== undefined) {
|
|
138
139
|
this.documentService.throttledCatchupv2(CatchupEventReason.RECONNECTED, {
|
|
139
|
-
disconnectionPeriodSeconds: Math.floor(
|
|
140
|
+
disconnectionPeriodSeconds: Math.floor(offlineDuration / 1000),
|
|
140
141
|
offlineStepsLength: editorExperiment('platform_editor_offline_editing_web', true) ? getOfflineStepsLength(this.documentService.getUnconfirmedSteps(), this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
141
142
|
offlineReplaceStepsLength: editorExperiment('platform_editor_offline_editing_web', true) ? getOfflineReplaceStepsLength(this.documentService.getUnconfirmedSteps(), this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
142
143
|
unconfirmedStepsLength: unconfirmedStepsLength
|
|
@@ -159,6 +160,7 @@ export class Provider extends Emitter {
|
|
|
159
160
|
this.participantsService.initializeFirstBatchFetchUsers();
|
|
160
161
|
}
|
|
161
162
|
this.disconnectedAt = undefined;
|
|
163
|
+
this.sleepDetector.reset();
|
|
162
164
|
}).on('init', ({
|
|
163
165
|
doc,
|
|
164
166
|
version,
|
|
@@ -229,6 +231,20 @@ export class Provider extends Emitter {
|
|
|
229
231
|
_defineProperty(this, "getAIProviderActiveIds", () => {
|
|
230
232
|
return this.aiProviderActiveIds;
|
|
231
233
|
});
|
|
234
|
+
_defineProperty(this, "getOutOfSyncDuration", () => {
|
|
235
|
+
if (!this.disconnectedAt) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
const disconnectedDuration = Date.now() - this.disconnectedAt;
|
|
239
|
+
if (disconnectedDuration >= OUT_OF_SYNC_PERIOD) {
|
|
240
|
+
return disconnectedDuration;
|
|
241
|
+
}
|
|
242
|
+
const sleepDuration = this.sleepDetector.getSleepDuration();
|
|
243
|
+
if (sleepDuration >= OUT_OF_SYNC_PERIOD && isExperimentEnabled('collab_check_sleep_detection_experiment')) {
|
|
244
|
+
return sleepDuration;
|
|
245
|
+
}
|
|
246
|
+
return undefined;
|
|
247
|
+
});
|
|
232
248
|
// Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
|
|
233
249
|
_defineProperty(this, "onDisconnected", ({
|
|
234
250
|
reason
|
|
@@ -368,6 +384,7 @@ export class Provider extends Emitter {
|
|
|
368
384
|
logger('Intervally sendStepsFromCurrentState');
|
|
369
385
|
this.documentService.sendStepsFromCurrentState(true, undefined);
|
|
370
386
|
}, 5000);
|
|
387
|
+
this.sleepDetector.start();
|
|
371
388
|
}
|
|
372
389
|
// eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
|
|
373
390
|
/**
|
|
@@ -609,6 +626,7 @@ export class Provider extends Emitter {
|
|
|
609
626
|
clearInterval(this.sendStepsTimer);
|
|
610
627
|
this.sendStepsTimer = undefined;
|
|
611
628
|
}
|
|
629
|
+
this.sleepDetector.stop();
|
|
612
630
|
} catch (error) {
|
|
613
631
|
var _this$analyticsHelper12;
|
|
614
632
|
(_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while shutting down the collab provider');
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
const TICK_INTERVAL = 1000;
|
|
3
|
+
const GAP_HISTORY_SIZE = 20;
|
|
4
|
+
export class SleepDetector {
|
|
5
|
+
constructor() {
|
|
6
|
+
_defineProperty(this, "lastTickAt", Date.now());
|
|
7
|
+
_defineProperty(this, "gaps", []);
|
|
8
|
+
_defineProperty(this, "tick", () => {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
this.gaps.push(now - this.lastTickAt);
|
|
11
|
+
if (this.gaps.length > GAP_HISTORY_SIZE) {
|
|
12
|
+
this.gaps.shift();
|
|
13
|
+
}
|
|
14
|
+
this.lastTickAt = now;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
start() {
|
|
18
|
+
if (this.sentinel) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.reset();
|
|
22
|
+
this.sentinel = setInterval(this.tick, TICK_INTERVAL);
|
|
23
|
+
}
|
|
24
|
+
stop() {
|
|
25
|
+
if (this.sentinel) {
|
|
26
|
+
clearInterval(this.sentinel);
|
|
27
|
+
this.sentinel = undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
reset() {
|
|
31
|
+
this.gaps = [];
|
|
32
|
+
this.lastTickAt = Date.now();
|
|
33
|
+
}
|
|
34
|
+
getSleepDuration() {
|
|
35
|
+
return this.gaps.length ? Math.max(...this.gaps) : 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -16,6 +16,7 @@ function _superPropGet(t, o, e, r) { var p = _get(_getPrototypeOf(1 & r ? t.prot
|
|
|
16
16
|
import { v4 as uuidv4 } from 'uuid';
|
|
17
17
|
import { Emitter } from '../emitter';
|
|
18
18
|
import { Channel } from '../channel';
|
|
19
|
+
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
19
20
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
20
21
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
21
22
|
import { createLogger, logObfuscatedSteps } from '../helpers/utils';
|
|
@@ -35,6 +36,7 @@ import { Api } from '../api/api';
|
|
|
35
36
|
import { shouldTelepointerBeSampled } from '../analytics/performance';
|
|
36
37
|
import { NullApi } from '../api/null-api';
|
|
37
38
|
import { getOfflineStepsLength, getOfflineReplaceStepsLength } from './get-offline-steps-length';
|
|
39
|
+
import { SleepDetector } from './sleep-detector';
|
|
38
40
|
var logger = createLogger('Provider', 'black');
|
|
39
41
|
var OUT_OF_SYNC_PERIOD = 3 * 1000; // 3 seconds
|
|
40
42
|
|
|
@@ -60,6 +62,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
60
62
|
// It determines if the provider should initialize immediately and will only be true if:
|
|
61
63
|
// the feature flag is enabled and the initial draft fetched from NCS is also passed in the config.
|
|
62
64
|
_defineProperty(_this, "isBufferingEnabled", false);
|
|
65
|
+
_defineProperty(_this, "sleepDetector", new SleepDetector());
|
|
63
66
|
// Local IDs of active AI Providers
|
|
64
67
|
_defineProperty(_this, "aiProviderActiveIds", []);
|
|
65
68
|
/**
|
|
@@ -145,12 +148,10 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
145
148
|
});
|
|
146
149
|
}
|
|
147
150
|
// If already initialized, `connected` means reconnected
|
|
148
|
-
var
|
|
149
|
-
if (
|
|
150
|
-
// Offline longer than `OUT_OF_SYNC_PERIOD`
|
|
151
|
-
shouldBypassOutOfSyncGracePeriod || Date.now() - _this.disconnectedAt >= OUT_OF_SYNC_PERIOD)) {
|
|
151
|
+
var offlineDuration = initialized ? _this.getOutOfSyncDuration() : undefined;
|
|
152
|
+
if (offlineDuration !== undefined) {
|
|
152
153
|
_this.documentService.throttledCatchupv2(CatchupEventReason.RECONNECTED, {
|
|
153
|
-
disconnectionPeriodSeconds: Math.floor(
|
|
154
|
+
disconnectionPeriodSeconds: Math.floor(offlineDuration / 1000),
|
|
154
155
|
offlineStepsLength: editorExperiment('platform_editor_offline_editing_web', true) ? getOfflineStepsLength(_this.documentService.getUnconfirmedSteps(), _this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
155
156
|
offlineReplaceStepsLength: editorExperiment('platform_editor_offline_editing_web', true) ? getOfflineReplaceStepsLength(_this.documentService.getUnconfirmedSteps(), _this.documentService.getUnconfirmedStepsOrigins()) : undefined,
|
|
156
157
|
unconfirmedStepsLength: unconfirmedStepsLength
|
|
@@ -173,6 +174,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
173
174
|
_this.participantsService.initializeFirstBatchFetchUsers();
|
|
174
175
|
}
|
|
175
176
|
_this.disconnectedAt = undefined;
|
|
177
|
+
_this.sleepDetector.reset();
|
|
176
178
|
}).on('init', function (_ref3) {
|
|
177
179
|
var doc = _ref3.doc,
|
|
178
180
|
version = _ref3.version,
|
|
@@ -260,6 +262,20 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
260
262
|
_defineProperty(_this, "getAIProviderActiveIds", function () {
|
|
261
263
|
return _this.aiProviderActiveIds;
|
|
262
264
|
});
|
|
265
|
+
_defineProperty(_this, "getOutOfSyncDuration", function () {
|
|
266
|
+
if (!_this.disconnectedAt) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
var disconnectedDuration = Date.now() - _this.disconnectedAt;
|
|
270
|
+
if (disconnectedDuration >= OUT_OF_SYNC_PERIOD) {
|
|
271
|
+
return disconnectedDuration;
|
|
272
|
+
}
|
|
273
|
+
var sleepDuration = _this.sleepDetector.getSleepDuration();
|
|
274
|
+
if (sleepDuration >= OUT_OF_SYNC_PERIOD && isExperimentEnabled('collab_check_sleep_detection_experiment')) {
|
|
275
|
+
return sleepDuration;
|
|
276
|
+
}
|
|
277
|
+
return undefined;
|
|
278
|
+
});
|
|
263
279
|
// Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
|
|
264
280
|
_defineProperty(_this, "onDisconnected", function (_ref5) {
|
|
265
281
|
var reason = _ref5.reason;
|
|
@@ -447,6 +463,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
447
463
|
logger('Intervally sendStepsFromCurrentState');
|
|
448
464
|
_this.documentService.sendStepsFromCurrentState(true, undefined);
|
|
449
465
|
}, 5000);
|
|
466
|
+
_this.sleepDetector.start();
|
|
450
467
|
return _this;
|
|
451
468
|
}
|
|
452
469
|
_inherits(Provider, _Emitter);
|
|
@@ -707,6 +724,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
707
724
|
clearInterval(this.sendStepsTimer);
|
|
708
725
|
this.sendStepsTimer = undefined;
|
|
709
726
|
}
|
|
727
|
+
this.sleepDetector.stop();
|
|
710
728
|
} catch (error) {
|
|
711
729
|
var _this$analyticsHelper10;
|
|
712
730
|
(_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 || _this$analyticsHelper10.sendErrorEvent(error, 'Error while shutting down the collab provider');
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
4
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
5
|
+
var TICK_INTERVAL = 1000;
|
|
6
|
+
var GAP_HISTORY_SIZE = 20;
|
|
7
|
+
export var SleepDetector = /*#__PURE__*/function () {
|
|
8
|
+
function SleepDetector() {
|
|
9
|
+
var _this = this;
|
|
10
|
+
_classCallCheck(this, SleepDetector);
|
|
11
|
+
_defineProperty(this, "lastTickAt", Date.now());
|
|
12
|
+
_defineProperty(this, "gaps", []);
|
|
13
|
+
_defineProperty(this, "tick", function () {
|
|
14
|
+
var now = Date.now();
|
|
15
|
+
_this.gaps.push(now - _this.lastTickAt);
|
|
16
|
+
if (_this.gaps.length > GAP_HISTORY_SIZE) {
|
|
17
|
+
_this.gaps.shift();
|
|
18
|
+
}
|
|
19
|
+
_this.lastTickAt = now;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return _createClass(SleepDetector, [{
|
|
23
|
+
key: "start",
|
|
24
|
+
value: function start() {
|
|
25
|
+
if (this.sentinel) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.reset();
|
|
29
|
+
this.sentinel = setInterval(this.tick, TICK_INTERVAL);
|
|
30
|
+
}
|
|
31
|
+
}, {
|
|
32
|
+
key: "stop",
|
|
33
|
+
value: function stop() {
|
|
34
|
+
if (this.sentinel) {
|
|
35
|
+
clearInterval(this.sentinel);
|
|
36
|
+
this.sentinel = undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
key: "reset",
|
|
41
|
+
value: function reset() {
|
|
42
|
+
this.gaps = [];
|
|
43
|
+
this.lastTickAt = Date.now();
|
|
44
|
+
}
|
|
45
|
+
}, {
|
|
46
|
+
key: "getSleepDuration",
|
|
47
|
+
value: function getSleepDuration() {
|
|
48
|
+
return this.gaps.length ? Math.max.apply(Math, _toConsumableArray(this.gaps)) : 0;
|
|
49
|
+
}
|
|
50
|
+
}]);
|
|
51
|
+
}();
|
|
@@ -35,6 +35,7 @@ export declare class Provider extends Emitter<CollabEvents> implements CollabEdi
|
|
|
35
35
|
private presenceUpdateTimeout?;
|
|
36
36
|
private disconnectedAt?;
|
|
37
37
|
private sendStepsTimer?;
|
|
38
|
+
private readonly sleepDetector;
|
|
38
39
|
private readonly participantsService;
|
|
39
40
|
private readonly metadataService;
|
|
40
41
|
private readonly documentService;
|
|
@@ -108,6 +109,7 @@ export declare class Provider extends Emitter<CollabEvents> implements CollabEdi
|
|
|
108
109
|
sendMessage(data: CollabTelepointerPayload | CollabActivityAIProviderChangedPayload | CollabPresenceActivityChangePayload): void;
|
|
109
110
|
setAIProviderActiveIds(ids?: string[]): void;
|
|
110
111
|
private getAIProviderActiveIds;
|
|
112
|
+
private getOutOfSyncDuration;
|
|
111
113
|
private onDisconnected;
|
|
112
114
|
/**
|
|
113
115
|
* "Destroy" the provider, disconnect it's connection to the back-end service and unsubscribe all event listeners on the provider.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/collab-provider",
|
|
3
|
-
"version": "22.0
|
|
3
|
+
"version": "22.1.0",
|
|
4
4
|
"description": "A provider for collaborative editing.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -26,10 +26,11 @@
|
|
|
26
26
|
"@atlaskit/editor-json-transformer": "^9.2.0",
|
|
27
27
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
28
28
|
"@atlaskit/feature-gate-js-client": "^6.0.0",
|
|
29
|
+
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
29
30
|
"@atlaskit/platform-feature-flags": "^2.1.0",
|
|
30
31
|
"@atlaskit/prosemirror-collab": "^1.0.0",
|
|
31
32
|
"@atlaskit/react-ufo": "^7.3.0",
|
|
32
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
33
|
+
"@atlaskit/tmp-editor-statsig": "^140.0.0",
|
|
33
34
|
"@atlaskit/ufo": "^1.0.0",
|
|
34
35
|
"@atlaskit/util-service-support": "^7.2.0",
|
|
35
36
|
"@babel/runtime": "^7.0.0",
|
|
@@ -57,6 +58,7 @@
|
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@atlaskit/adf-schema": "^56.5.0",
|
|
59
60
|
"@atlassian/a11y-jest-testing": "^0.14.0",
|
|
61
|
+
"@atlassian/experiment-test-utils": "^0.2.0",
|
|
60
62
|
"@atlassian/feature-flags-test-utils": "^1.2.0"
|
|
61
63
|
},
|
|
62
64
|
"platform-feature-flags": {
|
|
@@ -71,6 +73,6 @@
|
|
|
71
73
|
}
|
|
72
74
|
},
|
|
73
75
|
"peerDependencies": {
|
|
74
|
-
"@atlaskit/editor-common": "^117.
|
|
76
|
+
"@atlaskit/editor-common": "^117.2.0"
|
|
75
77
|
}
|
|
76
78
|
}
|