@atlaskit/editor-synced-block-provider 6.6.3 → 6.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 6.6.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [`7ddc63dca3716`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7ddc63dca3716) -
8
+ Fix synced block reference showing unpublished error when created from existing content on a live
9
+ page without further edits
10
+
3
11
  ## 6.6.3
4
12
 
5
13
  ### Patch Changes
@@ -12,6 +12,7 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/cl
12
12
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13
13
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
14
14
  var _monitoring = require("@atlaskit/editor-common/monitoring");
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
16
  var _types = require("../common/types");
16
17
  var _errorHandling = require("../utils/errorHandling");
17
18
  var _experienceTracking = require("../utils/experienceTracking");
@@ -21,6 +22,9 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
21
22
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
22
23
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
23
24
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
25
+ /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
26
+ var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
27
+
24
28
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
25
29
  // Designed to manage local in-memory state and synchronize with an external data provider.
26
30
  // Supports create, flush, and delete operations for source sync blocks.
@@ -31,6 +35,22 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
31
35
  var _this = this;
32
36
  (0, _classCallCheck2.default)(this, SourceSyncBlockStoreManager);
33
37
  (0, _defineProperty2.default)(this, "hasReceivedContentChange", false);
38
+ /**
39
+ * Promises for in-flight block creations, keyed by resourceId.
40
+ * `flush()` awaits these so that blocks created from existing content are
41
+ * persisted even if no further edits trigger a subsequent flush.
42
+ * See EDITOR-7112.
43
+ */
44
+ (0, _defineProperty2.default)(this, "pendingCreationPromises", new Map());
45
+ /**
46
+ * Set of resource IDs whose creation was still in-flight when a `flush()`
47
+ * timed out. Each completion (success or failure) is removed from this set;
48
+ * the first successful completion of any of these IDs triggers
49
+ * `postCreationFlushCallback` so the content is eventually persisted.
50
+ * Tracking IDs (not just a boolean) avoids dropping late completions when
51
+ * multiple blocks are created concurrently. See EDITOR-7112.
52
+ */
53
+ (0, _defineProperty2.default)(this, "creationsTimedOutDuringFlush", new Set());
34
54
  (0, _defineProperty2.default)(this, "setPendingDeletion", function (Ids, value) {
35
55
  if (_this.viewMode === 'view') {
36
56
  return;
@@ -57,6 +77,18 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
57
77
  value: function registerFlushCompletionCallback(callback) {
58
78
  this.flushCompletionCallback = callback;
59
79
  }
80
+
81
+ /**
82
+ * Register a callback to be invoked when flush() timed out waiting for a
83
+ * pending block creation and that creation subsequently completes. The
84
+ * callback should trigger a deferred flush to persist the content that
85
+ * was skipped due to the timeout. See EDITOR-7112.
86
+ */
87
+ }, {
88
+ key: "registerPostCreationFlushCallback",
89
+ value: function registerPostCreationFlushCallback(callback) {
90
+ this.postCreationFlushCallback = callback;
91
+ }
60
92
  }, {
61
93
  key: "setFireAnalyticsEvent",
62
94
  value: function setFireAnalyticsEvent(fireAnalyticsEvent) {
@@ -134,7 +166,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
134
166
  value: (function () {
135
167
  var _flush = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
136
168
  var _this2 = this;
137
- var _this$saveExperience, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
169
+ var _this$saveExperience, timedOut, timeoutId, timeout, _iterator, _step, resourceId, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
138
170
  return _regenerator.default.wrap(function _callee$(_context) {
139
171
  while (1) switch (_context.prev = _context.next) {
140
172
  case 0:
@@ -145,6 +177,39 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
145
177
  }
146
178
  return _context.abrupt("return", true);
147
179
  case 3:
180
+ if (!(this.pendingCreationPromises.size > 0 && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_12'))) {
181
+ _context.next = 10;
182
+ break;
183
+ }
184
+ timedOut = false;
185
+ timeout = new Promise(function (resolve) {
186
+ timeoutId = setTimeout(function () {
187
+ timedOut = true;
188
+ resolve();
189
+ }, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
190
+ });
191
+ _context.next = 8;
192
+ return Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
193
+ case 8:
194
+ if (timeoutId !== undefined) {
195
+ clearTimeout(timeoutId);
196
+ }
197
+ if (timedOut) {
198
+ // Record every still-in-flight creation so each late
199
+ // completion is tracked independently.
200
+ _iterator = _createForOfIteratorHelper(this.pendingCreationPromises.keys());
201
+ try {
202
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
203
+ resourceId = _step.value;
204
+ this.creationsTimedOutDuringFlush.add(resourceId);
205
+ }
206
+ } catch (err) {
207
+ _iterator.e(err);
208
+ } finally {
209
+ _iterator.f();
210
+ }
211
+ }
212
+ case 10:
148
213
  bodiedSyncBlockNodes = [];
149
214
  bodiedSyncBlockData = [];
150
215
  Array.from(this.syncBlockCache.values()).forEach(function (syncBlockData) {
@@ -174,21 +239,21 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
174
239
  }
175
240
  });
176
241
  if (!(bodiedSyncBlockNodes.length === 0)) {
177
- _context.next = 8;
242
+ _context.next = 15;
178
243
  break;
179
244
  }
180
245
  return _context.abrupt("return", Promise.resolve(true));
181
- case 8:
246
+ case 15:
182
247
  if (this.dataProvider) {
183
- _context.next = 10;
248
+ _context.next = 17;
184
249
  break;
185
250
  }
186
251
  throw new Error('Data provider not set');
187
- case 10:
252
+ case 17:
188
253
  (_this$saveExperience = this.saveExperience) === null || _this$saveExperience === void 0 || _this$saveExperience.start({});
189
- _context.next = 13;
254
+ _context.next = 20;
190
255
  return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
191
- case 13:
256
+ case 20:
192
257
  writeResults = _context.sent;
193
258
  writeResults.forEach(function (result) {
194
259
  // set isDirty to true for cases where it failed to save the sync block to the BE
@@ -202,7 +267,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
202
267
  if (!writeResults.every(function (result) {
203
268
  return result.resourceId && !result.error;
204
269
  })) {
205
- _context.next = 21;
270
+ _context.next = 28;
206
271
  break;
207
272
  }
208
273
  (_this$saveExperience2 = this.saveExperience) === null || _this$saveExperience2 === void 0 || _this$saveExperience2.success();
@@ -218,7 +283,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
218
283
  }
219
284
  });
220
285
  return _context.abrupt("return", true);
221
- case 21:
286
+ case 28:
222
287
  (_this$saveExperience3 = this.saveExperience) === null || _this$saveExperience3 === void 0 || _this$saveExperience3.failure();
223
288
  writeResults.filter(function (result) {
224
289
  return !result.resourceId || result.error;
@@ -227,11 +292,11 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
227
292
  (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, (0, _errorHandling.updateErrorPayload)(result.error || 'Failed to write data', result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId)));
228
293
  });
229
294
  return _context.abrupt("return", false);
230
- case 24:
231
- _context.next = 31;
295
+ case 31:
296
+ _context.next = 38;
232
297
  break;
233
- case 26:
234
- _context.prev = 26;
298
+ case 33:
299
+ _context.prev = 33;
235
300
  _context.t0 = _context["catch"](0);
236
301
  (0, _monitoring.logException)(_context.t0, {
237
302
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
@@ -239,15 +304,15 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
239
304
  // Top-level flush failure is not tied to a single resourceId.
240
305
  (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 || _this$fireAnalyticsEv2.call(this, (0, _errorHandling.updateErrorPayload)(_context.t0.message));
241
306
  return _context.abrupt("return", false);
242
- case 31:
243
- _context.prev = 31;
307
+ case 38:
308
+ _context.prev = 38;
244
309
  (_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
245
- return _context.finish(31);
246
- case 34:
310
+ return _context.finish(38);
311
+ case 41:
247
312
  case "end":
248
313
  return _context.stop();
249
314
  }
250
- }, _callee, this, [[0, 26, 31, 34]]);
315
+ }, _callee, this, [[0, 33, 38, 41]]);
251
316
  }));
252
317
  function flush() {
253
318
  return _flush.apply(this, arguments);
@@ -303,10 +368,20 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
303
368
  if (onCompletion) {
304
369
  this.creationCompletionCallbacks.delete(resourceId);
305
370
  onCompletion(success);
371
+ // If a previous flush() timed out waiting for this specific
372
+ // creation, drop it from the tracking set regardless of outcome so
373
+ // it does not leak. See EDITOR-7112.
374
+ var wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
306
375
  if (success) {
307
376
  // If creation is successful, set hasReceivedContentChange to true
308
377
  // to indicate that there are unsaved changes in the cache
309
378
  this.hasReceivedContentChange = true;
379
+ // If flush() timed out waiting for this creation, notify the
380
+ // plugin so it can trigger a deferred flush. See EDITOR-7112.
381
+ if (wasTimedOut) {
382
+ var _this$postCreationFlu;
383
+ (_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 || _this$postCreationFlu.call(this);
384
+ }
310
385
  }
311
386
  } else {
312
387
  var _this$fireAnalyticsEv3;
@@ -386,7 +461,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
386
461
  }
387
462
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
388
463
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
389
- this.dataProvider.createNodeData({
464
+ var creationPromise = this.dataProvider.createNodeData({
390
465
  content: [],
391
466
  blockInstanceId: blockInstanceId,
392
467
  resourceId: resourceId
@@ -414,7 +489,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
414
489
  reason: error.message
415
490
  });
416
491
  (_this4$fireAnalyticsE2 = _this4.fireAnalyticsEvent) === null || _this4$fireAnalyticsE2 === void 0 || _this4$fireAnalyticsE2.call(_this4, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
492
+ }).finally(function () {
493
+ _this4.pendingCreationPromises.delete(resourceId);
417
494
  });
495
+ this.pendingCreationPromises.set(resourceId, creationPromise);
418
496
  } catch (error) {
419
497
  var _this$fireAnalyticsEv6;
420
498
  if (this.isPendingCreation(resourceId)) {
@@ -575,7 +653,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
575
653
  value: (function () {
576
654
  var _fetchAndCacheStatuses = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
577
655
  var _this6 = this;
578
- var sourceToReferenceMap, syncBlockNodes, results, _iterator, _step, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
656
+ var sourceToReferenceMap, syncBlockNodes, results, _iterator2, _step2, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
579
657
  return _regenerator.default.wrap(function _callee4$(_context4) {
580
658
  while (1) switch (_context4.prev = _context4.next) {
581
659
  case 0:
@@ -611,10 +689,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
611
689
  return this.dataProvider.fetchNodesData(syncBlockNodes);
612
690
  case 7:
613
691
  results = _context4.sent;
614
- _iterator = _createForOfIteratorHelper(results);
692
+ _iterator2 = _createForOfIteratorHelper(results);
615
693
  try {
616
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
617
- result = _step.value;
694
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
695
+ result = _step2.value;
618
696
  // Map the reference resourceId back to the source resourceId
619
697
  sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
620
698
  cached = this.syncBlockCache.get(sourceResourceId);
@@ -623,9 +701,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
623
701
  }
624
702
  }
625
703
  } catch (err) {
626
- _iterator.e(err);
704
+ _iterator2.e(err);
627
705
  } finally {
628
- _iterator.f();
706
+ _iterator2.f();
629
707
  }
630
708
  _context4.next = 14;
631
709
  break;
@@ -801,6 +879,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
801
879
  this.confirmationCallback = undefined;
802
880
  this.creationCompletionCallbacks.clear();
803
881
  this.flushCompletionCallback = undefined;
882
+ this.postCreationFlushCallback = undefined;
883
+ this.pendingCreationPromises.clear();
884
+ this.creationsTimedOutDuringFlush.clear();
804
885
  this.dataProvider = undefined;
805
886
  (_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 || _this$saveExperience4.abort({
806
887
  reason: 'editorDestroyed'
@@ -1,9 +1,13 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { logException } from '@atlaskit/editor-common/monitoring';
3
+ import { fg } from '@atlaskit/platform-feature-flags';
3
4
  import { SyncBlockError } from '../common/types';
4
5
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
5
6
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
6
7
  import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
8
+ /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
9
+ const FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
10
+
7
11
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
8
12
  // Designed to manage local in-memory state and synchronize with an external data provider.
9
13
  // Supports create, flush, and delete operations for source sync blocks.
@@ -12,6 +16,22 @@ import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSa
12
16
  export class SourceSyncBlockStoreManager {
13
17
  constructor(dataProvider, viewMode, isLivePage) {
14
18
  _defineProperty(this, "hasReceivedContentChange", false);
19
+ /**
20
+ * Promises for in-flight block creations, keyed by resourceId.
21
+ * `flush()` awaits these so that blocks created from existing content are
22
+ * persisted even if no further edits trigger a subsequent flush.
23
+ * See EDITOR-7112.
24
+ */
25
+ _defineProperty(this, "pendingCreationPromises", new Map());
26
+ /**
27
+ * Set of resource IDs whose creation was still in-flight when a `flush()`
28
+ * timed out. Each completion (success or failure) is removed from this set;
29
+ * the first successful completion of any of these IDs triggers
30
+ * `postCreationFlushCallback` so the content is eventually persisted.
31
+ * Tracking IDs (not just a boolean) avoids dropping late completions when
32
+ * multiple blocks are created concurrently. See EDITOR-7112.
33
+ */
34
+ _defineProperty(this, "creationsTimedOutDuringFlush", new Set());
15
35
  _defineProperty(this, "setPendingDeletion", (Ids, value) => {
16
36
  if (this.viewMode === 'view') {
17
37
  return;
@@ -36,6 +56,16 @@ export class SourceSyncBlockStoreManager {
36
56
  registerFlushCompletionCallback(callback) {
37
57
  this.flushCompletionCallback = callback;
38
58
  }
59
+
60
+ /**
61
+ * Register a callback to be invoked when flush() timed out waiting for a
62
+ * pending block creation and that creation subsequently completes. The
63
+ * callback should trigger a deferred flush to persist the content that
64
+ * was skipped due to the timeout. See EDITOR-7112.
65
+ */
66
+ registerPostCreationFlushCallback(callback) {
67
+ this.postCreationFlushCallback = callback;
68
+ }
39
69
  setFireAnalyticsEvent(fireAnalyticsEvent) {
40
70
  this.fireAnalyticsEvent = fireAnalyticsEvent;
41
71
  this.createExperience = getCreateSourceExperience(fireAnalyticsEvent);
@@ -110,6 +140,39 @@ export class SourceSyncBlockStoreManager {
110
140
  if (this.viewMode === 'view') {
111
141
  return true;
112
142
  }
143
+
144
+ // Wait (up to FLUSH_CREATION_AWAIT_TIMEOUT_MS) for any in-flight
145
+ // block creations to complete before iterating the cache. Without
146
+ // this, blocks created from existing content are skipped
147
+ // (isPendingCreation check below) and if no further edits are made,
148
+ // no subsequent flush is triggered — causing references to show an
149
+ // "unpublished" error.
150
+ // If the timeout expires, any block whose creation is still
151
+ // in-flight is recorded in `creationsTimedOutDuringFlush` so that
152
+ // `commitPendingCreation()` can trigger a follow-up flush once that
153
+ // specific creation completes.
154
+ // See EDITOR-7112.
155
+ if (this.pendingCreationPromises.size > 0 && fg('platform_synced_block_patch_12')) {
156
+ let timedOut = false;
157
+ let timeoutId;
158
+ const timeout = new Promise(resolve => {
159
+ timeoutId = setTimeout(() => {
160
+ timedOut = true;
161
+ resolve();
162
+ }, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
163
+ });
164
+ await Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
165
+ if (timeoutId !== undefined) {
166
+ clearTimeout(timeoutId);
167
+ }
168
+ if (timedOut) {
169
+ // Record every still-in-flight creation so each late
170
+ // completion is tracked independently.
171
+ for (const resourceId of this.pendingCreationPromises.keys()) {
172
+ this.creationsTimedOutDuringFlush.add(resourceId);
173
+ }
174
+ }
175
+ }
113
176
  const bodiedSyncBlockNodes = [];
114
177
  const bodiedSyncBlockData = [];
115
178
  Array.from(this.syncBlockCache.values()).forEach(syncBlockData => {
@@ -232,10 +295,20 @@ export class SourceSyncBlockStoreManager {
232
295
  if (onCompletion) {
233
296
  this.creationCompletionCallbacks.delete(resourceId);
234
297
  onCompletion(success);
298
+ // If a previous flush() timed out waiting for this specific
299
+ // creation, drop it from the tracking set regardless of outcome so
300
+ // it does not leak. See EDITOR-7112.
301
+ const wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
235
302
  if (success) {
236
303
  // If creation is successful, set hasReceivedContentChange to true
237
304
  // to indicate that there are unsaved changes in the cache
238
305
  this.hasReceivedContentChange = true;
306
+ // If flush() timed out waiting for this creation, notify the
307
+ // plugin so it can trigger a deferred flush. See EDITOR-7112.
308
+ if (wasTimedOut) {
309
+ var _this$postCreationFlu;
310
+ (_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 ? void 0 : _this$postCreationFlu.call(this);
311
+ }
239
312
  }
240
313
  } else {
241
314
  var _this$fireAnalyticsEv5;
@@ -308,7 +381,7 @@ export class SourceSyncBlockStoreManager {
308
381
  }
309
382
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
310
383
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 ? void 0 : _this$createExperienc.start({});
311
- this.dataProvider.createNodeData({
384
+ const creationPromise = this.dataProvider.createNodeData({
312
385
  content: [],
313
386
  blockInstanceId,
314
387
  resourceId
@@ -336,7 +409,10 @@ export class SourceSyncBlockStoreManager {
336
409
  reason: error.message
337
410
  });
338
411
  (_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 ? void 0 : _this$fireAnalyticsEv9.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
412
+ }).finally(() => {
413
+ this.pendingCreationPromises.delete(resourceId);
339
414
  });
415
+ this.pendingCreationPromises.set(resourceId, creationPromise);
340
416
  } catch (error) {
341
417
  var _this$fireAnalyticsEv0;
342
418
  if (this.isPendingCreation(resourceId)) {
@@ -584,6 +660,9 @@ export class SourceSyncBlockStoreManager {
584
660
  this.confirmationCallback = undefined;
585
661
  this.creationCompletionCallbacks.clear();
586
662
  this.flushCompletionCallback = undefined;
663
+ this.postCreationFlushCallback = undefined;
664
+ this.pendingCreationPromises.clear();
665
+ this.creationsTimedOutDuringFlush.clear();
587
666
  this.dataProvider = undefined;
588
667
  (_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 ? void 0 : _this$saveExperience4.abort({
589
668
  reason: 'editorDestroyed'
@@ -3,17 +3,21 @@ 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";
5
5
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
6
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
6
7
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
7
8
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
8
9
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
9
- import _regeneratorRuntime from "@babel/runtime/regenerator";
10
10
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
11
11
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
12
12
  import { logException } from '@atlaskit/editor-common/monitoring';
13
+ import { fg } from '@atlaskit/platform-feature-flags';
13
14
  import { SyncBlockError } from '../common/types';
14
15
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
15
16
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
16
17
  import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
18
+ /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
19
+ var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
20
+
17
21
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
18
22
  // Designed to manage local in-memory state and synchronize with an external data provider.
19
23
  // Supports create, flush, and delete operations for source sync blocks.
@@ -24,6 +28,22 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
24
28
  var _this = this;
25
29
  _classCallCheck(this, SourceSyncBlockStoreManager);
26
30
  _defineProperty(this, "hasReceivedContentChange", false);
31
+ /**
32
+ * Promises for in-flight block creations, keyed by resourceId.
33
+ * `flush()` awaits these so that blocks created from existing content are
34
+ * persisted even if no further edits trigger a subsequent flush.
35
+ * See EDITOR-7112.
36
+ */
37
+ _defineProperty(this, "pendingCreationPromises", new Map());
38
+ /**
39
+ * Set of resource IDs whose creation was still in-flight when a `flush()`
40
+ * timed out. Each completion (success or failure) is removed from this set;
41
+ * the first successful completion of any of these IDs triggers
42
+ * `postCreationFlushCallback` so the content is eventually persisted.
43
+ * Tracking IDs (not just a boolean) avoids dropping late completions when
44
+ * multiple blocks are created concurrently. See EDITOR-7112.
45
+ */
46
+ _defineProperty(this, "creationsTimedOutDuringFlush", new Set());
27
47
  _defineProperty(this, "setPendingDeletion", function (Ids, value) {
28
48
  if (_this.viewMode === 'view') {
29
49
  return;
@@ -50,6 +70,18 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
50
70
  value: function registerFlushCompletionCallback(callback) {
51
71
  this.flushCompletionCallback = callback;
52
72
  }
73
+
74
+ /**
75
+ * Register a callback to be invoked when flush() timed out waiting for a
76
+ * pending block creation and that creation subsequently completes. The
77
+ * callback should trigger a deferred flush to persist the content that
78
+ * was skipped due to the timeout. See EDITOR-7112.
79
+ */
80
+ }, {
81
+ key: "registerPostCreationFlushCallback",
82
+ value: function registerPostCreationFlushCallback(callback) {
83
+ this.postCreationFlushCallback = callback;
84
+ }
53
85
  }, {
54
86
  key: "setFireAnalyticsEvent",
55
87
  value: function setFireAnalyticsEvent(fireAnalyticsEvent) {
@@ -127,7 +159,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
127
159
  value: (function () {
128
160
  var _flush = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
129
161
  var _this2 = this;
130
- var _this$saveExperience, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
162
+ var _this$saveExperience, timedOut, timeoutId, timeout, _iterator, _step, resourceId, bodiedSyncBlockNodes, bodiedSyncBlockData, writeResults, _this$saveExperience2, _this$saveExperience3, _this$fireAnalyticsEv2, _this$flushCompletion;
131
163
  return _regeneratorRuntime.wrap(function _callee$(_context) {
132
164
  while (1) switch (_context.prev = _context.next) {
133
165
  case 0:
@@ -138,6 +170,39 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
138
170
  }
139
171
  return _context.abrupt("return", true);
140
172
  case 3:
173
+ if (!(this.pendingCreationPromises.size > 0 && fg('platform_synced_block_patch_12'))) {
174
+ _context.next = 10;
175
+ break;
176
+ }
177
+ timedOut = false;
178
+ timeout = new Promise(function (resolve) {
179
+ timeoutId = setTimeout(function () {
180
+ timedOut = true;
181
+ resolve();
182
+ }, FLUSH_CREATION_AWAIT_TIMEOUT_MS);
183
+ });
184
+ _context.next = 8;
185
+ return Promise.race([Promise.all(this.pendingCreationPromises.values()), timeout]);
186
+ case 8:
187
+ if (timeoutId !== undefined) {
188
+ clearTimeout(timeoutId);
189
+ }
190
+ if (timedOut) {
191
+ // Record every still-in-flight creation so each late
192
+ // completion is tracked independently.
193
+ _iterator = _createForOfIteratorHelper(this.pendingCreationPromises.keys());
194
+ try {
195
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
196
+ resourceId = _step.value;
197
+ this.creationsTimedOutDuringFlush.add(resourceId);
198
+ }
199
+ } catch (err) {
200
+ _iterator.e(err);
201
+ } finally {
202
+ _iterator.f();
203
+ }
204
+ }
205
+ case 10:
141
206
  bodiedSyncBlockNodes = [];
142
207
  bodiedSyncBlockData = [];
143
208
  Array.from(this.syncBlockCache.values()).forEach(function (syncBlockData) {
@@ -167,21 +232,21 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
167
232
  }
168
233
  });
169
234
  if (!(bodiedSyncBlockNodes.length === 0)) {
170
- _context.next = 8;
235
+ _context.next = 15;
171
236
  break;
172
237
  }
173
238
  return _context.abrupt("return", Promise.resolve(true));
174
- case 8:
239
+ case 15:
175
240
  if (this.dataProvider) {
176
- _context.next = 10;
241
+ _context.next = 17;
177
242
  break;
178
243
  }
179
244
  throw new Error('Data provider not set');
180
- case 10:
245
+ case 17:
181
246
  (_this$saveExperience = this.saveExperience) === null || _this$saveExperience === void 0 || _this$saveExperience.start({});
182
- _context.next = 13;
247
+ _context.next = 20;
183
248
  return this.dataProvider.writeNodesData(bodiedSyncBlockNodes, bodiedSyncBlockData);
184
- case 13:
249
+ case 20:
185
250
  writeResults = _context.sent;
186
251
  writeResults.forEach(function (result) {
187
252
  // set isDirty to true for cases where it failed to save the sync block to the BE
@@ -195,7 +260,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
195
260
  if (!writeResults.every(function (result) {
196
261
  return result.resourceId && !result.error;
197
262
  })) {
198
- _context.next = 21;
263
+ _context.next = 28;
199
264
  break;
200
265
  }
201
266
  (_this$saveExperience2 = this.saveExperience) === null || _this$saveExperience2 === void 0 || _this$saveExperience2.success();
@@ -211,7 +276,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
211
276
  }
212
277
  });
213
278
  return _context.abrupt("return", true);
214
- case 21:
279
+ case 28:
215
280
  (_this$saveExperience3 = this.saveExperience) === null || _this$saveExperience3 === void 0 || _this$saveExperience3.failure();
216
281
  writeResults.filter(function (result) {
217
282
  return !result.resourceId || result.error;
@@ -220,11 +285,11 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
220
285
  (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, updateErrorPayload(result.error || 'Failed to write data', result.resourceId, getSourceProductFromResourceIdSafe(result.resourceId)));
221
286
  });
222
287
  return _context.abrupt("return", false);
223
- case 24:
224
- _context.next = 31;
288
+ case 31:
289
+ _context.next = 38;
225
290
  break;
226
- case 26:
227
- _context.prev = 26;
291
+ case 33:
292
+ _context.prev = 33;
228
293
  _context.t0 = _context["catch"](0);
229
294
  logException(_context.t0, {
230
295
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
@@ -232,15 +297,15 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
232
297
  // Top-level flush failure is not tied to a single resourceId.
233
298
  (_this$fireAnalyticsEv2 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv2 === void 0 || _this$fireAnalyticsEv2.call(this, updateErrorPayload(_context.t0.message));
234
299
  return _context.abrupt("return", false);
235
- case 31:
236
- _context.prev = 31;
300
+ case 38:
301
+ _context.prev = 38;
237
302
  (_this$flushCompletion = this.flushCompletionCallback) === null || _this$flushCompletion === void 0 || _this$flushCompletion.call(this);
238
- return _context.finish(31);
239
- case 34:
303
+ return _context.finish(38);
304
+ case 41:
240
305
  case "end":
241
306
  return _context.stop();
242
307
  }
243
- }, _callee, this, [[0, 26, 31, 34]]);
308
+ }, _callee, this, [[0, 33, 38, 41]]);
244
309
  }));
245
310
  function flush() {
246
311
  return _flush.apply(this, arguments);
@@ -296,10 +361,20 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
296
361
  if (onCompletion) {
297
362
  this.creationCompletionCallbacks.delete(resourceId);
298
363
  onCompletion(success);
364
+ // If a previous flush() timed out waiting for this specific
365
+ // creation, drop it from the tracking set regardless of outcome so
366
+ // it does not leak. See EDITOR-7112.
367
+ var wasTimedOut = this.creationsTimedOutDuringFlush.delete(resourceId);
299
368
  if (success) {
300
369
  // If creation is successful, set hasReceivedContentChange to true
301
370
  // to indicate that there are unsaved changes in the cache
302
371
  this.hasReceivedContentChange = true;
372
+ // If flush() timed out waiting for this creation, notify the
373
+ // plugin so it can trigger a deferred flush. See EDITOR-7112.
374
+ if (wasTimedOut) {
375
+ var _this$postCreationFlu;
376
+ (_this$postCreationFlu = this.postCreationFlushCallback) === null || _this$postCreationFlu === void 0 || _this$postCreationFlu.call(this);
377
+ }
303
378
  }
304
379
  } else {
305
380
  var _this$fireAnalyticsEv3;
@@ -379,7 +454,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
379
454
  }
380
455
  this.creationCompletionCallbacks.set(resourceId, onCompletion);
381
456
  (_this$createExperienc = this.createExperience) === null || _this$createExperienc === void 0 || _this$createExperienc.start({});
382
- this.dataProvider.createNodeData({
457
+ var creationPromise = this.dataProvider.createNodeData({
383
458
  content: [],
384
459
  blockInstanceId: blockInstanceId,
385
460
  resourceId: resourceId
@@ -407,7 +482,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
407
482
  reason: error.message
408
483
  });
409
484
  (_this4$fireAnalyticsE2 = _this4.fireAnalyticsEvent) === null || _this4$fireAnalyticsE2 === void 0 || _this4$fireAnalyticsE2.call(_this4, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
485
+ }).finally(function () {
486
+ _this4.pendingCreationPromises.delete(resourceId);
410
487
  });
488
+ this.pendingCreationPromises.set(resourceId, creationPromise);
411
489
  } catch (error) {
412
490
  var _this$fireAnalyticsEv6;
413
491
  if (this.isPendingCreation(resourceId)) {
@@ -568,7 +646,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
568
646
  value: (function () {
569
647
  var _fetchAndCacheStatuses = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
570
648
  var _this6 = this;
571
- var sourceToReferenceMap, syncBlockNodes, results, _iterator, _step, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
649
+ var sourceToReferenceMap, syncBlockNodes, results, _iterator2, _step2, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached;
572
650
  return _regeneratorRuntime.wrap(function _callee4$(_context4) {
573
651
  while (1) switch (_context4.prev = _context4.next) {
574
652
  case 0:
@@ -604,10 +682,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
604
682
  return this.dataProvider.fetchNodesData(syncBlockNodes);
605
683
  case 7:
606
684
  results = _context4.sent;
607
- _iterator = _createForOfIteratorHelper(results);
685
+ _iterator2 = _createForOfIteratorHelper(results);
608
686
  try {
609
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
610
- result = _step.value;
687
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
688
+ result = _step2.value;
611
689
  // Map the reference resourceId back to the source resourceId
612
690
  sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
613
691
  cached = this.syncBlockCache.get(sourceResourceId);
@@ -616,9 +694,9 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
616
694
  }
617
695
  }
618
696
  } catch (err) {
619
- _iterator.e(err);
697
+ _iterator2.e(err);
620
698
  } finally {
621
- _iterator.f();
699
+ _iterator2.f();
622
700
  }
623
701
  _context4.next = 14;
624
702
  break;
@@ -794,6 +872,9 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
794
872
  this.confirmationCallback = undefined;
795
873
  this.creationCompletionCallbacks.clear();
796
874
  this.flushCompletionCallback = undefined;
875
+ this.postCreationFlushCallback = undefined;
876
+ this.pendingCreationPromises.clear();
877
+ this.creationsTimedOutDuringFlush.clear();
797
878
  this.dataProvider = undefined;
798
879
  (_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 || _this$saveExperience4.abort({
799
880
  reason: 'editorDestroyed'
@@ -18,6 +18,23 @@ export declare class SourceSyncBlockStoreManager {
18
18
  private deletionRetryInfo?;
19
19
  private creationCompletionCallbacks;
20
20
  private flushCompletionCallback?;
21
+ private postCreationFlushCallback?;
22
+ /**
23
+ * Promises for in-flight block creations, keyed by resourceId.
24
+ * `flush()` awaits these so that blocks created from existing content are
25
+ * persisted even if no further edits trigger a subsequent flush.
26
+ * See EDITOR-7112.
27
+ */
28
+ private pendingCreationPromises;
29
+ /**
30
+ * Set of resource IDs whose creation was still in-flight when a `flush()`
31
+ * timed out. Each completion (success or failure) is removed from this set;
32
+ * the first successful completion of any of these IDs triggers
33
+ * `postCreationFlushCallback` so the content is eventually persisted.
34
+ * Tracking IDs (not just a boolean) avoids dropping late completions when
35
+ * multiple blocks are created concurrently. See EDITOR-7112.
36
+ */
37
+ private creationsTimedOutDuringFlush;
21
38
  private createExperience;
22
39
  private saveExperience;
23
40
  private deleteExperience;
@@ -29,6 +46,13 @@ export declare class SourceSyncBlockStoreManager {
29
46
  * hasUnsavedBodiedSyncBlockChanges is recalculated in plugin state.
30
47
  */
31
48
  registerFlushCompletionCallback(callback: () => void): void;
49
+ /**
50
+ * Register a callback to be invoked when flush() timed out waiting for a
51
+ * pending block creation and that creation subsequently completes. The
52
+ * callback should trigger a deferred flush to persist the content that
53
+ * was skipped due to the timeout. See EDITOR-7112.
54
+ */
55
+ registerPostCreationFlushCallback(callback: () => void): void;
32
56
  setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: SyncBlockEventPayload) => void): void;
33
57
  isSourceBlock(node: PMNode): boolean;
34
58
  /**
@@ -18,6 +18,23 @@ export declare class SourceSyncBlockStoreManager {
18
18
  private deletionRetryInfo?;
19
19
  private creationCompletionCallbacks;
20
20
  private flushCompletionCallback?;
21
+ private postCreationFlushCallback?;
22
+ /**
23
+ * Promises for in-flight block creations, keyed by resourceId.
24
+ * `flush()` awaits these so that blocks created from existing content are
25
+ * persisted even if no further edits trigger a subsequent flush.
26
+ * See EDITOR-7112.
27
+ */
28
+ private pendingCreationPromises;
29
+ /**
30
+ * Set of resource IDs whose creation was still in-flight when a `flush()`
31
+ * timed out. Each completion (success or failure) is removed from this set;
32
+ * the first successful completion of any of these IDs triggers
33
+ * `postCreationFlushCallback` so the content is eventually persisted.
34
+ * Tracking IDs (not just a boolean) avoids dropping late completions when
35
+ * multiple blocks are created concurrently. See EDITOR-7112.
36
+ */
37
+ private creationsTimedOutDuringFlush;
21
38
  private createExperience;
22
39
  private saveExperience;
23
40
  private deleteExperience;
@@ -29,6 +46,13 @@ export declare class SourceSyncBlockStoreManager {
29
46
  * hasUnsavedBodiedSyncBlockChanges is recalculated in plugin state.
30
47
  */
31
48
  registerFlushCompletionCallback(callback: () => void): void;
49
+ /**
50
+ * Register a callback to be invoked when flush() timed out waiting for a
51
+ * pending block creation and that creation subsequently completes. The
52
+ * callback should trigger a deferred flush to persist the content that
53
+ * was skipped due to the timeout. See EDITOR-7112.
54
+ */
55
+ registerPostCreationFlushCallback(callback: () => void): void;
32
56
  setFireAnalyticsEvent(fireAnalyticsEvent?: (payload: SyncBlockEventPayload) => void): void;
33
57
  isSourceBlock(node: PMNode): boolean;
34
58
  /**
package/package.json CHANGED
@@ -29,7 +29,7 @@
29
29
  "@atlaskit/editor-prosemirror": "^7.3.0",
30
30
  "@atlaskit/node-data-provider": "^11.1.0",
31
31
  "@atlaskit/platform-feature-flags": "^1.1.0",
32
- "@atlaskit/tmp-editor-statsig": "^81.0.0",
32
+ "@atlaskit/tmp-editor-statsig": "^81.1.0",
33
33
  "@babel/runtime": "^7.0.0",
34
34
  "@compiled/react": "^0.20.0",
35
35
  "graphql-ws": "^5.14.2",
@@ -38,7 +38,7 @@
38
38
  "uuid": "^3.1.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "@atlaskit/editor-common": "^114.32.0",
41
+ "@atlaskit/editor-common": "^114.35.0",
42
42
  "react": "^18.2.0"
43
43
  },
44
44
  "devDependencies": {
@@ -81,11 +81,16 @@
81
81
  }
82
82
  },
83
83
  "name": "@atlaskit/editor-synced-block-provider",
84
- "version": "6.6.3",
84
+ "version": "6.6.4",
85
85
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
86
86
  "author": "Atlassian Pty Ltd",
87
87
  "license": "Apache-2.0",
88
88
  "publishConfig": {
89
89
  "registry": "https://registry.npmjs.org/"
90
+ },
91
+ "platform-feature-flags": {
92
+ "platform_synced_block_patch_12": {
93
+ "type": "boolean"
94
+ }
90
95
  }
91
96
  }