@atlaskit/collab-provider 8.8.1 → 8.9.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 (83) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/analytics/analytics-helper.js +21 -12
  3. package/dist/cjs/channel.js +5 -3
  4. package/dist/cjs/document/document-service.js +1 -1
  5. package/dist/cjs/errors/error-code-mapper.js +9 -2
  6. package/dist/cjs/namespace/namespace-service.js +77 -0
  7. package/dist/cjs/participants/participants-helper.js +2 -0
  8. package/dist/cjs/participants/participants-service.js +94 -30
  9. package/dist/cjs/provider/index.js +91 -173
  10. package/dist/cjs/version-wrapper.js +1 -1
  11. package/dist/cjs/version.json +1 -1
  12. package/dist/es2019/analytics/analytics-helper.js +21 -12
  13. package/dist/es2019/channel.js +5 -3
  14. package/dist/es2019/document/document-service.js +1 -1
  15. package/dist/es2019/errors/error-code-mapper.js +9 -2
  16. package/dist/es2019/namespace/namespace-service.js +48 -0
  17. package/dist/es2019/participants/participants-helper.js +2 -0
  18. package/dist/es2019/participants/participants-service.js +88 -30
  19. package/dist/es2019/provider/index.js +82 -145
  20. package/dist/es2019/version-wrapper.js +1 -1
  21. package/dist/es2019/version.json +1 -1
  22. package/dist/esm/analytics/analytics-helper.js +21 -12
  23. package/dist/esm/channel.js +5 -3
  24. package/dist/esm/document/document-service.js +1 -1
  25. package/dist/esm/errors/error-code-mapper.js +9 -2
  26. package/dist/esm/namespace/namespace-service.js +69 -0
  27. package/dist/esm/participants/participants-helper.js +2 -0
  28. package/dist/esm/participants/participants-service.js +94 -30
  29. package/dist/esm/provider/index.js +91 -173
  30. package/dist/esm/version-wrapper.js +1 -1
  31. package/dist/esm/version.json +1 -1
  32. package/dist/types/channel.d.ts +1 -1
  33. package/dist/types/errors/error-types.d.ts +37 -37
  34. package/dist/types/feature-flags/types.d.ts +4 -4
  35. package/dist/types/helpers/const.d.ts +19 -19
  36. package/dist/types/helpers/utils.d.ts +2 -2
  37. package/dist/types/metadata/metadata-service.d.ts +1 -1
  38. package/dist/types/namespace/namespace-service.d.ts +14 -0
  39. package/dist/types/participants/participants-helper.d.ts +5 -7
  40. package/dist/types/participants/participants-service.d.ts +40 -16
  41. package/dist/types/provider/commit-step.d.ts +2 -2
  42. package/dist/types/provider/index.d.ts +21 -37
  43. package/dist/types/types.d.ts +28 -28
  44. package/dist/{types-ts4.0 → types-ts4.5}/channel.d.ts +1 -1
  45. package/dist/{types-ts4.0 → types-ts4.5}/errors/error-types.d.ts +37 -37
  46. package/dist/types-ts4.5/feature-flags/types.d.ts +13 -0
  47. package/dist/{types-ts4.0 → types-ts4.5}/helpers/const.d.ts +19 -19
  48. package/dist/{types-ts4.0 → types-ts4.5}/helpers/utils.d.ts +2 -2
  49. package/dist/{types-ts4.0 → types-ts4.5}/metadata/metadata-service.d.ts +1 -1
  50. package/dist/types-ts4.5/namespace/namespace-service.d.ts +14 -0
  51. package/dist/types-ts4.5/participants/participants-helper.d.ts +12 -0
  52. package/dist/types-ts4.5/participants/participants-service.d.ts +94 -0
  53. package/dist/{types-ts4.0 → types-ts4.5}/provider/commit-step.d.ts +2 -2
  54. package/dist/{types-ts4.0 → types-ts4.5}/provider/index.d.ts +21 -37
  55. package/dist/{types-ts4.0 → types-ts4.5}/types.d.ts +28 -28
  56. package/package.json +13 -5
  57. package/report.api.md +4 -2
  58. package/socket-io-provider/package.json +2 -2
  59. package/types/package.json +2 -2
  60. package/version-wrapper/package.json +2 -2
  61. package/dist/types-ts4.0/feature-flags/types.d.ts +0 -13
  62. package/dist/types-ts4.0/participants/participants-helper.d.ts +0 -14
  63. package/dist/types-ts4.0/participants/participants-service.d.ts +0 -70
  64. /package/dist/{types-ts4.0 → types-ts4.5}/analytics/analytics-helper.d.ts +0 -0
  65. /package/dist/{types-ts4.0 → types-ts4.5}/analytics/performance.d.ts +0 -0
  66. /package/dist/{types-ts4.0 → types-ts4.5}/analytics/ufo.d.ts +0 -0
  67. /package/dist/{types-ts4.0 → types-ts4.5}/config.d.ts +0 -0
  68. /package/dist/{types-ts4.0 → types-ts4.5}/connectivity/network.d.ts +0 -0
  69. /package/dist/{types-ts4.0 → types-ts4.5}/connectivity/reconnect-helper.d.ts +0 -0
  70. /package/dist/{types-ts4.0 → types-ts4.5}/connectivity/singleton.d.ts +0 -0
  71. /package/dist/{types-ts4.0 → types-ts4.5}/disconnected-reason-mapper.d.ts +0 -0
  72. /package/dist/{types-ts4.0 → types-ts4.5}/document/catchup.d.ts +0 -0
  73. /package/dist/{types-ts4.0 → types-ts4.5}/document/document-service.d.ts +0 -0
  74. /package/dist/{types-ts4.0 → types-ts4.5}/document/step-queue-state.d.ts +0 -0
  75. /package/dist/{types-ts4.0 → types-ts4.5}/emitter.d.ts +0 -0
  76. /package/dist/{types-ts4.0 → types-ts4.5}/errors/error-code-mapper.d.ts +0 -0
  77. /package/dist/{types-ts4.0 → types-ts4.5}/feature-flags/__test__/index.unit.d.ts +0 -0
  78. /package/dist/{types-ts4.0 → types-ts4.5}/feature-flags/index.d.ts +0 -0
  79. /package/dist/{types-ts4.0 → types-ts4.5}/index.d.ts +0 -0
  80. /package/dist/{types-ts4.0 → types-ts4.5}/participants/participants-state.d.ts +0 -0
  81. /package/dist/{types-ts4.0 → types-ts4.5}/participants/telepointers-helper.d.ts +0 -0
  82. /package/dist/{types-ts4.0 → types-ts4.5}/socket-io-provider.d.ts +0 -0
  83. /package/dist/{types-ts4.0 → types-ts4.5}/version-wrapper.d.ts +0 -0
