@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
|
@@ -25,7 +25,7 @@ var NCS_ERROR_CODE = exports.NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_C
|
|
|
25
25
|
NCS_ERROR_CODE["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
|
|
26
26
|
NCS_ERROR_CODE["PROSEMIRROR_SCHEMA_VALIDATION_ERROR"] = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR";
|
|
27
27
|
return NCS_ERROR_CODE;
|
|
28
|
-
}({}); // TODO: Import emitted error codes from NCS
|
|
28
|
+
}({}); // TODO: ED-26957 - Import emitted error codes from NCS
|
|
29
29
|
// NCS Errors
|
|
30
30
|
// - Step rejection errors
|
|
31
31
|
// - Permission errors
|
|
@@ -16,7 +16,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
|
|
|
16
16
|
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; }
|
|
17
17
|
var logger = (0, _utils.createLogger)('commit-step', 'black');
|
|
18
18
|
var readyToCommit = exports.readyToCommit = true;
|
|
19
|
-
var RESET_READYTOCOMMIT_INTERVAL_MS = exports.RESET_READYTOCOMMIT_INTERVAL_MS =
|
|
19
|
+
var RESET_READYTOCOMMIT_INTERVAL_MS = exports.RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
|
|
20
20
|
var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
21
21
|
var broadcast = _ref.broadcast,
|
|
22
22
|
steps = _ref.steps,
|
|
@@ -30,7 +30,7 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
|
30
30
|
__livePage = _ref.__livePage,
|
|
31
31
|
hasRecovered = _ref.hasRecovered,
|
|
32
32
|
collabMode = _ref.collabMode,
|
|
33
|
-
|
|
33
|
+
reason = _ref.reason;
|
|
34
34
|
if (!readyToCommit) {
|
|
35
35
|
logger('Not ready to commit, skip');
|
|
36
36
|
return;
|
|
@@ -92,8 +92,7 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
|
92
92
|
collabMode: collabMode,
|
|
93
93
|
steps: stepsWithClientAndUserId,
|
|
94
94
|
version: version,
|
|
95
|
-
userId: userId
|
|
96
|
-
forcePublish: forcePublish
|
|
95
|
+
userId: userId
|
|
97
96
|
}, function (response) {
|
|
98
97
|
var latency = new Date().getTime() - start;
|
|
99
98
|
if (timer) {
|
|
@@ -277,27 +277,32 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
277
277
|
* Used when returning the document to Confluence on publish.
|
|
278
278
|
* @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
|
|
279
279
|
*/
|
|
280
|
-
(0, _defineProperty2.default)(_this, "getFinalAcknowledgedState", /*#__PURE__*/
|
|
281
|
-
var
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
280
|
+
(0, _defineProperty2.default)(_this, "getFinalAcknowledgedState", /*#__PURE__*/function () {
|
|
281
|
+
var _ref7 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(reason) {
|
|
282
|
+
var _this$analyticsHelper5;
|
|
283
|
+
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
284
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
285
|
+
case 0:
|
|
286
|
+
_context3.prev = 0;
|
|
287
|
+
_context3.next = 3;
|
|
288
|
+
return _this.documentService.getFinalAcknowledgedState(reason);
|
|
289
|
+
case 3:
|
|
290
|
+
return _context3.abrupt("return", _context3.sent);
|
|
291
|
+
case 6:
|
|
292
|
+
_context3.prev = 6;
|
|
293
|
+
_context3.t0 = _context3["catch"](0);
|
|
294
|
+
(_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 || _this$analyticsHelper5.sendErrorEvent(_context3.t0, 'Error while returning ADF version of the final draft document');
|
|
295
|
+
throw new _customErrors.GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context3.t0);
|
|
296
|
+
case 10:
|
|
297
|
+
case "end":
|
|
298
|
+
return _context3.stop();
|
|
299
|
+
}
|
|
300
|
+
}, _callee3, null, [[0, 6]]);
|
|
301
|
+
}));
|
|
302
|
+
return function (_x2) {
|
|
303
|
+
return _ref7.apply(this, arguments);
|
|
304
|
+
};
|
|
305
|
+
}());
|
|
301
306
|
(0, _defineProperty2.default)(_this, "getUnconfirmedSteps", function () {
|
|
302
307
|
return _this.documentService.getUnconfirmedSteps();
|
|
303
308
|
});
|
|
@@ -354,7 +359,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
354
359
|
}
|
|
355
360
|
_this.sendStepsTimer = setInterval(function () {
|
|
356
361
|
logger('Intervally sendStepsFromCurrentState');
|
|
357
|
-
_this.documentService.sendStepsFromCurrentState(true);
|
|
362
|
+
_this.documentService.sendStepsFromCurrentState(true, undefined);
|
|
358
363
|
}, 5000);
|
|
359
364
|
return _this;
|
|
360
365
|
}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.version = exports.nextMajorVersion = exports.name = void 0;
|
|
7
7
|
var name = exports.name = "@atlaskit/collab-provider";
|
|
8
|
-
var version = exports.version = "10.9.
|
|
8
|
+
var version = exports.version = "10.9.4";
|
|
9
9
|
var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
|
|
10
10
|
return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
|
|
11
11
|
};
|
package/dist/es2019/channel.js
CHANGED
|
@@ -139,7 +139,7 @@ export class Channel extends Emitter {
|
|
|
139
139
|
const measure = stopMeasure(MEASURE_NAME.DOCUMENT_INIT, this.analyticsHelper);
|
|
140
140
|
(_this$initExperience = this.initExperience) === null || _this$initExperience === void 0 ? void 0 : _this$initExperience.success();
|
|
141
141
|
(_this$analyticsHelper6 = this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendActionEvent(EVENT_ACTION.DOCUMENT_INIT,
|
|
142
|
-
// TODO: detect when document init fails and fire corresponding event for it
|
|
142
|
+
// TODO: ED-26957 - detect when document init fails and fire corresponding event for it
|
|
143
143
|
EVENT_STATUS.SUCCESS, {
|
|
144
144
|
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
145
145
|
resetReason: data.resetReason,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import throttle from 'lodash/throttle';
|
|
3
3
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
|
+
import { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
|
|
4
5
|
import { getCollabState, sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
5
6
|
import { Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
6
7
|
import { JSONTransformer } from '@atlaskit/editor-json-transformer';
|
|
@@ -13,6 +14,7 @@ import { commitStepQueue } from '../provider/commit-step';
|
|
|
13
14
|
import { CantSyncUpError, UpdateDocumentError } from '../errors/custom-errors';
|
|
14
15
|
import { catchupv2 } from './catchupv2';
|
|
15
16
|
import { StepQueueState } from './step-queue-state';
|
|
17
|
+
import { getConflictChanges } from './getConflictChanges';
|
|
16
18
|
const CATCHUP_THROTTLE = 1 * 1000; // 1 second
|
|
17
19
|
|
|
18
20
|
const noop = () => {};
|
|
@@ -52,7 +54,7 @@ export class DocumentService {
|
|
|
52
54
|
*/
|
|
53
55
|
_defineProperty(this, "throttledCatchupv2", throttle((reason, reconnectionMetadata) => this.catchupv2(reason, reconnectionMetadata), CATCHUP_THROTTLE, {
|
|
54
56
|
leading: false,
|
|
55
|
-
// TODO: why shouldn't this be leading?
|
|
57
|
+
// TODO: ED-26957 - why shouldn't this be leading?
|
|
56
58
|
trailing: true
|
|
57
59
|
}));
|
|
58
60
|
/**
|
|
@@ -396,14 +398,14 @@ export class DocumentService {
|
|
|
396
398
|
});
|
|
397
399
|
}
|
|
398
400
|
});
|
|
399
|
-
_defineProperty(this, "getFinalAcknowledgedState", async
|
|
401
|
+
_defineProperty(this, "getFinalAcknowledgedState", async reason => {
|
|
400
402
|
this.aggressiveCatchup = true;
|
|
401
403
|
try {
|
|
402
404
|
var _this$analyticsHelper18;
|
|
403
405
|
startMeasure(MEASURE_NAME.PUBLISH_PAGE, this.analyticsHelper);
|
|
404
406
|
let finalAcknowledgedState;
|
|
405
407
|
try {
|
|
406
|
-
await this.commitUnconfirmedSteps();
|
|
408
|
+
await this.commitUnconfirmedSteps(reason);
|
|
407
409
|
finalAcknowledgedState = await this.getCurrentState();
|
|
408
410
|
} catch (error) {
|
|
409
411
|
// if fails to commit unconfirmed steps, send reconcile request to NCS BE and return the doc to CC
|
|
@@ -522,7 +524,7 @@ export class DocumentService {
|
|
|
522
524
|
* Commit the unconfirmed local steps to the back-end service
|
|
523
525
|
* @throws {Error} Couldn't sync the steps after retrying 30 times
|
|
524
526
|
*/
|
|
525
|
-
_defineProperty(this, "commitUnconfirmedSteps", async
|
|
527
|
+
_defineProperty(this, "commitUnconfirmedSteps", async reason => {
|
|
526
528
|
const unconfirmedSteps = this.getUnconfirmedSteps();
|
|
527
529
|
try {
|
|
528
530
|
if (unconfirmedSteps !== null && unconfirmedSteps !== void 0 && unconfirmedSteps.length) {
|
|
@@ -542,7 +544,7 @@ export class DocumentService {
|
|
|
542
544
|
}
|
|
543
545
|
while (!isLastTrConfirmed) {
|
|
544
546
|
// forcePublish = true, this is because commitUnconfirmedSteps is only called when the Editor publishes a document
|
|
545
|
-
this.sendStepsFromCurrentState(undefined,
|
|
547
|
+
this.sendStepsFromCurrentState(undefined, reason);
|
|
546
548
|
await sleep(500);
|
|
547
549
|
const nextUnconfirmedSteps = this.getUnconfirmedSteps();
|
|
548
550
|
if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
|
|
@@ -657,10 +659,22 @@ export class DocumentService {
|
|
|
657
659
|
const state = (_this$getState7 = this.getState) === null || _this$getState7 === void 0 ? void 0 : _this$getState7.call(this);
|
|
658
660
|
const unconfirmedSteps = state ? (_getCollabState = getCollabState(state)) === null || _getCollabState === void 0 ? void 0 : _getCollabState.unconfirmed : undefined;
|
|
659
661
|
if (steps.length > 0 && state && unconfirmedSteps && unconfirmedSteps.length > 0) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
662
|
+
const {
|
|
663
|
+
schema,
|
|
664
|
+
tr
|
|
665
|
+
} = state;
|
|
666
|
+
const remoteSteps = steps.map(s => ProseMirrorStep.fromJSON(schema, s));
|
|
667
|
+
const conflicts = getConflictChanges({
|
|
668
|
+
localSteps: unconfirmedSteps,
|
|
669
|
+
remoteSteps,
|
|
670
|
+
tr
|
|
663
671
|
});
|
|
672
|
+
if (conflicts.deleted.length > 0 || conflicts.inserted.length > 0) {
|
|
673
|
+
this.providerEmitCallback('data:conflict', {
|
|
674
|
+
offlineDoc: state.doc,
|
|
675
|
+
...conflicts
|
|
676
|
+
});
|
|
677
|
+
}
|
|
664
678
|
}
|
|
665
679
|
}
|
|
666
680
|
processQueue() {
|
|
@@ -744,7 +758,7 @@ export class DocumentService {
|
|
|
744
758
|
* The getState function will return the current EditorState
|
|
745
759
|
* from the EditorView.
|
|
746
760
|
*/
|
|
747
|
-
sendStepsFromCurrentState(sendAnalyticsEvent,
|
|
761
|
+
sendStepsFromCurrentState(sendAnalyticsEvent, reason) {
|
|
748
762
|
var _this$getState8;
|
|
749
763
|
const state = (_this$getState8 = this.getState) === null || _this$getState8 === void 0 ? void 0 : _this$getState8.call(this);
|
|
750
764
|
if (!state) {
|
|
@@ -752,13 +766,14 @@ export class DocumentService {
|
|
|
752
766
|
(_this$analyticsHelper33 = this.analyticsHelper) === null || _this$analyticsHelper33 === void 0 ? void 0 : _this$analyticsHelper33.sendErrorEvent(new Error('Editor state is undefined'), 'sendStepsFromCurrentState called without state');
|
|
753
767
|
return;
|
|
754
768
|
}
|
|
755
|
-
this.send(null, null, state, sendAnalyticsEvent,
|
|
769
|
+
this.send(null, null, state, sendAnalyticsEvent, reason);
|
|
756
770
|
}
|
|
757
771
|
/**
|
|
758
772
|
* Send steps from transaction to other participants
|
|
759
773
|
* It needs the superfluous arguments because we keep the interface of the send API the same as the Synchrony plugin
|
|
760
774
|
*/
|
|
761
|
-
send(tr, _oldState, newState, sendAnalyticsEvent,
|
|
775
|
+
send(tr, _oldState, newState, sendAnalyticsEvent, reason // only used for publish and draft-sync events - when called through getFinalAcknowledgedState
|
|
776
|
+
) {
|
|
762
777
|
const unconfirmedStepsData = sendableSteps(newState);
|
|
763
778
|
const version = this.getVersionFromCollabState(newState, 'collab-provider: send');
|
|
764
779
|
|
|
@@ -841,7 +856,7 @@ export class DocumentService {
|
|
|
841
856
|
__livePage: this.options.__livePage,
|
|
842
857
|
hasRecovered: this.hasRecovered,
|
|
843
858
|
collabMode: this.participantsService.getCollabMode(),
|
|
844
|
-
|
|
859
|
+
reason
|
|
845
860
|
});
|
|
846
861
|
}
|
|
847
862
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { ChangeSet } from 'prosemirror-changeset';
|
|
2
|
+
const simplifySteps = steps => {
|
|
3
|
+
return steps.reduce((acc, step) => {
|
|
4
|
+
const lastStep = acc[acc.length - 1];
|
|
5
|
+
if (lastStep) {
|
|
6
|
+
const mergedStep = lastStep.merge(step);
|
|
7
|
+
if (mergedStep) {
|
|
8
|
+
acc[acc.length - 1] = mergedStep;
|
|
9
|
+
return acc;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return acc.concat(step);
|
|
13
|
+
}, []);
|
|
14
|
+
};
|
|
15
|
+
function findContentChanges(doc, steps) {
|
|
16
|
+
let changes = ChangeSet.create(doc);
|
|
17
|
+
let latestDoc = doc;
|
|
18
|
+
simplifySteps(steps).forEach((step, index) => {
|
|
19
|
+
const stepResult = step.apply(latestDoc);
|
|
20
|
+
if (stepResult.failed !== null || stepResult.doc === null) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
latestDoc = stepResult.doc;
|
|
24
|
+
changes = changes.addSteps(latestDoc, [step.getMap()], {
|
|
25
|
+
step: index
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
return changes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Iterate through the changesets to find overlapping regions that indicate conflicting
|
|
33
|
+
* changes
|
|
34
|
+
*/
|
|
35
|
+
const getConflicts = ({
|
|
36
|
+
localChanges,
|
|
37
|
+
localDoc,
|
|
38
|
+
remoteChanges,
|
|
39
|
+
remoteDoc
|
|
40
|
+
}) => {
|
|
41
|
+
const conflictingChanges = [];
|
|
42
|
+
localChanges.changes.forEach(localChange => {
|
|
43
|
+
remoteChanges.changes.forEach(remoteChange => {
|
|
44
|
+
if (
|
|
45
|
+
// Local change is inside remote change
|
|
46
|
+
localChange.fromA >= remoteChange.fromA && localChange.toA <= remoteChange.toA ||
|
|
47
|
+
// Remote change is inside local change
|
|
48
|
+
remoteChange.fromA >= localChange.fromA && remoteChange.toA <= localChange.toA ||
|
|
49
|
+
// Partial overlap with the end
|
|
50
|
+
localChange.fromA >= remoteChange.fromA && localChange.fromA < remoteChange.toA && localChange.toA > remoteChange.toA ||
|
|
51
|
+
// Partial overlap with the start
|
|
52
|
+
localChange.fromA < remoteChange.fromA && localChange.toA > remoteChange.fromA && localChange.toA <= remoteChange.toA) {
|
|
53
|
+
conflictingChanges.push({
|
|
54
|
+
from: Math.min(localChange.fromA, remoteChange.fromA),
|
|
55
|
+
to: Math.max(localChange.toA, remoteChange.toA),
|
|
56
|
+
local: localDoc.slice(localChange.fromB, localChange.toB, true),
|
|
57
|
+
remote: remoteDoc.slice(remoteChange.fromB, remoteChange.toB)
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
return conflictingChanges;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Almost a copy of the rebaseSteps in the collab algorithm (which gets called
|
|
67
|
+
* synchronously after this).
|
|
68
|
+
*
|
|
69
|
+
* This also tracks the intermediate documents so we can generate the changesets
|
|
70
|
+
* to use for finding any overlapping regions.
|
|
71
|
+
* See: `packages/editor/prosemirror-collab/src/index.ts`
|
|
72
|
+
*/
|
|
73
|
+
const rebaseSteps = ({
|
|
74
|
+
localSteps,
|
|
75
|
+
remoteSteps,
|
|
76
|
+
tr
|
|
77
|
+
}) => {
|
|
78
|
+
var _tr$mapping$maps;
|
|
79
|
+
for (let i = (localSteps === null || localSteps === void 0 ? void 0 : localSteps.length) - 1; i >= 0; i--) {
|
|
80
|
+
tr.step(localSteps[i].inverted);
|
|
81
|
+
}
|
|
82
|
+
const originalDoc = tr.doc;
|
|
83
|
+
const mapStart = (_tr$mapping$maps = tr.mapping.maps) === null || _tr$mapping$maps === void 0 ? void 0 : _tr$mapping$maps.length;
|
|
84
|
+
for (let i = 0; i < remoteSteps.length; i++) {
|
|
85
|
+
tr.step(remoteSteps[i]);
|
|
86
|
+
}
|
|
87
|
+
const remoteDoc = tr.doc;
|
|
88
|
+
for (let i = 0, mapFrom = localSteps.length; i < localSteps.length; i++) {
|
|
89
|
+
const mapped = localSteps[i].step.map(tr.mapping.slice(mapFrom));
|
|
90
|
+
mapFrom--;
|
|
91
|
+
if (mapped && !tr.maybeStep(mapped).failed) {
|
|
92
|
+
// Open ticket for setMirror https://github.com/ProseMirror/prosemirror/issues/869
|
|
93
|
+
// @ts-expect-error
|
|
94
|
+
tr.mapping.setMirror(mapFrom, tr.steps.length - 1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
mapStart,
|
|
99
|
+
originalDoc,
|
|
100
|
+
remoteDoc
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Gets the conflicts between the local document and the remote document based on steps.
|
|
106
|
+
* It assumes the steps will be rebased using the `prosemirror-collab` algorithm synchronously after this
|
|
107
|
+
* Therefore the `tr` property is based on the document before rebasing.
|
|
108
|
+
*
|
|
109
|
+
* In the future we could possibly use `prosemirror-recreate-steps` (or similar approach)
|
|
110
|
+
* and tweak this to work for arbitrary diffs between offline and remote documents.
|
|
111
|
+
*
|
|
112
|
+
* @param localSteps Local steps applied between now and the server steps
|
|
113
|
+
* @param remoteSteps Steps retrieved from the server
|
|
114
|
+
* @param tr Transaction of the current document (expected to happen with local steps applied, before remote are applied)
|
|
115
|
+
* @returns All the conflicts (inserted + deleted) which can be applied to the current document
|
|
116
|
+
*/
|
|
117
|
+
export function getConflictChanges({
|
|
118
|
+
localSteps,
|
|
119
|
+
remoteSteps,
|
|
120
|
+
tr
|
|
121
|
+
}) {
|
|
122
|
+
const localDoc = tr.doc;
|
|
123
|
+
const {
|
|
124
|
+
originalDoc,
|
|
125
|
+
remoteDoc,
|
|
126
|
+
mapStart
|
|
127
|
+
} = rebaseSteps({
|
|
128
|
+
localSteps,
|
|
129
|
+
remoteSteps,
|
|
130
|
+
tr
|
|
131
|
+
});
|
|
132
|
+
const localChanges = findContentChanges(originalDoc, localSteps.map(s => s.step));
|
|
133
|
+
const remoteChanges = findContentChanges(originalDoc, remoteSteps);
|
|
134
|
+
|
|
135
|
+
// This is the mapping between the original document and our final one which can be used to
|
|
136
|
+
// map conflict positions (which are based on the original doc)
|
|
137
|
+
const mapping = tr.mapping.slice(mapStart);
|
|
138
|
+
|
|
139
|
+
// Find the overlapping conflicts - these are based on the positions of the original document so are
|
|
140
|
+
// common to both local and remote documents.
|
|
141
|
+
// The above mapping allows us to bring these positions to where they are in the current document
|
|
142
|
+
const conflictingChanges = getConflicts({
|
|
143
|
+
localChanges,
|
|
144
|
+
localDoc,
|
|
145
|
+
remoteDoc,
|
|
146
|
+
remoteChanges
|
|
147
|
+
});
|
|
148
|
+
const isConflictChange = value => Boolean(value);
|
|
149
|
+
return {
|
|
150
|
+
inserted: conflictingChanges.filter(i => i.remote.size !== 0).map(i => ({
|
|
151
|
+
...i,
|
|
152
|
+
from: mapping.map(i.from, -1),
|
|
153
|
+
to: mapping.map(i.to)
|
|
154
|
+
})).filter(isConflictChange),
|
|
155
|
+
deleted: conflictingChanges.filter(d => d.remote.size === 0).map(d => ({
|
|
156
|
+
...d,
|
|
157
|
+
from: mapping.map(d.from),
|
|
158
|
+
to: mapping.map(d.to)
|
|
159
|
+
})).filter(isConflictChange)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -21,7 +21,7 @@ export let NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_CODE) {
|
|
|
21
21
|
return NCS_ERROR_CODE;
|
|
22
22
|
}({});
|
|
23
23
|
|
|
24
|
-
// TODO: Import emitted error codes from NCS
|
|
24
|
+
// TODO: ED-26957 - Import emitted error codes from NCS
|
|
25
25
|
|
|
26
26
|
// NCS Errors
|
|
27
27
|
// - Step rejection errors
|
|
@@ -6,7 +6,7 @@ import { NCS_ERROR_CODE } from '../errors/ncs-errors';
|
|
|
6
6
|
import { createLogger } from '../helpers/utils';
|
|
7
7
|
const logger = createLogger('commit-step', 'black');
|
|
8
8
|
export let readyToCommit = true;
|
|
9
|
-
export const RESET_READYTOCOMMIT_INTERVAL_MS =
|
|
9
|
+
export const RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
|
|
10
10
|
export const commitStepQueue = ({
|
|
11
11
|
broadcast,
|
|
12
12
|
steps,
|
|
@@ -20,7 +20,7 @@ export const commitStepQueue = ({
|
|
|
20
20
|
__livePage,
|
|
21
21
|
hasRecovered,
|
|
22
22
|
collabMode,
|
|
23
|
-
|
|
23
|
+
reason
|
|
24
24
|
}) => {
|
|
25
25
|
if (!readyToCommit) {
|
|
26
26
|
logger('Not ready to commit, skip');
|
|
@@ -84,8 +84,7 @@ export const commitStepQueue = ({
|
|
|
84
84
|
collabMode,
|
|
85
85
|
steps: stepsWithClientAndUserId,
|
|
86
86
|
version,
|
|
87
|
-
userId
|
|
88
|
-
forcePublish
|
|
87
|
+
userId
|
|
89
88
|
}, response => {
|
|
90
89
|
const latency = new Date().getTime() - start;
|
|
91
90
|
if (timer) {
|
|
@@ -228,9 +228,9 @@ export class Provider extends Emitter {
|
|
|
228
228
|
* Used when returning the document to Confluence on publish.
|
|
229
229
|
* @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
|
|
230
230
|
*/
|
|
231
|
-
_defineProperty(this, "getFinalAcknowledgedState", async
|
|
231
|
+
_defineProperty(this, "getFinalAcknowledgedState", async reason => {
|
|
232
232
|
try {
|
|
233
|
-
return await this.documentService.getFinalAcknowledgedState();
|
|
233
|
+
return await this.documentService.getFinalAcknowledgedState(reason);
|
|
234
234
|
} catch (error) {
|
|
235
235
|
var _this$analyticsHelper5;
|
|
236
236
|
(_this$analyticsHelper5 = this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(error, 'Error while returning ADF version of the final draft document');
|
|
@@ -291,7 +291,7 @@ export class Provider extends Emitter {
|
|
|
291
291
|
}
|
|
292
292
|
this.sendStepsTimer = setInterval(() => {
|
|
293
293
|
logger('Intervally sendStepsFromCurrentState');
|
|
294
|
-
this.documentService.sendStepsFromCurrentState(true);
|
|
294
|
+
this.documentService.sendStepsFromCurrentState(true, undefined);
|
|
295
295
|
}, 5000);
|
|
296
296
|
}
|
|
297
297
|
// eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
|
package/dist/esm/channel.js
CHANGED
|
@@ -196,7 +196,7 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
196
196
|
var measure = stopMeasure(MEASURE_NAME.DOCUMENT_INIT, _this.analyticsHelper);
|
|
197
197
|
(_this$initExperience = _this.initExperience) === null || _this$initExperience === void 0 || _this$initExperience.success();
|
|
198
198
|
(_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 || _this$analyticsHelper6.sendActionEvent(EVENT_ACTION.DOCUMENT_INIT,
|
|
199
|
-
// TODO: detect when document init fails and fire corresponding event for it
|
|
199
|
+
// TODO: ED-26957 - detect when document init fails and fire corresponding event for it
|
|
200
200
|
EVENT_STATUS.SUCCESS, {
|
|
201
201
|
latency: measure === null || measure === void 0 ? void 0 : measure.duration,
|
|
202
202
|
resetReason: data.resetReason,
|