@atlaskit/collab-provider 10.10.2 → 10.11.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/document/document-service.js +13 -2
  3. package/dist/cjs/document/null-document-service.js +1 -0
  4. package/dist/cjs/errors/ncs-errors.js +1 -0
  5. package/dist/cjs/helpers/const.js +1 -0
  6. package/dist/cjs/provider/commit-step.js +14 -2
  7. package/dist/cjs/provider/index.js +4 -1
  8. package/dist/cjs/version-wrapper.js +1 -1
  9. package/dist/es2019/document/document-service.js +13 -2
  10. package/dist/es2019/document/null-document-service.js +1 -0
  11. package/dist/es2019/errors/ncs-errors.js +1 -0
  12. package/dist/es2019/helpers/const.js +1 -0
  13. package/dist/es2019/provider/commit-step.js +14 -2
  14. package/dist/es2019/provider/index.js +4 -1
  15. package/dist/es2019/version-wrapper.js +1 -1
  16. package/dist/esm/document/document-service.js +13 -2
  17. package/dist/esm/document/null-document-service.js +1 -0
  18. package/dist/esm/errors/ncs-errors.js +1 -0
  19. package/dist/esm/helpers/const.js +1 -0
  20. package/dist/esm/provider/commit-step.js +14 -2
  21. package/dist/esm/provider/index.js +4 -1
  22. package/dist/esm/version-wrapper.js +1 -1
  23. package/dist/types/document/document-service.d.ts +7 -0
  24. package/dist/types/document/null-document-service.d.ts +1 -0
  25. package/dist/types/errors/ncs-errors.d.ts +11 -2
  26. package/dist/types/helpers/const.d.ts +2 -1
  27. package/dist/types/provider/commit-step.d.ts +3 -1
  28. package/dist/types/types.d.ts +1 -0
  29. package/dist/types-ts4.5/document/document-service.d.ts +7 -0
  30. package/dist/types-ts4.5/document/null-document-service.d.ts +1 -0
  31. package/dist/types-ts4.5/errors/ncs-errors.d.ts +11 -2
  32. package/dist/types-ts4.5/helpers/const.d.ts +2 -1
  33. package/dist/types-ts4.5/provider/commit-step.d.ts +3 -1
  34. package/dist/types-ts4.5/types.d.ts +1 -0
  35. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @atlaskit/collab-provider
2
2
 
