@atlaskit/collab-provider 10.3.3 → 10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/collab-provider
2
2
 
3
+ ## 10.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#102499](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/102499)
8
+ [`c1bfe8b68a35e`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/c1bfe8b68a35e) -
9
+ log obfuscated steps in collab provider when catchup out of sync
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 10.3.4
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+
3
21
  ## 10.3.3
4
22
 
5
23
  ### Patch Changes
@@ -17,6 +17,9 @@
17
17
  "../src/**/test.*"
18
18
  ],
19
19
  "references": [
20
+ {
21
+ "path": "../../adf-utils/afm-cc/tsconfig.json"
22
+ },
20
23
  {
21
24
  "path": "../../../analytics/analytics-gas-types/afm-cc/tsconfig.json"
22
25
  },
@@ -7,11 +7,13 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.isOutOfSync = exports.catchupv2 = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _const = require("../helpers/const");
10
11
  var _utils = require("../helpers/utils");
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
11
13
  var logger = (0, _utils.createLogger)('Catchupv2', 'red');
12
14
  var catchupv2 = exports.catchupv2 = /*#__PURE__*/function () {
13
15
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(opt) {
14
- var steps, metadata, fromVersion, _yield$opt$fetchCatch, _opt$analyticsHelper, _opt$onCatchupComplet, version, stepsPayload, _opt$analyticsHelper2;
16
+ var steps, metadata, fromVersion, _yield$opt$fetchCatch, _opt$analyticsHelper, _opt$onCatchupComplet, version, stepsPayload, clientOutOfSync, _opt$analyticsHelper2;
15
17
  return _regenerator.default.wrap(function _callee$(_context) {
16
18
  while (1) switch (_context.prev = _context.next) {
17
19
  case 0:
@@ -53,23 +55,38 @@ var catchupv2 = exports.catchupv2 = /*#__PURE__*/function () {
53
55
  };
54
56
  opt.onStepsAdded(stepsPayload);
55
57
  opt.updateMetadata(metadata);
56
- return _context.abrupt("return", Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId)));
57
- case 26:
58
- _context.prev = 26;
58
+ clientOutOfSync = Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId));
59
+ if (clientOutOfSync) {
60
+ logObfuscatedSteps(steps, opt);
61
+ }
62
+ return _context.abrupt("return", clientOutOfSync);
63
+ case 28:
64
+ _context.prev = 28;
59
65
  _context.t1 = _context["catch"](14);
60
66
  (_opt$analyticsHelper2 = opt.analyticsHelper) === null || _opt$analyticsHelper2 === void 0 || _opt$analyticsHelper2.sendErrorEvent(_context.t1, 'Failed to apply catchupv2 result in the editor');
61
67
  logger("Apply catchupv2 steps failed:", _context.t1.message);
62
68
  throw _context.t1;
63
- case 31:
69
+ case 33:
64
70
  case "end":
65
71
  return _context.stop();
66
72
  }
67
- }, _callee, null, [[1, 9], [14, 26]]);
73
+ }, _callee, null, [[1, 9], [14, 28]]);
68
74
  }));
69
75
  return function catchupv2(_x) {
70
76
  return _ref.apply(this, arguments);
71
77
  };
72
78
  }();
79
+ var logObfuscatedSteps = function logObfuscatedSteps(steps, opt) {
80
+ if ((0, _platformFeatureFlags.fg)('platform_editor_log_obfuscated_steps')) {
81
+ var _opt$getState, _opt$analyticsHelper3;
82
+ var state = (_opt$getState = opt.getState) === null || _opt$getState === void 0 ? void 0 : _opt$getState.call(opt);
83
+ (_opt$analyticsHelper3 = opt.analyticsHelper) === null || _opt$analyticsHelper3 === void 0 || _opt$analyticsHelper3.sendActionEvent(_const.EVENT_ACTION.OUT_OF_SYNC, _const.EVENT_STATUS.FAILURE, {
84
+ obfuscatedSteps: (0, _utils.getObfuscatedSteps)(steps),
85
+ obfuscatedDoc: state ? (0, _utils.getDocAdfWithObfuscation)(state.doc) : null,
86
+ catchupReason: opt.reason
87
+ });
88
+ }
89
+ };
73
90
 
74
91
  /**
75
92
  * Checks if we're out of sync with the backend because catchup failed to apply, and thus the doc should be reset.
@@ -122,7 +122,8 @@ var DocumentService = exports.DocumentService = /*#__PURE__*/function () {
122
122
  remoteStepsLength: (_steps$length = steps === null || steps === void 0 ? void 0 : steps.length) !== null && _steps$length !== void 0 ? _steps$length : 0
123
123
  }));
124
124
  }
125
- }
125
+ },
126
+ getState: _this.getState
126
127
  });
127
128
  case 11:
128
129
  _this.catchUpOutofSync = _context.sent;