@@ -20,16 +20,15 @@ var _channel = require("../channel");
20
20
  var _utils = require("../helpers/utils");
21
21
  var _analyticsHelper = _interopRequireDefault(require("../analytics/analytics-helper"));
22
22
  var _telepointersHelper = require("../participants/telepointers-helper");
23
- var _participantsService = require("../participants/participants-service");
24
23
  var _errorTypes = require("../errors/error-types");
25
24
  var _metadataService = require("../metadata/metadata-service");
26
25
  var _documentService = require("../document/document-service");
26
+ var _namespaceService = require("../namespace/namespace-service");
27
+ var _participantsService = require("../participants/participants-service");
27
28
  var _errorCodeMapper = require("../errors/error-code-mapper");
28
29
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2.default)(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2.default)(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2.default)(this, result); }; }
29
30
  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; } }
30
31
  var logger = (0, _utils.createLogger)('Provider', 'black');
31
- var SEND_PRESENCE_INTERVAL = 150 * 1000; // 150 seconds
32
-
33
32
  var OUT_OF_SYNC_PERIOD = 3 * 1000; // 3 seconds
34
33
 
35
34
  var MAX_STEP_REJECTED_ERROR = 15;
@@ -43,10 +42,25 @@ var Provider = /*#__PURE__*/function (_Emitter) {
43
42
  _this = _super.call(this);
44
43
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isChannelInitialized", false);
45
44
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isProviderInitialized", false);
46
- // To keep track of the namespace event changes from the server.
47
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isNamespaceLocked", false);
45
+ // isPreinitializating acts as a feature flag to determine when the provider has been initialized early
46
+ // and also contains the initial draft
47
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isPreinitializing", false);
48
+ /**
49
+ * Wrapper for this.emit, it binds scope for callbacks and waits for initialising of the editor before emitting events.
50
+ * Waiting for the collab provider to become connected to the editor ensures the editor doesn't miss any events.
51
+ * @param evt - Event name to emit to subscribers
52
+ * @param data - Event data to emit to subscribers
53
+ */
48
54
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "emitCallback", function (evt, data) {
49
- return _this.emit(evt, data);
55
+ // When the provider is initialized early, we want the editor state promise to resolve before emitting events
56
+ // to ensure that it is ready to listen to the events fired by NCS
57
+ if (_this.isPreinitializing) {
58
+ _this.getStatePromise.then(function () {
59
+ return _this.emit(evt, data);
60
+ });
61
+ } else {
62
+ _this.emit(evt, data);
63
+ }
50
64
  });
