@atlaskit/collab-provider 7.6.3 → 8.0.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 (51) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/cjs/analytics/index.js +17 -27
  3. package/dist/cjs/analytics/performance.js +0 -2
  4. package/dist/cjs/channel.js +91 -35
  5. package/dist/cjs/helpers/const.js +11 -1
  6. package/dist/cjs/provider/catchup.js +2 -2
  7. package/dist/cjs/provider/index.js +310 -106
  8. package/dist/cjs/types.js +10 -1
  9. package/dist/cjs/version-wrapper.js +1 -1
  10. package/dist/cjs/version.json +1 -1
  11. package/dist/es2019/analytics/index.js +15 -22
  12. package/dist/es2019/analytics/performance.js +0 -2
  13. package/dist/es2019/channel.js +46 -10
  14. package/dist/es2019/helpers/const.js +9 -0
  15. package/dist/es2019/provider/catchup.js +2 -2
  16. package/dist/es2019/provider/index.js +244 -65
  17. package/dist/es2019/types.js +7 -1
  18. package/dist/es2019/version-wrapper.js +1 -1
  19. package/dist/es2019/version.json +1 -1
  20. package/dist/esm/analytics/index.js +15 -22
  21. package/dist/esm/analytics/performance.js +0 -2
  22. package/dist/esm/channel.js +92 -36
  23. package/dist/esm/helpers/const.js +9 -0
  24. package/dist/esm/provider/catchup.js +2 -2
  25. package/dist/esm/provider/index.js +314 -110
  26. package/dist/esm/types.js +7 -1
  27. package/dist/esm/version-wrapper.js +1 -1
  28. package/dist/esm/version.json +1 -1
  29. package/dist/types/analytics/index.d.ts +1 -3
  30. package/dist/types/analytics/performance.d.ts +0 -2
  31. package/dist/types/channel.d.ts +2 -1
  32. package/dist/types/helpers/const.d.ts +33 -3
  33. package/dist/types/provider/index.d.ts +16 -6
  34. package/dist/types/types.d.ts +39 -12
  35. package/package.json +9 -14
  36. package/report.api.md +28 -19
  37. package/dist/types-ts4.0/analytics/index.d.ts +0 -5
  38. package/dist/types-ts4.0/analytics/performance.d.ts +0 -14
  39. package/dist/types-ts4.0/channel.d.ts +0 -27
  40. package/dist/types-ts4.0/config.d.ts +0 -5
  41. package/dist/types-ts4.0/disconnected-reason-mapper.d.ts +0 -15
  42. package/dist/types-ts4.0/emitter.d.ts +0 -19
  43. package/dist/types-ts4.0/error-code-mapper.d.ts +0 -32
  44. package/dist/types-ts4.0/helpers/const.d.ts +0 -31
  45. package/dist/types-ts4.0/helpers/utils.d.ts +0 -11
  46. package/dist/types-ts4.0/index.d.ts +0 -2
  47. package/dist/types-ts4.0/provider/catchup.d.ts +0 -9
  48. package/dist/types-ts4.0/provider/index.d.ts +0 -124
  49. package/dist/types-ts4.0/socket-io-provider.d.ts +0 -4
  50. package/dist/types-ts4.0/types.d.ts +0 -170
  51. package/dist/types-ts4.0/version-wrapper.d.ts +0 -3
@@ -39,8 +39,12 @@ var _throttle = _interopRequireDefault(require("lodash/throttle"));
39
39
 
40
40
  var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
41
41
 
42
+ var _countBy = _interopRequireDefault(require("lodash/countBy"));
43
+
42
44
  var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
43
45
 
46
+ var _ufo = require("@atlaskit/ufo");
47
+
44
48
  var _emitter = require("../emitter");
45
49
 
46
50
  var _channel = require("../channel");
@@ -55,6 +59,8 @@ var _catchup = require("./catchup");
55
59
 
56
60
  var _errorCodeMapper = require("../error-code-mapper");
57
61
 
62
+ var _types = require("../types");
63
+
58
64
  var _disconnectedReasonMapper = require("../disconnected-reason-mapper");
59
65
 
60
66
  var _performance = require("../analytics/performance");