@@ -25,8 +25,9 @@ var EVENT_ACTION = exports.EVENT_ACTION = /*#__PURE__*/function (EVENT_ACTION) {
25
25
  EVENT_ACTION["RECONNECTION"] = "providerReconnection";
26
26
  EVENT_ACTION["PROVIDER_SETUP"] = "providerSetup";
27
27
  EVENT_ACTION["HAS_UNCONFIRMED_STEPS"] = "hasUnconfirmedSteps";
28
+ EVENT_ACTION["OUT_OF_SYNC"] = "outOfSync";
28
29
  return EVENT_ACTION;
29
- }({}); // https://data-portal.internal.atlassian.com/analytics/registry/56141
30
+ }({}); // https://data-portal.internal.atlassian.com/analytics/registry/74993
30
31
  var EVENT_STATUS = exports.EVENT_STATUS = /*#__PURE__*/function (EVENT_STATUS) {
31
32
  EVENT_STATUS["SUCCESS"] = "SUCCESS";
32
33
  EVENT_STATUS["FAILURE"] = "FAILURE";
@@ -1,10 +1,15 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.isAIProviderID = exports.getSubProduct = exports.getStepUGCFreeDetails = exports.getProduct = exports.createLogger = void 0;
7
+ exports.isAIProviderID = exports.getSubProduct = exports.getStepsAdfWithObfuscation = exports.getStepUGCFreeDetails = exports.getStepTypes = exports.getStepPositions = exports.getProduct = exports.getObfuscatedSteps = exports.getDocAdfWithObfuscation = exports.createLogger = void 0;
7
8
  exports.sleep = sleep;
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _scrub = require("@atlaskit/adf-utils/scrub");
11
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
12
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
13
  var createLogger = exports.createLogger = function createLogger(prefix) {
9
14
  var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'blue';
10
15
  return (
@@ -64,4 +69,134 @@ var getStepUGCFreeDetails = exports.getStepUGCFreeDetails = function getStepUGCF
64
69
  contentTypes: contentTypes,
65
70
  stepSizeInBytes: Buffer.byteLength(JSON.stringify(step))
66
71
  };
72
+ };
73
+ var stepWithNextDocument = function stepWithNextDocument(stepJson) {
74
+ return stepJson.stepType === 'override-document' && 'nextDocument' in stepJson;
75
+ };
76
+ var stepWithMark = function stepWithMark(stepJson) {
77
+ return stepJson.stepType === 'addMark' || stepJson.stepType === 'addNodeMark';
78
+ };
79
+ var stepWithAttrs = function stepWithAttrs(stepJson) {
80
+ return stepJson.stepType === 'setAttrs' && 'attrs' in stepJson;
81
+ };
82
+ var stepWithBatchAttrs = function stepWithBatchAttrs(stepJson) {
83
+ return stepJson.stepType === 'batchAttrs' && 'data' in stepJson;
84
+ };
85
+ var stepWithFromTo = function stepWithFromTo(stepJson) {
86
+ return 'from' in stepJson && typeof stepJson.from === 'number' && 'to' in stepJson && typeof stepJson.to === 'number';
87
+ };
88
+ var stepWithGapFromTo = function stepWithGapFromTo(stepJson) {
89
+ return 'gapFrom' in stepJson && typeof stepJson.gapFrom === 'number' && 'gapTo' in stepJson && typeof stepJson.gapTo === 'number';
90
+ };
91
+ var stepWithInsert = function stepWithInsert(stepJson) {
92
+ return 'insert' in stepJson && typeof stepJson.insert === 'number';
93
+ };
94
+ var stepWithPos = function stepWithPos(stepJson) {
95
+ return 'pos' in stepJson && typeof stepJson.pos === 'number';
96
+ };
97
+ var stepWithSlice = function stepWithSlice(stepJson) {
98
+ var _stepJson$slice3;
99
+ return 'slice' in stepJson && Array.isArray((_stepJson$slice3 = stepJson.slice) === null || _stepJson$slice3 === void 0 ? void 0 : _stepJson$slice3.content);
100
+ };
101
+
102
+ // Get as step info which is known not to contain user generated content.
103
+ var getStepTypes = exports.getStepTypes = function getStepTypes(stepJson) {
104
+ var contentTypes = null;
105
+ if (stepWithSlice(stepJson)) {
106
+ contentTypes = stepJson.slice.content.map(function (c) {
107
+ return (c === null || c === void 0 ? void 0 : c.type) || 'unknown';
108
+ }).join(', ');
109
+ }
110
+ return {
111
+ type: stepJson.stepType || 'unknown',
112
+ contentTypes: contentTypes
113
+ };
114
+ };
115
+ var getStepsAdfWithObfuscation = exports.getStepsAdfWithObfuscation = function getStepsAdfWithObfuscation(stepJson) {
116
+ var stepContentAsAdf = stepToAdf(stepJson);
117
+ if (!stepContentAsAdf) {
118
+ return null;
119
+ }
120
+ var scrubbedSteps = stepContentAsAdf.map(function (adf) {
121
+ return (0, _scrub.scrubAdf)(adf);
122
+ }).filter(function (adf) {
123
+ return !!adf;
124
+ });
125
+ return scrubbedSteps;
126
+ };
127
+ var getDocAdfWithObfuscation = exports.getDocAdfWithObfuscation = function getDocAdfWithObfuscation(doc) {
128
+ var docJson = doc.toJSON();
129
+ var scrubbedDoc = (0, _scrub.scrubAdf)(docJson);
130
+ if (!scrubbedDoc) {
131
+ return null;
132
+ }
133
+ return scrubbedDoc;
134
+ };
135
+ var getStepPositions = exports.getStepPositions = function getStepPositions(stepJson) {
136
+ return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, stepWithFromTo(stepJson) && {
137
+ from: stepJson.from,
138
+ to: stepJson.to
139
+ }), stepWithGapFromTo(stepJson) && {
140
+ gapFrom: stepJson.gapFrom,
141
+ gapTo: stepJson.gapTo
142
+ }), stepWithInsert(stepJson) && {
143
+ insert: stepJson.insert
144
+ }), stepWithPos(stepJson) && {
145
+ pos: stepJson.pos
146
+ });
147
+ };
148
+
149
+ /**
150
+ * Returns the metadata for Step
151
+ * @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)
152
+ */
153
+ var getStepMetadata = function getStepMetadata(stepJson) {
154
+ return stepJson.metadata;
155
+ };
156
+ var getObfuscatedSteps = exports.getObfuscatedSteps = function getObfuscatedSteps(steps) {
157
+ var endIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
158
+ return steps.slice(0, endIndex).map(function (step) {
159
+ return {
160
+ stepType: getStepTypes(step),
161
+ stepContent: getStepsAdfWithObfuscation(step),
162
+ stepPositions: getStepPositions(step),
163
+ stepMetadata: getStepMetadata(step)
164
+ };
165
+ });
166
+ };
167
+ var stepToAdf = function stepToAdf(step) {
168
+ if (stepWithSlice(step)) {
169
+ return [{
170
+ type: 'doc',
171
+ content: step.slice.content.filter(function (el) {
172
+ return el !== null;
173
+ })
174
+ }];
175
+ } else if (stepWithNextDocument(step)) {
176
+ return [{
177
+ type: 'doc',
178
+ content: step.nextDocument.content
179
+ }];
180
+ } else if (stepWithMark(step) && step.mark) {
181
+ return [{
182
+ type: 'doc',
183
+ marks: [{
184
+ type: step.mark.type || 'unknown',
185
+ attrs: step.mark.attrs
186
+ }]
187
+ }];
188
+ } else if (stepWithAttrs(step)) {
189
+ return [{
190
+ type: 'doc',
191
+ attrs: step.attrs
192
+ }];
193
+ } else if (stepWithBatchAttrs(step)) {
194
+ return step.data.map(function (stepData) {
195
+ return {
196
+ type: 'doc',
197
+ attrs: stepData.attrs
198
+ };
199
+ });
200
+ }
201
+ return [];
67
202
  };
