@atlaskit/collab-provider 8.2.0 → 8.4.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/cjs/analytics/index.js +67 -9
  3. package/dist/cjs/analytics/performance.js +46 -35
  4. package/dist/cjs/analytics/ufo.js +33 -0
  5. package/dist/cjs/channel.js +307 -162
  6. package/dist/cjs/connectivity/network.js +53 -0
  7. package/dist/cjs/connectivity/reconnect-helper.js +48 -0
  8. package/dist/cjs/connectivity/singleton.js +15 -0
  9. package/dist/cjs/disconnected-reason-mapper.js +19 -2
  10. package/dist/cjs/{error-code-mapper.js → errors/error-code-mapper.js} +17 -2
  11. package/dist/cjs/errors/error-types.js +43 -0
  12. package/dist/cjs/helpers/const.js +4 -11
  13. package/dist/cjs/provider/catchup.js +8 -12
  14. package/dist/cjs/provider/commit-step.js +70 -0
  15. package/dist/cjs/provider/index.js +503 -566
  16. package/dist/cjs/provider/telepointers.js +78 -0
  17. package/dist/cjs/version-wrapper.js +1 -1
  18. package/dist/cjs/version.json +1 -1
  19. package/dist/es2019/analytics/index.js +58 -8
  20. package/dist/es2019/analytics/performance.js +47 -35
  21. package/dist/es2019/analytics/ufo.js +22 -0
  22. package/dist/es2019/channel.js +192 -93
  23. package/dist/es2019/connectivity/network.js +34 -0
  24. package/dist/es2019/connectivity/reconnect-helper.js +29 -0
  25. package/dist/es2019/connectivity/singleton.js +7 -0
  26. package/dist/es2019/disconnected-reason-mapper.js +17 -1
  27. package/dist/es2019/{error-code-mapper.js → errors/error-code-mapper.js} +17 -2
  28. package/dist/es2019/errors/error-types.js +13 -0
  29. package/dist/es2019/helpers/const.js +3 -8
  30. package/dist/es2019/provider/catchup.js +5 -12
  31. package/dist/es2019/provider/commit-step.js +57 -0
  32. package/dist/es2019/provider/index.js +428 -515
  33. package/dist/es2019/provider/telepointers.js +65 -0
  34. package/dist/es2019/version-wrapper.js +1 -1
  35. package/dist/es2019/version.json +1 -1
  36. package/dist/esm/analytics/index.js +68 -9
  37. package/dist/esm/analytics/performance.js +47 -35
  38. package/dist/esm/analytics/ufo.js +25 -0
  39. package/dist/esm/channel.js +308 -165
  40. package/dist/esm/connectivity/network.js +45 -0
  41. package/dist/esm/connectivity/reconnect-helper.js +42 -0
  42. package/dist/esm/connectivity/singleton.js +7 -0
  43. package/dist/esm/disconnected-reason-mapper.js +17 -1
  44. package/dist/esm/{error-code-mapper.js → errors/error-code-mapper.js} +17 -2
  45. package/dist/esm/errors/error-types.js +34 -0
  46. package/dist/esm/helpers/const.js +3 -8
  47. package/dist/esm/provider/catchup.js +8 -12
  48. package/dist/esm/provider/commit-step.js +62 -0
  49. package/dist/esm/provider/index.js +504 -567
  50. package/dist/esm/provider/telepointers.js +69 -0
  51. package/dist/esm/version-wrapper.js +1 -1
  52. package/dist/esm/version.json +1 -1
  53. package/dist/types/analytics/index.d.ts +8 -2
  54. package/dist/types/analytics/performance.d.ts +6 -5
  55. package/dist/types/analytics/ufo.d.ts +3 -0
  56. package/dist/types/channel.d.ts +16 -5
  57. package/dist/types/connectivity/network.d.ts +17 -0
  58. package/dist/types/connectivity/reconnect-helper.d.ts +8 -0
  59. package/dist/types/connectivity/singleton.d.ts +3 -0
  60. package/dist/types/disconnected-reason-mapper.d.ts +1 -0
  61. package/dist/types/{error-code-mapper.d.ts → errors/error-code-mapper.d.ts} +6 -2
  62. package/dist/types/errors/error-types.d.ts +8 -0
  63. package/dist/types/helpers/const.d.ts +133 -26
  64. package/dist/types/provider/commit-step.d.ts +14 -0
  65. package/dist/types/provider/index.d.ts +24 -6
  66. package/dist/types/provider/telepointers.d.ts +5 -0
  67. package/dist/types/socket-io-provider.d.ts +3 -2
  68. package/dist/types/types.d.ts +44 -12
  69. package/package.json +5 -6
  70. package/report.api.md +49 -3
  71. package/.vscode/settings.json +0 -3
  72. package/error-code-mapper/package.json +0 -15