3
+ ## 10.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#130166](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/130166)
8
+ [`1d522a3c3f04a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1d522a3c3f04a) -
9
+ handle corrupt step validation errors and tag first steps from client
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
3
15
  ## 10.10.2
4
16
 
5
17
  ### Patch Changes
@@ -66,6 +66,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
66
66
  (0, _defineProperty2.default)(this, "aggressiveCatchup", false);
67
67
  (0, _defineProperty2.default)(this, "catchUpOutofSync", false);
68
68
  (0, _defineProperty2.default)(this, "hasRecovered", false);
69
+ (0, _defineProperty2.default)(this, "numberOfStepCommitsSent", 0);
69
70
  /**
70
71
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
71
72
  * @param reason - optional reason to attach.
@@ -77,6 +78,14 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
77
78
  // TODO: ED-26957 - why shouldn't this be leading?
78
79
  trailing: true
79
80
  }));
81
+ /**
82
+ * Updates the number of commits sent since connect/reconnect
83
+ * This is used to track the number of commits sent to the server.
84
+ * currently we are validating the first steps from a user after connect/reconnect - CEPS-710
85
+ */
86
+ (0, _defineProperty2.default)(this, "setNumberOfCommitsSent", function (steps) {
87
+ _this.numberOfStepCommitsSent = steps;
88
+ });
80
89
  /**
81
90
  * Called when:
82
91
  * * session established(offline -> online)
@@ -114,7 +123,7 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
114
123
  analyticsHelper: _this.analyticsHelper,
115
124
  clientId: _this.clientId,
116
125
  onStepsAdded: _this.onStepsAdded,
117
- catchUpOutofSync: _this.catchUpOutofSync,
126
+ catchUpOutofSync: reason === _const.CatchupEventReason.CORRUPT_STEP ? true : _this.catchUpOutofSync,
118
127
  reason: reason,
119
128
  onCatchupComplete: function onCatchupComplete(steps) {
120
129
  // We want to capture the number of steps made while offline vs. online
@@ -971,7 +980,9 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
971
980
  __livePage: this.options.__livePage,
972
981
  hasRecovered: this.hasRecovered,
973
982
  collabMode: this.participantsService.getCollabMode(),
974
- reason: reason
983
+ reason: reason,
984
+ numberOfStepCommitsSent: this.numberOfStepCommitsSent,
985
+ setNumberOfCommitsSent: this.setNumberOfCommitsSent
975
986
  });
976
987
  }
977
988
  }]);
@@ -17,6 +17,7 @@ var NullDocumentService = exports.NullDocumentService = /*#__PURE__*/function ()
17
17
  return _this;
18
18
  });
19
19
  (0, _defineProperty2.default)(this, "onErrorHandled", function () {});
20
+ (0, _defineProperty2.default)(this, "setNumberOfCommitsSent", function () {});
20
21
  }
21
22
  return (0, _createClass2.default)(NullDocumentService, [{
22
23
  key: "updateDocument",
@@ -24,6 +24,7 @@ var NCS_ERROR_CODE = exports.NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_C
24
24
  NCS_ERROR_CODE["INVALID_CLOUD_ID"] = "INVALID_CLOUD_ID";
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
+ NCS_ERROR_CODE["CORRUPT_STEP_FAILED_TO_SAVE"] = "CORRUPT_STEP_FAILED_TO_SAVE";
27
28
  return NCS_ERROR_CODE;
28
29
  }({}); // TODO: ED-26957 - Import emitted error codes from NCS
29
30
  // NCS Errors
@@ -51,5 +51,6 @@ var CatchupEventReason = exports.CatchupEventReason = /*#__PURE__*/function (Cat
51
51
  CatchupEventReason["STEPS_REJECTED"] = "onStepsRejected";
52
52
  CatchupEventReason["PROCESS_STEPS"] = "processSteps";
53
53
  CatchupEventReason["RECONNECTED"] = "reconnected";
54
+ CatchupEventReason["CORRUPT_STEP"] = "corruptStep";
54
55
  return CatchupEventReason;
55
56
  }({});
@@ -8,6 +8,7 @@ exports.readyToCommit = exports.lastBroadcastRequestAcked = exports.commitStepQu
8
8
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
9
  var _countBy = _interopRequireDefault(require("lodash/countBy"));
10
10
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
+ var _featureGateJsClient = _interopRequireDefault(require("@atlaskit/feature-gate-js-client"));
11
12
  var _const = require("../helpers/const");
12
13
  var _types = require("../types");
13
14
  var _ncsErrors = require("../errors/ncs-errors");
@@ -31,7 +32,9 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
31
32
  __livePage = _ref.__livePage,
32
33
  hasRecovered = _ref.hasRecovered,
33
34
  collabMode = _ref.collabMode,
34
- reason = _ref.reason;
35
+ reason = _ref.reason,
36
+ numberOfStepCommitsSent = _ref.numberOfStepCommitsSent,
37
+ setNumberOfCommitsSent = _ref.setNumberOfCommitsSent;
35
38
  // this timer is for waiting to send the next batch in between acks from the BE
36
39
  var commitWaitTimer;
37
40
  // if publishing and not waiting for an ACK, then clear the commit timer and proceed, skipping the timer
@@ -101,11 +104,17 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
101
104
  version: version
102
105
  });
103
106
  try {
107
+ var _FeatureGates$getExpe;
108
+ var n = (_FeatureGates$getExpe = _featureGateJsClient.default.getExperimentValue('validate-first-n-steps-experiment', 'steps', 0)) !== null && _FeatureGates$getExpe !== void 0 ? _FeatureGates$getExpe : 0;
109
+ var isExperimentEnabled = n > 0;
110
+ // skip validation if FG is on and we have already sent n steps, or if FG is off
111
+ var skipValidation = isExperimentEnabled ? numberOfStepCommitsSent >= n : true;
104
112
  broadcast('steps:commit', {
105
113
  collabMode: collabMode,
106
114
  steps: stepsWithClientAndUserId,
107
115
  version: version,
108
- userId: userId
116
+ userId: userId,
117
+ skipValidation: skipValidation
109
118
  }, function (response) {
110
119
  exports.lastBroadcastRequestAcked = lastBroadcastRequestAcked = true;
111
120
  var latency = new Date().getTime() - start;
@@ -150,6 +159,9 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
150
159
  });
151
160
  }
152
161
  });
162
+ if (isExperimentEnabled && numberOfStepCommitsSent < n) {
163
+ setNumberOfCommitsSent(numberOfStepCommitsSent + 1);
164
+ }
153
165
  } catch (error) {
154
166
  // if the broadcast failed for any reason, we shouldn't keep the queue locked as the BE has not recieved any message
155
167
  exports.readyToCommit = readyToCommit = true;
@@ -117,6 +117,7 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
117
117
  initial: !initialized
118
118
  });
119
119
  var unconfirmedStepsLength = (_this$documentService = _this.documentService.getUnconfirmedSteps()) === null || _this$documentService === void 0 ? void 0 : _this$documentService.length;
120
+ _this.documentService.setNumberOfCommitsSent(0);
120
121
 
121
122
  // if buffering is enabled and the provider is initialized before connection,
122
123
  // send any unconfirmed steps
@@ -213,12 +214,14 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
213
214
  * @param {InternalError} error The error to handle
214
215
  */
215
216
  (0, _defineProperty2.default)(_this, "onErrorHandled", function (error) {
216
- var _error$data, _error$data2;
217
+ var _error$data, _error$data2, _error$data3;
217
218
  // User tried committing steps but they were rejected because:
218
219
  // HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
219
220
  // VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
220
221
  if (((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) === _ncsErrors.NCS_ERROR_CODE.HEAD_VERSION_UPDATE_FAILED || ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.code) === _ncsErrors.NCS_ERROR_CODE.VERSION_NUMBER_ALREADY_EXISTS) {
221
222
  _this.documentService.onStepRejectedError();
223
+ } else if (((_error$data3 = error.data) === null || _error$data3 === void 0 ? void 0 : _error$data3.code) === _ncsErrors.NCS_ERROR_CODE.CORRUPT_STEP_FAILED_TO_SAVE) {
224
+ _this.documentService.throttledCatchupv2(_const.CatchupEventReason.CORRUPT_STEP);
222
225
  } else {
223
226
  var _this$analyticsHelper2;
224
227
  (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 || _this$analyticsHelper2.sendErrorEvent(error, 'Error handled');
@@ -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.10.2";
8
+ var version = exports.version = "10.11.0";
9
9
  var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
10
10
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
11
11
  };
@@ -48,6 +48,7 @@ export class DocumentService {
48
48
  _defineProperty(this, "aggressiveCatchup", false);
49
49
  _defineProperty(this, "catchUpOutofSync", false);
50
50
  _defineProperty(this, "hasRecovered", false);
51
+ _defineProperty(this, "numberOfStepCommitsSent", 0);
51
52
  /**
52
53
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
53
54
  * @param reason - optional reason to attach.
@@ -57,6 +58,14 @@ export class DocumentService {
57
58
  // TODO: ED-26957 - why shouldn't this be leading?
58
59
  trailing: true
59
60
  }));
61
+ /**
62
+ * Updates the number of commits sent since connect/reconnect
63
+ * This is used to track the number of commits sent to the server.
64
+ * currently we are validating the first steps from a user after connect/reconnect - CEPS-710
65
+ */
66
+ _defineProperty(this, "setNumberOfCommitsSent", steps => {
67
+ this.numberOfStepCommitsSent = steps;
68
+ });
60
69
  /**
61
70
  * Called when:
62
71
  * * session established(offline -> online)
@@ -107,7 +116,7 @@ export class DocumentService {
107
116
  analyticsHelper: this.analyticsHelper,
108
117
  clientId: this.clientId,
109
118
  onStepsAdded: this.onStepsAdded,
110
- catchUpOutofSync: this.catchUpOutofSync,
119
+ catchUpOutofSync: reason === CatchupEventReason.CORRUPT_STEP ? true : this.catchUpOutofSync,
111
120
  reason,
112
121
  onCatchupComplete: steps => {
113
122
  // We want to capture the number of steps made while offline vs. online
@@ -845,7 +854,9 @@ export class DocumentService {
845
854
  __livePage: this.options.__livePage,
846
855
  hasRecovered: this.hasRecovered,
847
856
  collabMode: this.participantsService.getCollabMode(),
848
- reason
857
+ reason,
858
+ numberOfStepCommitsSent: this.numberOfStepCommitsSent,
859
+ setNumberOfCommitsSent: this.setNumberOfCommitsSent
849
860
  });
850
861
  }
851
862
  }
@@ -6,6 +6,7 @@ export class NullDocumentService {
6
6
  return this;
7
7
  });
8
8
  _defineProperty(this, "onErrorHandled", () => {});
9
+ _defineProperty(this, "setNumberOfCommitsSent", () => {});
9
10
  }
10
11
  updateDocument() {}
11
12
  onRestore() {}
@@ -18,6 +18,7 @@ export let NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_CODE) {
18
18
  NCS_ERROR_CODE["INVALID_CLOUD_ID"] = "INVALID_CLOUD_ID";
19
19
  NCS_ERROR_CODE["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
20
20
  NCS_ERROR_CODE["PROSEMIRROR_SCHEMA_VALIDATION_ERROR"] = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR";
21
+ NCS_ERROR_CODE["CORRUPT_STEP_FAILED_TO_SAVE"] = "CORRUPT_STEP_FAILED_TO_SAVE";
21
22
  return NCS_ERROR_CODE;
22
23
  }({});
23
24
 
@@ -45,5 +45,6 @@ export let CatchupEventReason = /*#__PURE__*/function (CatchupEventReason) {
45
45
  CatchupEventReason["STEPS_REJECTED"] = "onStepsRejected";
46
46
  CatchupEventReason["PROCESS_STEPS"] = "processSteps";
47
47
  CatchupEventReason["RECONNECTED"] = "reconnected";
48
+ CatchupEventReason["CORRUPT_STEP"] = "corruptStep";
48
49
  return CatchupEventReason;
49
50
  }({});
@@ -1,5 +1,6 @@
1
1
  import countBy from 'lodash/countBy';
2
2
  import { fg } from '@atlaskit/platform-feature-flags';
3
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
3
4
  import { ADD_STEPS_TYPE, EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
4
5
  import { AcknowledgementResponseTypes } from '../types';
5
6
  import { NCS_ERROR_CODE } from '../errors/ncs-errors';
@@ -21,7 +22,9 @@ export const commitStepQueue = ({
21
22
  __livePage,
22
23
  hasRecovered,
23
24
  collabMode,
24
- reason
25
+ reason,
26
+ numberOfStepCommitsSent,
27
+ setNumberOfCommitsSent
25
28
  }) => {
26
29
  // this timer is for waiting to send the next batch in between acks from the BE
27
30
  let commitWaitTimer;
@@ -93,11 +96,17 @@ export const commitStepQueue = ({
93
96
  version
94
97
  });
95
98
  try {
99
+ var _FeatureGates$getExpe;
100
+ const n = (_FeatureGates$getExpe = FeatureGates.getExperimentValue('validate-first-n-steps-experiment', 'steps', 0)) !== null && _FeatureGates$getExpe !== void 0 ? _FeatureGates$getExpe : 0;
101
+ const isExperimentEnabled = n > 0;
102
+ // skip validation if FG is on and we have already sent n steps, or if FG is off
103
+ const skipValidation = isExperimentEnabled ? numberOfStepCommitsSent >= n : true;
96
104
  broadcast('steps:commit', {
97
105
  collabMode,
98
106
  steps: stepsWithClientAndUserId,
99
107
  version,
100
- userId
108
+ userId,
109
+ skipValidation
101
110
  }, response => {
102
111
  lastBroadcastRequestAcked = true;
103
112
  const latency = new Date().getTime() - start;
@@ -142,6 +151,9 @@ export const commitStepQueue = ({
142
151
  });
143
152
  }
144
153
  });
154
+ if (isExperimentEnabled && numberOfStepCommitsSent < n) {
155
+ setNumberOfCommitsSent(numberOfStepCommitsSent + 1);
156
+ }
145
157
  } catch (error) {
146
158
  // if the broadcast failed for any reason, we shouldn't keep the queue locked as the BE has not recieved any message
147
159
  readyToCommit = true;
@@ -95,6 +95,7 @@ export class Provider extends Emitter {
95
95
  initial: !initialized
96
96
  });
97
97
  const unconfirmedStepsLength = (_this$documentService = this.documentService.getUnconfirmedSteps()) === null || _this$documentService === void 0 ? void 0 : _this$documentService.length;
98
+ this.documentService.setNumberOfCommitsSent(0);
98
99
 
99
100
  // if buffering is enabled and the provider is initialized before connection,
100
101
  // send any unconfirmed steps
@@ -175,12 +176,14 @@ export class Provider extends Emitter {
175
176
  * @param {InternalError} error The error to handle
176
177
  */
177
178
  _defineProperty(this, "onErrorHandled", error => {
178
- var _error$data, _error$data2;
179
+ var _error$data, _error$data2, _error$data3;
179
180
  // User tried committing steps but they were rejected because:
180
181
  // HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
181
182
  // VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
182
183
  if (((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) === NCS_ERROR_CODE.HEAD_VERSION_UPDATE_FAILED || ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.code) === NCS_ERROR_CODE.VERSION_NUMBER_ALREADY_EXISTS) {
183
184
  this.documentService.onStepRejectedError();
185
+ } else if (((_error$data3 = error.data) === null || _error$data3 === void 0 ? void 0 : _error$data3.code) === NCS_ERROR_CODE.CORRUPT_STEP_FAILED_TO_SAVE) {
186
+ this.documentService.throttledCatchupv2(CatchupEventReason.CORRUPT_STEP);
184
187
  } else {
185
188
  var _this$analyticsHelper2;
186
189
  (_this$analyticsHelper2 = this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(error, 'Error handled');
@@ -1,5 +1,5 @@
1
1
  export const name = "@atlaskit/collab-provider";
2
- export const version = "10.10.2";
2
+ export const version = "10.11.0";
3
3
  export const nextMajorVersion = () => {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -59,6 +59,7 @@ export var DocumentService = /*#__PURE__*/function () {
59
59
  _defineProperty(this, "aggressiveCatchup", false);
60
60
  _defineProperty(this, "catchUpOutofSync", false);
61
61
  _defineProperty(this, "hasRecovered", false);
62
+ _defineProperty(this, "numberOfStepCommitsSent", 0);
62
63
  /**
63
64
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
64
65
  * @param reason - optional reason to attach.
@@ -70,6 +71,14 @@ export var DocumentService = /*#__PURE__*/function () {
70
71
  // TODO: ED-26957 - why shouldn't this be leading?
71
72
  trailing: true
72
73
  }));
74
+ /**
75
+ * Updates the number of commits sent since connect/reconnect
76
+ * This is used to track the number of commits sent to the server.
77
+ * currently we are validating the first steps from a user after connect/reconnect - CEPS-710
78
+ */
79
+ _defineProperty(this, "setNumberOfCommitsSent", function (steps) {
80
+ _this.numberOfStepCommitsSent = steps;
81
+ });
73
82
  /**
74
83
  * Called when:
75
84
  * * session established(offline -> online)
@@ -107,7 +116,7 @@ export var DocumentService = /*#__PURE__*/function () {
107
116
  analyticsHelper: _this.analyticsHelper,
108
117
  clientId: _this.clientId,
109
118
  onStepsAdded: _this.onStepsAdded,
110
- catchUpOutofSync: _this.catchUpOutofSync,
119
+ catchUpOutofSync: reason === CatchupEventReason.CORRUPT_STEP ? true : _this.catchUpOutofSync,
111
120
  reason: reason,
112
121
  onCatchupComplete: function onCatchupComplete(steps) {
113
122
  // We want to capture the number of steps made while offline vs. online
@@ -964,7 +973,9 @@ export var DocumentService = /*#__PURE__*/function () {
964
973
  __livePage: this.options.__livePage,
965
974
  hasRecovered: this.hasRecovered,
966
975
  collabMode: this.participantsService.getCollabMode(),
967
- reason: reason
976
+ reason: reason,
977
+ numberOfStepCommitsSent: this.numberOfStepCommitsSent,
978
+ setNumberOfCommitsSent: this.setNumberOfCommitsSent
968
979
  });
969
980
  }
970
981
  }]);
@@ -10,6 +10,7 @@ export var NullDocumentService = /*#__PURE__*/function () {
10
10
  return _this;
11
11
  });
12
12
  _defineProperty(this, "onErrorHandled", function () {});
13
+ _defineProperty(this, "setNumberOfCommitsSent", function () {});
13
14
  }
14
15
  return _createClass(NullDocumentService, [{
15
16
  key: "updateDocument",
@@ -18,6 +18,7 @@ export var NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_CODE) {
18
18
  NCS_ERROR_CODE["INVALID_CLOUD_ID"] = "INVALID_CLOUD_ID";
19
19
  NCS_ERROR_CODE["RATE_LIMIT_ERROR"] = "RATE_LIMIT_ERROR";
20
20
  NCS_ERROR_CODE["PROSEMIRROR_SCHEMA_VALIDATION_ERROR"] = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR";
21
+ NCS_ERROR_CODE["CORRUPT_STEP_FAILED_TO_SAVE"] = "CORRUPT_STEP_FAILED_TO_SAVE";
21
22
  return NCS_ERROR_CODE;
22
23
  }({});
23
24
 
@@ -45,5 +45,6 @@ export var CatchupEventReason = /*#__PURE__*/function (CatchupEventReason) {
45
45
  CatchupEventReason["STEPS_REJECTED"] = "onStepsRejected";
46
46
  CatchupEventReason["PROCESS_STEPS"] = "processSteps";
47
47
  CatchupEventReason["RECONNECTED"] = "reconnected";
48
+ CatchupEventReason["CORRUPT_STEP"] = "corruptStep";
48
49
  return CatchupEventReason;
49
50
  }({});
@@ -3,6 +3,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
3
3
  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) { _defineProperty(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; }
4
4
  import countBy from 'lodash/countBy';
5
5
  import { fg } from '@atlaskit/platform-feature-flags';
6
+ import FeatureGates from '@atlaskit/feature-gate-js-client';
6
7
  import { ADD_STEPS_TYPE, EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
7
8
  import { AcknowledgementResponseTypes } from '../types';
8
9
  import { NCS_ERROR_CODE } from '../errors/ncs-errors';
@@ -24,7 +25,9 @@ export var commitStepQueue = function commitStepQueue(_ref) {
24
25
  __livePage = _ref.__livePage,
25
26
  hasRecovered = _ref.hasRecovered,
26
27
  collabMode = _ref.collabMode,
27
- reason = _ref.reason;
28
+ reason = _ref.reason,
29
+ numberOfStepCommitsSent = _ref.numberOfStepCommitsSent,
30
+ setNumberOfCommitsSent = _ref.setNumberOfCommitsSent;
28
31
  // this timer is for waiting to send the next batch in between acks from the BE
29
32
  var commitWaitTimer;
30
33
  // if publishing and not waiting for an ACK, then clear the commit timer and proceed, skipping the timer
@@ -94,11 +97,17 @@ export var commitStepQueue = function commitStepQueue(_ref) {
94
97
  version: version
95
98
  });
96
99
  try {
100
+ var _FeatureGates$getExpe;
101
+ var n = (_FeatureGates$getExpe = FeatureGates.getExperimentValue('validate-first-n-steps-experiment', 'steps', 0)) !== null && _FeatureGates$getExpe !== void 0 ? _FeatureGates$getExpe : 0;
102
+ var isExperimentEnabled = n > 0;
103
+ // skip validation if FG is on and we have already sent n steps, or if FG is off
104
+ var skipValidation = isExperimentEnabled ? numberOfStepCommitsSent >= n : true;
97
105
  broadcast('steps:commit', {
98
106
  collabMode: collabMode,
99
107
  steps: stepsWithClientAndUserId,
100
108
  version: version,
101
- userId: userId
109
+ userId: userId,
110
+ skipValidation: skipValidation
102
111
  }, function (response) {
103
112
  lastBroadcastRequestAcked = true;
104
113
  var latency = new Date().getTime() - start;
@@ -143,6 +152,9 @@ export var commitStepQueue = function commitStepQueue(_ref) {
143
152
  });
144
153
  }
145
154
  });
155
+ if (isExperimentEnabled && numberOfStepCommitsSent < n) {
156
+ setNumberOfCommitsSent(numberOfStepCommitsSent + 1);
157
+ }
146
158
  } catch (error) {
147
159
  // if the broadcast failed for any reason, we shouldn't keep the queue locked as the BE has not recieved any message
148
160
  readyToCommit = true;
@@ -110,6 +110,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
110
110
  initial: !initialized
111
111
  });
112
112
  var unconfirmedStepsLength = (_this$documentService = _this.documentService.getUnconfirmedSteps()) === null || _this$documentService === void 0 ? void 0 : _this$documentService.length;
113
+ _this.documentService.setNumberOfCommitsSent(0);
113
114
 
114
115
  // if buffering is enabled and the provider is initialized before connection,
115
116
  // send any unconfirmed steps
@@ -206,12 +207,14 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
206
207
  * @param {InternalError} error The error to handle
207
208
  */
208
209
  _defineProperty(_this, "onErrorHandled", function (error) {
209
- var _error$data, _error$data2;
210
+ var _error$data, _error$data2, _error$data3;
210
211
  // User tried committing steps but they were rejected because:
211
212
  // HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
212
213
  // VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
213
214
  if (((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) === NCS_ERROR_CODE.HEAD_VERSION_UPDATE_FAILED || ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.code) === NCS_ERROR_CODE.VERSION_NUMBER_ALREADY_EXISTS) {
214
215
  _this.documentService.onStepRejectedError();
216
+ } else if (((_error$data3 = error.data) === null || _error$data3 === void 0 ? void 0 : _error$data3.code) === NCS_ERROR_CODE.CORRUPT_STEP_FAILED_TO_SAVE) {
217
+ _this.documentService.throttledCatchupv2(CatchupEventReason.CORRUPT_STEP);
215
218
  } else {
216
219
  var _this$analyticsHelper2;
217
220
  (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 || _this$analyticsHelper2.sendErrorEvent(error, 'Error handled');
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/collab-provider";
2
- export var version = "10.10.2";
2
+ export var version = "10.11.0";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -31,6 +31,7 @@ export declare class DocumentService implements DocumentServiceInterface {
31
31
  private aggressiveCatchup;
32
32
  private catchUpOutofSync;
33
33
  private hasRecovered;
34
+ private numberOfStepCommitsSent;
34
35
  private clientId?;
35
36
  onErrorHandled: (error: InternalError) => void;
36
37
  /**
@@ -56,6 +57,12 @@ export declare class DocumentService implements DocumentServiceInterface {
56
57
  * @param reason - optional reason to attach.
57
58
  */
58
59
  throttledCatchupv2: import("lodash").DebouncedFunc<(reason?: CatchupEventReason, reconnectionMetadata?: ReconnectionMetadata) => Promise<void>>;
60
+ /**
61
+ * Updates the number of commits sent since connect/reconnect
62
+ * This is used to track the number of commits sent to the server.
63
+ * currently we are validating the first steps from a user after connect/reconnect - CEPS-710
64
+ */
65
+ setNumberOfCommitsSent: (steps: number) => void;
59
66
  /**
60
67
  * Called when:
61
68
  * * session established(offline -> online)
@@ -16,4 +16,5 @@ export declare class NullDocumentService implements DocumentServiceInterface {
16
16
  getUnconfirmedSteps(): undefined;
17
17
  getCurrentPmVersion(): number;
18
18
  onErrorHandled: () => void;
19
+ setNumberOfCommitsSent: () => void;
19
20
  }
@@ -16,7 +16,8 @@ export declare enum NCS_ERROR_CODE {
16
16
  INVALID_DOCUMENT_ARI = "INVALID_DOCUMENT_ARI",
17
17
  INVALID_CLOUD_ID = "INVALID_CLOUD_ID",
18
18
  RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
19
- PROSEMIRROR_SCHEMA_VALIDATION_ERROR = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR"
19
+ PROSEMIRROR_SCHEMA_VALIDATION_ERROR = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR",
20
+ CORRUPT_STEP_FAILED_TO_SAVE = "CORRUPT_STEP_FAILED_TO_SAVE"
20
21
  }
21
22
  type HeadVersionUpdateFailedError = {
22
23
  message: string;
@@ -163,6 +164,14 @@ type InvalidCloudIdError = {
163
164
  status: number;
164
165
  };
165
166
  };
167
+ type CorruptStepFailedToApplyError = {
168
+ message: string;
169
+ data: {
170
+ code: NCS_ERROR_CODE.CORRUPT_STEP_FAILED_TO_SAVE;
171
+ meta: string;
172
+ status: number;
173
+ };
174
+ };
166
175
  /**
167
176
  * The client is trying to send too many messages or messages that are too large. This not expected to be a standard
168
177
  * operating condition and should only ever indicate a frontend bug.
@@ -180,5 +189,5 @@ export type RateLimitError = {
180
189
  status: 500;
181
190
  };
182
191
  };
183
- export type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError | RateLimitError | ProsemirrorSchemaValidationError;
192
+ export type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError | RateLimitError | ProsemirrorSchemaValidationError | CorruptStepFailedToApplyError;
184
193
  export {};
@@ -303,6 +303,7 @@ export declare enum CatchupEventReason {
303
303
  STEPS_ADDED = "onStepsAdded",
304
304
  STEPS_REJECTED = "onStepsRejected",
305
305
  PROCESS_STEPS = "processSteps",
306
- RECONNECTED = "reconnected"
306
+ RECONNECTED = "reconnected",
307
+ CORRUPT_STEP = "corruptStep"
307
308
  }
308
309
  export {};
@@ -7,7 +7,7 @@ import type { GetResolvedEditorStateReason } from '@atlaskit/editor-common/types
7
7
  export declare let readyToCommit: boolean;
8
8
  export declare let lastBroadcastRequestAcked: boolean;
9
9
  export declare const RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
10
- export declare const commitStepQueue: ({ broadcast, steps, version, userId, clientId, onStepsAdded, onErrorHandled, analyticsHelper, emit, __livePage, hasRecovered, collabMode, reason, }: {
10
+ export declare const commitStepQueue: ({ broadcast, steps, version, userId, clientId, onStepsAdded, onErrorHandled, analyticsHelper, emit, __livePage, hasRecovered, collabMode, reason, numberOfStepCommitsSent, setNumberOfCommitsSent, }: {
11
11
  broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void;
12
12
  steps: readonly ProseMirrorStep[];
13
13
  version: number;
@@ -21,4 +21,6 @@ export declare const commitStepQueue: ({ broadcast, steps, version, userId, clie
21
21
  hasRecovered: boolean;
22
22
  collabMode: string;
23
23
  reason?: GetResolvedEditorStateReason | undefined;
24
+ numberOfStepCommitsSent: number;
25
+ setNumberOfCommitsSent: (steps: number) => void;
24
26
  }) => void;
@@ -185,6 +185,7 @@ export type ChannelEvent = {
185
185
  userId: string;
186
186
  collabMode: string;
187
187
  forcePublish?: boolean;
188
+ skipValidation: boolean;
188
189
  };
189
190
  'steps:added': StepsPayload;
190
191
  'metadata:changed': Metadata;
@@ -31,6 +31,7 @@ export declare class DocumentService implements DocumentServiceInterface {
31
31
  private aggressiveCatchup;
32
32
  private catchUpOutofSync;
33
33
  private hasRecovered;
34
+ private numberOfStepCommitsSent;
34
35
  private clientId?;
35
36
  onErrorHandled: (error: InternalError) => void;
36
37
  /**
@@ -56,6 +57,12 @@ export declare class DocumentService implements DocumentServiceInterface {
56
57
  * @param reason - optional reason to attach.
57
58
  */
58
59
  throttledCatchupv2: import("lodash").DebouncedFunc<(reason?: CatchupEventReason, reconnectionMetadata?: ReconnectionMetadata) => Promise<void>>;
60
+ /**
61
+ * Updates the number of commits sent since connect/reconnect
62
+ * This is used to track the number of commits sent to the server.
63
+ * currently we are validating the first steps from a user after connect/reconnect - CEPS-710
64
+ */
65
+ setNumberOfCommitsSent: (steps: number) => void;
59
66
  /**
60
67
  * Called when:
61
68
  * * session established(offline -> online)
@@ -16,4 +16,5 @@ export declare class NullDocumentService implements DocumentServiceInterface {
16
16
  getUnconfirmedSteps(): undefined;
17
17
  getCurrentPmVersion(): number;
18
18
  onErrorHandled: () => void;
19
+ setNumberOfCommitsSent: () => void;
19
20
  }
@@ -16,7 +16,8 @@ export declare enum NCS_ERROR_CODE {
16
16
  INVALID_DOCUMENT_ARI = "INVALID_DOCUMENT_ARI",
17
17
  INVALID_CLOUD_ID = "INVALID_CLOUD_ID",
18
18
  RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
19
- PROSEMIRROR_SCHEMA_VALIDATION_ERROR = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR"
19
+ PROSEMIRROR_SCHEMA_VALIDATION_ERROR = "PROSEMIRROR_SCHEMA_VALIDATION_ERROR",
20
+ CORRUPT_STEP_FAILED_TO_SAVE = "CORRUPT_STEP_FAILED_TO_SAVE"
20
21
  }
21
22
  type HeadVersionUpdateFailedError = {
22
23
  message: string;
@@ -163,6 +164,14 @@ type InvalidCloudIdError = {
163
164
  status: number;
164
165
  };
165
166
  };
167
+ type CorruptStepFailedToApplyError = {
168
+ message: string;
169
+ data: {
170
+ code: NCS_ERROR_CODE.CORRUPT_STEP_FAILED_TO_SAVE;
171
+ meta: string;
172
+ status: number;
173
+ };
174
+ };
166
175
  /**
167
176
  * The client is trying to send too many messages or messages that are too large. This not expected to be a standard
168
177
  * operating condition and should only ever indicate a frontend bug.
@@ -180,5 +189,5 @@ export type RateLimitError = {
180
189
  status: 500;
181
190
  };
182
191
  };
183
- export type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError | RateLimitError | ProsemirrorSchemaValidationError;
192
+ export type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError | RateLimitError | ProsemirrorSchemaValidationError | CorruptStepFailedToApplyError;
184
193
  export {};
@@ -303,6 +303,7 @@ export declare enum CatchupEventReason {
303
303
  STEPS_ADDED = "onStepsAdded",
304
304
  STEPS_REJECTED = "onStepsRejected",
305
305
  PROCESS_STEPS = "processSteps",
306
- RECONNECTED = "reconnected"
306
+ RECONNECTED = "reconnected",
307
+ CORRUPT_STEP = "corruptStep"
307
308
  }
308
309
  export {};
@@ -7,7 +7,7 @@ import type { GetResolvedEditorStateReason } from '@atlaskit/editor-common/types
7
7
  export declare let readyToCommit: boolean;
8
8
  export declare let lastBroadcastRequestAcked: boolean;
9
9
  export declare const RESET_READYTOCOMMIT_INTERVAL_MS = 5000;
10
- export declare const commitStepQueue: ({ broadcast, steps, version, userId, clientId, onStepsAdded, onErrorHandled, analyticsHelper, emit, __livePage, hasRecovered, collabMode, reason, }: {
10
+ export declare const commitStepQueue: ({ broadcast, steps, version, userId, clientId, onStepsAdded, onErrorHandled, analyticsHelper, emit, __livePage, hasRecovered, collabMode, reason, numberOfStepCommitsSent, setNumberOfCommitsSent, }: {
11
11
  broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void;
12
12
  steps: readonly ProseMirrorStep[];
13
13
  version: number;
@@ -21,4 +21,6 @@ export declare const commitStepQueue: ({ broadcast, steps, version, userId, clie
21
21
  hasRecovered: boolean;
22
22
  collabMode: string;
23
23
  reason?: GetResolvedEditorStateReason | undefined;
24
+ numberOfStepCommitsSent: number;
25
+ setNumberOfCommitsSent: (steps: number) => void;
24
26
  }) => void;
@@ -185,6 +185,7 @@ export type ChannelEvent = {
185
185
  userId: string;
186
186
  collabMode: string;
187
187
  forcePublish?: boolean;
188
+ skipValidation: boolean;
188
189
  };
189
190
  'steps:added': StepsPayload;
190
191
  'metadata:changed': Metadata;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "10.10.2",
3
+ "version": "10.11.0",
4
4
  "description": "A provider for collaborative editing.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"