@@ -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.3.3";
8
+ var version = exports.version = "10.4.0";
9
9
  var nextMajorVersion = exports.nextMajorVersion = function nextMajorVersion() {
10
10
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
11
11
  };
@@ -1,4 +1,6 @@
1
- import { createLogger } from '../helpers/utils';
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
- return Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId));
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.
@@ -116,7 +116,8 @@ export class DocumentService {
116
116
  remoteStepsLength: (_steps$length = steps === null || steps === void 0 ? void 0 : steps.length) !== null && _steps$length !== void 0 ? _steps$length : 0
117
117
  });
118
118
  }
119
- }
119
+ },
120
+ getState: this.getState
120
121
  });
121
122
  const latency = new Date().getTime() - start;
122
123
  (_this$analyticsHelper2 = this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendActionEvent(EVENT_ACTION.CATCHUP, EVENT_STATUS.SUCCESS, {
@@ -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/56141
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,4 @@
1
+ import { scrubAdf } from '@atlaskit/adf-utils/scrub';
1
2
  export const createLogger = (prefix, color = 'blue') =>
2
3
  // Ignored via go/ees005
3
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -50,4 +51,132 @@ export const getStepUGCFreeDetails = step => {
50
51
  contentTypes,
51
52
  stepSizeInBytes: Buffer.byteLength(JSON.stringify(step))
52
53
  };
54
+ };
55
+ const stepWithNextDocument = stepJson => {
56
+ return stepJson.stepType === 'override-document' && 'nextDocument' in stepJson;
57
+ };
58
+ const stepWithMark = stepJson => {
59
+ return stepJson.stepType === 'addMark' || stepJson.stepType === 'addNodeMark';
60
+ };
61
+ const stepWithAttrs = stepJson => {
62
+ return stepJson.stepType === 'setAttrs' && 'attrs' in stepJson;
63
+ };
64
+ const stepWithBatchAttrs = stepJson => {
65
+ return stepJson.stepType === 'batchAttrs' && 'data' in stepJson;
66
+ };
67
+ const stepWithFromTo = stepJson => {
68
+ return 'from' in stepJson && typeof stepJson.from === 'number' && 'to' in stepJson && typeof stepJson.to === 'number';
69
+ };
70
+ const stepWithGapFromTo = stepJson => {
71
+ return 'gapFrom' in stepJson && typeof stepJson.gapFrom === 'number' && 'gapTo' in stepJson && typeof stepJson.gapTo === 'number';
72
+ };
73
+ const stepWithInsert = stepJson => {
74
+ return 'insert' in stepJson && typeof stepJson.insert === 'number';
75
+ };
76
+ const stepWithPos = stepJson => {
77
+ return 'pos' in stepJson && typeof stepJson.pos === 'number';
78
+ };
79
+ const stepWithSlice = stepJson => {
80
+ var _stepJson$slice3;
81
+ return 'slice' in stepJson && Array.isArray((_stepJson$slice3 = stepJson.slice) === null || _stepJson$slice3 === void 0 ? void 0 : _stepJson$slice3.content);
82
+ };
83
+
84
+ // Get as step info which is known not to contain user generated content.
85
+ export const getStepTypes = stepJson => {
86
+ let contentTypes = null;
87
+ if (stepWithSlice(stepJson)) {
88
+ contentTypes = stepJson.slice.content.map(c => {
89
+ return (c === null || c === void 0 ? void 0 : c.type) || 'unknown';
90
+ }).join(', ');
91
+ }
92
+ return {
93
+ type: stepJson.stepType || 'unknown',
94
+ contentTypes
95
+ };
96
+ };
97
+ export const getStepsAdfWithObfuscation = stepJson => {
98
+ const stepContentAsAdf = stepToAdf(stepJson);
99
+ if (!stepContentAsAdf) {
100
+ return null;
101
+ }
102
+ const scrubbedSteps = stepContentAsAdf.map(adf => scrubAdf(adf)).filter(adf => !!adf);
103
+ return scrubbedSteps;
104
+ };
105
+ export const getDocAdfWithObfuscation = doc => {
106
+ const docJson = doc.toJSON();
107
+ const scrubbedDoc = scrubAdf(docJson);
108
+ if (!scrubbedDoc) {
109
+ return null;
110
+ }
111
+ return scrubbedDoc;
112
+ };
113
+ export const getStepPositions = stepJson => {
114
+ return {
115
+ ...(stepWithFromTo(stepJson) && {
116
+ from: stepJson.from,
117
+ to: stepJson.to
118
+ }),
119
+ ...(stepWithGapFromTo(stepJson) && {
120
+ gapFrom: stepJson.gapFrom,
121
+ gapTo: stepJson.gapTo
122
+ }),
123
+ ...(stepWithInsert(stepJson) && {
124
+ insert: stepJson.insert
125
+ }),
126
+ ...(stepWithPos(stepJson) && {
127
+ pos: stepJson.pos
128
+ })
129
+ };
130
+ };
131
+
132
+ /**
133
+ * Returns the metadata for Step
134
+ * @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)
135
+ */
136
+ const getStepMetadata = stepJson => {
137
+ return stepJson.metadata;
138
+ };
139
+ export const getObfuscatedSteps = (steps, endIndex = undefined) => {
140
+ return steps.slice(0, endIndex).map(step => {
141
+ return {
142
+ stepType: getStepTypes(step),
143
+ stepContent: getStepsAdfWithObfuscation(step),
144
+ stepPositions: getStepPositions(step),
145
+ stepMetadata: getStepMetadata(step)
146
+ };
147
+ });
148
+ };
149
+ const stepToAdf = step => {
150
+ if (stepWithSlice(step)) {
151
+ return [{
152
+ type: 'doc',
153
+ content: step.slice.content.filter(el => el !== null)
154
+ }];
155
+ } else if (stepWithNextDocument(step)) {
156
+ return [{
157
+ type: 'doc',
158
+ content: step.nextDocument.content
159
+ }];
160
+ } else if (stepWithMark(step) && step.mark) {
161
+ return [{
162
+ type: 'doc',
163
+ marks: [{
164
+ type: step.mark.type || 'unknown',
165
+ attrs: step.mark.attrs
166
+ }]
167
+ }];
168
+ } else if (stepWithAttrs(step)) {
169
+ return [{
170
+ type: 'doc',
171
+ attrs: step.attrs
172
+ }];
173
+ } else if (stepWithBatchAttrs(step)) {
174
+ return step.data.map(stepData => {
175
+ return {
176
+ type: 'doc',
177
+ attrs: stepData.attrs
178
+ };
179
+ });
180
+ }
181
+ return [];
53
182
  };
@@ -1,5 +1,5 @@
1
1
  export const name = "@atlaskit/collab-provider";
2
- export const version = "10.3.3";
2
+ export const version = "10.4.0";
3
3
  export const nextMajorVersion = () => {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -1,10 +1,12 @@
1
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
- import { createLogger } from '../helpers/utils';
3
+ import { EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
4
+ import { createLogger, getObfuscatedSteps, getDocAdfWithObfuscation } from '../helpers/utils';
5
+ import { fg } from '@atlaskit/platform-feature-flags';
4
6
  var logger = createLogger('Catchupv2', 'red');
5
7
  export var catchupv2 = /*#__PURE__*/function () {
6
8
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(opt) {
7
- var steps, metadata, fromVersion, _yield$opt$fetchCatch, _opt$analyticsHelper, _opt$onCatchupComplet, version, stepsPayload, _opt$analyticsHelper2;
9
+ var steps, metadata, fromVersion, _yield$opt$fetchCatch, _opt$analyticsHelper, _opt$onCatchupComplet, version, stepsPayload, clientOutOfSync, _opt$analyticsHelper2;
8
10
  return _regeneratorRuntime.wrap(function _callee$(_context) {
9
11
  while (1) switch (_context.prev = _context.next) {
10
12
  case 0:
@@ -46,23 +48,38 @@ export var catchupv2 = /*#__PURE__*/function () {
46
48
  };
47
49
  opt.onStepsAdded(stepsPayload);
48
50
  opt.updateMetadata(metadata);
49
- return _context.abrupt("return", Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId)));
50
- case 26:
51
- _context.prev = 26;
51
+ clientOutOfSync = Boolean(opt.clientId && isOutOfSync(fromVersion, opt.getCurrentPmVersion(), steps, opt.clientId));
52
+ if (clientOutOfSync) {
53
+ logObfuscatedSteps(steps, opt);
54
+ }
55
+ return _context.abrupt("return", clientOutOfSync);
56
+ case 28:
57
+ _context.prev = 28;
52
58
  _context.t1 = _context["catch"](14);
53
59
  (_opt$analyticsHelper2 = opt.analyticsHelper) === null || _opt$analyticsHelper2 === void 0 || _opt$analyticsHelper2.sendErrorEvent(_context.t1, 'Failed to apply catchupv2 result in the editor');
54
60
  logger("Apply catchupv2 steps failed:", _context.t1.message);
55
61
  throw _context.t1;
56
- case 31:
62
+ case 33:
57
63
  case "end":
58
64
  return _context.stop();
59
65
  }
60
- }, _callee, null, [[1, 9], [14, 26]]);
66
+ }, _callee, null, [[1, 9], [14, 28]]);
61
67
  }));
