@atlaskit/collab-provider 9.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/channel.js +6 -8
  3. package/dist/cjs/document/catchup.js +8 -1
  4. package/dist/cjs/document/document-service.js +33 -17
  5. package/dist/cjs/helpers/const.js +5 -1
  6. package/dist/cjs/participants/participants-service.js +11 -5
  7. package/dist/cjs/provider/commit-step.js +22 -1
  8. package/dist/cjs/provider/index.js +20 -7
  9. package/dist/cjs/version-wrapper.js +1 -1
  10. package/dist/cjs/version.json +1 -1
  11. package/dist/es2019/channel.js +6 -6
  12. package/dist/es2019/document/catchup.js +8 -0
  13. package/dist/es2019/document/document-service.js +23 -8
  14. package/dist/es2019/helpers/const.js +5 -1
  15. package/dist/es2019/participants/participants-service.js +10 -6
  16. package/dist/es2019/provider/commit-step.js +22 -1
  17. package/dist/es2019/provider/index.js +13 -3
  18. package/dist/es2019/version-wrapper.js +1 -1
  19. package/dist/es2019/version.json +1 -1
  20. package/dist/esm/channel.js +6 -8
  21. package/dist/esm/document/catchup.js +8 -1
  22. package/dist/esm/document/document-service.js +33 -17
  23. package/dist/esm/helpers/const.js +5 -1
  24. package/dist/esm/participants/participants-service.js +11 -5
  25. package/dist/esm/provider/commit-step.js +22 -1
  26. package/dist/esm/provider/index.js +20 -7
  27. package/dist/esm/version-wrapper.js +1 -1
  28. package/dist/esm/version.json +1 -1
  29. package/dist/types/channel.d.ts +1 -1
  30. package/dist/types/document/document-service.d.ts +5 -2
  31. package/dist/types/helpers/const.d.ts +30 -4
  32. package/dist/types/participants/participants-helper.d.ts +3 -1
  33. package/dist/types/participants/participants-service.d.ts +4 -2
  34. package/dist/types/provider/commit-step.d.ts +5 -3
  35. package/dist/types/provider/index.d.ts +2 -0
  36. package/dist/types/types.d.ts +15 -1
  37. package/dist/types-ts4.5/channel.d.ts +1 -1
  38. package/dist/types-ts4.5/document/document-service.d.ts +5 -2
  39. package/dist/types-ts4.5/helpers/const.d.ts +30 -4
  40. package/dist/types-ts4.5/participants/participants-helper.d.ts +3 -1
  41. package/dist/types-ts4.5/participants/participants-service.d.ts +4 -2
  42. package/dist/types-ts4.5/provider/commit-step.d.ts +5 -3
  43. package/dist/types-ts4.5/provider/index.d.ts +2 -0
  44. package/dist/types-ts4.5/types.d.ts +15 -1
  45. package/package.json +3 -3
  46. package/report.api.md +9 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/collab-provider
2
2
 
