@atlaskit/collab-provider 8.2.0 → 8.3.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 +33 -0
- package/dist/cjs/analytics/index.js +66 -9
- package/dist/cjs/analytics/performance.js +45 -35
- package/dist/cjs/analytics/ufo.js +33 -0
- package/dist/cjs/channel.js +89 -54
- package/dist/cjs/connectivity/network.js +53 -0
- package/dist/cjs/connectivity/reconnect-helper.js +48 -0
- package/dist/cjs/connectivity/singleton.js +15 -0
- package/dist/cjs/disconnected-reason-mapper.js +19 -2
- package/dist/cjs/error-code-mapper.js +16 -1
- package/dist/cjs/helpers/const.js +5 -10
- package/dist/cjs/provider/catchup.js +8 -12
- package/dist/cjs/provider/commit-step.js +66 -0
- package/dist/cjs/provider/index.js +480 -558
- package/dist/cjs/provider/telepointers.js +78 -0
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/analytics/index.js +57 -8
- package/dist/es2019/analytics/performance.js +46 -35
- package/dist/es2019/analytics/ufo.js +22 -0
- package/dist/es2019/channel.js +89 -58
- package/dist/es2019/connectivity/network.js +34 -0
- package/dist/es2019/connectivity/reconnect-helper.js +29 -0
- package/dist/es2019/connectivity/singleton.js +7 -0
- package/dist/es2019/disconnected-reason-mapper.js +17 -1
- package/dist/es2019/error-code-mapper.js +16 -1
- package/dist/es2019/helpers/const.js +4 -7
- package/dist/es2019/provider/catchup.js +5 -12
- package/dist/es2019/provider/commit-step.js +53 -0
- package/dist/es2019/provider/index.js +397 -496
- package/dist/es2019/provider/telepointers.js +65 -0
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/es2019/version.json +1 -1
- package/dist/esm/analytics/index.js +67 -9
- package/dist/esm/analytics/performance.js +46 -35
- package/dist/esm/analytics/ufo.js +25 -0
- package/dist/esm/channel.js +89 -56
- package/dist/esm/connectivity/network.js +45 -0
- package/dist/esm/connectivity/reconnect-helper.js +42 -0
- package/dist/esm/connectivity/singleton.js +7 -0
- package/dist/esm/disconnected-reason-mapper.js +17 -1
- package/dist/esm/error-code-mapper.js +16 -1
- package/dist/esm/helpers/const.js +4 -7
- package/dist/esm/provider/catchup.js +8 -12
- package/dist/esm/provider/commit-step.js +58 -0
- package/dist/esm/provider/index.js +482 -559
- package/dist/esm/provider/telepointers.js +69 -0
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/esm/version.json +1 -1
- package/dist/types/analytics/index.d.ts +8 -2
- package/dist/types/analytics/performance.d.ts +5 -5
- package/dist/types/analytics/ufo.d.ts +3 -0
- package/dist/types/channel.d.ts +11 -5
- package/dist/types/connectivity/network.d.ts +17 -0
- package/dist/types/connectivity/reconnect-helper.d.ts +8 -0
- package/dist/types/connectivity/singleton.d.ts +3 -0
- package/dist/types/disconnected-reason-mapper.d.ts +1 -0
- package/dist/types/error-code-mapper.d.ts +5 -1
- package/dist/types/helpers/const.d.ts +109 -25
- package/dist/types/provider/commit-step.d.ts +14 -0
- package/dist/types/provider/index.d.ts +9 -5
- package/dist/types/provider/telepointers.d.ts +5 -0
- package/dist/types/socket-io-provider.d.ts +2 -1
- package/dist/types/types.d.ts +27 -10
- package/package.json +4 -5
- package/report.api.md +29 -0
- package/.vscode/settings.json +0 -3
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createLogger } from '../helpers/utils';
|
|
2
|
+
import { ExperiencePerformanceTypes, ExperienceTypes, UFOExperience } from '@atlaskit/ufo';
|
|
3
|
+
import { AcknowledgementResponseTypes } from '../types';
|
|
4
|
+
const logger = createLogger('Telepointer', 'green');
|
|
5
|
+
export const telepointersFromStep = (participants, step) => {
|
|
6
|
+
const [participant] = Array.from(participants.values()).filter(p => p.clientId === step.clientId);
|
|
7
|
+
if (participant) {
|
|
8
|
+
var _node$text;
|
|
9
|
+
const {
|
|
10
|
+
stepType,
|
|
11
|
+
to,
|
|
12
|
+
from,
|
|
13
|
+
slice = {
|
|
14
|
+
content: []
|
|
15
|
+
}
|
|
16
|
+
} = step;
|
|
17
|
+
const [node] = slice.content;
|
|
18
|
+
if (to && from && stepType === 'replace' && to === from && slice.content.length === 1 && (node === null || node === void 0 ? void 0 : node.type) === 'text' && (node === null || node === void 0 ? void 0 : (_node$text = node.text) === null || _node$text === void 0 ? void 0 : _node$text.length) === 1) {
|
|
19
|
+
return {
|
|
20
|
+
sessionId: participant.sessionId,
|
|
21
|
+
selection: {
|
|
22
|
+
type: 'textSelection',
|
|
23
|
+
anchor: from + 1,
|
|
24
|
+
head: to + 1
|
|
25
|
+
},
|
|
26
|
+
type: 'telepointer'
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
export const telepointerCallback = documentAri => {
|
|
32
|
+
const telepointerExperience = new UFOExperience('collab-provider.telepointer', {
|
|
33
|
+
type: ExperienceTypes.Operation,
|
|
34
|
+
performanceType: ExperiencePerformanceTypes.Custom,
|
|
35
|
+
performanceConfig: {
|
|
36
|
+
histogram: {
|
|
37
|
+
[ExperiencePerformanceTypes.Custom]: {
|
|
38
|
+
duration: '250_500_1000_1500_2000_3000_4000'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
telepointerExperience.addMetadata({
|
|
44
|
+
documentAri
|
|
45
|
+
});
|
|
46
|
+
telepointerExperience.start();
|
|
47
|
+
return response => {
|
|
48
|
+
if (response.type === AcknowledgementResponseTypes.SUCCESS) {
|
|
49
|
+
telepointerExperience.success();
|
|
50
|
+
} else if (response.type === AcknowledgementResponseTypes.ERROR) {
|
|
51
|
+
const errorMessage = response.error;
|
|
52
|
+
telepointerExperience.addMetadata({
|
|
53
|
+
error: errorMessage
|
|
54
|
+
});
|
|
55
|
+
logger('Error from collab service with telepointer broadcast', errorMessage);
|
|
56
|
+
telepointerExperience.failure();
|
|
57
|
+
} else {
|
|
58
|
+
logger('Invalid ACK from collab service with telepointer broadcast');
|
|
59
|
+
telepointerExperience.addMetadata({
|
|
60
|
+
error: 'Invalid ACK from collab service with telepointer broadcast'
|
|
61
|
+
});
|
|
62
|
+
telepointerExperience.failure();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
};
|
package/dist/es2019/version.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
1
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
4
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
3
5
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
-
import {
|
|
6
|
+
import { EVENT_ACTION } from '../helpers/const';
|
|
5
7
|
import { name as packageName, version as packageVersion } from '../version-wrapper';
|
|
6
|
-
|
|
8
|
+
import { network } from '../connectivity/singleton';
|
|
9
|
+
var EVENT_SUBJECT = 'collab';
|
|
10
|
+
var COLLAB_SERVICE;
|
|
11
|
+
(function (COLLAB_SERVICE) {
|
|
12
|
+
COLLAB_SERVICE["NCS"] = "ncs";
|
|
13
|
+
COLLAB_SERVICE["SYNCHRONY"] = "synchrony";
|
|
14
|
+
})(COLLAB_SERVICE || (COLLAB_SERVICE = {}));
|
|
15
|
+
var triggerAnalyticsEvent = function triggerAnalyticsEvent(analyticsEvent, analyticsClient) {
|
|
7
16
|
if (!analyticsClient) {
|
|
8
17
|
return;
|
|
9
18
|
}
|
|
@@ -12,18 +21,67 @@ export var triggerAnalyticsEvent = function triggerAnalyticsEvent(analyticsEvent
|
|
|
12
21
|
attributes: _objectSpread({
|
|
13
22
|
packageName: packageName,
|
|
14
23
|
packageVersion: packageVersion,
|
|
15
|
-
collabService: COLLAB_SERVICE.NCS
|
|
24
|
+
collabService: COLLAB_SERVICE.NCS,
|
|
25
|
+
network: {
|
|
26
|
+
status: network.getStatus()
|
|
27
|
+
}
|
|
16
28
|
}, analyticsEvent.attributes),
|
|
17
29
|
tags: ['editor'],
|
|
18
30
|
action: analyticsEvent.eventAction,
|
|
19
31
|
source: 'unknown' // Adds zero analytics value, but event validation throws an error if you don't add it :-(
|
|
20
32
|
};
|
|
21
33
|
|
|
34
|
+
if (analyticsEvent.eventAction === EVENT_ACTION.ERROR) {
|
|
35
|
+
payload.nonPrivacySafeAttributes = analyticsEvent.nonPrivacySafeAttributes;
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
// Let the browser figure out
|
|
23
39
|
// when it should send those events
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
};
|
|
40
|
+
try {
|
|
41
|
+
var requestIdleCallbackFunction = window.requestIdleCallback;
|
|
42
|
+
var runItLater = typeof requestIdleCallbackFunction === 'function' ? requestIdleCallbackFunction : window.requestAnimationFrame;
|
|
43
|
+
runItLater(function () {
|
|
44
|
+
analyticsClient.sendOperationalEvent(payload);
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
// silently fail for now https://product-fabric.atlassian.net/browse/ESS-3112
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var AnalyticsHelper = /*#__PURE__*/function () {
|
|
51
|
+
function AnalyticsHelper(documentAri, analyticsClient) {
|
|
52
|
+
_classCallCheck(this, AnalyticsHelper);
|
|
53
|
+
this.analyticsClient = analyticsClient;
|
|
54
|
+
this.documentAri = documentAri;
|
|
55
|
+
}
|
|
56
|
+
_createClass(AnalyticsHelper, [{
|
|
57
|
+
key: "sendErrorEvent",
|
|
58
|
+
value: function sendErrorEvent(error, errorMessage) {
|
|
59
|
+
var errorAnalyticsEvent = {
|
|
60
|
+
eventAction: EVENT_ACTION.ERROR,
|
|
61
|
+
attributes: {
|
|
62
|
+
documentAri: this.documentAri,
|
|
63
|
+
errorMessage: errorMessage
|
|
64
|
+
},
|
|
65
|
+
nonPrivacySafeAttributes: {
|
|
66
|
+
error: error
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
triggerAnalyticsEvent(errorAnalyticsEvent, this.analyticsClient);
|
|
70
|
+
}
|
|
71
|
+
}, {
|
|
72
|
+
key: "sendActionEvent",
|
|
73
|
+
value: function sendActionEvent(action, status, attributes // This breaks discriminated unions, because there is no obvious field to discriminate against any more
|
|
74
|
+
) {
|
|
75
|
+
var analyticsEvent = {
|
|
76
|
+
eventAction: action,
|
|
77
|
+
attributes: _objectSpread({
|
|
78
|
+
documentAri: this.documentAri,
|
|
79
|
+
eventStatus: status
|
|
80
|
+
}, attributes)
|
|
81
|
+
};
|
|
82
|
+
triggerAnalyticsEvent(analyticsEvent, this.analyticsClient);
|
|
83
|
+
}
|
|
84
|
+
}]);
|
|
85
|
+
return AnalyticsHelper;
|
|
86
|
+
}();
|
|
87
|
+
export { AnalyticsHelper as default };
|
|
@@ -2,8 +2,8 @@ export var MEASURE_NAME;
|
|
|
2
2
|
(function (MEASURE_NAME) {
|
|
3
3
|
MEASURE_NAME["SOCKET_CONNECT"] = "socketConnect";
|
|
4
4
|
MEASURE_NAME["DOCUMENT_INIT"] = "documentInit";
|
|
5
|
-
MEASURE_NAME["CONVERT_PM_TO_ADF"] = "convertPMToADF";
|
|
6
5
|
MEASURE_NAME["COMMIT_UNCONFIRMED_STEPS"] = "commitUnconfirmedSteps";
|
|
6
|
+
MEASURE_NAME["PUBLISH_PAGE"] = "publishPage";
|
|
7
7
|
})(MEASURE_NAME || (MEASURE_NAME = {}));
|
|
8
8
|
var isPerformanceAPIAvailable = function isPerformanceAPIAvailable() {
|
|
9
9
|
return typeof window !== 'undefined' && 'performance' in window && ['measure', 'clearMeasures', 'clearMarks', 'getEntriesByName', 'getEntriesByType'].every(function (api) {
|
|
@@ -12,47 +12,58 @@ var isPerformanceAPIAvailable = function isPerformanceAPIAvailable() {
|
|
|
12
12
|
};
|
|
13
13
|
var hasPerformanceAPIAvailable = isPerformanceAPIAvailable();
|
|
14
14
|
var measureMap = new Map();
|
|
15
|
-
export function startMeasure(measureName) {
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
export function startMeasure(measureName, analyticsHelper) {
|
|
16
|
+
try {
|
|
17
|
+
if (!hasPerformanceAPIAvailable) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
performance.mark("".concat(measureName, "::start"));
|
|
21
|
+
measureMap.set(measureName, performance.now());
|
|
22
|
+
} catch (error) {
|
|
23
|
+
analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while measuring performance when marking the start');
|
|
18
24
|
}
|
|
19
|
-
performance.mark("".concat(measureName, "::start"));
|
|
20
|
-
measureMap.set(measureName, performance.now());
|
|
21
25
|
}
|
|
22
|
-
export function stopMeasure(measureName, onMeasureComplete) {
|
|
23
|
-
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// `startMeasure` is not called with `measureName` before.
|
|
28
|
-
if (!measureMap.get(measureName)) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
performance.mark("".concat(measureName, "::end"));
|
|
32
|
-
var start = onMeasureComplete ? measureMap.get(measureName) : undefined;
|
|
26
|
+
export function stopMeasure(measureName, analyticsHelper, onMeasureComplete) {
|
|
27
|
+
var start;
|
|
33
28
|
try {
|
|
29
|
+
if (!hasPerformanceAPIAvailable) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// `startMeasure` is not called with `measureName` before.
|
|
34
|
+
if (!measureMap.get(measureName)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
performance.mark("".concat(measureName, "::end"));
|
|
38
|
+
start = onMeasureComplete ? measureMap.get(measureName) : undefined;
|
|
34
39
|
performance.measure(measureName, "".concat(measureName, "::start"), "".concat(measureName, "::end"));
|
|
35
|
-
} catch (
|
|
36
|
-
|
|
37
|
-
clearMeasure(measureName);
|
|
38
|
-
var measure;
|
|
39
|
-
if (entry) {
|
|
40
|
-
measure = {
|
|
41
|
-
duration: entry.duration,
|
|
42
|
-
startTime: entry.startTime
|
|
43
|
-
};
|
|
44
|
-
} else if (start) {
|
|
45
|
-
measure = {
|
|
46
|
-
duration: performance.now() - start,
|
|
47
|
-
startTime: start
|
|
48
|
-
};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while measuring performance when marking the end');
|
|
49
42
|
}
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
try {
|
|
44
|
+
var entry = performance.getEntriesByName(measureName).pop();
|
|
45
|
+
clearMeasure(measureName);
|
|
46
|
+
var measure;
|
|
47
|
+
if (entry) {
|
|
48
|
+
measure = {
|
|
49
|
+
duration: entry.duration,
|
|
50
|
+
startTime: entry.startTime
|
|
51
|
+
};
|
|
52
|
+
} else if (start) {
|
|
53
|
+
measure = {
|
|
54
|
+
duration: performance.now() - start,
|
|
55
|
+
startTime: start
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (measure && onMeasureComplete) {
|
|
59
|
+
onMeasureComplete(measure.duration, measure.startTime);
|
|
60
|
+
}
|
|
61
|
+
return measure;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while measuring performance when completing the measurement');
|
|
52
64
|
}
|
|
53
|
-
return measure;
|
|
54
65
|
}
|
|
55
|
-
|
|
66
|
+
function clearMeasure(measureName) {
|
|
56
67
|
if (!hasPerformanceAPIAvailable) {
|
|
57
68
|
return;
|
|
58
69
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import { ExperiencePerformanceTypes, ExperienceTypes, UFOExperience } from '@atlaskit/ufo';
|
|
3
|
+
var createDocumentInitExperience = function createDocumentInitExperience() {
|
|
4
|
+
return new UFOExperience('collab-provider.document-init', {
|
|
5
|
+
type: ExperienceTypes.Load,
|
|
6
|
+
performanceType: ExperiencePerformanceTypes.Custom,
|
|
7
|
+
performanceConfig: {
|
|
8
|
+
histogram: _defineProperty({}, ExperiencePerformanceTypes.Custom, {
|
|
9
|
+
duration: '250_500_1000_1500_2000_3000_4000'
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
var withErrorHandling = function withErrorHandling(createExperience, analyticsHelper) {
|
|
15
|
+
var initExperience;
|
|
16
|
+
try {
|
|
17
|
+
initExperience = createExperience();
|
|
18
|
+
} catch (error) {
|
|
19
|
+
analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while initialising a UFO experience');
|
|
20
|
+
}
|
|
21
|
+
return initExperience;
|
|
22
|
+
};
|
|
23
|
+
export var createDocInitExp = function createDocInitExp(analyticsHelper) {
|
|
24
|
+
return withErrorHandling(createDocumentInitExperience, analyticsHelper);
|
|
25
|
+
};
|
package/dist/esm/channel.js
CHANGED
|
@@ -12,35 +12,27 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
|
|
|
12
12
|
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
13
13
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
14
14
|
import { utils } from '@atlaskit/util-service-support';
|
|
15
|
-
// TODO: Validate if this is actually equivalent to the AnalyticsWebClient in @atlassiansox/analytics-web-client
|
|
16
|
-
|
|
17
15
|
import { Emitter } from './emitter';
|
|
18
16
|
import { ErrorCodeMapper } from './error-code-mapper';
|
|
19
17
|
import { createLogger, getProduct, getSubProduct } from './helpers/utils';
|
|
20
18
|
import { MEASURE_NAME, startMeasure, stopMeasure } from './analytics/performance';
|
|
21
|
-
import { triggerAnalyticsEvent } from './analytics';
|
|
22
19
|
import { EVENT_ACTION, EVENT_STATUS } from './helpers/const';
|
|
23
|
-
import
|
|
20
|
+
import ReconnectHelper from './connectivity/reconnect-helper';
|
|
21
|
+
import { createDocInitExp } from './analytics/ufo';
|
|
22
|
+
import Network from './connectivity/network';
|
|
24
23
|
var logger = createLogger('Channel', 'green');
|
|
25
24
|
export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
26
25
|
_inherits(Channel, _Emitter);
|
|
27
26
|
var _super = _createSuper(Channel);
|
|
28
|
-
function Channel(config) {
|
|
27
|
+
function Channel(config, analyticsHelper) {
|
|
29
28
|
var _this;
|
|
30
29
|
_classCallCheck(this, Channel);
|
|
31
30
|
_this = _super.call(this);
|
|
32
31
|
_defineProperty(_assertThisInitialized(_this), "connected", false);
|
|
33
32
|
_defineProperty(_assertThisInitialized(_this), "socket", null);
|
|
33
|
+
_defineProperty(_assertThisInitialized(_this), "reconnectHelper", null);
|
|
34
34
|
_defineProperty(_assertThisInitialized(_this), "initialized", false);
|
|
35
|
-
_defineProperty(_assertThisInitialized(_this), "
|
|
36
|
-
type: ExperienceTypes.Load,
|
|
37
|
-
performanceType: ExperiencePerformanceTypes.Custom,
|
|
38
|
-
performanceConfig: {
|
|
39
|
-
histogram: _defineProperty({}, ExperiencePerformanceTypes.Custom, {
|
|
40
|
-
duration: '250_500_1000_1500_2000_3000_4000'
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
}));
|
|
35
|
+
_defineProperty(_assertThisInitialized(_this), "network", null);
|
|
44
36
|
_defineProperty(_assertThisInitialized(_this), "getInitialized", function () {
|
|
45
37
|
return _this.initialized;
|
|
46
38
|
});
|
|
@@ -51,16 +43,12 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
51
43
|
return _this.socket;
|
|
52
44
|
});
|
|
53
45
|
_defineProperty(_assertThisInitialized(_this), "onConnectError", function (error) {
|
|
54
|
-
var
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
61
|
-
documentAri: _this.config.documentAri
|
|
62
|
-
}
|
|
63
|
-
}, _this.analyticsClient);
|
|
46
|
+
var _this$analyticsHelper, _this$analyticsHelper2;
|
|
47
|
+
var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT, _this.analyticsHelper);
|
|
48
|
+
(_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendActionEvent(EVENT_ACTION.CONNECTION, EVENT_STATUS.FAILURE, {
|
|
49
|
+
latency: measure === null || measure === void 0 ? void 0 : measure.duration
|
|
50
|
+
});
|
|
51
|
+
(_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(error, 'Error while establishing connection');
|
|
64
52
|
// If error received with `data`, it means the connection is rejected
|
|
65
53
|
// by the server on purpose for example no permission, so no need to
|
|
66
54
|
// keep the underneath connection, need to close. But some error like
|
|
@@ -74,18 +62,29 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
74
62
|
data: error.data
|
|
75
63
|
});
|
|
76
64
|
});
|
|
65
|
+
_defineProperty(_assertThisInitialized(_this), "onReconnectError", function (error) {
|
|
66
|
+
var _this$reconnectHelper, _this$reconnectHelper2;
|
|
67
|
+
(_this$reconnectHelper = _this.reconnectHelper) === null || _this$reconnectHelper === void 0 ? void 0 : _this$reconnectHelper.countReconnectError();
|
|
68
|
+
if ((_this$reconnectHelper2 = _this.reconnectHelper) !== null && _this$reconnectHelper2 !== void 0 && _this$reconnectHelper2.isLikelyNetworkIssue()) {
|
|
69
|
+
var _this$analyticsHelper3;
|
|
70
|
+
(_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(error, 'Likely network issue while reconnecting the channel');
|
|
71
|
+
_this.emit('error', {
|
|
72
|
+
message: 'Reconnection failed 8 times when browser was offline, likely there was a network issue.',
|
|
73
|
+
data: {
|
|
74
|
+
status: 400,
|
|
75
|
+
code: 'RECONNECTION_NETWORK_ISSUE'
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
77
80
|
_defineProperty(_assertThisInitialized(_this), "onConnect", function () {
|
|
81
|
+
var _this$analyticsHelper4;
|
|
78
82
|
_this.connected = true;
|
|
79
83
|
logger('Connected.', _this.socket.id);
|
|
80
|
-
var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT);
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
eventStatus: EVENT_STATUS.SUCCESS,
|
|
85
|
-
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
86
|
-
documentAri: _this.config.documentAri
|
|
87
|
-
}
|
|
88
|
-
}, _this.analyticsClient);
|
|
84
|
+
var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT, _this.analyticsHelper);
|
|
85
|
+
(_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendActionEvent(EVENT_ACTION.CONNECTION, EVENT_STATUS.SUCCESS, {
|
|
86
|
+
latency: measure === null || measure === void 0 ? void 0 : measure.duration
|
|
87
|
+
});
|
|
89
88
|
_this.emit('connected', {
|
|
90
89
|
sid: _this.socket.id,
|
|
91
90
|
initialized: _this.initialized
|
|
@@ -96,19 +95,16 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
96
95
|
logger('Session ID is', _this.socket.id);
|
|
97
96
|
if (data.type === 'initial') {
|
|
98
97
|
if (!_this.initialized) {
|
|
99
|
-
var
|
|
100
|
-
_this.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
ttlEnabled: data === null || data === void 0 ? void 0 : data.ttlEnabled
|
|
110
|
-
}
|
|
111
|
-
}, _this.analyticsClient);
|
|
98
|
+
var _this$initExperience, _this$analyticsHelper5;
|
|
99
|
+
var measure = stopMeasure(MEASURE_NAME.DOCUMENT_INIT, _this.analyticsHelper);
|
|
100
|
+
(_this$initExperience = _this.initExperience) === null || _this$initExperience === void 0 ? void 0 : _this$initExperience.success();
|
|
101
|
+
(_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendActionEvent(EVENT_ACTION.DOCUMENT_INIT,
|
|
102
|
+
// TODO: detect when document init fails and fire corresponding event for it
|
|
103
|
+
EVENT_STATUS.SUCCESS, {
|
|
104
|
+
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
105
|
+
resetReason: data === null || data === void 0 ? void 0 : data.resetReason,
|
|
106
|
+
ttlEnabled: data === null || data === void 0 ? void 0 : data.ttlEnabled
|
|
107
|
+
});
|
|
112
108
|
var doc = data.doc,
|
|
113
109
|
version = data.version,
|
|
114
110
|
userId = data.userId,
|
|
@@ -137,10 +133,17 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
137
133
|
_this.emit('steps:added', data);
|
|
138
134
|
}
|
|
139
135
|
});
|
|
136
|
+
_defineProperty(_assertThisInitialized(_this), "onOnlineHandler", function () {
|
|
137
|
+
// Force an immediate reconnect, the socket must first be closed to reset reconnection delay logic
|
|
138
|
+
if (!_this.connected) {
|
|
139
|
+
var _this$socket2, _this$socket3;
|
|
140
|
+
(_this$socket2 = _this.socket) === null || _this$socket2 === void 0 ? void 0 : _this$socket2.close();
|
|
141
|
+
(_this$socket3 = _this.socket) === null || _this$socket3 === void 0 ? void 0 : _this$socket3.connect();
|
|
142
|
+
}
|
|
143
|
+
});
|
|
140
144
|
_this.config = config;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
145
|
+
_this.analyticsHelper = analyticsHelper;
|
|
146
|
+
_this.initExperience = createDocInitExp(_this.analyticsHelper);
|
|
144
147
|
return _this;
|
|
145
148
|
}
|
|
146
149
|
|
|
@@ -153,10 +156,11 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
153
156
|
*/
|
|
154
157
|
function connect() {
|
|
155
158
|
var _this2 = this;
|
|
156
|
-
startMeasure(MEASURE_NAME.SOCKET_CONNECT);
|
|
159
|
+
startMeasure(MEASURE_NAME.SOCKET_CONNECT, this.analyticsHelper);
|
|
157
160
|
if (!this.initialized) {
|
|
158
|
-
|
|
159
|
-
this.
|
|
161
|
+
var _this$initExperience2;
|
|
162
|
+
startMeasure(MEASURE_NAME.DOCUMENT_INIT, this.analyticsHelper);
|
|
163
|
+
(_this$initExperience2 = this.initExperience) === null || _this$initExperience2 === void 0 ? void 0 : _this$initExperience2.start();
|
|
160
164
|
}
|
|
161
165
|
var _this$config = this.config,
|
|
162
166
|
documentAri = _this$config.documentAri,
|
|
@@ -232,6 +236,7 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
232
236
|
});
|
|
233
237
|
this.socket.on('disconnect', /*#__PURE__*/function () {
|
|
234
238
|
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(reason) {
|
|
239
|
+
var _this2$analyticsHelpe;
|
|
235
240
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
236
241
|
while (1) {
|
|
237
242
|
switch (_context.prev = _context.next) {
|
|
@@ -243,7 +248,18 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
243
248
|
});
|
|
244
249
|
if (reason === 'io server disconnect' && _this2.socket) {
|
|
245
250
|
// The disconnection was initiated by the server, we need to reconnect manually.
|
|
246
|
-
|
|
251
|
+
try {
|
|
252
|
+
_this2.socket.connect();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
(_this2$analyticsHelpe = _this2.analyticsHelper) === null || _this2$analyticsHelpe === void 0 ? void 0 : _this2$analyticsHelpe.sendErrorEvent(error, 'Error while reconnecting the channel');
|
|
255
|
+
_this2.emit('error', {
|
|
256
|
+
message: 'Caught error during reconnection.',
|
|
257
|
+
data: {
|
|
258
|
+
status: 500,
|
|
259
|
+
code: 'RECONNECTION_ERROR'
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
247
263
|
}
|
|
248
264
|
case 4:
|
|
249
265
|
case "end":
|
|
@@ -257,14 +273,26 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
257
273
|
};
|
|
258
274
|
}());
|
|
259
275
|
|
|
260
|
-
// Socket error, including errors from `packetMiddleware`, `controllers` and `onconnect` and more.
|
|
276
|
+
// Socket error, including errors from `packetMiddleware`, `controllers` and `onconnect` and more. Parameter is a plain JSON object.
|
|
261
277
|
this.socket.on('error', function (error) {
|
|
262
278
|
_this2.emit('error', error);
|
|
263
279
|
});
|
|
264
280
|
|
|
265
|
-
// `connect_error`'s
|
|
281
|
+
// `connect_error`'s parameter type is `Error`.
|
|
266
282
|
// Ensure the error emit to the provider has the same structure, so we can handle them unified.
|
|
267
283
|
this.socket.on('connect_error', this.onConnectError);
|
|
284
|
+
|
|
285
|
+
// To trigger reconnection when browser comes back online
|
|
286
|
+
if (!this.network) {
|
|
287
|
+
this.network = new Network({
|
|
288
|
+
onlineCallback: this.onOnlineHandler
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Helper class to track reconnection issues, to emit an error if too many failed reconnection attempts happen
|
|
293
|
+
this.reconnectHelper = new ReconnectHelper();
|
|
294
|
+
// Fired upon a reconnection attempt error (from Socket.IO Manager)
|
|
295
|
+
this.socket.io.on('reconnect_error', this.onReconnectError);
|
|
268
296
|
}
|
|
269
297
|
}, {
|
|
270
298
|
key: "fetchCatchup",
|
|
@@ -375,7 +403,7 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
375
403
|
}
|
|
376
404
|
};
|
|
377
405
|
this.emit('error', errorCatchup);
|
|
378
|
-
|
|
406
|
+
throw _context2.t19;
|
|
379
407
|
case 52:
|
|
380
408
|
case "end":
|
|
381
409
|
return _context2.stop();
|
|
@@ -420,10 +448,15 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
420
448
|
}, {
|
|
421
449
|
key: "disconnect",
|
|
422
450
|
value: function disconnect() {
|
|
451
|
+
var _this$network;
|
|
423
452
|
this.unsubscribeAll();
|
|
453
|
+
(_this$network = this.network) === null || _this$network === void 0 ? void 0 : _this$network.destroy();
|
|
454
|
+
this.network = null;
|
|
424
455
|
if (this.socket) {
|
|
456
|
+
var _this$reconnectHelper3;
|
|
425
457
|
this.socket.close();
|
|
426
458
|
this.socket = null;
|
|
459
|
+
(_this$reconnectHelper3 = this.reconnectHelper) === null || _this$reconnectHelper3 === void 0 ? void 0 : _this$reconnectHelper3.destroy();
|
|
427
460
|
}
|
|
428
461
|
}
|
|
429
462
|
}]);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
export var NetworkStatus;
|
|
5
|
+
(function (NetworkStatus) {
|
|
6
|
+
NetworkStatus["ONLINE"] = "ONLINE";
|
|
7
|
+
NetworkStatus["OFFLINE"] = "OFFLINE";
|
|
8
|
+
})(NetworkStatus || (NetworkStatus = {}));
|
|
9
|
+
var Network = /*#__PURE__*/function () {
|
|
10
|
+
function Network(props) {
|
|
11
|
+
var _this = this;
|
|
12
|
+
_classCallCheck(this, Network);
|
|
13
|
+
_defineProperty(this, "offlineHandler", function () {
|
|
14
|
+
_this.status = NetworkStatus.OFFLINE;
|
|
15
|
+
});
|
|
16
|
+
_defineProperty(this, "onlineHandler", function () {
|
|
17
|
+
_this.status = NetworkStatus.ONLINE;
|
|
18
|
+
if (_this.onlineCallback) {
|
|
19
|
+
_this.onlineCallback();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
if (props !== null && props !== void 0 && props.initialStatus) {
|
|
23
|
+
this.status = props.initialStatus;
|
|
24
|
+
}
|
|
25
|
+
if (props !== null && props !== void 0 && props.onlineCallback) {
|
|
26
|
+
this.onlineCallback = props.onlineCallback;
|
|
27
|
+
}
|
|
28
|
+
window.addEventListener('offline', this.offlineHandler);
|
|
29
|
+
window.addEventListener('online', this.onlineHandler);
|
|
30
|
+
}
|
|
31
|
+
_createClass(Network, [{
|
|
32
|
+
key: "getStatus",
|
|
33
|
+
value: function getStatus() {
|
|
34
|
+
return this.status || null;
|
|
35
|
+
}
|
|
36
|
+
}, {
|
|
37
|
+
key: "destroy",
|
|
38
|
+
value: function destroy() {
|
|
39
|
+
window.removeEventListener('offline', this.offlineHandler);
|
|
40
|
+
window.removeEventListener('online', this.onlineHandler);
|
|
41
|
+
}
|
|
42
|
+
}]);
|
|
43
|
+
return Network;
|
|
44
|
+
}();
|
|
45
|
+
export { Network as default };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
+
import { NetworkStatus } from './network';
|
|
5
|
+
import { network } from './singleton';
|
|
6
|
+
|
|
7
|
+
// Calculation for max 8 offline reconnect attempts, with reconnection delay 200ms, randomization factor 0.5, reconnection delay max 128s
|
|
8
|
+
// Min: 800ms, Avg: 51s, Max: 6m
|
|
9
|
+
var FAILED_RECONNECTS_WHILE_OFFLINE_THRESHOLD = 8;
|
|
10
|
+
var ReconnectHelper = /*#__PURE__*/function () {
|
|
11
|
+
function ReconnectHelper() {
|
|
12
|
+
var _this = this;
|
|
13
|
+
_classCallCheck(this, ReconnectHelper);
|
|
14
|
+
_defineProperty(this, "failedReconnectCount", 0);
|
|
15
|
+
_defineProperty(this, "onlineHandler", function () {
|
|
16
|
+
_this.failedReconnectCount = 0;
|
|
17
|
+
});
|
|
18
|
+
window.addEventListener('online', this.onlineHandler);
|
|
19
|
+
}
|
|
20
|
+
_createClass(ReconnectHelper, [{
|
|
21
|
+
key: "countReconnectError",
|
|
22
|
+
value: function countReconnectError() {
|
|
23
|
+
// Only count the reconnection attempts when offline
|
|
24
|
+
if (network.getStatus() === NetworkStatus.OFFLINE) {
|
|
25
|
+
this.failedReconnectCount++;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, {
|
|
29
|
+
key: "isLikelyNetworkIssue",
|
|
30
|
+
value: function isLikelyNetworkIssue() {
|
|
31
|
+
var isLikelyNetworkIssue = this.failedReconnectCount >= FAILED_RECONNECTS_WHILE_OFFLINE_THRESHOLD;
|
|
32
|
+
return isLikelyNetworkIssue;
|
|
33
|
+
}
|
|
34
|
+
}, {
|
|
35
|
+
key: "destroy",
|
|
36
|
+
value: function destroy() {
|
|
37
|
+
window.removeEventListener('online', this.onlineHandler);
|
|
38
|
+
}
|
|
39
|
+
}]);
|
|
40
|
+
return ReconnectHelper;
|
|
41
|
+
}();
|
|
42
|
+
export { ReconnectHelper as default };
|