@atlaskit/collab-provider 9.8.0 → 9.9.1
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 +12 -0
- package/dist/cjs/channel.js +140 -34
- package/dist/cjs/document/document-service.js +57 -16
- package/dist/cjs/feature-flags/__test__/index.unit.js +3 -2
- package/dist/cjs/feature-flags/index.js +5 -3
- package/dist/cjs/provider/index.js +2 -2
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/channel.js +40 -4
- package/dist/es2019/document/document-service.js +26 -4
- package/dist/es2019/feature-flags/__test__/index.unit.js +3 -2
- package/dist/es2019/feature-flags/index.js +5 -3
- package/dist/es2019/provider/index.js +1 -1
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/es2019/version.json +1 -1
- package/dist/esm/channel.js +140 -34
- package/dist/esm/document/document-service.js +57 -16
- package/dist/esm/feature-flags/__test__/index.unit.js +3 -2
- package/dist/esm/feature-flags/index.js +5 -3
- package/dist/esm/provider/index.js +2 -2
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/esm/version.json +1 -1
- package/dist/types/channel.d.ts +2 -1
- package/dist/types/document/document-service.d.ts +8 -2
- package/dist/types/feature-flags/types.d.ts +1 -0
- package/dist/types/types.d.ts +6 -0
- package/dist/types-ts4.5/channel.d.ts +2 -1
- package/dist/types-ts4.5/document/document-service.d.ts +8 -2
- package/dist/types-ts4.5/feature-flags/types.d.ts +1 -0
- package/dist/types-ts4.5/types.d.ts +6 -0
- package/package.json +4 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const defaultNCSFeatureFlags = {
|
|
2
2
|
testFF: false,
|
|
3
|
-
socketMessageMetricsFF: false
|
|
3
|
+
socketMessageMetricsFF: false,
|
|
4
|
+
enableFallbackToReconcile: false
|
|
4
5
|
};
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -8,8 +9,9 @@ const defaultNCSFeatureFlags = {
|
|
|
8
9
|
*/
|
|
9
10
|
const productKeys = {
|
|
10
11
|
confluence: {
|
|
11
|
-
testFF: 'confluence.
|
|
12
|
-
socketMessageMetricsFF: 'confluence.
|
|
12
|
+
testFF: 'confluence.frontend.collab.provider.testFF',
|
|
13
|
+
socketMessageMetricsFF: 'confluence.frontend.collab.provider.socketMessageMetricsFF',
|
|
14
|
+
enableFallbackToReconcile: 'confluence.frontend.collab.provider.enable-fallback-to-reconcile'
|
|
13
15
|
}
|
|
14
16
|
};
|
|
15
17
|
const filterFeatureFlagNames = flags => {
|
|
@@ -241,7 +241,7 @@ export class Provider extends Emitter {
|
|
|
241
241
|
this.isPreinitializing = false;
|
|
242
242
|
this.participantsService = new ParticipantsService(this.analyticsHelper, undefined, this.emitCallback, this.config.getUser, this.channel.broadcast, this.channel.sendPresenceJoined, this.getPresenceData, this.setUserId);
|
|
243
243
|
this.metadataService = new MetadataService(this.emitCallback, this.channel.sendMetadata);
|
|
244
|
-
this.documentService = new DocumentService(this.participantsService, this.analyticsHelper, this.channel.fetchCatchup, this.emitCallback, this.channel.broadcast, () => this.userId, this.onErrorHandled, this.metadataService, this.config.failedStepLimitBeforeCatchupOnPublish, this.config.enableErrorOnFailedDocumentApply);
|
|
244
|
+
this.documentService = new DocumentService(this.participantsService, this.analyticsHelper, this.channel.fetchCatchup, this.channel.fetchReconcile, this.emitCallback, this.channel.broadcast, () => this.userId, this.onErrorHandled, this.metadataService, this.config.failedStepLimitBeforeCatchupOnPublish, this.config.enableErrorOnFailedDocumentApply, this.config.featureFlags);
|
|
245
245
|
this.onSetupPromise = new Promise(resolve => {
|
|
246
246
|
this.resolveOnSetupPromise = resolve;
|
|
247
247
|
});
|
package/dist/es2019/version.json
CHANGED
package/dist/esm/channel.js
CHANGED
|
@@ -325,6 +325,112 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
325
325
|
return _ref.apply(this, arguments);
|
|
326
326
|
};
|
|
327
327
|
}());
|
|
328
|
+
_defineProperty(_assertThisInitialized(_this), "fetchReconcile", /*#__PURE__*/function () {
|
|
329
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(currentStateDoc) {
|
|
330
|
+
var _ref4, _this$token2, reqBody, reconcileResponse, _this$analyticsHelper7;
|
|
331
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
332
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
333
|
+
case 0:
|
|
334
|
+
_context2.prev = 0;
|
|
335
|
+
reqBody = JSON.stringify({
|
|
336
|
+
doc: currentStateDoc,
|
|
337
|
+
productId: 'ccollab',
|
|
338
|
+
reason: 'UNKNOWN' // different reason here?
|
|
339
|
+
});
|
|
340
|
+
_context2.t0 = utils;
|
|
341
|
+
_context2.t1 = _this.config;
|
|
342
|
+
_context2.t2 = "document/".concat(encodeURIComponent(_this.config.documentAri), "/reconcile");
|
|
343
|
+
_context2.t3 = _objectSpread;
|
|
344
|
+
_context2.t4 = _objectSpread;
|
|
345
|
+
_context2.t5 = {};
|
|
346
|
+
if (!_this.config.permissionTokenRefresh) {
|
|
347
|
+
_context2.next = 29;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
if (!((_this$token2 = _this.token) !== null && _this$token2 !== void 0)) {
|
|
351
|
+
_context2.next = 13;
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
_context2.t8 = _this$token2;
|
|
355
|
+
_context2.next = 16;
|
|
356
|
+
break;
|
|
357
|
+
case 13:
|
|
358
|
+
_context2.next = 15;
|
|
359
|
+
return _this.config.permissionTokenRefresh().then(function (token) {
|
|
360
|
+
if (token) {
|
|
361
|
+
_this.setToken(token);
|
|
362
|
+
}
|
|
363
|
+
return token;
|
|
364
|
+
});
|
|
365
|
+
case 15:
|
|
366
|
+
_context2.t8 = _context2.sent;
|
|
367
|
+
case 16:
|
|
368
|
+
_context2.t9 = _ref4 = _context2.t8;
|
|
369
|
+
_context2.t7 = _context2.t9 !== null;
|
|
370
|
+
if (!_context2.t7) {
|
|
371
|
+
_context2.next = 20;
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
_context2.t7 = _ref4 !== void 0;
|
|
375
|
+
case 20:
|
|
376
|
+
if (!_context2.t7) {
|
|
377
|
+
_context2.next = 24;
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
_context2.t10 = _ref4;
|
|
381
|
+
_context2.next = 25;
|
|
382
|
+
break;
|
|
383
|
+
case 24:
|
|
384
|
+
_context2.t10 = undefined;
|
|
385
|
+
case 25:
|
|
386
|
+
_context2.t11 = _context2.t10;
|
|
387
|
+
_context2.t6 = {
|
|
388
|
+
'x-token': _context2.t11
|
|
389
|
+
};
|
|
390
|
+
_context2.next = 30;
|
|
391
|
+
break;
|
|
392
|
+
case 29:
|
|
393
|
+
_context2.t6 = {};
|
|
394
|
+
case 30:
|
|
395
|
+
_context2.t12 = _context2.t6;
|
|
396
|
+
_context2.t13 = (0, _context2.t4)(_context2.t5, _context2.t12);
|
|
397
|
+
_context2.t14 = {};
|
|
398
|
+
_context2.t15 = {
|
|
399
|
+
'x-product': getProduct(_this.config.productInfo),
|
|
400
|
+
'x-subproduct': getSubProduct(_this.config.productInfo),
|
|
401
|
+
'Content-Type': 'application/json'
|
|
402
|
+
};
|
|
403
|
+
_context2.t16 = (0, _context2.t3)(_context2.t13, _context2.t14, _context2.t15);
|
|
404
|
+
_context2.t17 = reqBody;
|
|
405
|
+
_context2.t18 = {
|
|
406
|
+
headers: _context2.t16,
|
|
407
|
+
method: 'POST',
|
|
408
|
+
body: _context2.t17
|
|
409
|
+
};
|
|
410
|
+
_context2.t19 = {
|
|
411
|
+
path: _context2.t2,
|
|
412
|
+
requestInit: _context2.t18
|
|
413
|
+
};
|
|
414
|
+
_context2.next = 40;
|
|
415
|
+
return _context2.t0.requestService.call(_context2.t0, _context2.t1, _context2.t19);
|
|
416
|
+
case 40:
|
|
417
|
+
reconcileResponse = _context2.sent;
|
|
418
|
+
return _context2.abrupt("return", reconcileResponse);
|
|
419
|
+
case 44:
|
|
420
|
+
_context2.prev = 44;
|
|
421
|
+
_context2.t20 = _context2["catch"](0);
|
|
422
|
+
(_this$analyticsHelper7 = _this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(_context2.t20, 'Error while fetching reconciled document');
|
|
423
|
+
throw _context2.t20;
|
|
424
|
+
case 48:
|
|
425
|
+
case "end":
|
|
426
|
+
return _context2.stop();
|
|
427
|
+
}
|
|
428
|
+
}, _callee2, null, [[0, 44]]);
|
|
429
|
+
}));
|
|
430
|
+
return function (_x2) {
|
|
431
|
+
return _ref3.apply(this, arguments);
|
|
432
|
+
};
|
|
433
|
+
}());
|
|
328
434
|
/**
|
|
329
435
|
* Send message to the back-end service over the channel. Timestamp will be added server side.
|
|
330
436
|
* @throws {NotInitializedError} Channel not initialized
|
|
@@ -409,10 +515,10 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
409
515
|
var auth;
|
|
410
516
|
if (permissionTokenRefresh) {
|
|
411
517
|
auth = /*#__PURE__*/function () {
|
|
412
|
-
var
|
|
518
|
+
var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(cb) {
|
|
413
519
|
var authData, token, _data, _data$meta, authenticationError;
|
|
414
|
-
return _regeneratorRuntime.wrap(function
|
|
415
|
-
while (1) switch (
|
|
520
|
+
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
521
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
416
522
|
case 0:
|
|
417
523
|
// Rebuild authData to ensure values are current
|
|
418
524
|
authData = {
|
|
@@ -422,19 +528,19 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
422
528
|
need404: _this2.config.need404
|
|
423
529
|
}; // use the cached token if caching in enabled and token valid
|
|
424
530
|
if (!(cacheToken && _this2.token)) {
|
|
425
|
-
|
|
531
|
+
_context3.next = 6;
|
|
426
532
|
break;
|
|
427
533
|
}
|
|
428
534
|
authData.token = _this2.token;
|
|
429
535
|
cb(authData);
|
|
430
|
-
|
|
536
|
+
_context3.next = 18;
|
|
431
537
|
break;
|
|
432
538
|
case 6:
|
|
433
|
-
|
|
434
|
-
|
|
539
|
+
_context3.prev = 6;
|
|
540
|
+
_context3.next = 9;
|
|
435
541
|
return permissionTokenRefresh();
|
|
436
542
|
case 9:
|
|
437
|
-
token =
|
|
543
|
+
token = _context3.sent;
|
|
438
544
|
if (token) {
|
|
439
545
|
// save token locally
|
|
440
546
|
_this2.setToken(token);
|
|
@@ -444,11 +550,11 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
444
550
|
authData.token = undefined;
|
|
445
551
|
}
|
|
446
552
|
cb(authData);
|
|
447
|
-
|
|
553
|
+
_context3.next = 18;
|
|
448
554
|
break;
|
|
449
555
|
case 14:
|
|
450
|
-
|
|
451
|
-
|
|
556
|
+
_context3.prev = 14;
|
|
557
|
+
_context3.t0 = _context3["catch"](6);
|
|
452
558
|
// Pass the error back to the consumers so they can deal with exceptional cases themselves (eg. no permissions because the page was deleted)
|
|
453
559
|
authenticationError = {
|
|
454
560
|
message: 'Insufficient editing permissions',
|
|
@@ -456,8 +562,8 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
456
562
|
status: 403,
|
|
457
563
|
code: INTERNAL_ERROR_CODE.TOKEN_PERMISSION_ERROR,
|
|
458
564
|
meta: {
|
|
459
|
-
originalError:
|
|
460
|
-
reason:
|
|
565
|
+
originalError: _context3.t0,
|
|
566
|
+
reason: _context3.t0 === null || _context3.t0 === void 0 ? void 0 : (_data = _context3.t0.data) === null || _data === void 0 ? void 0 : (_data$meta = _data.meta) === null || _data$meta === void 0 ? void 0 : _data$meta.reason // Should always be 'RESOURCE_DELETED' Temporary, until Confluence Cloud removes their hack
|
|
461
567
|
// https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/browse/next/packages/native-collab/src/fetchCollabPermissionToken.ts#37
|
|
462
568
|
}
|
|
463
569
|
}
|
|
@@ -466,12 +572,12 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
466
572
|
_this2.emit('error', authenticationError);
|
|
467
573
|
case 18:
|
|
468
574
|
case "end":
|
|
469
|
-
return
|
|
575
|
+
return _context3.stop();
|
|
470
576
|
}
|
|
471
|
-
},
|
|
577
|
+
}, _callee3, null, [[6, 14]]);
|
|
472
578
|
}));
|
|
473
|
-
return function auth(
|
|
474
|
-
return
|
|
579
|
+
return function auth(_x3) {
|
|
580
|
+
return _ref5.apply(this, arguments);
|
|
475
581
|
};
|
|
476
582
|
}();
|
|
477
583
|
} else {
|
|
@@ -495,9 +601,9 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
495
601
|
this.socket.on('steps:added', function (data) {
|
|
496
602
|
_this2.emit('steps:added', data);
|
|
497
603
|
});
|
|
498
|
-
this.socket.on('participant:telepointer', function (
|
|
499
|
-
var timestamp =
|
|
500
|
-
data =
|
|
604
|
+
this.socket.on('participant:telepointer', function (_ref6) {
|
|
605
|
+
var timestamp = _ref6.timestamp,
|
|
606
|
+
data = _ref6.data;
|
|
501
607
|
// data is TelepointerPayload without timestamp
|
|
502
608
|
_this2.emit('participant:telepointer', _objectSpread({
|
|
503
609
|
timestamp: timestamp
|
|
@@ -512,11 +618,11 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
512
618
|
this.socket.on('participant:left', function (data) {
|
|
513
619
|
_this2.emit('participant:left', data);
|
|
514
620
|
});
|
|
515
|
-
this.socket.on('participant:updated', function (
|
|
516
|
-
var sessionId =
|
|
517
|
-
timestamp =
|
|
518
|
-
data =
|
|
519
|
-
clientId =
|
|
621
|
+
this.socket.on('participant:updated', function (_ref7) {
|
|
622
|
+
var sessionId = _ref7.sessionId,
|
|
623
|
+
timestamp = _ref7.timestamp,
|
|
624
|
+
data = _ref7.data,
|
|
625
|
+
clientId = _ref7.clientId;
|
|
520
626
|
_this2.emit('participant:updated', _objectSpread({
|
|
521
627
|
sessionId: sessionId,
|
|
522
628
|
timestamp: timestamp,
|
|
@@ -532,10 +638,10 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
532
638
|
_this2.emit('status', data);
|
|
533
639
|
});
|
|
534
640
|
this.socket.on('disconnect', /*#__PURE__*/function () {
|
|
535
|
-
var
|
|
641
|
+
var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(reason) {
|
|
536
642
|
var _this2$analyticsHelpe, reconnectionError;
|
|
537
|
-
return _regeneratorRuntime.wrap(function
|
|
538
|
-
while (1) switch (
|
|
643
|
+
return _regeneratorRuntime.wrap(function _callee4$(_context4) {
|
|
644
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
539
645
|
case 0:
|
|
540
646
|
if (getCollabProviderFeatureFlag('socketMessageMetricsFF', _this2.config.featureFlags) && _this2.socketMessageMetrics) {
|
|
541
647
|
_this2.socketMessageMetrics.closeSocketMessageMetrics();
|
|
@@ -563,12 +669,12 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
563
669
|
}
|
|
564
670
|
case 5:
|
|
565
671
|
case "end":
|
|
566
|
-
return
|
|
672
|
+
return _context4.stop();
|
|
567
673
|
}
|
|
568
|
-
},
|
|
674
|
+
}, _callee4);
|
|
569
675
|
}));
|
|
570
|
-
return function (
|
|
571
|
-
return
|
|
676
|
+
return function (_x4) {
|
|
677
|
+
return _ref8.apply(this, arguments);
|
|
572
678
|
};
|
|
573
679
|
}());
|
|
574
680
|
|
|
@@ -658,8 +764,8 @@ export var Channel = /*#__PURE__*/function (_Emitter) {
|
|
|
658
764
|
this.emit('error', rateLimitError);
|
|
659
765
|
throw new Error();
|
|
660
766
|
} else if (rateLimitType === this.RATE_LIMIT_TYPE_SOFT) {
|
|
661
|
-
var _this$
|
|
662
|
-
(_this$
|
|
767
|
+
var _this$analyticsHelper8;
|
|
768
|
+
(_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(rateLimitError, 'Rate limited');
|
|
663
769
|
}
|
|
664
770
|
}
|
|
665
771
|
}
|
|
@@ -15,6 +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 { getCollabProviderFeatureFlag } from '../feature-flags';
|
|
18
19
|
import { CantSyncUpError, INTERNAL_ERROR_CODE, UpdateDocumentError } from '../errors/error-types';
|
|
19
20
|
var CATCHUP_THROTTLE = 1 * 1000; // 1 second
|
|
20
21
|
|
|
@@ -29,6 +30,7 @@ export var DocumentService = /*#__PURE__*/function () {
|
|
|
29
30
|
* and to emit their telepointers from steps they add
|
|
30
31
|
* @param analyticsHelper - Helper for analytics events
|
|
31
32
|
* @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
|
|
33
|
+
* @param fetchReconcile - Function to call "reconcile" from NCS backend
|
|
32
34
|
* @param providerEmitCallback - Callback for emitting events to listeners on the provider
|
|
33
35
|
* @param broadcast - Callback for broadcasting events to other clients
|
|
34
36
|
* @param getUserId - Callback to fetch the current user's ID
|
|
@@ -36,11 +38,13 @@ export var DocumentService = /*#__PURE__*/function () {
|
|
|
36
38
|
* @param metadataService
|
|
37
39
|
* @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
|
|
38
40
|
* @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
|
|
41
|
+
* @param featureFlags - Feature flag config
|
|
39
42
|
*/
|
|
40
|
-
function DocumentService(participantsService, analyticsHelper, fetchCatchup, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
|
|
43
|
+
function DocumentService(participantsService, analyticsHelper, fetchCatchup, fetchReconcile, providerEmitCallback, broadcast, getUserId, onErrorHandled, metadataService) {
|
|
41
44
|
var _this = this;
|
|
42
|
-
var failedStepsBeforeCatchupOnPublish = arguments.length >
|
|
43
|
-
var enableErrorOnFailedDocumentApply = arguments.length >
|
|
45
|
+
var failedStepsBeforeCatchupOnPublish = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : MAX_STEP_REJECTED_ERROR;
|
|
46
|
+
var enableErrorOnFailedDocumentApply = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : false;
|
|
47
|
+
var featureFlags = arguments.length > 11 ? arguments[11] : undefined;
|
|
44
48
|
_classCallCheck(this, DocumentService);
|
|
45
49
|
// Fires analytics to editor when collab editor cannot sync up
|
|
46
50
|
_defineProperty(this, "stepRejectCounter", 0);
|
|
@@ -276,41 +280,76 @@ export var DocumentService = /*#__PURE__*/function () {
|
|
|
276
280
|
}
|
|
277
281
|
});
|
|
278
282
|
_defineProperty(this, "getFinalAcknowledgedState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
279
|
-
var _this$analyticsHelper14, currentState, measure, _this$analyticsHelper15, _this$analyticsHelper16, _measure2;
|
|
283
|
+
var _this$analyticsHelper14, finalAcknowledgedState, currentState, reconcileResponse, measure, _this$analyticsHelper15, _this$analyticsHelper16, _measure2;
|
|
280
284
|
return _regeneratorRuntime.wrap(function _callee3$(_context3) {
|
|
281
285
|
while (1) switch (_context3.prev = _context3.next) {
|
|
282
286
|
case 0:
|
|
283
287
|
_this.aggressiveCatchup = true;
|
|
284
288
|
_context3.prev = 1;
|
|
285
289
|
startMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
290
|
+
if (!getCollabProviderFeatureFlag('enableFallbackToReconcile', _this.featureFlags)) {
|
|
291
|
+
_context3.next = 23;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
_context3.prev = 4;
|
|
289
295
|
_context3.next = 7;
|
|
290
|
-
return _this.
|
|
296
|
+
return _this.commitUnconfirmedSteps();
|
|
291
297
|
case 7:
|
|
298
|
+
_context3.next = 9;
|
|
299
|
+
return _this.getCurrentState();
|
|
300
|
+
case 9:
|
|
301
|
+
finalAcknowledgedState = _context3.sent;
|
|
302
|
+
_context3.next = 21;
|
|
303
|
+
break;
|
|
304
|
+
case 12:
|
|
305
|
+
_context3.prev = 12;
|
|
306
|
+
_context3.t0 = _context3["catch"](4);
|
|
307
|
+
_context3.next = 16;
|
|
308
|
+
return _this.getCurrentState();
|
|
309
|
+
case 16:
|
|
292
310
|
currentState = _context3.sent;
|
|
311
|
+
_context3.next = 19;
|
|
312
|
+
return _this.fetchReconcile(JSON.stringify(currentState.content));
|
|
313
|
+
case 19:
|
|
314
|
+
reconcileResponse = _context3.sent;
|
|
315
|
+
finalAcknowledgedState = {
|
|
316
|
+
content: JSON.parse(reconcileResponse.document),
|
|
317
|
+
title: currentState.title,
|
|
318
|
+
stepVersion: reconcileResponse.version
|
|
319
|
+
};
|
|
320
|
+
case 21:
|
|
321
|
+
_context3.next = 28;
|
|
322
|
+
break;
|
|
323
|
+
case 23:
|
|
324
|
+
_context3.next = 25;
|
|
325
|
+
return _this.commitUnconfirmedSteps();
|
|
326
|
+
case 25:
|
|
327
|
+
_context3.next = 27;
|
|
328
|
+
return _this.getCurrentState();
|
|
329
|
+
case 27:
|
|
330
|
+
finalAcknowledgedState = _context3.sent;
|
|
331
|
+
case 28:
|
|
293
332
|
measure = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
294
333
|
(_this$analyticsHelper14 = _this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.SUCCESS, {
|
|
295
334
|
latency: measure === null || measure === void 0 ? void 0 : measure.duration
|
|
296
335
|
});
|
|
297
336
|
_this.aggressiveCatchup = false;
|
|
298
|
-
return _context3.abrupt("return",
|
|
299
|
-
case
|
|
300
|
-
_context3.prev =
|
|
301
|
-
_context3.
|
|
337
|
+
return _context3.abrupt("return", finalAcknowledgedState);
|
|
338
|
+
case 34:
|
|
339
|
+
_context3.prev = 34;
|
|
340
|
+
_context3.t1 = _context3["catch"](1);
|
|
302
341
|
_this.aggressiveCatchup = false;
|
|
303
342
|
_measure2 = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
|
|
304
343
|
(_this$analyticsHelper15 = _this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.FAILURE, {
|
|
305
344
|
latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
|
|
306
345
|
});
|
|
307
|
-
(_this$analyticsHelper16 = _this.analyticsHelper) === null || _this$analyticsHelper16 === void 0 ? void 0 : _this$analyticsHelper16.sendErrorEvent(_context3.
|
|
308
|
-
throw _context3.
|
|
309
|
-
case
|
|
346
|
+
(_this$analyticsHelper16 = _this.analyticsHelper) === null || _this$analyticsHelper16 === void 0 ? void 0 : _this$analyticsHelper16.sendErrorEvent(_context3.t1, 'Error while returning ADF version of the final draft document');
|
|
347
|
+
throw _context3.t1;
|
|
348
|
+
case 41:
|
|
310
349
|
case "end":
|
|
311
350
|
return _context3.stop();
|
|
312
351
|
}
|
|
313
|
-
}, _callee3, null, [[1,
|
|
352
|
+
}, _callee3, null, [[1, 34], [4, 12]]);
|
|
314
353
|
})));
|
|
315
354
|
_defineProperty(this, "updateDocument", function (_ref6) {
|
|
316
355
|
var doc = _ref6.doc,
|
|
@@ -488,6 +527,7 @@ export var DocumentService = /*#__PURE__*/function () {
|
|
|
488
527
|
this.participantsService = participantsService;
|
|
489
528
|
this.analyticsHelper = analyticsHelper;
|
|
490
529
|
this.fetchCatchup = fetchCatchup;
|
|
530
|
+
this.fetchReconcile = fetchReconcile;
|
|
491
531
|
this.providerEmitCallback = providerEmitCallback;
|
|
492
532
|
this.broadcast = broadcast;
|
|
493
533
|
this.getUserId = getUserId;
|
|
@@ -495,6 +535,7 @@ export var DocumentService = /*#__PURE__*/function () {
|
|
|
495
535
|
this.metadataService = metadataService;
|
|
496
536
|
this.failedStepsBeforeCatchupOnPublish = failedStepsBeforeCatchupOnPublish;
|
|
497
537
|
this.enableErrorOnFailedDocumentApply = enableErrorOnFailedDocumentApply;
|
|
538
|
+
this.featureFlags = featureFlags;
|
|
498
539
|
this.stepQueue = new StepQueueState();
|
|
499
540
|
}
|
|
500
541
|
_createClass(DocumentService, [{
|
|
@@ -3,9 +3,10 @@ describe('Feature flags', function () {
|
|
|
3
3
|
it('getProductSpecificFeatureFlags', function () {
|
|
4
4
|
var result = getProductSpecificFeatureFlags({
|
|
5
5
|
testFF: true,
|
|
6
|
-
socketMessageMetricsFF: true
|
|
6
|
+
socketMessageMetricsFF: true,
|
|
7
|
+
enableFallbackToReconcile: true
|
|
7
8
|
}, 'confluence');
|
|
8
|
-
expect(result).toEqual(['confluence.
|
|
9
|
+
expect(result).toEqual(['confluence.frontend.collab.provider.testFF', 'confluence.frontend.collab.provider.socketMessageMetricsFF', 'confluence.frontend.collab.provider.enable-fallback-to-reconcile']);
|
|
9
10
|
});
|
|
10
11
|
it('getCollabProviderFeatureFlag return true', function () {
|
|
11
12
|
var result = getCollabProviderFeatureFlag('testFF', {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
2
|
var defaultNCSFeatureFlags = {
|
|
3
3
|
testFF: false,
|
|
4
|
-
socketMessageMetricsFF: false
|
|
4
|
+
socketMessageMetricsFF: false,
|
|
5
|
+
enableFallbackToReconcile: false
|
|
5
6
|
};
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -9,8 +10,9 @@ var defaultNCSFeatureFlags = {
|
|
|
9
10
|
*/
|
|
10
11
|
var productKeys = {
|
|
11
12
|
confluence: {
|
|
12
|
-
testFF: 'confluence.
|
|
13
|
-
socketMessageMetricsFF: 'confluence.
|
|
13
|
+
testFF: 'confluence.frontend.collab.provider.testFF',
|
|
14
|
+
socketMessageMetricsFF: 'confluence.frontend.collab.provider.socketMessageMetricsFF',
|
|
15
|
+
enableFallbackToReconcile: 'confluence.frontend.collab.provider.enable-fallback-to-reconcile'
|
|
14
16
|
}
|
|
15
17
|
};
|
|
16
18
|
var filterFeatureFlagNames = function filterFeatureFlagNames(flags) {
|
|
@@ -279,9 +279,9 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
279
279
|
_this.isPreinitializing = false;
|
|
280
280
|
_this.participantsService = new ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined, _this.getPresenceData, _this.setUserId);
|
|
281
281
|
_this.metadataService = new MetadataService(_this.emitCallback, _this.channel.sendMetadata);
|
|
282
|
-
_this.documentService = new DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
|
|
282
|
+
_this.documentService = new DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.channel.fetchReconcile, _this.emitCallback, _this.channel.broadcast, function () {
|
|
283
283
|
return _this.userId;
|
|
284
|
-
}, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish, _this.config.enableErrorOnFailedDocumentApply);
|
|
284
|
+
}, _this.onErrorHandled, _this.metadataService, _this.config.failedStepLimitBeforeCatchupOnPublish, _this.config.enableErrorOnFailedDocumentApply, _this.config.featureFlags);
|
|
285
285
|
_this.onSetupPromise = new Promise(function (resolve) {
|
|
286
286
|
_this.resolveOnSetupPromise = resolve;
|
|
287
287
|
});
|
package/dist/esm/version.json
CHANGED
package/dist/types/channel.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Emitter } from './emitter';
|
|
2
|
-
import type { Config, ChannelEvent, CatchupResponse } from './types';
|
|
2
|
+
import type { Config, ChannelEvent, CatchupResponse, ReconcileResponse } from './types';
|
|
3
3
|
import type { Socket } from 'socket.io-client';
|
|
4
4
|
import AnalyticsHelper from './analytics/analytics-helper';
|
|
5
5
|
import type { Metadata } from '@atlaskit/editor-common/collab';
|
|
@@ -41,6 +41,7 @@ export declare class Channel extends Emitter<ChannelEvent> {
|
|
|
41
41
|
private onConnect;
|
|
42
42
|
private onReceiveData;
|
|
43
43
|
fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>;
|
|
44
|
+
fetchReconcile: (currentStateDoc: string) => Promise<ReconcileResponse>;
|
|
44
45
|
/**
|
|
45
46
|
* Send message to the back-end service over the channel. Timestamp will be added server side.
|
|
46
47
|
* @throws {NotInitializedError} Channel not initialized
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="lodash" />
|
|
2
2
|
import AnalyticsHelper from '../analytics/analytics-helper';
|
|
3
|
-
import { CatchupResponse, ChannelEvent, StepsPayload } from '../types';
|
|
3
|
+
import { CatchupResponse, ReconcileResponse, ChannelEvent, StepsPayload } from '../types';
|
|
4
4
|
import type { SyncUpErrorFunction, ResolvedEditorState } from '@atlaskit/editor-common/collab';
|
|
5
5
|
import type { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
|
|
6
6
|
import type { MetadataService } from '../metadata/metadata-service';
|
|
@@ -12,6 +12,7 @@ export declare class DocumentService {
|
|
|
12
12
|
private participantsService;
|
|
13
13
|
private analyticsHelper;
|
|
14
14
|
private fetchCatchup;
|
|
15
|
+
private fetchReconcile;
|
|
15
16
|
private providerEmitCallback;
|
|
16
17
|
private broadcast;
|
|
17
18
|
private getUserId;
|
|
@@ -19,6 +20,7 @@ export declare class DocumentService {
|
|
|
19
20
|
private metadataService;
|
|
20
21
|
private failedStepsBeforeCatchupOnPublish;
|
|
21
22
|
private enableErrorOnFailedDocumentApply;
|
|
23
|
+
private featureFlags;
|
|
22
24
|
private getState;
|
|
23
25
|
private onSyncUpError?;
|
|
24
26
|
private stepQueue;
|
|
@@ -31,6 +33,7 @@ export declare class DocumentService {
|
|
|
31
33
|
* and to emit their telepointers from steps they add
|
|
32
34
|
* @param analyticsHelper - Helper for analytics events
|
|
33
35
|
* @param fetchCatchup - Function to fetch "catchup" data, data required to rebase current steps to the latest version.
|
|
36
|
+
* @param fetchReconcile - Function to call "reconcile" from NCS backend
|
|
34
37
|
* @param providerEmitCallback - Callback for emitting events to listeners on the provider
|
|
35
38
|
* @param broadcast - Callback for broadcasting events to other clients
|
|
36
39
|
* @param getUserId - Callback to fetch the current user's ID
|
|
@@ -38,8 +41,11 @@ export declare class DocumentService {
|
|
|
38
41
|
* @param metadataService
|
|
39
42
|
* @param failedStepsBeforeCatchupOnPublish - Control MAX_STEP_REJECTED_ERROR during page publishes.
|
|
40
43
|
* @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
|
|
44
|
+
* @param featureFlags - Feature flag config
|
|
41
45
|
*/
|
|
42
|
-
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
|
|
46
|
+
constructor(participantsService: ParticipantsService, analyticsHelper: AnalyticsHelper | undefined, fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>, fetchReconcile: (currentStateDoc: string) => Promise<ReconcileResponse>, 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, featureFlags: {
|
|
47
|
+
[key: string]: boolean;
|
|
48
|
+
} | undefined);
|
|
43
49
|
/**
|
|
44
50
|
* To prevent calling catchup to often, use lodash throttle to reduce the frequency
|
|
45
51
|
*/
|
package/dist/types/types.d.ts
CHANGED
|
@@ -179,6 +179,12 @@ export interface CatchupResponse {
|
|
|
179
179
|
stepMaps?: any[];
|
|
180
180
|
metadata?: Metadata;
|
|
181
181
|
}
|
|
182
|
+
export interface ReconcileResponse {
|
|
183
|
+
document: string;
|
|
184
|
+
version: number;
|
|
185
|
+
ari?: string;
|
|
186
|
+
metadata?: Metadata;
|
|
187
|
+
}
|
|
182
188
|
export interface CatchupOptions {
|
|
183
189
|
getCurrentPmVersion: () => number;
|
|
184
190
|
fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Emitter } from './emitter';
|
|
2
|
-
import type { Config, ChannelEvent, CatchupResponse } from './types';
|
|
2
|
+
import type { Config, ChannelEvent, CatchupResponse, ReconcileResponse } from './types';
|
|
3
3
|
import type { Socket } from 'socket.io-client';
|
|
4
4
|
import AnalyticsHelper from './analytics/analytics-helper';
|
|
5
5
|
import type { Metadata } from '@atlaskit/editor-common/collab';
|
|
@@ -41,6 +41,7 @@ export declare class Channel extends Emitter<ChannelEvent> {
|
|
|
41
41
|
private onConnect;
|
|
42
42
|
private onReceiveData;
|
|
43
43
|
fetchCatchup: (fromVersion: number) => Promise<CatchupResponse>;
|
|
44
|
+
fetchReconcile: (currentStateDoc: string) => Promise<ReconcileResponse>;
|
|
44
45
|
/**
|
|
45
46
|
* Send message to the back-end service over the channel. Timestamp will be added server side.
|
|
46
47
|
* @throws {NotInitializedError} Channel not initialized
|