@atlaskit/collab-provider 9.7.4 → 9.9.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 (35) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/channel.js +140 -34
  3. package/dist/cjs/document/document-service.js +57 -16
  4. package/dist/cjs/feature-flags/__test__/index.unit.js +3 -2
  5. package/dist/cjs/feature-flags/index.js +5 -3
  6. package/dist/cjs/provider/index.js +27 -4
  7. package/dist/cjs/version-wrapper.js +1 -1
  8. package/dist/cjs/version.json +1 -1
  9. package/dist/es2019/channel.js +40 -4
  10. package/dist/es2019/document/document-service.js +26 -4
  11. package/dist/es2019/feature-flags/__test__/index.unit.js +3 -2
  12. package/dist/es2019/feature-flags/index.js +5 -3
  13. package/dist/es2019/provider/index.js +25 -1
  14. package/dist/es2019/version-wrapper.js +1 -1
  15. package/dist/es2019/version.json +1 -1
  16. package/dist/esm/channel.js +140 -34
  17. package/dist/esm/document/document-service.js +57 -16
  18. package/dist/esm/feature-flags/__test__/index.unit.js +3 -2
  19. package/dist/esm/feature-flags/index.js +5 -3
  20. package/dist/esm/provider/index.js +27 -4
  21. package/dist/esm/version-wrapper.js +1 -1
  22. package/dist/esm/version.json +1 -1
  23. package/dist/types/channel.d.ts +2 -1
  24. package/dist/types/document/document-service.d.ts +8 -2
  25. package/dist/types/feature-flags/types.d.ts +1 -0
  26. package/dist/types/provider/index.d.ts +1 -0
  27. package/dist/types/types.d.ts +7 -0
  28. package/dist/types-ts4.5/channel.d.ts +2 -1
  29. package/dist/types-ts4.5/document/document-service.d.ts +8 -2
  30. package/dist/types-ts4.5/feature-flags/types.d.ts +1 -0
  31. package/dist/types-ts4.5/provider/index.d.ts +1 -0
  32. package/dist/types-ts4.5/types.d.ts +7 -0
  33. package/package.json +2 -2
  34. package/report.api.md +2 -0
  35. package/tmp/api-report-tmp.d.ts +2 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/collab-provider
2
2
 
3
+ ## 9.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`4c6ebd50aeb`](https://bitbucket.org/atlassian/atlassian-frontend/commits/4c6ebd50aeb) - call reconcile when commitUnconfirmedSteps fails (mitigation for 'can't sync up' errors)
8
+
9
+ ## 9.8.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`aceff84b101`](https://bitbucket.org/atlassian/atlassian-frontend/commits/aceff84b101) - initializing provider on setup if buffering is enabled
14
+
3
15
  ## 9.7.4
4
16
 
5
17
  ### Patch Changes
@@ -332,6 +332,112 @@ var Channel = /*#__PURE__*/function (_Emitter) {
332
332
  return _ref.apply(this, arguments);
333
333
  };
334
334
  }());