@@ -91,17 +97,74 @@ var commitStep = function commitStep(_ref) {
91
97
  steps = _ref.steps,
92
98
  version = _ref.version,
93
99
  userId = _ref.userId,
94
- clientId = _ref.clientId;
100
+ clientId = _ref.clientId,
101
+ documentAri = _ref.documentAri,
102
+ analyticsClient = _ref.analyticsClient,
103
+ onStepsAdded = _ref.onStepsAdded,
104
+ onErrorHandled = _ref.onErrorHandled;
95
105
  var stepsWithClientAndUserId = steps.map(function (step) {
96
106
  return _objectSpread(_objectSpread({}, step.toJSON()), {}, {
97
107
  clientId: clientId,
98
108
  userId: userId
99
109
  });
100
110
  });
111
+ var start = new Date().getTime();
101
112
  channel.broadcast('steps:commit', {
102
113
  steps: stepsWithClientAndUserId,
103
114
  version: version,
104
115
  userId: userId
116
+ }, function (response) {
117
+ var latency = new Date().getTime() - start;
118
+
119
+ if (response.type === _types.AcknowledgementResponseTypes.SUCCESS) {
120
+ onStepsAdded({
121
+ steps: stepsWithClientAndUserId,
122
+ version: response.version
123
+ }, true);
124
+ var analyticStepEvent = {
125
+ eventAction: _const.EVENT_ACTION.ADD_STEPS,
126
+ attributes: {
127
+ eventStatus: _const.EVENT_STATUS.SUCCESS,
128
+ type: _const.ADD_STEPS_TYPE.ACCEPTED,
129
+ documentAri: documentAri,
130
+ latency: latency
131
+ }
132
+ };
133
+ analyticStepEvent.attributes.stepType = (0, _countBy.default)(stepsWithClientAndUserId, function (stepWithClientAndUserId) {
134
+ return stepWithClientAndUserId.stepType;
135
+ });
136
+ (0, _analytics.triggerAnalyticsEvent)(analyticStepEvent, analyticsClient);
137
+ } else if (response.type === _types.AcknowledgementResponseTypes.ERROR) {
138
+ var _response$error, _response$error$data, _response$error2, _response$error2$data;
139
+
140
+ onErrorHandled(response.error, true);
141
+ (0, _analytics.triggerAnalyticsEvent)({
142
+ eventAction: _const.EVENT_ACTION.ADD_STEPS,
143
+ attributes: {
144
+ eventStatus: _const.EVENT_STATUS.FAILURE,
145
+ // User tried committing steps but they were rejected because:
146
+ // - HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
147
+ // - VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
148
+ type: ((_response$error = response.error) === null || _response$error === void 0 ? void 0 : (_response$error$data = _response$error.data) === null || _response$error$data === void 0 ? void 0 : _response$error$data.code) === 'HEAD_VERSION_UPDATE_FAILED' || ((_response$error2 = response.error) === null || _response$error2 === void 0 ? void 0 : (_response$error2$data = _response$error2.data) === null || _response$error2$data === void 0 ? void 0 : _response$error2$data.code) === 'VERSION_NUMBER_ALREADY_EXISTS' ? _const.ADD_STEPS_TYPE.REJECTED : _const.ADD_STEPS_TYPE.ERROR,
149
+ documentAri: documentAri,
150
+ latency: latency,
151
+ error: response.error
152
+ }
153
+ }, analyticsClient);
154
+ } else {
155
+ (0, _analytics.triggerAnalyticsEvent)({
156
+ eventAction: _const.EVENT_ACTION.ADD_STEPS,
157
+ attributes: {
158
+ eventStatus: _const.EVENT_STATUS.FAILURE,
159
+ type: _const.ADD_STEPS_TYPE.ERROR,
160
+ documentAri: documentAri,
161
+ latency: latency,
162
+ error: {
163
+ message: 'Invalid Acknowledgement'
164
+ }
165
+ }
166
+ }, analyticsClient);
167
+ }
105
168
  });
106
169
  };
107
170
 
@@ -115,6 +178,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
115
178
 
116
179
  var _super = _createSuper(Provider);
117
180
 