62
68
  return function catchupv2(_x) {
63
69
  return _ref.apply(this, arguments);
64
70
  };
65
71
  }();
72
+ var logObfuscatedSteps = function logObfuscatedSteps(steps, opt) {
73
+ if (fg('platform_editor_log_obfuscated_steps')) {
74
+ var _opt$getState, _opt$analyticsHelper3;
75
+ var state = (_opt$getState = opt.getState) === null || _opt$getState === void 0 ? void 0 : _opt$getState.call(opt);
76
+ (_opt$analyticsHelper3 = opt.analyticsHelper) === null || _opt$analyticsHelper3 === void 0 || _opt$analyticsHelper3.sendActionEvent(EVENT_ACTION.OUT_OF_SYNC, EVENT_STATUS.FAILURE, {
77
+ obfuscatedSteps: getObfuscatedSteps(steps),
78
+ obfuscatedDoc: state ? getDocAdfWithObfuscation(state.doc) : null,
79
+ catchupReason: opt.reason
80
+ });
81
+ }
82
+ };
66
83
 
67
84
  /**
68
85
  * Checks if we're out of sync with the backend because catchup failed to apply, and thus the doc should be reset.
@@ -115,7 +115,8 @@ export var DocumentService = /*#__PURE__*/function () {
115
115
  remoteStepsLength: (_steps$length = steps === null || steps === void 0 ? void 0 : steps.length) !== null && _steps$length !== void 0 ? _steps$length : 0
116
116
  }));
117
117
  }
118
- }
118
+ },
119
+ getState: _this.getState
119
120
  });
120
121
  case 11:
121
122
  _this.catchUpOutofSync = _context.sent;
