@atlaskit/editor-synced-block-provider 2.7.4 → 2.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 (37) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/index.js +37 -0
  3. package/dist/cjs/providers/block-service/blockServiceAPI.js +238 -0
  4. package/dist/cjs/providers/confluence/confluenceContentAPI.js +5 -0
  5. package/dist/cjs/providers/syncBlockProvider.js +5 -0
  6. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +2 -5
  7. package/dist/cjs/utils/ari.js +32 -4
  8. package/dist/cjs/utils/blockService.js +168 -0
  9. package/dist/es2019/index.js +2 -1
  10. package/dist/es2019/providers/block-service/blockServiceAPI.js +148 -0
  11. package/dist/es2019/providers/confluence/confluenceContentAPI.js +4 -1
  12. package/dist/es2019/providers/syncBlockProvider.js +3 -0
  13. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +2 -5
  14. package/dist/es2019/utils/ari.js +31 -1
  15. package/dist/es2019/utils/blockService.js +71 -0
  16. package/dist/esm/index.js +2 -1
  17. package/dist/esm/providers/block-service/blockServiceAPI.js +231 -0
  18. package/dist/esm/providers/confluence/confluenceContentAPI.js +6 -1
  19. package/dist/esm/providers/syncBlockProvider.js +5 -0
  20. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +2 -5
  21. package/dist/esm/utils/ari.js +31 -3
  22. package/dist/esm/utils/blockService.js +161 -0
  23. package/dist/types/index.d.ts +2 -1
  24. package/dist/types/providers/block-service/blockServiceAPI.d.ts +21 -0
  25. package/dist/types/providers/confluence/confluenceContentAPI.d.ts +1 -0
  26. package/dist/types/providers/syncBlockProvider.d.ts +1 -0
  27. package/dist/types/providers/types.d.ts +8 -0
  28. package/dist/types/utils/ari.d.ts +15 -1
  29. package/dist/types/utils/blockService.d.ts +39 -0
  30. package/dist/types-ts4.5/index.d.ts +2 -1
  31. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +21 -0
  32. package/dist/types-ts4.5/providers/confluence/confluenceContentAPI.d.ts +1 -0
  33. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +1 -0
  34. package/dist/types-ts4.5/providers/types.d.ts +8 -0
  35. package/dist/types-ts4.5/utils/ari.d.ts +15 -1
  36. package/dist/types-ts4.5/utils/blockService.d.ts +39 -0
  37. package/package.json +8 -2
