@atlaskit/collab-provider 8.4.0 → 8.6.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 (88) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/dist/cjs/analytics/analytics-helper.js +135 -0
  3. package/dist/cjs/analytics/performance.js +6 -5
  4. package/dist/cjs/channel.js +242 -223
  5. package/dist/cjs/document/catchup.js +142 -0
  6. package/dist/cjs/document/document-service.js +587 -0
  7. package/dist/cjs/document/step-queue-state.js +56 -0
  8. package/dist/cjs/errors/error-code-mapper.js +86 -67
  9. package/dist/cjs/errors/error-types.js +329 -21
  10. package/dist/cjs/helpers/utils.js +1 -12
  11. package/dist/cjs/index.js +8 -1
  12. package/dist/cjs/metadata/metadata-service.js +82 -0
  13. package/dist/cjs/participants/participants-helper.js +52 -0
  14. package/dist/cjs/participants/participants-service.js +259 -0
  15. package/dist/cjs/participants/participants-state.js +56 -0
  16. package/dist/cjs/{provider/telepointers.js → participants/telepointers-helper.js} +6 -6
  17. package/dist/cjs/provider/commit-step.js +14 -6
  18. package/dist/cjs/provider/index.js +291 -780
  19. package/dist/cjs/types.js +6 -1
  20. package/dist/cjs/version-wrapper.js +1 -1
  21. package/dist/cjs/version.json +1 -1
  22. package/dist/es2019/analytics/{index.js → analytics-helper.js} +15 -4
  23. package/dist/es2019/analytics/performance.js +5 -6
  24. package/dist/es2019/channel.js +140 -113
  25. package/dist/es2019/{provider → document}/catchup.js +6 -4
  26. package/dist/es2019/document/document-service.js +472 -0
  27. package/dist/es2019/document/step-queue-state.js +35 -0
  28. package/dist/es2019/errors/error-code-mapper.js +87 -63
  29. package/dist/es2019/errors/error-types.js +221 -5
  30. package/dist/es2019/helpers/utils.js +0 -10
  31. package/dist/es2019/index.js +2 -1
  32. package/dist/es2019/metadata/metadata-service.js +61 -0
  33. package/dist/es2019/participants/participants-helper.js +25 -0
  34. package/dist/es2019/participants/participants-service.js +207 -0
  35. package/dist/es2019/participants/participants-state.js +30 -0
  36. package/dist/es2019/{provider/telepointers.js → participants/telepointers-helper.js} +2 -2
  37. package/dist/es2019/provider/commit-step.js +12 -5
  38. package/dist/es2019/provider/index.js +240 -640
  39. package/dist/es2019/types.js +8 -1
  40. package/dist/es2019/version-wrapper.js +1 -1
  41. package/dist/es2019/version.json +1 -1
  42. package/dist/esm/analytics/analytics-helper.js +128 -0
  43. package/dist/esm/analytics/performance.js +5 -6
  44. package/dist/esm/channel.js +243 -224
  45. package/dist/esm/document/catchup.js +133 -0
  46. package/dist/esm/document/document-service.js +579 -0
  47. package/dist/esm/document/step-queue-state.js +48 -0
  48. package/dist/esm/errors/error-code-mapper.js +87 -64
  49. package/dist/esm/errors/error-types.js +321 -18
  50. package/dist/esm/helpers/utils.js +0 -10
  51. package/dist/esm/index.js +2 -1
  52. package/dist/esm/metadata/metadata-service.js +74 -0
  53. package/dist/esm/participants/participants-helper.js +44 -0
  54. package/dist/esm/participants/participants-service.js +251 -0
  55. package/dist/esm/participants/participants-state.js +48 -0
  56. package/dist/esm/{provider/telepointers.js → participants/telepointers-helper.js} +4 -4
  57. package/dist/esm/provider/commit-step.js +12 -5
  58. package/dist/esm/provider/index.js +291 -779
  59. package/dist/esm/types.js +8 -1
  60. package/dist/esm/version-wrapper.js +1 -1
  61. package/dist/esm/version.json +1 -1
  62. package/dist/types/analytics/{index.d.ts → analytics-helper.d.ts} +3 -1
  63. package/dist/types/analytics/performance.d.ts +3 -1
  64. package/dist/types/analytics/ufo.d.ts +1 -1
  65. package/dist/types/channel.d.ts +13 -6
  66. package/dist/types/document/document-service.d.ts +86 -0
  67. package/dist/types/document/step-queue-state.d.ts +16 -0
  68. package/dist/types/errors/error-code-mapper.d.ts +2 -36
  69. package/dist/types/errors/error-types.d.ts +439 -4
  70. package/dist/types/helpers/const.d.ts +2 -2
  71. package/dist/types/helpers/utils.d.ts +0 -6
  72. package/dist/types/index.d.ts +3 -1
  73. package/dist/types/metadata/metadata-service.d.ts +25 -0
  74. package/dist/types/participants/participants-helper.d.ts +15 -0
  75. package/dist/types/participants/participants-service.d.ts +74 -0
  76. package/dist/types/participants/participants-state.d.ts +13 -0
  77. package/dist/types/participants/telepointers-helper.d.ts +4 -0
  78. package/dist/types/provider/commit-step.d.ts +17 -6
  79. package/dist/types/provider/index.d.ts +81 -78
  80. package/dist/types/types.d.ts +56 -31
  81. package/package.json +6 -6
  82. package/report.api.md +187 -21
  83. package/dist/cjs/analytics/index.js +0 -95
  84. package/dist/cjs/provider/catchup.js +0 -139
  85. package/dist/esm/analytics/index.js +0 -88
  86. package/dist/esm/provider/catchup.js +0 -130
  87. package/dist/types/provider/telepointers.d.ts +0 -5
  88. /package/dist/types/{provider → document}/catchup.d.ts +0 -0
@@ -1,4 +1,4 @@
1
- import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
1
+ import _typeof from "@babel/runtime/helpers/typeof";
2
2
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
3
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4
4
  import _createClass from "@babel/runtime/helpers/createClass";
@@ -8,56 +8,51 @@ import _inherits from "@babel/runtime/helpers/inherits";
8
8
  import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
9
9
  import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