@@ -19,8 +19,9 @@ export var 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/56141
24
+ }({}); // https://data-portal.internal.atlassian.com/analytics/registry/74993
24
25
  export var EVENT_STATUS = /*#__PURE__*/function (EVENT_STATUS) {
25
26
  EVENT_STATUS["SUCCESS"] = "SUCCESS";
26
27
  EVENT_STATUS["FAILURE"] = "FAILURE";
@@ -1,3 +1,7 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { scrubAdf } from '@atlaskit/adf-utils/scrub';
1
5
  export var createLogger = function createLogger(prefix) {
2
6
  var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'blue';
3
7
  return (
@@ -57,4 +61,134 @@ export var getStepUGCFreeDetails = function getStepUGCFreeDetails(step) {
57
61
  contentTypes: contentTypes,
58
62
  stepSizeInBytes: Buffer.byteLength(JSON.stringify(step))
59
63
  };
64
+ };
65
+ var stepWithNextDocument = function stepWithNextDocument(stepJson) {
66
+ return stepJson.stepType === 'override-document' && 'nextDocument' in stepJson;
67
+ };
68
+ var stepWithMark = function stepWithMark(stepJson) {
69
+ return stepJson.stepType === 'addMark' || stepJson.stepType === 'addNodeMark';
70
+ };
71
+ var stepWithAttrs = function stepWithAttrs(stepJson) {
72
+ return stepJson.stepType === 'setAttrs' && 'attrs' in stepJson;
73
+ };
74
+ var stepWithBatchAttrs = function stepWithBatchAttrs(stepJson) {
75
+ return stepJson.stepType === 'batchAttrs' && 'data' in stepJson;
76
+ };
77
+ var stepWithFromTo = function stepWithFromTo(stepJson) {
78
+ return 'from' in stepJson && typeof stepJson.from === 'number' && 'to' in stepJson && typeof stepJson.to === 'number';
79
+ };
80
+ var stepWithGapFromTo = function stepWithGapFromTo(stepJson) {
81
+ return 'gapFrom' in stepJson && typeof stepJson.gapFrom === 'number' && 'gapTo' in stepJson && typeof stepJson.gapTo === 'number';
82
+ };
83
+ var stepWithInsert = function stepWithInsert(stepJson) {
84
+ return 'insert' in stepJson && typeof stepJson.insert === 'number';
85
+ };
86
+ var stepWithPos = function stepWithPos(stepJson) {
87
+ return 'pos' in stepJson && typeof stepJson.pos === 'number';
88
+ };
89
+ var stepWithSlice = function stepWithSlice(stepJson) {
90
+ var _stepJson$slice3;
91
+ return 'slice' in stepJson && Array.isArray((_stepJson$slice3 = stepJson.slice) === null || _stepJson$slice3 === void 0 ? void 0 : _stepJson$slice3.content);
92
+ };
93
+
94
+ // Get as step info which is known not to contain user generated content.
95
+ export var getStepTypes = function getStepTypes(stepJson) {
96
+ var contentTypes = null;
97
+ if (stepWithSlice(stepJson)) {
98
+ contentTypes = stepJson.slice.content.map(function (c) {
99
+ return (c === null || c === void 0 ? void 0 : c.type) || 'unknown';
100
+ }).join(', ');
101
+ }
102
+ return {
103
+ type: stepJson.stepType || 'unknown',
104
+ contentTypes: contentTypes
105
+ };
106
+ };
107
+ export var getStepsAdfWithObfuscation = function getStepsAdfWithObfuscation(stepJson) {
108
+ var stepContentAsAdf = stepToAdf(stepJson);
109
+ if (!stepContentAsAdf) {
110
+ return null;
111
+ }
112
+ var scrubbedSteps = stepContentAsAdf.map(function (adf) {
113
+ return scrubAdf(adf);
114
+ }).filter(function (adf) {
115
+ return !!adf;
116
+ });
117
+ return scrubbedSteps;
118
+ };
119
+ export var getDocAdfWithObfuscation = function getDocAdfWithObfuscation(doc) {
120
+ var docJson = doc.toJSON();
121
+ var scrubbedDoc = scrubAdf(docJson);
122
+ if (!scrubbedDoc) {
123
+ return null;
124
+ }
125
+ return scrubbedDoc;
126
+ };
127
+ export var getStepPositions = function getStepPositions(stepJson) {
128
+ return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, stepWithFromTo(stepJson) && {
129
+ from: stepJson.from,
130
+ to: stepJson.to
131
+ }), stepWithGapFromTo(stepJson) && {
132
+ gapFrom: stepJson.gapFrom,
133
+ gapTo: stepJson.gapTo
134
+ }), stepWithInsert(stepJson) && {
135
+ insert: stepJson.insert
136
+ }), stepWithPos(stepJson) && {
137
+ pos: stepJson.pos
138
+ });
139
+ };
140
+
141
+ /**
142
+ * Returns the metadata for Step
143
+ * @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)
144
+ */
145
+ var getStepMetadata = function getStepMetadata(stepJson) {
146
+ return stepJson.metadata;
147
+ };
148
+ export var getObfuscatedSteps = function getObfuscatedSteps(steps) {
149
+ var endIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
150
+ return steps.slice(0, endIndex).map(function (step) {
151
+ return {
152
+ stepType: getStepTypes(step),
153
+ stepContent: getStepsAdfWithObfuscation(step),
154
+ stepPositions: getStepPositions(step),
155
+ stepMetadata: getStepMetadata(step)
156
+ };
157
+ });
158
+ };
159
+ var stepToAdf = function stepToAdf(step) {
160
+ if (stepWithSlice(step)) {
161
+ return [{
162
+ type: 'doc',
163
+ content: step.slice.content.filter(function (el) {
164
+ return el !== null;
165
+ })
166
+ }];
167
+ } else if (stepWithNextDocument(step)) {
168
+ return [{
169
+ type: 'doc',
170
+ content: step.nextDocument.content
171
+ }];
172
+ } else if (stepWithMark(step) && step.mark) {
173
+ return [{
174
+ type: 'doc',
175
+ marks: [{
176
+ type: step.mark.type || 'unknown',
177
+ attrs: step.mark.attrs
178
+ }]
179
+ }];
180
+ } else if (stepWithAttrs(step)) {
181
+ return [{
182
+ type: 'doc',
183
+ attrs: step.attrs
184
+ }];
185
+ } else if (stepWithBatchAttrs(step)) {
186
+ return step.data.map(function (stepData) {
187
+ return {
188
+ type: 'doc',
189
+ attrs: stepData.attrs
190
+ };
191
+ });
192
+ }
193
+ return [];
60
194
  };
@@ -1,5 +1,5 @@
1
1
  export var name = "@atlaskit/collab-provider";
2
- export var version = "10.3.3";
2
+ export var version = "10.4.0";
3
3
  export var nextMajorVersion = function nextMajorVersion() {
4
4
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
5
5
  };
@@ -19,7 +19,8 @@ export declare enum EVENT_ACTION {
19
19
  PROVIDER_INITIALIZED = "providerInitialized",// https://data-portal.internal.atlassian.com/analytics/registry/54714
20
20
  RECONNECTION = "providerReconnection",// https://data-portal.internal.atlassian.com/analytics/registry/73992
21
21
  PROVIDER_SETUP = "providerSetup",// https://data-portal.internal.atlassian.com/analytics/registry/54715
22
- HAS_UNCONFIRMED_STEPS = "hasUnconfirmedSteps"
22
+ HAS_UNCONFIRMED_STEPS = "hasUnconfirmedSteps",// https://data-portal.internal.atlassian.com/analytics/registry/56141
23
+ OUT_OF_SYNC = "outOfSync"
23
24
  }