@@ -0,0 +1,148 @@
1
+ import { useMemo } from 'react';
2
+ import { SyncBlockError } from '../../common/types';
3
+ import { blockResourceIdFromSourceAndLocalId, getLocalIdFromResourceId } from '../../utils/ari';
4
+ import { BlockError, createSyncedBlock, deleteSyncedBlock, getSyncedBlockContent, updateSyncedBlock } from '../../utils/blockService';
5
+ import { stringifyError } from '../../utils/errorHandling';
6
+ const mapBlockError = error => {
7
+ switch (error.status) {
8
+ case 403:
9
+ return SyncBlockError.Forbidden;
10
+ case 404:
11
+ return SyncBlockError.NotFound;
12
+ }
13
+ return SyncBlockError.Errored;
14
+ };
15
+
16
+ /**
17
+ * ADFFetchProvider implementation that fetches synced block data from Block Service API
18
+ */
19
+ class BlockServiceADFFetchProvider {
20
+ // resourceId is the ARI of the block. E.G ari:cloud:blocks:site-123:synced-block/uuid-456
21
+ // in the content API provider, this was the concatenation of the source document's ARI and the local ID. E.G ari:cloud:confluence:site-123:page/pageId/uuid-456
22
+ async fetchData(resourceId) {
23
+ const localId = getLocalIdFromResourceId(resourceId);
24
+ try {
25
+ const blockContentResponse = await getSyncedBlockContent({
26
+ blockAri: resourceId
27
+ });
28
+ const value = blockContentResponse.content;
29
+ if (!value) {
30
+ return {
31
+ error: SyncBlockError.NotFound,
32
+ resourceId
33
+ };
34
+ }
35
+
36
+ // Parse the synced block content from the response's content
37
+ const syncedBlockData = JSON.parse(value);
38
+ return {
39
+ data: {
40
+ content: syncedBlockData,
41
+ resourceId,
42
+ blockInstanceId: localId
43
+ },
44
+ resourceId
45
+ };
46
+ } catch (error) {
47
+ if (error instanceof BlockError) {
48
+ return {
49
+ error: mapBlockError(error),
50
+ resourceId
51
+ };
52
+ }
53
+ return {
54
+ error: SyncBlockError.Errored,
55
+ resourceId
56
+ };
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * ADFWriteProvider implementation that writes synced block data to Block Service API
63
+ */
64
+ class BlockServiceADFWriteProvider {
65
+ // it will first try to update and if it can't (404) then it will try to create
66
+ async writeData(data) {
67
+ const {
68
+ resourceId
69
+ } = data;
70
+ try {
71
+ // Try update existing block's content
72
+ await updateSyncedBlock({
73
+ blockAri: resourceId,
74
+ content: JSON.stringify(data.content)
75
+ });
76
+ return {
77
+ resourceId
78
+ };
79
+ } catch (error) {
80
+ if (error instanceof BlockError) {
81
+ if (error.status === 404) {
82
+ // Create the block
83
+ await createSyncedBlock({
84
+ blockAri: resourceId,
85
+ blockInstanceId: data.blockInstanceId,
86
+ sourceAri: resourceId,
87
+ product: 'confluence-page',
88
+ content: JSON.stringify(data.content)
89
+ });
90
+ } else {
91
+ return {
92
+ error: mapBlockError(error),
93
+ resourceId
94
+ };
95
+ }
96
+ }
97
+ return {
98
+ error: stringifyError(error),
99
+ resourceId
100
+ };
101
+ }
102
+ }
103
+
104
+ // soft deletes the source synced block
105
+ async deleteData(resourceId) {
106
+ try {
107
+ await deleteSyncedBlock({
108
+ blockAri: resourceId
109
+ });
110
+ return {
111
+ resourceId,
112
+ success: true,
113
+ error: undefined
114
+ };
115
+ } catch (error) {
116
+ if (error instanceof BlockError) {
117
+ return {
118
+ resourceId,
119
+ success: false,
120
+ error: mapBlockError(error)
121
+ };
122
+ }
123
+ return {
124
+ resourceId,
125
+ success: false,
126
+ error: stringifyError(error)
127
+ };
128
+ }
129
+ }
130
+ generateResourceId(sourceId, localId) {
131
+ return blockResourceIdFromSourceAndLocalId(sourceId, localId);
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Factory function to create both providers with shared configuration
137
+ */
138
+ const createBlockServiceAPIProviders = () => {
139
+ const fetchProvider = new BlockServiceADFFetchProvider();
140
+ const writeProvider = new BlockServiceADFWriteProvider();
141
+ return {
142
+ fetchProvider,
143
+ writeProvider
144
+ };
145
+ };
146
+ export const useMemoizedBlockServiceAPIProviders = () => {
147
+ return useMemo(createBlockServiceAPIProviders, []);
148
+ };
@@ -1,7 +1,7 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  import { useMemo } from 'react';
3
3
  import { SyncBlockError } from '../../common/types';
4
- import { getLocalIdFromAri, getPageIdAndTypeFromAri } from '../../utils/ari';
4
+ import { getLocalIdFromAri, getPageIdAndTypeFromAri, resourceIdFromSourceAndLocalId } from '../../utils/ari';
5
5
  import { getContentProperty, createContentProperty, updateContentProperty, deleteContentProperty } from '../../utils/contentProperty';
6
6
  import { stringifyError } from '../../utils/errorHandling';
7
7
  import { isBlogPageType } from '../../utils/utils';
@@ -227,6 +227,9 @@ class ConfluenceADFWriteProvider {
227
227
  error: deleteResult.errors.join()
228
228
  };
229
229
  }
230
+ generateResourceId(sourceId, localId) {
231
+ return resourceIdFromSourceAndLocalId(sourceId, localId);
232
+ }
230
233
  }
231
234
 
232
235
  /**
@@ -99,6 +99,9 @@ export class SyncBlockProvider extends SyncBlockDataProvider {
99
99
  }
100
100
  return pageARI ? fetchSourceInfo(pageARI, sourceLocalId) : Promise.resolve(undefined);
101
101
  }
102
+ generateResourceId(sourceId, localId) {
103
+ return this.writeProvider.generateResourceId(sourceId, localId);
104
+ }
102
105
  }
103
106
  export const useMemoizedSyncedBlockProvider = (fetchProvider, writeProvider, sourceId) => {
104
107
  return useMemo(() => {
@@ -2,7 +2,6 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
2
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
3
3
  import uuid from 'uuid';
4
4
  import { rebaseTransaction } from '../common/rebase-transaction';
5
- import { resourceIdFromSourceAndLocalId } from '../utils/ari';
6
5
  import { convertSyncBlockPMNodeToSyncBlockData, createBodiedSyncBlockNode } from '../utils/utils';
7
6
  export class SourceSyncBlockStoreManager {
8
7
  constructor(dataProvider) {
@@ -106,12 +105,10 @@ export class SourceSyncBlockStoreManager {
106
105
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
107
106
  const localId = uuid();
108
107
  const sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
109
- if (!sourceId) {
108
+ if (!this.dataProvider || !sourceId) {
110
109
  throw new Error('Provider of sync block plugin is not set');
111
110
  }
112
-
113
- // This should be generated by the data provider implementation as it differs between data providers
114
- const resourceId = resourceIdFromSourceAndLocalId(sourceId, localId);
111
+ const resourceId = this.dataProvider.generateResourceId(sourceId, localId);
115
112
  return {
116
113
  resourceId,
117
114
  localId
@@ -25,7 +25,37 @@ export const getPageARIFromResourceId = resourceId => {
25
25
  }
26
26
  throw new Error(`Invalid resourceId: ${resourceId}`);
27
27
  };
28
- export const getContentPropertyAri = (contentPropertyId, cloudId) => `ari:cloud:confluence:${cloudId}:content/${contentPropertyId}`;
29
28
  export const resourceIdFromSourceAndLocalId = (sourceId, localId) => {
30
29
  return sourceId + '/' + localId;
30
+ };
31
+
32
+ /**
33
+ * For the following functions, they are used for the block service API provider.
34
+ * The resourceId/blockResourceId always refers to the block ARI.
35
+ */
36
+
37
+ /**
38
+ * @param sourceId - the ARI of the document. E.G ari:cloud:confluence:cloudId:page/pageId
39
+ * @param localId - the localId of the block node. A randomly generated UUID
40
+ * @returns the block ARI. E.G ari:cloud:blocks:cloudId:synced-block/localId
41
+ */
42
+ export const blockResourceIdFromSourceAndLocalId = (sourceId, localId) => {
43
+ const match = sourceId.match(/ari:cloud:confluence:([^:]+):(page|blogpost)\/.*/);
44
+ if (!(match !== null && match !== void 0 && match[1])) {
45
+ throw new Error(`Invalid source ARI: ${sourceId}`);
46
+ }
47
+ const cloudId = match[1];
48
+ return `ari:cloud:blocks:${cloudId}:synced-block/${localId}`;
49
+ };
50
+
51
+ /**
52
+ * @param ari - the block ARI. E.G ari:cloud:blocks:cloudId:synced-block/localId
53
+ * @returns the localId of the block node. A randomly generated UUID
54
+ */
55
+ export const getLocalIdFromResourceId = ari => {
56
+ const match = ari.match(/ari:cloud:confluence:[^:]+:(page|blogpost)\/\d+\/([a-zA-Z0-9-]+)/);
57
+ if (match !== null && match !== void 0 && match[2]) {
58
+ return match[2];
59
+ }
60
+ throw new Error(`Invalid page ARI: ${ari}`);
31
61
  };
@@ -0,0 +1,71 @@
1
+ const COMMON_HEADERS = {
2
+ 'Content-Type': 'application/json',
3
+ Accept: 'application/json'
4
+ };
5
+ const BLOCK_SERVICE_API_URL = '/gateway/api/blocks/v1';
6
+ export class BlockError extends Error {
7
+ constructor(status) {
8
+ super(`Block error`);
9
+ this.status = status;
10
+ }
11
+ }
12
+ export const getSyncedBlockContent = async ({
13
+ blockAri
14
+ }) => {
15
+ const response = await fetch(`${BLOCK_SERVICE_API_URL}/block/${blockAri}`, {
16
+ method: 'GET',
17
+ headers: COMMON_HEADERS
18
+ });
19
+ if (!response.ok) {
20
+ throw new BlockError(response.status);
21
+ }
22
+ return await response.json();
23
+ };
24
+ export const deleteSyncedBlock = async ({
25
+ blockAri
26
+ }) => {
27
+ const response = await fetch(`${BLOCK_SERVICE_API_URL}/block/${blockAri}`, {
28
+ method: 'DELETE',
29
+ headers: COMMON_HEADERS
30
+ });
31
+ if (!response.ok) {
32
+ throw new BlockError(response.status);
33
+ }
34
+ };
35
+ export const updateSyncedBlock = async ({
36
+ blockAri,
37
+ content
38
+ }) => {
39
+ const response = await fetch(`${BLOCK_SERVICE_API_URL}/block/${blockAri}`, {
40
+ method: 'PUT',
41
+ headers: COMMON_HEADERS,
42
+ body: JSON.stringify({
43
+ content
44
+ })
45
+ });
46
+ if (!response.ok) {
47
+ throw new BlockError(response.status);
48
+ }
49
+ };
50
+ export const createSyncedBlock = async ({
51
+ blockAri,
52
+ blockInstanceId,
53
+ sourceAri,
54
+ product,
55
+ content
56
+ }) => {
57
+ const response = await fetch(`${BLOCK_SERVICE_API_URL}/block/${blockAri}`, {
58
+ method: 'POST',
59
+ headers: COMMON_HEADERS,
60
+ body: JSON.stringify({
61
+ blockInstanceId,
62
+ sourceAri,
63
+ product,
64
+ content
65
+ })
66
+ });
67
+ if (!response.ok) {
68
+ throw new BlockError(response.status);
69
+ }
70
+ return await response.json();
71
+ };
package/dist/esm/index.js CHANGED
@@ -5,10 +5,11 @@ export { SyncBlockError } from './common/types';
5
5
  export { useFetchSyncBlockData } from './hooks/useFetchSyncBlockData';
6
6
  export { useFetchSyncBlockTitle } from './hooks/useFetchSyncBlockTitle';
7
7
  export { useHandleContentChanges } from './hooks/useHandleContentChanges';
8
+ export { useMemoizedBlockServiceAPIProviders } from './providers/block-service/blockServiceAPI';
8
9
  export { createContentAPIProvidersWithDefaultKey, useMemoizedContentAPIProviders } from './providers/confluence/confluenceContentAPI';
9
10
  export { SyncBlockProvider as SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
10
11
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
11
12
  export { SyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
12
- export { getConfluencePageAri, getPageIdAndTypeFromAri } from './utils/ari';
13
+ export { blockResourceIdFromSourceAndLocalId, getConfluencePageAri, getLocalIdFromAri, getLocalIdFromResourceId, getPageARIFromResourceId, getPageIdAndTypeFromAri, resourceIdFromSourceAndLocalId } from './utils/ari';
13
14
  export { createSyncBlockNode, convertSyncBlockPMNodeToSyncBlockData, convertSyncBlockJSONNodeToSyncBlockNode } from './utils/utils';
14
15
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
@@ -0,0 +1,231 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
+ import _createClass from "@babel/runtime/helpers/createClass";
4
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
5
+ import { useMemo } from 'react';
6
+ import { SyncBlockError } from '../../common/types';
7
+ import { blockResourceIdFromSourceAndLocalId, getLocalIdFromResourceId } from '../../utils/ari';
8
+ import { BlockError, createSyncedBlock, deleteSyncedBlock, getSyncedBlockContent, updateSyncedBlock } from '../../utils/blockService';
9
+ import { stringifyError } from '../../utils/errorHandling';
10
+ var mapBlockError = function mapBlockError(error) {
11
+ switch (error.status) {
12
+ case 403:
13
+ return SyncBlockError.Forbidden;
14
+ case 404:
15
+ return SyncBlockError.NotFound;
16
+ }
17
+ return SyncBlockError.Errored;
18
+ };
19
+
20
+ /**
21
+ * ADFFetchProvider implementation that fetches synced block data from Block Service API
22
+ */
23
+ var BlockServiceADFFetchProvider = /*#__PURE__*/function () {
24
+ function BlockServiceADFFetchProvider() {
25
+ _classCallCheck(this, BlockServiceADFFetchProvider);
26
+ }
27
+ return _createClass(BlockServiceADFFetchProvider, [{
28
+ key: "fetchData",
29
+ value: // resourceId is the ARI of the block. E.G ari:cloud:blocks:site-123:synced-block/uuid-456
30
+ // in the content API provider, this was the concatenation of the source document's ARI and the local ID. E.G ari:cloud:confluence:site-123:page/pageId/uuid-456
31
+ function () {
32
+ var _fetchData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(resourceId) {
33
+ var localId, blockContentResponse, value, syncedBlockData;
34
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
35
+ while (1) switch (_context.prev = _context.next) {
36
+ case 0:
37
+ localId = getLocalIdFromResourceId(resourceId);
38
+ _context.prev = 1;
39
+ _context.next = 4;
40
+ return getSyncedBlockContent({
41
+ blockAri: resourceId
42
+ });
43
+ case 4:
44
+ blockContentResponse = _context.sent;
45
+ value = blockContentResponse.content;
46
+ if (value) {
47
+ _context.next = 8;
48
+ break;
49
+ }
50
+ return _context.abrupt("return", {
51
+ error: SyncBlockError.NotFound,
52
+ resourceId: resourceId
53
+ });
54
+ case 8:
55
+ // Parse the synced block content from the response's content
56
+ syncedBlockData = JSON.parse(value);
57
+ return _context.abrupt("return", {
58
+ data: {
59
+ content: syncedBlockData,
60
+ resourceId: resourceId,
61
+ blockInstanceId: localId
62
+ },
63
+ resourceId: resourceId
64
+ });
65
+ case 12:
66
+ _context.prev = 12;
67
+ _context.t0 = _context["catch"](1);
68
+ if (!(_context.t0 instanceof BlockError)) {
69
+ _context.next = 16;
70
+ break;
71
+ }
72
+ return _context.abrupt("return", {
73
+ error: mapBlockError(_context.t0),
74
+ resourceId: resourceId
75
+ });
76
+ case 16:
77
+ return _context.abrupt("return", {
78
+ error: SyncBlockError.Errored,
79
+ resourceId: resourceId
80
+ });
81
+ case 17:
82
+ case "end":
83
+ return _context.stop();
84
+ }
85
+ }, _callee, null, [[1, 12]]);
86
+ }));
87
+ function fetchData(_x) {
88
+ return _fetchData.apply(this, arguments);
89
+ }
90
+ return fetchData;
91
+ }()
92
+ }]);
93
+ }();
94
+ /**
95
+ * ADFWriteProvider implementation that writes synced block data to Block Service API
96
+ */
97
+ var BlockServiceADFWriteProvider = /*#__PURE__*/function () {
98
+ function BlockServiceADFWriteProvider() {
99
+ _classCallCheck(this, BlockServiceADFWriteProvider);
100
+ }
101
+ return _createClass(BlockServiceADFWriteProvider, [{
102
+ key: "writeData",
103
+ value: // it will first try to update and if it can't (404) then it will try to create
104
+ function () {
105
+ var _writeData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(data) {
106
+ var resourceId;
107
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
108
+ while (1) switch (_context2.prev = _context2.next) {
109
+ case 0:
110
+ resourceId = data.resourceId;
111
+ _context2.prev = 1;
112
+ _context2.next = 4;
113
+ return updateSyncedBlock({
114
+ blockAri: resourceId,
115
+ content: JSON.stringify(data.content)
116
+ });
117
+ case 4:
118
+ return _context2.abrupt("return", {
119
+ resourceId: resourceId
120
+ });
121
+ case 7:
122
+ _context2.prev = 7;
123
+ _context2.t0 = _context2["catch"](1);
124
+ if (!(_context2.t0 instanceof BlockError)) {
125
+ _context2.next = 16;
126
+ break;
127
+ }
128
+ if (!(_context2.t0.status === 404)) {
129
+ _context2.next = 15;
130
+ break;
131
+ }
132
+ _context2.next = 13;
133
+ return createSyncedBlock({
134
+ blockAri: resourceId,
135
+ blockInstanceId: data.blockInstanceId,
136
+ sourceAri: resourceId,
137
+ product: 'confluence-page',
138
+ content: JSON.stringify(data.content)
139
+ });
140
+ case 13:
141
+ _context2.next = 16;
142
+ break;
143
+ case 15:
144
+ return _context2.abrupt("return", {
145
+ error: mapBlockError(_context2.t0),
146
+ resourceId: resourceId
147
+ });
148
+ case 16:
149
+ return _context2.abrupt("return", {
150
+ error: stringifyError(_context2.t0),
151
+ resourceId: resourceId
152
+ });
153
+ case 17:
154
+ case "end":
155
+ return _context2.stop();
156
+ }
157
+ }, _callee2, null, [[1, 7]]);
158
+ }));
159
+ function writeData(_x2) {
160
+ return _writeData.apply(this, arguments);
161
+ }
162
+ return writeData;
163
+ }() // soft deletes the source synced block
164
+ }, {
165
+ key: "deleteData",
166
+ value: function () {
167
+ var _deleteData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(resourceId) {
168
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
169
+ while (1) switch (_context3.prev = _context3.next) {
170
+ case 0:
171
+ _context3.prev = 0;
172
+ _context3.next = 3;
173
+ return deleteSyncedBlock({
174
+ blockAri: resourceId
175
+ });
176
+ case 3:
177
+ return _context3.abrupt("return", {
178
+ resourceId: resourceId,
179
+ success: true,
180
+ error: undefined
181
+ });
182
+ case 6:
183
+ _context3.prev = 6;
184
+ _context3.t0 = _context3["catch"](0);
185
+ if (!(_context3.t0 instanceof BlockError)) {
186
+ _context3.next = 10;
187
+ break;
188
+ }
189
+ return _context3.abrupt("return", {
190
+ resourceId: resourceId,
191
+ success: false,
192
+ error: mapBlockError(_context3.t0)
193
+ });
194
+ case 10:
195
+ return _context3.abrupt("return", {
196
+ resourceId: resourceId,
197
+ success: false,
198
+ error: stringifyError(_context3.t0)
199
+ });
200
+ case 11:
201
+ case "end":
202
+ return _context3.stop();
203
+ }
204
+ }, _callee3, null, [[0, 6]]);
205
+ }));
206
+ function deleteData(_x3) {
207
+ return _deleteData.apply(this, arguments);
208
+ }
209
+ return deleteData;
210
+ }()
211
+ }, {
212
+ key: "generateResourceId",
213
+ value: function generateResourceId(sourceId, localId) {
214
+ return blockResourceIdFromSourceAndLocalId(sourceId, localId);
215
+ }
216
+ }]);
217
+ }();
218
+ /**
219
+ * Factory function to create both providers with shared configuration
220
+ */
221
+ var createBlockServiceAPIProviders = function createBlockServiceAPIProviders() {
222
+ var fetchProvider = new BlockServiceADFFetchProvider();
223
+ var writeProvider = new BlockServiceADFWriteProvider();
224
+ return {
225
+ fetchProvider: fetchProvider,
226
+ writeProvider: writeProvider
227
+ };
228
+ };
229
+ export var useMemoizedBlockServiceAPIProviders = function useMemoizedBlockServiceAPIProviders() {
230
+ return useMemo(createBlockServiceAPIProviders, []);
231
+ };
@@ -6,7 +6,7 @@ import _typeof from "@babel/runtime/helpers/typeof";
6
6
  import _regeneratorRuntime from "@babel/runtime/regenerator";