51
65
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "initializeChannel", function () {
52
66
  _this.emit('connecting', {
@@ -57,7 +71,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
57
71
  var sid = _ref.sid,
58
72
  initialized = _ref.initialized;
59
73
  _this.sessionId = sid;
60
- _this.emit('connected', {
74
+ _this.emitCallback('connected', {
61
75
  sid: sid,
62
76
  initial: !initialized
63
77
  });
@@ -83,7 +97,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
83
97
  Date.now() - _this.disconnectedAt >= OUT_OF_SYNC_PERIOD) {
84
98
  _this.documentService.throttledCatchup();
85
99
  }
86
- _this.startInactiveRemover();
100
+ _this.participantsService.startInactiveRemover(_this.sessionId);
87
101
  _this.disconnectedAt = undefined;
88
102
  }).on('init', function (_ref2) {
89
103
  var doc = _ref2.doc,
@@ -96,7 +110,10 @@ var Provider = /*#__PURE__*/function (_Emitter) {
96
110
  metadata: metadata
97
111
  });
98
112
  _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((0, _assertThisInitialized2.default)(_this))).on('presence:joined', _this.onPresenceJoined.bind((0, _assertThisInitialized2.default)(_this))).on('presence', _this.onPresence.bind((0, _assertThisInitialized2.default)(_this))).on('participant:left', _this.onParticipantLeft.bind((0, _assertThisInitialized2.default)(_this))).on('participant:updated', _this.onParticipantUpdated.bind((0, _assertThisInitialized2.default)(_this))).on('disconnect', _this.onDisconnected.bind((0, _assertThisInitialized2.default)(_this))).on('error', _this.onErrorHandled).on('status', _this.onNamespaceStatusChanged.bind((0, _assertThisInitialized2.default)(_this))).connect(shouldInitialize);
113
+ _this.isProviderInitialized = true;
114
+ }).on('restore', _this.documentService.onRestore).on('steps:added', _this.documentService.onStepsAdded).on('metadata:changed', _this.metadataService.onMetadataChanged).on('participant:telepointer', function (payload) {
115
+ return _this.participantsService.onParticipantTelepointer(payload, _this.sessionId);
116
+ }).on('presence:joined', _this.participantsService.onPresenceJoined).on('presence', _this.participantsService.onPresence).on('participant:left', _this.participantsService.onParticipantLeft).on('participant:updated', _this.participantsService.onParticipantUpdated).on('disconnect', _this.onDisconnected.bind((0, _assertThisInitialized2.default)(_this))).on('error', _this.onErrorHandled).on('status', _this.namespaceService.onNamespaceStatusChanged).connect(shouldInitialize);
100
117
  });
101
118
  /**
102
119
  * @param {InternalError} error The error to handle
@@ -116,90 +133,15 @@ var Provider = /*#__PURE__*/function (_Emitter) {
116
133
  if (mappedError) {
117
134
  var _this$analyticsHelper2;
118
135
  (_this$analyticsHelper2 = _this.analyticsHelper) === null || _this$analyticsHelper2 === void 0 ? void 0 : _this$analyticsHelper2.sendErrorEvent(mappedError, 'Error emitted');
119
- _this.emit('error', mappedError);
136
+ _this.emitCallback('error', mappedError);
120
137
  }
121
138
  }
122
139
  });
123
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "sendPresence", function () {
124
- try {
125
- if (_this.presenceUpdateTimeout) {
126
- clearTimeout(_this.presenceUpdateTimeout);
127
- }
128
- _this.channel.broadcast('participant:updated', {
129
- sessionId: _this.sessionId,
130
- userId: _this.userId,
131
- clientId: _this.clientId
132
- });
133
- _this.presenceUpdateTimeout = window.setTimeout(function () {
134
- return _this.sendPresence();
135
- }, SEND_PRESENCE_INTERVAL);
136
- } catch (error) {
137
- var _this$analyticsHelper3;
138
- // We don't want to throw errors for Presence features as they tend to self-restore
139
- (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(error, 'Error while sending presence');
140
- }
141
- });
142
- /**
143
- * Called when a participant joins the session.
144
- *
145
- * We keep track of participants internally in this class, and emit the `presence` event to update
146
- * the active avatars in the editor.
147
- * This method will be triggered from backend to notify all participants to exchange presence
148
- */
149
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresenceJoined", function (_ref3) {
150
- var sessionId = _ref3.sessionId;
151
- try {
152
- logger('Participant joined with session: ', sessionId);
153
- // This expose existing users to the newly joined user
154
- _this.sendPresence();
155
- } catch (error) {
156
- var _this$analyticsHelper4;
157
- // We don't want to throw errors for Presence features as they tend to self-restore
158
- (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(error, 'Error while joining presence');
159
- }
160
- });
161
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onPresence", function (_ref4) {
162
- var userId = _ref4.userId;
163
- try {
164
- logger('onPresence userId: ', userId);
165
- _this.userId = userId;
166
- _this.sendPresence();
167
- _this.channel.sendPresenceJoined();
168
- } catch (error) {
169
- var _this$analyticsHelper5;
170
- // We don't want to throw errors for Presence features as they tend to self-restore
171
- (_this$analyticsHelper5 = _this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(error, 'Error while receiving presence');
172
- }
173
- });
174
- /**
175
- * Called when a participant leaves the session.
176
- *
177
- * We emit the `presence` event to update the active avatars in the editor.
178
- */
179
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantLeft", function (data) {
180
- return _this.participantsService.participantLeft(data, _this.emitCallback);
181
- });
182
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "startInactiveRemover", function () {
183
- return _this.participantsService.removeInactiveParticipants(_this.sessionId, _this.emitCallback);
184
- });
185
- /**
186
- * Called when we receive an update event from another participant.
187
- */
188
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantUpdated", function (data) {
189
- return _this.participantsService.updateParticipant(data, _this.config.getUser, _this.emitCallback);
190
- });
191
- /**
192
- * Called when we receive a telepointer update from another
193
- * participant.
194
- */
195
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onParticipantTelepointer", function (data) {
196
- return _this.participantsService.participantTelepointer(data, _this.sessionId, _this.config.getUser, _this.emitCallback);
197
- });
198
140
  // Note: this gets triggered on page reload for Firefox (not other browsers) because of closeOnBeforeunload: false