3
+ ## 9.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`2c0c19cc14b`](https://bitbucket.org/atlassian/atlassian-frontend/commits/2c0c19cc14b) - ESS-3609: add step commit status events for confl save indicator feature
8
+ - [`470c3a7e8c6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/470c3a7e8c6) - ESS-3644: allow max steps retry param to be passed thru collab provider to allow getFinalAcknowledgeState to catch up sooner on publish
9
+
10
+ ## 9.0.1
11
+
12
+ ### Patch Changes
13
+
14
+ - [`6fe0ddc993e`](https://bitbucket.org/atlassian/atlassian-frontend/commits/6fe0ddc993e) - ESS-3624 bug fix for missing avatar in editing sessions
15
+ - [`579326b4915`](https://bitbucket.org/atlassian/atlassian-frontend/commits/579326b4915) - ESS-2763 update get final editor state
16
+
3
17
  ## 9.0.0
4
18
 
5
19
  ### Major Changes
@@ -350,6 +350,12 @@ var Channel = /*#__PURE__*/function (_Emitter) {
350
350
  }
351
351
  _this.socket.emit('metadata', metadata);
352
352
  });
353
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "sendPresenceJoined", function () {
354
+ if (!_this.connected || !_this.socket) {
355
+ return;
356
+ }
357
+ _this.socket.emit('presence:joined');
358
+ });
353
359
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onOnlineHandler", function () {
354
360
  // Force an immediate reconnect, the socket must first be closed to reset reconnection delay logic
355
361
  if (!_this.connected) {
@@ -566,14 +572,6 @@ var Channel = /*#__PURE__*/function (_Emitter) {
566
572
  // Fired upon a reconnection attempt error (from Socket.IO Manager)
567
573
  this.socket.io.on('reconnect_error', this.onReconnectError);
568
574
  }
569
- }, {
570
- key: "sendPresenceJoined",
571
- value: function sendPresenceJoined() {
572
- if (!this.connected || !this.socket) {
573
- return;
574
- }
575
- this.socket.emit('presence:joined');
576
- }
577
575
  }, {
578
576
  key: "disconnect",
579
577
  value: function disconnect() {
@@ -8,6 +8,7 @@ exports.catchup = void 0;
8
8
  exports.rebaseSteps = rebaseSteps;
9
9
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
10
10
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
+ var _const = require("../helpers/const");
11
12
  var _utils = require("../helpers/utils");
12
13
  var _prosemirrorTransform = require("prosemirror-transform");
13
14
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
@@ -42,7 +43,7 @@ function rebaseSteps(steps, mapping) {
42
43
  }
43
44
  var catchup = /*#__PURE__*/function () {
44
45
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(opt) {
45
- var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, unconfirmedSteps, _unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps;
46
+ var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, unconfirmedSteps, _unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps, _opt$analyticsHelper;
46
47
  return _regenerator.default.wrap(function _callee$(_context) {
47
48
  while (1) switch (_context.prev = _context.next) {
48
49
  case 0:
@@ -120,6 +121,12 @@ var catchup = /*#__PURE__*/function () {
120
121
  mapping = new _prosemirrorTransform.Mapping(stepMaps);
121
122
  logger("".concat(_unconfirmedSteps.length, " unconfirmed steps before rebased: ").concat(JSON.stringify(_unconfirmedSteps)));
122
123
  newUnconfirmedSteps = rebaseSteps(_unconfirmedSteps, mapping);
124
+ if ((newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length) < _unconfirmedSteps.length) {
125
+ // Log the dropped steps after rebase
126
+ (_opt$analyticsHelper = opt.analyticsHelper) === null || _opt$analyticsHelper === void 0 ? void 0 : _opt$analyticsHelper.sendActionEvent(_const.EVENT_ACTION.DROPPED_STEPS, _const.EVENT_STATUS.SUCCESS, {
127
+ numOfDroppedSteps: _unconfirmedSteps.length - (newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length)
128
+ });
129
+ }
123
130
  logger("Re-aply ".concat(newUnconfirmedSteps.length, " mapped unconfirmed steps: ").concat(JSON.stringify(newUnconfirmedSteps)));
124
131
  // Re-apply local steps
125
132
  opt.applyLocalSteps(newUnconfirmedSteps);
@@ -37,16 +37,19 @@ var DocumentService = /*#__PURE__*/function () {
37
37
  * @param analyticsHelper - Helper for analytics events
38
38
  * @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
39
39
  * @param providerEmitCallback - Callback for emitting events to listeners on the provider
40
- * @param broadcastMetadata - Callback for broadcasting metadata changes to other clients
41
40
  * @param broadcast - Callback for broadcasting events to other clients
42
41
  * @param getUserId - Callback to fetch the current user's ID
43
42
  * @param onErrorHandled - Callback to handle
43
+ * @param metadataService
44
+ * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
44
45
  */
45
46
  function DocumentService(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
46
47
  var _this = this;
48
+ var failedStepsBeforeCatchupOnPublish = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : _provider.MAX_STEP_REJECTED_ERROR;
47
49
  (0, _classCallCheck2.default)(this, DocumentService);
48
50
  // Fires analytics to editor when collab editor cannot sync up
49
51
  (0, _defineProperty2.default)(this, "stepRejectCounter", 0);
52
+ (0, _defineProperty2.default)(this, "aggressiveCatchup", false);
50
53
  /**
51
54
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
52
55
  */
@@ -85,7 +88,8 @@ var DocumentService = /*#__PURE__*/function () {
85
88
  filterQueue: _this.stepQueue.filterQueue,
86
89
  applyLocalSteps: _this.applyLocalSteps,
87
90
  updateDocument: _this.updateDocument,
88
- updateMetadata: _this.metadataService.updateMetadata
91
+ updateMetadata: _this.metadataService.updateMetadata,
92
+ analyticsHelper: _this.analyticsHelper
89
93
  });
90
94
  case 8:
91
95
  latency = new Date().getTime() - start;
@@ -280,34 +284,37 @@ var DocumentService = /*#__PURE__*/function () {
280
284
  return _regenerator.default.wrap(function _callee3$(_context3) {
281
285
  while (1) switch (_context3.prev = _context3.next) {
282
286
  case 0:
283
- _context3.prev = 0;
287
+ _this.aggressiveCatchup = true;
288
+ _context3.prev = 1;
284
289
  (0, _performance.startMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
285
- _context3.next = 4;
290
+ _context3.next = 5;
286
291
  return _this.commitUnconfirmedSteps();
287
- case 4:
288
- _context3.next = 6;
292
+ case 5:
293
+ _context3.next = 7;
289
294
  return _this.getCurrentState();
290
- case 6:
295
+ case 7:
291
296
  currentState = _context3.sent;
292
297
  measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
293
298
  (_this$analyticsHelper14 = _this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.SUCCESS, {
294
299
  latency: measure === null || measure === void 0 ? void 0 : measure.duration
295
300
  });
301
+ _this.aggressiveCatchup = false;
296
302
  return _context3.abrupt("return", currentState);
297
- case 12:
298
- _context3.prev = 12;
299
- _context3.t0 = _context3["catch"](0);
303
+ case 14:
304
+ _context3.prev = 14;
305
+ _context3.t0 = _context3["catch"](1);
306
+ _this.aggressiveCatchup = false;
300
307
  _measure2 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
301
308
  (_this$analyticsHelper15 = _this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.FAILURE, {
302
309
  latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
303
310
  });
304
311
  (_this$analyticsHelper16 = _this.analyticsHelper) === null || _this$analyticsHelper16 === void 0 ? void 0 : _this$analyticsHelper16.sendErrorEvent(_context3.t0, 'Error while returning ADF version of the final draft document');
305
312
  throw _context3.t0;
306
- case 18:
313
+ case 21:
307
314
  case "end":
308
315
  return _context3.stop();
309
316
  }
310
- }, _callee3, null, [[0, 12]]);
317
+ }, _callee3, null, [[1, 14]]);
311
318
  })));
312
319
  (0, _defineProperty2.default)(this, "updateDocument", function (_ref6) {
313
320
  var doc = _ref6.doc,
@@ -352,7 +359,7 @@ var DocumentService = /*#__PURE__*/function () {
352
359
  }
353
360
  _this.sendStepsFromCurrentState();
354
361
  _context4.next = 12;
355
- return (0, _utils.sleep)(1000);
362
+ return (0, _utils.sleep)(500);
356
363
  case 12:
357
364
  nextUnconfirmedSteps = _this.getUnconfirmedSteps();
358
365
  if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
@@ -408,10 +415,17 @@ var DocumentService = /*#__PURE__*/function () {
408
415
  }, _callee4, null, [[1, 23]]);
409
416
  })));
410
417
  (0, _defineProperty2.default)(this, "onStepRejectedError", function () {
418
+ var _this$analyticsHelper20;
411
419
  _this.stepRejectCounter++;
412
420
  logger("Steps rejected (tries=".concat(_this.stepRejectCounter, ")"));
413
- if (_this.stepRejectCounter >= _provider.MAX_STEP_REJECTED_ERROR) {
421
+ (_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendActionEvent(_const.EVENT_ACTION.SEND_STEPS_RETRY, _const.EVENT_STATUS.INFO, {
422
+ count: _this.stepRejectCounter
423
+ });
424
+ var maxRetries = _this.aggressiveCatchup ? _this.failedStepsBeforeCatchupOnPublish : _provider.MAX_STEP_REJECTED_ERROR;
425
+ if (_this.stepRejectCounter >= maxRetries) {
426
+ var _this$analyticsHelper21;
414
427
  logger("The steps were rejected too many times (tries=".concat(_this.stepRejectCounter, ", limit=").concat(_provider.MAX_STEP_REJECTED_ERROR, "). Trying to catch-up."));
428
+ (_this$analyticsHelper21 = _this.analyticsHelper) === null || _this$analyticsHelper21 === void 0 ? void 0 : _this$analyticsHelper21.sendActionEvent(_const.EVENT_ACTION.CATCHUP_AFTER_MAX_SEND_STEPS_RETRY, _const.EVENT_STATUS.INFO);
415
429
  _this.throttledCatchup();
416
430
  } else {
417
431
  // If committing steps failed try again automatically in 1s
@@ -431,6 +445,7 @@ var DocumentService = /*#__PURE__*/function () {
431
445
  this.getUserId = getUserId;
432
446
  this.onErrorHandled = onErrorHandled;
433
447
  this.metadataService = metadataService;
448
+ this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
434
449
  this.stepQueue = new _stepQueueState.StepQueueState();
435
450
  }
436
451
  (0, _createClass2.default)(DocumentService, [{
@@ -482,9 +497,9 @@ var DocumentService = /*#__PURE__*/function () {
482
497
  }, 100);
483
498
  }
484
499
  } catch (error) {
485
- var _this$analyticsHelper20;
500
+ var _this$analyticsHelper22;
486
501
  logger("Processing steps failed with error: ".concat(error, ". Triggering catch up call."));
487
- (_this$analyticsHelper20 = this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendErrorEvent(error, 'Error while processing steps');
502
+ (_this$analyticsHelper22 = this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendErrorEvent(error, 'Error while processing steps');
488
503
  this.throttledCatchup();
489
504
  }
490
505
  }
@@ -549,7 +564,8 @@ var DocumentService = /*#__PURE__*/function () {
549
564
  version: version,
550
565
  onStepsAdded: this.onStepsAdded,
551
566
  onErrorHandled: this.onErrorHandled,
552
- analyticsHelper: this.analyticsHelper
567
+ analyticsHelper: this.analyticsHelper,
568
+ emit: this.providerEmitCallback
553
569
  });
554
570
  }
555
571
  }]);
@@ -16,12 +16,16 @@ var EVENT_ACTION = /*#__PURE__*/function (EVENT_ACTION) {
16
16
  EVENT_ACTION["PUBLISH_PAGE"] = "publishPage";
17
17
  EVENT_ACTION["GET_CURRENT_STATE"] = "getCurrentState";
18
18
  EVENT_ACTION["INVALIDATE_TOKEN"] = "invalidateToken";
19
+ EVENT_ACTION["SEND_STEPS_RETRY"] = "sendStepsRetry";
20
+ EVENT_ACTION["CATCHUP_AFTER_MAX_SEND_STEPS_RETRY"] = "catchupAfterMaxSendStepsRetry";
21
+ EVENT_ACTION["DROPPED_STEPS"] = "droppedStepInCatchup";
19
22
  return EVENT_ACTION;
20
23
  }({});
21
24
  exports.EVENT_ACTION = EVENT_ACTION;
22
25
  var EVENT_STATUS = /*#__PURE__*/function (EVENT_STATUS) {
23
26
  EVENT_STATUS["SUCCESS"] = "SUCCESS";
24
27
  EVENT_STATUS["FAILURE"] = "FAILURE";
28
+ EVENT_STATUS["INFO"] = "INFO";
25
29
  return EVENT_STATUS;
26
30
  }({});
27
31
  exports.EVENT_STATUS = EVENT_STATUS;
@@ -32,7 +36,7 @@ var ADD_STEPS_TYPE = /*#__PURE__*/function (ADD_STEPS_TYPE) {
32
36
  return ADD_STEPS_TYPE;
33
37
  }({});
34
38
  exports.ADD_STEPS_TYPE = ADD_STEPS_TYPE;
35
- var ACK_MAX_TRY = 30;
39
+ var ACK_MAX_TRY = 60;
36
40
  exports.ACK_MAX_TRY = ACK_MAX_TRY;
37
41
  var CONFLUENCE = 'confluence';
38
42
  exports.CONFLUENCE = CONFLUENCE;
@@ -38,6 +38,8 @@ var ParticipantsService = /*#__PURE__*/function () {
38
38
  var getUser = arguments.length > 3 ? arguments[3] : undefined;
39
39
  var channelBroadcast = arguments.length > 4 ? arguments[4] : undefined;
40
40
  var sendPresenceJoined = arguments.length > 5 ? arguments[5] : undefined;
41
+ var getPresenceData = arguments.length > 6 ? arguments[6] : undefined;
42
+ var setUserId = arguments.length > 7 ? arguments[7] : undefined;
41
43
  (0, _classCallCheck2.default)(this, ParticipantsService);
42
44
  /**
43
45
  * Carries out 3 things: 1) enriches the participant with user data, 2) updates the participantsState, 3) emits the presence event
@@ -234,12 +236,13 @@ var ParticipantsService = /*#__PURE__*/function () {
234
236
  (0, _defineProperty2.default)(this, "clearTimers", function () {
235
237
  clearTimeout(_this.participantUpdateTimeout);
236
238
  });
237
- (0, _defineProperty2.default)(this, "sendPresence", function (payload) {
239
+ (0, _defineProperty2.default)(this, "sendPresence", function () {
238
240
  try {
239
241
  clearTimeout(_this.presenceUpdateTimeout);
240
- _this.channelBroadcast('participant:updated', payload);
242
+ var _data = _this.getPresenceData();
243
+ _this.channelBroadcast('participant:updated', _data);
241
244
  _this.presenceUpdateTimeout = window.setTimeout(function () {
242
- return _this.sendPresence(payload);
245
+ return _this.sendPresence();
243
246
  }, SEND_PRESENCE_INTERVAL);
244
247
  } catch (error) {
245
248
  var _this$analyticsHelper7;
@@ -258,7 +261,7 @@ var ParticipantsService = /*#__PURE__*/function () {
258
261
  try {
259
262
  logger('Participant joined with session: ', payload.sessionId);
260
263
  // This expose existing users to the newly joined user
261
- _this.sendPresence(payload);
264
+ _this.sendPresence();
262
265
  } catch (error) {
263
266
  var _this$analyticsHelper8;
264
267
  // We don't want to throw errors for Presence features as they tend to self-restore
@@ -274,7 +277,8 @@ var ParticipantsService = /*#__PURE__*/function () {
274
277
  (0, _defineProperty2.default)(this, "onPresence", function (payload) {
275
278
  try {
276
279
  logger('onPresence userId: ', payload.userId);
277
- _this.sendPresence(payload);
280
+ _this.setUserId(payload.userId);
281
+ _this.sendPresence();
278
282
  _this.sendPresenceJoined();
279
283
  } catch (error) {
280
284
  var _this$analyticsHelper9;
@@ -288,6 +292,8 @@ var ParticipantsService = /*#__PURE__*/function () {
288
292
  this.getUser = getUser;
289
293
  this.channelBroadcast = channelBroadcast;
290
294
  this.sendPresenceJoined = sendPresenceJoined;
295
+ this.getPresenceData = getPresenceData;
296
+ this.setUserId = setUserId;
291
297
  }
292
298
  (0, _createClass2.default)(ParticipantsService, [{
293
299
  key: "emitTelepointersFromSteps",
@@ -23,7 +23,8 @@ var commitStep = function commitStep(_ref) {
23
23
  clientId = _ref.clientId,
24
24
  onStepsAdded = _ref.onStepsAdded,
25
25
  onErrorHandled = _ref.onErrorHandled,
26
- analyticsHelper = _ref.analyticsHelper;
26
+ analyticsHelper = _ref.analyticsHelper,
27
+ emit = _ref.emit;
27
28
  var stepsWithClientAndUserId = steps.map(function (step) {
28
29
  return _objectSpread(_objectSpread({}, step.toJSON()), {}, {
29
30
  clientId: clientId,
@@ -31,6 +32,10 @@ var commitStep = function commitStep(_ref) {
31
32
  });
32
33
  });
33
34
  var start = new Date().getTime();
35
+ emit('commit-status', {
36
+ status: 'attempt',
37
+ version: version
38
+ });
34
39
  try {
35
40
  broadcast('steps:commit', {
36
41
  steps: stepsWithClientAndUserId,
@@ -50,6 +55,10 @@ var commitStep = function commitStep(_ref) {
50
55
  return stepWithClientAndUserId.stepType;
51
56
  })
52
57
  });
58
+ emit('commit-status', {
59
+ status: 'success',
60
+ version: response.version
61
+ });
53
62
  } else if (response.type === _types.AcknowledgementResponseTypes.ERROR) {
54
63
  onErrorHandled(response.error);
55
64
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendActionEvent(_const.EVENT_ACTION.ADD_STEPS, _const.EVENT_STATUS.FAILURE, {
@@ -60,14 +69,26 @@ var commitStep = function commitStep(_ref) {
60
69
  latency: latency
61
70
  });
62
71
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(response.error, 'Error while adding steps - Acknowledgement Error');
72
+ emit('commit-status', {
73
+ status: 'failure',
74
+ version: version
75
+ });
63
76
  } else {
64
77
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(
65
78
  // @ts-expect-error We didn't type the invalid type case
66
79
  new Error("Response type: ".concat((response === null || response === void 0 ? void 0 : response.type) || 'No response type')), 'Error while adding steps - Invalid Acknowledgement');
80
+ emit('commit-status', {
81
+ status: 'failure',
82
+ version: version
83
+ });
67
84
  }
68
85
  });
69
86
  } catch (error) {
70
87
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while adding steps - Broadcast threw exception');
88
+ emit('commit-status', {
89
+ status: 'failure',
90
+ version: version
91
+ });
71
92
  }
72
93
  };
73
94
  exports.commitStep = commitStep;
@@ -115,6 +115,16 @@ var Provider = /*#__PURE__*/function (_Emitter) {
115
115
  return _this.participantsService.onParticipantTelepointer(payload, _this.sessionId);
116
116
  }).on('presence:joined', _this.participantsService.onPresenceJoined).on('presence', _this.participantsService.onPresence).on('participant:left', _this.participantsService.onParticipantLeft).on('participant:updated', _this.participantsService.onParticipantUpdated).on('disconnect', _this.onDisconnected.bind((0, _assertThisInitialized2.default)(_this))).on('error', _this.onErrorHandled).on('status', _this.namespaceService.onNamespaceStatusChanged).connect(shouldInitialize);
117
117
  });
118
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "setUserId", function (id) {
119
+ _this.userId = id;
120
+ });
121
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getPresenceData", function () {
122
+ return {
123
+ sessionId: _this.sessionId,
124
+ userId: _this.userId,
125
+ clientId: _this.clientId
126
+ };
127
+ });
118
128
  /**
119
129
  * @param {InternalError} error The error to handle
120
130
  */
@@ -183,17 +193,20 @@ var Provider = /*#__PURE__*/function (_Emitter) {
183
193
  while (1) switch (_context2.prev = _context2.next) {
184
194
  case 0:
185
195
  _context2.prev = 0;
186
- return _context2.abrupt("return", _this.documentService.getFinalAcknowledgedState());
187
- case 4:
188
- _context2.prev = 4;
196
+ _context2.next = 3;
197
+ return _this.documentService.getFinalAcknowledgedState();
198
+ case 3:
199
+ return _context2.abrupt("return", _context2.sent);
200
+ case 6:
201
+ _context2.prev = 6;
189
202
  _context2.t0 = _context2["catch"](0);
190
203
  (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(_context2.t0, 'Error while returning ADF version of the final draft document');
191
204
  throw new _errorTypes.GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context2.t0);
192
- case 8:
205
+ case 10:
193
206
  case "end":
194
207
  return _context2.stop();
195
208
  }
196
- }, _callee2, null, [[0, 4]]);
209
+ }, _callee2, null, [[0, 6]]);
197
210
  })));
198
211
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getUnconfirmedSteps", function () {
199
212
  return _this.documentService.getUnconfirmedSteps();
@@ -212,11 +225,11 @@ var Provider = /*#__PURE__*/function (_Emitter) {
212
225
  _this.initialDraft = _this.config.initialDraft;
213
226
  _this.isProviderInitialized = false;
214
227
  _this.isPreinitializing = false;
215
- _this.participantsService = new _participantsService.ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined);
228
+ _this.participantsService = new _participantsService.ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined, _this.getPresenceData, _this.setUserId);
216
229
  _this.metadataService = new _metadataService.MetadataService(_this.emitCallback, _this.channel.sendMetadata);
217
230
  _this.documentService = new _documentService.DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
218
231
  return _this.userId;
219
- }, _this.onErrorHandled, _this.metadataService);
232
+ }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish);
220
233
  _this.getStatePromise = new Promise(function (resolve) {
221
234
  _this.getStatePromiseResolve = resolve;
222
235
  });
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.version = exports.nextMajorVersion = exports.name = void 0;
7
7
  var name = "@atlaskit/collab-provider";
8
8
  exports.name = name;
9
- var version = "9.0.0";
9
+ var version = "9.1.0";
10
10
  exports.version = version;
11
11
  var nextMajorVersion = function nextMajorVersion() {
12
12
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "9.0.0",
3
+ "version": "9.1.0",
4
4
  "sideEffects": false
5
5
  }
@@ -250,6 +250,12 @@ export class Channel extends Emitter {
250
250
  }
251
251
  this.socket.emit('metadata', metadata);
252
252
  });
253
+ _defineProperty(this, "sendPresenceJoined", () => {
254
+ if (!this.connected || !this.socket) {
255
+ return;
256
+ }
257
+ this.socket.emit('presence:joined');
258
+ });
253
259
  _defineProperty(this, "onOnlineHandler", () => {
254
260
  // Force an immediate reconnect, the socket must first be closed to reset reconnection delay logic
255
261
  if (!this.connected) {
@@ -433,12 +439,6 @@ export class Channel extends Emitter {
433
439
  // Fired upon a reconnection attempt error (from Socket.IO Manager)
434
440
  this.socket.io.on('reconnect_error', this.onReconnectError);
435
441
  }
436
- sendPresenceJoined() {
437
- if (!this.connected || !this.socket) {
438
- return;
439
- }
440
- this.socket.emit('presence:joined');
441
- }
442
442
  disconnect() {
443
443
  var _this$network;
444
444
  this.unsubscribeAll();
@@ -1,3 +1,4 @@
1
+ import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
1
2
  import { createLogger } from '../helpers/utils';
2
3
  import { StepMap, Mapping } from 'prosemirror-transform';
3
4
  const logger = createLogger('Catchup', 'red');
@@ -93,6 +94,13 @@ export const catchup = async opt => {
93
94
  const mapping = new Mapping(stepMaps);
94
95
  logger(`${unconfirmedSteps.length} unconfirmed steps before rebased: ${JSON.stringify(unconfirmedSteps)}`);
95
96
  const newUnconfirmedSteps = rebaseSteps(unconfirmedSteps, mapping);
97
+ if ((newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length) < unconfirmedSteps.length) {
98
+ var _opt$analyticsHelper;
99
+ // Log the dropped steps after rebase
100
+ (_opt$analyticsHelper = opt.analyticsHelper) === null || _opt$analyticsHelper === void 0 ? void 0 : _opt$analyticsHelper.sendActionEvent(EVENT_ACTION.DROPPED_STEPS, EVENT_STATUS.SUCCESS, {
101
+ numOfDroppedSteps: unconfirmedSteps.length - (newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length)
102
+ });
103
+ }
96
104
  logger(`Re-aply ${newUnconfirmedSteps.length} mapped unconfirmed steps: ${JSON.stringify(newUnconfirmedSteps)}`);
97
105
  // Re-apply local steps
98
106
  opt.applyLocalSteps(newUnconfirmedSteps);
@@ -24,14 +24,16 @@ export class DocumentService {
24
24
  * @param analyticsHelper - Helper for analytics events
25
25
  * @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
26
26
  * @param providerEmitCallback - Callback for emitting events to listeners on the provider
27
- * @param broadcastMetadata - Callback for broadcasting metadata changes to other clients
28
27
  * @param broadcast - Callback for broadcasting events to other clients
29
28
  * @param getUserId - Callback to fetch the current user's ID
30
29
  * @param onErrorHandled - Callback to handle
30
+ * @param metadataService
31
+ * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
31
32
  */
32
- constructor(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
33
+ constructor(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService, failedStepsBeforeCatchupOnPublish = MAX_STEP_REJECTED_ERROR) {
33
34
  // Fires analytics to editor when collab editor cannot sync up
34
35
  _defineProperty(this, "stepRejectCounter", 0);
36
+ _defineProperty(this, "aggressiveCatchup", false);
35
37
  /**
36
38
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
37
39
  */
@@ -62,7 +64,8 @@ export class DocumentService {
62
64
  filterQueue: this.stepQueue.filterQueue,
63
65
  applyLocalSteps: this.applyLocalSteps,
64
66
  updateDocument: this.updateDocument,
65
- updateMetadata: this.metadataService.updateMetadata
67
+ updateMetadata: this.metadataService.updateMetadata,
68
+ analyticsHelper: this.analyticsHelper
66
69
  });
67
70
  const latency = new Date().getTime() - start;
68
71
  (_this$analyticsHelper = this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendActionEvent(EVENT_ACTION.CATCHUP, EVENT_STATUS.SUCCESS, {
@@ -235,6 +238,7 @@ export class DocumentService {
235
238
  }
236
239
  });
237
240
  _defineProperty(this, "getFinalAcknowledgedState", async () => {
241
+ this.aggressiveCatchup = true;
238
242
  try {
239
243
  var _this$analyticsHelper14;
240
244
  startMeasure(MEASURE_NAME.PUBLISH_PAGE, this.analyticsHelper);
@@ -244,9 +248,11 @@ export class DocumentService {
244
248
  (_this$analyticsHelper14 = this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.SUCCESS, {
245
249
  latency: measure === null || measure === void 0 ? void 0 : measure.duration
246
250
  });
251
+ this.aggressiveCatchup = false;
247
252
  return currentState;
248
253
  } catch (error) {
249
254
  var _this$analyticsHelper15, _this$analyticsHelper16;
255
+ this.aggressiveCatchup = false;
250
256
  const measure = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, this.analyticsHelper);
251
257
  (_this$analyticsHelper15 = this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.FAILURE, {
252
258
  latency: measure === null || measure === void 0 ? void 0 : measure.duration
@@ -290,7 +296,7 @@ export class DocumentService {
290
296
  let isLastTrConfirmed = false;
291
297
  while (!isLastTrConfirmed) {
292
298
  this.sendStepsFromCurrentState();
293
- await sleep(1000);
299
+ await sleep(500);
294
300
  const nextUnconfirmedSteps = this.getUnconfirmedSteps();
295
301
  if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
296
302
  const nextUnconfirmedTrs = this.getUnconfirmedStepsOrigins();
@@ -331,10 +337,17 @@ export class DocumentService {
331
337
  }
332
338
  });
333
339
  _defineProperty(this, "onStepRejectedError", () => {
340
+ var _this$analyticsHelper20;
334
341
  this.stepRejectCounter++;
335
342
  logger(`Steps rejected (tries=${this.stepRejectCounter})`);
336
- if (this.stepRejectCounter >= MAX_STEP_REJECTED_ERROR) {
343
+ (_this$analyticsHelper20 = this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendActionEvent(EVENT_ACTION.SEND_STEPS_RETRY, EVENT_STATUS.INFO, {
344
+ count: this.stepRejectCounter
345
+ });
346
+ let maxRetries = this.aggressiveCatchup ? this.failedStepsBeforeCatchupOnPublish : MAX_STEP_REJECTED_ERROR;
347
+ if (this.stepRejectCounter >= maxRetries) {
348
+ var _this$analyticsHelper21;
337
349
  logger(`The steps were rejected too many times (tries=${this.stepRejectCounter}, limit=${MAX_STEP_REJECTED_ERROR}). Trying to catch-up.`);
350
+ (_this$analyticsHelper21 = this.analyticsHelper) === null || _this$analyticsHelper21 === void 0 ? void 0 : _this$analyticsHelper21.sendActionEvent(EVENT_ACTION.CATCHUP_AFTER_MAX_SEND_STEPS_RETRY, EVENT_STATUS.INFO);
338
351
  this.throttledCatchup();
339
352
  } else {
340
353
  // If committing steps failed try again automatically in 1s
@@ -352,6 +365,7 @@ export class DocumentService {
352
365
  this.getUserId = getUserId;
353
366
  this.onErrorHandled = onErrorHandled;
354
367
  this.metadataService = metadataService;
368
+ this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
355
369
  this.stepQueue = new StepQueueState();
356
370
  }
357
371
  processQueue() {
@@ -397,9 +411,9 @@ export class DocumentService {
397
411
  setTimeout(() => this.sendStepsFromCurrentState(), 100);
398
412
  }
399
413
  } catch (error) {
400
- var _this$analyticsHelper20;
414
+ var _this$analyticsHelper22;
401
415
  logger(`Processing steps failed with error: ${error}. Triggering catch up call.`);
402
- (_this$analyticsHelper20 = this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendErrorEvent(error, 'Error while processing steps');
416
+ (_this$analyticsHelper22 = this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendErrorEvent(error, 'Error while processing steps');
403
417
  this.throttledCatchup();
404
418
  }
405
419
  }
@@ -458,7 +472,8 @@ export class DocumentService {
458
472
  version,
459
473
  onStepsAdded: this.onStepsAdded,
460
474
  onErrorHandled: this.onErrorHandled,
461
- analyticsHelper: this.analyticsHelper
475
+ analyticsHelper: this.analyticsHelper,
476
+ emit: this.providerEmitCallback
462
477
  });
463
478
  }
464
479
  }
@@ -10,11 +10,15 @@ export let EVENT_ACTION = /*#__PURE__*/function (EVENT_ACTION) {
10
10
  EVENT_ACTION["PUBLISH_PAGE"] = "publishPage";
11
11
  EVENT_ACTION["GET_CURRENT_STATE"] = "getCurrentState";
12
12
  EVENT_ACTION["INVALIDATE_TOKEN"] = "invalidateToken";
13
+ EVENT_ACTION["SEND_STEPS_RETRY"] = "sendStepsRetry";
14
+ EVENT_ACTION["CATCHUP_AFTER_MAX_SEND_STEPS_RETRY"] = "catchupAfterMaxSendStepsRetry";
15
+ EVENT_ACTION["DROPPED_STEPS"] = "droppedStepInCatchup";
13
16
  return EVENT_ACTION;
14
17
  }({});
15
18
  export let EVENT_STATUS = /*#__PURE__*/function (EVENT_STATUS) {
16
19
  EVENT_STATUS["SUCCESS"] = "SUCCESS";
17
20
  EVENT_STATUS["FAILURE"] = "FAILURE";
21
+ EVENT_STATUS["INFO"] = "INFO";
18
22
  return EVENT_STATUS;
19
23
  }({});
20
24
  export let ADD_STEPS_TYPE = /*#__PURE__*/function (ADD_STEPS_TYPE) {
@@ -23,5 +27,5 @@ export let ADD_STEPS_TYPE = /*#__PURE__*/function (ADD_STEPS_TYPE) {
23
27
  ADD_STEPS_TYPE["ERROR"] = "ERROR";
24
28
  return ADD_STEPS_TYPE;
25
29
  }({});
26
- export const ACK_MAX_TRY = 30;
30
+ export const ACK_MAX_TRY = 60;
27
31
  export const CONFLUENCE = 'confluence';