@@ -6,41 +6,35 @@ import _inherits from "@babel/runtime/helpers/inherits";
6
6
  import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
7
7
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
8
8
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
9
- import _regeneratorRuntime from "@babel/runtime/regenerator";
10
9
  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; }
11
10
  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; }
11
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
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
- import { ErrorCodeMapper } from './error-code-mapper';
16
+ import { ErrorCodeMapper } from './errors/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 { ExperiencePerformanceTypes, ExperienceTypes, UFOExperience } from '@atlaskit/ufo';
20
+ import ReconnectHelper from './connectivity/reconnect-helper';
21
+ import { createDocInitExp } from './analytics/ufo';
22
+ import { socketIOReasons } from './disconnected-reason-mapper';
23
+ import Network from './connectivity/network';
24
+ import { NotConnectedError, NotInitializedError } from './errors/error-types';
24
25
  var logger = createLogger('Channel', 'green');
25
26
  export var Channel = /*#__PURE__*/function (_Emitter) {
26
27
  _inherits(Channel, _Emitter);
27
28
  var _super = _createSuper(Channel);
28
- function Channel(config) {
29
+ function Channel(config, analyticsHelper) {
29
30
  var _this;
30
31
  _classCallCheck(this, Channel);
31
32
  _this = _super.call(this);
32
33
  _defineProperty(_assertThisInitialized(_this), "connected", false);
33
34
  _defineProperty(_assertThisInitialized(_this), "socket", null);
35
+ _defineProperty(_assertThisInitialized(_this), "reconnectHelper", null);
34
36
  _defineProperty(_assertThisInitialized(_this), "initialized", false);
35
- _defineProperty(_assertThisInitialized(_this), "initExperience", new UFOExperience('collab-provider.document-init', {
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
- }));
37
+ _defineProperty(_assertThisInitialized(_this), "network", null);
44
38
  _defineProperty(_assertThisInitialized(_this), "getInitialized", function () {
45
39
  return _this.initialized;
46
40
  });
@@ -50,42 +44,83 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
50
44
  _defineProperty(_assertThisInitialized(_this), "getSocket", function () {
51
45
  return _this.socket;
52
46
  });
47
+ _defineProperty(_assertThisInitialized(_this), "getToken", function () {
48
+ return _this.token;
49
+ });
50
+ _defineProperty(_assertThisInitialized(_this), "setToken", function (value) {
51
+ if (_this.config.cacheToken) {
52
+ _this.token = value;
53
+ }
54
+ });
55
+ _defineProperty(_assertThisInitialized(_this), "unsetToken", function () {
56
+ return _this.setToken();
57
+ });
58
+ _defineProperty(_assertThisInitialized(_this), "handlePermissionInvalidateToken", function (data) {
59
+ var _this$analyticsHelper;
60
+ logger('Received permission invalidate event ', data);
61
+ (_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendActionEvent(EVENT_ACTION.INVALIDATE_TOKEN, EVENT_STATUS.SUCCESS, {
62
+ reason: data.reason,
63
+ // Potentially incorrect when value of token changes between connecting and connect.
64
+ // See: https://bitbucket.org/atlassian/%7Bc8e2f021-38d2-46d0-9b7a-b3f7b428f724%7D/pull-requests/29905#comment-375308874
65
+ usedCachedToken: _this.token ? true : false
66
+ });
67
+ _this.unsetToken();
68
+ });
53
69
  _defineProperty(_assertThisInitialized(_this), "onConnectError", function (error) {
54
- var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT);
55
- triggerAnalyticsEvent({
56
- eventAction: EVENT_ACTION.CONNECTION,
57
- attributes: {
58
- eventStatus: EVENT_STATUS.FAILURE,
59
- error: error,
60
- latency: measure === null || measure === void 0 ? void 0 : measure.duration,
61
- documentAri: _this.config.documentAri
62
- }
63
- }, _this.analyticsClient);
70
+ var _this$analyticsHelper2, _this$analyticsHelper3;
71
+ var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT, _this.analyticsHelper);
72
+ (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendActionEvent(EVENT_ACTION.CONNECTION, EVENT_STATUS.FAILURE, {
73
+ latency: measure === null || measure === void 0 ? void 0 : measure.duration,
74
+ // Potentially incorrect when value of token changes between connecting and connect.
75
+ // See: https://bitbucket.org/atlassian/%7Bc8e2f021-38d2-46d0-9b7a-b3f7b428f724%7D/pull-requests/29905#comment-375308874
76
+ usedCachedToken: _this.token ? true : false
77
+ });
78
+ (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(error, 'Error while establishing connection');
64
79
  // If error received with `data`, it means the connection is rejected
65
80
  // by the server on purpose for example no permission, so no need to
66
81
  // keep the underneath connection, need to close. But some error like
67
82
  // `xhr polling error` needs to retry.
68
- if (!!error.data) {
83
+ var errorData = error.data;
84
+ if (errorData) {
69
85
  var _this$socket;
86
+ // We only want to refresh the token if only its invalid
87
+ if ([401, 403].includes(errorData.status)) {
88
+ //nullify token so it is forced to generate new token on reconnect
89
+ _this.unsetToken();
90
+ }
70
91
  (_this$socket = _this.socket) === null || _this$socket === void 0 ? void 0 : _this$socket.close();
71
92
  }
72
93
  _this.emit('error', {
73
94
  message: error.message,
74
- data: error.data
95
+ data: errorData
75
96
  });
76
97
  });
98
+ _defineProperty(_assertThisInitialized(_this), "onReconnectError", function (error) {
99
+ var _this$reconnectHelper, _this$reconnectHelper2;
100
+ (_this$reconnectHelper = _this.reconnectHelper) === null || _this$reconnectHelper === void 0 ? void 0 : _this$reconnectHelper.countReconnectError();
101
+ if ((_this$reconnectHelper2 = _this.reconnectHelper) !== null && _this$reconnectHelper2 !== void 0 && _this$reconnectHelper2.isLikelyNetworkIssue()) {
102
+ var _this$analyticsHelper4;
103
+ (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(error, 'Likely network issue while reconnecting the channel');
104
+ _this.emit('error', {
105
+ message: 'Reconnection failed 8 times when browser was offline, likely there was a network issue.',
106
+ data: {
107
+ status: 400,
108
+ code: 'RECONNECTION_NETWORK_ISSUE'
109
+ }
110
+ });
111
+ }
112
+ });
77
113
  _defineProperty(_assertThisInitialized(_this), "onConnect", function () {
114
+ var _this$analyticsHelper5;
78
115
  _this.connected = true;
79
116
  logger('Connected.', _this.socket.id);
80
- var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT);
81
- triggerAnalyticsEvent({
82
- eventAction: EVENT_ACTION.CONNECTION,
83
- attributes: {
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);
117
+ var measure = stopMeasure(MEASURE_NAME.SOCKET_CONNECT, _this.analyticsHelper);
118
+ (_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendActionEvent(EVENT_ACTION.CONNECTION, EVENT_STATUS.SUCCESS, {
119
+ latency: measure === null || measure === void 0 ? void 0 : measure.duration,
120
+ // Potentially incorrect when value of token changes between connecting and connect.
121
+ // See: https://bitbucket.org/atlassian/%7Bc8e2f021-38d2-46d0-9b7a-b3f7b428f724%7D/pull-requests/29905#comment-375308874
122
+ usedCachedToken: _this.token ? true : false
123
+ });
89
124
  _this.emit('connected', {
90
125
  sid: _this.socket.id,
91
126
  initialized: _this.initialized
@@ -96,19 +131,16 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
96
131
  logger('Session ID is', _this.socket.id);
97
132
  if (data.type === 'initial') {
98
133
  if (!_this.initialized) {
99
- var measure = stopMeasure(MEASURE_NAME.DOCUMENT_INIT);
100
- _this.initExperience.success();
101
- triggerAnalyticsEvent({
102
- eventAction: EVENT_ACTION.DOCUMENT_INIT,
103
- attributes: {
104
- eventStatus: EVENT_STATUS.SUCCESS,
105
- // TODO: detect when document init fails and fire corresponding event for it
106
- latency: measure === null || measure === void 0 ? void 0 : measure.duration,
107
- documentAri: _this.config.documentAri,
108
- requiredPageRecovery: data === null || data === void 0 ? void 0 : data.requiredPageRecovery,
109
- ttlEnabled: data === null || data === void 0 ? void 0 : data.ttlEnabled
110
- }
111
- }, _this.analyticsClient);
134
+ var _this$initExperience, _this$analyticsHelper6;
135
+ var measure = stopMeasure(MEASURE_NAME.DOCUMENT_INIT, _this.analyticsHelper);
136
+ (_this$initExperience = _this.initExperience) === null || _this$initExperience === void 0 ? void 0 : _this$initExperience.success();
137
+ (_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendActionEvent(EVENT_ACTION.DOCUMENT_INIT,
138
+ // TODO: detect when document init fails and fire corresponding event for it
139
+ EVENT_STATUS.SUCCESS, {
140
+ latency: measure === null || measure === void 0 ? void 0 : measure.duration,
141
+ resetReason: data === null || data === void 0 ? void 0 : data.resetReason,
142
+ ttlEnabled: data === null || data === void 0 ? void 0 : data.ttlEnabled
143
+ });
112
144
  var doc = data.doc,
113
145
  version = data.version,
114
146
  userId = data.userId,
@@ -137,10 +169,17 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
137
169
  _this.emit('steps:added', data);
138
170
  }
139
171
  });
172
+ _defineProperty(_assertThisInitialized(_this), "onOnlineHandler", function () {
173
+ // Force an immediate reconnect, the socket must first be closed to reset reconnection delay logic
174
+ if (!_this.connected) {
175
+ var _this$socket2, _this$socket3;
176
+ (_this$socket2 = _this.socket) === null || _this$socket2 === void 0 ? void 0 : _this$socket2.close();
177
+ (_this$socket3 = _this.socket) === null || _this$socket3 === void 0 ? void 0 : _this$socket3.connect();
178
+ }
179
+ });
140
180
  _this.config = config;
141
- if (config.analyticsClient) {
142
- _this.analyticsClient = config.analyticsClient;
143
- }
181
+ _this.analyticsHelper = analyticsHelper;
182
+ _this.initExperience = createDocInitExp(_this.analyticsHelper);
144
183
  return _this;
145
184
  }
146
185
 
@@ -153,43 +192,86 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
153
192
  */
154
193
  function connect() {
155
194
  var _this2 = this;
156
- startMeasure(MEASURE_NAME.SOCKET_CONNECT);
195
+ startMeasure(MEASURE_NAME.SOCKET_CONNECT, this.analyticsHelper);
157
196
  if (!this.initialized) {
158
- startMeasure(MEASURE_NAME.DOCUMENT_INIT);
159
- this.initExperience.start();
197
+ var _this$initExperience2;
198
+ startMeasure(MEASURE_NAME.DOCUMENT_INIT, this.analyticsHelper);
199
+ (_this$initExperience2 = this.initExperience) === null || _this$initExperience2 === void 0 ? void 0 : _this$initExperience2.start();
160
200
  }
161
201
  var _this$config = this.config,
162
202
  documentAri = _this$config.documentAri,
163
203
  url = _this$config.url;
164
204
  var createSocket = this.config.createSocket;
165
- var permissionTokenRefresh = this.config.permissionTokenRefresh;
166
- var authCb = null;
205
+ var _this$config2 = this.config,
206
+ permissionTokenRefresh = _this$config2.permissionTokenRefresh,
207
+ cacheToken = _this$config2.cacheToken;
208
+ var auth;
209
+ var authData = {
210
+ // The initialized status. If false, BE will send document, otherwise not.
211
+ initialized: this.initialized,
212
+ // ESS-1009 Allow to opt-in into 404 response
213
+ need404: this.config.need404
214
+ };
167
215
  if (permissionTokenRefresh) {
168
- authCb = function authCb(cb) {
169
- permissionTokenRefresh().then(function (token) {
170
- cb(_objectSpread(_objectSpread({}, token ? {
171
- token: token
172
- } : {}), {}, {
173
- // The initialized status. If false, BE will send document, otherwise not.
174
- initialized: _this2.initialized,
175
- // ESS-1009 Allow to opt-in into 404 response
176
- need404: _this2.config.need404
177
- }));
178
- }).catch(function (err) {
179
- _this2.emit('error', err);
180
- });
181
- };
216
+ auth = /*#__PURE__*/function () {
217
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(cb) {
218
+ var token, newErr;
219
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
220
+ while (1) {
221
+ switch (_context.prev = _context.next) {
222
+ case 0:
223
+ if (!(cacheToken && _this2.token)) {
224
+ _context.next = 5;
225
+ break;
226
+ }
227
+ authData.token = _this2.token;
228
+ cb(authData);
229
+ _context.next = 17;
230
+ break;
231
+ case 5:
232
+ _context.prev = 5;
233
+ _context.next = 8;
234
+ return permissionTokenRefresh();
235
+ case 8:
236
+ token = _context.sent;
237
+ if (token) {
238
+ // save token locally
239
+ _this2.setToken(token);
240
+ authData.token = token;
241
+ }
242
+ cb(authData);
243
+ _context.next = 17;
244
+ break;
245
+ case 13:
246
+ _context.prev = 13;
247
+ _context.t0 = _context["catch"](5);
248
+ newErr = {
249
+ message: _context.t0.message ? _context.t0.message : 'Content not found',
250
+ data: {
251
+ status: 403,
252
+ code: _context.t0.data.code ? _context.t0.data.code : 'INSUFFICIENT_EDITING_PERMISSION',
253
+ meta: {
254
+ description: _context.t0.data.meta.description ? _context.t0.data.meta.description : 'RESOURCE_DELETED',
255
+ reason: _context.t0.data.meta.reason ? _context.t0.data.meta.reason : 'RESOURCE_DELETED'
256
+ }
257
+ }
258
+ };
259
+ _this2.emit('error', newErr);
260
+ case 17:
261
+ case "end":
262
+ return _context.stop();
263
+ }
264
+ }
265
+ }, _callee, null, [[5, 13]]);
266
+ }));
267
+ return function auth(_x) {
268
+ return _ref.apply(this, arguments);
269
+ };
270
+ }();
182
271
  } else {
183
- authCb = function authCb(cb) {
184
- cb({
185
- // The initialized status. If false, BE will send document, otherwise not.
186
- initialized: _this2.initialized,
187
- // ESS-1009 Allow to opt-in into 404 response
188
- need404: _this2.config.need404
189
- });
190
- };
272
+ auth = authData;
191
273
  }
192
- this.socket = createSocket("".concat(url, "/session/").concat(documentAri), authCb, this.config.productInfo);
274
+ this.socket = createSocket("".concat(url, "/session/").concat(documentAri), auth, this.config.productInfo);
193
275
 
194
276
  // Due to https://github.com/socketio/socket.io-client/issues/1473,
195
277
  // reconnect no longer fired on the socket.
@@ -211,11 +293,11 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
211
293
  this.socket.on('participant:left', function (data) {
212
294
  _this2.emit('participant:left', data);
213
295
  });
214
- this.socket.on('participant:updated', function (_ref) {
215
- var sessionId = _ref.sessionId,
216
- timestamp = _ref.timestamp,
217
- data = _ref.data,
218
- clientId = _ref.clientId;
296
+ this.socket.on('participant:updated', function (_ref2) {
297
+ var sessionId = _ref2.sessionId,
298
+ timestamp = _ref2.timestamp,
299
+ data = _ref2.data,
300
+ clientId = _ref2.clientId;
219
301
  _this2.emit('participant:updated', _objectSpread({
220
302
  sessionId: sessionId,
221
303
  timestamp: timestamp,
@@ -231,159 +313,202 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
231
313
  _this2.emit('status', data);
232
314
  });
233
315
  this.socket.on('disconnect', /*#__PURE__*/function () {
234
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(reason) {
235
- return _regeneratorRuntime.wrap(function _callee$(_context) {
316
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(reason) {
317
+ var _this2$analyticsHelpe;
318
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
236
319
  while (1) {
237
- switch (_context.prev = _context.next) {
320
+ switch (_context2.prev = _context2.next) {
238
321
  case 0:
239
322
  _this2.connected = false;
240
323
  logger("disconnect reason: ".concat(reason));
241
324
  _this2.emit('disconnect', {
242
325
  reason: reason
243
326
  });
244
- if (reason === 'io server disconnect' && _this2.socket) {
327
+ if (reason === socketIOReasons.IO_SERVER_DISCONNECT && _this2.socket) {
245
328
  // The disconnection was initiated by the server, we need to reconnect manually.
246
- _this2.socket.connect();
329
+ try {
330
+ _this2.socket.connect();
331
+ } catch (error) {
332
+ (_this2$analyticsHelpe = _this2.analyticsHelper) === null || _this2$analyticsHelpe === void 0 ? void 0 : _this2$analyticsHelpe.sendErrorEvent(error, 'Error while reconnecting the channel');
333
+ _this2.emit('error', {
334
+ message: 'Caught error during reconnection.',
335
+ data: {
336
+ status: 500,
337
+ code: 'RECONNECTION_ERROR'
338
+ }
339
+ });
340
+ }
247
341
  }
248
342
  case 4:
249
343
  case "end":
250
- return _context.stop();
344
+ return _context2.stop();
251
345
  }
252
346
  }
253
- }, _callee);
347
+ }, _callee2);
254
348
  }));
255
- return function (_x) {
256
- return _ref2.apply(this, arguments);
349
+ return function (_x2) {
350
+ return _ref3.apply(this, arguments);
257
351
  };
258
352
  }());
259
353
 
260
- // Socket error, including errors from `packetMiddleware`, `controllers` and `onconnect` and more. Paramter is a plain JSON object.
354
+ // Socket error, including errors from `packetMiddleware`, `controllers` and `onconnect` and more. Parameter is a plain JSON object.
261
355
  this.socket.on('error', function (error) {
262
356
  _this2.emit('error', error);
263
357
  });
264
358
 
265
- // `connect_error`'s paramter type is `Error`.
359
+ // `connect_error`'s parameter type is `Error`.
266
360
  // Ensure the error emit to the provider has the same structure, so we can handle them unified.
267
361
  this.socket.on('connect_error', this.onConnectError);
362
+ this.socket.on('permission:invalidateToken', this.handlePermissionInvalidateToken);
363
+
364
+ // To trigger reconnection when browser comes back online
365
+ if (!this.network) {
366
+ this.network = new Network({
367
+ onlineCallback: this.onOnlineHandler
368
+ });
369
+ }
370
+
371
+ // Helper class to track reconnection issues, to emit an error if too many failed reconnection attempts happen
372
+ this.reconnectHelper = new ReconnectHelper();
373
+ // Fired upon a reconnection attempt error (from Socket.IO Manager)
374
+ this.socket.io.on('reconnect_error', this.onReconnectError);
268
375
  }
269
376
  }, {
270
377
  key: "fetchCatchup",
271
378
  value: function () {
272
- var _fetchCatchup = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(fromVersion) {
273
- var _yield$this$config$pe, _yield$utils$requestS, doc, version, stepMaps, metadata, errorNotFound, errorCatchup;
274
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
379
+ var _fetchCatchup = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(fromVersion) {
380
+ var _this3 = this;
381
+ var _ref4, _this$token, _yield$utils$requestS, doc, version, stepMaps, metadata, errorNotFound, errorCatchup;
382
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
275
383
  while (1) {
276
- switch (_context2.prev = _context2.next) {
384
+ switch (_context3.prev = _context3.next) {
277
385
  case 0:
278
- _context2.prev = 0;
279
- _context2.t0 = utils;
280
- _context2.t1 = this.config;
281
- _context2.t2 = "document/".concat(encodeURIComponent(this.config.documentAri), "/catchup");
282
- _context2.t3 = {
386
+ _context3.prev = 0;
387
+ _context3.t0 = utils;
388
+ _context3.t1 = this.config;
389
+ _context3.t2 = "document/".concat(encodeURIComponent(this.config.documentAri), "/catchup");
390
+ _context3.t3 = {
283
391
  version: fromVersion
284
392
  };
285
- _context2.t4 = _objectSpread;
286
- _context2.t5 = _objectSpread;
287
- _context2.t6 = {};
393
+ _context3.t4 = _objectSpread;
394
+ _context3.t5 = _objectSpread;
395
+ _context3.t6 = {};
288
396
  if (!this.config.permissionTokenRefresh) {
289
- _context2.next = 24;
397
+ _context3.next = 29;
290
398
  break;
291
399
  }
292
- _context2.next = 11;
293
- return this.config.permissionTokenRefresh();
294
- case 11:
295
- _context2.t9 = _yield$this$config$pe = _context2.sent;
296
- _context2.t8 = _context2.t9 !== null;
297
- if (!_context2.t8) {
298
- _context2.next = 15;
400
+ if (!((_this$token = this.token) !== null && _this$token !== void 0)) {
401
+ _context3.next = 13;
299
402
  break;
300
403
  }
301
- _context2.t8 = _yield$this$config$pe !== void 0;
404
+ _context3.t9 = _this$token;
405
+ _context3.next = 16;
406
+ break;
407
+ case 13:
408
+ _context3.next = 15;
409
+ return this.config.permissionTokenRefresh().then(function (token) {
410
+ if (token) {
411
+ _this3.setToken(token);
412
+ }
413
+ return token;
414
+ });
302
415
  case 15:
303
- if (!_context2.t8) {
304
- _context2.next = 19;
416
+ _context3.t9 = _context3.sent;
417
+ case 16:
418
+ _context3.t10 = _ref4 = _context3.t9;
419
+ _context3.t8 = _context3.t10 !== null;
420
+ if (!_context3.t8) {
421
+ _context3.next = 20;
305
422
  break;
306
423
  }
307
- _context2.t10 = _yield$this$config$pe;
308
- _context2.next = 20;
309
- break;
310
- case 19:
311
- _context2.t10 = undefined;
424
+ _context3.t8 = _ref4 !== void 0;
312
425
  case 20:
313
- _context2.t11 = _context2.t10;
314
- _context2.t7 = {
315
- 'x-token': _context2.t11
316
- };
317
- _context2.next = 25;
426
+ if (!_context3.t8) {
427
+ _context3.next = 24;
428
+ break;
429
+ }
430
+ _context3.t11 = _ref4;
431
+ _context3.next = 25;
318
432
  break;
319
433
  case 24:
320
- _context2.t7 = {};
434
+ _context3.t11 = undefined;
321
435
  case 25:
322
- _context2.t12 = _context2.t7;
323
- _context2.t13 = (0, _context2.t5)(_context2.t6, _context2.t12);
324
- _context2.t14 = {};
325
- _context2.t15 = {
436
+ _context3.t12 = _context3.t11;
437
+ _context3.t7 = {
438
+ 'x-token': _context3.t12
439
+ };
440
+ _context3.next = 30;
441
+ break;
442
+ case 29:
443
+ _context3.t7 = {};
444
+ case 30:
445
+ _context3.t13 = _context3.t7;
446
+ _context3.t14 = (0, _context3.t5)(_context3.t6, _context3.t13);
447
+ _context3.t15 = {};
448
+ _context3.t16 = {
326
449
  'x-product': getProduct(this.config.productInfo),
327
450
  'x-subproduct': getSubProduct(this.config.productInfo)
328
451
  };
329
- _context2.t16 = (0, _context2.t4)(_context2.t13, _context2.t14, _context2.t15);
330
- _context2.t17 = {
331
- headers: _context2.t16
452
+ _context3.t17 = (0, _context3.t4)(_context3.t14, _context3.t15, _context3.t16);
453
+ _context3.t18 = {
454
+ headers: _context3.t17
332
455
  };
333
- _context2.t18 = {
334
- path: _context2.t2,
335
- queryParams: _context2.t3,
336
- requestInit: _context2.t17
456
+ _context3.t19 = {
457
+ path: _context3.t2,
458
+ queryParams: _context3.t3,
459
+ requestInit: _context3.t18
337
460
  };
338
- _context2.next = 34;
339
- return _context2.t0.requestService.call(_context2.t0, _context2.t1, _context2.t18);
340
- case 34:
341
- _yield$utils$requestS = _context2.sent;
461
+ _context3.next = 39;
462
+ return _context3.t0.requestService.call(_context3.t0, _context3.t1, _context3.t19);
463
+ case 39:
464
+ _yield$utils$requestS = _context3.sent;
342
465
  doc = _yield$utils$requestS.doc;
343
466
  version = _yield$utils$requestS.version;
344
467
  stepMaps = _yield$utils$requestS.stepMaps;
345
468
  metadata = _yield$utils$requestS.metadata;
346
- return _context2.abrupt("return", {
469
+ return _context3.abrupt("return", {
347
470
  doc: doc,
348
471
  version: version,
349
472
  stepMaps: stepMaps,
350
473
  metadata: metadata
351
474
  });
352
- case 42:
353
- _context2.prev = 42;
354
- _context2.t19 = _context2["catch"](0);
355
- if (!(_context2.t19.code === 404)) {
356
- _context2.next = 48;
475
+ case 47:
476
+ _context3.prev = 47;
477
+ _context3.t20 = _context3["catch"](0);
478
+ if (!(_context3.t20.code === 404)) {
479
+ _context3.next = 53;
357
480
  break;
358
481
  }
359
482
  errorNotFound = {
360
483
  message: ErrorCodeMapper.documentNotFound.message,
361
484
  data: {
362
- status: _context2.t19.code,
485
+ status: _context3.t20.code,
363
486
  code: ErrorCodeMapper.documentNotFound.code
364
487
  }
365
488
  };
366
489
  this.emit('error', errorNotFound);
367
- return _context2.abrupt("return", {});
368
- case 48:
369
- logger("Can't fetch the catchup", _context2.t19.message);
490
+ return _context3.abrupt("return", {});
491
+ case 53:
492
+ //nullify token so it is forced to generate new token on reconnect
493
+ this.unsetToken();
494
+ logger("Can't fetch the catchup", _context3.t20.message);
370
495
  errorCatchup = {
371
496
  message: ErrorCodeMapper.catchupFail.message,
372
497
  data: {
373
- status: _context2.t19.status,
498
+ status: _context3.t20.status,
374
499
  code: ErrorCodeMapper.catchupFail.code
375
500
  }
376
501
  };
377
502
  this.emit('error', errorCatchup);
378
- return _context2.abrupt("return", {});
379
- case 52:
503
+ throw _context3.t20;
504
+ case 58:
380
505
  case "end":
381
- return _context2.stop();
506
+ return _context3.stop();
382
507
  }
383
508
  }
384
- }, _callee2, this, [[0, 42]]);
509
+ }, _callee3, this, [[0, 47]]);
385
510
  }));
386
- function fetchCatchup(_x2) {
511
+ function fetchCatchup(_x3) {
387
512
  return _fetchCatchup.apply(this, arguments);
388
513
  }
389
514
  return fetchCatchup;
@@ -394,7 +519,13 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
394
519
  }, {
395
520
  key: "broadcast",
396
521
  value: function broadcast(type, data, callback) {
397
- if (!this.connected || !this.socket) {
522
+ if (!this.socket) {
523
+ throw new NotInitializedError('Cannot broadcast, not initialized yet');
524
+ }
525
+ if (!this.connected) {
526
+ if (this.config.throwOnNotConnected) {
527
+ throw new NotConnectedError('Cannot broadcast, currently offline.');
528
+ }
398
529
  return;
399
530
  }
400
531
  this.socket.emit('broadcast', _objectSpread({
@@ -404,8 +535,13 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
404
535
  }, {
405
536
  key: "sendMetadata",
406
537
  value: function sendMetadata(metadata) {
407
- if (!this.connected || !this.socket) {
408
- return;
538
+ if (!this.socket) {
539
+ throw new NotInitializedError('Cannot send metadata, not initialized yet');
540
+ }
541
+ if (!this.connected) {
542
+ if (this.config.throwOnNotConnected) {
543
+ throw new NotConnectedError('Cannot send metadata, currently offline.');
544
+ }
409
545
  }
410
546
  this.socket.emit('metadata', metadata);
411
547
  }
@@ -420,10 +556,17 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
420
556
  }, {
421
557
  key: "disconnect",
422
558
  value: function disconnect() {
559
+ var _this$network;
423
560
  this.unsubscribeAll();
561
+ (_this$network = this.network) === null || _this$network === void 0 ? void 0 : _this$network.destroy();
562
+ this.network = null;
563
+ //nullify token so it is forced to generate new token on reconnect
564
+ this.unsetToken();
424
565
  if (this.socket) {
566
+ var _this$reconnectHelper3;
425
567
  this.socket.close();
426
568
  this.socket = null;
569
+ (_this$reconnectHelper3 = this.reconnectHelper) === null || _this$reconnectHelper3 === void 0 ? void 0 : _this$reconnectHelper3.destroy();
427
570
  }
428
571
  }
429
572
  }]);