@atlaskit/collab-provider 8.0.1 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/cjs/analytics/index.js +2 -11
  3. package/dist/cjs/analytics/performance.js +2 -16
  4. package/dist/cjs/channel.js +66 -115
  5. package/dist/cjs/disconnected-reason-mapper.js +0 -2
  6. package/dist/cjs/emitter.js +3 -11
  7. package/dist/cjs/error-code-mapper.js +4 -17
  8. package/dist/cjs/feature-flags/__test__/index.unit.js +27 -0
  9. package/dist/cjs/feature-flags/index.js +52 -0
  10. package/dist/cjs/feature-flags/types.js +12 -0
  11. package/dist/cjs/helpers/const.js +6 -10
  12. package/dist/cjs/helpers/utils.js +0 -12
  13. package/dist/cjs/index.js +0 -1
  14. package/dist/cjs/provider/catchup.js +38 -42
  15. package/dist/cjs/provider/index.js +153 -283
  16. package/dist/cjs/socket-io-provider.js +2 -12
  17. package/dist/cjs/types.js +0 -1
  18. package/dist/cjs/version-wrapper.js +1 -3
  19. package/dist/cjs/version.json +1 -1
  20. package/dist/es2019/analytics/index.js +2 -3
  21. package/dist/es2019/analytics/performance.js +2 -13
  22. package/dist/es2019/channel.js +57 -65
  23. package/dist/es2019/disconnected-reason-mapper.js +1 -2
  24. package/dist/es2019/emitter.js +3 -8
  25. package/dist/es2019/error-code-mapper.js +4 -12
  26. package/dist/es2019/feature-flags/__test__/index.unit.js +25 -0
  27. package/dist/es2019/feature-flags/index.js +31 -0
  28. package/dist/es2019/feature-flags/types.js +5 -0
  29. package/dist/es2019/helpers/const.js +4 -9
  30. package/dist/es2019/helpers/utils.js +0 -2
  31. package/dist/es2019/provider/catchup.js +33 -17
  32. package/dist/es2019/provider/index.js +119 -189
  33. package/dist/es2019/socket-io-provider.js +4 -2
  34. package/dist/es2019/types.js +1 -1
  35. package/dist/es2019/version-wrapper.js +1 -1
  36. package/dist/es2019/version.json +1 -1
  37. package/dist/esm/analytics/index.js +2 -6
  38. package/dist/esm/analytics/performance.js +2 -13
  39. package/dist/esm/channel.js +68 -108
  40. package/dist/esm/disconnected-reason-mapper.js +1 -2
  41. package/dist/esm/emitter.js +3 -6
  42. package/dist/esm/error-code-mapper.js +4 -12
  43. package/dist/esm/feature-flags/__test__/index.unit.js +25 -0
  44. package/dist/esm/feature-flags/index.js +43 -0
  45. package/dist/esm/feature-flags/types.js +5 -0
  46. package/dist/esm/helpers/const.js +4 -9
  47. package/dist/esm/helpers/utils.js +0 -3
  48. package/dist/esm/provider/catchup.js +38 -35
  49. package/dist/esm/provider/index.js +153 -285
  50. package/dist/esm/socket-io-provider.js +2 -5
  51. package/dist/esm/types.js +1 -1
  52. package/dist/esm/version-wrapper.js +1 -1
  53. package/dist/esm/version.json +1 -1
  54. package/dist/types/channel.d.ts +1 -0
  55. package/dist/types/error-code-mapper.d.ts +1 -1
  56. package/dist/types/feature-flags/__test__/index.unit.d.ts +1 -0
  57. package/dist/types/feature-flags/index.d.ts +9 -0
  58. package/dist/types/feature-flags/types.d.ts +11 -0
  59. package/dist/types/helpers/const.d.ts +19 -3
  60. package/dist/types/provider/catchup.d.ts +1 -1
  61. package/dist/types/provider/index.d.ts +1 -0
  62. package/dist/types/types.d.ts +9 -4
  63. package/package.json +10 -9
  64. package/report.api.md +11 -1
@@ -26,29 +26,27 @@ export var ErrorCodeMapper = {
26
26
  },
