@atlaskit/collab-provider 10.3.4 → 10.4.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 +20 -0
- package/afm-cc/tsconfig.json +6 -0
- package/afm-jira/tsconfig.json +6 -0
- package/dist/cjs/analytics/analytics-helper.js +0 -2
- package/dist/cjs/api/api.js +26 -14
- package/dist/cjs/channel.js +0 -2
- package/dist/cjs/document/catchupv2.js +24 -10
- package/dist/cjs/document/document-service.js +35 -33
- package/dist/cjs/helpers/const.js +2 -1
- package/dist/cjs/helpers/utils.js +216 -2
- package/dist/cjs/participants/participants-service.js +0 -2
- package/dist/cjs/provider/commit-step.js +12 -1
- package/dist/cjs/provider/index.js +69 -33
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/analytics/analytics-helper.js +0 -2
- package/dist/es2019/api/api.js +13 -1
- package/dist/es2019/channel.js +0 -2
- package/dist/es2019/document/catchupv2.js +20 -6
- package/dist/es2019/document/document-service.js +8 -6
- package/dist/es2019/helpers/const.js +2 -1
- package/dist/es2019/helpers/utils.js +159 -1
- package/dist/es2019/participants/participants-service.js +0 -2
- package/dist/es2019/provider/commit-step.js +13 -1
- package/dist/es2019/provider/index.js +40 -17
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/analytics/analytics-helper.js +0 -2
- package/dist/esm/api/api.js +26 -14
- package/dist/esm/channel.js +0 -2
- package/dist/esm/document/catchupv2.js +25 -11
- package/dist/esm/document/document-service.js +35 -33
- package/dist/esm/helpers/const.js +2 -1
- package/dist/esm/helpers/utils.js +212 -1
- package/dist/esm/participants/participants-service.js +0 -2
- package/dist/esm/provider/commit-step.js +12 -1
- package/dist/esm/provider/index.js +71 -35
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/document/document-service.d.ts +1 -0
- package/dist/types/errors/custom-errors.d.ts +1 -1
- package/dist/types/helpers/const.d.ts +16 -2
- package/dist/types/helpers/utils.d.ts +49 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/provider/commit-step.d.ts +2 -1
- package/dist/types/types.d.ts +3 -2
- package/dist/types-ts4.5/document/document-service.d.ts +1 -0
- package/dist/types-ts4.5/errors/custom-errors.d.ts +1 -1
- package/dist/types-ts4.5/helpers/const.d.ts +16 -2
- package/dist/types-ts4.5/helpers/utils.d.ts +49 -0
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/dist/types-ts4.5/provider/commit-step.d.ts +2 -1
- package/dist/types-ts4.5/types.d.ts +3 -2
- package/package.json +16 -2
|
@@ -31,8 +31,6 @@ var SEND_PRESENCE_INTERVAL = 150 * 1000; // 150 seconds
|
|
|
31
31
|
* @param sendPresenceJoined Callback to Channel class
|
|
32
32
|
*/
|
|
33
33
|
var ParticipantsService = exports.ParticipantsService = /*#__PURE__*/function () {
|
|
34
|
-
// Ignored via go/ees005
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
36
34
|
function ParticipantsService(analyticsHelper) {
|
|
37
35
|
var _this = this;
|
|
38
36
|
var participantsState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new _participantsState.ParticipantsState();
|
|
@@ -27,7 +27,8 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
|
27
27
|
onErrorHandled = _ref.onErrorHandled,
|
|
28
28
|
analyticsHelper = _ref.analyticsHelper,
|
|
29
29
|
emit = _ref.emit,
|
|
30
|
-
__livePage = _ref.__livePage
|
|
30
|
+
__livePage = _ref.__livePage,
|
|
31
|
+
hasRecovered = _ref.hasRecovered;
|
|
31
32
|
if (!readyToCommit) {
|
|
32
33
|
logger('Not ready to commit, skip');
|
|
33
34
|
return;
|
|
@@ -69,6 +70,16 @@ var commitStepQueue = exports.commitStepQueue = function commitStepQueue(_ref) {
|
|
|
69
70
|
return step;
|
|
70
71
|
});
|
|
71
72
|
}
|
|
73
|
+
|
|
74
|
+
// tag unconfirmed steps sent after page has been recovered during client's editing session
|
|
75
|
+
if (hasRecovered && (0, _platformFeatureFlags.fg)('tag_unconfirmed_steps_after_recovery')) {
|
|
76
|
+
stepsWithClientAndUserId = stepsWithClientAndUserId.map(function (step) {
|
|
77
|
+
step.metadata = _objectSpread(_objectSpread({}, step.metadata), {}, {
|
|
78
|
+
unconfirmedStepAfterRecovery: true
|
|
79
|
+
});
|
|
80
|
+
return step;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
72
83
|
var start = new Date().getTime();
|
|
73
84
|
emit('commit-status', {
|
|
74
85
|
status: 'attempt',
|
|
@@ -15,6 +15,7 @@ var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get"));
|
|
|
15
15
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
16
16
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
17
17
|
var _uuid = require("uuid");
|
|
18
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
18
19
|
var _emitter = require("../emitter");
|
|
19
20
|
var _channel = require("../channel");
|
|
20
21
|
var _utils = require("../helpers/utils");
|
|
@@ -162,7 +163,29 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
162
163
|
_this.emit('permission', permit);
|
|
163
164
|
}).on('steps:added', _this.documentService.onStepsAdded).on('metadata:changed', _this.metadataService.onMetadataChanged).on('participant:telepointer', function (payload) {
|
|
164
165
|
return _this.participantsService.onParticipantTelepointer(payload, _this.sessionId);
|
|
165
|
-
}).on('participant:activity-join', _this.participantsService.onParticipantActivityJoin).on('participant:activity-ack', _this.participantsService.onParticipantActivityAck).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(_this)).on('error', _this.onErrorHandled).on('status',
|
|
166
|
+
}).on('participant:activity-join', _this.participantsService.onParticipantActivityJoin).on('participant:activity-ack', _this.participantsService.onParticipantActivityAck).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(_this)).on('error', _this.onErrorHandled).on('status', /*#__PURE__*/function () {
|
|
167
|
+
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(status) {
|
|
168
|
+
var isLocked;
|
|
169
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
170
|
+
while (1) switch (_context.prev = _context.next) {
|
|
171
|
+
case 0:
|
|
172
|
+
_context.next = 2;
|
|
173
|
+
return _this.namespaceService.onNamespaceStatusChanged(status);
|
|
174
|
+
case 2:
|
|
175
|
+
isLocked = _this.namespaceService.getIsNamespaceLocked();
|
|
176
|
+
_this.emit('namespace-lock:check', {
|
|
177
|
+
isLocked: isLocked
|
|
178
|
+
});
|
|
179
|
+
case 4:
|
|
180
|
+
case "end":
|
|
181
|
+
return _context.stop();
|
|
182
|
+
}
|
|
183
|
+
}, _callee);
|
|
184
|
+
}));
|
|
185
|
+
return function (_x) {
|
|
186
|
+
return _ref4.apply(this, arguments);
|
|
187
|
+
};
|
|
188
|
+
}()).connect(shouldSkipDocumentInit);
|
|
166
189
|
});
|
|
167
190
|
(0, _defineProperty2.default)(_this, "setUserId", function (id) {
|
|
168
191
|
_this.userId = id;
|
|
@@ -209,8 +232,8 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
209
232
|
return _this.aiProviderActiveIds;
|
|
210
233
|
});
|
|
211
234
|
// Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
|
|
212
|
-
(0, _defineProperty2.default)(_this, "onDisconnected", function (
|
|
213
|
-
var reason =
|
|
235
|
+
(0, _defineProperty2.default)(_this, "onDisconnected", function (_ref5) {
|
|
236
|
+
var reason = _ref5.reason;
|
|
214
237
|
_this.disconnectedAt = Date.now();
|
|
215
238
|
_this.participantsService.disconnect(reason, _this.sessionId);
|
|
216
239
|
});
|
|
@@ -225,52 +248,52 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
225
248
|
* Used for draft sync, a process running every 5s for the first editor of a document to sync the document to the Confluence back-end.
|
|
226
249
|
* @throws {GetCurrentStateError} Something went wrong while returning the current state
|
|
227
250
|
*/
|
|
228
|
-
(0, _defineProperty2.default)(_this, "getCurrentState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
251
|
+
(0, _defineProperty2.default)(_this, "getCurrentState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
229
252
|
var _this$analyticsHelper4;
|
|
230
|
-
return _regenerator.default.wrap(function
|
|
231
|
-
while (1) switch (
|
|
253
|
+
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
254
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
232
255
|
case 0:
|
|
233
|
-
|
|
234
|
-
|
|
256
|
+
_context2.prev = 0;
|
|
257
|
+
_context2.next = 3;
|
|
235
258
|
return _this.documentService.getCurrentState();
|
|
236
259
|
case 3:
|
|
237
|
-
return
|
|
260
|
+
return _context2.abrupt("return", _context2.sent);
|
|
238
261
|
case 6:
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
(_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 || _this$analyticsHelper4.sendErrorEvent(
|
|
242
|
-
throw new _customErrors.GetCurrentStateError('Error while returning the current state of the draft document',
|
|
262
|
+
_context2.prev = 6;
|
|
263
|
+
_context2.t0 = _context2["catch"](0);
|
|
264
|
+
(_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 || _this$analyticsHelper4.sendErrorEvent(_context2.t0, 'Error while returning ADF version of current draft document');
|
|
265
|
+
throw new _customErrors.GetCurrentStateError('Error while returning the current state of the draft document', _context2.t0);
|
|
243
266
|
case 10:
|
|
244
267
|
case "end":
|
|
245
|
-
return
|
|
268
|
+
return _context2.stop();
|
|
246
269
|
}
|
|
247
|
-
},
|
|
270
|
+
}, _callee2, null, [[0, 6]]);
|
|
248
271
|
})));
|
|
249
272
|
/**
|
|
250
273
|
* Return the final acknowledged (by NCS) ADF version of the current draft document, together with it's title and the current step version.
|
|
251
274
|
* Used when returning the document to Confluence on publish.
|
|
252
275
|
* @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
|
|
253
276
|
*/
|
|
254
|
-
(0, _defineProperty2.default)(_this, "getFinalAcknowledgedState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
277
|
+
(0, _defineProperty2.default)(_this, "getFinalAcknowledgedState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
255
278
|
var _this$analyticsHelper5;
|
|
256
|
-
return _regenerator.default.wrap(function
|
|
257
|
-
while (1) switch (
|
|
279
|
+
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
280
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
258
281
|
case 0:
|
|
259
|
-
|
|
260
|
-
|
|
282
|
+
_context3.prev = 0;
|
|
283
|
+
_context3.next = 3;
|
|
261
284
|
return _this.documentService.getFinalAcknowledgedState();
|
|
262
285
|
case 3:
|
|
263
|
-
return
|
|
286
|
+
return _context3.abrupt("return", _context3.sent);
|
|
264
287
|
case 6:
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
(_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 || _this$analyticsHelper5.sendErrorEvent(
|
|
268
|
-
throw new _customErrors.GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document',
|
|
288
|
+
_context3.prev = 6;
|
|
289
|
+
_context3.t0 = _context3["catch"](0);
|
|
290
|
+
(_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 || _this$analyticsHelper5.sendErrorEvent(_context3.t0, 'Error while returning ADF version of the final draft document');
|
|
291
|
+
throw new _customErrors.GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context3.t0);
|
|
269
292
|
case 10:
|
|
270
293
|
case "end":
|
|
271
|
-
return
|
|
294
|
+
return _context3.stop();
|
|
272
295
|
}
|
|
273
|
-
},
|
|
296
|
+
}, _callee3, null, [[0, 6]]);
|
|
274
297
|
})));
|
|
275
298
|
(0, _defineProperty2.default)(_this, "getUnconfirmedSteps", function () {
|
|
276
299
|
return _this.documentService.getUnconfirmedSteps();
|
|
@@ -359,10 +382,10 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
359
382
|
*/
|
|
360
383
|
}, {
|
|
361
384
|
key: "setup",
|
|
362
|
-
value: function setup(
|
|
363
|
-
var getState =
|
|
364
|
-
editorApi =
|
|
365
|
-
onSyncUpError =
|
|
385
|
+
value: function setup(_ref8) {
|
|
386
|
+
var getState = _ref8.getState,
|
|
387
|
+
editorApi = _ref8.editorApi,
|
|
388
|
+
onSyncUpError = _ref8.onSyncUpError;
|
|
366
389
|
this.checkForCookies();
|
|
367
390
|
try {
|
|
368
391
|
// Ignored via go/ees005
|
|
@@ -456,16 +479,29 @@ var Provider = exports.Provider = /*#__PURE__*/function (_Emitter) {
|
|
|
456
479
|
}, {
|
|
457
480
|
key: "send",
|
|
458
481
|
value: function send(_tr, _oldState, newState) {
|
|
482
|
+
var _this2 = this;
|
|
459
483
|
try {
|
|
460
484
|
if (this.isViewOnly()) {
|
|
461
|
-
var _this$analyticsHelper10;
|
|
462
485
|
var error = {
|
|
463
486
|
message: 'Attempted to send steps in view only mode',
|
|
464
487
|
data: {
|
|
465
488
|
code: _internalErrors.INTERNAL_ERROR_CODE.VIEW_ONLY_STEPS_ERROR
|
|
466
489
|
}
|
|
467
490
|
};
|
|
468
|
-
(
|
|
491
|
+
if ((0, _platformFeatureFlags.fg)('log_obfuscated_steps_for_view_only')) {
|
|
492
|
+
(0, _utils.logObfuscatedSteps)(_oldState, newState).then(function (attributes) {
|
|
493
|
+
var _this2$analyticsHelpe;
|
|
494
|
+
var stepAttributes = attributes instanceof _customErrors.CustomError ? {} : _objectSpread({}, attributes);
|
|
495
|
+
var stepsError = new _customErrors.CustomError(error.message, error, _objectSpread({}, stepAttributes));
|
|
496
|
+
(_this2$analyticsHelpe = _this2.analyticsHelper) === null || _this2$analyticsHelpe === void 0 || _this2$analyticsHelpe.sendErrorEvent(stepsError, stepsError.message);
|
|
497
|
+
}).catch(function (err) {
|
|
498
|
+
var _this2$analyticsHelpe2;
|
|
499
|
+
return (_this2$analyticsHelpe2 = _this2.analyticsHelper) === null || _this2$analyticsHelpe2 === void 0 ? void 0 : _this2$analyticsHelpe2.sendErrorEvent(err, err.message);
|
|
500
|
+
});
|
|
501
|
+
} else {
|
|
502
|
+
var _this$analyticsHelper10;
|
|
503
|
+
(_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 || _this$analyticsHelper10.sendErrorEvent(error, error.message);
|
|
504
|
+
}
|
|
469
505
|
return;
|
|
470
506
|
}
|
|
471
507
|
// Don't send steps while the document is locked (eg. when restoring the document)
|
|
@@ -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.
|
|
8
|
+
var version = exports.version = "10.4.1";
|
|
9
9
|
var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
|
|
10
10
|
return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
|
|
11
11
|
};
|
|
@@ -58,8 +58,6 @@ const triggerAnalyticsEvent = (analyticsEvent, analyticsClient) => {
|
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
export default class AnalyticsHelper {
|
|
61
|
-
// Ignored via go/ees005
|
|
62
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
63
61
|
constructor(documentAri, subProduct, analyticsClient, getAnalyticsClient) {
|
|
64
62
|
this.documentAri = documentAri;
|
|
65
63
|
this.subProduct = subProduct;
|
package/dist/es2019/api/api.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { getProduct, getSubProduct, createLogger } from '../helpers/utils';
|
|
3
|
+
import { getActiveTraceHttpRequestHeaders } from '@atlaskit/react-ufo/experience-trace-id-context';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
|
+
import { addFeatureFlagAccessed } from '@atlaskit/react-ufo/feature-flags-accessed';
|
|
3
6
|
const logger = createLogger('Api', 'blue');
|
|
4
7
|
class AddCommentError extends Error {
|
|
5
8
|
constructor(message, status, meta) {
|
|
@@ -27,6 +30,14 @@ export class Api {
|
|
|
27
30
|
});
|
|
28
31
|
const url = `${this.config.url}/document/${encodeURIComponent(this.config.documentAri)}/comment`;
|
|
29
32
|
logger(`Request url: `, url);
|
|
33
|
+
|
|
34
|
+
//Get tracing headers from UFO
|
|
35
|
+
const tracingHeaderEnabled = fg('platform_collab_provider_tracingheaders');
|
|
36
|
+
addFeatureFlagAccessed('platform_collab_provider_tracingheaders', tracingHeaderEnabled);
|
|
37
|
+
let tracingHeaders = {};
|
|
38
|
+
if (tracingHeaderEnabled) {
|
|
39
|
+
tracingHeaders = getActiveTraceHttpRequestHeaders(url);
|
|
40
|
+
}
|
|
30
41
|
const fetchOptions = {
|
|
31
42
|
credentials: 'include',
|
|
32
43
|
headers: {
|
|
@@ -35,7 +46,8 @@ export class Api {
|
|
|
35
46
|
} : {}),
|
|
36
47
|
'x-product': getProduct(this.config.productInfo),
|
|
37
48
|
'x-subproduct': getSubProduct(this.config.productInfo),
|
|
38
|
-
'Content-Type': 'application/json'
|
|
49
|
+
'Content-Type': 'application/json',
|
|
50
|
+
...tracingHeaders
|
|
39
51
|
},
|
|
40
52
|
method: 'POST',
|
|
41
53
|
body: reqBody
|
package/dist/es2019/channel.js
CHANGED
|
@@ -173,8 +173,6 @@ export class Channel extends Emitter {
|
|
|
173
173
|
this.emit('steps:added', data);
|
|
174
174
|
}
|
|
175
175
|
});
|
|
176
|
-
// Ignored via go/ees005
|
|
177
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
178
176
|
_defineProperty(this, "fetchCatchupv2", async (fromVersion, clientId, catchUpOutofSync, reason) => {
|
|
179
177
|
try {
|
|
180
178
|
const {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
|
|
2
|
+
import { createLogger, getObfuscatedSteps, getDocAdfWithObfuscation } from '../helpers/utils';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
4
|
const logger = createLogger('Catchupv2', 'red');
|
|
3
5
|
export const catchupv2 = async opt => {
|
|
4
6
|
// Ignored via go/ees005
|
|
@@ -34,7 +36,11 @@ export const catchupv2 = async opt => {
|
|
|
34
36
|
};
|
|
35
37
|
opt.onStepsAdded(stepsPayload);
|
|
36
38
|
opt.updateMetadata(metadata);
|
|
37
|
-
|
|
39
|
+
const clientOutOfSync = Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId));
|
|
40
|
+
if (clientOutOfSync) {
|
|
41
|
+
logObfuscatedSteps(steps, opt);
|
|
42
|
+
}
|
|
43
|
+
return clientOutOfSync;
|
|
38
44
|
} catch (error) {
|
|
39
45
|
var _opt$analyticsHelper2;
|
|
40
46
|
(_opt$analyticsHelper2 = opt.analyticsHelper) === null || _opt$analyticsHelper2 === void 0 ? void 0 : _opt$analyticsHelper2.sendErrorEvent(error, 'Failed to apply catchupv2 result in the editor');
|
|
@@ -42,6 +48,17 @@ export const catchupv2 = async opt => {
|
|
|
42
48
|
throw error;
|
|
43
49
|
}
|
|
44
50
|
};
|
|
51
|
+
const logObfuscatedSteps = (steps, opt) => {
|
|
52
|
+
if (fg('platform_editor_log_obfuscated_steps')) {
|
|
53
|
+
var _opt$getState, _opt$analyticsHelper3;
|
|
54
|
+
const state = (_opt$getState = opt.getState) === null || _opt$getState === void 0 ? void 0 : _opt$getState.call(opt);
|
|
55
|
+
(_opt$analyticsHelper3 = opt.analyticsHelper) === null || _opt$analyticsHelper3 === void 0 ? void 0 : _opt$analyticsHelper3.sendActionEvent(EVENT_ACTION.OUT_OF_SYNC, EVENT_STATUS.FAILURE, {
|
|
56
|
+
obfuscatedSteps: getObfuscatedSteps(steps),
|
|
57
|
+
obfuscatedDoc: state ? getDocAdfWithObfuscation(state.doc) : null,
|
|
58
|
+
catchupReason: opt.reason
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
45
62
|
|
|
46
63
|
/**
|
|
47
64
|
* Checks if we're out of sync with the backend because catchup failed to apply, and thus the doc should be reset.
|
|
@@ -51,9 +68,6 @@ export const catchupv2 = async opt => {
|
|
|
51
68
|
* @param clientId The ID of the currently connected session (one user can have multiple if theu have multiple tabs open)
|
|
52
69
|
* @returns True if we're out of sync, false if not.
|
|
53
70
|
*/
|
|
54
|
-
export const isOutOfSync = (fromVersion, currentVersion, steps, clientId
|
|
55
|
-
// Ignored via go/ees005
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
57
|
-
) =>
|
|
71
|
+
export const isOutOfSync = (fromVersion, currentVersion, steps, clientId) =>
|
|
58
72
|
// If version number hasn't increased, and steps are not from our client, we're out of sync
|
|
59
73
|
Boolean(fromVersion >= currentVersion && steps.some(step => step.clientId !== clientId));
|
|
@@ -34,8 +34,6 @@ export class DocumentService {
|
|
|
34
34
|
* @param enableErrorOnFailedDocumentApply - Enable failed document update exceptions.
|
|
35
35
|
* @param getConnected - if the channel is currently connected
|
|
36
36
|
*/
|
|
37
|
-
// Ignored via go/ees005
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
39
37
|
constructor(participantsService, analyticsHelper, fetchCatchupv2, fetchReconcile,
|
|
40
38
|
// Ignored via go/ees005
|
|
41
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -46,6 +44,7 @@ export class DocumentService {
|
|
|
46
44
|
_defineProperty(this, "stepRejectCounter", 0);
|
|
47
45
|
_defineProperty(this, "aggressiveCatchup", false);
|
|
48
46
|
_defineProperty(this, "catchUpOutofSync", false);
|
|
47
|
+
_defineProperty(this, "hasRecovered", false);
|
|
49
48
|
/**
|
|
50
49
|
* To prevent calling catchup to often, use lodash throttle to reduce the frequency
|
|
51
50
|
* @param reason - optional reason to attach.
|
|
@@ -116,7 +115,8 @@ export class DocumentService {
|
|
|
116
115
|
remoteStepsLength: (_steps$length = steps === null || steps === void 0 ? void 0 : steps.length) !== null && _steps$length !== void 0 ? _steps$length : 0
|
|
117
116
|
});
|
|
118
117
|
}
|
|
119
|
-
}
|
|
118
|
+
},
|
|
119
|
+
getState: this.getState
|
|
120
120
|
});
|
|
121
121
|
const latency = new Date().getTime() - start;
|
|
122
122
|
(_this$analyticsHelper2 = this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendActionEvent(EVENT_ACTION.CATCHUP, EVENT_STATUS.SUCCESS, {
|
|
@@ -282,6 +282,9 @@ export class DocumentService {
|
|
|
282
282
|
metadata,
|
|
283
283
|
targetClientId
|
|
284
284
|
}) => {
|
|
285
|
+
if (!targetClientId) {
|
|
286
|
+
this.hasRecovered = true;
|
|
287
|
+
}
|
|
285
288
|
if (targetClientId && this.clientId !== targetClientId) {
|
|
286
289
|
return;
|
|
287
290
|
}
|
|
@@ -703,8 +706,6 @@ export class DocumentService {
|
|
|
703
706
|
* Send steps from transaction to other participants
|
|
704
707
|
* It needs the superfluous arguments because we keep the interface of the send API the same as the Synchrony plugin
|
|
705
708
|
*/
|
|
706
|
-
// Ignored via go/ees005
|
|
707
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
708
709
|
send(_tr, _oldState, newState, sendAnalyticsEvent) {
|
|
709
710
|
const unconfirmedStepsData = sendableSteps(newState);
|
|
710
711
|
const version = this.getVersionFromCollabState(newState, 'collab-provider: send');
|
|
@@ -762,7 +763,8 @@ export class DocumentService {
|
|
|
762
763
|
onErrorHandled: this.onErrorHandled,
|
|
763
764
|
analyticsHelper: this.analyticsHelper,
|
|
764
765
|
emit: this.providerEmitCallback,
|
|
765
|
-
__livePage: this.options.__livePage
|
|
766
|
+
__livePage: this.options.__livePage,
|
|
767
|
+
hasRecovered: this.hasRecovered
|
|
766
768
|
});
|
|
767
769
|
}
|
|
768
770
|
}
|
|
@@ -19,8 +19,9 @@ export let EVENT_ACTION = /*#__PURE__*/function (EVENT_ACTION) {
|
|
|
19
19
|
EVENT_ACTION["RECONNECTION"] = "providerReconnection";
|
|
20
20
|
EVENT_ACTION["PROVIDER_SETUP"] = "providerSetup";
|
|
21
21
|
EVENT_ACTION["HAS_UNCONFIRMED_STEPS"] = "hasUnconfirmedSteps";
|
|
22
|
+
EVENT_ACTION["OUT_OF_SYNC"] = "outOfSync";
|
|
22
23
|
return EVENT_ACTION;
|
|
23
|
-
}({}); // https://data-portal.internal.atlassian.com/analytics/registry/
|
|
24
|
+
}({}); // https://data-portal.internal.atlassian.com/analytics/registry/74993
|
|
24
25
|
export let EVENT_STATUS = /*#__PURE__*/function (EVENT_STATUS) {
|
|
25
26
|
EVENT_STATUS["SUCCESS"] = "SUCCESS";
|
|
26
27
|
EVENT_STATUS["FAILURE"] = "FAILURE";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { scrubAdf } from '@atlaskit/adf-utils/scrub';
|
|
2
|
+
import { sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
3
|
+
import { CustomError } from '../errors/custom-errors';
|
|
1
4
|
export const createLogger = (prefix, color = 'blue') =>
|
|
2
5
|
// Ignored via go/ees005
|
|
3
6
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -50,4 +53,159 @@ export const getStepUGCFreeDetails = step => {
|
|
|
50
53
|
contentTypes,
|
|
51
54
|
stepSizeInBytes: Buffer.byteLength(JSON.stringify(step))
|
|
52
55
|
};
|
|
53
|
-
};
|
|
56
|
+
};
|
|
57
|
+
const stepWithNextDocument = stepJson => {
|
|
58
|
+
return stepJson.stepType === 'override-document' && 'nextDocument' in stepJson;
|
|
59
|
+
};
|
|
60
|
+
const stepWithMark = stepJson => {
|
|
61
|
+
return stepJson.stepType === 'addMark' || stepJson.stepType === 'addNodeMark';
|
|
62
|
+
};
|
|
63
|
+
const stepWithAttrs = stepJson => {
|
|
64
|
+
return stepJson.stepType === 'setAttrs' && 'attrs' in stepJson;
|
|
65
|
+
};
|
|
66
|
+
const stepWithBatchAttrs = stepJson => {
|
|
67
|
+
return stepJson.stepType === 'batchAttrs' && 'data' in stepJson;
|
|
68
|
+
};
|
|
69
|
+
const stepWithFromTo = stepJson => {
|
|
70
|
+
return 'from' in stepJson && typeof stepJson.from === 'number' && 'to' in stepJson && typeof stepJson.to === 'number';
|
|
71
|
+
};
|
|
72
|
+
const stepWithGapFromTo = stepJson => {
|
|
73
|
+
return 'gapFrom' in stepJson && typeof stepJson.gapFrom === 'number' && 'gapTo' in stepJson && typeof stepJson.gapTo === 'number';
|
|
74
|
+
};
|
|
75
|
+
const stepWithInsert = stepJson => {
|
|
76
|
+
return 'insert' in stepJson && typeof stepJson.insert === 'number';
|
|
77
|
+
};
|
|
78
|
+
const stepWithPos = stepJson => {
|
|
79
|
+
return 'pos' in stepJson && typeof stepJson.pos === 'number';
|
|
80
|
+
};
|
|
81
|
+
const stepWithSlice = stepJson => {
|
|
82
|
+
var _stepJson$slice3;
|
|
83
|
+
return 'slice' in stepJson && Array.isArray((_stepJson$slice3 = stepJson.slice) === null || _stepJson$slice3 === void 0 ? void 0 : _stepJson$slice3.content);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Get as step info which is known not to contain user generated content.
|
|
87
|
+
export const getStepTypes = stepJson => {
|
|
88
|
+
let contentTypes = null;
|
|
89
|
+
if (stepWithSlice(stepJson)) {
|
|
90
|
+
contentTypes = stepJson.slice.content.map(c => {
|
|
91
|
+
return (c === null || c === void 0 ? void 0 : c.type) || 'unknown';
|
|
92
|
+
}).join(', ');
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
type: stepJson.stepType || 'unknown',
|
|
96
|
+
contentTypes
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
export const getStepsAdfWithObfuscation = stepJson => {
|
|
100
|
+
const stepContentAsAdf = stepToAdf(stepJson);
|
|
101
|
+
if (!stepContentAsAdf) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const scrubbedSteps = stepContentAsAdf.map(adf => scrubAdf(adf)).filter(adf => !!adf);
|
|
105
|
+
return scrubbedSteps;
|
|
106
|
+
};
|
|
107
|
+
export const getDocAdfWithObfuscation = doc => {
|
|
108
|
+
const docJson = doc.toJSON();
|
|
109
|
+
const scrubbedDoc = scrubAdf(docJson);
|
|
110
|
+
if (!scrubbedDoc) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return scrubbedDoc;
|
|
114
|
+
};
|
|
115
|
+
export const getStepPositions = stepJson => {
|
|
116
|
+
return {
|
|
117
|
+
...(stepWithFromTo(stepJson) && {
|
|
118
|
+
from: stepJson.from,
|
|
119
|
+
to: stepJson.to
|
|
120
|
+
}),
|
|
121
|
+
...(stepWithGapFromTo(stepJson) && {
|
|
122
|
+
gapFrom: stepJson.gapFrom,
|
|
123
|
+
gapTo: stepJson.gapTo
|
|
124
|
+
}),
|
|
125
|
+
...(stepWithInsert(stepJson) && {
|
|
126
|
+
insert: stepJson.insert
|
|
127
|
+
}),
|
|
128
|
+
...(stepWithPos(stepJson) && {
|
|
129
|
+
pos: stepJson.pos
|
|
130
|
+
})
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Returns the metadata for Step
|
|
136
|
+
* @description metadata is applied by transform overrides [here](https://bitbucket.org/atlassian/adf-schema/src/e13bbece84ede8f245067dc53dd7ce694f427eda/packages/editor-prosemirror/src/transform-override.ts#lines-12)
|
|
137
|
+
*/
|
|
138
|
+
const getStepMetadata = stepJson => {
|
|
139
|
+
return stepJson.metadata;
|
|
140
|
+
};
|
|
141
|
+
export const getObfuscatedSteps = (steps, endIndex = undefined) => {
|
|
142
|
+
return steps.slice(0, endIndex).map(step => {
|
|
143
|
+
return {
|
|
144
|
+
stepType: getStepTypes(step),
|
|
145
|
+
stepContent: getStepsAdfWithObfuscation(step),
|
|
146
|
+
stepPositions: getStepPositions(step),
|
|
147
|
+
stepMetadata: getStepMetadata(step)
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
const stepToAdf = step => {
|
|
152
|
+
if (stepWithSlice(step)) {
|
|
153
|
+
return [{
|
|
154
|
+
type: 'doc',
|
|
155
|
+
content: step.slice.content.filter(el => el !== null)
|
|
156
|
+
}];
|
|
157
|
+
} else if (stepWithNextDocument(step)) {
|
|
158
|
+
return [{
|
|
159
|
+
type: 'doc',
|
|
160
|
+
content: step.nextDocument.content
|
|
161
|
+
}];
|
|
162
|
+
} else if (stepWithMark(step) && step.mark) {
|
|
163
|
+
return [{
|
|
164
|
+
type: 'doc',
|
|
165
|
+
marks: [{
|
|
166
|
+
type: step.mark.type || 'unknown',
|
|
167
|
+
attrs: step.mark.attrs
|
|
168
|
+
}]
|
|
169
|
+
}];
|
|
170
|
+
} else if (stepWithAttrs(step)) {
|
|
171
|
+
return [{
|
|
172
|
+
type: 'doc',
|
|
173
|
+
attrs: step.attrs
|
|
174
|
+
}];
|
|
175
|
+
} else if (stepWithBatchAttrs(step)) {
|
|
176
|
+
return step.data.map(stepData => {
|
|
177
|
+
return {
|
|
178
|
+
type: 'doc',
|
|
179
|
+
attrs: stepData.attrs
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return [];
|
|
184
|
+
};
|
|
185
|
+
export async function logObfuscatedSteps(oldState, newState) {
|
|
186
|
+
try {
|
|
187
|
+
var _states$new, _states$old;
|
|
188
|
+
let stepsFromOldState = '',
|
|
189
|
+
stepsFromNewState = '';
|
|
190
|
+
const states = {
|
|
191
|
+
old: oldState ? sendableSteps(oldState) : null,
|
|
192
|
+
new: sendableSteps(newState)
|
|
193
|
+
};
|
|
194
|
+
if ((_states$new = states.new) !== null && _states$new !== void 0 && _states$new.steps) {
|
|
195
|
+
stepsFromNewState = await toObfuscatedSteps(states.new.steps);
|
|
196
|
+
}
|
|
197
|
+
if ((_states$old = states.old) !== null && _states$old !== void 0 && _states$old.steps) {
|
|
198
|
+
stepsFromOldState = await toObfuscatedSteps(states.old.steps);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
stepsFromOldState,
|
|
202
|
+
stepsFromNewState
|
|
203
|
+
};
|
|
204
|
+
} catch (err) {
|
|
205
|
+
return new CustomError('Failed to obfuscate steps', err);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
export async function toObfuscatedSteps(steps) {
|
|
209
|
+
const _steps = await Promise.resolve(steps.slice().map(s => s.toJSON()));
|
|
210
|
+
return JSON.stringify(getObfuscatedSteps(_steps));
|
|
211
|
+
}
|
|
@@ -18,8 +18,6 @@ const SEND_PRESENCE_INTERVAL = 150 * 1000; // 150 seconds
|
|
|
18
18
|
* @param sendPresenceJoined Callback to Channel class
|
|
19
19
|
*/
|
|
20
20
|
export class ParticipantsService {
|
|
21
|
-
// Ignored via go/ees005
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/max-params
|
|
23
21
|
constructor(analyticsHelper, participantsState = new ParticipantsState(), emit, getUser, channelBroadcast, sendPresenceJoined, getPresenceData, setUserId, getAIProviderActiveIds) {
|
|
24
22
|
_defineProperty(this, "sendAIProviderChanged", payload => {
|
|
25
23
|
if (payload.providerId) {
|
|
@@ -17,7 +17,8 @@ export const commitStepQueue = ({
|
|
|
17
17
|
onErrorHandled,
|
|
18
18
|
analyticsHelper,
|
|
19
19
|
emit,
|
|
20
|
-
__livePage
|
|
20
|
+
__livePage,
|
|
21
|
+
hasRecovered
|
|
21
22
|
}) => {
|
|
22
23
|
if (!readyToCommit) {
|
|
23
24
|
logger('Not ready to commit, skip');
|
|
@@ -60,6 +61,17 @@ export const commitStepQueue = ({
|
|
|
60
61
|
return step;
|
|
61
62
|
});
|
|
62
63
|
}
|
|
64
|
+
|
|
65
|
+
// tag unconfirmed steps sent after page has been recovered during client's editing session
|
|
66
|
+
if (hasRecovered && fg('tag_unconfirmed_steps_after_recovery')) {
|
|
67
|
+
stepsWithClientAndUserId = stepsWithClientAndUserId.map(step => {
|
|
68
|
+
step.metadata = {
|
|
69
|
+
...step.metadata,
|
|
70
|
+
unconfirmedStepAfterRecovery: true
|
|
71
|
+
};
|
|
72
|
+
return step;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
63
75
|
const start = new Date().getTime();
|
|
64
76
|
emit('commit-status', {
|
|
65
77
|
status: 'attempt',
|