24
25
  export declare enum EVENT_STATUS {
25
26
  SUCCESS = "SUCCESS",
@@ -261,7 +262,20 @@ type ReconnectionAnalyticsEvent = {
261
262
  disconnectionPeriodSeconds: number;
262
263
  } & BaseActionAnalyticsEventAttributes;
263
264
  };
264
- export type ActionAnalyticsEvent = AddStepsSuccessAnalyticsEvent | AddStepsFailureAnalyticsEvent | ReInitDocFailAnalyticsEvent | ReInitDocSuccessAnalyticsEvent | ConnectionSuccessAnalyticsEvent | ConnectionFailureAnalyticsEvent | CatchUpSuccessAnalyticsEvent | CatchUpFailureAnalyticsEvent | DocumentInitSuccessAnalyticsEvent | UpdateParticipantsSuccessAnalyticsEvent | CommitUnconfirmedStepsSuccessAnalyticsEvent | CommitUnconfirmedStepsFailureAnalyticsEvent | PublishPageSuccessAnalyticsEvent | PublishPageFailureAnalyticsEvent | GetCurrentStateSuccessAnalyticsEvent | GetCurrentStateFailureAnalyticsEvent | InvalidateTokenAnalyticsEvent | SendStepsRetryAnalyticsEvent | CatchupAfterMaxSendStepsRetryAnalyticsEvent | CatchUpDroppedStepsEvent | WebsocketMessageVolumeMetricEvent | ProviderInitializedAnalyticsEvent | ProviderSetupAnalyticsEvent | ProviderHasUnconfirmedStepsAnalyticsEvent | UpdateDocumentAnalyticsEvent | ReconnectionAnalyticsEvent;
265
+ type OutOfSyncAnalyticsEvent = {
266
+ eventAction: EVENT_ACTION.OUT_OF_SYNC;
267
+ attributes: {
268
+ eventStatus: EVENT_STATUS.FAILURE;
269
+ obfuscatedSteps: {
270
+ [key: string]: number;
271
+ }[];
272
+ obfuscatedDoc: {
273
+ [key: string]: number;
274
+ };
275
+ catchupReason: CatchupEventReason | undefined;
276
+ } & BaseActionAnalyticsEventAttributes;
277
+ };
278
+ export type ActionAnalyticsEvent = AddStepsSuccessAnalyticsEvent | AddStepsFailureAnalyticsEvent | ReInitDocFailAnalyticsEvent | ReInitDocSuccessAnalyticsEvent | ConnectionSuccessAnalyticsEvent | ConnectionFailureAnalyticsEvent | CatchUpSuccessAnalyticsEvent | CatchUpFailureAnalyticsEvent | DocumentInitSuccessAnalyticsEvent | UpdateParticipantsSuccessAnalyticsEvent | CommitUnconfirmedStepsSuccessAnalyticsEvent | CommitUnconfirmedStepsFailureAnalyticsEvent | PublishPageSuccessAnalyticsEvent | PublishPageFailureAnalyticsEvent | GetCurrentStateSuccessAnalyticsEvent | GetCurrentStateFailureAnalyticsEvent | InvalidateTokenAnalyticsEvent | SendStepsRetryAnalyticsEvent | CatchupAfterMaxSendStepsRetryAnalyticsEvent | CatchUpDroppedStepsEvent | WebsocketMessageVolumeMetricEvent | ProviderInitializedAnalyticsEvent | ProviderSetupAnalyticsEvent | ProviderHasUnconfirmedStepsAnalyticsEvent | UpdateDocumentAnalyticsEvent | ReconnectionAnalyticsEvent | OutOfSyncAnalyticsEvent;
265
279
  export declare const ACK_MAX_TRY = 60;
266
280
  export declare const CONFLUENCE = "confluence";
267
281
  /** Enumerable for attaching a reason to catchup (v2) call(s) */
@@ -1,5 +1,8 @@
1
+ import { type ADFEntity } from '@atlaskit/adf-utils/types';
1
2
  import type { ProductInformation } from '../types';