10
10
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
11
- import _regeneratorRuntime from "@babel/runtime/regenerator";
12
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
13
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
11
+ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function define(obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == _typeof(value) && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function value(method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) { if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; } return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) { keys.push(key); } return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function reset(skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) { "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); } }, stop: function stop() { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function dispatchException(exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function abrupt(type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function complete(record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function finish(finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, catch: function _catch(tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; }
14
12
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
15
13
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
16
- import { getVersion, sendableSteps } from '@atlaskit/prosemirror-collab';
17
- import throttle from 'lodash/throttle';
18
- import isEqual from 'lodash/isEqual';
19
- import { JSONTransformer } from '@atlaskit/editor-json-transformer';
20
14
  import { Emitter } from '../emitter';
21
15
  import { Channel } from '../channel';
22
- import { createLogger, getParticipant, sleep } from '../helpers/utils';
23
- import { ACK_MAX_TRY, EVENT_ACTION, EVENT_STATUS } from '../helpers/const';
24
- import AnalyticsHelper from '../analytics';
25
- import { catchup } from './catchup';
26
- import { ErrorCodeMapper, errorCodeMapper } from '../errors/error-code-mapper';
27
- import { disconnectedReasonMapper } from '../disconnected-reason-mapper';
28
- import { MEASURE_NAME, startMeasure, stopMeasure } from '../analytics/performance';
29
- import { commitStep } from './commit-step';
30
- import { telepointerCallback, telepointersFromStep } from './telepointers';
16
+ import { createLogger } from '../helpers/utils';
17
+ import AnalyticsHelper from '../analytics/analytics-helper';
18
+ import { telepointerCallback } from '../participants/telepointers-helper';
19
+ import { ParticipantsService } from '../participants/participants-service';
20
+ import { DestroyError, GetCurrentStateError, GetFinalAcknowledgedStateError, ProviderInitialisationError, SendTransactionError, SetEditorWidthError, SetMetadataError, SetTitleError, NCS_ERROR_CODE } from '../errors/error-types';
21
+ import { MetadataService } from '../metadata/metadata-service';
22
+ import { DocumentService } from '../document/document-service';
23
+ import { errorCodeMapper } from '../errors/error-code-mapper';
31
24
  var logger = createLogger('Provider', 'black');
32
- var PARTICIPANT_UPDATE_INTERVAL = 300 * 1000; // 300 seconds
33
25
  var SEND_PRESENCE_INTERVAL = 150 * 1000; // 150 seconds
34
- var SEND_STEPS_THROTTLE = 500; // 0.5 second
35
- var CATCHUP_THROTTLE = 1 * 1000; // 1 second
26
+
36
27
  var OUT_OF_SYNC_PERIOD = 3 * 1000; // 3 seconds
37
- var noop = function noop() {};
28
+
38
29
  export var MAX_STEP_REJECTED_ERROR = 15;
39
- export var throttledCommitStep = throttle(commitStep, SEND_STEPS_THROTTLE, {
40
- leading: false,
41
- trailing: true
42
- });
43
30
  export var Provider = /*#__PURE__*/function (_Emitter) {
44
31
  _inherits(Provider, _Emitter);
45
32
  var _super = _createSuper(Provider);
46
33
  // To keep track of the namespace event changes from the server.
47
34
 
35
+ // SessionID is the unique socket-session.
36
+
37
+ // ClientID is the unique ID for a prosemirror client. Used for step-rebasing.
38
+
39
+ // UserID is the users actual account id.
40
+
48
41
  function Provider(config) {
49
42
  var _this;
50
43
  _classCallCheck(this, Provider);
51
44
  _this = _super.call(this);
52
- _defineProperty(_assertThisInitialized(_this), "participants", new Map());
53
- _defineProperty(_assertThisInitialized(_this), "metadata", {});
54
- _defineProperty(_assertThisInitialized(_this), "stepRejectCounter", 0);
55
45
  _defineProperty(_assertThisInitialized(_this), "isChannelInitialized", false);
46
+ _defineProperty(_assertThisInitialized(_this), "isProviderInitialized", false);
56
47
  _defineProperty(_assertThisInitialized(_this), "isNamespaceLocked", false);
48
+ _defineProperty(_assertThisInitialized(_this), "emitCallback", function (evt, data) {
49
+ return _this.emit(evt, data);
50
+ });
57
51
  _defineProperty(_assertThisInitialized(_this), "initializeChannel", function () {
58
52
  _this.emit('connecting', {
59
53
  initial: true
60
54
  });
55
+ var shouldInitialize = Boolean(_this.initialDraft) && !_this.isProviderInitialized;
61
56
  _this.channel.on('connected', function (_ref) {
62
57
  var sid = _ref.sid,
63
58
  initialized = _ref.initialized;
@@ -66,253 +61,62 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
66
61
  sid: sid,
67
62
  initial: !initialized
68
63
  });
64
+ // If initial draft is already present and the channel is initialized,
65
+ // fire the provider's init event with initial draft document and version
66
+ if (_this.initialDraft && initialized && !_this.isProviderInitialized) {
67
+ var _this$initialDraft = _this.initialDraft,
68
+ document = _this$initialDraft.document,
69
+ version = _this$initialDraft.version,
70
+ metadata = _this$initialDraft.metadata;
71
+ // Initial document, version, metadata from initial draft
72
+ _this.documentService.updateDocument({
73
+ doc: document,
74
+ version: version,
75
+ metadata: metadata
76
+ });
77
+ _this.metadataService.updateMetadata(metadata);
78
+ _this.isProviderInitialized = true;
79
+ }
69
80
  // If already initialized, `connected` means reconnected
70
81
  if (initialized && _this.disconnectedAt &&
71
82
  // Offline longer than `OUT_OF_SYNC_PERIOD`
72
83
  Date.now() - _this.disconnectedAt >= OUT_OF_SYNC_PERIOD) {
73
- _this.throttledCatchup();
84
+ _this.documentService.throttledCatchup();
74
85
  }
86
+ _this.startInactiveRemover();
75
87
  _this.disconnectedAt = undefined;
76
88
  }).on('init', function (_ref2) {
77
89
  var doc = _ref2.doc,
78
90
  version = _ref2.version,
79
91
  metadata = _ref2.metadata;
80
92
  // Initial document and version
81
- _this.updateDocumentWithMetadata({
93
+ _this.documentService.updateDocument({
82
94
  doc: doc,
83
95
  version: version,
84
96
  metadata: metadata
85
97
  });
86
- }).on('restore', _this.onRestore.bind(_assertThisInitialized(_this))).on('steps:added', _this.onStepsAdded.bind(_assertThisInitialized(_this))).on('participant:telepointer', _this.onParticipantTelepointer.bind(_assertThisInitialized(_this))).on('presence:joined', _this.onPresenceJoined.bind(_assertThisInitialized(_this))).on('presence', _this.onPresence.bind(_assertThisInitialized(_this))).on('participant:left', _this.onParticipantLeft.bind(_assertThisInitialized(_this))).on('participant:updated', _this.onParticipantUpdated.bind(_assertThisInitialized(_this))).on('metadata:changed', _this.onMetadataChanged.bind(_assertThisInitialized(_this))).on('disconnect', _this.onDisconnected.bind(_assertThisInitialized(_this))).on('error', _this.onErrorHandled.bind(_assertThisInitialized(_this))).on('status', _this.onNamespaceStatusChanged.bind(_assertThisInitialized(_this))).connect();
87
- });
88
- _defineProperty(_assertThisInitialized(_this), "onRestore", function (_ref3) {
89
- var doc = _ref3.doc,
90
- version = _ref3.version,
91
- metadata = _ref3.metadata;
92
- // Preserve the unconfirmed steps to prevent data loss.
93
- var unconfirmedSteps = _this.getUnconfirmedSteps();
94
- try {
95
- var _this$analyticsHelper;
96
- // Reset the editor,
97
- // - Replace the document, keep in sync with the server
98
- // - Replace the version number, so editor is in sync with NCS server and can commit new changes.
99
- // - Replace the metadata
100
- // - Reserve the cursor position, in case a cursor jump.
101
- _this.updateDocumentWithMetadata({
102
- doc: doc,
103
- version: version,
104
- metadata: metadata,
105
- reserveCursor: true
106
- });
107
- (_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendActionEvent(EVENT_ACTION.REINITIALISE_DOCUMENT, EVENT_STATUS.SUCCESS, {
108
- numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
109
- });
110
- // Re-apply the unconfirmed steps, not 100% of them can be applied, if document is changed significantly.
111
- if (unconfirmedSteps !== null && unconfirmedSteps !== void 0 && unconfirmedSteps.length) {
112
- _this.applyLocalSteps(unconfirmedSteps);
113
- }
114
- } catch (restoreError) {
115
- var _this$analyticsHelper2, _this$analyticsHelper3;
116
- (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendActionEvent(EVENT_ACTION.REINITIALISE_DOCUMENT, EVENT_STATUS.FAILURE, {
117
- numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
118
- });
119
- (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(restoreError, 'Error while reinitialising document');
120
- _this.onErrorHandled({
121
- message: 'Caught error while trying to recover the document',
122
- data: {
123
- status: 500,
124
- // Meaningless, remove when we review error structure
125
- code: ErrorCodeMapper.restoreError.code
126
- }
127
- });
128
- }
129
- });
130
- _defineProperty(_assertThisInitialized(_this), "onStepsAdded", function (data) {
131
- logger("Received steps", {
132
- steps: data.steps,
133
- version: data.version
134
- });
135
- if (!data.steps) {
136
- logger("No steps.. waiting..");
137
- return;
138
- }
139
- try {
140
- var currentVersion = _this.getCurrentPmVersion();
141
- var expectedVersion = currentVersion + data.steps.length;
142
- if (data.version === currentVersion) {
143
- logger("Received steps we already have. Ignoring.");
144
- } else if (data.version === expectedVersion) {
145
- _this.processSteps(data);
146
- } else if (data.version > expectedVersion) {
147
- logger("Version too high. Expected \"".concat(expectedVersion, "\" but got \"").concat(data.version, ". Current local version is ").concat(currentVersion, "."));
148
- _this.queueSteps(data);
149
- _this.throttledCatchup();
150
- }
151
- _this.updateParticipants([], data.steps.map(function (_ref4) {
152
- var userId = _ref4.userId;
153
- return userId;
154
- }));
155
- } catch (stepsAddedError) {
156
- var _this$analyticsHelper4;
157
- (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(stepsAddedError, 'Error while adding steps in the provider');
158
- _this.onErrorHandled({
159
- message: 'Error while adding steps in the provider',
160
- data: {
161
- status: 500,
162
- // Meaningless, remove when we review error structure
163
- code: ErrorCodeMapper.internalError.code
164
- }
165
- });
166
- }
167
- });
168
- _defineProperty(_assertThisInitialized(_this), "throttledCatchup", throttle(function () {
169
- return _this.catchup();
170
- }, CATCHUP_THROTTLE, {
171
- leading: false,
172
- trailing: true
173
- }));
174
- _defineProperty(_assertThisInitialized(_this), "filterQueue", function (condition) {
175
- _this.queue = _this.queue.filter(condition);
98
+ _this.metadataService.updateMetadata(metadata);
99
+ }).on('restore', _this.documentService.onRestore).on('steps:added', _this.documentService.onStepsAdded).on('metadata:changed', _this.metadataService.onMetadataChanged).on('participant:telepointer', _this.onParticipantTelepointer.bind(_assertThisInitialized(_this))).on('presence:joined', _this.onPresenceJoined.bind(_assertThisInitialized(_this))).on('presence', _this.onPresence.bind(_assertThisInitialized(_this))).on('participant:left', _this.onParticipantLeft.bind(_assertThisInitialized(_this))).on('participant:updated', _this.onParticipantUpdated.bind(_assertThisInitialized(_this))).on('disconnect', _this.onDisconnected.bind(_assertThisInitialized(_this))).on('error', _this.onErrorHandled).on('status', _this.onNamespaceStatusChanged.bind(_assertThisInitialized(_this))).connect(shouldInitialize);
176
100
  });
177
- _defineProperty(_assertThisInitialized(_this), "updateDocumentWithMetadata", function (_ref5) {
178
- var doc = _ref5.doc,
179
- version = _ref5.version,
180
- metadata = _ref5.metadata,
181
- reserveCursor = _ref5.reserveCursor;
182
- _this.emit('init', _objectSpread({
183
- doc: doc,
184
- version: version,
185
- metadata: metadata
186
- }, reserveCursor ? {
187
- reserveCursor: reserveCursor
188
- } : {}));
189
- if (metadata && Object.keys(metadata).length > 0) {
190
- _this.metadata = metadata;
191
- _this.emit('metadata:changed', metadata);
192
- }
193
- });
194
- _defineProperty(_assertThisInitialized(_this), "applyLocalSteps", function (steps) {
195
- // Re-apply local steps
196
- _this.emit('local-steps', {
197
- steps: steps
198
- });
199
- });
200
- _defineProperty(_assertThisInitialized(_this), "getCurrentPmVersion", function () {
201
- var _this$getState, _this2;
202
- var state = (_this$getState = (_this2 = _this).getState) === null || _this$getState === void 0 ? void 0 : _this$getState.call(_this2);
203
- if (!state) {
204
- var _this$analyticsHelper5;
205
- (_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(new Error('No editor state when calling ProseMirror function'), 'getCurrentPmVersion called without state');
206
- return 0;
207
- }
208
- return getVersion(state);
209
- });
210
- _defineProperty(_assertThisInitialized(_this), "getUnconfirmedSteps", function () {
211
- var _this$getState2, _this3, _sendableSteps;
212
- var state = (_this$getState2 = (_this3 = _this).getState) === null || _this$getState2 === void 0 ? void 0 : _this$getState2.call(_this3);
213
- if (!state) {
214
- var _this$analyticsHelper6;
215
- (_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendErrorEvent(new Error('No editor state when calling ProseMirror function'), 'getUnconfirmedSteps called without state');
216
- return;
217
- }
218
- return (_sendableSteps = sendableSteps(state)) === null || _sendableSteps === void 0 ? void 0 : _sendableSteps.steps;
219
- });
220
- _defineProperty(_assertThisInitialized(_this), "getUnconfirmedStepsOrigins", function () {
221
- var _this$getState3, _this4, _sendableSteps2;
222
- var state = (_this$getState3 = (_this4 = _this).getState) === null || _this$getState3 === void 0 ? void 0 : _this$getState3.call(_this4);
223
- if (!state) {
224
- var _this$analyticsHelper7;
225
- (_this$analyticsHelper7 = _this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(new Error('No editor state when calling ProseMirror function'), 'getUnconfirmedStepsOrigins called without state');
226
- return;
227
- }
228
- return (_sendableSteps2 = sendableSteps(state)) === null || _sendableSteps2 === void 0 ? void 0 : _sendableSteps2.origins;
229
- });
230
- _defineProperty(_assertThisInitialized(_this), "catchup", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
231
- var start, _this$analyticsHelper8, latency, _this$analyticsHelper9, _this$analyticsHelper10, _latency;
232
- return _regeneratorRuntime.wrap(function _callee$(_context) {
233
- while (1) {
234
- switch (_context.prev = _context.next) {
235
- case 0:
236
- start = new Date().getTime(); // if the queue is already paused, we are busy with something else, so don't proceed.
237
- if (!_this.pauseQueue) {
238
- _context.next = 4;
239
- break;
240
- }
241
- logger("Queue is paused. Aborting.");
242
- return _context.abrupt("return");
243
- case 4:
244
- _this.pauseQueue = true;
245
- _context.prev = 5;
246
- _context.next = 8;
247
- return catchup({
248
- getCurrentPmVersion: _this.getCurrentPmVersion,
249
- fetchCatchup: _this.channel.fetchCatchup.bind(_this.channel),
250
- getUnconfirmedSteps: _this.getUnconfirmedSteps,
251
- getUnconfirmedStepsOrigins: _this.getUnconfirmedStepsOrigins,
252
- filterQueue: _this.filterQueue,
253
- updateDocumentWithMetadata: _this.updateDocumentWithMetadata,
254
- applyLocalSteps: _this.applyLocalSteps
255
- });
256
- case 8:
257
- latency = new Date().getTime() - start;
258
- (_this$analyticsHelper8 = _this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendActionEvent(EVENT_ACTION.CATCHUP, EVENT_STATUS.SUCCESS, {
259
- latency: latency
260
- });
261
- _context.next = 18;
262
- break;
263
- case 12:
264
- _context.prev = 12;
265
- _context.t0 = _context["catch"](5);
266
- _latency = new Date().getTime() - start;
267
- (_this$analyticsHelper9 = _this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendActionEvent(EVENT_ACTION.CATCHUP, EVENT_STATUS.FAILURE, {
268
- latency: _latency
269
- });
270
- (_this$analyticsHelper10 = _this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(_context.t0, 'Error while catching up');
271
- logger("Catch-Up Failed:", _context.t0.message);
272
- case 18:
273
- _context.prev = 18;
274
- _this.pauseQueue = false;
275
- _this.processQueue();
276
- _this.sendStepsFromCurrentState(); // this will eventually retry catchup as it calls commitStep which will either catchup on onStepsAdded or onErrorHandled
277
- _this.stepRejectCounter = 0;
278
- return _context.finish(18);
279
- case 24:
280
- case "end":
281
- return _context.stop();
282
- }
283
- }
284
- }, _callee, null, [[5, 12, 18, 24]]);
285
- })));
286
101
  _defineProperty(_assertThisInitialized(_this), "onErrorHandled", function (error) {
287
102
  var _error$data, _error$data2;
288
103
  // User tried committing steps but they were rejected because:
289
104
  // HEAD_VERSION_UPDATE_FAILED: the collab service's latest stored step tail version didn't correspond to the head version of the first step submitted
290
105
  // VERSION_NUMBER_ALREADY_EXISTS: while storing the steps there was a conflict meaning someone else wrote steps into the database more quickly
291
- if (((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) === 'HEAD_VERSION_UPDATE_FAILED' || ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.code) === 'VERSION_NUMBER_ALREADY_EXISTS') {
292
- _this.stepRejectCounter++;
293
- logger("Steps rejected (tries=".concat(_this.stepRejectCounter, ")"));
294
- if (_this.stepRejectCounter >= MAX_STEP_REJECTED_ERROR) {
295
- logger("The steps were rejected too many times (tries=".concat(_this.stepRejectCounter, ", limit=").concat(MAX_STEP_REJECTED_ERROR, "). Trying to catch-up."));
296
- _this.throttledCatchup();
297
- } else {
298
- // If committing steps failed try again automatically in 1s
299
- // This makes it more likely that unconfirmed steps trigger a catch-up
300
- // within 15s even if there is no one editing actively (or draft sync polling)
301
- // reducing the risk of data loss at the expense of step commits
302
- setTimeout(function () {
303
- return _this.sendStepsFromCurrentState();
304
- }, 1000);
305
- }
106
+ if (((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) === NCS_ERROR_CODE.HEAD_VERSION_UPDATE_FAILED || ((_error$data2 = error.data) === null || _error$data2 === void 0 ? void 0 : _error$data2.code) === NCS_ERROR_CODE.VERSION_NUMBER_ALREADY_EXISTS) {
107
+ _this.documentService.onStepRejectedError();
306
108
  } else {
307
- logger('Error from collab service', error);
109
+ var _this$analyticsHelper;
110
+ (_this$analyticsHelper = _this.analyticsHelper) === null || _this$analyticsHelper === void 0 ? void 0 : _this$analyticsHelper.sendErrorEvent(error, 'Error handled');
308
111
  var mappedError = errorCodeMapper(error);
309
112
  // Temporarily only emit errors to Confluence very intentionally because they will disconnect the collab provider
310
113
  if (mappedError) {
114
+ var _this$analyticsHelper2;
115
+ (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(mappedError, 'Error emitted');
311
116
  _this.emit('error', mappedError);
312
117
  }
313
118
  }
314
119
  });
315
- _defineProperty(_assertThisInitialized(_this), "queue", []);
316
120
  _defineProperty(_assertThisInitialized(_this), "sendPresence", function () {
317
121
  try {
318
122
  if (_this.presenceUpdateTimeout) {
@@ -327,399 +131,102 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
327
131
  return _this.sendPresence();
328
132
  }, SEND_PRESENCE_INTERVAL);
329
133
  } catch (error) {
330
- var _this$analyticsHelper11;
134
+ var _this$analyticsHelper3;
331
135
  // We don't want to throw errors for Presence features as they tend to self-restore
332
- (_this$analyticsHelper11 = _this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while sending presence');
136
+ (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(error, 'Error while sending presence');
333
137
  }
334
138
  });
335
- _defineProperty(_assertThisInitialized(_this), "onPresenceJoined", function (_ref7) {
336
- var sessionId = _ref7.sessionId;
139
+ _defineProperty(_assertThisInitialized(_this), "onPresenceJoined", function (_ref3) {
140
+ var sessionId = _ref3.sessionId;
337
141
  try {
338
142
  logger('Participant joined with session: ', sessionId);
339
143
  // This expose existing users to the newly joined user
340
144
  _this.sendPresence();
341
145
  } catch (error) {
342
- var _this$analyticsHelper12;
146
+ var _this$analyticsHelper4;
343
147
  // We don't want to throw errors for Presence features as they tend to self-restore
344
- (_this$analyticsHelper12 = _this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while joining presence');
148
+ (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(error, 'Error while joining presence');
345
149
  }
346
150
  });
347
- _defineProperty(_assertThisInitialized(_this), "onPresence", function (_ref8) {
348
- var userId = _ref8.userId;
151
+ _defineProperty(_assertThisInitialized(_this), "onPresence", function (_ref4) {
152
+ var userId = _ref4.userId;
349
153
  try {
350
154
  logger('onPresence userId: ', userId);
351
155
  _this.userId = userId;
352
156
  _this.sendPresence();
353
157
  _this.channel.sendPresenceJoined();
354
158
  } catch (error) {
355
- var _this$analyticsHelper13;
159
+ var _this$analyticsHelper5;
356
160
  // We don't want to throw errors for Presence features as they tend to self-restore
357
- (_this$analyticsHelper13 = _this.analyticsHelper) === null || _this$analyticsHelper13 === void 0 ? void 0 : _this$analyticsHelper13.sendErrorEvent(error, 'Error while receiving presence');
161
+ (_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(error, 'Error while receiving presence');
358
162
  }
359
163
  });
360
- _defineProperty(_assertThisInitialized(_this), "onMetadataChanged", function (metadata) {
361
- if (metadata !== undefined && !isEqual(_this.metadata, metadata)) {
362
- _this.metadata = metadata;
363
- _this.emit('metadata:changed', metadata);
364
- }
164
+ _defineProperty(_assertThisInitialized(_this), "onParticipantLeft", function (data) {
165
+ return _this.participantsService.participantLeft(data, _this.emitCallback);
365
166
  });
366
- _defineProperty(_assertThisInitialized(_this), "onParticipantLeft", function (_ref9) {
367
- var sessionId = _ref9.sessionId;
368
- try {
369
- logger("Participant left");
370
- _this.participants.delete(sessionId);
371
- _this.emit('presence', {
372
- left: [{
373
- sessionId: sessionId
374
- }]
375
- });
376
- } catch (error) {
377
- var _this$analyticsHelper14;
378
- // We don't want to throw errors for Presence features as they tend to self-restore
379
- (_this$analyticsHelper14 = _this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendErrorEvent(error, 'Error while participant leaving');
380
- }
167
+ _defineProperty(_assertThisInitialized(_this), "startInactiveRemover", function () {
168
+ return _this.participantsService.removeInactiveParticipants(_this.sessionId, _this.emitCallback);
381
169
  });
382
- _defineProperty(_assertThisInitialized(_this), "onParticipantUpdated", function (_ref10) {
383
- var sessionId = _ref10.sessionId,
384
- timestamp = _ref10.timestamp,
385
- userId = _ref10.userId,
386
- clientId = _ref10.clientId;
387
- try {
388
- _this.updateParticipant({
389
- sessionId: sessionId,
390
- timestamp: timestamp,
391
- userId: userId,
392
- clientId: clientId
393
- });
394
- } catch (error) {
395
- var _this$analyticsHelper15;
396
- // We don't want to throw errors for Presence features as they tend to self-restore
397
- (_this$analyticsHelper15 = _this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendErrorEvent(error, 'Error while handling participant updated event');
398
- }
170
+ _defineProperty(_assertThisInitialized(_this), "onParticipantUpdated", function (data) {
171
+ return _this.participantsService.updateParticipant(data, _this.config.getUser, _this.emitCallback);
399
172
  });
400
173
  _defineProperty(_assertThisInitialized(_this), "onParticipantTelepointer", function (data) {
401
- try {
402
- var sessionId = data.sessionId,
403
- selection = data.selection,
404
- timestamp = data.timestamp;
405
- var participant = _this.participants.get(sessionId);
406
- if (sessionId === _this.sessionId ||
407
- // Ignore old telepointer events
408
- participant && participant.lastActive > timestamp) {
409
- return;
410
- }
411
-
412
- // Set last active
413
- _this.updateParticipant(data);
414
- _this.emit('telepointer', {
415
- type: 'telepointer',
416
- selection: selection,
417
- sessionId: sessionId
418
- });
419
- } catch (error) {
420
- var _this$analyticsHelper16;
421
- // We don't want to throw errors for Presence features as they tend to self-restore
422
- (_this$analyticsHelper16 = _this.analyticsHelper) === null || _this$analyticsHelper16 === void 0 ? void 0 : _this$analyticsHelper16.sendErrorEvent(error, 'Error while handling participant telepointer event');
423
- }
424
- });
425
- _defineProperty(_assertThisInitialized(_this), "updateParticipant", /*#__PURE__*/function () {
426
- var _ref12 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref11) {
427
- var sessionId, timestamp, userId, clientId, getUser, _yield, _yield$name, name, _yield$email, email, _yield$avatar, avatar, isNewParticipant, _this$analyticsHelper17;
428
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
429
- while (1) {
430
- switch (_context2.prev = _context2.next) {
431
- case 0:
432
- sessionId = _ref11.sessionId, timestamp = _ref11.timestamp, userId = _ref11.userId, clientId = _ref11.clientId;
433
- _context2.prev = 1;
434
- if (userId) {
435
- _context2.next = 4;
436
- break;
437
- }
438
- return _context2.abrupt("return");
439
- case 4:
440
- getUser = _this.config.getUser;
441
- _context2.next = 7;
442
- return getUser ? getUser(userId) : getParticipant(userId);
443
- case 7:
444
- _yield = _context2.sent;
445
- _yield$name = _yield.name;
446
- name = _yield$name === void 0 ? '' : _yield$name;
447
- _yield$email = _yield.email;
448
- email = _yield$email === void 0 ? '' : _yield$email;
449
- _yield$avatar = _yield.avatar;
450
- avatar = _yield$avatar === void 0 ? '' : _yield$avatar;
451
- isNewParticipant = !_this.participants.has(sessionId);
452
- if (isNewParticipant) {
453
- logger('new Participant updated', {
454
- name: name,
455
- avatar: avatar
456
- });
457
- }
458
- _this.participants.set(sessionId, {
459
- name: name,
460
- email: email,
461
- avatar: avatar,
462
- sessionId: sessionId,
463
- lastActive: timestamp,
464
- userId: userId,
465
- clientId: clientId
466
- });
467
-
468
- // Collab-plugin expects an array of users that joined.
469
- _this.updateParticipants(isNewParticipant ? [_this.participants.get(sessionId)] : []);
470
- _context2.next = 23;
471
- break;
472
- case 20:
473
- _context2.prev = 20;
474
- _context2.t0 = _context2["catch"](1);
475
- // We don't want to throw errors for Presence features as they tend to self-restore
476
- (_this$analyticsHelper17 = _this.analyticsHelper) === null || _this$analyticsHelper17 === void 0 ? void 0 : _this$analyticsHelper17.sendErrorEvent(_context2.t0, 'Error while updating participant');
477
- case 23:
478
- case "end":
479
- return _context2.stop();
480
- }
481
- }
482
- }, _callee2, null, [[1, 20]]);
483
- }));
484
- return function (_x) {
485
- return _ref12.apply(this, arguments);
486
- };
487
- }());
488
- _defineProperty(_assertThisInitialized(_this), "updateParticipants", function () {
489
- var joined = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
490
- var userIds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
491
- try {
492
- if (_this.participantUpdateTimeout) {
493
- clearTimeout(_this.participantUpdateTimeout);
494
- }
495
- var now = new Date().getTime();
496
- Array.from(_this.participants.values()).forEach(function (p) {
497
- if (userIds.indexOf(p.userId) !== -1) {
498
- _this.participants.set(p.sessionId, _objectSpread(_objectSpread({}, p), {}, {
499
- lastActive: now
500
- }));
501
- }
502
- });
503
-
504
- // Filter out participants that's been inactive for more than 5 minutes.
505
- var left = Array.from(_this.participants.values()).filter(function (p) {
506
- return p.sessionId !== _this.sessionId && now - p.lastActive > PARTICIPANT_UPDATE_INTERVAL;
507
- });
508
- left.forEach(function (p) {
509
- return _this.participants.delete(p.sessionId);
510
- });
511
- if (joined.length || left.length) {
512
- var _this$analyticsHelper18, _this$participants$si;
513
- (_this$analyticsHelper18 = _this.analyticsHelper) === null || _this$analyticsHelper18 === void 0 ? void 0 : _this$analyticsHelper18.sendActionEvent(EVENT_ACTION.UPDATE_PARTICIPANTS, EVENT_STATUS.SUCCESS, {
514
- participants: (_this$participants$si = _this.participants.size) !== null && _this$participants$si !== void 0 ? _this$participants$si : 1
515
- });
516
- _this.emit('presence', _objectSpread(_objectSpread({}, joined.length ? {
517
- joined: joined
518
- } : {}), left.length ? {
519
- left: left
520
- } : {}));
521
- }
522
- _this.participantUpdateTimeout = window.setTimeout(function () {
523
- return _this.updateParticipants();
524
- }, PARTICIPANT_UPDATE_INTERVAL);
525
- } catch (error) {
526
- var _this$analyticsHelper19;
527
- // We don't want to throw errors for Presence features as they tend to self-restore
528
- (_this$analyticsHelper19 = _this.analyticsHelper) === null || _this$analyticsHelper19 === void 0 ? void 0 : _this$analyticsHelper19.sendErrorEvent(error, 'Error while updating participants');
529
- }
174
+ return _this.participantsService.participantTelepointer(data, _this.sessionId, _this.config.getUser, _this.emitCallback);
530
175
  });
531
- _defineProperty(_assertThisInitialized(_this), "onDisconnected", function (_ref13) {
532
- var reason = _ref13.reason;
176
+ _defineProperty(_assertThisInitialized(_this), "onDisconnected", function (_ref5) {
177
+ var reason = _ref5.reason;
533
178
  _this.disconnectedAt = Date.now();
534
- var left = Array.from(_this.participants.values());
535
- _this.participants.clear();
536
- _this.emit('disconnected', {
537
- reason: disconnectedReasonMapper(reason),
538
- sid: _this.sessionId
539
- });
540
- if (left.length) {
541
- _this.emit('presence', {
542
- left: left
543
- });
544
- }
179
+ _this.participantsService.disconnect(reason, _this.sessionId, _this.emitCallback);
545
180
  });
546
- _defineProperty(_assertThisInitialized(_this), "getCurrentState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
547
- var _this$metadata$title, _this$analyticsHelper20, state, adfDocument, currentState, measure, _this$analyticsHelper21, _this$analyticsHelper22, _measure;
548
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
181
+ _defineProperty(_assertThisInitialized(_this), "getCurrentState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
182
+ var _this$analyticsHelper6;
183
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
549
184
  while (1) {
550
- switch (_context3.prev = _context3.next) {
551
- case 0:
552
- _context3.prev = 0;
553
- startMeasure(MEASURE_NAME.GET_CURRENT_STATE, _this.analyticsHelper);
554
-
555
- // Convert ProseMirror document in Editor state to ADF document
556
- state = _this.getState();
557
- adfDocument = new JSONTransformer().encode(state.doc);
558
- currentState = {
559
- content: adfDocument,
560
- title: (_this$metadata$title = _this.metadata.title) === null || _this$metadata$title === void 0 ? void 0 : _this$metadata$title.toString(),
561
- stepVersion: getVersion(state)
562
- };
563
- measure = stopMeasure(MEASURE_NAME.GET_CURRENT_STATE, _this.analyticsHelper);
564
- (_this$analyticsHelper20 = _this.analyticsHelper) === null || _this$analyticsHelper20 === void 0 ? void 0 : _this$analyticsHelper20.sendActionEvent(EVENT_ACTION.GET_CURRENT_STATE, EVENT_STATUS.SUCCESS, {
565
- latency: measure === null || measure === void 0 ? void 0 : measure.duration
566
- });
567
- return _context3.abrupt("return", currentState);
568
- case 10:
569
- _context3.prev = 10;
570
- _context3.t0 = _context3["catch"](0);
571
- _measure = stopMeasure(MEASURE_NAME.GET_CURRENT_STATE, _this.analyticsHelper);
572
- (_this$analyticsHelper21 = _this.analyticsHelper) === null || _this$analyticsHelper21 === void 0 ? void 0 : _this$analyticsHelper21.sendActionEvent(EVENT_ACTION.GET_CURRENT_STATE, EVENT_STATUS.FAILURE, {
573
- latency: _measure === null || _measure === void 0 ? void 0 : _measure.duration
574
- });
575
- (_this$analyticsHelper22 = _this.analyticsHelper) === null || _this$analyticsHelper22 === void 0 ? void 0 : _this$analyticsHelper22.sendErrorEvent(_context3.t0, 'Error while returning ADF version of current draft document');
576
- throw _context3.t0;
577
- case 16:
578
- case "end":
579
- return _context3.stop();
580
- }
581
- }
582
- }, _callee3, null, [[0, 10]]);
583
- })));
584
- _defineProperty(_assertThisInitialized(_this), "commitUnconfirmedSteps", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
585
- var unconfirmedSteps, _this$analyticsHelper24, _this$analyticsHelper25, measure;
586
- return _regeneratorRuntime.wrap(function _callee5$(_context5) {
587
- while (1) {
588
- switch (_context5.prev = _context5.next) {
185
+ switch (_context.prev = _context.next) {
589
186
  case 0:
590
- unconfirmedSteps = _this.getUnconfirmedSteps();
591
- _context5.prev = 1;
592
- if (!(unconfirmedSteps !== null && unconfirmedSteps !== void 0 && unconfirmedSteps.length)) {
593
- _context5.next = 4;
594
- break;
595
- }
596
- return _context5.delegateYield( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
597
- var _this$analyticsHelper23;
598
- var count, unconfirmedTrs, lastTr, isLastTrConfirmed, nextUnconfirmedSteps, nextUnconfirmedTrs, state, measure;
599
- return _regeneratorRuntime.wrap(function _callee4$(_context4) {
600
- while (1) {
601
- switch (_context4.prev = _context4.next) {
602
- case 0:
603
- startMeasure(MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
604
- count = 0; // We use origins here as steps can be rebased. When steps are rebased a new step is created.
605
- // This means that we can not track if it has been removed from the unconfirmed array or not.
606
- // Origins points to the original transaction that the step was created in. This is never changed
607
- // and gets passed down when a step is rebased.
608
- unconfirmedTrs = _this.getUnconfirmedStepsOrigins();
609
- lastTr = unconfirmedTrs === null || unconfirmedTrs === void 0 ? void 0 : unconfirmedTrs[unconfirmedTrs.length - 1];
610
- isLastTrConfirmed = false;
611
- case 5:
612
- if (isLastTrConfirmed) {
613
- _context4.next = 16;
614
- break;
615
- }
616
- _this.sendStepsFromCurrentState();
617
- _context4.next = 9;
618
- return sleep(1000);
619
- case 9:
620
- nextUnconfirmedSteps = _this.getUnconfirmedSteps();
621
- if (nextUnconfirmedSteps !== null && nextUnconfirmedSteps !== void 0 && nextUnconfirmedSteps.length) {
622
- nextUnconfirmedTrs = _this.getUnconfirmedStepsOrigins();
623
- isLastTrConfirmed = !(nextUnconfirmedTrs !== null && nextUnconfirmedTrs !== void 0 && nextUnconfirmedTrs.some(function (tr) {
624
- return tr === lastTr;
625
- }));
626
- } else {
627
- isLastTrConfirmed = true;
628
- }
629
- if (!(!isLastTrConfirmed && count++ >= ACK_MAX_TRY)) {
630
- _context4.next = 14;
631
- break;
632
- }
633
- if (_this.onSyncUpError) {
634
- state = _this.getState();
635
- _this.onSyncUpError({
636
- lengthOfUnconfirmedSteps: nextUnconfirmedSteps === null || nextUnconfirmedSteps === void 0 ? void 0 : nextUnconfirmedSteps.length,
637
- tries: count,
638
- maxRetries: ACK_MAX_TRY,
639
- clientId: _this.clientId,
640
- version: getVersion(state)
641
- });
642
- }
643
- throw new Error("Can't sync up with Collab Service");
644
- case 14:
645
- _context4.next = 5;
646
- break;
647
- case 16:
648
- measure = stopMeasure(MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
649
- (_this$analyticsHelper23 = _this.analyticsHelper) === null || _this$analyticsHelper23 === void 0 ? void 0 : _this$analyticsHelper23.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.SUCCESS, {
650
- latency: measure === null || measure === void 0 ? void 0 : measure.duration,
651
- // upon success, emit the total number of unconfirmed steps we synced
652
- numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
653
- });
654
- case 18:
655
- case "end":
656
- return _context4.stop();
657
- }
658
- }
659
- }, _callee4);
660
- })(), "t0", 4);
187
+ _context.prev = 0;
188
+ return _context.abrupt("return", _this.documentService.getCurrentState());
661
189
  case 4:
662
- _context5.next = 12;
663
- break;
664
- case 6:
665
- _context5.prev = 6;
666
- _context5.t1 = _context5["catch"](1);
667
- measure = stopMeasure(MEASURE_NAME.COMMIT_UNCONFIRMED_STEPS, _this.analyticsHelper);
668
- (_this$analyticsHelper24 = _this.analyticsHelper) === null || _this$analyticsHelper24 === void 0 ? void 0 : _this$analyticsHelper24.sendActionEvent(EVENT_ACTION.COMMIT_UNCONFIRMED_STEPS, EVENT_STATUS.FAILURE, {
669
- latency: measure === null || measure === void 0 ? void 0 : measure.duration,
670
- numUnconfirmedSteps: unconfirmedSteps === null || unconfirmedSteps === void 0 ? void 0 : unconfirmedSteps.length
671
- });
672
- (_this$analyticsHelper25 = _this.analyticsHelper) === null || _this$analyticsHelper25 === void 0 ? void 0 : _this$analyticsHelper25.sendErrorEvent(_context5.t1, 'Error while committing unconfirmed steps');
673
- throw _context5.t1;
674
- case 12:
190
+ _context.prev = 4;
191
+ _context.t0 = _context["catch"](0);
192
+ (_this$analyticsHelper6 = _this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendErrorEvent(_context.t0, 'Error while returning ADF version of current draft document');
193
+ throw new GetCurrentStateError('Error while returning the current state of the draft document', _context.t0);
194
+ case 8:
675
195
  case "end":
676
- return _context5.stop();
196
+ return _context.stop();
677
197
  }
678
198
  }
679
- }, _callee5, null, [[1, 6]]);
199
+ }, _callee, null, [[0, 4]]);
680
200
  })));
681
- _defineProperty(_assertThisInitialized(_this), "getFinalAcknowledgedState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
682
- var _this$analyticsHelper26, currentState, measure, _this$analyticsHelper27, _this$analyticsHelper28, _measure2;
683
- return _regeneratorRuntime.wrap(function _callee6$(_context6) {
201
+ _defineProperty(_assertThisInitialized(_this), "getFinalAcknowledgedState", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
202
+ var _this$analyticsHelper7;
203
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
684
204
  while (1) {
685
- switch (_context6.prev = _context6.next) {
205
+ switch (_context2.prev = _context2.next) {
686
206
  case 0:
687
- _context6.prev = 0;
688
- startMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
689
- _context6.next = 4;
690
- return _this.commitUnconfirmedSteps();
207
+ _context2.prev = 0;
208
+ return _context2.abrupt("return", _this.documentService.getFinalAcknowledgedState());
691
209
  case 4:
692
- _context6.next = 6;
693
- return _this.getCurrentState();
694
- case 6:
695
- currentState = _context6.sent;
696
- measure = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
697
- (_this$analyticsHelper26 = _this.analyticsHelper) === null || _this$analyticsHelper26 === void 0 ? void 0 : _this$analyticsHelper26.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.SUCCESS, {
698
- latency: measure === null || measure === void 0 ? void 0 : measure.duration
699
- });
700
- return _context6.abrupt("return", currentState);
701
- case 12:
702
- _context6.prev = 12;
703
- _context6.t0 = _context6["catch"](0);
704
- _measure2 = stopMeasure(MEASURE_NAME.PUBLISH_PAGE, _this.analyticsHelper);
705
- (_this$analyticsHelper27 = _this.analyticsHelper) === null || _this$analyticsHelper27 === void 0 ? void 0 : _this$analyticsHelper27.sendActionEvent(EVENT_ACTION.PUBLISH_PAGE, EVENT_STATUS.FAILURE, {
706
- latency: _measure2 === null || _measure2 === void 0 ? void 0 : _measure2.duration
707
- });
708
- (_this$analyticsHelper28 = _this.analyticsHelper) === null || _this$analyticsHelper28 === void 0 ? void 0 : _this$analyticsHelper28.sendErrorEvent(_context6.t0, 'Error while returning ADF version of the final draft document');
709
- throw _context6.t0;
710
- case 18:
210
+ _context2.prev = 4;
211
+ _context2.t0 = _context2["catch"](0);
212
+ (_this$analyticsHelper7 = _this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(_context2.t0, 'Error while returning ADF version of the final draft document');
213
+ throw new GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context2.t0);
214
+ case 8:
711
215
  case "end":
712
- return _context6.stop();
216
+ return _context2.stop();
713
217
  }
714
218
  }
715
- }, _callee6, null, [[0, 12]]);
219
+ }, _callee2, null, [[0, 4]]);
716
220
  })));
221
+ _defineProperty(_assertThisInitialized(_this), "getUnconfirmedSteps", function () {
222
+ return _this.documentService.getUnconfirmedSteps();
223
+ });
717
224
  _defineProperty(_assertThisInitialized(_this), "onNamespaceStatusChanged", /*#__PURE__*/function () {
718
- var _ref17 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee7(data) {
225
+ var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(data) {
719
226
  var isLocked, waitTimeInMs, timestamp, start;
720
- return _regeneratorRuntime.wrap(function _callee7$(_context7) {
227
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
721
228
  while (1) {
722
- switch (_context7.prev = _context7.next) {
229
+ switch (_context3.prev = _context3.next) {
723
230
  case 0:
724
231
  isLocked = data.isLocked, waitTimeInMs = data.waitTimeInMs, timestamp = data.timestamp;
725
232
  start = Date.now();
@@ -727,7 +234,7 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
727
234
  data: data
728
235
  });
729
236
  if (!(isLocked && waitTimeInMs)) {
730
- _context7.next = 8;
237
+ _context3.next = 8;
731
238
  break;
732
239
  }
733
240
  _this.isNamespaceLocked = true;
@@ -743,195 +250,132 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
743
250
  });
744
251
  _this.isNamespaceLocked = false;
745
252
  }, waitTimeInMs);
746
- return _context7.abrupt("return");
253
+ return _context3.abrupt("return");
747
254
  case 8:
748
255
  _this.isNamespaceLocked = false;
749
256
  logger("The page lock has expired");
750
257
  case 10:
751
258
  case "end":
752
- return _context7.stop();
259
+ return _context3.stop();
753
260
  }
754
261
  }
755
- }, _callee7);
262
+ }, _callee3);
756
263
  }));
757
- return function (_x2) {
758
- return _ref17.apply(this, arguments);
264
+ return function (_x) {
265
+ return _ref8.apply(this, arguments);
759
266
  };
760
267
  }());
268
+ _defineProperty(_assertThisInitialized(_this), "clearTimers", function () {
269
+ clearTimeout(_this.presenceUpdateTimeout);
270
+ _this.participantsService.clearTimers();
271
+ });
761
272
  _this.config = config;
762
- _this.analyticsHelper = new AnalyticsHelper(_this.config.documentAri, config.analyticsClient);
273
+ _this.analyticsHelper = new AnalyticsHelper(_this.config.documentAri, _this.config.analyticsClient, _this.config.getAnalyticsWebClient);
763
274
  _this.channel = new Channel(config, _this.analyticsHelper);
764
275
  _this.isChannelInitialized = false;
276
+ _this.initialDraft = _this.config.initialDraft;
277
+ _this.isProviderInitialized = false;
278
+ _this.participantsService = new ParticipantsService(_this.analyticsHelper);
279
+ _this.metadataService = new MetadataService(_this.emitCallback, _this.channel.sendMetadata);
280
+ _this.documentService = new DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
281
+ return _this.userId;
282
+ }, _this.onErrorHandled, _this.metadataService);
765
283
  return _this;
766
284
  }
767
285
  _createClass(Provider, [{
768
286
  key: "initialize",
769
287
  value:
770
288
  /**
771
- * Called by collab plugin in editor when it's ready to
772
- * initialize a collab session.
289
+ * Initialisation logic, called by Jira with a dummy getState function, deprecated in favour of the setup method which allows more configuration
290
+ * @param {Function} getState Function that returns the editor state, used to retrieve collab-edit properties and to interact with prosemirror-collab
291
+ * @throws {ProviderInitialisationError} Something went wrong during provider initialisation
292
+ * @deprecated Use setup method instead
773
293
  */
774
294
  function initialize(getState) {
775
295
  return this.setup({
776
296
  getState: getState
777
297
  });
778
298
  }
299
+
300
+ /**
301
+ * Initialisation logic, called by the editor in the collab-edit plugin
302
+ * @param {Object} parameters ...
303
+ * @param {Function} parameters.getState Function that returns the editor state, used to retrieve collab-edit properties and to interact with prosemirror-collab
304
+ * @param {SyncUpErrorFunction} parameters.onSyncUpError (Optional) Function that gets called when the sync of steps fails after retrying 30 times, used by Editor to log to analytics
305
+ * @throws {ProviderInitialisationError} Something went wrong during provider initialisation
306
+ */
779
307
  }, {
780
308
  key: "setup",
781
- value: function setup(_ref18) {
782
- var getState = _ref18.getState,
783
- onSyncUpError = _ref18.onSyncUpError;
309
+ value: function setup(_ref9) {
310
+ var getState = _ref9.getState,
311
+ onSyncUpError = _ref9.onSyncUpError;
784
312
  try {
785
- this.getState = getState;
786
- this.onSyncUpError = onSyncUpError || noop;
787
- this.clientId = getState().plugins.find(function (p) {
313
+ var collabPlugin = getState().plugins.find(function (p) {
788
314
  return p.key === 'collab$';
789
- }).spec.config.clientID;
315
+ });
316
+ if (collabPlugin === undefined) {
317
+ throw new ProviderInitialisationError('Collab provider attempted to initialise, but Editor state is missing collab plugin');
318
+ }
319
+ this.clientId = collabPlugin.spec.config.clientID;
320
+ this.documentService.setup({
321
+ getState: getState,
322
+ onSyncUpError: onSyncUpError,
323
+ clientId: this.clientId
324
+ });
790
325
  if (!this.isChannelInitialized) {
791
326
  this.initializeChannel();
792
327
  this.isChannelInitialized = true;
793
328
  }
794
329
  } catch (initError) {
795
- var _this$analyticsHelper29;
796
- (_this$analyticsHelper29 = this.analyticsHelper) === null || _this$analyticsHelper29 === void 0 ? void 0 : _this$analyticsHelper29.sendErrorEvent(initError, 'Error while initialising the provider');
330
+ var _this$analyticsHelper8;
331
+ (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(initError, 'Error while initialising the provider');
797
332
  // Throw error so consumers are aware the initialisation failed when initialising themselves
798
- throw initError;
333
+ throw new ProviderInitialisationError('Provider initialisation error', initError);
799
334
  }
800
335
  return this;
801
336
  }
802
337
 
803
338
  /**
804
- * We can use this function to throttle/delay
805
- * Any send steps operation
806
- *
807
- * The getState function will return the current EditorState
808
- * from the EditorView.
809
- */
810
- }, {
811
- key: "sendStepsFromCurrentState",
812
- value: function sendStepsFromCurrentState() {
813
- var _this$getState4;
814
- var state = (_this$getState4 = this.getState) === null || _this$getState4 === void 0 ? void 0 : _this$getState4.call(this);
815
- if (!state) {
816
- return;
817
- }
818
- this.send(null, null, state);
819
- }
820
-
821
- /**
822
- * Send steps from transaction to other participants
823
- * It needs the superfluous arguments because we keep the interface of the send API the same as the Synchrony plugin
339
+ * Send steps from transaction to NCS (and as a consequence to other participants), called from the collab-edit plugin in the editor
340
+ * @param {Transaction} _tr Deprecated, included to keep API consistent with Synchrony provider
341
+ * @param {EditorState} _oldState Deprecated, included to keep API consistent with Synchrony provider
342
+ * @param {EditorState} newState The editor state after applying the transaction
343
+ * @throws {SendTransactionError} Something went wrong while sending the steps for this transaction
824
344
  */
825
345
  }, {
826
346
  key: "send",
827
347
  value: function send(_tr, _oldState, newState) {
828
- var unconfirmedStepsData = sendableSteps(newState);
829
- var version = getVersion(newState);
830
-
831
- // Don't send any steps before we're ready.
832
- if (!unconfirmedStepsData) {
833
- return;
834
- }
835
- // Don't send steps while the document is locked (eg. when restoring the document)
836
- if (this.isNamespaceLocked) {
837
- logger('The document is temporary locked');
838
- return;
839
- }
840
- var unconfirmedSteps = unconfirmedStepsData.steps;
841
- if (!(unconfirmedSteps !== null && unconfirmedSteps !== void 0 && unconfirmedSteps.length)) {
842
- return;
843
- }
844
-
845
- // Avoid reference issues using a
846
- // method outside of the provider
847
- // scope
848
- throttledCommitStep({
849
- channel: this.channel,
850
- userId: this.userId,
851
- clientId: this.clientId,
852
- steps: unconfirmedSteps,
853
- version: version,
854
- onStepsAdded: this.onStepsAdded.bind(this),
855
- onErrorHandled: this.onErrorHandled.bind(this),
856
- analyticsHelper: this.analyticsHelper
857
- });
858
- }
859
-
860
- // Triggered when page recovery has emitted an 'init' event on a page client is currently connected to.
861
- }, {
862
- key: "queueSteps",
863
- value: function queueSteps(data) {
864
- logger("Queueing data for version \"".concat(data.version, "\"."));
865
- var orderedQueue = [].concat(_toConsumableArray(this.queue), [data]).sort(function (a, b) {
866
- return a.version > b.version ? 1 : -1;
867
- });
868
- this.queue = orderedQueue;
869
- }
870
- }, {
871
- key: "processQueue",
872
- value: function processQueue() {
873
- if (this.pauseQueue) {
874
- logger("Queue is paused. Aborting.");
875
- return;
876
- }
877
- logger("Looking for processable data.");
878
- if (this.queue.length > 0) {
879
- var firstItem = this.queue.shift();
880
- var currentVersion = this.getCurrentPmVersion();
881
- var expectedVersion = currentVersion + firstItem.steps.length;
882
- if (firstItem.version === expectedVersion) {
883
- logger("Applying data from queue!");
884
- this.processSteps(firstItem);
885
- // recur
886
- this.processQueue();
887
- }
888
- }
889
- }
890
- }, {
891
- key: "processSteps",
892
- value: function processSteps(data) {
893
- var _this5 = this;
894
- var version = data.version,
895
- steps = data.steps;
896
- logger("Processing data. Version \"".concat(version, "\"."));
897
- if (steps !== null && steps !== void 0 && steps.length) {
898
- try {
899
- var clientIds = steps.map(function (_ref19) {
900
- var clientId = _ref19.clientId;
901
- return clientId;
902
- });
903
- this.emit('data', {
904
- json: steps,
905
- version: version,
906
- userIds: clientIds
907
- });
908
- // If steps can apply to local editor successfully, no need to accumulate the error counter.
909
- this.stepRejectCounter = 0;
910
- this.emitTelepointersFromSteps(steps);
911
-
912
- // Resend local steps if none of the received steps originated with us!
913
- if (clientIds.indexOf(this.clientId) === -1) {
914
- setTimeout(function () {
915
- return _this5.sendStepsFromCurrentState();
916
- }, 100);
917
- }
918
- } catch (error) {
919
- var _this$analyticsHelper30;
920
- logger("Processing steps failed with error: ".concat(error, ". Triggering catch up call."));
921
- (_this$analyticsHelper30 = this.analyticsHelper) === null || _this$analyticsHelper30 === void 0 ? void 0 : _this$analyticsHelper30.sendErrorEvent(error, 'Error while processing steps');
922
- this.throttledCatchup();
348
+ try {
349
+ // Don't send steps while the document is locked (eg. when restoring the document)
350
+ if (this.isNamespaceLocked) {
351
+ logger('The document is temporary locked');
352
+ return;
923
353
  }
354
+ this.documentService.send(_tr, _oldState, newState);
355
+ } catch (error) {
356
+ var _this$analyticsHelper9;
357
+ (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(error, 'Error while sending steps for a transaction');
358
+ throw new SendTransactionError('Error while sending steps for a transaction', error);
924
359
  }
925
360
  }
926
361
 
927
362
  /**
928
- * Send messages, such as telepointers, to other participants.
363
+ * @param {InternalError} error The error to handle
929
364
  */
930
365
  }, {
931
366
  key: "sendMessage",
932
- value: function sendMessage(data) {
933
- if ((data === null || data === void 0 ? void 0 : data.type) === 'telepointer') {
934
- try {
367
+ value:
368
+ /**
369
+ * Send messages, such as telepointers, to NCS and other participants. Only used for telepointer data (text and node selections) in the editor and JWM. JWM does some weird serialisation stuff on the node selections.
370
+ * Silently fails if an error occurs, since Presence isn't a critical functionality and self-restores over time.
371
+ * @param {CollabEventTelepointerData} data Data you want to send to NCS / the other participants
372
+ * @param {string} data.type Can only be 'telepointer' for now, we don't support anything else yet
373
+ * @param {CollabSendableSelection} data.selection Object representing the selected element
374
+ * @param {string} data.sessionId Identifier identifying the session
375
+ */
376
+ function sendMessage(data) {
377
+ try {
378
+ if ((data === null || data === void 0 ? void 0 : data.type) === 'telepointer') {
935
379
  var payload = {
936
380
  userId: this.userId,
937
381
  sessionId: this.sessionId,
@@ -940,87 +384,155 @@ export var Provider = /*#__PURE__*/function (_Emitter) {
940
384
  };
941
385
  var callback = telepointerCallback(this.config.documentAri);
942
386
  this.channel.broadcast('participant:telepointer', payload, callback);
943
- } catch (error) {
944
- var _this$analyticsHelper31;
945
- // We don't want to throw errors for Presence features as they tend to self-restore
946
- (_this$analyticsHelper31 = this.analyticsHelper) === null || _this$analyticsHelper31 === void 0 ? void 0 : _this$analyticsHelper31.sendErrorEvent(error, 'Error while sending message - telepointer');
947
387
  }
948
- }
949
- }
950
- }, {
951
- key: "emitTelepointersFromSteps",
952
- value: function emitTelepointersFromSteps(steps) {
953
- var _this6 = this;
954
- try {
955
- steps.forEach(function (step) {
956
- var event = telepointersFromStep(_this6.participants, step);
957
- if (event) {
958
- _this6.emit('telepointer', event);
959
- }
960
- });
961
388
  } catch (error) {
962
- var _this$analyticsHelper32;
389
+ var _this$analyticsHelper10;
963
390
  // We don't want to throw errors for Presence features as they tend to self-restore
964
- (_this$analyticsHelper32 = this.analyticsHelper) === null || _this$analyticsHelper32 === void 0 ? void 0 : _this$analyticsHelper32.sendErrorEvent(error, 'Error while emitting telepointers from steps');
391
+ (_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(error, 'Error while sending message - telepointer');
965
392
  }
966
393
  }
967
394
 
395
+ /**
396
+ * Called when a participant joins the session.
397
+ *
398
+ * We keep track of participants internally in this class, and emit the `presence` event to update
399
+ * the active avatars in the editor.
400
+ * This method will be triggered from backend to notify all participants to exchange presence
401
+ */
402
+
403
+ /**
404
+ * Called when a participant leaves the session.
405
+ *
406
+ * We emit the `presence` event to update the active avatars in the editor.
407
+ */
408
+
409
+ /**
410
+ * Called when we receive an update event from another participant.
411
+ */
412
+
413
+ /**
414
+ * Called when we receive a telepointer update from another
415
+ * participant.
416
+ */
417
+
968
418
  // Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
969
419
  }, {
970
420
  key: "destroy",
971
- value: function destroy() {
972
- return this.disconnect();
421
+ value:
422
+ /**
423
+ * "Destroy" the provider, disconnect it's connection to the back-end service and unsubscribe all event listeners on the provider.
424
+ * Used by Jira products (JWM, JPD) to disable the provider
425
+ * @throws {DestroyError} Something went wrong while shutting down the collab provider
426
+ */
427
+ function destroy() {
428
+ return this.unsubscribeAll();
973
429
  }
430
+
431
+ /**
432
+ * Disconnect the provider, disconnect it's connection to the back-end service and unsubscribe all event listeners on the provider.
433
+ * Used by Confluence to disable the provider when a user doesn't have access to a resource.
434
+ * @deprecated use destroy instead, it does the same thing
435
+ * @throws {DestroyError} Something went wrong while shutting down the collab provider
436
+ */
974
437
  }, {
975
438
  key: "disconnect",
976
439
  value: function disconnect() {
977
440
  return this.unsubscribeAll();
978
441
  }
442
+
443
+ /**
444
+ * Disconnect the provider's connection to the back-end service and unsubscribe from all events emitted by this provider. Kept to keep roughly aligned to Synchrony API, which you need to call for each event.
445
+ * @deprecated use destroy instead, it does the same thing
446
+ * @throws {DestroyError} Something went wrong while shutting down the collab provider
447
+ */
448
+ }, {
449
+ key: "unsubscribeAll",
450
+ value: function unsubscribeAll() {
451
+ try {
452
+ _get(_getPrototypeOf(Provider.prototype), "unsubscribeAll", this).call(this);
453
+ this.channel.disconnect();
454
+ } catch (error) {
455
+ var _this$analyticsHelper11;
456
+ (_this$analyticsHelper11 = this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while shutting down the collab provider');
457
+ throw new DestroyError('Error while shutting down the collab provider', error);
458
+ }
459
+ this.clearTimers();
460
+ return this;
461
+ }
462
+
463
+ /**
464
+ * Update the title of the document in the collab provider and optionally broadcast it to other participants and NCS
465
+ * @param {string} title Title you want to set on the document
466
+ * @param {boolean} broadcast (Optional) Flag indicating whether you want to broadcast the title change to the other participants, always true for now (otherwise we would lose title changes)
467
+ * @throws {SetTitleError} Something went wrong while setting the title
468
+ */
979
469
  }, {
980
470
  key: "setTitle",
981
471
  value: function setTitle(title, broadcast) {
982
- if (broadcast) {
983
- this.channel.sendMetadata({
984
- title: title
985
- });
472
+ try {
473
+ this.metadataService.setTitle(title, broadcast);
474
+ } catch (error) {
475
+ var _this$analyticsHelper12;
476
+ (_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while setting title');
477
+ throw new SetTitleError('Error while setting title', error);
986
478
  }
987
- Object.assign(this.metadata, {
988
- title: title
989
- });
990
479
  }
480
+
481
+ /**
482
+ * Set editor width, not used any more
483
+ * @deprecated use setMetadata instead, it does the same thing
484
+ * @param {string} editorWidth string? indicating the editor width
485
+ * @param {boolean} broadcast (Optional) Flag indicating whether you want to broadcast the editor width change
486
+ * @throws {SetEditorWidthError} Something went wrong while setting the editor width
487
+ */
991
488
  }, {
992
489
  key: "setEditorWidth",
993
490
  value: function setEditorWidth(editorWidth, broadcast) {
994
- if (broadcast) {
995
- this.channel.sendMetadata({
996
- editorWidth: editorWidth
997
- });
491
+ try {
492
+ this.metadataService.setEditorWidth(editorWidth, broadcast);
493
+ } catch (error) {
494
+ var _this$analyticsHelper13;
495
+ (_this$analyticsHelper13 = this.analyticsHelper) === null || _this$analyticsHelper13 === void 0 ? void 0 : _this$analyticsHelper13.sendErrorEvent(error, 'Error while setting editor width');
496
+ throw new SetEditorWidthError('Error while setting editor width', error);
998
497
  }
999
- Object.assign(this.metadata, {
1000
- editorWidth: editorWidth
1001
- });
1002
498
  }
499
+
500
+ /**
501
+ * Set the editor width and title and distribute it to all participants. Used by Confluence
502
+ * @param {Metadata} metadata The metadata you want to update
503
+ * @throws {ExampleError} Something went wrong while setting the metadata
504
+ */
1003
505
  }, {
1004
506
  key: "setMetadata",
1005
507
  value: function setMetadata(metadata) {
1006
- this.channel.sendMetadata(metadata);
1007
- Object.assign(this.metadata, metadata);
508
+ try {
509
+ this.metadataService.setMetadata(metadata);
510
+ } catch (error) {
511
+ var _this$analyticsHelper14;
512
+ (_this$analyticsHelper14 = this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendErrorEvent(error, 'Error while setting metadata');
513
+ throw new SetMetadataError('Error while setting metadata', error);
514
+ }
1008
515
  }
1009
- }, {
1010
- key: "unsubscribeAll",
1011
- value:
516
+
1012
517
  /**
1013
- * Unsubscribe from all events emitted by this provider.
518
+ * Return the ADF version of the current draft document, together with it's title and the current step version.
519
+ * 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.
520
+ * @throws {GetCurrentStateError} Something went wrong while returning the current state
521
+ */
522
+
523
+ /**
524
+ * Return the final acknowledged (by NCS) ADF version of the current draft document, together with it's title and the current step version.
525
+ * Used when returning the document to Confluence on publish.
526
+ * @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
1014
527
  */
1015
- function unsubscribeAll() {
1016
- _get(_getPrototypeOf(Provider.prototype), "unsubscribeAll", this).call(this);
1017
- this.channel.disconnect();
1018
- return this;
1019
- }
1020
528
 
1021
529
  /**
1022
530
  * ESS-2916 namespace status event- lock/unlock
1023
531
  */
532
+
533
+ /**
534
+ * Used when the provider is disconnected or destroyed to prevent perpetual timers from continuously running
535
+ */
1024
536
  }]);
1025
537
  return Provider;
1026
538
  }(Emitter);