@atlaskit/collab-provider 10.9.2 → 10.9.4
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.
- package/CHANGELOG.md +19 -0
- package/dist/cjs/channel.js +1 -1
- package/dist/cjs/document/document-service.js +180 -156
- package/dist/cjs/document/getConflictChanges.js +177 -0
- package/dist/cjs/document/null-document-service.js +1 -1
- package/dist/cjs/errors/ncs-errors.js +1 -1
- package/dist/cjs/provider/commit-step.js +3 -4
- package/dist/cjs/provider/index.js +27 -22
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/channel.js +1 -1
- package/dist/es2019/document/document-service.js +27 -12
- package/dist/es2019/document/getConflictChanges.js +161 -0
- package/dist/es2019/document/null-document-service.js +1 -1
- package/dist/es2019/errors/ncs-errors.js +1 -1
- package/dist/es2019/provider/commit-step.js +3 -4
- package/dist/es2019/provider/index.js +3 -3
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/channel.js +1 -1
- package/dist/esm/document/document-service.js +180 -156
- package/dist/esm/document/getConflictChanges.js +170 -0
- package/dist/esm/document/null-document-service.js +1 -1
- package/dist/esm/errors/ncs-errors.js +1 -1
- package/dist/esm/provider/commit-step.js +3 -4
- package/dist/esm/provider/index.js +27 -22
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/document/document-service.d.ts +5 -4
- package/dist/types/document/getConflictChanges.d.ts +26 -0
- package/dist/types/document/interface-document-service.d.ts +3 -2
- package/dist/types/document/null-document-service.d.ts +2 -1
- package/dist/types/provider/commit-step.d.ts +4 -3
- package/dist/types/provider/index.d.ts +2 -1
- package/dist/types-ts4.5/document/document-service.d.ts +5 -4
- package/dist/types-ts4.5/document/getConflictChanges.d.ts +26 -0
- package/dist/types-ts4.5/document/interface-document-service.d.ts +3 -2
- package/dist/types-ts4.5/document/null-document-service.d.ts +2 -1
- package/dist/types-ts4.5/provider/commit-step.d.ts +4 -3
- package/dist/types-ts4.5/provider/index.d.ts +2 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @atlaskit/collab-provider
|
|
2
2
|
|
|
3
|
+
## 10.9.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#124114](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/124114)
|
|
8
|
+
[`a0b9383dc1bf3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a0b9383dc1bf3) -
|
|
9
|
+
CEPS-362: add reason to getResolvedEditorState call chain, to allow collab provider/NCS to
|
|
10
|
+
differentiate between draft sync and publish use cases
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 10.9.3
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [#122605](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/122605)
|
|
18
|
+
[`1bf1493f744ce`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1bf1493f744ce) -
|
|
19
|
+
[ux] Add conflict metadata on reconnection
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
|
|
3
22
|
## 10.9.2
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/dist/cjs/channel.js
CHANGED
|
@@ -203,7 +203,7 @@ var Channel = exports.Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
203
203
|
var measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.DOCUMENT_INIT, _this.analyticsHelper);
|
|
204
204
|
(_this$initExperience = _this.initExperience) === null || _this$initExperience === void 0 || _this$initExperience.success();
|
|
205
205
|
(_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 || _this$analyticsHelper6.sendActionEvent(_const.EVENT_ACTION.DOCUMENT_INIT,
|
|
206
|
-
// TODO: detect when document init fails and fire corresponding event for it
|
|
206
|
+
// TODO: ED-26957 - detect when document init fails and fire corresponding event for it
|
|
207
207
|
_const.EVENT_STATUS.SUCCESS, {
|
|
208
208
|
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
209
209
|
resetReason: data.resetReason,
|
|
@@ -12,6 +12,7 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
|
|
|
12
12
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
13
13
|
var _throttle = _interopRequireDefault(require("lodash/throttle"));
|
|
14
14
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
15
|
+
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
15
16
|
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
16
17
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
17
18
|
var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
|
|
@@ -24,6 +25,7 @@ var _commitStep = require("../provider/commit-step");
|
|
|
24
25
|
var _customErrors = require("../errors/custom-errors");
|
|
25
26
|
var _catchupv = require("./catchupv2");
|
|
26
27
|
var _stepQueueState = require("./step-queue-state");
|
|
28
|
+
var _getConflictChanges = require("./getConflictChanges");
|
|
27
29
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
28
30
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
29
31
|
var CATCHUP_THROTTLE = 1 * 1000; // 1 second
|
|
@@ -72,7 +74,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
72
74
|
return _this.catchupv2(reason, reconnectionMetadata);
|
|
73
75
|
}, CATCHUP_THROTTLE, {
|
|
74
76
|
leading: false,
|
|
75
|
-
// TODO: why shouldn't this be leading?
|
|
77
|
+
// TODO: ED-26957 - why shouldn't this be leading?
|
|
76
78
|
trailing: true
|
|
77
79
|
}));
|
|
78
80
|
/**
|
|
@@ -458,63 +460,68 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
458
460
|
return _ref7.apply(this, arguments);
|
|
459
461
|
};
|
|
460
462
|
}());
|
|
461
|
-
(0, _defineProperty2.default)(this, "getFinalAcknowledgedState", /*#__PURE__*/
|
|
462
|
-
var
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
463
|
+
(0, _defineProperty2.default)(this, "getFinalAcknowledgedState", /*#__PURE__*/function () {
|
|
464
|
+
var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(reason) {
|
|
465
|
+
var _this$analyticsHelper18, finalAcknowledgedState, currentState, reconcileResponse, measure, _this$analyticsHelper19, _this$analyticsHelper20, _measure2;
|
|
466
|
+
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
467
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
468
|
+
case 0:
|
|
469
|
+
_this.aggressiveCatchup = true;
|
|
470
|
+
_context4.prev = 1;
|
|
471
|
+
(0, _performance.startMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
472
|
+
_context4.prev = 3;
|
|
473
|
+
_context4.next = 6;
|
|
474
|
+
return _this.commitUnconfirmedSteps(reason);
|
|
475
|
+
case 6:
|
|
476
|
+
_context4.next = 8;
|
|
477
|
+
return _this.getCurrentState();
|
|
478
|
+
case 8:
|
|
479
|
+
finalAcknowledgedState = _context4.sent;
|
|
480
|
+
_context4.next = 20;
|
|
481
|
+
break;
|
|
482
|
+
case 11:
|
|
483
|
+
_context4.prev = 11;
|
|
484
|
+
_context4.t0 = _context4["catch"](3);
|
|
485
|
+
_context4.next = 15;
|
|
486
|
+
return _this.getCurrentState();
|
|
487
|
+
case 15:
|
|
488
|
+
currentState = _context4.sent;
|
|
489
|
+
_context4.next = 18;
|
|
490
|
+
return _this.fetchReconcile(JSON.stringify(currentState.content), 'fe-final-ack');
|
|
491
|
+
case 18:
|
|
492
|
+
reconcileResponse = _context4.sent;
|
|
493
|
+
finalAcknowledgedState = {
|
|
494
|
+
content: JSON.parse(reconcileResponse.document),
|
|
495
|
+
title: currentState.title,
|
|
496
|
+
stepVersion: reconcileResponse.version
|
|
497
|
+
};
|
|
498
|
+
case 20:
|
|
499
|
+
measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
500
|
+
(_this$analyticsHelper18 = _this.analyticsHelper) === null || _this$analyticsHelper18 === void 0 || _this$analyticsHelper18.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.SUCCESS, {
|
|
501
|
+
latency: measure === null || measure === void 0 ? void 0 : measure.duration
|
|
502
|
+
});
|
|
503
|
+
_this.aggressiveCatchup = false;
|
|
504
|
+
return _context4.abrupt("return", finalAcknowledgedState);
|
|
505
|
+
case 26:
|
|
506
|
+
_context4.prev = 26;
|
|
507
|
+
_context4.t1 = _context4["catch"](1);
|
|
508
|
+
_this.aggressiveCatchup = false;
|
|
509
|
+
_measure2 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
510
|
+
(_this$analyticsHelper19 = _this.analyticsHelper) === null || _this$analyticsHelper19 === void 0 || _this$analyticsHelper19.sendActionEvent(_const.EVENT_ACTION.PUBLISH_PAGE, _const.EVENT_STATUS.FAILURE, {
|
|
511
|
+
latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
|
|
512
|
+
});
|
|
513
|
+
(_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 || _this$analyticsHelper20.sendErrorEvent(_context4.t1, 'Error while returning ADF version of the final draft document');
|
|
514
|
+
throw _context4.t1;
|
|
515
|
+
case 33:
|
|
516
|
+
case "end":
|
|
517
|
+
return _context4.stop();
|
|
518
|
+
}
|
|
519
|
+
}, _callee4, null, [[1, 26], [3, 11]]);
|
|
520
|
+
}));
|
|
521
|
+
return function (_x4) {
|
|
522
|
+
return _ref8.apply(this, arguments);
|
|
523
|
+
};
|
|
524
|
+
}());
|
|
518
525
|
(0, _defineProperty2.default)(this, "updateDocument", function (_ref9) {
|
|
519
526
|
var doc = _ref9.doc,
|
|
520
527
|
version = _ref9.version,
|
|
@@ -605,100 +612,105 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
605
612
|
* Commit the unconfirmed local steps to the back-end service
|
|
606
613
|
* @throws {Error} Couldn't sync the steps after retrying 30 times
|
|
607
614
|
*/
|
|
608
|
-
(0, _defineProperty2.default)(this, "commitUnconfirmedSteps", /*#__PURE__*/
|
|
609
|
-
var
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
(_this$
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
615
|
+
(0, _defineProperty2.default)(this, "commitUnconfirmedSteps", /*#__PURE__*/function () {
|
|
616
|
+
var _ref10 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(reason) {
|
|
617
|
+
var unconfirmedSteps, _this$getState6, _this$analyticsHelper25, count, unconfirmedTrs, lastTr, isLastTrConfirmed, _this$analyticsHelper24, nextUnconfirmedSteps, nextUnconfirmedTrs, _this$getUnconfirmedS, state, version, unconfirmedStepsInfoUGCRemoved, error, measure, _this$analyticsHelper26, _this$analyticsHelper27, _measure3;
|
|
618
|
+
return _regenerator.default.wrap(function _callee5$(_context5) {
|
|
619
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
620
|
+
case 0:
|
|
621
|
+
unconfirmedSteps = _this.getUnconfirmedSteps();
|
|
622
|
+
_context5.prev = 1;
|
|
623
|
+
if (!(unconfirmedSteps !== null && unconfirmedSteps !== void 0 && unconfirmedSteps.length)) {
|
|
624
|
+
_context5.next = 24;
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
(0, _performance.startMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
|
|
628
|
+
count = 0; // We use origins here as steps can be rebased. When steps are rebased a new step is created.
|
|
629
|
+
// This means that we can not track if it has been removed from the unconfirmed array or not.
|
|
630
|
+
// Origins points to the original transaction that the step was created in. This is never changed
|
|
631
|
+
// and gets passed down when a step is rebased.
|
|
632
|
+
unconfirmedTrs = _this.getUnconfirmedStepsOrigins();
|
|
633
|
+
lastTr = unconfirmedTrs === null || unconfirmedTrs === void 0 ? void 0 : unconfirmedTrs[unconfirmedTrs.length - 1];
|
|
634
|
+
isLastTrConfirmed = false;
|
|
635
|
+
if (!((_this$getState6 = _this.getState) !== null && _this$getState6 !== void 0 && _this$getState6.call(_this))) {
|
|
636
|
+
(_this$analyticsHelper24 = _this.analyticsHelper) === null || _this$analyticsHelper24 === void 0 || _this$analyticsHelper24.sendErrorEvent(new Error('Editor state is undefined'), 'commitUnconfirmedSteps called without state');
|
|
637
|
+
}
|
|
638
|
+
case 9:
|
|
639
|
+
if (isLastTrConfirmed) {
|
|
640
|
+
_context5.next = 22;
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
// forcePublish = true, this is because commitUnconfirmedSteps is only called when the Editor publishes a document
|
|
644
|
+
_this.sendStepsFromCurrentState(undefined, reason);
|
|
645
|
+
_context5.next = 13;
|
|
646
|
+
return (0, _utils.sleep)(500);
|
|
647
|
+
case 13:
|
|
648
|
+
nextUnconfirmedSteps = _this.getUnconfirmedSteps();
|
|
649
|
+
if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
|
|
650
|
+
nextUnconfirmedTrs = _this.getUnconfirmedStepsOrigins();
|
|
651
|
+
isLastTrConfirmed = !(nextUnconfirmedTrs !== null && nextUnconfirmedTrs !== void 0 && nextUnconfirmedTrs.some(function (tr) {
|
|
652
|
+
return tr === lastTr;
|
|
653
|
+
}));
|
|
654
|
+
} else {
|
|
655
|
+
isLastTrConfirmed = true;
|
|
656
|
+
}
|
|
657
|
+
if (!(!isLastTrConfirmed && count++ >= _const.ACK_MAX_TRY)) {
|
|
658
|
+
_context5.next = 20;
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
if (_this.onSyncUpError) {
|
|
662
|
+
// Ignored via go/ees005
|
|
663
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
664
|
+
state = _this.getState();
|
|
665
|
+
version = _this.getVersionFromCollabState(state, 'collab-provider: commitUnconfirmedSteps');
|
|
666
|
+
_this.onSyncUpError({
|
|
667
|
+
lengthOfUnconfirmedSteps: nextUnconfirmedSteps === null || nextUnconfirmedSteps === void 0 ? void 0 : nextUnconfirmedSteps.length,
|
|
668
|
+
tries: count,
|
|
669
|
+
maxRetries: _const.ACK_MAX_TRY,
|
|
670
|
+
clientId: _this.clientId,
|
|
671
|
+
version: version
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
unconfirmedStepsInfoUGCRemoved = (_this$getUnconfirmedS = _this.getUnconfirmedSteps()) === null || _this$getUnconfirmedS === void 0 ? void 0 : _this$getUnconfirmedS.map(function (step) {
|
|
675
|
+
return (0, _utils.getStepUGCFreeDetails)(step);
|
|
676
|
+
});
|
|
677
|
+
error = new _customErrors.CantSyncUpError("Can't sync up with Collab Service: unable to send unconfirmed steps and max retry reached", {
|
|
678
|
+
unconfirmedStepsInfo: unconfirmedStepsInfoUGCRemoved ? JSON.stringify(unconfirmedStepsInfoUGCRemoved) : 'Unable to generate UGC removed step info'
|
|
679
|
+
});
|
|
680
|
+
throw error;
|
|
681
|
+
case 20:
|
|
682
|
+
_context5.next = 9;
|
|
633
683
|
break;
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
isLastTrConfirmed = !(nextUnconfirmedTrs !== null && nextUnconfirmedTrs !== void 0 && nextUnconfirmedTrs.some(function (tr) {
|
|
644
|
-
return tr === lastTr;
|
|
645
|
-
}));
|
|
646
|
-
} else {
|
|
647
|
-
isLastTrConfirmed = true;
|
|
648
|
-
}
|
|
649
|
-
if (!(!isLastTrConfirmed && count++ >= _const.ACK_MAX_TRY)) {
|
|
650
|
-
_context5.next = 20;
|
|
684
|
+
case 22:
|
|
685
|
+
measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
|
|
686
|
+
(_this$analyticsHelper25 = _this.analyticsHelper) === null || _this$analyticsHelper25 === void 0 || _this$analyticsHelper25.sendActionEvent(_const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, _const.EVENT_STATUS.SUCCESS, {
|
|
687
|
+
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
688
|
+
// upon success, emit the total number of unconfirmed steps we synced
|
|
689
|
+
numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
|
|
690
|
+
});
|
|
691
|
+
case 24:
|
|
692
|
+
_context5.next = 32;
|
|
651
693
|
break;
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
lengthOfUnconfirmedSteps: nextUnconfirmedSteps === null || nextUnconfirmedSteps === void 0 ? void 0 : nextUnconfirmedSteps.length,
|
|
660
|
-
tries: count,
|
|
661
|
-
maxRetries: _const.ACK_MAX_TRY,
|
|
662
|
-
clientId: _this.clientId,
|
|
663
|
-
version: version
|
|
694
|
+
case 26:
|
|
695
|
+
_context5.prev = 26;
|
|
696
|
+
_context5.t0 = _context5["catch"](1);
|
|
697
|
+
_measure3 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
|
|
698
|
+
(_this$analyticsHelper26 = _this.analyticsHelper) === null || _this$analyticsHelper26 === void 0 || _this$analyticsHelper26.sendActionEvent(_const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, _const.EVENT_STATUS.FAILURE, {
|
|
699
|
+
latency: _measure3 === null || _measure3 === void 0 ? void 0 : _measure3.duration,
|
|
700
|
+
numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
|
|
664
701
|
});
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
measure = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
|
|
678
|
-
(_this$analyticsHelper25 = _this.analyticsHelper) === null || _this$analyticsHelper25 === void 0 || _this$analyticsHelper25.sendActionEvent(_const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, _const.EVENT_STATUS.SUCCESS, {
|
|
679
|
-
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
680
|
-
// upon success, emit the total number of unconfirmed steps we synced
|
|
681
|
-
numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
|
|
682
|
-
});
|
|
683
|
-
case 24:
|
|
684
|
-
_context5.next = 32;
|
|
685
|
-
break;
|
|
686
|
-
case 26:
|
|
687
|
-
_context5.prev = 26;
|
|
688
|
-
_context5.t0 = _context5["catch"](1);
|
|
689
|
-
_measure3 = (0, _performance.stopMeasure)(_performance.MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
|
|
690
|
-
(_this$analyticsHelper26 = _this.analyticsHelper) === null || _this$analyticsHelper26 === void 0 || _this$analyticsHelper26.sendActionEvent(_const.EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, _const.EVENT_STATUS.FAILURE, {
|
|
691
|
-
latency: _measure3 === null || _measure3 === void 0 ? void 0 : _measure3.duration,
|
|
692
|
-
numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
|
|
693
|
-
});
|
|
694
|
-
(_this$analyticsHelper27 = _this.analyticsHelper) === null || _this$analyticsHelper27 === void 0 || _this$analyticsHelper27.sendErrorEvent(_context5.t0, 'Error while committing unconfirmed steps');
|
|
695
|
-
throw _context5.t0;
|
|
696
|
-
case 32:
|
|
697
|
-
case "end":
|
|
698
|
-
return _context5.stop();
|
|
699
|
-
}
|
|
700
|
-
}, _callee5, null, [[1, 26]]);
|
|
701
|
-
})));
|
|
702
|
+
(_this$analyticsHelper27 = _this.analyticsHelper) === null || _this$analyticsHelper27 === void 0 || _this$analyticsHelper27.sendErrorEvent(_context5.t0, 'Error while committing unconfirmed steps');
|
|
703
|
+
throw _context5.t0;
|
|
704
|
+
case 32:
|
|
705
|
+
case "end":
|
|
706
|
+
return _context5.stop();
|
|
707
|
+
}
|
|
708
|
+
}, _callee5, null, [[1, 26]]);
|
|
709
|
+
}));
|
|
710
|
+
return function (_x5) {
|
|
711
|
+
return _ref10.apply(this, arguments);
|
|
712
|
+
};
|
|
713
|
+
}());
|
|
702
714
|
(0, _defineProperty2.default)(this, "onStepRejectedError", function () {
|
|
703
715
|
var _this$analyticsHelper28;
|
|
704
716
|
_this.stepRejectCounter++;
|
|
@@ -772,10 +784,21 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
772
784
|
var state = (_this$getState7 = this.getState) === null || _this$getState7 === void 0 ? void 0 : _this$getState7.call(this);
|
|
773
785
|
var unconfirmedSteps = state ? (_getCollabState = (0, _prosemirrorCollab.getCollabState)(state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.unconfirmed : undefined;
|
|
774
786
|
if (steps.length > 0 && state && unconfirmedSteps && unconfirmedSteps.length > 0) {
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
787
|
+
var schema = state.schema,
|
|
788
|
+
tr = state.tr;
|
|
789
|
+
var remoteSteps = steps.map(function (s) {
|
|
790
|
+
return _transform.Step.fromJSON(schema, s);
|
|
778
791
|
});
|
|
792
|
+
var conflicts = (0, _getConflictChanges.getConflictChanges)({
|
|
793
|
+
localSteps: unconfirmedSteps,
|
|
794
|
+
remoteSteps: remoteSteps,
|
|
795
|
+
tr: tr
|
|
796
|
+
});
|
|
797
|
+
if (conflicts.deleted.length > 0 || conflicts.inserted.length > 0) {
|
|
798
|
+
this.providerEmitCallback('data:conflict', _objectSpread({
|
|
799
|
+
offlineDoc: state.doc
|
|
800
|
+
}, conflicts));
|
|
801
|
+
}
|
|
779
802
|
}
|
|
780
803
|
}
|
|
781
804
|
}, {
|
|
@@ -870,7 +893,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
870
893
|
*/
|
|
871
894
|
}, {
|
|
872
895
|
key: "sendStepsFromCurrentState",
|
|
873
|
-
value: function sendStepsFromCurrentState(sendAnalyticsEvent,
|
|
896
|
+
value: function sendStepsFromCurrentState(sendAnalyticsEvent, reason) {
|
|
874
897
|
var _this$getState8;
|
|
875
898
|
var state = (_this$getState8 = this.getState) === null || _this$getState8 === void 0 ? void 0 : _this$getState8.call(this);
|
|
876
899
|
if (!state) {
|
|
@@ -878,7 +901,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
878
901
|
(_this$analyticsHelper33 = this.analyticsHelper) === null || _this$analyticsHelper33 === void 0 || _this$analyticsHelper33.sendErrorEvent(new Error('Editor state is undefined'), 'sendStepsFromCurrentState called without state');
|
|
879
902
|
return;
|
|
880
903
|
}
|
|
881
|
-
this.send(null, null, state, sendAnalyticsEvent,
|
|
904
|
+
this.send(null, null, state, sendAnalyticsEvent, reason);
|
|
882
905
|
}
|
|
883
906
|
}, {
|
|
884
907
|
key: "send",
|
|
@@ -887,7 +910,8 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
887
910
|
* Send steps from transaction to other participants
|
|
888
911
|
* It needs the superfluous arguments because we keep the interface of the send API the same as the Synchrony plugin
|
|
889
912
|
*/
|
|
890
|
-
function send(tr, _oldState, newState, sendAnalyticsEvent,
|
|
913
|
+
function send(tr, _oldState, newState, sendAnalyticsEvent, reason // only used for publish and draft-sync events - when called through getFinalAcknowledgedState
|
|
914
|
+
) {
|
|
891
915
|
var unconfirmedStepsData = (0, _prosemirrorCollab.sendableSteps)(newState);
|
|
892
916
|
var version = this.getVersionFromCollabState(newState, 'collab-provider: send');
|
|
893
917
|
|
|
@@ -970,7 +994,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
|
|
|
970
994
|
__livePage: this.options.__livePage,
|
|
971
995
|
hasRecovered: this.hasRecovered,
|
|
972
996
|
collabMode: this.participantsService.getCollabMode(),
|
|
973
|
-
|
|
997
|
+
reason: reason
|
|
974
998
|
});
|
|
975
999
|
}
|
|
976
1000
|
}]);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.getConflictChanges = getConflictChanges;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _prosemirrorChangeset = require("prosemirror-changeset");
|
|
10
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
11
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
12
|
+
var simplifySteps = function simplifySteps(steps) {
|
|
13
|
+
return steps.reduce(function (acc, step) {
|
|
14
|
+
var lastStep = acc[acc.length - 1];
|
|
15
|
+
if (lastStep) {
|
|
16
|
+
var mergedStep = lastStep.merge(step);
|
|
17
|
+
if (mergedStep) {
|
|
18
|
+
acc[acc.length - 1] = mergedStep;
|
|
19
|
+
return acc;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return acc.concat(step);
|
|
23
|
+
}, []);
|
|
24
|
+
};
|
|
25
|
+
function findContentChanges(doc, steps) {
|
|
26
|
+
var changes = _prosemirrorChangeset.ChangeSet.create(doc);
|
|
27
|
+
var latestDoc = doc;
|
|
28
|
+
simplifySteps(steps).forEach(function (step, index) {
|
|
29
|
+
var stepResult = step.apply(latestDoc);
|
|
30
|
+
if (stepResult.failed !== null || stepResult.doc === null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
latestDoc = stepResult.doc;
|
|
34
|
+
changes = changes.addSteps(latestDoc, [step.getMap()], {
|
|
35
|
+
step: index
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
return changes;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Iterate through the changesets to find overlapping regions that indicate conflicting
|
|
43
|
+
* changes
|
|
44
|
+
*/
|
|
45
|
+
var getConflicts = function getConflicts(_ref) {
|
|
46
|
+
var localChanges = _ref.localChanges,
|
|
47
|
+
localDoc = _ref.localDoc,
|
|
48
|
+
remoteChanges = _ref.remoteChanges,
|
|
49
|
+
remoteDoc = _ref.remoteDoc;
|
|
50
|
+
var conflictingChanges = [];
|
|
51
|
+
localChanges.changes.forEach(function (localChange) {
|
|
52
|
+
remoteChanges.changes.forEach(function (remoteChange) {
|
|
53
|
+
if (
|
|
54
|
+
// Local change is inside remote change
|
|
55
|
+
localChange.fromA >= remoteChange.fromA && localChange.toA <= remoteChange.toA ||
|
|
56
|
+
// Remote change is inside local change
|
|
57
|
+
remoteChange.fromA >= localChange.fromA && remoteChange.toA <= localChange.toA ||
|
|
58
|
+
// Partial overlap with the end
|
|
59
|
+
localChange.fromA >= remoteChange.fromA && localChange.fromA < remoteChange.toA && localChange.toA > remoteChange.toA ||
|
|
60
|
+
// Partial overlap with the start
|
|
61
|
+
localChange.fromA < remoteChange.fromA && localChange.toA > remoteChange.fromA && localChange.toA <= remoteChange.toA) {
|
|
62
|
+
conflictingChanges.push({
|
|
63
|
+
from: Math.min(localChange.fromA, remoteChange.fromA),
|
|
64
|
+
to: Math.max(localChange.toA, remoteChange.toA),
|
|
65
|
+
local: localDoc.slice(localChange.fromB, localChange.toB, true),
|
|
66
|
+
remote: remoteDoc.slice(remoteChange.fromB, remoteChange.toB)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
return conflictingChanges;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Almost a copy of the rebaseSteps in the collab algorithm (which gets called
|
|
76
|
+
* synchronously after this).
|
|
77
|
+
*
|
|
78
|
+
* This also tracks the intermediate documents so we can generate the changesets
|
|
79
|
+
* to use for finding any overlapping regions.
|
|
80
|
+
* See: `packages/editor/prosemirror-collab/src/index.ts`
|
|
81
|
+
*/
|
|
82
|
+
var rebaseSteps = function rebaseSteps(_ref2) {
|
|
83
|
+
var _tr$mapping$maps;
|
|
84
|
+
var localSteps = _ref2.localSteps,
|
|
85
|
+
remoteSteps = _ref2.remoteSteps,
|
|
86
|
+
tr = _ref2.tr;
|
|
87
|
+
for (var i = (localSteps === null || localSteps === void 0 ? void 0 : localSteps.length) - 1; i >= 0; i--) {
|
|
88
|
+
tr.step(localSteps[i].inverted);
|
|
89
|
+
}
|
|
90
|
+
var originalDoc = tr.doc;
|
|
91
|
+
var mapStart = (_tr$mapping$maps = tr.mapping.maps) === null || _tr$mapping$maps === void 0 ? void 0 : _tr$mapping$maps.length;
|
|
92
|
+
for (var _i = 0; _i < remoteSteps.length; _i++) {
|
|
93
|
+
tr.step(remoteSteps[_i]);
|
|
94
|
+
}
|
|
95
|
+
var remoteDoc = tr.doc;
|
|
96
|
+
for (var _i2 = 0, mapFrom = localSteps.length; _i2 < localSteps.length; _i2++) {
|
|
97
|
+
var mapped = localSteps[_i2].step.map(tr.mapping.slice(mapFrom));
|
|
98
|
+
mapFrom--;
|
|
99
|
+
if (mapped && !tr.maybeStep(mapped).failed) {
|
|
100
|
+
// Open ticket for setMirror https://github.com/ProseMirror/prosemirror/issues/869
|
|
101
|
+
// @ts-expect-error
|
|
102
|
+
tr.mapping.setMirror(mapFrom, tr.steps.length - 1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
mapStart: mapStart,
|
|
107
|
+
originalDoc: originalDoc,
|
|
108
|
+
remoteDoc: remoteDoc
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Gets the conflicts between the local document and the remote document based on steps.
|
|
114
|
+
* It assumes the steps will be rebased using the `prosemirror-collab` algorithm synchronously after this
|
|
115
|
+
* Therefore the `tr` property is based on the document before rebasing.
|
|
116
|
+
*
|
|
117
|
+
* In the future we could possibly use `prosemirror-recreate-steps` (or similar approach)
|
|
118
|
+
* and tweak this to work for arbitrary diffs between offline and remote documents.
|
|
119
|
+
*
|
|
120
|
+
* @param localSteps Local steps applied between now and the server steps
|
|
121
|
+
* @param remoteSteps Steps retrieved from the server
|
|
122
|
+
* @param tr Transaction of the current document (expected to happen with local steps applied, before remote are applied)
|
|
123
|
+
* @returns All the conflicts (inserted + deleted) which can be applied to the current document
|
|
124
|
+
*/
|
|
125
|
+
function getConflictChanges(_ref3) {
|
|
126
|
+
var localSteps = _ref3.localSteps,
|
|
127
|
+
remoteSteps = _ref3.remoteSteps,
|
|
128
|
+
tr = _ref3.tr;
|
|
129
|
+
var localDoc = tr.doc;
|
|
130
|
+
var _rebaseSteps = rebaseSteps({
|
|
131
|
+
localSteps: localSteps,
|
|
132
|
+
remoteSteps: remoteSteps,
|
|
133
|
+
tr: tr
|
|
134
|
+
}),
|
|
135
|
+
originalDoc = _rebaseSteps.originalDoc,
|
|
136
|
+
remoteDoc = _rebaseSteps.remoteDoc,
|
|
137
|
+
mapStart = _rebaseSteps.mapStart;
|
|
138
|
+
var localChanges = findContentChanges(originalDoc, localSteps.map(function (s) {
|
|
139
|
+
return s.step;
|
|
140
|
+
}));
|
|
141
|
+
var remoteChanges = findContentChanges(originalDoc, remoteSteps);
|
|
142
|
+
|
|
143
|
+
// This is the mapping between the original document and our final one which can be used to
|
|
144
|
+
// map conflict positions (which are based on the original doc)
|
|
145
|
+
var mapping = tr.mapping.slice(mapStart);
|
|
146
|
+
|
|
147
|
+
// Find the overlapping conflicts - these are based on the positions of the original document so are
|
|
148
|
+
// common to both local and remote documents.
|
|
149
|
+
// The above mapping allows us to bring these positions to where they are in the current document
|
|
150
|
+
var conflictingChanges = getConflicts({
|
|
151
|
+
localChanges: localChanges,
|
|
152
|
+
localDoc: localDoc,
|
|
153
|
+
remoteDoc: remoteDoc,
|
|
154
|
+
remoteChanges: remoteChanges
|
|
155
|
+
});
|
|
156
|
+
var isConflictChange = function isConflictChange(value) {
|
|
157
|
+
return Boolean(value);
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
inserted: conflictingChanges.filter(function (i) {
|
|
161
|
+
return i.remote.size !== 0;
|
|
162
|
+
}).map(function (i) {
|
|
163
|
+
return _objectSpread(_objectSpread({}, i), {}, {
|
|
164
|
+
from: mapping.map(i.from, -1),
|
|
165
|
+
to: mapping.map(i.to)
|
|
166
|
+
});
|
|
167
|
+
}).filter(isConflictChange),
|
|
168
|
+
deleted: conflictingChanges.filter(function (d) {
|
|
169
|
+
return d.remote.size === 0;
|
|
170
|
+
}).map(function (d) {
|
|
171
|
+
return _objectSpread(_objectSpread({}, d), {}, {
|
|
172
|
+
from: mapping.map(d.from),
|
|
173
|
+
to: mapping.map(d.to)
|
|
174
|
+
});
|
|
175
|
+
}).filter(isConflictChange)
|
|
176
|
+
};
|
|
177
|
+
}
|
|
@@ -46,7 +46,7 @@ var NullDocumentService = exports.NullDocumentService = /*#__PURE__*/function ()
|
|
|
46
46
|
}
|
|
47
47
|
}, {
|
|
48
48
|
key: "getFinalAcknowledgedState",
|
|
49
|
-
value: function getFinalAcknowledgedState() {
|
|
49
|
+
value: function getFinalAcknowledgedState(reason) {
|
|
50
50
|
return Promise.resolve({});
|
|
51
51
|
}
|
|
52
52
|
}, {
|