27
27
  internalError: {
28
28
  code: 'INTERNAL_SERVICE_ERROR',
29
- message: 'Collab service has return internal server error'
29
+ message: 'Collab service has experienced an internal server error'
30
30
  }
31
31
  };
32
32
  export var errorCodeMapper = function errorCodeMapper(error) {
33
33
  var _error$data;
34
-
35
34
  switch ((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) {
36
35
  case 'INSUFFICIENT_EDITING_PERMISSION':
37
36
  return {
38
37
  status: 403,
39
38
  code: ErrorCodeMapper.noPermissionError.code,
40
39
  message: ErrorCodeMapper.noPermissionError.message,
41
- reason: // Typescript magic so it detects the union type
40
+ reason:
41
+ // Typescript magic so it detects the union type
42
42
  _typeof(error.data.meta) === 'object' ? error.data.meta.reason : undefined
43
43
  };
44
-
45
44
  case 'DOCUMENT_NOT_FOUND':
46
45
  return {
47
46
  status: 404,
48
47
  code: ErrorCodeMapper.documentNotFound.code,
49
48
  message: ErrorCodeMapper.documentNotFound.message
50
49
  };
51
-
52
50
  case 'FAILED_ON_S3':
53
51
  case 'DYNAMO_ERROR':
54
52
  return {
@@ -56,17 +54,11 @@ export var errorCodeMapper = function errorCodeMapper(error) {
56
54
  code: ErrorCodeMapper.failToSave.code,
57
55
  message: ErrorCodeMapper.failToSave.message
58
56
  };
59
-
60
- case 'CATCHUP_FAILED':
61
- case 'GET_QUERY_TIME_OUT':
62
- case 'INIT_DATA_LOAD_FAILED':
57
+ default:
63
58
  return {
64
59
  status: 500,
65
60
  code: ErrorCodeMapper.internalError.code,
66
61
  message: ErrorCodeMapper.internalError.message
67
62
  };
68
-
69
- default:
70
- break;
71
63
  }
72
64
  };
@@ -0,0 +1,25 @@
1
+ import { getProductSpecificFeatureFlags, getCollabProviderFeatureFlag } from '../index';
2
+ describe('Feature flags', function () {
3
+ it('getProductSpecificFeatureFlags', function () {
4
+ var result = getProductSpecificFeatureFlags({
5
+ testFF: true
6
+ }, 'confluence');
7
+ expect(result).toEqual(['confluence.fe.collab.provider.testFF']);
8
+ });
9
+ it('getCollabProviderFeatureFlag return true', function () {
10
+ var result = getCollabProviderFeatureFlag('testFF', {
11
+ testFF: true
12
+ });
13
+ expect(result).toEqual(true);
14
+ });
15
+ it('getCollabProviderFeatureFlag with wrong ff set', function () {
16
+ var result = getCollabProviderFeatureFlag('testFF', {
17
+ abc: true
18
+ });
19
+ expect(result).toEqual(false);
20
+ });
21
+ it('getCollabProviderFeatureFlag with wrong ff set', function () {
22
+ var result = getCollabProviderFeatureFlag('testFF', undefined);
23
+ expect(result).toEqual(false);
24
+ });
25
+ });
@@ -0,0 +1,43 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ var defaultNCSFeatureFlags = {
3
+ testFF: false
4
+ };
5
+
6
+ /**
7
+ * Note that Confluence should have the same FF sets as NCS
8
+ */
9
+ var productKeys = {
10
+ confluence: {
11
+ testFF: 'confluence.fe.collab.provider.testFF'
12
+ }
13
+ };
14
+ var filterFeatureFlagNames = function filterFeatureFlagNames(flags) {
15
+ var pairs = Object.entries(flags);
16
+ return pairs.filter(function (_ref) {
17
+ var _ref2 = _slicedToArray(_ref, 2),
18
+ _key = _ref2[0],
19
+ value = _ref2[1];
20
+ return !!value;
21
+ }).map(function (_ref3) {
22
+ var _ref4 = _slicedToArray(_ref3, 1),
23
+ key = _ref4[0];
24
+ return key;
25
+ });
26
+ };
27
+
28
+ /**
29
+ * Takes a record of {NCS Feature Flag Names → boolean} and a supported product name.
30
+ * Returns the corresponding product’s Launch Darkly Keys for each of the flags set as true in the input record.
31
+ * */
32
+ export var getProductSpecificFeatureFlags = function getProductSpecificFeatureFlags(flags, product) {
33
+ var ncsFeatureFlags = filterFeatureFlagNames(flags);
34
+ return ncsFeatureFlags.map(function (key) {
35
+ return productKeys[product][key];
36
+ });
37
+ };
38
+ export function getCollabProviderFeatureFlag(flagName, featureFlags) {
39
+ if (featureFlags) {
40
+ return flagName in featureFlags ? featureFlags[flagName] : defaultNCSFeatureFlags[flagName];
41
+ }
42
+ return defaultNCSFeatureFlags[flagName];
43
+ }
@@ -0,0 +1,5 @@
1
+ // NCS feature flags - type and defaults defined here in one source of truth
2
+
3
+ // With this type we ensure the object will contain all the flags
4
+
5
+ export var supportedProducts = ['confluence'];
@@ -1,13 +1,10 @@
1
1
  export var EVENT_SUBJECT = 'collab';
2
2
  export var COLLAB_SERVICE;
3
-
4
3
  (function (COLLAB_SERVICE) {
5
4
  COLLAB_SERVICE["NCS"] = "ncs";
6
5
  COLLAB_SERVICE["SYNCHRONY"] = "synchrony";
7
6
  })(COLLAB_SERVICE || (COLLAB_SERVICE = {}));
8
-
9
7
  export var EVENT_ACTION;
10
-
11
8
  (function (EVENT_ACTION) {
12
9
  EVENT_ACTION["CONNECTION"] = "connection";
13
10
  EVENT_ACTION["CATCHUP"] = "catchup";
@@ -17,21 +14,19 @@ export var EVENT_ACTION;
17
14
  EVENT_ACTION["UPDATE_PARTICIPANTS"] = "updateParticipants";
18
15
  EVENT_ACTION["COMMIT_UNCONFIRMED_STEPS"] = "commitUnconfirmedSteps";
19
16
  EVENT_ACTION["REINITIALISE_DOCUMENT"] = "reinitialiseDocument";
17
+ EVENT_ACTION["INIT_PROVIDER"] = "initProvider";
18
+ EVENT_ACTION["ERROR"] = "error";
20
19
  })(EVENT_ACTION || (EVENT_ACTION = {}));
21
-
22
20
  export var EVENT_STATUS;
23
-
24
21
  (function (EVENT_STATUS) {
25
22
  EVENT_STATUS["SUCCESS"] = "SUCCESS";
26
23
  EVENT_STATUS["FAILURE"] = "FAILURE";
27
24
  })(EVENT_STATUS || (EVENT_STATUS = {}));
28
-
29
25
  export var ADD_STEPS_TYPE;
30
-
31
26
  (function (ADD_STEPS_TYPE) {
32
27
  ADD_STEPS_TYPE["ACCEPTED"] = "ACCEPTED";
33
28
  ADD_STEPS_TYPE["REJECTED"] = "REJECTED";
34
29
  ADD_STEPS_TYPE["ERROR"] = "ERROR";
35
30
  })(ADD_STEPS_TYPE || (ADD_STEPS_TYPE = {}));
36
-
37
- export var ACK_MAX_TRY = 30;
31
+ export var ACK_MAX_TRY = 30;
32
+ export var CONFLUENCE = 'confluence';
@@ -2,7 +2,6 @@ export var createLogger = function createLogger(prefix) {
2
2
  var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'blue';
3
3
  return function (msg) {
4
4
  var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
5
-
6
5
  if (window.COLLAB_PROVIDER_LOGGER) {
7
6
  // eslint-disable-next-line no-console
8
7
  console.log("%cCollab-".concat(prefix, ": ").concat(msg), "color: ".concat(color, "; font-weight: bold"), data);
@@ -26,11 +25,9 @@ export function sleep(ms) {
26
25
  }
27
26
  export var getProduct = function getProduct(productInfo) {
28
27
  var _productInfo$product;
29
-
30
28
  return (_productInfo$product = productInfo === null || productInfo === void 0 ? void 0 : productInfo.product) !== null && _productInfo$product !== void 0 ? _productInfo$product : 'unknown';
31
29
  };
32
30
  export var getSubProduct = function getSubProduct(productInfo) {
33
31
  var _productInfo$subProdu;
34
-
35
32
  return (_productInfo$subProdu = productInfo === null || productInfo === void 0 ? void 0 : productInfo.subProduct) !== null && _productInfo$subProdu !== void 0 ? _productInfo$subProdu : !!(productInfo !== null && productInfo !== void 0 && productInfo.product) ? 'none' : 'unknown';
36
33
  };
@@ -1,32 +1,26 @@
1
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
-
4
3
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
5
-
6
4
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
7
-
8
5
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
9
-
10
6
  import { createLogger } from '../helpers/utils';
11
7
  import { StepMap, Mapping } from 'prosemirror-transform';
12
8
  var logger = createLogger('Catchup', 'red');
9
+
13
10
  /**
14
11
  * Rebase the steps based on the mapping pipeline.
15
12
  * Some steps could be lost, if they are no longer
16
13
  * invalid after rebased.
17
14
  */
18
-
19
15
  export function rebaseSteps(steps, mapping) {
20
16
  var newSteps = [];
21
-
22
17
  var _iterator = _createForOfIteratorHelper(steps),
23
- _step;
24
-
18
+ _step;
25
19
  try {
26
20
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
27
21
  var step = _step.value;
28
- var newStep = step.map(mapping); // newStep could be null(means invalid after rebase) when can't rebase.
29
-
22
+ var newStep = step.map(mapping);
23
+ // newStep could be null(means invalid after rebase) when can't rebase.
30
24
  if (newStep) {
31
25
  newSteps.push(newStep);
32
26
  }
@@ -36,87 +30,97 @@ export function rebaseSteps(steps, mapping) {
36
30
  } finally {
37
31
  _iterator.f();
38
32
  }
39
-
40
33
  return newSteps;
41
34
  }
42
35
  export var catchup = /*#__PURE__*/function () {
43
36
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(opt) {
44
- var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, _ref2, unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps;
45
-
37
+ var _yield$opt$fetchCatch, doc, serverStepMaps, serverVersion, metadata, currentPmVersion, _ref2, unconfirmedSteps, _ref3, _unconfirmedSteps, stepMaps, mapping, newUnconfirmedSteps;
46
38
  return _regeneratorRuntime.wrap(function _callee$(_context) {
47
39
  while (1) {
48
40
  switch (_context.prev = _context.next) {
49
41
  case 0:
50
42
  _context.next = 2;
51
43
  return opt.fetchCatchup(opt.getCurrentPmVersion());
52
-
53
44
  case 2:
54
45
  _yield$opt$fetchCatch = _context.sent;
55
46
  doc = _yield$opt$fetchCatch.doc;
56
47
  serverStepMaps = _yield$opt$fetchCatch.stepMaps;
57
48
  serverVersion = _yield$opt$fetchCatch.version;
58
49
  metadata = _yield$opt$fetchCatch.metadata;
59
-
60
50
  if (doc) {
61
51
  currentPmVersion = opt.getCurrentPmVersion();
62
-
63
52
  if (typeof serverVersion === 'undefined') {
64
53
  logger("Could not determine server version");
65
54
  } else if (serverVersion <= currentPmVersion) {
66
- logger("Catchup steps we already have. Ignoring.");
55
+ // there are no step maps in this case after page recovery
56
+ _ref2 = opt.getUnconfirmedSteps() || {
57
+ steps: []
58
+ }, unconfirmedSteps = _ref2.steps; // replace the entire document
59
+ logger("Replacing document: ".concat(doc));
60
+ logger("getting metadata: ".concat(metadata));
61
+ // Replace local document and version number
62
+ opt.updateDocumentWithMetadata({
63
+ doc: JSON.parse(doc),
64
+ version: serverVersion,
65
+ metadata: metadata,
66
+ reserveCursor: true
67
+ });
68
+ if (unconfirmedSteps.length) {
69
+ opt.applyLocalSteps(unconfirmedSteps);
70
+ }
67
71
  } else {
68
72
  // Please, do not use those steps inside of async
69
73
  // method. That will lead to outdated steps
70
- _ref2 = opt.getUnconfirmedSteps() || {
74
+ _ref3 = opt.getUnconfirmedSteps() || {
71
75
  steps: []
72
- }, unconfirmedSteps = _ref2.steps;
76
+ }, _unconfirmedSteps = _ref3.steps;
73
77
  logger("Too far behind[current: v".concat(currentPmVersion, ", server: v").concat(serverVersion, ". ").concat(serverStepMaps.length, " steps need to catchup]"));
74
78
  /**
75
79
  * Remove steps from queue where the version is older than
76
80
  * the version we received from service. Keep steps that might be
77
81
  * newer.
78
82
  */
79
-
80
83
  opt.filterQueue(function (data) {
81
84
  return data.version > serverVersion;
82
- }); // We are too far behind - replace the entire document
85
+ });
83
86
 
87
+ // We are too far behind - replace the entire document
84
88
  logger("Replacing document: ".concat(doc));
85
- logger("getting metadata: ".concat(metadata)); // Replace local document and version number
89
+ logger("getting metadata: ".concat(metadata));
86
90
 
91
+ // Replace local document and version number
87
92
  opt.updateDocumentWithMetadata({
88
93
  doc: JSON.parse(doc),
89
94
  version: serverVersion,
90
95
  metadata: metadata,
91
96
  reserveCursor: true
92
- }); // After replacing the whole document in the editor, we need to reapply the unconfirmed
97
+ });
98
+
99
+ // After replacing the whole document in the editor, we need to reapply the unconfirmed
93
100
  // steps back into the editor, so we don't lose any data. But before that, we need to rebase
94
101
  // those steps since their position could be changed after replacing.
95
102
  // https://prosemirror.net/docs/guide/#transform.rebasing
96
-
97
- if (unconfirmedSteps.length) {
103
+ if (_unconfirmedSteps.length) {
98
104
  // Create StepMap from StepMap JSON
99
105
  // eslint-disable-next-line no-unused-vars
100
- stepMaps = serverStepMaps.map(function (_ref3) {
101
- var ranges = _ref3.ranges,
102
- inverted = _ref3.inverted;
106
+ stepMaps = serverStepMaps.map(function (_ref4) {
107
+ var ranges = _ref4.ranges,
108
+ inverted = _ref4.inverted;
103
109
  // Due to @types/prosemirror-transform mismatch with the actual
104
110
  // constructor, hack to set the `inverted`.
105
111
  var stepMap = new StepMap(ranges);
106
112
  stepMap.inverted = inverted;
107
113
  return stepMap;
108
114
  }); // create Mappng used for Step.map
109
-
110
115
  mapping = new Mapping(stepMaps);
111
- logger("".concat(unconfirmedSteps.length, " unconfirmed steps before rebased: ").concat(JSON.stringify(unconfirmedSteps)));
112
- newUnconfirmedSteps = rebaseSteps(unconfirmedSteps, mapping);
113
- logger("Re-aply ".concat(newUnconfirmedSteps.length, " mapped unconfirmed steps: ").concat(JSON.stringify(newUnconfirmedSteps))); // Re-aply local steps
114
-
116
+ logger("".concat(_unconfirmedSteps.length, " unconfirmed steps before rebased: ").concat(JSON.stringify(_unconfirmedSteps)));
117
+ newUnconfirmedSteps = rebaseSteps(_unconfirmedSteps, mapping);
118
+ logger("Re-aply ".concat(newUnconfirmedSteps.length, " mapped unconfirmed steps: ").concat(JSON.stringify(newUnconfirmedSteps)));
119
+ // Re-aply local steps
115
120
  opt.applyLocalSteps(newUnconfirmedSteps);
116
121
  }
117
122
  }
118
123
  }
119
-
120
124
  case 8:
121
125
  case "end":
122
126
  return _context.stop();
@@ -124,7 +128,6 @@ export var catchup = /*#__PURE__*/function () {
124
128
  }
125
129
  }, _callee);
126
130
  }));
127
-
128
131
  return function catchup(_x) {
129
132
  return _ref.apply(this, arguments);
130
133
  };