2
3
  import type { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
4
+ import type { StepJson } from '@atlaskit/editor-common/collab';
5
+ import type { Node as ProseMirrorNode } from '@atlaskit/editor-prosemirror/model';
3
6
  export declare const createLogger: (prefix: string, color?: string) => (msg: string, data?: any) => void;
4
7
  export declare function sleep(ms: number): Promise<unknown>;
5
8
  export declare const isAIProviderID: (id: string) => boolean;
@@ -11,3 +14,41 @@ export type UGCFreeStepDetails = {
11
14
  stepSizeInBytes?: number;
12
15
  };
13
16
  export declare const getStepUGCFreeDetails: (step: ProseMirrorStep) => UGCFreeStepDetails;
17
+ export declare const getStepTypes: (stepJson: StepJson) => {
18
+ type: string;
19
+ contentTypes: string | null;
20
+ };
21
+ export declare const getStepsAdfWithObfuscation: (stepJson: StepJson) => ADFEntity[] | null;
22
+ export declare const getDocAdfWithObfuscation: (doc: ProseMirrorNode) => ADFEntity | null;
23
+ export declare const getStepPositions: (stepJson: StepJson) => {
24
+ pos?: number | undefined;
25
+ insert?: number | undefined;
26
+ gapFrom?: number | undefined;
27
+ gapTo?: number | undefined;
28
+ from?: number | undefined;
29
+ to?: number | undefined;
30
+ };
31
+ export declare const getObfuscatedSteps: (steps: StepJson[], endIndex?: number | undefined) => {
32
+ stepType: {
33
+ type: string;
34
+ contentTypes: string | null;
35
+ };
36
+ stepContent: ADFEntity[] | null;
37
+ stepPositions: {
38
+ pos?: number | undefined;
39
+ insert?: number | undefined;
40
+ gapFrom?: number | undefined;
41
+ gapTo?: number | undefined;
42
+ from?: number | undefined;
43
+ to?: number | undefined;
44
+ };
45
+ stepMetadata: {
46
+ source?: string | undefined;
47
+ stepId?: string | undefined;
48
+ prevStepId?: string | undefined;
49
+ rebased?: boolean | undefined;
50
+ traceId?: string | undefined;
51
+ reqId?: string | undefined;
52
+ schemaVersion?: string | undefined;
53
+ } | undefined;
54
+ }[];
@@ -1,4 +1,3 @@
1
- import type { Step } from '@atlaskit/editor-prosemirror/transform';
2
1
  import type { AnalyticsWebClient } from '@atlaskit/analytics-listeners';
3
2
  import type { Manager, Socket as SocketIOSocket } from 'socket.io-client';
4
3
  import type { InternalError } from './errors/internal-errors';
@@ -7,6 +6,7 @@ import type { GetUserType } from './participants/participants-helper';
7
6
  import type AnalyticsHelper from './analytics/analytics-helper';
8
7
  import type { StepJson, CollabSendableSelection, Metadata, UserPermitType, Activity, PresenceActivity } from '@atlaskit/editor-common/collab';
9
8
  import { type CatchupEventReason } from './helpers/const';
9
+ import type { EditorState } from '@atlaskit/editor-prosemirror/state';
10
10
  export interface CollabEventDisconnectedData {
11
11
  sid: string;
12
12
  reason: 'CLIENT_DISCONNECT' | 'SERVER_DISCONNECT' | 'SOCKET_CLOSED' | 'SOCKET_ERROR' | 'SOCKET_TIMEOUT' | 'UNKNOWN_DISCONNECT';
@@ -199,7 +199,7 @@ export type ChannelEvent = {
199
199
  status: NamespaceStatus;
200
200
  };
201
201
  export interface Catchupv2Response {
202
- steps?: Step[];
202
+ steps?: StepJson[];
203
203
  metadata?: Metadata;
204
204
  }
205
205
  export interface ReconcileResponse {
@@ -218,6 +218,7 @@ export interface Catchupv2Options {
218
218
  catchUpOutofSync: boolean;
219
219
  reason?: CatchupEventReason;
220
220
  onCatchupComplete?: (steps: StepJson[]) => void;
221
+ getState: (() => EditorState) | undefined;
221
222
  }
222
223
  export type ReconnectionMetadata = {
223
224
  unconfirmedStepsLength: number | undefined;
@@ -19,7 +19,8 @@ export declare enum EVENT_ACTION {
19
19
  PROVIDER_INITIALIZED = "providerInitialized",// https://data-portal.internal.atlassian.com/analytics/registry/54714
20
20
  RECONNECTION = "providerReconnection",// https://data-portal.internal.atlassian.com/analytics/registry/73992
21
21
  PROVIDER_SETUP = "providerSetup",// https://data-portal.internal.atlassian.com/analytics/registry/54715
22
- HAS_UNCONFIRMED_STEPS = "hasUnconfirmedSteps"
22
+ HAS_UNCONFIRMED_STEPS = "hasUnconfirmedSteps",// https://data-portal.internal.atlassian.com/analytics/registry/56141
23
+ OUT_OF_SYNC = "outOfSync"
23
24
  }
24
25
  export declare enum EVENT_STATUS {
25
26
  SUCCESS = "SUCCESS",
@@ -261,7 +262,20 @@ type ReconnectionAnalyticsEvent = {
261
262
  disconnectionPeriodSeconds: number;
262
263
  } & BaseActionAnalyticsEventAttributes;
263
264
  };
264
- export type ActionAnalyticsEvent = AddStepsSuccessAnalyticsEvent | AddStepsFailureAnalyticsEvent | ReInitDocFailAnalyticsEvent | ReInitDocSuccessAnalyticsEvent | ConnectionSuccessAnalyticsEvent | ConnectionFailureAnalyticsEvent | CatchUpSuccessAnalyticsEvent | CatchUpFailureAnalyticsEvent | DocumentInitSuccessAnalyticsEvent | UpdateParticipantsSuccessAnalyticsEvent | CommitUnconfirmedStepsSuccessAnalyticsEvent | CommitUnconfirmedStepsFailureAnalyticsEvent | PublishPageSuccessAnalyticsEvent | PublishPageFailureAnalyticsEvent | GetCurrentStateSuccessAnalyticsEvent | GetCurrentStateFailureAnalyticsEvent | InvalidateTokenAnalyticsEvent | SendStepsRetryAnalyticsEvent | CatchupAfterMaxSendStepsRetryAnalyticsEvent | CatchUpDroppedStepsEvent | WebsocketMessageVolumeMetricEvent | ProviderInitializedAnalyticsEvent | ProviderSetupAnalyticsEvent | ProviderHasUnconfirmedStepsAnalyticsEvent | UpdateDocumentAnalyticsEvent | ReconnectionAnalyticsEvent;
265
+ type OutOfSyncAnalyticsEvent = {
266
+ eventAction: EVENT_ACTION.OUT_OF_SYNC;
267
+ attributes: {
268
+ eventStatus: EVENT_STATUS.FAILURE;
269
+ obfuscatedSteps: {
270
+ [key: string]: number;
271
+ }[];
272
+ obfuscatedDoc: {
273
+ [key: string]: number;
274
+ };
275
+ catchupReason: CatchupEventReason | undefined;
276
+ } & BaseActionAnalyticsEventAttributes;
277
+ };
278
+ export type ActionAnalyticsEvent = AddStepsSuccessAnalyticsEvent | AddStepsFailureAnalyticsEvent | ReInitDocFailAnalyticsEvent | ReInitDocSuccessAnalyticsEvent | ConnectionSuccessAnalyticsEvent | ConnectionFailureAnalyticsEvent | CatchUpSuccessAnalyticsEvent | CatchUpFailureAnalyticsEvent | DocumentInitSuccessAnalyticsEvent | UpdateParticipantsSuccessAnalyticsEvent | CommitUnconfirmedStepsSuccessAnalyticsEvent | CommitUnconfirmedStepsFailureAnalyticsEvent | PublishPageSuccessAnalyticsEvent | PublishPageFailureAnalyticsEvent | GetCurrentStateSuccessAnalyticsEvent | GetCurrentStateFailureAnalyticsEvent | InvalidateTokenAnalyticsEvent | SendStepsRetryAnalyticsEvent | CatchupAfterMaxSendStepsRetryAnalyticsEvent | CatchUpDroppedStepsEvent | WebsocketMessageVolumeMetricEvent | ProviderInitializedAnalyticsEvent | ProviderSetupAnalyticsEvent | ProviderHasUnconfirmedStepsAnalyticsEvent | UpdateDocumentAnalyticsEvent | ReconnectionAnalyticsEvent | OutOfSyncAnalyticsEvent;
265
279
  export declare const ACK_MAX_TRY = 60;
266
280
  export declare const CONFLUENCE = "confluence";
267
281
  /** Enumerable for attaching a reason to catchup (v2) call(s) */
@@ -1,5 +1,8 @@
1
+ import { type ADFEntity } from '@atlaskit/adf-utils/types';
1
2
  import type { ProductInformation } from '../types';
2
3
  import type { Step as ProseMirrorStep } from '@atlaskit/editor-prosemirror/transform';
4
+ import type { StepJson } from '@atlaskit/editor-common/collab';
5
+ import type { Node as ProseMirrorNode } from '@atlaskit/editor-prosemirror/model';
3
6
  export declare const createLogger: (prefix: string, color?: string) => (msg: string, data?: any) => void;
4
7
  export declare function sleep(ms: number): Promise<unknown>;
5
8
  export declare const isAIProviderID: (id: string) => boolean;
@@ -11,3 +14,41 @@ export type UGCFreeStepDetails = {
11
14
  stepSizeInBytes?: number;
12
15
  };
13
16
  export declare const getStepUGCFreeDetails: (step: ProseMirrorStep) => UGCFreeStepDetails;
17
+ export declare const getStepTypes: (stepJson: StepJson) => {
18
+ type: string;
19
+ contentTypes: string | null;
20
+ };
21
+ export declare const getStepsAdfWithObfuscation: (stepJson: StepJson) => ADFEntity[] | null;
22
+ export declare const getDocAdfWithObfuscation: (doc: ProseMirrorNode) => ADFEntity | null;
23
+ export declare const getStepPositions: (stepJson: StepJson) => {
24
+ pos?: number | undefined;
25
+ insert?: number | undefined;
26
+ gapFrom?: number | undefined;
27
+ gapTo?: number | undefined;
28
+ from?: number | undefined;
29
+ to?: number | undefined;
30
+ };
31
+ export declare const getObfuscatedSteps: (steps: StepJson[], endIndex?: number | undefined) => {
32
+ stepType: {
33
+ type: string;
34
+ contentTypes: string | null;
35
+ };
36
+ stepContent: ADFEntity[] | null;
37
+ stepPositions: {
38
+ pos?: number | undefined;
39
+ insert?: number | undefined;
40
+ gapFrom?: number | undefined;
41
+ gapTo?: number | undefined;
42
+ from?: number | undefined;
43
+ to?: number | undefined;
44
+ };
45
+ stepMetadata: {
46
+ source?: string | undefined;
47
+ stepId?: string | undefined;
48
+ prevStepId?: string | undefined;
49
+ rebased?: boolean | undefined;
50
+ traceId?: string | undefined;
51
+ reqId?: string | undefined;
52
+ schemaVersion?: string | undefined;
53
+ } | undefined;
54
+ }[];
@@ -1,4 +1,3 @@
1
- import type { Step } from '@atlaskit/editor-prosemirror/transform';
2
1
  import type { AnalyticsWebClient } from '@atlaskit/analytics-listeners';
3
2
  import type { Manager, Socket as SocketIOSocket } from 'socket.io-client';
4
3
  import type { InternalError } from './errors/internal-errors';
@@ -7,6 +6,7 @@ import type { GetUserType } from './participants/participants-helper';
7
6
  import type AnalyticsHelper from './analytics/analytics-helper';
8
7
  import type { StepJson, CollabSendableSelection, Metadata, UserPermitType, Activity, PresenceActivity } from '@atlaskit/editor-common/collab';
9
8
  import { type CatchupEventReason } from './helpers/const';
9
+ import type { EditorState } from '@atlaskit/editor-prosemirror/state';
10
10
  export interface CollabEventDisconnectedData {
11
11
  sid: string;
12
12
  reason: 'CLIENT_DISCONNECT' | 'SERVER_DISCONNECT' | 'SOCKET_CLOSED' | 'SOCKET_ERROR' | 'SOCKET_TIMEOUT' | 'UNKNOWN_DISCONNECT';
@@ -199,7 +199,7 @@ export type ChannelEvent = {
199
199
  status: NamespaceStatus;
200
200
  };
201
201
  export interface Catchupv2Response {
202
- steps?: Step[];
202
+ steps?: StepJson[];
203
203
  metadata?: Metadata;
204
204
  }
205
205
  export interface ReconcileResponse {
@@ -218,6 +218,7 @@ export interface Catchupv2Options {
218
218
  catchUpOutofSync: boolean;
219
219
  reason?: CatchupEventReason;
220
220
  onCatchupComplete?: (steps: StepJson[]) => void;
221
+ getState: (() => EditorState) | undefined;
221
222
  }
222
223
  export type ReconnectionMetadata = {
223
224
  unconfirmedStepsLength: number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "10.3.3",
3
+ "version": "10.4.0",
4
4
  "description": "A provider for collaborative editing.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -32,9 +32,10 @@
32
32
  "./version-wrapper": "./src/version-wrapper.ts"
33
33
  },
34
34
  "dependencies": {
35
+ "@atlaskit/adf-utils": "^19.17.0",
35
36
  "@atlaskit/analytics-gas-types": "^5.1.0",
36
37
  "@atlaskit/analytics-listeners": "^8.13.0",
37
- "@atlaskit/editor-common": "^98.0.0",
38
+ "@atlaskit/editor-common": "^99.2.0",
38
39
  "@atlaskit/editor-json-transformer": "^8.21.0",
39
40
  "@atlaskit/editor-prosemirror": "6.2.1",
40
41
  "@atlaskit/feature-gate-js-client": "^4.22.0",
@@ -71,6 +72,9 @@
71
72
  "platform.editor.live-pages-expand-divergence": {
72
73
  "type": "boolean"
73
74
  },
75
+ "platform_editor_log_obfuscated_steps": {
76
+ "type": "boolean"
77
+ },
74
78
  "platform_editor_merge_unconfirmed_steps": {
75
79
  "type": "boolean"
76
80
  },