181
+ // To keep track of the namespace event changes from the server.
118
182
  function Provider(config) {
119
183
  var _this;
120
184
 
@@ -124,6 +188,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
124
188
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "metadata", {});
125
189
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "stepRejectCounter", 0);
126
190
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isChannelInitialized", false);
191
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isNamespaceLocked", false);
127
192
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "initializeChannel", function () {
128
193
  _this.channel.on('connected', function (_ref2) {
129
194
  var sid = _ref2.sid,
@@ -152,9 +217,45 @@ var Provider = /*#__PURE__*/function (_Emitter) {
152
217
  version: version,
153
218
  metadata: metadata
154
219
  });
155
- }).on('steps:added', _this.onStepsAdded.bind((0, _assertThisInitialized2.default)(_this))).on('participant:telepointer', _this.onParticipantTelepointer.bind((0, _assertThisInitialized2.default)(_this))).on('presence:joined', _this.onPresenceJoined.bind((0, _assertThisInitialized2.default)(_this))).on('presence', _this.onPresence.bind((0, _assertThisInitialized2.default)(_this))).on('participant:left', _this.onParticipantLeft.bind((0, _assertThisInitialized2.default)(_this))).on('participant:updated', _this.onParticipantUpdated.bind((0, _assertThisInitialized2.default)(_this))).on('metadata:changed', _this.onMetadataChanged.bind((0, _assertThisInitialized2.default)(_this))).on('disconnect', _this.onDisconnected.bind((0, _assertThisInitialized2.default)(_this))).on('error', _this.onErrorHandled.bind((0, _assertThisInitialized2.default)(_this))).connect();
220
+ }).on('restore', _this.onRestore.bind((0, _assertThisInitialized2.default)(_this))).on('steps:added', _this.onStepsAdded.bind((0, _assertThisInitialized2.default)(_this))).on('participant:telepointer', _this.onParticipantTelepointer.bind((0, _assertThisInitialized2.default)(_this))).on('presence:joined', _this.onPresenceJoined.bind((0, _assertThisInitialized2.default)(_this))).on('presence', _this.onPresence.bind((0, _assertThisInitialized2.default)(_this))).on('participant:left', _this.onParticipantLeft.bind((0, _assertThisInitialized2.default)(_this))).on('participant:updated', _this.onParticipantUpdated.bind((0, _assertThisInitialized2.default)(_this))).on('metadata:changed', _this.onMetadataChanged.bind((0, _assertThisInitialized2.default)(_this))).on('disconnect', _this.onDisconnected.bind((0, _assertThisInitialized2.default)(_this))).on('error', _this.onErrorHandled.bind((0, _assertThisInitialized2.default)(_this))).on('status', _this.onNamespaceStatusChanged.bind((0, _assertThisInitialized2.default)(_this))).connect();
221
+ });
222
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onRestore", function (_ref4) {
223
+ var doc = _ref4.doc,
224
+ version = _ref4.version,
225
+ metadata = _ref4.metadata;
226
+
227
+ // Preserve the unconfirmed steps to prevent data loss.
228
+ var _ref5 = _this.getUnconfirmedSteps() || {
229
+ steps: []
230
+ },
231
+ unconfirmedSteps = _ref5.steps; // Reset the editor,
232
+ // - Replace the document, keep in sync with the server
233
+ // - Replace the version number, so editor is in sync with NCS server and can commit new changes.
234
+ // - Replace the metadata
235
+ // - Reserve the cursor position, in case a cursor jump.
236
+
237
+
238
+ _this.updateDocumentWithMetadata({
239
+ doc: doc,
240
+ version: version,
241
+ metadata: metadata,
242
+ reserveCursor: true
243
+ });
244
+
245
+ (0, _analytics.triggerAnalyticsEvent)({
246
+ eventAction: _const.EVENT_ACTION.REINITIALISE_DOCUMENT,
247
+ attributes: {
248
+ numUnconfirmedSteps: unconfirmedSteps.length,
249
+ documentAri: _this.config.documentAri
250
+ }
251
+ }, _this.analyticsClient); // Re-apply the unconfirmed steps, not 100% of them can be applied, if document is changed significantly.
252
+
253
+ if (unconfirmedSteps.length > 0) {
254
+ _this.applyLocalSteps(unconfirmedSteps);
255
+ }
156
256
  });
157
257
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onStepsAdded", function (data) {
258
+ var disableAnalytics = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
158
259
  logger("Received steps", {
159
260
  steps: data.steps,
160
261
  version: data.version
@@ -172,7 +273,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
172
273
  if (data.version === currentVersion) {
173
274
  logger("Received steps we already have. Ignoring.");
174
275
  } else if (data.version === expectedVersion) {
175
- _this.processSteps(data);
276
+ _this.processSteps(data, disableAnalytics);
176
277
  } else if (data.version > expectedVersion) {
177
278
  logger("Version too high. Expected \"".concat(expectedVersion, "\" but got \"").concat(data.version, ". Current local version is ").concat(currentVersion, "."));
178
279
 
@@ -181,8 +282,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
181
282
  _this.throttledCatchup();
182
283
  }
183
284
 
184
- _this.updateParticipants([], data.steps.map(function (_ref4) {
185
- var userId = _ref4.userId;
285
+ _this.updateParticipants([], data.steps.map(function (_ref6) {
286
+ var userId = _ref6.userId;
186
287
  return userId;
187
288
  }));
188
289
  });
@@ -192,14 +293,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
192
293
  leading: false,
193
294
  trailing: true
194
295
  }));
195
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "fitlerQueue", function (condition) {
296
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "filterQueue", function (condition) {
196
297
  _this.queue = _this.queue.filter(condition);
197
298
  });
198
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateDocumentWithMetadata", function (_ref5) {
199
- var doc = _ref5.doc,
200
- version = _ref5.version,
201
- metadata = _ref5.metadata,
202
- reserveCursor = _ref5.reserveCursor;
299
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateDocumentWithMetadata", function (_ref7) {
300
+ var doc = _ref7.doc,
301
+ version = _ref7.version,
302
+ metadata = _ref7.metadata,
303
+ reserveCursor = _ref7.reserveCursor;
203
304
 
204
305
  _this.emit('init', _objectSpread({
205
306
  doc: doc,
@@ -215,7 +316,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
215
316
  _this.emit('metadata:changed', metadata);
216
317
  }
217
318
  });
