@atlaskit/collab-provider 9.3.1 → 9.4.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 (36) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/analytics/analytics-helper.js +7 -2
  3. package/dist/cjs/channel.js +26 -20
  4. package/dist/cjs/document/document-service.js +60 -11
  5. package/dist/cjs/errors/error-code-mapper.js +7 -0
  6. package/dist/cjs/errors/error-types.js +31 -5
  7. package/dist/cjs/provider/index.js +52 -38
  8. package/dist/cjs/version-wrapper.js +1 -1
  9. package/dist/cjs/version.json +1 -1
  10. package/dist/es2019/analytics/analytics-helper.js +7 -1
  11. package/dist/es2019/channel.js +13 -7
  12. package/dist/es2019/document/document-service.js +61 -15
  13. package/dist/es2019/errors/error-code-mapper.js +7 -0
  14. package/dist/es2019/errors/error-types.js +20 -2
  15. package/dist/es2019/provider/index.js +52 -38
  16. package/dist/es2019/version-wrapper.js +1 -1
  17. package/dist/es2019/version.json +1 -1
  18. package/dist/esm/analytics/analytics-helper.js +7 -2
  19. package/dist/esm/channel.js +26 -20
  20. package/dist/esm/document/document-service.js +61 -12
  21. package/dist/esm/errors/error-code-mapper.js +7 -0
  22. package/dist/esm/errors/error-types.js +30 -4
  23. package/dist/esm/provider/index.js +52 -38
  24. package/dist/esm/version-wrapper.js +1 -1
  25. package/dist/esm/version.json +1 -1
  26. package/dist/types/document/document-service.d.ts +4 -1
  27. package/dist/types/errors/error-types.d.ts +47 -7
  28. package/dist/types/helpers/const.d.ts +8 -1
  29. package/dist/types/types.d.ts +5 -0
  30. package/dist/types-ts4.5/document/document-service.d.ts +4 -1
  31. package/dist/types-ts4.5/errors/error-types.d.ts +47 -7
  32. package/dist/types-ts4.5/helpers/const.d.ts +8 -1
  33. package/dist/types-ts4.5/types.d.ts +5 -0
  34. package/package.json +1 -1
  35. package/report.api.md +13 -1
  36. package/tmp/api-report-tmp.d.ts +12 -1
@@ -15,7 +15,7 @@ import { JSONTransformer } from '@atlaskit/editor-json-transformer';
15
15
  import { MAX_STEP_REJECTED_ERROR } from '../provider';
16
16
  import { catchup } from './catchup';
17
17
  import { StepQueueState } from './step-queue-state';
18
- import { INTERNAL_ERROR_CODE } from '../errors/error-types';
18
+ import { INTERNAL_ERROR_CODE, UpdateDocumentError } from '../errors/error-types';
19
19
  var CATCHUP_THROTTLE = 1 * 1000; // 1 second
20
20
 
21
21
  var noop = function noop() {};
@@ -35,10 +35,12 @@ export var DocumentService = /*#__PURE__*/function () {
35
35
  * @param onErrorHandled - Callback to handle
36
36
  * @param metadataService
37
37
  * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
38
+ * @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
38
39
  */
39
40
  function DocumentService(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
40
41
  var _this = this;
41
42
  var failedStepsBeforeCatchupOnPublish = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : MAX_STEP_REJECTED_ERROR;
43
+ var enableErrorOnFailedDocumentApply = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false;
42
44
  _classCallCheck(this, DocumentService);
43
45
  // Fires analytics to editor when collab editor cannot sync up
44
46
  _defineProperty(this, "stepRejectCounter", 0);
@@ -321,13 +323,59 @@ export var DocumentService = /*#__PURE__*/function () {
321
323
  }, reserveCursor ? {
322
324
  reserveCursor: reserveCursor
323
325
  } : {}));
326
+ var updatedVersion = _this.getCurrentPmVersion();
327
+ if (_this.getCurrentPmVersion() !== version) {
328
+ var _doc$content, _this$analyticsHelper17;
329
+ var isDocContentValid = _this.validatePMJSONDocument(doc);
330
+ var _error = new UpdateDocumentError('Failed to update the document', {
331
+ newVersion: version,
332
+ editorVersion: updatedVersion,
333
+ isDocTruthy: !!doc,
334
+ docHasContent: (doc === null || doc === void 0 ? void 0 : (_doc$content = doc.content) === null || _doc$content === void 0 ? void 0 : _doc$content.length) >= 1,
335
+ isDocContentValid: isDocContentValid
336
+ });
337
+ (_this$analyticsHelper17 = _this.analyticsHelper) === null || _this$analyticsHelper17 === void 0 ? void 0 : _this$analyticsHelper17.sendErrorEvent(_error, 'Failed to update the document in document service');
338
+ if (_this.enableErrorOnFailedDocumentApply) {
339
+ _this.onErrorHandled({
340
+ message: 'The provider failed to apply changes to the editor',
341
+ data: {
342
+ code: INTERNAL_ERROR_CODE.DOCUMENT_UPDATE_ERROR,
343
+ meta: {
344
+ newVersion: version,
345
+ editorVersion: updatedVersion
346
+ },
347
+ status: 500
348
+ }
349
+ });
350
+ throw _error;
351
+ }
352
+ // Otherwise just fail silently for now
353
+ }
354
+ });
355
+ _defineProperty(this, "validatePMJSONDocument", function (doc) {
356
+ try {
357
+ var state = _this.getState();
358
+ var content = (doc.content || []).map(function (child) {
359
+ return state.schema.nodeFromJSON(child);
360
+ });
361
+ return content.every(function (node) {
362
+ try {
363
+ node.check(); // this will throw an error if the node is invalid
364
+ } catch (error) {
365
+ return false;
366
+ }
367
+ return true;
368
+ });
369
+ } catch (e) {
370
+ return false;
371
+ }
324
372
  });