199
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onDisconnected", function (_ref5) {
200
- var reason = _ref5.reason;
141
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onDisconnected", function (_ref3) {
142
+ var reason = _ref3.reason;
201
143
  _this.disconnectedAt = Date.now();
202
- _this.participantsService.disconnect(reason, _this.sessionId, _this.emitCallback);
144
+ _this.participantsService.disconnect(reason, _this.sessionId);
203
145
  });
204
146
  /**
205
147
  * Returns the documents metadata
@@ -213,7 +155,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
213
155
  * @throws {GetCurrentStateError} Something went wrong while returning the current state
214
156
  */
215
157
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getCurrentState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
216
- var _this$analyticsHelper6;
158
+ var _this$analyticsHelper3;
217
159
  return _regenerator.default.wrap(function _callee$(_context) {
218
160
  while (1) switch (_context.prev = _context.next) {
219
161
  case 0:
@@ -222,7 +164,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
222
164
  case 4:
223
165
  _context.prev = 4;
224
166
  _context.t0 = _context["catch"](0);
225
- (_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');
167
+ (_this$analyticsHelper3 = _this.analyticsHelper) === null || _this$analyticsHelper3 === void 0 ? void 0 : _this$analyticsHelper3.sendErrorEvent(_context.t0, 'Error while returning ADF version of current draft document');
226
168
  throw new _errorTypes.GetCurrentStateError('Error while returning the current state of the draft document', _context.t0);
227
169
  case 8:
228
170
  case "end":
@@ -236,7 +178,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
236
178
  * @throws {GetFinalAcknowledgedStateError} Something went wrong while returning the acknowledged state
237
179
  */
238
180
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getFinalAcknowledgedState", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
239
- var _this$analyticsHelper7;
181
+ var _this$analyticsHelper4;
240
182
  return _regenerator.default.wrap(function _callee2$(_context2) {
241
183
  while (1) switch (_context2.prev = _context2.next) {
242
184
  case 0:
@@ -245,7 +187,7 @@ var Provider = /*#__PURE__*/function (_Emitter) {
245
187
  case 4:
246
188
  _context2.prev = 4;
247
189
  _context2.t0 = _context2["catch"](0);
248
- (_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');
190
+ (_this$analyticsHelper4 = _this.analyticsHelper) === null || _this$analyticsHelper4 === void 0 ? void 0 : _this$analyticsHelper4.sendErrorEvent(_context2.t0, 'Error while returning ADF version of the final draft document');
249
191
  throw new _errorTypes.GetFinalAcknowledgedStateError('Error while returning the final acknowledged state of the draft document', _context2.t0);
250
192
  case 8:
251
193
  case "end":
@@ -256,51 +198,6 @@ var Provider = /*#__PURE__*/function (_Emitter) {
256
198
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getUnconfirmedSteps", function () {
257
199
  return _this.documentService.getUnconfirmedSteps();
258
200
  });
259
- /**
260
- * ESS-2916 namespace status event- lock/unlock
261
- */
262
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "onNamespaceStatusChanged", /*#__PURE__*/function () {
263
- var _ref8 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(data) {
264
- var isLocked, waitTimeInMs, timestamp, start;
265
- return _regenerator.default.wrap(function _callee3$(_context3) {
266
- while (1) switch (_context3.prev = _context3.next) {
267
- case 0:
268
- isLocked = data.isLocked, waitTimeInMs = data.waitTimeInMs, timestamp = data.timestamp;
269
- start = Date.now();
270
- logger("Received a namespace status changed event ", {
271
- data: data
272
- });
273
- if (!(isLocked && waitTimeInMs)) {
274
- _context3.next = 8;
275
- break;
276
- }
277
- _this.isNamespaceLocked = true;
278
- logger("Received a namespace status change event ", {
279
- isLocked: isLocked
280
- });
281
-
282
- // To protect the collab editing process from locked out due to BE
283
- setTimeout(function () {
284
- logger("The namespace lock has expired", {
285
- waitTime: Date.now() - start,
286
- timestamp: timestamp
287
- });
288
- _this.isNamespaceLocked = false;
289
- }, waitTimeInMs);
290
- return _context3.abrupt("return");
291
- case 8:
292
- _this.isNamespaceLocked = false;
293
- logger("The page lock has expired");
294
- case 10:
295
- case "end":
296
- return _context3.stop();
297
- }
298
- }, _callee3);
299
- }));
300
- return function (_x) {
301
- return _ref8.apply(this, arguments);
302
- };
303
- }());
304
201
  /**
305
202
  * Used when the provider is disconnected or destroyed to prevent perpetual timers from continuously running
306
203
  */
@@ -314,11 +211,16 @@ var Provider = /*#__PURE__*/function (_Emitter) {
314
211
  _this.isChannelInitialized = false;
315
212
  _this.initialDraft = _this.config.initialDraft;
316
213
  _this.isProviderInitialized = false;
317
- _this.participantsService = new _participantsService.ParticipantsService(_this.analyticsHelper);
214
+ _this.isPreinitializing = false;
215
+ _this.participantsService = new _participantsService.ParticipantsService(_this.analyticsHelper, undefined, _this.emitCallback, _this.config.getUser, _this.channel.broadcast, _this.channel.sendPresenceJoined);
318
216
  _this.metadataService = new _metadataService.MetadataService(_this.emitCallback, _this.channel.sendMetadata);
319
217
  _this.documentService = new _documentService.DocumentService(_this.participantsService, _this.analyticsHelper, _this.channel.fetchCatchup, _this.emitCallback, _this.channel.broadcast, function () {
320
218
  return _this.userId;
321
219
  }, _this.onErrorHandled, _this.metadataService);
220
+ _this.getStatePromise = new Promise(function (resolve) {
221
+ _this.getStatePromiseResolve = resolve;
222
+ });
223
+ _this.namespaceService = new _namespaceService.NamespaceService();
322
224
  return _this;
323
225
  }
324
226
  (0, _createClass2.default)(Provider, [{
@@ -337,38 +239,54 @@ var Provider = /*#__PURE__*/function (_Emitter) {
337
239
  }
338
240
 
339
241
  /**
340
- * Initialisation logic, called by the editor in the collab-edit plugin
341
- * @param {Object} parameters ...
342
- * @param {Function} parameters.getState Function that returns the editor state, used to retrieve collab-edit properties and to interact with prosemirror-collab
343
- * @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
242
+ * Initialisation logic, called by the editor in the collab-edit plugin.
243
+ *
244
+ * When getState is nullish and a initialDraft is provided the collab provider is in a state of pre-initialization,
245
+ * the provider starts to enable the connection to NCS, but the provider will not emit any events until this function
246
+ * is called again with a getState function, indicating that the editor is loaded and ready to receive the emits.
247
+ *
248
+ * @param {Object} options ...
249
+ * @param {Function} options.getState Function that returns the editor state, used to retrieve collab-edit properties and to interact with prosemirror-collab
250
+ * @param {SyncUpErrorFunction} options.onSyncUpError (Optional) Function that gets called when the sync of steps fails after retrying 30 times, used by Editor to log to analytics
344
251
  * @throws {ProviderInitialisationError} Something went wrong during provider initialisation
345
252
  */
346
253
  }, {
347
254
  key: "setup",
348
- value: function setup(_ref9) {
349
- var getState = _ref9.getState,
350
- onSyncUpError = _ref9.onSyncUpError;
255
+ value: function setup(_ref6) {
256
+ var getState = _ref6.getState,
257
+ onSyncUpError = _ref6.onSyncUpError;
351
258
  this.checkForCookies();
352
259
  try {
353
- var collabPlugin = getState().plugins.find(function (p) {
354
- return p.key === 'collab$';
355
- });
356
- if (collabPlugin === undefined) {
357
- throw new _errorTypes.ProviderInitialisationError('Collab provider attempted to initialise, but Editor state is missing collab plugin');
260
+ // if setup is called with no state and the initial draft is already provided
261
+ // set a flag to mark early provider setup
262
+ if (!getState && this.initialDraft) {
263
+ this.isPreinitializing = true;
264
+ }
265
+ if (getState) {
266
+ // if provider has already been initialized earlier, resolve the state once it is available
267
+ if (this.isPreinitializing) {
268
+ this.getStatePromiseResolve();
269
+ }
270
+ var collabPlugin = getState().plugins.find(function (p) {
271
+ return p.key === 'collab$';
272
+ });
273
+ if (collabPlugin === undefined) {
274
+ throw new _errorTypes.ProviderInitialisationError('Collab provider attempted to initialise, but Editor state is missing collab plugin');
275
+ }
276
+ this.clientId = collabPlugin.spec.config.clientID;
277
+ this.documentService.setup({
278
+ getState: getState,
279
+ onSyncUpError: onSyncUpError,
280
+ clientId: this.clientId
281
+ });
358
282
  }
359
- this.clientId = collabPlugin.spec.config.clientID;
360
- this.documentService.setup({
361
- getState: getState,
362
- onSyncUpError: onSyncUpError,
363
- clientId: this.clientId
364
- });
365
283
  if (!this.isChannelInitialized) {
366
284
  this.initializeChannel();
367
285
  this.isChannelInitialized = true;
368
286
  }
369
287
  } catch (initError) {
370
- var _this$analyticsHelper8;
371
- (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(initError, 'Error while initialising the provider');
288
+ var _this$analyticsHelper5;
289
+ (_this$analyticsHelper5 = this.analyticsHelper) === null || _this$analyticsHelper5 === void 0 ? void 0 : _this$analyticsHelper5.sendErrorEvent(initError, 'Error while initialising the provider');
372
290
  // Throw error so consumers are aware the initialisation failed when initialising themselves
373
291
  throw new _errorTypes.ProviderInitialisationError('Provider initialisation error', initError);
374
292
  }
@@ -378,9 +296,9 @@ var Provider = /*#__PURE__*/function (_Emitter) {
378
296
  key: "checkForCookies",
379
297
  value: function checkForCookies() {
380
298
  if (!global.navigator.cookieEnabled) {
381
- var _this$analyticsHelper9;
299
+ var _this$analyticsHelper6;
382
300
  var initError = new _errorTypes.ProviderInitialisationError('Cookies are not enabled. Please enable cookies to use collaborative editing.');
383
- (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(initError, 'Error while initialising the provider - cookies disabled');
301
+ (_this$analyticsHelper6 = this.analyticsHelper) === null || _this$analyticsHelper6 === void 0 ? void 0 : _this$analyticsHelper6.sendErrorEvent(initError, 'Error while initialising the provider - cookies disabled');
384
302
  throw new _errorTypes.ProviderInitialisationError('Provider initialisation error - cookies disabled', initError);
385
303
  }
386
304
  }
@@ -397,14 +315,14 @@ var Provider = /*#__PURE__*/function (_Emitter) {
397
315
  value: function send(_tr, _oldState, newState) {
398
316
  try {
399
317
  // Don't send steps while the document is locked (eg. when restoring the document)
400
- if (this.isNamespaceLocked) {
318
+ if (this.namespaceService.getIsNamespaceLocked()) {
401
319
  logger('The document is temporary locked');
402
320
  return;
403
321
  }
404
322
  this.documentService.send(_tr, _oldState, newState);
405
323
  } catch (error) {
406
- var _this$analyticsHelper10;
407
- (_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(error, 'Error while sending steps for a transaction');
324
+ var _this$analyticsHelper7;
325
+ (_this$analyticsHelper7 = this.analyticsHelper) === null || _this$analyticsHelper7 === void 0 ? void 0 : _this$analyticsHelper7.sendErrorEvent(error, 'Error while sending steps for a transaction');
408
326
  throw new _errorTypes.SendTransactionError('Error while sending steps for a transaction', error);
409
327
  }
410
328
  }
@@ -432,9 +350,9 @@ var Provider = /*#__PURE__*/function (_Emitter) {
432
350
  this.channel.broadcast('participant:telepointer', payload, callback);
433
351
  }
434
352
  } catch (error) {
435
- var _this$analyticsHelper11;
353
+ var _this$analyticsHelper8;
436
354
  // We don't want to throw errors for Presence features as they tend to self-restore
437
- (_this$analyticsHelper11 = this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while sending message - telepointer');
355
+ (_this$analyticsHelper8 = this.analyticsHelper) === null || _this$analyticsHelper8 === void 0 ? void 0 : _this$analyticsHelper8.sendErrorEvent(error, 'Error while sending message - telepointer');
438
356
  }
439
357
  }
440
358
  }, {
@@ -473,8 +391,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
473
391
  (0, _get2.default)((0, _getPrototypeOf2.default)(Provider.prototype), "unsubscribeAll", this).call(this);
474
392
  this.channel.disconnect();
475
393
  } catch (error) {
476
- var _this$analyticsHelper12;
477
- (_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while shutting down the collab provider');
394
+ var _this$analyticsHelper9;
395
+ (_this$analyticsHelper9 = this.analyticsHelper) === null || _this$analyticsHelper9 === void 0 ? void 0 : _this$analyticsHelper9.sendErrorEvent(error, 'Error while shutting down the collab provider');
478
396
  throw new _errorTypes.DestroyError('Error while shutting down the collab provider', error);
479
397
  }
480
398
  this.clearTimers();
@@ -494,8 +412,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
494
412
  try {
495
413
  this.metadataService.setTitle(title, broadcast);
496
414
  } catch (error) {
497
- var _this$analyticsHelper13;
498
- (_this$analyticsHelper13 = this.analyticsHelper) === null || _this$analyticsHelper13 === void 0 ? void 0 : _this$analyticsHelper13.sendErrorEvent(error, 'Error while setting title');
415
+ var _this$analyticsHelper10;
416
+ (_this$analyticsHelper10 = this.analyticsHelper) === null || _this$analyticsHelper10 === void 0 ? void 0 : _this$analyticsHelper10.sendErrorEvent(error, 'Error while setting title');
499
417
  throw new _errorTypes.SetTitleError('Error while setting title', error);
500
418
  }
501
419
  }
@@ -513,8 +431,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
513
431
  try {
514
432
  this.metadataService.setEditorWidth(editorWidth, broadcast);
515
433
  } catch (error) {
516
- var _this$analyticsHelper14;
517
- (_this$analyticsHelper14 = this.analyticsHelper) === null || _this$analyticsHelper14 === void 0 ? void 0 : _this$analyticsHelper14.sendErrorEvent(error, 'Error while setting editor width');
434
+ var _this$analyticsHelper11;
435
+ (_this$analyticsHelper11 = this.analyticsHelper) === null || _this$analyticsHelper11 === void 0 ? void 0 : _this$analyticsHelper11.sendErrorEvent(error, 'Error while setting editor width');
518
436
  throw new _errorTypes.SetEditorWidthError('Error while setting editor width', error);
519
437
  }
520
438
  }
@@ -530,8 +448,8 @@ var Provider = /*#__PURE__*/function (_Emitter) {
530
448
  try {
531
449
  this.metadataService.setMetadata(metadata);
532
450
  } catch (error) {
533
- var _this$analyticsHelper15;
534
- (_this$analyticsHelper15 = this.analyticsHelper) === null || _this$analyticsHelper15 === void 0 ? void 0 : _this$analyticsHelper15.sendErrorEvent(error, 'Error while setting metadata');
451
+ var _this$analyticsHelper12;
452
+ (_this$analyticsHelper12 = this.analyticsHelper) === null || _this$analyticsHelper12 === void 0 ? void 0 : _this$analyticsHelper12.sendErrorEvent(error, 'Error while setting metadata');
535
453
  throw new _errorTypes.SetMetadataError('Error while setting metadata', error);
536
454
  }
537
455
  }
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.version = exports.nextMajorVersion = exports.name = void 0;
7
7
  var name = "@atlaskit/collab-provider";
8
8
  exports.name = name;
9
- var version = "8.8.1";
9
+ var version = "8.9.0";
10
10
  exports.version = version;
11
11
  var nextMajorVersion = function nextMajorVersion() {
12
12
  return [Number(version.split('.')[0]) + 1, 0, 0].join('.');
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/collab-provider",
3
- "version": "8.8.1",
3
+ "version": "8.9.0",
4
4
  "sideEffects": false
5
5
  }
@@ -29,18 +29,27 @@ const triggerAnalyticsEvent = (analyticsEvent, analyticsClient) => {
29
29
 
30
30
  if (analyticsEvent.eventAction === EVENT_ACTION.ERROR) {
31
31
  payload.nonPrivacySafeAttributes = analyticsEvent.nonPrivacySafeAttributes;
32
- }
33
-
34
- // Let the browser figure out
35
- // when it should send those events
36
- try {
37
- const requestIdleCallbackFunction = window.requestIdleCallback;
38
- const runItLater = typeof requestIdleCallbackFunction === 'function' ? requestIdleCallbackFunction : window.requestAnimationFrame;
39
- runItLater(() => {
40
- analyticsClient.sendOperationalEvent(payload);
41
- });
42
- } catch (error) {
43
- // silently fail for now https://product-fabric.atlassian.net/browse/ESS-3112
32
+ try {
33
+ const requestIdleCallbackFunction = window.requestIdleCallback;
34
+ const runItLater = typeof requestIdleCallbackFunction === 'function' ? requestIdleCallbackFunction : window.requestAnimationFrame;
35
+ runItLater(() => {
36
+ analyticsClient.sendTrackEvent(payload);
37
+ });
38
+ } catch (error) {
39
+ // silently fail for now https://product-fabric.atlassian.net/browse/ESS-3112
40
+ }
41
+ } else {
42
+ // Let the browser figure out
43
+ // when it should send those events
44
+ try {
45
+ const requestIdleCallbackFunction = window.requestIdleCallback;
46
+ const runItLater = typeof requestIdleCallbackFunction === 'function' ? requestIdleCallbackFunction : window.requestAnimationFrame;
47
+ runItLater(() => {
48
+ analyticsClient.sendOperationalEvent(payload);
49
+ });
50
+ } catch (error) {
51
+ // silently fail for now https://product-fabric.atlassian.net/browse/ESS-3112
52
+ }
44
53
  }
45
54
  };
46
55
  export default class AnalyticsHelper {
@@ -308,10 +308,13 @@ export class Channel extends Emitter {
308
308
  // save token locally
309
309
  this.setToken(token);
310
310
  authData.token = token;
311
+ } else {
312
+ this.unsetToken();
313
+ authData.token = undefined;
311
314
  }
312
315
  cb(authData);
313
316
  } catch (error) {
314
- var _err, _err$data, _err$data$meta;
317
+ var _data, _data$meta;
315
318
  // Pass the error back to the consumers so they can deal with exceptional cases themselves (eg. no permissions because the page was deleted)
316
319
  const authenticationError = {
317
320
  message: 'Insufficient editing permissions',
@@ -320,8 +323,7 @@ export class Channel extends Emitter {
320
323
  code: INTERNAL_ERROR_CODE.TOKEN_PERMISSION_ERROR,
321
324
  meta: {
322
325
  originalError: error,
323
- // @ts-expect-error we know the error structure passed in this hack
324
- reason: (_err = err) === null || _err === void 0 ? void 0 : (_err$data = _err.data) === null || _err$data === void 0 ? void 0 : (_err$data$meta = _err$data.meta) === null || _err$data$meta === void 0 ? void 0 : _err$data$meta.reason // Should always be 'RESOURCE_DELETED' Temporary, until Confluence Cloud removes their hack
326
+ reason: error === null || error === void 0 ? void 0 : (_data = error.data) === null || _data === void 0 ? void 0 : (_data$meta = _data.meta) === null || _data$meta === void 0 ? void 0 : _data$meta.reason // Should always be 'RESOURCE_DELETED' Temporary, until Confluence Cloud removes their hack
325
327
  // https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/browse/next/packages/native-collab/src/fetchCollabPermissionToken.ts#37
326
328
  }
327
329
  }
@@ -390,7 +390,7 @@ export class DocumentService {
390
390
  });
391
391
  // If steps can apply to local editor successfully, no need to accumulate the error counter.
392
392
  this.stepRejectCounter = 0;
393
- this.participantsService.emitTelepointersFromSteps(steps, this.providerEmitCallback);
393
+ this.participantsService.emitTelepointersFromSteps(steps);
394
394
 
395
395
  // Resend local steps if none of the received steps originated with us!
396
396
  if (clientIds.indexOf(this.clientId) === -1) {
@@ -5,7 +5,7 @@ import { INTERNAL_ERROR_CODE, PROVIDER_ERROR_CODE } from './error-types';
5
5
  * Maps internal collab provider errors to an emitted error format
6
6
  */
7
7
  export const errorCodeMapper = error => {
8
- var _error$data, _error$data2, _error$data3;
8
+ var _error$data, _error$data2, _error$data3, _error$data4;
9
9
  switch ((_error$data = error.data) === null || _error$data === void 0 ? void 0 : _error$data.code) {
10
10
  case NCS_ERROR_CODE.HEAD_VERSION_UPDATE_FAILED:
11
11
  case NCS_ERROR_CODE.VERSION_NUMBER_ALREADY_EXISTS:
@@ -88,7 +88,6 @@ export const errorCodeMapper = error => {
88
88
  case NCS_ERROR_CODE.NAMESPACE_NOT_FOUND:
89
89
  case NCS_ERROR_CODE.ERROR_MAPPING_ERROR:
90
90
  case NCS_ERROR_CODE.EMPTY_BROADCAST:
91
- case INTERNAL_ERROR_CODE.CATCHUP_FAILED:
92
91
  return {
93
92
  code: PROVIDER_ERROR_CODE.INTERNAL_SERVICE_ERROR,
94
93
  message: 'Collab Provider experienced an unrecoverable error',
@@ -96,6 +95,14 @@ export const errorCodeMapper = error => {
96
95
  reason: (_error$data3 = error.data) === null || _error$data3 === void 0 ? void 0 : _error$data3.code,
97
96
  status: 500
98
97
  };
98
+ case INTERNAL_ERROR_CODE.CATCHUP_FAILED:
99
+ return {
100
+ code: PROVIDER_ERROR_CODE.INTERNAL_SERVICE_ERROR,
101
+ message: 'Collab Provider experienced an unrecoverable error',
102
+ recoverable: true,
103
+ reason: (_error$data4 = error.data) === null || _error$data4 === void 0 ? void 0 : _error$data4.code,
104
+ status: 500
105
+ };
99
106
  default:
100
107
  return;
101
108
  }
@@ -0,0 +1,48 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { createLogger } from '../helpers/utils';
3
+ const logger = createLogger('Provider', 'orange');
4
+
5
+ /**
6
+ * Allows us to keep track of any namespace changes from the server.
7
+ * @param isNamespaceLocked - whether the namespace is locked or not, defaults to false
8
+ */
9
+ export class NamespaceService {
10
+ constructor(isNamespaceLocked = false) {
11
+ // Primitive values are always copied
12
+ _defineProperty(this, "getIsNamespaceLocked", () => this.isNamespaceLocked);
13
+ /**
14
+ * ESS-2916 namespace status event- lock/unlock
15
+ */
16
+ _defineProperty(this, "onNamespaceStatusChanged", async ({
17
+ isLocked,
18
+ waitTimeInMs,
19
+ timestamp
20
+ }) => {
21
+ const start = Date.now();
22
+ logger(`Received a namespace status changed event `, {
23
+ isLocked,
24
+ waitTimeInMs,
25
+ timestamp
26
+ });
27
+ if (isLocked && waitTimeInMs) {
28
+ this.isNamespaceLocked = true;
29
+ logger(`Received a namespace status change event `, {
30
+ isLocked
31
+ });
32
+
33
+ // To protect the collab editing process from locked out due to BE
34
+ setTimeout(() => {
35
+ logger(`The namespace lock has expired`, {
36
+ waitTime: Date.now() - start,
37
+ timestamp
38
+ });
39
+ this.isNamespaceLocked = false;
40
+ }, waitTimeInMs);
41
+ return;
42
+ }
43
+ this.isNamespaceLocked = false;
44
+ logger(`The page lock has expired`);
45
+ });
46
+ this.isNamespaceLocked = isNamespaceLocked;
47
+ }
48
+ }
@@ -1,5 +1,7 @@
1
1
  export const PARTICIPANT_UPDATE_INTERVAL = 300 * 1000; // 300 seconds
2
2
 
3
+ // Names are hard
4
+
3
5
  export const createParticipantFromPayload = async (payload, getUser) => {
4
6
  const {
5
7
  sessionId,