218
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "applyLocalsteps", function (steps) {
319
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "applyLocalSteps", function (steps) {
219
320
  // Re-aply local steps
220
321
  _this.emit('local-steps', {
221
322
  steps: steps
@@ -228,13 +329,13 @@ var Provider = /*#__PURE__*/function (_Emitter) {
228
329
  return (0, _prosemirrorCollab.sendableSteps)(_this.getState());
229
330
  });
230
331
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "catchup", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
231
- var measure, _measure;
332
+ var start, latency, _latency;
232
333
 
233
334
  return _regenerator.default.wrap(function _callee$(_context) {
234
335
  while (1) {
235
336
  switch (_context.prev = _context.next) {
236
337
  case 0:
237
- (0, _performance.startMeasure)(_performance.MEASURE_NAME.CALLING_CATCHUP_API); // if the queue is already paused, we are busy with something else, so don't proceed.
338
+ start = new Date().getTime(); // if the queue is already paused, we are busy with something else, so don't proceed.
238
339
 
239
340
  if (!_this.pauseQueue) {
240
341
  _context.next = 4;
@@ -252,18 +353,18 @@ var Provider = /*#__PURE__*/function (_Emitter) {
252
353
  getCurrentPmVersion: _this.getCurrentPmVersion,
253
354
  fetchCatchup: _this.channel.fetchCatchup.bind(_this.channel),
254
355
  getUnconfirmedSteps: _this.getUnconfirmedSteps,
255
- fitlerQueue: _this.fitlerQueue,
356
+ filterQueue: _this.filterQueue,
256
357
  updateDocumentWithMetadata: _this.updateDocumentWithMetadata,
257
- applyLocalsteps: _this.applyLocalsteps
358
+ applyLocalSteps: _this.applyLocalSteps
258
359
  });
259
360
 
260
361
  case 8:
261
- measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.CALLING_CATCHUP_API);
262
- (0, _analytics.triggerCollabAnalyticsEvent)({
362
+ latency = new Date().getTime() - start;
363
+ (0, _analytics.triggerAnalyticsEvent)({
263
364
  eventAction: _const.EVENT_ACTION.CATCHUP,
264
365
  attributes: {
265
366
  eventStatus: _const.EVENT_STATUS.SUCCESS,
266
- latency: measure === null || measure === void 0 ? void 0 : measure.duration,
367
+ latency: latency,
267
368
  documentAri: _this.config.documentAri
268
369
  }
269
370
  }, _this.analyticsClient);
@@ -273,13 +374,13 @@ var Provider = /*#__PURE__*/function (_Emitter) {
273
374
  case 12:
274
375
  _context.prev = 12;
275
376
  _context.t0 = _context["catch"](5);
276
- _measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.CALLING_CATCHUP_API);
277
- (0, _analytics.triggerCollabAnalyticsEvent)({
377
+ _latency = new Date().getTime() - start;
378
+ (0, _analytics.triggerAnalyticsEvent)({
278
379
  eventAction: _const.EVENT_ACTION.CATCHUP,
279
380
  attributes: {
280
381
  eventStatus: _const.EVENT_STATUS.FAILURE,
281
382
  error: _context.t0,
282
- latency: _measure === null || _measure === void 0 ? void 0 : _measure.duration,
383
+ latency: _latency,
283
384
  documentAri: _this.config.documentAri
284
385
  }
285
386
  }, _this.analyticsClient);
@@ -304,27 +405,34 @@ var Provider = /*#__PURE__*/function (_Emitter) {
304
405
  }, _callee, null, [[5, 12, 17, 23]]);
305
406
  })));
306
407
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onErrorHandled", function (error) {
307
- if (error && error.data) {
408
+ var disableAnalytics = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
409
+
410
+ if (error !== null && error !== void 0 && error.data) {
411
+ // User tried committing steps but they were rejected because:
412
+ // HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
413
+ // VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
308
414
  if (error.data.code === 'HEAD_VERSION_UPDATE_FAILED' || error.data.code === 'VERSION_NUMBER_ALREADY_EXISTS') {
309
- var measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.ADD_STEPS);
310
- (0, _analytics.triggerCollabAnalyticsEvent)({
311
- eventAction: _const.EVENT_ACTION.ADD_STEPS,
312
- attributes: {
313
- eventStatus: _const.EVENT_STATUS.FAILURE,
314
- error: error,
315
- documentAri: _this.config.documentAri,
316
- latency: measure === null || measure === void 0 ? void 0 : measure.duration
317
- }
318
- }, _this.analyticsClient);
319
- _this.stepRejectCounter++;
320
- }
415
+ // TODO: Remove this analytics logic once we have validated the ack messages and aren't likely to go back to a generic error handler
416
+ if (!disableAnalytics) {
417
+ (0, _analytics.triggerAnalyticsEvent)({
418
+ eventAction: _const.EVENT_ACTION.ADD_STEPS,
419
+ attributes: {
420
+ eventStatus: _const.EVENT_STATUS.FAILURE,
421
+ type: _const.ADD_STEPS_TYPE.REJECTED,
422
+ error: error,
423
+ documentAri: _this.config.documentAri
424
+ }
425
+ }, _this.analyticsClient);
426
+ }
321
427
 
322
- logger("The stepRejectCounter(\"".concat(_this.stepRejectCounter, "\")"));
428
+ _this.stepRejectCounter++;
429
+ logger("Steps rejected (tries=".concat(_this.stepRejectCounter, ")"));
323
430
 
324
- if (_this.stepRejectCounter >= MAX_STEP_REJECTED_ERROR) {
325
- logger("The stepRejected(\"".concat(_this.stepRejectCounter, "\") exceed maximun(\"").concat(MAX_STEP_REJECTED_ERROR, "\"), trigger catch"));
431
+ if (_this.stepRejectCounter >= MAX_STEP_REJECTED_ERROR) {
432
+ logger("The steps were rejected too many times (tries=".concat(_this.stepRejectCounter, ", limit=").concat(MAX_STEP_REJECTED_ERROR, "). Trying to catch-up."));
326
433
 
327
- _this.throttledCatchup();
434
+ _this.throttledCatchup();
435
+ }
328
436
  }
329
437
 
330
438
  var errorToEmit = (0, _errorCodeMapper.errorCodeMapper)(error);
@@ -334,7 +442,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
334
442
  }
335
443
  }
336
444
 
337
- logger("Error from collab service", error);
445
+ logger('Error from collab service', error);
338
446
  });
339
447
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "queue", []);
340
448
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "sendPresence", function () {
@@ -352,14 +460,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
352
460
  return _this.sendPresence();
353
461
  }, SEND_PRESENCE_INTERVAL);
