@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
@@ -18,7 +18,7 @@ const SEND_PRESENCE_INTERVAL = 150 * 1000; // 150 seconds
18
18
  * @param sendPresenceJoined Callback to Channel class
19
19
  */
20
20
  export class ParticipantsService {
21
- constructor(analyticsHelper, participantsState = new ParticipantsState(), emit, getUser, channelBroadcast, sendPresenceJoined) {
21
+ constructor(analyticsHelper, participantsState = new ParticipantsState(), emit, getUser, channelBroadcast, sendPresenceJoined, getPresenceData, setUserId) {
22
22
  /**
23
23
  * Carries out 3 things: 1) enriches the participant with user data, 2) updates the participantsState, 3) emits the presence event
24
24
  * @param payload Payload from incoming socket event
@@ -187,11 +187,12 @@ export class ParticipantsService {
187
187
  _defineProperty(this, "clearTimers", () => {
188
188
  clearTimeout(this.participantUpdateTimeout);
189
189
  });
190
- _defineProperty(this, "sendPresence", payload => {
190
+ _defineProperty(this, "sendPresence", () => {
191
191
  try {
192
192
  clearTimeout(this.presenceUpdateTimeout);
193
- this.channelBroadcast('participant:updated', payload);
194
- this.presenceUpdateTimeout = window.setTimeout(() => this.sendPresence(payload), SEND_PRESENCE_INTERVAL);
193
+ const data = this.getPresenceData();
194
+ this.channelBroadcast('participant:updated', data);
195
+ this.presenceUpdateTimeout = window.setTimeout(() => this.sendPresence(), SEND_PRESENCE_INTERVAL);
195
196
  } catch (error) {
196
197
  var _this$analyticsHelper7;
197
198
  // We don't want to throw errors for Presence features as they tend to self-restore
@@ -209,7 +210,7 @@ export class ParticipantsService {
209
210
  try {
210
211
  logger('Participant joined with session: ', payload.sessionId);
211
212
  // This expose existing users to the newly joined user
212
- this.sendPresence(payload);
213
+ this.sendPresence();
213
214
  } catch (error) {
214
215
  var _this$analyticsHelper8;
215
216
  // We don't want to throw errors for Presence features as they tend to self-restore
@@ -225,7 +226,8 @@ export class ParticipantsService {
225
226
  _defineProperty(this, "onPresence", payload => {
226
227
  try {
227
228
  logger('onPresence userId: ', payload.userId);
228
- this.sendPresence(payload);
229
+ this.setUserId(payload.userId);
230
+ this.sendPresence();
229
231
  this.sendPresenceJoined();
230
232
  } catch (error) {
231
233
  var _this$analyticsHelper9;
@@ -239,6 +241,8 @@ export class ParticipantsService {
239
241
  this.getUser = getUser;
240
242
  this.channelBroadcast = channelBroadcast;
241
243
  this.sendPresenceJoined = sendPresenceJoined;
244
+ this.getPresenceData = getPresenceData;
245
+ this.setUserId = setUserId;
242
246
  }
243
247
  /**
244
248
  * Called on receiving steps, emits each step's telepointer
@@ -13,7 +13,8 @@ export const commitStep = ({
13
13
  clientId,
14
14
  onStepsAdded,
15
15
  onErrorHandled,
16
- analyticsHelper
16
+ analyticsHelper,
17
+ emit
17
18
  }) => {
18
19
  const stepsWithClientAndUserId = steps.map(step => ({
19
20
  ...step.toJSON(),
@@ -21,6 +22,10 @@ export const commitStep = ({
21
22
  userId
22
23
  }));
23
24
  const start = new Date().getTime();
25
+ emit('commit-status', {
26
+ status: 'attempt',
27
+ version
28
+ });
24
29
  try {
25
30
  broadcast('steps:commit', {
26
31
  steps: stepsWithClientAndUserId,
@@ -38,6 +43,10 @@ export const commitStep = ({
38
43
  latency,
39
44
  stepType: countBy(stepsWithClientAndUserId, stepWithClientAndUserId => stepWithClientAndUserId.stepType)
40
45
  });
46
+ emit('commit-status', {
47
+ status: 'success',
48
+ version: response.version
49
+ });
41
50
  } else if (response.type === AcknowledgementResponseTypes.ERROR) {
42
51
  onErrorHandled(response.error);
43
52
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendActionEvent(EVENT_ACTION.ADD_STEPS, EVENT_STATUS.FAILURE, {
@@ -48,14 +57,26 @@ export const commitStep = ({
48
57
  latency
49
58
  });
50
59
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(response.error, 'Error while adding steps - Acknowledgement Error');
60
+ emit('commit-status', {
61
+ status: 'failure',
62
+ version
63
+ });
51
64
  } else {
52
65
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(
53
66
  // @ts-expect-error We didn't type the invalid type case
54
67
  new Error(`Response type: ${(response === null || response === void 0 ? void 0 : response.type) || 'No response type'}`), 'Error while adding steps - Invalid Acknowledgement');
68
+ emit('commit-status', {
69
+ status: 'failure',
70
+ version
71
+ });
55
72
  }
56
73
  });
57
74
  } catch (error) {
58
75
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while adding steps - Broadcast threw exception');
76
+ emit('commit-status', {
77
+ status: 'failure',
78
+ version
79
+ });
59
80
  }
60
81
  };
61
82
  export const throttledCommitStep = throttle(commitStep, SEND_STEPS_THROTTLE, {
@@ -91,6 +91,16 @@ export class Provider extends Emitter {
91
91
  this.isProviderInitialized = true;
92
92
  }).on('restore', this.documentService.onRestore).on('steps:added', this.documentService.onStepsAdded).on('metadata:changed', this.metadataService.onMetadataChanged).on('participant:telepointer', payload => this.participantsService.onParticipantTelepointer(payload, this.sessionId)).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(this)).on('error', this.onErrorHandled).on('status', this.namespaceService.onNamespaceStatusChanged).connect(shouldInitialize);
93
93
  });
94
+ _defineProperty(this, "setUserId", id => {
95
+ this.userId = id;
96
+ });
97
+ _defineProperty(this, "getPresenceData", () => {
98
+ return {
99
+ sessionId: this.sessionId,
100
+ userId: this.userId,
101
+ clientId: this.clientId
102
+ };
103
+ });
94
104
  /**
95
105
  * @param {InternalError} error The error to handle
96
106
  */
@@ -147,7 +157,7 @@ export class Provider extends Emitter {
147
157
  */
148
158
  _defineProperty(this, "getFinalAcknowledgedState", async () => {
149
159
  try {
150
- return this.documentService.getFinalAcknowledgedState();
160
+ return await this.documentService.getFinalAcknowledgedState();
151
161
  } catch (error) {
152
162
  var _this$analyticsHelper4;
153
163
  (_this$analyticsHelper4 = this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(error, 'Error while returning ADF version of the final draft document');
@@ -171,9 +181,9 @@ export class Provider extends Emitter {
171
181
  this.initialDraft = this.config.initialDraft;
172
182
  this.isProviderInitialized = false;
173
183
  this.isPreinitializing = false;
174
- this.participantsService = new ParticipantsService(this.analyticsHelper, undefined, this.emitCallback, this.config.getUser, this.channel.broadcast, this.channel.sendPresenceJoined);
184
+ this.participantsService = new ParticipantsService(this.analyticsHelper, undefined, this.emitCallback, this.config.getUser, this.channel.broadcast, this.channel.sendPresenceJoined, this.getPresenceData, this.setUserId);
175
185
  this.metadataService = new MetadataService(this.emitCallback, this.channel.sendMetadata);
176
- this.documentService = new DocumentService(this.participantsService, this.analyticsHelper, this.channel.fetchCatchup, this.emitCallback, this.channel.broadcast, () => this.userId, this.onErrorHandled, this.metadataService);
186
+ this.documentService = new DocumentService(this.participantsService, this.analyticsHelper, this.channel.fetchCatchup, this.emitCallback, this.channel.broadcast, () => this.userId, this.onErrorHandled, this.metadataService, this.config.failedStepLimitBeforeCatchupOnPublish);
177
187
  this.getStatePromise = new Promise(resolve => {
178
188
  this.getStatePromiseResolve = resolve;
179
189
  });
@@ -1,5 +1,5 @@
1
1
  export const name = "@atlaskit/collab-provider";
2
- export const version = "9.0.0";
2
+ export const version = "9.1.0";
3
3
  export const nextMajorVersion = () => {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -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
  }
@@ -343,6 +343,12 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
343
343
  }
344
344
  _this.socket.emit('metadata', metadata);
345
345
  });
346
+ _defineProperty(_assertThisInitialized(_this), "sendPresenceJoined", function () {
347
+ if (!_this.connected || !_this.socket) {
348
+ return;
349
+ }
350
+ _this.socket.emit('presence:joined');
351
+ });
346
352
  _defineProperty(_assertThisInitialized(_this), "onOnlineHandler", function () {
347
353
  // Force an immediate reconnect, the socket must first be closed to reset reconnection delay logic
348
354
  if (!_this.connected) {
@@ -559,14 +565,6 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
559
565
  // Fired upon a reconnection attempt error (from Socket.IO Manager)
560
566
  this.socket.io.on('reconnect_error', this.onReconnectError);
561
567
  }
562
- }, {
563
- key: "sendPresenceJoined",
564
- value: function sendPresenceJoined() {
565
- if (!this.connected || !this.socket) {
566
- return;
567
- }
568
- this.socket.emit('presence:joined');
569
- }
570
568
  }, {
571
569
  key: "disconnect",
572
570
  value: function disconnect() {
@@ -3,6 +3,7 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  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; } } }; }
4
4
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
5
5
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
6
+ import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
6
7
  import { createLogger } from '../helpers/utils';
7
8
  import { StepMap, Mapping } from 'prosemirror-transform';
8
9
  var logger = createLogger('Catchup', 'red');
@@ -34,7 +35,7 @@ export function rebaseSteps(steps, mapping) {
34
35
  }
35
36
  export var catchup = /*#__PURE__*/function () {
36
37
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(opt) {
37
- var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, unconfirmedSteps, _unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps;
38
+ var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, unconfirmedSteps, _unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps, _opt$analyticsHelper;
38
39
  return _regeneratorRuntime.wrap(function _callee$(_context) {
39
40
  while (1) switch (_context.prev = _context.next) {
40
41
  case 0:
@@ -112,6 +113,12 @@ export var catchup = /*#__PURE__*/function () {
112
113
  mapping = new Mapping(stepMaps);
113
114
  logger("".concat(_unconfirmedSteps.length, " unconfirmed steps before rebased: ").concat(JSON.stringify(_unconfirmedSteps)));
114
115
  newUnconfirmedSteps = rebaseSteps(_unconfirmedSteps, mapping);
116
+ if ((newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length) < _unconfirmedSteps.length) {
117
+ // Log the dropped steps after rebase
118
+ (_opt$analyticsHelper = opt.analyticsHelper) === null || _opt$analyticsHelper === void 0 ? void 0 : _opt$analyticsHelper.sendActionEvent(EVENT_ACTION.DROPPED_STEPS, EVENT_STATUS.SUCCESS, {
119
+ numOfDroppedSteps: _unconfirmedSteps.length - (newUnconfirmedSteps === null || newUnconfirmedSteps === void 0 ? void 0 : newUnconfirmedSteps.length)
120
+ });
121
+ }
115
122
  logger("Re-aply ".concat(newUnconfirmedSteps.length, " mapped unconfirmed steps: ").concat(JSON.stringify(newUnconfirmedSteps)));
116
123
  // Re-apply local steps
117
124
  opt.applyLocalSteps(newUnconfirmedSteps);
@@ -30,16 +30,19 @@ export var DocumentService = /*#__PURE__*/function () {
30
30
  * @param analyticsHelper - Helper for analytics events
31
31
  * @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
32
32
  * @param providerEmitCallback - Callback for emitting events to listeners on the provider
33
- * @param broadcastMetadata - Callback for broadcasting metadata changes to other clients
34
33
  * @param broadcast - Callback for broadcasting events to other clients
35
34
  * @param getUserId - Callback to fetch the current user's ID
36
35
  * @param onErrorHandled - Callback to handle
36
+ * @param metadataService
37
+ * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
37
38
  */
38
39
  function DocumentService(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
39
40
  var _this = this;
41
+ var failedStepsBeforeCatchupOnPublish = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : MAX_STEP_REJECTED_ERROR;
40
42
  _classCallCheck(this, DocumentService);
41
43
  // Fires analytics to editor when collab editor cannot sync up
42
44
  _defineProperty(this, "stepRejectCounter", 0);
45
+ _defineProperty(this, "aggressiveCatchup", false);
43
46
  /**
44
47
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
45
48
  */
@@ -78,7 +81,8 @@ export var DocumentService = /*#__PURE__*/function () {
78
81
  filterQueue: _this.stepQueue.filterQueue,
79
82
  applyLocalSteps: _this.applyLocalSteps,
80
83
  updateDocument: _this.updateDocument,
81
- updateMetadata: _this.metadataService.updateMetadata
84
+ updateMetadata: _this.metadataService.updateMetadata,
85
+ analyticsHelper: _this.analyticsHelper
82
86
  });
83
87
  case 8:
84
88
  latency = new Date().getTime() - start;
@@ -273,34 +277,37 @@ export var DocumentService = /*#__PURE__*/function () {
273
277
  return _regeneratorRuntime.wrap(function _callee3$(_context3) {
274
278
  while (1) switch (_context3.prev = _context3.next) {
275
279
  case 0:
276
- _context3.prev = 0;
280
+ _this.aggressiveCatchup = true;
281
+ _context3.prev = 1;
277
282
  startMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
278
- _context3.next = 4;
283
+ _context3.next = 5;
279
284
  return _this.commitUnconfirmedSteps();
280
- case 4:
281
- _context3.next = 6;
285
+ case 5:
286
+ _context3.next = 7;
282
287
  return _this.getCurrentState();
283
- case 6:
288
+ case 7:
284
289
  currentState = _context3.sent;
285
290
  measure = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
286
291
  (_this$analyticsHelper14 = _this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.SUCCESS, {
287
292
  latency: measure === null || measure === void 0 ? void 0 : measure.duration
288
293
  });
294
+ _this.aggressiveCatchup = false;
289
295
  return _context3.abrupt("return", currentState);
290
- case 12:
291
- _context3.prev = 12;
292
- _context3.t0 = _context3["catch"](0);
296
+ case 14:
297
+ _context3.prev = 14;
298
+ _context3.t0 = _context3["catch"](1);
299
+ _this.aggressiveCatchup = false;
293
300
  _measure2 = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
294
301
  (_this$analyticsHelper15 = _this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.FAILURE, {
295
302
  latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
296
303
  });
297
304
  (_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');
298
305
  throw _context3.t0;
299
- case 18:
306
+ case 21:
300
307
  case "end":
301
308
  return _context3.stop();
302
309
  }
303
- }, _callee3, null, [[0, 12]]);
310
+ }, _callee3, null, [[1, 14]]);
304
311
  })));
305
312
  _defineProperty(this, "updateDocument", function (_ref6) {
306
313
  var doc = _ref6.doc,
@@ -345,7 +352,7 @@ export var DocumentService = /*#__PURE__*/function () {
345
352
  }
346
353
  _this.sendStepsFromCurrentState();
347
354
  _context4.next = 12;
348
- return sleep(1000);
355
+ return sleep(500);
349
356
  case 12:
350
357
  nextUnconfirmedSteps = _this.getUnconfirmedSteps();
351
358
  if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
@@ -401,10 +408,17 @@ export var DocumentService = /*#__PURE__*/function () {
401
408
  }, _callee4, null, [[1, 23]]);
402
409
  })));
403
410
  _defineProperty(this, "onStepRejectedError", function () {
411
+ var _this$analyticsHelper20;
404
412
  _this.stepRejectCounter++;
405
413
  logger("Steps rejected (tries=".concat(_this.stepRejectCounter, ")"));
406
- if (_this.stepRejectCounter >= MAX_STEP_REJECTED_ERROR) {
414
+ (_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendActionEvent(EVENT_ACTION.SEND_STEPS_RETRY, EVENT_STATUS.INFO, {
415
+ count: _this.stepRejectCounter
416
+ });
417
+ var maxRetries = _this.aggressiveCatchup ? _this.failedStepsBeforeCatchupOnPublish : MAX_STEP_REJECTED_ERROR;
418
+ if (_this.stepRejectCounter >= maxRetries) {
419
+ var _this$analyticsHelper21;
407
420
  logger("The steps were rejected too many times (tries=".concat(_this.stepRejectCounter, ", limit=").concat(MAX_STEP_REJECTED_ERROR, "). Trying to catch-up."));
421
+ (_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);
408
422
  _this.throttledCatchup();
409
423
  } else {
410
424
  // If committing steps failed try again automatically in 1s
@@ -424,6 +438,7 @@ export var DocumentService = /*#__PURE__*/function () {
424
438
  this.getUserId = getUserId;
425
439
  this.onErrorHandled = onErrorHandled;
426
440
  this.metadataService = metadataService;
441
+ this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
427
442
  this.stepQueue = new StepQueueState();
428
443
  }
429
444
  _createClass(DocumentService, [{
@@ -475,9 +490,9 @@ export var DocumentService = /*#__PURE__*/function () {
475
490
  }, 100);
476
491
  }
477
492
  } catch (error) {
478
- var _this$analyticsHelper20;
493
+ var _this$analyticsHelper22;
479
494
  logger("Processing steps failed with error: ".concat(error, ". Triggering catch up call."));
480
- (_this$analyticsHelper20 = this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendErrorEvent(error, 'Error while processing steps');
495
+ (_this$analyticsHelper22 = this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendErrorEvent(error, 'Error while processing steps');
481
496
  this.throttledCatchup();
482
497
  }
483
498
  }
@@ -542,7 +557,8 @@ export var DocumentService = /*#__PURE__*/function () {
542
557
  version: version,
543
558
  onStepsAdded: this.onStepsAdded,
544
559
  onErrorHandled: this.onErrorHandled,
545
- analyticsHelper: this.analyticsHelper
560
+ analyticsHelper: this.analyticsHelper,
561
+ emit: this.providerEmitCallback
546
562
  });
547
563
  }
548
564
  }]);
@@ -10,11 +10,15 @@ export var 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 var 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 var ADD_STEPS_TYPE = /*#__PURE__*/function (ADD_STEPS_TYPE) {
@@ -23,5 +27,5 @@ export var 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 var ACK_MAX_TRY = 30;
30
+ export var ACK_MAX_TRY = 60;
27
31
  export var CONFLUENCE = 'confluence';
@@ -31,6 +31,8 @@ export var ParticipantsService = /*#__PURE__*/function () {
31
31
  var getUser = arguments.length > 3 ? arguments[3] : undefined;
32
32
  var channelBroadcast = arguments.length > 4 ? arguments[4] : undefined;
33
33
  var sendPresenceJoined = arguments.length > 5 ? arguments[5] : undefined;
34
+ var getPresenceData = arguments.length > 6 ? arguments[6] : undefined;
35
+ var setUserId = arguments.length > 7 ? arguments[7] : undefined;
34
36
  _classCallCheck(this, ParticipantsService);
35
37
  /**
36
38
  * Carries out 3 things: 1) enriches the participant with user data, 2) updates the participantsState, 3) emits the presence event
@@ -227,12 +229,13 @@ export var ParticipantsService = /*#__PURE__*/function () {
227
229
  _defineProperty(this, "clearTimers", function () {
228
230
  clearTimeout(_this.participantUpdateTimeout);
229
231
  });
230
- _defineProperty(this, "sendPresence", function (payload) {
232
+ _defineProperty(this, "sendPresence", function () {
231
233
  try {
232
234
  clearTimeout(_this.presenceUpdateTimeout);
233
- _this.channelBroadcast('participant:updated', payload);
235
+ var _data = _this.getPresenceData();
236
+ _this.channelBroadcast('participant:updated', _data);
234
237
  _this.presenceUpdateTimeout = window.setTimeout(function () {
235
- return _this.sendPresence(payload);
238
+ return _this.sendPresence();
236
239
  }, SEND_PRESENCE_INTERVAL);
237
240
  } catch (error) {
238
241
  var _this$analyticsHelper7;
@@ -251,7 +254,7 @@ export var ParticipantsService = /*#__PURE__*/function () {
251
254
  try {
252
255
  logger('Participant joined with session: ', payload.sessionId);
253
256
  // This expose existing users to the newly joined user
254
- _this.sendPresence(payload);
257
+ _this.sendPresence();
255
258
  } catch (error) {
256
259
  var _this$analyticsHelper8;
257
260
  // We don't want to throw errors for Presence features as they tend to self-restore
@@ -267,7 +270,8 @@ export var ParticipantsService = /*#__PURE__*/function () {
267
270
  _defineProperty(this, "onPresence", function (payload) {
268
271
  try {
269
272
  logger('onPresence userId: ', payload.userId);
270
- _this.sendPresence(payload);
273
+ _this.setUserId(payload.userId);
274
+ _this.sendPresence();
271
275
  _this.sendPresenceJoined();
272
276
  } catch (error) {
273
277
  var _this$analyticsHelper9;
@@ -281,6 +285,8 @@ export var ParticipantsService = /*#__PURE__*/function () {
281
285
  this.getUser = getUser;
282
286
  this.channelBroadcast = channelBroadcast;
283
287
  this.sendPresenceJoined = sendPresenceJoined;
288
+ this.getPresenceData = getPresenceData;
289
+ this.setUserId = setUserId;
284
290
  }
285
291
  _createClass(ParticipantsService, [{
286
292
  key: "emitTelepointersFromSteps",
@@ -16,7 +16,8 @@ export var commitStep = function commitStep(_ref) {
16
16
  clientId = _ref.clientId,
17
17
  onStepsAdded = _ref.onStepsAdded,
18
18
  onErrorHandled = _ref.onErrorHandled,
19
- analyticsHelper = _ref.analyticsHelper;
19
+ analyticsHelper = _ref.analyticsHelper,
20
+ emit = _ref.emit;
20
21
  var stepsWithClientAndUserId = steps.map(function (step) {
21
22
  return _objectSpread(_objectSpread({}, step.toJSON()), {}, {
22
23
  clientId: clientId,
@@ -24,6 +25,10 @@ export var commitStep = function commitStep(_ref) {
24
25
  });
25
26
  });
26
27
  var start = new Date().getTime();
28
+ emit('commit-status', {
29
+ status: 'attempt',
30
+ version: version
31
+ });
27
32
  try {
28
33
  broadcast('steps:commit', {
29
34
  steps: stepsWithClientAndUserId,
@@ -43,6 +48,10 @@ export var commitStep = function commitStep(_ref) {
43
48
  return stepWithClientAndUserId.stepType;
44
49
  })
45
50
  });
51
+ emit('commit-status', {
52
+ status: 'success',
53
+ version: response.version
54
+ });
46
55
  } else if (response.type === AcknowledgementResponseTypes.ERROR) {
47
56
  onErrorHandled(response.error);
48
57
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendActionEvent(EVENT_ACTION.ADD_STEPS, EVENT_STATUS.FAILURE, {
@@ -53,14 +62,26 @@ export var commitStep = function commitStep(_ref) {
53
62
  latency: latency
54
63
  });
55
64
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(response.error, 'Error while adding steps - Acknowledgement Error');
65
+ emit('commit-status', {
66
+ status: 'failure',
67
+ version: version
68
+ });
56
69
  } else {
57
70
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(
58
71
  // @ts-expect-error We didn't type the invalid type case
59
72
  new Error("Response type: ".concat((response === null || response === void 0 ? void 0 : response.type) || 'No response type')), 'Error while adding steps - Invalid Acknowledgement');
73
+ emit('commit-status', {
74
+ status: 'failure',
75
+ version: version
76
+ });
60
77
  }
61
78
  });
62
79
  } catch (error) {
63
80
  analyticsHelper === null || analyticsHelper === void 0 ? void 0 : analyticsHelper.sendErrorEvent(error, 'Error while adding steps - Broadcast threw exception');
81
+ emit('commit-status', {
82
+ status: 'failure',
83
+ version: version
84
+ });
64
85
  }
65
86
  };
66
87
  export var throttledCommitStep = throttle(commitStep, SEND_STEPS_THROTTLE, {
@@ -107,6 +107,16 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
107
107
  return _this.participantsService.onParticipantTelepointer(payload, _this.sessionId);
108
108
  }).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(_assertThisInitialized(_this))).on('error', _this.onErrorHandled).on('status', _this.namespaceService.onNamespaceStatusChanged).connect(shouldInitialize);
109
109
  });
110
+ _defineProperty(_assertThisInitialized(_this), "setUserId", function (id) {
111
+ _this.userId = id;
112
+ });
113
+ _defineProperty(_assertThisInitialized(_this), "getPresenceData", function () {
114
+ return {
115
+ sessionId: _this.sessionId,
116
+ userId: _this.userId,
117
+ clientId: _this.clientId
118
+ };
119
+ });
110
120
  /**
111
121
  * @param {InternalError} error The error to handle
112
122
  */
@@ -175,17 +185,20 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
175
185
  while (1) switch (_context2.prev = _context2.next) {
176
186
  case 0:
177
187
  _context2.prev = 0;
178
- return _context2.abrupt("return", _this.documentService.getFinalAcknowledgedState());
179
- case 4:
180
- _context2.prev = 4;
188
+ _context2.next = 3;
189
+ return _this.documentService.getFinalAcknowledgedState();
190
+ case 3:
191
+ return _context2.abrupt("return", _context2.sent);
192
+ case 6:
193
+ _context2.prev = 6;
181
194
  _context2.t0 = _context2["catch"](0);
182
195
  (_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');
183
196
  throw new GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context2.t0);
184
- case 8:
197
+ case 10:
185
198
  case "end":
186
199
  return _context2.stop();
187
200
  }
188
- }, _callee2, null, [[0, 4]]);
201
+ }, _callee2, null, [[0, 6]]);
189
202
  })));
190
203
  _defineProperty(_assertThisInitialized(_this), "getUnconfirmedSteps", function () {
191
204
  return _this.documentService.getUnconfirmedSteps();
@@ -204,11 +217,11 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
204
217
  _this.initialDraft = _this.config.initialDraft;
205
218
  _this.isProviderInitialized = false;
206
219
  _this.isPreinitializing = false;
207
- _this.participantsService = new ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined);
220
+ _this.participantsService = new ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined, _this.getPresenceData, _this.setUserId);
208
221
  _this.metadataService = new MetadataService(_this.emitCallback, _this.channel.sendMetadata);
209
222
  _this.documentService = new DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
210
223
  return _this.userId;
211
- }, _this.onErrorHandled, _this.metadataService);
224
+ }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish);
212
225
  _this.getStatePromise = new Promise(function (resolve) {
213
226
  _this.getStatePromiseResolve = resolve;
214
227
  });
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/collab-provider";
2
- export var version = "9.0.0";
2
+ export var version = "9.1.0";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -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
  }
@@ -41,7 +41,7 @@ export declare class Channel extends Emitter<ChannelEvent> {
41
41
  * @throws {NotConnectedError} Channel not connected
42
42
  */
43
43
  sendMetadata: (metadata: Metadata) => void;
44
- sendPresenceJoined(): void;
44
+ sendPresenceJoined: () => void;
45
45
  onOnlineHandler: () => void;
46
46
  disconnect(): void;
47
47
  }
@@ -16,10 +16,12 @@ export declare class DocumentService {
16
16
  private getUserId;
17
17
  private onErrorHandled;
18
18
  private metadataService;
19
+ private failedStepsBeforeCatchupOnPublish;
19
20
  private getState;
20
21
  private onSyncUpError?;
21
22
  private stepQueue;
22
23
  private stepRejectCounter;
24
+ private aggressiveCatchup;
23
25
  private clientId?;
24
26
  /**
25
27
  *
@@ -28,12 +30,13 @@ export declare class DocumentService {
28
30
  * @param analyticsHelper - Helper for analytics events
29
31
  * @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
30
32
  * @param providerEmitCallback - Callback for emitting events to listeners on the provider
31
- * @param broadcastMetadata - Callback for broadcasting metadata changes to other clients
32
33
  * @param broadcast - Callback for broadcasting events to other clients
33
34
  * @param getUserId - Callback to fetch the current user's ID
34
35
  * @param onErrorHandled - Callback to handle
36
+ * @param metadataService
37
+ * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
35
38
  */
36
- constructor(participantsService: ParticipantsService, analyticsHelper: AnalyticsHelper | undefined, fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>, providerEmitCallback: (evt: keyof CollabEvents, data: any) => void, broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void, getUserId: () => string | undefined, onErrorHandled: (error: InternalError) => void, metadataService: MetadataService);
39
+ constructor(participantsService: ParticipantsService, analyticsHelper: AnalyticsHelper | undefined, fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>, providerEmitCallback: (evt: keyof CollabEvents, data: any) => void, broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void, getUserId: () => string | undefined, onErrorHandled: (error: InternalError) => void, metadataService: MetadataService, failedStepsBeforeCatchupOnPublish?: number);
37
40
  /**
38
41
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
39
42
  */