325
373
  /**
326
374
  * Commit the unconfirmed local steps to the back-end service
327
375
  * @throws {Error} Couldn't sync the steps after retrying 30 times
328
376
  */
329
377
  _defineProperty(this, "commitUnconfirmedSteps", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
330
- var unconfirmedSteps, _this$analyticsHelper18, count, unconfirmedTrs, lastTr, isLastTrConfirmed, nextUnconfirmedSteps, nextUnconfirmedTrs, _this$getUnconfirmedS, _this$analyticsHelper17, state, unconfirmedStepsInfoUGCRemoved, measure, _this$analyticsHelper19, _this$analyticsHelper20, _measure3;
378
+ var unconfirmedSteps, _this$analyticsHelper19, count, unconfirmedTrs, lastTr, isLastTrConfirmed, nextUnconfirmedSteps, nextUnconfirmedTrs, _this$getUnconfirmedS, _this$analyticsHelper18, state, unconfirmedStepsInfoUGCRemoved, measure, _this$analyticsHelper20, _this$analyticsHelper21, _measure3;
331
379
  return _regeneratorRuntime.wrap(function _callee4$(_context4) {
332
380
  while (1) switch (_context4.prev = _context4.next) {
333
381
  case 0:
@@ -380,7 +428,7 @@ export var DocumentService = /*#__PURE__*/function () {
380
428
  unconfirmedStepsInfoUGCRemoved = (_this$getUnconfirmedS = _this.getUnconfirmedSteps()) === null || _this$getUnconfirmedS === void 0 ? void 0 : _this$getUnconfirmedS.map(function (step) {
381
429
  return getStepUGCFreeDetails(step);
382
430
  });
383
- (_this$analyticsHelper17 = _this.analyticsHelper) === null || _this$analyticsHelper17 === void 0 ? void 0 : _this$analyticsHelper17.sendErrorEvent({
431
+ (_this$analyticsHelper18 = _this.analyticsHelper) === null || _this$analyticsHelper18 === void 0 ? void 0 : _this$analyticsHelper18.sendErrorEvent({
384
432
  unconfirmedStepsInfo: unconfirmedStepsInfoUGCRemoved
385
433
  }, "Can't sync up with Collab Service: unable to send unconfirmed steps and max retry reached");
386
434
  throw new Error("Can't sync up with Collab Service");
@@ -389,7 +437,7 @@ export var DocumentService = /*#__PURE__*/function () {
389
437
  break;
390
438
  case 21:
391
439
  measure = stopMeasure(MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
392
- (_this$analyticsHelper18 = _this.analyticsHelper) === null || _this$analyticsHelper18 === void 0 ? void 0 : _this$analyticsHelper18.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.SUCCESS, {
440
+ (_this$analyticsHelper19 = _this.analyticsHelper) === null || _this$analyticsHelper19 === void 0 ? void 0 : _this$analyticsHelper19.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.SUCCESS, {
393
441
  latency: measure === null || measure === void 0 ? void 0 : measure.duration,
394
442
  // upon success, emit the total number of unconfirmed steps we synced
395
443
  numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
@@ -401,11 +449,11 @@ export var DocumentService = /*#__PURE__*/function () {
401
449
  _context4.prev = 25;
402
450
  _context4.t0 = _context4["catch"](1);
403
451
  _measure3 = stopMeasure(MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
404
- (_this$analyticsHelper19 = _this.analyticsHelper) === null || _this$analyticsHelper19 === void 0 ? void 0 : _this$analyticsHelper19.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.FAILURE, {
452
+ (_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.FAILURE, {
405
453
  latency: _measure3 === null || _measure3 === void 0 ? void 0 : _measure3.duration,
406
454
  numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
407
455
  });
408
- (_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendErrorEvent(_context4.t0, 'Error while committing unconfirmed steps');
456
+ (_this$analyticsHelper21 = _this.analyticsHelper) === null || _this$analyticsHelper21 === void 0 ? void 0 : _this$analyticsHelper21.sendErrorEvent(_context4.t0, 'Error while committing unconfirmed steps');
409
457
  throw _context4.t0;
410
458
  case 31:
411
459
  case "end":
@@ -414,17 +462,17 @@ export var DocumentService = /*#__PURE__*/function () {
414
462
  }, _callee4, null, [[1, 25]]);
415
463
  })));
416
464
  _defineProperty(this, "onStepRejectedError", function () {
417
- var _this$analyticsHelper21;
465
+ var _this$analyticsHelper22;
418
466
  _this.stepRejectCounter++;
419
467
  logger("Steps rejected (tries=".concat(_this.stepRejectCounter, ")"));
420
- (_this$analyticsHelper21 = _this.analyticsHelper) === null || _this$analyticsHelper21 === void 0 ? void 0 : _this$analyticsHelper21.sendActionEvent(EVENT_ACTION.SEND_STEPS_RETRY, EVENT_STATUS.INFO, {
468
+ (_this$analyticsHelper22 = _this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendActionEvent(EVENT_ACTION.SEND_STEPS_RETRY, EVENT_STATUS.INFO, {
421
469
  count: _this.stepRejectCounter
422
470
  });
423
471
  var maxRetries = _this.aggressiveCatchup ? _this.failedStepsBeforeCatchupOnPublish : MAX_STEP_REJECTED_ERROR;
424
472
  if (_this.stepRejectCounter >= maxRetries) {
425
- var _this$analyticsHelper22;
473
+ var _this$analyticsHelper23;
426
474
  logger("The steps were rejected too many times (tries=".concat(_this.stepRejectCounter, ", limit=").concat(MAX_STEP_REJECTED_ERROR, "). Trying to catch-up."));
427
- (_this$analyticsHelper22 = _this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendActionEvent(EVENT_ACTION.CATCHUP_AFTER_MAX_SEND_STEPS_RETRY, EVENT_STATUS.INFO);
475
+ (_this$analyticsHelper23 = _this.analyticsHelper) === null || _this$analyticsHelper23 === void 0 ? void 0 : _this$analyticsHelper23.sendActionEvent(EVENT_ACTION.CATCHUP_AFTER_MAX_SEND_STEPS_RETRY, EVENT_STATUS.INFO);
428
476
  _this.throttledCatchup();
429
477
  } else {
430
478
  // If committing steps failed try again automatically in 1s
@@ -445,6 +493,7 @@ export var DocumentService = /*#__PURE__*/function () {
445
493
  this.onErrorHandled = onErrorHandled;
446
494
  this.metadataService = metadataService;
447
495
  this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
496
+ this.enableErrorOnFailedDocumentApply = enableErrorOnFailedDocumentApply;
448
497
  this.stepQueue = new StepQueueState();
449
498
  }
450
499
  _createClass(DocumentService, [{
@@ -496,9 +545,9 @@ export var DocumentService = /*#__PURE__*/function () {
496
545
  }, 100);
497
546
  }
498
547
  } catch (error) {
499
- var _this$analyticsHelper23;
548
+ var _this$analyticsHelper24;
500
549
  logger("Processing steps failed with error: ".concat(error, ". Triggering catch up call."));
501
- (_this$analyticsHelper23 = this.analyticsHelper) === null || _this$analyticsHelper23 === void 0 ? void 0 : _this$analyticsHelper23.sendErrorEvent(error, 'Error while processing steps');
550
+ (_this$analyticsHelper24 = this.analyticsHelper) === null || _this$analyticsHelper24 === void 0 ? void 0 : _this$analyticsHelper24.sendErrorEvent(error, 'Error while processing steps');
502
551
  this.throttledCatchup();
503
552
  }
504
553
  }
@@ -67,6 +67,13 @@ export var errorCodeMapper = function errorCodeMapper(error) {
67
67
  recoverable: false,
68
68
  status: 500
69
69
  };
70
+ case INTERNAL_ERROR_CODE.DOCUMENT_UPDATE_ERROR:
71
+ return {
72
+ code: PROVIDER_ERROR_CODE.DOCUMENT_UPDATE_ERROR,
73
+ message: 'The provider failed to apply changes to the editor',
74
+ recoverable: false,
75
+ status: 500
76
+ };
70
77
  case INTERNAL_ERROR_CODE.RECONNECTION_NETWORK_ISSUE:
71
78
  return {
72
79
  code: PROVIDER_ERROR_CODE.NETWORK_ISSUE,
@@ -1,14 +1,15 @@
1
- import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
2
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
3
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4
2
  import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
5
4
  import _inherits from "@babel/runtime/helpers/inherits";
6
5
  import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
7
6
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
8
7
  import _wrapNativeSuper from "@babel/runtime/helpers/wrapNativeSuper";
8
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
9
9
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
10
10
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
11
11
  // Internal error codes (generated by collab provider)
12
+
12
13
  export var INTERNAL_ERROR_CODE = /*#__PURE__*/function (INTERNAL_ERROR_CODE) {
13
14
  INTERNAL_ERROR_CODE["TOKEN_PERMISSION_ERROR"] = "TOKEN_PERMISSION_ERROR";
14
15
  INTERNAL_ERROR_CODE["RECONNECTION_NETWORK_ISSUE"] = "RECONNECTION_NETWORK_ISSUE";
@@ -18,8 +19,10 @@ export var INTERNAL_ERROR_CODE = /*#__PURE__*/function (INTERNAL_ERROR_CODE) {
18
19
  INTERNAL_ERROR_CODE["CATCHUP_FAILED"] = "CATCHUP_FAILED";
19
20
  INTERNAL_ERROR_CODE["DOCUMENT_RESTORE_ERROR"] = "DOCUMENT_RESTORE_ERROR";
20
21
  INTERNAL_ERROR_CODE["ADD_STEPS_ERROR"] = "ADD_STEPS_ERROR";
22
+ INTERNAL_ERROR_CODE["DOCUMENT_UPDATE_ERROR"] = "DOCUMENT_UPDATE_ERROR";
21
23
  return INTERNAL_ERROR_CODE;
22
24
  }({});
25
+
23
26
  // NCS error coded (generated by NCS)
24
27
  export var NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_CODE) {
25
28
  NCS_ERROR_CODE["HEAD_VERSION_UPDATE_FAILED"] = "HEAD_VERSION_UPDATE_FAILED";
@@ -51,6 +54,10 @@ export var NCS_ERROR_CODE = /*#__PURE__*/function (NCS_ERROR_CODE) {
51
54
  // - Less common back-end errors
52
55
  // Provider Errors
53
56
  // Channel Errors
57
+ /**
58
+ * When we try to apply state updates to the editor, if that fails to apply the user can enter an invalid state where no
59
+ * changes can be saved to NCS.
60
+ */
54
61
  /**
55
62
  * A union of all possible internal errors, that are mapped to another error if being emitted to the editor.
56
63
  */
@@ -66,6 +73,7 @@ export var PROVIDER_ERROR_CODE = /*#__PURE__*/function (PROVIDER_ERROR_CODE) {
66
73
  PROVIDER_ERROR_CODE["NETWORK_ISSUE"] = "NETWORK_ISSUE";
67
74
  PROVIDER_ERROR_CODE["INVALID_PROVIDER_CONFIGURATION"] = "INVALID_PROVIDER_CONFIGURATION";
68
75
  PROVIDER_ERROR_CODE["INTERNAL_SERVICE_ERROR"] = "INTERNAL_SERVICE_ERROR";
76
+ PROVIDER_ERROR_CODE["DOCUMENT_UPDATE_ERROR"] = "DOCUMENT_UPDATE_ERROR";
69
77
  return PROVIDER_ERROR_CODE;
70
78
  }({});
71
79
 
@@ -163,16 +171,22 @@ export var PROVIDER_ERROR_CODE = /*#__PURE__*/function (PROVIDER_ERROR_CODE) {
163
171
  * A union of all possible provider errors that can be emitted back to the editor.
164
172
  */
165
173
  // Custom Errors
166
- var CustomError = /*#__PURE__*/function (_Error) {
174
+ export var CustomError = /*#__PURE__*/function (_Error) {
167
175
  _inherits(CustomError, _Error);
168
176
  var _super = _createSuper(CustomError);
169
- function CustomError(message, error) {
177
+ function CustomError(message, error, extraEventAttributes) {
170
178
  var _this;
171
179
  _classCallCheck(this, CustomError);
172
180
  _this = _super.call(this, message);
181
+ _defineProperty(_assertThisInitialized(_this), "getExtraErrorEventAttributes", function () {
182
+ return _this.extraEventAttributes;
183
+ });
173
184
  if (typeof (error === null || error === void 0 ? void 0 : error.message) === 'string') {
174
185
  _this.message = error.message;
175
186
  }
187
+ if (extraEventAttributes) {
188
+ _this.extraEventAttributes = extraEventAttributes;
189
+ }
176
190
  return _this;
177
191
  }
178
192
  _createClass(CustomError, [{
@@ -335,4 +349,16 @@ export var GetFinalAcknowledgedStateError = /*#__PURE__*/function (_CustomError1
335
349
  return _this11;
336
350
  }
337
351
  return _createClass(GetFinalAcknowledgedStateError);
352
+ }(CustomError);
353
+ export var UpdateDocumentError = /*#__PURE__*/function (_CustomError11) {
354
+ _inherits(UpdateDocumentError, _CustomError11);
355
+ var _super12 = _createSuper(UpdateDocumentError);
356
+ function UpdateDocumentError(message, extraAttributes) {
357
+ var _this12;
358
+ _classCallCheck(this, UpdateDocumentError);
359
+ _this12 = _super12.call(this, message, undefined, extraAttributes);
360
+ _defineProperty(_assertThisInitialized(_this12), "name", 'UpdateDocumentError');
361
+ return _this12;
362
+ }
363
+ return _createClass(UpdateDocumentError);
338
364
  }(CustomError);
@@ -81,12 +81,19 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
81
81
  document = _this$initialDraft.document,
82
82
  version = _this$initialDraft.version,
83
83
  metadata = _this$initialDraft.metadata;
84
- // Initial document, version, metadata from initial draft
85
- _this.documentService.updateDocument({
86
- doc: document,
87
- version: version,
88
- metadata: metadata
89
- });
84
+ try {
85
+ // Initial document, version, metadata from initial draft
86
+ _this.documentService.updateDocument({
87
+ doc: document,
88
+ version: version,
89
+ metadata: metadata
90
+ });
91
+ } catch (e) {
92
+ var _this$analyticsHelper;
93
+ (_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendErrorEvent(e, 'Failed to update the document on reconnect, destroying provider');
94
+ // Stop events and connections to step us trying to talk to the backend with an invalid state.
95
+ _this.destroy();
96
+ }
90
97
  _this.metadataService.updateMetadata(metadata);
91
98
  }
92
99
  _this.isProviderInitialized = true;
@@ -104,13 +111,20 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
104
111
  version = _ref2.version,
105
112
  metadata = _ref2.metadata;
106
113
  // Initial document and version
107
- _this.documentService.updateDocument({
108
- doc: doc,
109
- version: version,
110
- metadata: metadata
111
- });
112
- _this.metadataService.updateMetadata(metadata);
113
- _this.isProviderInitialized = true;
114
+ try {
115
+ _this.documentService.updateDocument({
116
+ doc: doc,
117
+ version: version,
118
+ metadata: metadata
119
+ });
120
+ _this.metadataService.updateMetadata(metadata);
121
+ _this.isProviderInitialized = true;
122
+ } catch (e) {
123
+ var _this$analyticsHelper2;
124
+ (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(e, 'Failed to update with the init document, destroying provider');
125
+ // Stop events and connections to step us trying to talk to the backend with an invalid state.
126
+ _this.destroy();
127
+ }
114
128
  }).on('restore', _this.documentService.onRestore).on('steps:added', _this.documentService.onStepsAdded).on('metadata:changed', _this.metadataService.onMetadataChanged).on('participant:telepointer', function (payload) {
115
129
  return _this.participantsService.onParticipantTelepointer(payload, _this.sessionId);
116
130
  }).on('presence:joined', _this.participantsService.onPresenceJoined).on('presence', _this.participantsService.onPresence).on('participant:left', _this.participantsService.onParticipantLeft).on('participant:updated', _this.participantsService.onParticipantUpdated).on('disconnect', _this.onDisconnected.bind(_assertThisInitialized(_this))).on('error', _this.onErrorHandled).on('status', _this.namespaceService.onNamespaceStatusChanged).connect(shouldInitialize);
@@ -136,13 +150,13 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
136
150
  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) {
137
151
  _this.documentService.onStepRejectedError();
138
152
  } else {
139
- var _this$analyticsHelper;
140
- (_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendErrorEvent(error, 'Error handled');
153
+ var _this$analyticsHelper3;
154
+ (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(error, 'Error handled');
141
155
  var mappedError = errorCodeMapper(error);
142
156
  // Temporarily only emit errors to Confluence very intentionally because they will disconnect the collab provider
143
157
  if (mappedError) {
144
- var _this$analyticsHelper2;
145
- (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(mappedError, 'Error emitted');
158
+ var _this$analyticsHelper4;
159
+ (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(mappedError, 'Error emitted');
146
160
  _this.emitCallback('error', mappedError);
147
161
  }
148
162
  }
@@ -165,7 +179,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
165
179
  * @throws {GetCurrentStateError} Something went wrong while returning the current state
166
180
  */
167
181
  _defineProperty(_assertThisInitialized(_this), "getCurrentState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
168
- var _this$analyticsHelper3;
182
+ var _this$analyticsHelper5;
169
183
  return _regeneratorRuntime.wrap(function _callee$(_context) {
170
184
  while (1) switch (_context.prev = _context.next) {
171
185
  case 0:
@@ -174,7 +188,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
174
188
  case 4:
175
189
  _context.prev = 4;
176
190
  _context.t0 = _context["catch"](0);
177
- (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(_context.t0, 'Error while returning ADF version of current draft document');
191
+ (_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(_context.t0, 'Error while returning ADF version of current draft document');
178
192
  throw new GetCurrentStateError('Error while returning the current state of the draft document', _context.t0);
179
193
  case 8:
180
194
  case "end":
@@ -188,7 +202,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
188
202
  * @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
189
203
  */
190
204
  _defineProperty(_assertThisInitialized(_this), "getFinalAcknowledgedState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
191
- var _this$analyticsHelper4;
205
+ var _this$analyticsHelper6;
192
206
  return _regeneratorRuntime.wrap(function _callee2$(_context2) {
193
207
  while (1) switch (_context2.prev = _context2.next) {
194
208
  case 0:
@@ -200,7 +214,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
200
214
  case 6:
201
215
  _context2.prev = 6;
202
216
  _context2.t0 = _context2["catch"](0);
203
- (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(_context2.t0, 'Error while returning ADF version of the final draft document');
217
+ (_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendErrorEvent(_context2.t0, 'Error while returning ADF version of the final draft document');
204
218
  throw new GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context2.t0);
205
219
  case 10:
206
220
  case "end":
@@ -235,7 +249,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
235
249
  _this.metadataService = new MetadataService(_this.emitCallback, _this.channel.sendMetadata);
236
250
  _this.documentService = new DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
237
251
  return _this.userId;
238
- }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish);
252
+ }, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish, _this.config.enableErrorOnFailedDocumentApply);
239
253
  _this.getStatePromise = new Promise(function (resolve) {
240
254
  _this.getStatePromiseResolve = resolve;
241
255
  });
@@ -304,8 +318,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
304
318
  this.isChannelInitialized = true;
305
319
  }
306
320
  } catch (initError) {
307
- var _this$analyticsHelper5;
308
- (_this$analyticsHelper5 = this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(initError, 'Error while initialising the provider');
321
+ var _this$analyticsHelper7;
322
+ (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(initError, 'Error while initialising the provider');
309
323
  // Throw error so consumers are aware the initialisation failed when initialising themselves
310
324
  throw new ProviderInitialisationError('Provider initialisation error', initError);
311
325
  }
@@ -315,9 +329,9 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
315
329
  key: "checkForCookies",
316
330
  value: function checkForCookies() {
317
331
  if (!global.navigator.cookieEnabled) {
318
- var _this$analyticsHelper6;
332
+ var _this$analyticsHelper8;
319
333
  var initError = new ProviderInitialisationError('Cookies are not enabled. Please enable cookies to use collaborative editing.');
320
- (_this$analyticsHelper6 = this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendErrorEvent(initError, 'Error while initialising the provider - cookies disabled');
334
+ (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(initError, 'Error while initialising the provider - cookies disabled');
321
335
  throw new ProviderInitialisationError('Provider initialisation error - cookies disabled', initError);
322
336
  }
323
337
  }
@@ -355,8 +369,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
355
369
  }
356
370
  this.documentService.send(_tr, _oldState, newState);
357
371
  } catch (error) {
358
- var _this$analyticsHelper7;
359
- (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(error, 'Error while sending steps for a transaction');
372
+ var _this$analyticsHelper9;
373
+ (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(error, 'Error while sending steps for a transaction');
360
374
  throw new SendTransactionError('Error while sending steps for a transaction', error);
361
375
  }
362
376
  }
@@ -384,9 +398,9 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
384
398
  this.channel.broadcast('participant:telepointer', payload, callback);
385
399
  }
386
400
  } catch (error) {
387
- var _this$analyticsHelper8;
401
+ var _this$analyticsHelper10;
388
402
  // We don't want to throw errors for Presence features as they tend to self-restore
389
- (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(error, 'Error while sending message - telepointer');
403
+ (_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(error, 'Error while sending message - telepointer');
390
404
  }
391
405
  }
392
406
  }, {
@@ -425,8 +439,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
425
439
  _get(_getPrototypeOf(Provider.prototype), "unsubscribeAll", this).call(this);
426
440
  this.channel.disconnect();
427
441
  } catch (error) {
428
- var _this$analyticsHelper9;
429
- (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(error, 'Error while shutting down the collab provider');
442
+ var _this$analyticsHelper11;
443
+ (_this$analyticsHelper11 = this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while shutting down the collab provider');
430
444
  throw new DestroyError('Error while shutting down the collab provider', error);
431
445
  }
432
446
  this.clearTimers();
@@ -446,8 +460,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
446
460
  try {
447
461
  this.metadataService.setTitle(title, broadcast);
448
462
  } catch (error) {
449
- var _this$analyticsHelper10;
450
- (_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(error, 'Error while setting title');
463
+ var _this$analyticsHelper12;
464
+ (_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while setting title');
451
465
  throw new SetTitleError('Error while setting title', error);
452
466
  }
453
467
  }
@@ -465,8 +479,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
465
479
  try {
466
480
  this.metadataService.setEditorWidth(editorWidth, broadcast);
467
481
  } catch (error) {
468
- var _this$analyticsHelper11;
469
- (_this$analyticsHelper11 = this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while setting editor width');
482
+ var _this$analyticsHelper13;
483
+ (_this$analyticsHelper13 = this.analyticsHelper) === null || _this$analyticsHelper13 === void 0 ? void 0 : _this$analyticsHelper13.sendErrorEvent(error, 'Error while setting editor width');
470
484
  throw new SetEditorWidthError('Error while setting editor width', error);
471
485
  }
472
486
  }
@@ -482,8 +496,8 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
482
496
  try {
483
497
  this.metadataService.setMetadata(metadata);
484
498
  } catch (error) {
485
- var _this$analyticsHelper12;
486
- (_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while setting metadata');
499
+ var _this$analyticsHelper14;
500
+ (_this$analyticsHelper14 = this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendErrorEvent(error, 'Error while setting metadata');
487
501
  throw new SetMetadataError('Error while setting metadata', error);
488
502
  }
489
503
  }
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/collab-provider";
2
- export var version = "9.3.1";
2
+ export var version = "9.4.0";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "9.3.1",
3
+ "version": "9.4.0",
4
4
  "sideEffects": false
5
5
  }
@@ -17,6 +17,7 @@ export declare class DocumentService {
17
17
  private onErrorHandled;
18
18
  private metadataService;
19
19
  private failedStepsBeforeCatchupOnPublish;
20
+ private enableErrorOnFailedDocumentApply;
20
21
  private getState;
21
22
  private onSyncUpError?;
22
23
  private stepQueue;
@@ -35,8 +36,9 @@ export declare class DocumentService {
35
36
  * @param onErrorHandled - Callback to handle
36
37
  * @param metadataService
37
38
  * @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
39
+ * @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
38
40
  */
39
- constructor(participantsService: ParticipantsService, analyticsHelper: AnalyticsHelper | undefined, fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>, providerEmitCallback: (evt: keyof CollabEvents, data: any) => void, broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void, getUserId: () => string | undefined, onErrorHandled: (error: InternalError) => void, metadataService: MetadataService, failedStepsBeforeCatchupOnPublish?: number);
41
+ constructor(participantsService: ParticipantsService, analyticsHelper: AnalyticsHelper | undefined, fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>, providerEmitCallback: (evt: keyof CollabEvents, data: any) => void, broadcast: <K extends keyof ChannelEvent>(type: K, data: Omit<ChannelEvent[K], 'timestamp'>, callback?: Function) => void, getUserId: () => string | undefined, onErrorHandled: (error: InternalError) => void, metadataService: MetadataService, failedStepsBeforeCatchupOnPublish?: number, enableErrorOnFailedDocumentApply?: boolean);
40
42
  /**
41
43
  * To prevent calling catchup to often, use lodash throttle to reduce the frequency
42
44
  */
@@ -61,6 +63,7 @@ export declare class DocumentService {
61
63
  onRestore: ({ doc, version, metadata }: CollabInitPayload) => void;
62
64
  getFinalAcknowledgedState: () => Promise<ResolvedEditorState>;
63
65
  updateDocument: ({ doc, version, metadata, reserveCursor, }: CollabInitPayload) => void;
66
+ private validatePMJSONDocument;
64
67
  /**
65
68
  * Commit the unconfirmed local steps to the back-end service
66
69
  * @throws {Error} Couldn't sync the steps after retrying 30 times
@@ -1,3 +1,4 @@
1
+ import { DocumentUpdateErrorAttributes } from '../helpers/const';
1
2
  export declare enum INTERNAL_ERROR_CODE {
2
3
  TOKEN_PERMISSION_ERROR = "TOKEN_PERMISSION_ERROR",
3
4
  RECONNECTION_NETWORK_ISSUE = "RECONNECTION_NETWORK_ISSUE",
@@ -6,7 +7,8 @@ export declare enum INTERNAL_ERROR_CODE {
6
7
  DOCUMENT_NOT_FOUND = "DOCUMENT_NOT_FOUND",
7
8
  CATCHUP_FAILED = "CATCHUP_FAILED",
8
9
  DOCUMENT_RESTORE_ERROR = "DOCUMENT_RESTORE_ERROR",
9
- ADD_STEPS_ERROR = "ADD_STEPS_ERROR"
10
+ ADD_STEPS_ERROR = "ADD_STEPS_ERROR",
11
+ DOCUMENT_UPDATE_ERROR = "DOCUMENT_UPDATE_ERROR"
10
12
  }
11
13
  export declare enum NCS_ERROR_CODE {
12
14
  HEAD_VERSION_UPDATE_FAILED = "HEAD_VERSION_UPDATE_FAILED",
@@ -160,7 +162,7 @@ type InvalidCloudIdError = {
160
162
  status: number;
161
163
  };
162
164
  };
163
- type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError;
165
+ type NCSErrors = HeadVersionUpdateFailedError | VersionAlreadyPresentInDynamoError | InsufficientEditingPermissionError | ForbiddenUserTokenError | NCSDocumentNotFoundError | FailedToLoadInitDataError | ErrorMappingError | InvalidNamespaceDefinedError | SocketNamespaceNotFoundError | TenantInstanceMaintenanceError | NamespaceLockedError | EmptyBroadcastError | DynamoError | InvalidActivationIdError | InvalidDocumentAriError | InvalidCloudIdError | InternalDocumentUpdateFailure;
164
166
  type DocumentRecoveryError = {
165
167
  message: string;
166
168
  data: {
@@ -219,10 +221,25 @@ export type DocumentNotFoundError = {
219
221
  status: number;
220
222
  };
221
223
  };
224
+ /**
225
+ * When we try to apply state updates to the editor, if that fails to apply the user can enter an invalid state where no
226
+ * changes can be saved to NCS.
227
+ */
228
+ export type InternalDocumentUpdateFailure = {
229
+ message: 'The provider failed to apply changes to the editor';
230
+ data: {
231
+ code: INTERNAL_ERROR_CODE.DOCUMENT_UPDATE_ERROR;
232
+ meta: {
233
+ newVersion?: number;
234
+ editorVersion?: number;
235
+ };
236
+ status: 500;
237
+ };
238
+ };
222
239
  /**
223
240
  * A union of all possible internal errors, that are mapped to another error if being emitted to the editor.
224
241
  */
225
- export type InternalError = NCSErrors | DocumentRecoveryError | AddStepsError | CatchUpFailedError | TokenPermissionError | ReconnectionError | ConnectionError | ReconnectionNetworkError | DocumentNotFoundError;
242
+ export type InternalError = NCSErrors | DocumentRecoveryError | AddStepsError | CatchUpFailedError | TokenPermissionError | ReconnectionError | ConnectionError | ReconnectionNetworkError | DocumentNotFoundError | InternalDocumentUpdateFailure;
226
243
  export declare enum PROVIDER_ERROR_CODE {
227
244
  NO_PERMISSION_ERROR = "NO_PERMISSION_ERROR",
228
245
  INVALID_USER_TOKEN = "INVALID_USER_TOKEN",
@@ -233,7 +250,8 @@ export declare enum PROVIDER_ERROR_CODE {
233
250
  INITIALISATION_ERROR = "INITIALISATION_ERROR",
234
251
  NETWORK_ISSUE = "NETWORK_ISSUE",
235
252
  INVALID_PROVIDER_CONFIGURATION = "INVALID_PROVIDER_CONFIGURATION",
236
- INTERNAL_SERVICE_ERROR = "INTERNAL_SERVICE_ERROR"
253
+ INTERNAL_SERVICE_ERROR = "INTERNAL_SERVICE_ERROR",
254
+ DOCUMENT_UPDATE_ERROR = "DOCUMENT_UPDATE_ERROR"
237
255
  }
238
256
  /**
239
257
  * This occurs when the provided user token is considered invalid for the given document ARI.
@@ -399,16 +417,34 @@ type InternalServiceError = {
399
417
  */
400
418
  status?: number;
401
419
  };
420
+ type ProviderDocumentUpdateError = {
421
+ code: PROVIDER_ERROR_CODE.DOCUMENT_UPDATE_ERROR;
422
+ message: 'The provider failed to apply changes to the editor';
423
+ recoverable: boolean;
424
+ /**
425
+ * @deprecated switch to using either the error code or the recoverable flag
426
+ */
427
+ status?: number;
428
+ };
402
429
  /**
403
430
  * A union of all possible provider errors that can be emitted back to the editor.
404
431
  */
405
- export type ProviderError = InsufficientEditingPermission | InvalidUserToken | DocumentNotFound | Locked | FailToSave | DocumentNotRestore | InitialisationError | NetworkIssue | InvalidProviderConfiguration | InternalServiceError;
406
- declare class CustomError extends Error {
407
- constructor(message: string, error?: unknown);
432
+ export type ProviderError = InsufficientEditingPermission | InvalidUserToken | DocumentNotFound | Locked | FailToSave | DocumentNotRestore | InitialisationError | NetworkIssue | InvalidProviderConfiguration | InternalServiceError | ProviderDocumentUpdateError;
433
+ type ValidEventAttributeType = boolean | string | number;
434
+ export declare class CustomError extends Error {
435
+ extraEventAttributes?: {
436
+ [key: string]: ValidEventAttributeType;
437
+ };
438
+ constructor(message: string, error?: unknown, extraEventAttributes?: {
439
+ [key: string]: ValidEventAttributeType;
440
+ });
408
441
  toJSON(): {
409
442
  name: string;
410
443
  message: string;
411
444
  };
445
+ getExtraErrorEventAttributes: () => {
446
+ [key: string]: ValidEventAttributeType;
447
+ } | undefined;
412
448
  }
413
449
  export declare class NotConnectedError extends CustomError {
414
450
  name: string;
@@ -440,4 +476,8 @@ export declare class GetCurrentStateError extends CustomError {
440
476
  export declare class GetFinalAcknowledgedStateError extends CustomError {
441
477
  name: string;
442
478
  }
479
+ export declare class UpdateDocumentError extends CustomError {
480
+ name: string;
481
+ constructor(message: string, extraAttributes: DocumentUpdateErrorAttributes);
482
+ }
443
483
  export {};
@@ -25,6 +25,13 @@ export declare enum ADD_STEPS_TYPE {
25
25
  REJECTED = "REJECTED",
26
26
  ERROR = "ERROR"
27
27
  }
28
+ export type DocumentUpdateErrorAttributes = {
29
+ isDocTruthy?: boolean;
30
+ editorVersion?: number;
31
+ newVersion?: number;
32
+ docHasContent?: boolean;
33
+ isDocContentValid?: boolean;
34
+ };
28
35
  export type ErrorAnalyticsEvent = {
29
36
  eventAction: EVENT_ACTION.ERROR;
30
37
  attributes: {
@@ -32,7 +39,7 @@ export type ErrorAnalyticsEvent = {
32
39
  errorName?: string;
33
40
  documentAri?: string;
34
41
  mappedError?: ProviderError;
35
- };
42
+ } & DocumentUpdateErrorAttributes;
36
43
  nonPrivacySafeAttributes: {
37
44
  error: unknown;
38
45
  };