354
462
  });
355
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresenceJoined", function (_ref7) {
356
- var sessionId = _ref7.sessionId;
463
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresenceJoined", function (_ref9) {
464
+ var sessionId = _ref9.sessionId;
357
465
  logger('Participant joined with session: ', sessionId); // This expose existing users to the newly joined user
358
466
 
359
467
  _this.sendPresence();
360
468
  });
361
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresence", function (_ref8) {
362
- var userId = _ref8.userId;
469
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresence", function (_ref10) {
470
+ var userId = _ref10.userId;
363
471
  logger('onPresence userId: ', userId);
364
472
  _this.userId = userId;
365
473
 
@@ -374,8 +482,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
374
482
  _this.emit('metadata:changed', metadata);
375
483
  }
376
484
  });
377
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantLeft", function (_ref9) {
378
- var sessionId = _ref9.sessionId;
485
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantLeft", function (_ref11) {
486
+ var sessionId = _ref11.sessionId;
379
487
  logger("Participant left");
380
488
 
381
489
  _this.participants.delete(sessionId);
@@ -386,11 +494,11 @@ var Provider = /*#__PURE__*/function (_Emitter) {
386
494
  }]
387
495
  });
388
496
  });
389
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantUpdated", function (_ref10) {
390
- var sessionId = _ref10.sessionId,
391
- timestamp = _ref10.timestamp,
392
- userId = _ref10.userId,
393
- clientId = _ref10.clientId;
497
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantUpdated", function (_ref12) {
498
+ var sessionId = _ref12.sessionId,
499
+ timestamp = _ref12.timestamp,
500
+ userId = _ref12.userId,
501
+ clientId = _ref12.clientId;
394
502
 
395
503
  _this.updateParticipant({
396
504
  sessionId: sessionId,
@@ -399,12 +507,12 @@ var Provider = /*#__PURE__*/function (_Emitter) {
399
507
  clientId: clientId
400
508
  });
401
509
  });
402
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantTelepointer", function (_ref11) {
403
- var sessionId = _ref11.sessionId,
404
- timestamp = _ref11.timestamp,
405
- selection = _ref11.selection,
406
- userId = _ref11.userId,
407
- clientId = _ref11.clientId;
510
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantTelepointer", function (_ref13) {
511
+ var sessionId = _ref13.sessionId,
512
+ timestamp = _ref13.timestamp,
513
+ selection = _ref13.selection,
514
+ userId = _ref13.userId,
515
+ clientId = _ref13.clientId;
408
516
 
409
517
  if (sessionId === _this.sessionId) {
410
518
  return;
@@ -432,14 +540,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
432
540
  });
433
541
  });