7
7
  import { useMemo } from 'react';
8
8
  import { SyncBlockError } from '../../common/types';
9
- import { getLocalIdFromAri, getPageIdAndTypeFromAri } from '../../utils/ari';
9
+ import { getLocalIdFromAri, getPageIdAndTypeFromAri, resourceIdFromSourceAndLocalId } from '../../utils/ari';
10
10
  import { getContentProperty, createContentProperty, updateContentProperty, deleteContentProperty } from '../../utils/contentProperty';
11
11
  import { stringifyError } from '../../utils/errorHandling';
12
12
  import { isBlogPageType } from '../../utils/utils';
@@ -337,6 +337,11 @@ var ConfluenceADFWriteProvider = /*#__PURE__*/function () {
337
337
  }
338
338
  return deleteData;
339
339
  }()
340
+ }, {
341
+ key: "generateResourceId",
342
+ value: function generateResourceId(sourceId, localId) {
343
+ return resourceIdFromSourceAndLocalId(sourceId, localId);
344
+ }
340
345
  }]);
341
346
  }();
342
347
  /**
@@ -170,6 +170,11 @@ export var SyncBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
170
170
  }
171
171
  return pageARI ? fetchSourceInfo(pageARI, sourceLocalId) : Promise.resolve(undefined);
172
172
  }
173
+ }, {
174
+ key: "generateResourceId",
175
+ value: function generateResourceId(sourceId, localId) {
176
+ return this.writeProvider.generateResourceId(sourceId, localId);
177
+ }
173
178
  }]);
174
179
  }(SyncBlockDataProvider);
175
180
  export var useMemoizedSyncedBlockProvider = function useMemoizedSyncedBlockProvider(fetchProvider, writeProvider, sourceId) {
@@ -6,7 +6,6 @@ import _regeneratorRuntime from "@babel/runtime/regenerator";
6
6
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
7
7
  import uuid from 'uuid';
8
8
  import { rebaseTransaction as _rebaseTransaction } from '../common/rebase-transaction';
9
- import { resourceIdFromSourceAndLocalId } from '../utils/ari';
10
9
  import { convertSyncBlockPMNodeToSyncBlockData, createBodiedSyncBlockNode as _createBodiedSyncBlockNode } from '../utils/utils';
11
10
  export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
12
11
  function SourceSyncBlockStoreManager(dataProvider) {
@@ -158,12 +157,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
158
157
  // eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
159
158
  var localId = uuid();
160
159
  var sourceId = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getSourceId();
161
- if (!sourceId) {
160
+ if (!this.dataProvider || !sourceId) {
162
161
  throw new Error('Provider of sync block plugin is not set');
163
162
  }
164
-
165
- // This should be generated by the data provider implementation as it differs between data providers
166
- var resourceId = resourceIdFromSourceAndLocalId(sourceId, localId);
163
+ var resourceId = this.dataProvider.generateResourceId(sourceId, localId);
167
164
  return {
168
165
  resourceId: resourceId,
169
166
  localId: localId
@@ -28,9 +28,37 @@ export var getPageARIFromResourceId = function getPageARIFromResourceId(resource
28
28
  }
29
29
  throw new Error("Invalid resourceId: ".concat(resourceId));
30
30
  };
31
- export var getContentPropertyAri = function getContentPropertyAri(contentPropertyId, cloudId) {
32
- return "ari:cloud:confluence:".concat(cloudId, ":content/").concat(contentPropertyId);
33
- };
34
31
  export var resourceIdFromSourceAndLocalId = function resourceIdFromSourceAndLocalId(sourceId, localId) {
35
32
  return sourceId + '/' + localId;
33
+ };
34
+
35
+ /**
36
+ * For the following functions, they are used for the block service API provider.
37
+ * The resourceId/blockResourceId always refers to the block ARI.
38
+ */
39
+
40
+ /**
41
+ * @param sourceId - the ARI of the document. E.G ari:cloud:confluence:cloudId:page/pageId
42
+ * @param localId - the localId of the block node. A randomly generated UUID
43
+ * @returns the block ARI. E.G ari:cloud:blocks:cloudId:synced-block/localId
44
+ */
45
+ export var blockResourceIdFromSourceAndLocalId = function blockResourceIdFromSourceAndLocalId(sourceId, localId) {
46
+ var match = sourceId.match(/ari:cloud:confluence:([^:]+):(page|blogpost)\/.*/);
47
+ if (!(match !== null && match !== void 0 && match[1])) {
48
+ throw new Error("Invalid source ARI: ".concat(sourceId));
49
+ }
50
+ var cloudId = match[1];
51
+ return "ari:cloud:blocks:".concat(cloudId, ":synced-block/").concat(localId);
52
+ };
53
+
54
+ /**
55
+ * @param ari - the block ARI. E.G ari:cloud:blocks:cloudId:synced-block/localId
56
+ * @returns the localId of the block node. A randomly generated UUID
57
+ */
58
+ export var getLocalIdFromResourceId = function getLocalIdFromResourceId(ari) {
59
+ var match = ari.match(/ari:cloud:confluence:[^:]+:(page|blogpost)\/\d+\/([a-zA-Z0-9-]+)/);
60
+ if (match !== null && match !== void 0 && match[2]) {
61
+ return match[2];
62
+ }
63
+ throw new Error("Invalid page ARI: ".concat(ari));
36
64
  };