335
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "fetchReconcile", /*#__PURE__*/function () {
336
+ var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(currentStateDoc) {
337
+ var _ref4, _this$token2, reqBody, reconcileResponse, _this$analyticsHelper7;
338
+ return _regenerator.default.wrap(function _callee2$(_context2) {
339
+ while (1) switch (_context2.prev = _context2.next) {
340
+ case 0:
341
+ _context2.prev = 0;
342
+ reqBody = JSON.stringify({
343
+ doc: currentStateDoc,
344
+ productId: 'ccollab',
345
+ reason: 'UNKNOWN' // different reason here?
346
+ });
347
+ _context2.t0 = _utilServiceSupport.utils;
348
+ _context2.t1 = _this.config;
349
+ _context2.t2 = "document/".concat(encodeURIComponent(_this.config.documentAri), "/reconcile");
350
+ _context2.t3 = _objectSpread;
351
+ _context2.t4 = _objectSpread;
352
+ _context2.t5 = {};
353
+ if (!_this.config.permissionTokenRefresh) {
354
+ _context2.next = 29;
355
+ break;
356
+ }
357
+ if (!((_this$token2 = _this.token) !== null && _this$token2 !== void 0)) {
358
+ _context2.next = 13;
359
+ break;
360
+ }
361
+ _context2.t8 = _this$token2;
362
+ _context2.next = 16;
363
+ break;
364
+ case 13:
365
+ _context2.next = 15;
366
+ return _this.config.permissionTokenRefresh().then(function (token) {
367
+ if (token) {
368
+ _this.setToken(token);
369
+ }
370
+ return token;
371
+ });
372
+ case 15:
373
+ _context2.t8 = _context2.sent;
374
+ case 16:
375
+ _context2.t9 = _ref4 = _context2.t8;
376
+ _context2.t7 = _context2.t9 !== null;
377
+ if (!_context2.t7) {
378
+ _context2.next = 20;
379
+ break;
380
+ }
381
+ _context2.t7 = _ref4 !== void 0;
382
+ case 20:
383
+ if (!_context2.t7) {
384
+ _context2.next = 24;
385
+ break;
386
+ }
387
+ _context2.t10 = _ref4;
388
+ _context2.next = 25;
389
+ break;
390
+ case 24:
391
+ _context2.t10 = undefined;
392
+ case 25:
393
+ _context2.t11 = _context2.t10;
394
+ _context2.t6 = {
395
+ 'x-token': _context2.t11
396
+ };
397
+ _context2.next = 30;
398
+ break;
399
+ case 29:
400
+ _context2.t6 = {};
401
+ case 30:
402
+ _context2.t12 = _context2.t6;
403
+ _context2.t13 = (0, _context2.t4)(_context2.t5, _context2.t12);
404
+ _context2.t14 = {};
405
+ _context2.t15 = {
406
+ 'x-product': (0, _utils.getProduct)(_this.config.productInfo),
407
+ 'x-subproduct': (0, _utils.getSubProduct)(_this.config.productInfo),
408
+ 'Content-Type': 'application/json'
409
+ };
410
+ _context2.t16 = (0, _context2.t3)(_context2.t13, _context2.t14, _context2.t15);
411
+ _context2.t17 = reqBody;
412
+ _context2.t18 = {
413
+ headers: _context2.t16,
414
+ method: 'POST',
415
+ body: _context2.t17
416
+ };
417
+ _context2.t19 = {
418
+ path: _context2.t2,
419
+ requestInit: _context2.t18
420
+ };
421
+ _context2.next = 40;
422
+ return _context2.t0.requestService.call(_context2.t0, _context2.t1, _context2.t19);
423
+ case 40:
424
+ reconcileResponse = _context2.sent;
425
+ return _context2.abrupt("return", reconcileResponse);
426
+ case 44:
427
+ _context2.prev = 44;
428
+ _context2.t20 = _context2["catch"](0);
429
+ (_this$analyticsHelper7 = _this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(_context2.t20, 'Error while fetching reconciled document');
430
+ throw _context2.t20;
431
+ case 48:
432
+ case "end":
433
+ return _context2.stop();
434
+ }
435
+ }, _callee2, null, [[0, 44]]);
436
+ }));
437
+ return function (_x2) {
438
+ return _ref3.apply(this, arguments);
439
+ };
440
+ }());
335
441
  /**
336
442
  * Send message to the back-end service over the channel. Timestamp will be added server side.
337
443
  * @throws {NotInitializedError} Channel not initialized
@@ -416,10 +522,10 @@ var Channel = /*#__PURE__*/function (_Emitter) {
416
522
  var auth;
417
523
  if (permissionTokenRefresh) {
418
524
  auth = /*#__PURE__*/function () {
419
- var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(cb) {
525
+ var _ref5 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(cb) {
420
526
  var authData, token, _data, _data$meta, authenticationError;
421
- return _regenerator.default.wrap(function _callee2$(_context2) {
422
- while (1) switch (_context2.prev = _context2.next) {
527
+ return _regenerator.default.wrap(function _callee3$(_context3) {
528
+ while (1) switch (_context3.prev = _context3.next) {
423
529
  case 0:
424
530
  // Rebuild authData to ensure values are current
425
531
  authData = {
@@ -429,19 +535,19 @@ var Channel = /*#__PURE__*/function (_Emitter) {
429
535
  need404: _this2.config.need404
430
536
  }; // use the cached token if caching in enabled and token valid
431
537
  if (!(cacheToken && _this2.token)) {
432
- _context2.next = 6;
538
+ _context3.next = 6;
433
539
  break;
434
540
  }
435
541
  authData.token = _this2.token;
436
542
  cb(authData);
437
- _context2.next = 18;
543
+ _context3.next = 18;
438
544
  break;
439
545
  case 6:
440
- _context2.prev = 6;
441
- _context2.next = 9;
546
+ _context3.prev = 6;
547
+ _context3.next = 9;
442
548
  return permissionTokenRefresh();
443
549
  case 9:
444
- token = _context2.sent;
550
+ token = _context3.sent;
445
551
  if (token) {
446
552
  // save token locally
447
553
  _this2.setToken(token);
@@ -451,11 +557,11 @@ var Channel = /*#__PURE__*/function (_Emitter) {
451
557
  authData.token = undefined;
452
558
  }
453
559
  cb(authData);
454
- _context2.next = 18;
560
+ _context3.next = 18;
455
561
  break;
456
562
  case 14:
457
- _context2.prev = 14;
458
- _context2.t0 = _context2["catch"](6);
563
+ _context3.prev = 14;
564
+ _context3.t0 = _context3["catch"](6);
459
565
  // Pass the error back to the consumers so they can deal with exceptional cases themselves (eg. no permissions because the page was deleted)
460
566
  authenticationError = {
461
567
  message: 'Insufficient editing permissions',
@@ -463,8 +569,8 @@ var Channel = /*#__PURE__*/function (_Emitter) {
463
569
  status: 403,
464
570
  code: _errorTypes.INTERNAL_ERROR_CODE.TOKEN_PERMISSION_ERROR,
465
571
  meta: {
466
- originalError: _context2.t0,
467
- reason: _context2.t0 === null || _context2.t0 === void 0 ? void 0 : (_data = _context2.t0.data) === null || _data === void 0 ? void 0 : (_data$meta = _data.meta) === null || _data$meta === void 0 ? void 0 : _data$meta.reason // Should always be 'RESOURCE_DELETED' Temporary, until Confluence Cloud removes their hack
572
+ originalError: _context3.t0,
573
+ reason: _context3.t0 === null || _context3.t0 === void 0 ? void 0 : (_data = _context3.t0.data) === null || _data === void 0 ? void 0 : (_data$meta = _data.meta) === null || _data$meta === void 0 ? void 0 : _data$meta.reason // Should always be 'RESOURCE_DELETED' Temporary, until Confluence Cloud removes their hack
468
574
  // https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/browse/next/packages/native-collab/src/fetchCollabPermissionToken.ts#37
469
575
  }
470
576
  }
@@ -473,12 +579,12 @@ var Channel = /*#__PURE__*/function (_Emitter) {
473
579
  _this2.emit('error', authenticationError);
474
580
  case 18:
475
581
  case "end":
476
- return _context2.stop();
582
+ return _context3.stop();
477
583
  }
478
- }, _callee2, null, [[6, 14]]);
584
+ }, _callee3, null, [[6, 14]]);
479
585
  }));
480
- return function auth(_x2) {
481
- return _ref3.apply(this, arguments);
586
+ return function auth(_x3) {
587
+ return _ref5.apply(this, arguments);
482
588
  };
483
589
  }();
484
590
  } else {
@@ -502,9 +608,9 @@ var Channel = /*#__PURE__*/function (_Emitter) {
502
608
  this.socket.on('steps:added', function (data) {
503
609
  _this2.emit('steps:added', data);
504
610
  });
505
- this.socket.on('participant:telepointer', function (_ref4) {
506
- var timestamp = _ref4.timestamp,
507
- data = _ref4.data;
611
+ this.socket.on('participant:telepointer', function (_ref6) {
612
+ var timestamp = _ref6.timestamp,
613
+ data = _ref6.data;
508
614
  // data is TelepointerPayload without timestamp
509
615
  _this2.emit('participant:telepointer', _objectSpread({
510
616
  timestamp: timestamp
@@ -519,11 +625,11 @@ var Channel = /*#__PURE__*/function (_Emitter) {
519
625
  this.socket.on('participant:left', function (data) {
520
626
  _this2.emit('participant:left', data);
521
627
  });
522
- this.socket.on('participant:updated', function (_ref5) {
523
- var sessionId = _ref5.sessionId,
524
- timestamp = _ref5.timestamp,
525
- data = _ref5.data,
526
- clientId = _ref5.clientId;
628
+ this.socket.on('participant:updated', function (_ref7) {
629
+ var sessionId = _ref7.sessionId,
630
+ timestamp = _ref7.timestamp,
631
+ data = _ref7.data,
632
+ clientId = _ref7.clientId;
527
633
  _this2.emit('participant:updated', _objectSpread({
528
634
  sessionId: sessionId,
529
635
  timestamp: timestamp,
@@ -539,10 +645,10 @@ var Channel = /*#__PURE__*/function (_Emitter) {
539
645
  _this2.emit('status', data);
540
646
  });
541
647
  this.socket.on('disconnect', /*#__PURE__*/function () {
542
- var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(reason) {
648
+ var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(reason) {
543
649
  var _this2$analyticsHelpe, reconnectionError;
544
- return _regenerator.default.wrap(function _callee3$(_context3) {
545
- while (1) switch (_context3.prev = _context3.next) {
650
+ return _regenerator.default.wrap(function _callee4$(_context4) {
651
+ while (1) switch (_context4.prev = _context4.next) {
546
652
  case 0:
547
653
  if ((0, _featureFlags.getCollabProviderFeatureFlag)('socketMessageMetricsFF', _this2.config.featureFlags) && _this2.socketMessageMetrics) {
548
654
  _this2.socketMessageMetrics.closeSocketMessageMetrics();
@@ -570,12 +676,12 @@ var Channel = /*#__PURE__*/function (_Emitter) {
570
676
  }
571
677
  case 5:
572
678
  case "end":
573
- return _context3.stop();
679
+ return _context4.stop();
574
680
  }
575
- }, _callee3);
681
+ }, _callee4);
576
682
  }));
577
- return function (_x3) {
578
- return _ref6.apply(this, arguments);
683
+ return function (_x4) {
684
+ return _ref8.apply(this, arguments);
579
685
  };
580
686
  }());
581
687
 
@@ -665,8 +771,8 @@ var Channel = /*#__PURE__*/function (_Emitter) {
665
771
  this.emit('error', rateLimitError);
666
772
  throw new Error();
667
773
  } else if (rateLimitType === this.RATE_LIMIT_TYPE_SOFT) {
668
- var _this$analyticsHelper7;
669
- (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(rateLimitError, 'Rate limited');
774
+ var _this$analyticsHelper8;
775
+ (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(rateLimitError, 'Rate limited');
670
776
  }
671
777
  }
672
778
  }
@@ -20,6 +20,7 @@ var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
20
20
  var _provider = require("../provider");
21
21
  var _catchup = require("./catchup");
22
22
  var _stepQueueState = require("./step-queue-state");
23
+ var _featureFlags = require("../feature-flags");
23
24
  var _errorTypes = require("../errors/error-types");
24
25
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
25
26
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -36,6 +37,7 @@ var DocumentService = /*#__PURE__*/function () {
36
37
  * and to emit their telepointers from steps they add
37
38
  * @param analyticsHelper - Helper for analytics events
38
39
  * @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
40
+ * @param fetchReconcile - Function to call "reconcile" from NCS backend
39
41
  * @param providerEmitCallback - Callback for emitting events to listeners on the provider
40
42
  * @param broadcast - Callback for broadcasting events to other clients
41
43
  * @param getUserId - Callback to fetch the current user's ID
@@ -43,11 +45,13 @@ var DocumentService = /*#__PURE__*/function () {
43
45
  * @param metadataService
44
46
  * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
45
47
  * @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
48
+ * @param featureFlags - Feature flag config
46
49
  */
47
- function DocumentService(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
50
+ function DocumentService(participantsService, analyticsHelper, fetchCatchup, fetchReconcile, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
48
51
  var _this = this;
49
- var failedStepsBeforeCatchupOnPublish = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : _provider.MAX_STEP_REJECTED_ERROR;
50
- var enableErrorOnFailedDocumentApply = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false;
52
+ var failedStepsBeforeCatchupOnPublish = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : _provider.MAX_STEP_REJECTED_ERROR;
53
+ var enableErrorOnFailedDocumentApply = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : false;
54
+ var featureFlags = arguments.length > 11 ? arguments[11] : undefined;
51
55
  (0, _classCallCheck2.default)(this, DocumentService);
52
56
  // Fires analytics to editor when collab editor cannot sync up
53
57
  (0, _defineProperty2.default)(this, "stepRejectCounter", 0);
@@ -283,41 +287,76 @@ var DocumentService = /*#__PURE__*/function () {
283
287
  }
284
288
  });
285
289
  (0, _defineProperty2.default)(this, "getFinalAcknowledgedState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
286
- var _this$analyticsHelper14, currentState, measure, _this$analyticsHelper15, _this$analyticsHelper16, _measure2;
290
+ var _this$analyticsHelper14, finalAcknowledgedState, currentState, reconcileResponse, measure, _this$analyticsHelper15, _this$analyticsHelper16, _measure2;
287
291
  return _regenerator.default.wrap(function _callee3$(_context3) {
288
292
  while (1) switch (_context3.prev = _context3.next) {
289
293
  case 0:
290
294
  _this.aggressiveCatchup = true;
291
295
  _context3.prev = 1;
292
296
  (0, _performance.startMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
293
- _context3.next = 5;
294
- return _this.commitUnconfirmedSteps();
295
- case 5:
297
+ if (!(0, _featureFlags.getCollabProviderFeatureFlag)('enableFallbackToReconcile', _this.featureFlags)) {
298
+ _context3.next = 23;
299
+ break;
300
+ }
301
+ _context3.prev = 4;
296
302
  _context3.next = 7;
297
- return _this.getCurrentState();
303
+ return _this.commitUnconfirmedSteps();
298
304
  case 7:
305
+ _context3.next = 9;
306
+ return _this.getCurrentState();
307
+ case 9:
308
+ finalAcknowledgedState = _context3.sent;
309
+ _context3.next = 21;
310
+ break;
311
+ case 12:
312
+ _context3.prev = 12;
313
+ _context3.t0 = _context3["catch"](4);
314
+ _context3.next = 16;
315
+ return _this.getCurrentState();
316
+ case 16:
299
317
  currentState = _context3.sent;
318
+ _context3.next = 19;
319
+ return _this.fetchReconcile(JSON.stringify(currentState.content));
320
+ case 19:
321
+ reconcileResponse = _context3.sent;
322
+ finalAcknowledgedState = {
323
+ content: JSON.parse(reconcileResponse.document),
324
+ title: currentState.title,
325
+ stepVersion: reconcileResponse.version
326
+ };
327
+ case 21:
328
+ _context3.next = 28;
329
+ break;
330
+ case 23:
331
+ _context3.next = 25;
332
+ return _this.commitUnconfirmedSteps();
333
+ case 25:
334
+ _context3.next = 27;
335
+ return _this.getCurrentState();
336
+ case 27:
337
+ finalAcknowledgedState = _context3.sent;
338
+ case 28:
300
339
  measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
301
340
  (_this$analyticsHelper14 = _this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.SUCCESS, {
302
341
  latency: measure === null || measure === void 0 ? void 0 : measure.duration
303
342
  });
304
343
  _this.aggressiveCatchup = false;
305
- return _context3.abrupt("return", currentState);
306
- case 14:
307
- _context3.prev = 14;
308
- _context3.t0 = _context3["catch"](1);
344
+ return _context3.abrupt("return", finalAcknowledgedState);
345
+ case 34:
346
+ _context3.prev = 34;
347
+ _context3.t1 = _context3["catch"](1);
309
348
  _this.aggressiveCatchup = false;
310
349
  _measure2 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
311
350
  (_this$analyticsHelper15 = _this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.FAILURE, {
312
351
  latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
313
352
  });
314
- (_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');
315
- throw _context3.t0;
316
- case 21:
353
+ (_this$analyticsHelper16 = _this.analyticsHelper) === null || _this$analyticsHelper16 === void 0 ? void 0 : _this$analyticsHelper16.sendErrorEvent(_context3.t1, 'Error while returning ADF version of the final draft document');
354
+ throw _context3.t1;
355
+ case 41:
317
356
  case "end":
318
357
  return _context3.stop();
319
358
  }
320
- }, _callee3, null, [[1, 14]]);
359
+ }, _callee3, null, [[1, 34], [4, 12]]);
321
360
  })));
322
361
  (0, _defineProperty2.default)(this, "updateDocument", function (_ref6) {
323
362
  var doc = _ref6.doc,
@@ -495,6 +534,7 @@ var DocumentService = /*#__PURE__*/function () {
495
534
  this.participantsService = participantsService;
496
535
  this.analyticsHelper = analyticsHelper;
497
536
  this.fetchCatchup = fetchCatchup;
537
+ this.fetchReconcile = fetchReconcile;
498
538
  this.providerEmitCallback = providerEmitCallback;
499
539
  this.broadcast = broadcast;
500
540
  this.getUserId = getUserId;
@@ -502,6 +542,7 @@ var DocumentService = /*#__PURE__*/function () {
502
542
  this.metadataService = metadataService;
503
543
  this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
504
544
  this.enableErrorOnFailedDocumentApply = enableErrorOnFailedDocumentApply;
545
+ this.featureFlags = featureFlags;
505
546
  this.stepQueue = new _stepQueueState.StepQueueState();
506
547
  }
507
548
  (0, _createClass2.default)(DocumentService, [{
@@ -5,9 +5,10 @@ describe('Feature flags', function () {
5
5
  it('getProductSpecificFeatureFlags', function () {
6
6
  var result = (0, _index.getProductSpecificFeatureFlags)({
7
7
  testFF: true,
8
- socketMessageMetricsFF: true
8
+ socketMessageMetricsFF: true,
9
+ enableFallbackToReconcile: true
9
10
  }, 'confluence');
10
- expect(result).toEqual(['confluence.fe.collab.provider.testFF', 'confluence.fe.collab.provider.socketMessageMetricsFF']);
11
+ expect(result).toEqual(['confluence.frontend.collab.provider.testFF', 'confluence.frontend.collab.provider.socketMessageMetricsFF', 'confluence.frontend.collab.provider.enable-fallback-to-reconcile']);
11
12
  });
12
13
  it('getCollabProviderFeatureFlag return true', function () {
13
14
  var result = (0, _index.getCollabProviderFeatureFlag)('testFF', {
@@ -9,7 +9,8 @@ exports.getProductSpecificFeatureFlags = void 0;
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var defaultNCSFeatureFlags = {
11
11
  testFF: false,
12
- socketMessageMetricsFF: false
12
+ socketMessageMetricsFF: false,
13
+ enableFallbackToReconcile: false
13
14
  };
14
15
 
15
16
  /**
@@ -17,8 +18,9 @@ var defaultNCSFeatureFlags = {
17
18
  */
18
19
  var productKeys = {
19
20
  confluence: {
20
- testFF: 'confluence.fe.collab.provider.testFF',
21
- socketMessageMetricsFF: 'confluence.fe.collab.provider.socketMessageMetricsFF'
21
+ testFF: 'confluence.frontend.collab.provider.testFF',
22
+ socketMessageMetricsFF: 'confluence.frontend.collab.provider.socketMessageMetricsFF',
23
+ enableFallbackToReconcile: 'confluence.frontend.collab.provider.enable-fallback-to-reconcile'
22
24
  }
23
25
  };
24
26
  var filterFeatureFlagNames = function filterFeatureFlagNames(flags) {
@@ -43,6 +43,10 @@ var Provider = /*#__PURE__*/function (_Emitter) {
43
43
  _this = _super.call(this);
44
44
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isChannelInitialized", false);
45
45
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isProviderInitialized", false);
46
+ // isBufferingEnabled is a boolean value passed to the config during provider creation.
47
+ // It determines if the provider should initialize immediately and will only be true if:
48
+ // the feature flag is enabled and the initial draft fetched from NCS is also passed in the config.
49
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isBufferingEnabled", false);
46
50
  // isPreinitializating acts as a feature flag to determine when the provider has been initialized early
47
51
  // and also contains the initial draft
48
52
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isPreinitializing", false);
@@ -96,6 +100,13 @@ var Provider = /*#__PURE__*/function (_Emitter) {
96
100
  var sid = _ref2.sid,
97
101
  initialized = _ref2.initialized;
98
102
  _this.sessionId = sid;
103
+ // if buffering is enabled and the provider is initialized before connection, call catchup
104
+ // once setup resolves with the defined editor state
105
+ if (_this.isBufferingEnabled && _this.isProviderInitialized) {
106
+ _this.onSetupPromise.then(function () {
107
+ _this.documentService.sendStepsFromCurrentState();
108
+ });
109
+ }
99
110
  _this.emitCallback('connected', {
100
111
  sid: sid,
101
112
  initial: !initialized
@@ -271,13 +282,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
271
282
  _this.channel = new _channel.Channel(config, _this.analyticsHelper);
272
283
  _this.isChannelInitialized = false;
273
284
  _this.initialDraft = _this.config.initialDraft;
285
+ _this.isBufferingEnabled = Boolean(_this.config.isBufferingEnabled);
274
286
  _this.isProviderInitialized = false;
275
287
  _this.isPreinitializing = false;
276
288
  _this.participantsService = new _participantsService.ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined, _this.getPresenceData, _this.setUserId);
277
289
  _this.metadataService = new _metadataService.MetadataService(_this.emitCallback, _this.channel.sendMetadata);
278
- _this.documentService = new _documentService.DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
290
+ _this.documentService = new _documentService.DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.channel.fetchReconcile, _this.emitCallback, _this.channel.broadcast, function () {
279
291
  return _this.userId;
280
- }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish, _this.config.enableErrorOnFailedDocumentApply);
292
+ }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish, _this.config.enableErrorOnFailedDocumentApply, _this.config.featureFlags);
281
293
  _this.onSetupPromise = new Promise(function (resolve) {
282
294
  _this.resolveOnSetupPromise = resolve;
283
295
  });
@@ -341,6 +353,17 @@ var Provider = /*#__PURE__*/function (_Emitter) {
341
353
  // a defined getState (ie editor state is ready) AND after documentService sets the editor state
342
354
  if (this.isPreinitializing) {
343
355
  this.resolveOnSetupPromise();
356
+ if (this.isBufferingEnabled && this.initialDraft && !this.isProviderInitialized) {
357
+ var _this$initialDraft2 = this.initialDraft,
358
+ document = _this$initialDraft2.document,
359
+ version = _this$initialDraft2.version,
360
+ metadata = _this$initialDraft2.metadata;
361
+ this.updateDocumentAndMetadata({
362
+ doc: document,
363
+ version: version,
364
+ metadata: metadata
365
+ });
366
+ }
344
367
  }
345
368
  }
346
369
  if (!this.isChannelInitialized) {
@@ -374,8 +397,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
374
397
  }, {
375
398
  key: "isDraftTimestampStale",
376
399
  value: function isDraftTimestampStale() {
377
- var _this$initialDraft2;
378
- if (!((_this$initialDraft2 = this.initialDraft) !== null && _this$initialDraft2 !== void 0 && _this$initialDraft2.timestamp)) {
400
+ var _this$initialDraft3;
401
+ if (!((_this$initialDraft3 = this.initialDraft) !== null && _this$initialDraft3 !== void 0 && _this$initialDraft3.timestamp)) {
379
402
  return false;
380
403
  }
381
404
  return Date.now() - this.initialDraft.timestamp >= PRELOAD_DRAFT_SYNC_PERIOD;
@@ -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.7.4";
9
+ var version = "9.9.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.7.4",
3
+ "version": "9.9.0",
4
4
  "sideEffects": false
5
5
  }
@@ -228,6 +228,42 @@ export class Channel extends Emitter {
228
228
  throw error;
229
229
  }
230
230
  });
231
+ _defineProperty(this, "fetchReconcile", async currentStateDoc => {
232
+ try {
233
+ var _ref2, _this$token2;
234
+ const reqBody = JSON.stringify({
235
+ doc: currentStateDoc,
236
+ productId: 'ccollab',
237
+ reason: 'UNKNOWN' // different reason here?
238
+ });
239
+
240
+ const reconcileResponse = await utils.requestService(this.config, {
241
+ path: `document/${encodeURIComponent(this.config.documentAri)}/reconcile`,
242
+ requestInit: {
243
+ headers: {
244
+ ...(this.config.permissionTokenRefresh ? {
245
+ 'x-token': (_ref2 = (_this$token2 = this.token) !== null && _this$token2 !== void 0 ? _this$token2 : await this.config.permissionTokenRefresh().then(token => {
246
+ if (token) {
247
+ this.setToken(token);
248
+ }
249
+ return token;
250
+ })) !== null && _ref2 !== void 0 ? _ref2 : undefined
251
+ } : {}),
252
+ 'x-product': getProduct(this.config.productInfo),
253
+ 'x-subproduct': getSubProduct(this.config.productInfo),
254
+ 'Content-Type': 'application/json'
255
+ },
256
+ method: 'POST',
257
+ body: reqBody
258
+ }
259
+ });
260
+ return reconcileResponse;
261
+ } catch (error) {
262
+ var _this$analyticsHelper7;
263
+ (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(error, 'Error while fetching reconciled document');
264
+ throw error;
265
+ }
266
+ });
231
267
  /**
232
268
  * Send message to the back-end service over the channel. Timestamp will be added server side.
233
269
  * @throws {NotInitializedError} Channel not initialized
@@ -429,8 +465,8 @@ export class Channel extends Emitter {
429
465
  try {
430
466
  this.socket.connect();
431
467
  } catch (error) {
432
- var _this$analyticsHelper7;
433
- (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(error, 'Error while reconnecting the channel');
468
+ var _this$analyticsHelper8;
469
+ (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(error, 'Error while reconnecting the channel');
434
470
  const reconnectionError = {
435
471
  message: 'Caught error during reconnection',
436
472
  data: {
@@ -509,8 +545,8 @@ export class Channel extends Emitter {
509
545
  this.emit('error', rateLimitError);
510
546
  throw new Error();
511
547
  } else if (rateLimitType === this.RATE_LIMIT_TYPE_SOFT) {
512
- var _this$analyticsHelper8;
513
- (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(rateLimitError, 'Rate limited');
548
+ var _this$analyticsHelper9;
549
+ (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(rateLimitError, 'Rate limited');
514
550
  }
515
551
  }
516
552
  }