434
542
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateParticipant", /*#__PURE__*/function () {
435
- var _ref13 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref12) {
543
+ var _ref15 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref14) {
436
544
  var sessionId, timestamp, userId, clientId, getUser, _yield, _yield$name, name, _yield$email, email, _yield$avatar, avatar, isNewParticipant;
437
545
 
438
546
  return _regenerator.default.wrap(function _callee2$(_context2) {
439
547
  while (1) {
440
548
  switch (_context2.prev = _context2.next) {
441
549
  case 0:
442
- sessionId = _ref12.sessionId, timestamp = _ref12.timestamp, userId = _ref12.userId, clientId = _ref12.clientId;
550
+ sessionId = _ref14.sessionId, timestamp = _ref14.timestamp, userId = _ref14.userId, clientId = _ref14.clientId;
443
551
 
444
552
  if (userId) {
445
553
  _context2.next = 3;
@@ -492,7 +600,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
492
600
  }));
493
601
 
494
602
  return function (_x) {
495
- return _ref13.apply(this, arguments);
603
+ return _ref15.apply(this, arguments);
496
604
  };
497
605
  }());
498
606
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "updateParticipants", function () {
@@ -522,7 +630,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
522
630
  if (joined.length || left.length) {
523
631
  var _this$participants$si;
524
632
 
525
- (0, _analytics.triggerCollabAnalyticsEvent)({
633
+ (0, _analytics.triggerAnalyticsEvent)({
526
634
  eventAction: _const.EVENT_ACTION.UPDATE_PARTICIPANTS,
527
635
  attributes: {
528
636
  participants: (_this$participants$si = _this.participants.size) !== null && _this$participants$si !== void 0 ? _this$participants$si : 1,
@@ -562,8 +670,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
562
670
  return _disconnectedReasonMapper.DisconnectReason.UNKNOWN_DISCONNECT;
563
671
  }
564
672
  });
565
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onDisconnected", function (_ref14) {
566
- var reason = _ref14.reason;
673
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onDisconnected", function (_ref16) {
674
+ var reason = _ref16.reason;
567
675
  _this.disconnectedAt = Date.now();
568
676
  var left = Array.from(_this.participants.values());
569
677
 
@@ -583,7 +691,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
583
691
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getFinalAcknowledgedState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
584
692
  var _this$metadata$title;
585
693
 
586
- var maxAttemptsToSync, count, unconfirmedState, state, adfDocument, measure, _measure3;
694
+ var maxAttemptsToSync, count, unconfirmedState, state, adfDocument, measure, _measure2;
587
695
 
588
696
  return _regenerator.default.wrap(function _callee4$(_context4) {
589
697
  while (1) {
@@ -599,7 +707,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
599
707
  }
600
708
 
601
709
  return _context4.delegateYield( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
602
- var unconfirmedTrs, lastTr, isLastTrConfirmed, nextUnconfirmedState, nextUnconfirmedTrs, _state, _measure2, measure;
710
+ var unconfirmedTrs, lastTr, isLastTrConfirmed, nextUnconfirmedState, nextUnconfirmedTrs, _state, _measure, measure;
603
711
 
604
712
  return _regenerator.default.wrap(function _callee3$(_context3) {
605
713
  while (1) {
@@ -654,13 +762,15 @@ var Provider = /*#__PURE__*/function (_Emitter) {
654
762
  });
655
763
  }
656
764
 
657
- _measure2 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS);
658
- (0, _analytics.triggerCollabAnalyticsEvent)({
765
+ _measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS);
766
+ (0, _analytics.triggerAnalyticsEvent)({
659
767
  eventAction: _const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS,
660
768
  attributes: {
661
769
  eventStatus: _const.EVENT_STATUS.FAILURE,
662
- latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration,
663
- documentAri: _this.config.documentAri
770
+ latency: _measure === null || _measure === void 0 ? void 0 : _measure.duration,
771
+ documentAri: _this.config.documentAri,
772
+ // upon failure, emit the number of unconfirmed steps we attempted to sync
773
+ numUnconfirmedSteps: nextUnconfirmedState === null || nextUnconfirmedState === void 0 ? void 0 : nextUnconfirmedState.steps.length
664
774
  }
665
775
  }, _this.analyticsClient);
666
776
  throw new Error("Can't sync up with Collab Service");
@@ -671,12 +781,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
671
781
 
672
782
  case 17:
673
783
  measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS);
674
- (0, _analytics.triggerCollabAnalyticsEvent)({
784
+ (0, _analytics.triggerAnalyticsEvent)({
675
785
  eventAction: _const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS,
676
786
  attributes: {
677
787
  eventStatus: _const.EVENT_STATUS.SUCCESS,
678
788
  latency: measure === null || measure === void 0 ? void 0 : measure.duration,
679
- documentAri: _this.config.documentAri
789
+ documentAri: _this.config.documentAri,
790
+ // upon success, emit the total number of unconfirmed steps we synced
791
+ numUnconfirmedSteps: unconfirmedState.steps.length
680
792
  }
681
793
  }, _this.analyticsClient);
682
794
 
@@ -695,7 +807,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
695
807
  (0, _performance.startMeasure)(_performance.MEASURE_NAME.CONVERT_PM_TO_ADF);
696
808
  adfDocument = new _editorJsonTransformer.JSONTransformer().encode(state.doc);
697
809
  measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.CONVERT_PM_TO_ADF);
698
- (0, _analytics.triggerCollabAnalyticsEvent)({
810
+ (0, _analytics.triggerAnalyticsEvent)({
699
811
  eventAction: _const.EVENT_ACTION.CONVERT_PM_TO_ADF,
700
812
  attributes: {
701
813
  eventStatus: _const.EVENT_STATUS.SUCCESS,
@@ -704,12 +816,12 @@ var Provider = /*#__PURE__*/function (_Emitter) {
704
816
  }
705
817
  }, _this.analyticsClient);
706
818
  } catch (error) {
707
- _measure3 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.CONVERT_PM_TO_ADF);
708
- (0, _analytics.triggerCollabAnalyticsEvent)({
819
+ _measure2 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.CONVERT_PM_TO_ADF);
820
+ (0, _analytics.triggerAnalyticsEvent)({
709
821
  eventAction: _const.EVENT_ACTION.CONVERT_PM_TO_ADF,
710
822
  attributes: {
711
823
  eventStatus: _const.EVENT_STATUS.FAILURE,
712
- latency: _measure3 === null || _measure3 === void 0 ? void 0 : _measure3.duration,
824
+ latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration,
713
825
  error: error,
714
826
  documentAri: _this.config.documentAri
715
827
  }
@@ -730,6 +842,54 @@ var Provider = /*#__PURE__*/function (_Emitter) {
730
842
  }
731
843
  }, _callee4);
732
844
  })));
845
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onNamespaceStatusChanged", /*#__PURE__*/function () {
846
+ var _ref18 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(data) {
847
+ var isLocked, waitTimeInMs, timestamp, start;
848
+ return _regenerator.default.wrap(function _callee5$(_context5) {
849
+ while (1) {
850
+ switch (_context5.prev = _context5.next) {
851
+ case 0:
852
+ isLocked = data.isLocked, waitTimeInMs = data.waitTimeInMs, timestamp = data.timestamp;
853
+ start = Date.now();
854
+ logger("Received a namespace status changed event ", {
855
+ data: data
856
+ });
857
+
858
+ if (!(isLocked && waitTimeInMs)) {
859
+ _context5.next = 8;
860
+ break;
861
+ }
862
+
863
+ _this.isNamespaceLocked = true;
864
+ logger("Received a namespace status change event ", {
865
+ isLocked: isLocked
866
+ }); // To protect the collab editing process from locked out due to BE
867
+
868
+ setTimeout(function () {
869
+ logger("The namespace lock has expired", {
870
+ waitTime: Date.now() - start,
871
+ timestamp: timestamp
872
+ });
873
+ _this.isNamespaceLocked = false;
874
+ }, waitTimeInMs);
875
+ return _context5.abrupt("return");
876
+
877
+ case 8:
878
+ _this.isNamespaceLocked = false;
879
+ logger("The page lock has expired");
880
+
881
+ case 10:
882
+ case "end":
883
+ return _context5.stop();
884
+ }
885
+ }
886
+ }, _callee5);
887
+ }));
888
+
889
+ return function (_x2) {
890
+ return _ref18.apply(this, arguments);
891
+ };
892
+ }());
733
893
  _this.config = config;
734
894
  _this.channel = new _channel.Channel(config);
735
895
  _this.isChannelInitialized = false;
@@ -755,9 +915,9 @@ var Provider = /*#__PURE__*/function (_Emitter) {
755
915
  }
756
916
  }, {
757
917
  key: "setup",
758
- value: function setup(_ref16) {
759
- var getState = _ref16.getState,
760
- onSyncUpError = _ref16.onSyncUpError;
918
+ value: function setup(_ref19) {
919
+ var getState = _ref19.getState,
920
+ onSyncUpError = _ref19.onSyncUpError;
761
921
  this.getState = getState;
762
922
  this.onSyncUpError = onSyncUpError || noop;
763
923
  this.clientId = getState().plugins.find(function (p) {
@@ -804,27 +964,32 @@ var Provider = /*#__PURE__*/function (_Emitter) {
804
964
  return;
805
965
  }
806
966
 
967
+ if (this.isNamespaceLocked) {
968
+ logger('The document is temporary locked');
969
+ return;
970
+ }
971
+
807
972
  var steps = sendable.steps;
808
973
 
809
974
  if (!steps || !steps.length) {
810
975
  return;
811
- }
812
-
813
- (0, _performance.startMeasure)(_performance.MEASURE_NAME.ADD_STEPS); // Avoid reference issues using a
976
+ } // Avoid reference issues using a
814
977
  // method outside of the provider
815
978
  // scope
816
979
 
980
+
817
981
  throttledCommitStep({
818
982
  channel: this.channel,
819
983
  userId: this.userId,
820
984
  clientId: this.clientId,
821
985
  steps: steps,
822
- version: version
986
+ version: version,
987
+ documentAri: this.config.documentAri,
988
+ analyticsClient: this.analyticsClient,
989
+ onStepsAdded: this.onStepsAdded.bind(this),
990
+ onErrorHandled: this.onErrorHandled.bind(this)
823
991
  });
824
- }
825
- /**
826
- * Called when we receive steps from the service
827
- */
992
+ } // Triggered when page recovery has emitted an 'init' event on a page client is currently connected to.
828
993
 
829
994
  }, {
830
995
  key: "queueSteps",
@@ -863,13 +1028,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
863
1028
  value: function processSteps(data) {
864
1029
  var _this2 = this;
865
1030
 
1031
+ var disableAnalytics = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
866
1032
  var version = data.version,
867
1033
  steps = data.steps;
868
1034
  logger("Processing data. Version \"".concat(version, "\"."));
869
1035
 
870
- if (steps && steps.length) {
871
- var clientIds = steps.map(function (_ref17) {
872
- var clientId = _ref17.clientId;
1036
+ if (steps !== null && steps !== void 0 && steps.length) {
1037
+ var clientIds = steps.map(function (_ref20) {
1038
+ var clientId = _ref20.clientId;
873
1039
  return clientId;
874
1040
  });
875
1041
  this.emit('data', {
@@ -878,16 +1044,23 @@ var Provider = /*#__PURE__*/function (_Emitter) {
878
1044
  userIds: clientIds
879
1045
  }); // If steps can apply to local editor successfully, no need to accumulate the error counter.
880
1046
 
881
- this.stepRejectCounter = 0;
882
- var measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.ADD_STEPS);
883
- (0, _analytics.triggerCollabAnalyticsEvent)({
884
- eventAction: _const.EVENT_ACTION.ADD_STEPS,
885
- attributes: {
886
- eventStatus: _const.EVENT_STATUS.SUCCESS,
887
- documentAri: this.config.documentAri,
888
- latency: measure === null || measure === void 0 ? void 0 : measure.duration
889
- }
890
- }, this.analyticsClient);
1047
+ this.stepRejectCounter = 0; // TODO: Remove this analytics logic after we've validated the ack call-backs
1048
+
1049
+ if (!disableAnalytics && clientIds.indexOf(this.clientId) >= 0) {
1050
+ var analyticStepEvent = {
1051
+ eventAction: _const.EVENT_ACTION.ADD_STEPS,
1052
+ attributes: {
1053
+ eventStatus: _const.EVENT_STATUS.SUCCESS,
1054
+ type: _const.ADD_STEPS_TYPE.ACCEPTED,
1055
+ documentAri: this.config.documentAri
1056
+ }
1057
+ };
1058
+ analyticStepEvent.attributes.stepType = (0, _countBy.default)(steps, function (step) {
1059
+ return step.stepType;
1060
+ });
1061
+ (0, _analytics.triggerAnalyticsEvent)(analyticStepEvent, this.analyticsClient);
1062
+ }
1063
+
891
1064
  this.emitTelepointersFromSteps(steps); // Resend local steps if none of the received steps originated with us!
892
1065
 
893
1066
  if (clientIds.indexOf(this.clientId) === -1) {
@@ -916,12 +1089,39 @@ var Provider = /*#__PURE__*/function (_Emitter) {
916
1089
 
917
1090
  switch (type) {
918
1091
  case 'telepointer':
1092
+ var telepointerExperience = new _ufo.UFOExperience('collab-provider.telepointer', {
1093
+ type: _ufo.ExperienceTypes.Operation,
1094
+ performanceType: _ufo.ExperiencePerformanceTypes.Custom,
1095
+ performanceConfig: {
1096
+ histogram: (0, _defineProperty2.default)({}, _ufo.ExperiencePerformanceTypes.Custom, {
1097
+ duration: '250_500_1000_1500_2000_3000_4000'
1098
+ })
1099
+ }
1100
+ });
1101
+ telepointerExperience.addMetadata({
1102
+ documentAri: this.config.documentAri
1103
+ });
1104
+ telepointerExperience.start();
919
1105
  var selection = rest.selection;
920
1106
  this.channel.broadcast('participant:telepointer', {
921
1107
  selection: selection,
922
1108
  userId: userId,
923
1109
  sessionId: sessionId,
924
1110
  clientId: clientId
1111
+ }, function (response) {
1112
+ if (response.type === _types.AcknowledgementResponseTypes.SUCCESS) {
1113
+ telepointerExperience.success();
1114
+ } else if (response.type === _types.AcknowledgementResponseTypes.ERROR) {
1115
+ var errorMessage = response.error;
1116
+ telepointerExperience.addMetadata({
1117
+ error: errorMessage
1118
+ });
1119
+ logger('Error from collab service with telepointer broadcast', errorMessage);
1120
+ telepointerExperience.failure();
1121
+ } else {
1122
+ // Abort if invalid ACK sent
1123
+ telepointerExperience.abort();
1124
+ }
925
1125
  });
926
1126
  break;
927
1127
  }
@@ -939,14 +1139,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
939
1139
  participant = _Array$from$filter2[0];
940
1140
 
941
1141
  if (participant) {
942
- var _ref18 = step,
943
- stepType = _ref18.stepType,
944
- to = _ref18.to,
945
- from = _ref18.from,
946
- _ref18$slice = _ref18.slice,
947
- slice = _ref18$slice === void 0 ? {
1142
+ var _ref21 = step,
1143
+ stepType = _ref21.stepType,
1144
+ to = _ref21.to,
1145
+ from = _ref21.from,
1146
+ _ref21$slice = _ref21.slice,
1147
+ slice = _ref21$slice === void 0 ? {
948
1148
  content: []
949
- } : _ref18$slice;
1149
+ } : _ref21$slice;
950
1150
 
951
1151
  var _slice$content = (0, _slicedToArray2.default)(slice.content, 1),
952
1152
  node = _slice$content[0];
@@ -1018,6 +1218,10 @@ var Provider = /*#__PURE__*/function (_Emitter) {
1018
1218
  this.channel.disconnect();
1019
1219
  return this;
1020
1220
  }
1221
+ /**
1222
+ * ESS-2916 namespace status event- lock/unlock
1223
+ */
1224
+
1021
1225
  }]);
1022
1226
  return Provider;
1023
1227
  }(_emitter.Emitter);