@atlaskit/node-data-provider 4.3.0 → 4.5.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.
@@ -13,14 +13,28 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
13
13
 
14
14
  /**
15
15
  * Represents the aggregated SSR data for all node data providers.
16
- * It's a map where each key is a provider's name and the value is the {@link SsrData} for that provider.
17
- * This structure is used to hydrate the client-side caches.
16
+ * Each key is a provider's name, and the value contains the fetch status, duration,
17
+ * and a map of node data keys to their prefetched data.
18
18
  *
19
19
  * @example
20
+ * ```
20
21
  * {
21
- * 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
22
- * 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
22
+ * mentionProvider: {
23
+ * success: true,
24
+ * duration: 220,
25
+ * data: {
26
+ * 'mention-1': { id: '1', name: 'John Doe' }
27
+ * }
28
+ * },
29
+ * emojiProvider: {
30
+ * success: true,
31
+ * duration: 110,
32
+ * data: {
33
+ * 'emoji-123': { shortName: ':smile:', representation: '😊' }
34
+ * }
35
+ * }
23
36
  * }
37
+ * ```
24
38
  */
25
39
 
26
40
  /**
@@ -43,7 +57,7 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
43
57
  * },
44
58
  * ];
45
59
  *
46
- * window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
60
+ * const data = await prefetchNodeDataProvidersData({
47
61
  * providers,
48
62
  * doc,
49
63
  * timeout: 1_000,
@@ -53,7 +67,7 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
53
67
  *
54
68
  * @param props The properties for prefetching node data.
55
69
  * @returns Record of provider names to their respective SSR data,
56
- * where each SSR data is a record of node data keys to the fetched data.
70
+ * success status, and duration of the fetch operation.
57
71
  */
58
72
  export async function prefetchNodeDataProvidersData({
59
73
  providers,
@@ -91,21 +105,29 @@ export async function prefetchNodeDataProvidersData({
91
105
  provider,
92
106
  timeout
93
107
  }) => {
108
+ const start = performance.now();
109
+ function getDurationFromStart() {
110
+ return Math.min(performance.now() - start, timeout);
111
+ }
94
112
  try {
95
- const timeoutPromise = new Promise(resolve => {
113
+ const timeoutPromise = new Promise((_, reject) => {
96
114
  setTimeout(() => {
97
- resolve([]);
115
+ reject();
98
116
  }, timeout);
99
117
  });
100
118
  const data = await Promise.race([provider.fetchNodesData(nodes), timeoutPromise]);
101
119
  return {
102
120
  provider,
121
+ success: true,
122
+ duration: getDurationFromStart(),
103
123
  nodes,
104
124
  data
105
125
  };
106
126
  } catch {
107
127
  return {
108
128
  provider,
129
+ success: false,
130
+ duration: getDurationFromStart(),
109
131
  nodes,
110
132
  data: []
111
133
  };
@@ -114,15 +136,22 @@ export async function prefetchNodeDataProvidersData({
114
136
  const results = await Promise.all(promises);
115
137
  return results.reduce((acc, {
116
138
  provider,
139
+ success,
140
+ duration,
117
141
  nodes,
118
142
  data
119
143
  }) => {
120
- acc[provider.name] = data.reduce((providerSsrData, nodeData, nodeIndex) => {
144
+ const ssrData = data.reduce((providerSsrData, nodeData, nodeIndex) => {
121
145
  const node = nodes[nodeIndex];
122
146
  const nodeDataKey = provider.nodeDataKey(node);
123
147
  providerSsrData[nodeDataKey] = nodeData;
124
148
  return providerSsrData;
125
149
  }, {});
150
+ acc[provider.name] = {
151
+ data: ssrData,
152
+ success,
153
+ duration
154
+ };
126
155
  return acc;
127
156
  }, {});
128
157
  }
@@ -30,6 +30,11 @@ import { isSSR } from '@atlaskit/editor-common/core-utils';
30
30
  * }
31
31
  */
32
32
 
33
+ /**
34
+ * Represents the payload passed to the callback function when data is fetched.
35
+ * It can either contain an error or the fetched data.
36
+ */
37
+
33
38
  /**
34
39
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
35
40
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -62,16 +67,15 @@ export var NodeDataProvider = /*#__PURE__*/function () {
62
67
  value: function setSSRData() {
63
68
  var ssrData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
64
69
  this.cacheVersion++;
65
- this.cache = Object.entries(ssrData).reduce(function (acc, _ref) {
70
+ this.cache = Object.fromEntries(Object.entries(ssrData).map(function (_ref) {
66
71
  var _ref2 = _slicedToArray(_ref, 2),
67
72
  key = _ref2[0],
68
73
  data = _ref2[1];
69
- acc[key] = {
70
- source: 'ssr',
71
- data: data
72
- };
73
- return acc;
74
- }, {});
74
+ return [key, {
75
+ data: data,
76
+ source: 'ssr'
77
+ }];
78
+ }));
75
79
  }
76
80
 
77
81
  /**
@@ -116,7 +120,7 @@ export var NodeDataProvider = /*#__PURE__*/function () {
116
120
  * ```
117
121
  *
118
122
  * @param node The node (or its ProseMirror representation) for which to fetch data.
119
- * @param callback The function to call when data is available.
123
+ * @param callback The callback function to call with the fetched data or an error.
120
124
  */
121
125
  }, {
122
126
  key: "getData",
@@ -129,48 +133,54 @@ export var NodeDataProvider = /*#__PURE__*/function () {
129
133
  key: "getDataAsync",
130
134
  value: function () {
131
135
  var _getDataAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(node, callback) {
132
- var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
136
+ var jsonNode, _dataKey, dataFromCache, cacheVersionBeforeRequest, dataPromise, data;
133
137
  return _regeneratorRuntime.wrap(function _callee$(_context) {
134
138
  while (1) switch (_context.prev = _context.next) {
135
139
  case 0:
140
+ _context.prev = 0;
136
141
  jsonNode = 'toJSON' in node ? node.toJSON() : node;
137
142
  if (this.isNodeSupported(jsonNode)) {
138
- _context.next = 4;
143
+ _context.next = 5;
139
144
  break;
140
145
  }
141
146
  // eslint-disable-next-line no-console
142
147
  console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
143
148
  return _context.abrupt("return");
144
- case 4:
145
- dataKey = this.nodeDataKey(jsonNode);
146
- dataFromCache = this.cache[dataKey];
149
+ case 5:
150
+ _dataKey = this.nodeDataKey(jsonNode);
151
+ dataFromCache = this.cache[_dataKey];
147
152
  if (!(dataFromCache !== undefined)) {
148
- _context.next = 18;
153
+ _context.next = 20;
149
154
  break;
150
155
  }
151
156
  if (!isPromise(dataFromCache.data)) {
152
- _context.next = 15;
157
+ _context.next = 17;
153
158
  break;
154
159
  }
155
160
  _context.t0 = callback;
156
- _context.next = 11;
161
+ _context.next = 12;
157
162
  return dataFromCache.data;
158
- case 11:
163
+ case 12:
159
164
  _context.t1 = _context.sent;
160
- (0, _context.t0)(_context.t1);
161
- _context.next = 16;
165
+ _context.t2 = {
166
+ data: _context.t1
167
+ };
168
+ (0, _context.t0)(_context.t2);
169
+ _context.next = 18;
162
170
  break;
163
- case 15:
164
- callback(dataFromCache.data);
165
- case 16:
171
+ case 17:
172
+ callback({
173
+ data: dataFromCache.data
174
+ });
175
+ case 18:
166
176
  if (!isSSR()) {
167
- _context.next = 18;
177
+ _context.next = 20;
168
178
  break;
169
179
  }
170
180
  return _context.abrupt("return");
171
- case 18:
181
+ case 20:
172
182
  if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
173
- _context.next = 27;
183
+ _context.next = 29;
174
184
  break;
175
185
  }
176
186
  // Store the current cache version before making the request,
@@ -181,32 +191,44 @@ export var NodeDataProvider = /*#__PURE__*/function () {
181
191
  value = _ref4[0];
182
192
  return value;
183
193
  }); // Store the promise in the cache to avoid multiple requests for the same data
184
- this.cache[dataKey] = {
194
+ this.cache[_dataKey] = {
185
195
  source: 'network',
186
196
  data: dataPromise
187
197
  };
188
- _context.next = 24;
198
+ _context.next = 26;
189
199
  return dataPromise;
190
- case 24:
200
+ case 26:
191
201
  data = _context.sent;
192
202
  // We need to call the callback with the data with result even if the cache version has changed,
193
203
  // so all promises that are waiting for the data can resolve.
194
- callback(data);
204
+ callback({
205
+ data: data
206
+ });
195
207
 
196
208
  // If the cache version has changed, we don't want to use the data from the network
197
209
  // because it could be stale data.
198
210
  if (cacheVersionBeforeRequest === this.cacheVersion) {
199
211
  // Replace promise with the resolved data in the cache
200
- this.cache[dataKey] = {
212
+ this.cache[_dataKey] = {
201
213
  source: 'network',
202
214
  data: data
203
215
  };
204
216
  }
205
- case 27:
217
+ case 29:
218
+ _context.next = 34;
219
+ break;
220
+ case 31:
221
+ _context.prev = 31;
222
+ _context.t3 = _context["catch"](0);
223
+ // If an error occurs, we call the callback with the error
224
+ callback({
225
+ error: _context.t3 instanceof Error ? _context.t3 : new Error(String(_context.t3))
226
+ });
227
+ case 34:
206
228
  case "end":
207
229
  return _context.stop();
208
230
  }
209
- }, _callee, this);
231
+ }, _callee, this, [[0, 31]]);
210
232
  }));
211
233
  function getDataAsync(_x, _x2) {
212
234
  return _getDataAsync.apply(this, arguments);
@@ -235,7 +257,13 @@ export var NodeDataProvider = /*#__PURE__*/function () {
235
257
  var _this = this;
236
258
  return new Promise(function (resolve, reject) {
237
259
  try {
238
- return _this.getData(node, resolve);
260
+ _this.getData(node, function (payload) {
261
+ if (payload.error) {
262
+ reject(payload.error);
263
+ } else {
264
+ resolve(payload.data);
265
+ }
266
+ });
239
267
  } catch (error) {
240
268
  reject(error);
241
269
  }
@@ -8,7 +8,9 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
8
8
  * @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
9
9
  */
10
10
  export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
11
+ // Counter for the total number of visited nodes to limit the traversal.
11
12
  var totalVisitedNodesCount = 0;
13
+ // A map to store the results, with the provider name as the key.
12
14
  var resultMap = providers.reduce(function (acc, _ref) {
13
15
  var provider = _ref.provider;
14
16
  acc[provider.name] = {
@@ -21,6 +23,7 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
21
23
  // It doesn't use `filter` function from `@atlaskit/adf-utils/traverse` because it does not support early stopping.
22
24
  // We need to stop traversing when we reach the maximum number of nodes to visit to support large documents.
23
25
 
26
+ // Create a list of providers for which we still need to find nodes.
24
27
  var providersToLookup = providers.filter(function (_ref2) {
25
28
  var maxNodesToPrefetch = _ref2.maxNodesToPrefetch;
26
29
  return maxNodesToPrefetch > 0;
@@ -30,32 +33,46 @@ export function findNodesToPrefetch(doc, providers, maxNodesToVisit) {
30
33
  return {
31
34
  provider: provider,
32
35
  maxNodesToPrefetch: maxNodesToPrefetch,
33
- foundNodes: 0
36
+ foundNodes: 0 // Counter for nodes found for each provider.
34
37
  };
35
38
  });
39
+
40
+ // Queue for the breadth-first search (BFS), starting with the root document node.
36
41
  var nodesToVisit = [doc];
37
42
  var currentIndex = 0;
43
+ // The loop continues as long as there are nodes to visit, providers to look for,
44
+ // and the visited nodes limit has not been reached.
38
45
  while (currentIndex < nodesToVisit.length && providersToLookup.length > 0 && totalVisitedNodesCount < maxNodesToVisit) {
39
46
  totalVisitedNodesCount += 1;
40
47
  var currentNode = nodesToVisit[currentIndex];
41
48
  currentIndex++;
42
49
 
43
- // Using reverse loop to avoid issues with array mutation
50
+ // Using a reverse loop to avoid issues with array mutation (when removing elements).
44
51
  for (var i = providersToLookup.length - 1; i >= 0; i--) {
45
52
  var providerToFind = providersToLookup[i];
53
+
54
+ // Check if the current provider supports this node.
46
55
  if (providerToFind.provider.isNodeSupported(currentNode)) {
56
+ // If provider supports the node, add it to the result map.
47
57
  resultMap[providerToFind.provider.name].nodes.push(currentNode);
58
+ // Increment the count of found nodes for this provider.
48
59
  providerToFind.foundNodes += 1;
60
+
61
+ // If the provider has found enough nodes, remove it from the lookup list.
49
62
  if (providerToFind.foundNodes >= providerToFind.maxNodesToPrefetch) {
50
63
  providersToLookup.splice(i, 1);
51
64
  }
52
65
  }
53
66
  }
67
+
68
+ // If the current node has children, add them to the queue to be visited.
54
69
  if (currentNode.content) {
55
70
  nodesToVisit.push.apply(nodesToVisit, _toConsumableArray(currentNode.content.filter(function (node) {
56
71
  return node !== undefined;
57
72
  })));
58
73
  }
59
74
  }
75
+
76
+ // Return an array of the found nodes, grouped by provider.
60
77
  return Object.values(resultMap);
61
78
  }
@@ -15,14 +15,28 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
15
15
 
16
16
  /**
17
17
  * Represents the aggregated SSR data for all node data providers.
18
- * It's a map where each key is a provider's name and the value is the {@link SsrData} for that provider.
19
- * This structure is used to hydrate the client-side caches.
18
+ * Each key is a provider's name, and the value contains the fetch status, duration,
19
+ * and a map of node data keys to their prefetched data.
20
20
  *
21
21
  * @example
22
+ * ```
22
23
  * {
23
- * 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
24
- * 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
24
+ * mentionProvider: {
25
+ * success: true,
26
+ * duration: 220,
27
+ * data: {
28
+ * 'mention-1': { id: '1', name: 'John Doe' }
29
+ * }
30
+ * },
31
+ * emojiProvider: {
32
+ * success: true,
33
+ * duration: 110,
34
+ * data: {
35
+ * 'emoji-123': { shortName: ':smile:', representation: '😊' }
36
+ * }
37
+ * }
25
38
  * }
39
+ * ```
26
40
  */
27
41
 
28
42
  /**
@@ -45,7 +59,7 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
45
59
  * },
46
60
  * ];
47
61
  *
48
- * window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
62
+ * const data = await prefetchNodeDataProvidersData({
49
63
  * providers,
50
64
  * doc,
51
65
  * timeout: 1_000,
@@ -55,7 +69,7 @@ import { findNodesToPrefetch } from './find-nodes-to-prefetch';
55
69
  *
56
70
  * @param props The properties for prefetching node data.
57
71
  * @returns Record of provider names to their respective SSR data,
58
- * where each SSR data is a record of node data keys to the fetched data.
72
+ * success status, and duration of the fetch operation.
59
73
  */
60
74
  export function prefetchNodeDataProvidersData(_x) {
61
75
  return _prefetchNodeDataProvidersData.apply(this, arguments);
@@ -97,39 +111,47 @@ function _prefetchNodeDataProvidersData() {
97
111
  });
98
112
  promises = nodesWithProviders.map( /*#__PURE__*/function () {
99
113
  var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref5) {
100
- var nodes, provider, timeout, timeoutPromise, data;
114
+ var nodes, provider, timeout, start, getDurationFromStart, timeoutPromise, data;
101
115
  return _regeneratorRuntime.wrap(function _callee$(_context) {
102
116
  while (1) switch (_context.prev = _context.next) {
103
117
  case 0:
118
+ getDurationFromStart = function _getDurationFromStart() {
119
+ return Math.min(performance.now() - start, timeout);
120
+ };
104
121
  nodes = _ref5.nodes, provider = _ref5.provider, timeout = _ref5.timeout;
105
- _context.prev = 1;
106
- timeoutPromise = new Promise(function (resolve) {
122
+ start = performance.now();
123
+ _context.prev = 3;
124
+ timeoutPromise = new Promise(function (_, reject) {
107
125
  setTimeout(function () {
108
- resolve([]);
126
+ reject();
109
127
  }, timeout);
110
128
  });
111
- _context.next = 5;
129
+ _context.next = 7;
112
130
  return Promise.race([provider.fetchNodesData(nodes), timeoutPromise]);
113
- case 5:
131
+ case 7:
114
132
  data = _context.sent;
115
133
  return _context.abrupt("return", {
116
134
  provider: provider,
135
+ success: true,
136
+ duration: getDurationFromStart(),
117
137
  nodes: nodes,
118
138
  data: data
119
139
  });
120
- case 9:
121
- _context.prev = 9;
122
- _context.t0 = _context["catch"](1);
140
+ case 11:
141
+ _context.prev = 11;
142
+ _context.t0 = _context["catch"](3);
123
143
  return _context.abrupt("return", {
124
144
  provider: provider,
145
+ success: false,
146
+ duration: getDurationFromStart(),
125
147
  nodes: nodes,
126
148
  data: []
127
149
  });
128
- case 12:
150
+ case 14:
129
151
  case "end":
130
152
  return _context.stop();
131
153
  }
132
- }, _callee, null, [[1, 9]]);
154
+ }, _callee, null, [[3, 11]]);
133
155
  }));
134
156
  return function (_x2) {
135
157
  return _ref6.apply(this, arguments);
@@ -141,14 +163,21 @@ function _prefetchNodeDataProvidersData() {
141
163
  results = _context2.sent;
142
164
  return _context2.abrupt("return", results.reduce(function (acc, _ref7) {
143
165
  var provider = _ref7.provider,
166
+ success = _ref7.success,
167
+ duration = _ref7.duration,
144
168
  nodes = _ref7.nodes,
145
169
  data = _ref7.data;
146
- acc[provider.name] = data.reduce(function (providerSsrData, nodeData, nodeIndex) {
170
+ var ssrData = data.reduce(function (providerSsrData, nodeData, nodeIndex) {
147
171
  var node = nodes[nodeIndex];
148
172
  var nodeDataKey = provider.nodeDataKey(node);
149
173
  providerSsrData[nodeDataKey] = nodeData;
150
174
  return providerSsrData;
151
175
  }, {});
176
+ acc[provider.name] = {
177
+ data: ssrData,
178
+ success: success,
179
+ duration: duration
180
+ };
152
181
  return acc;
153
182
  }, {}));
154
183
  case 9:
@@ -13,6 +13,19 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
13
13
  type SSRData<Data> = {
14
14
  [dataKey: string]: Data;
15
15
  };
16
+ /**
17
+ * Represents the payload passed to the callback function when data is fetched.
18
+ * It can either contain an error or the fetched data.
19
+ */
20
+ type CallbackPayload<Data> = {
21
+ /** An error that occurred while fetching data. */
22
+ error: Error;
23
+ data?: undefined;
24
+ } | {
25
+ /** Fetched data for the node. */
26
+ data: Data;
27
+ error?: undefined;
28
+ };
16
29
  /**
17
30
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
18
31
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -100,9 +113,9 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
100
113
  * ```
101
114
  *
102
115
  * @param node The node (or its ProseMirror representation) for which to fetch data.
103
- * @param callback The function to call when data is available.
116
+ * @param callback The callback function to call with the fetched data or an error.
104
117
  */
105
- getData(node: Node | PMNode, callback: (data: Data) => void): void;
118
+ getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
106
119
  private getDataAsync;
107
120
  /**
108
121
  * Fetches data for a given node and returns it as a Promise.
@@ -15,17 +15,35 @@ type SsrData = {
15
15
  };
16
16
  /**
17
17
  * Represents the aggregated SSR data for all node data providers.
18
- * It's a map where each key is a provider's name and the value is the {@link SsrData} for that provider.
19
- * This structure is used to hydrate the client-side caches.
18
+ * Each key is a provider's name, and the value contains the fetch status, duration,
19
+ * and a map of node data keys to their prefetched data.
20
20
  *
21
21
  * @example
22
+ * ```
22
23
  * {
23
- * 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
24
- * 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
24
+ * mentionProvider: {
25
+ * success: true,
26
+ * duration: 220,
27
+ * data: {
28
+ * 'mention-1': { id: '1', name: 'John Doe' }
29
+ * }
30
+ * },
31
+ * emojiProvider: {
32
+ * success: true,
33
+ * duration: 110,
34
+ * data: {
35
+ * 'emoji-123': { shortName: ':smile:', representation: '😊' }
36
+ * }
37
+ * }
25
38
  * }
39
+ * ```
26
40
  */
27
41
  type NodeDataProvidersSsrData = {
28
- [providerName: string]: SsrData;
42
+ [providerName: string]: {
43
+ success: boolean;
44
+ duration: number;
45
+ data: SsrData;
46
+ };
29
47
  };
30
48
  interface Props {
31
49
  /**
@@ -91,7 +109,7 @@ interface Props {
91
109
  * },
92
110
  * ];
93
111
  *
94
- * window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
112
+ * const data = await prefetchNodeDataProvidersData({
95
113
  * providers,
96
114
  * doc,
97
115
  * timeout: 1_000,
@@ -101,7 +119,7 @@ interface Props {
101
119
  *
102
120
  * @param props The properties for prefetching node data.
103
121
  * @returns Record of provider names to their respective SSR data,
104
- * where each SSR data is a record of node data keys to the fetched data.
122
+ * success status, and duration of the fetch operation.
105
123
  */
106
124
  export declare function prefetchNodeDataProvidersData({ providers, doc, timeout, maxNodesToVisit, }: Props): Promise<NodeDataProvidersSsrData>;
107
125
  export {};
@@ -13,6 +13,19 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
13
13
  type SSRData<Data> = {
14
14
  [dataKey: string]: Data;
15
15
  };
16
+ /**
17
+ * Represents the payload passed to the callback function when data is fetched.
18
+ * It can either contain an error or the fetched data.
19
+ */
20
+ type CallbackPayload<Data> = {
21
+ /** An error that occurred while fetching data. */
22
+ error: Error;
23
+ data?: undefined;
24
+ } | {
25
+ /** Fetched data for the node. */
26
+ data: Data;
27
+ error?: undefined;
28
+ };
16
29
  /**
17
30
  * A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
18
31
  * It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
@@ -100,9 +113,9 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
100
113
  * ```
101
114
  *
102
115
  * @param node The node (or its ProseMirror representation) for which to fetch data.
103
- * @param callback The function to call when data is available.
116
+ * @param callback The callback function to call with the fetched data or an error.
104
117
  */
105
- getData(node: Node | PMNode, callback: (data: Data) => void): void;
118
+ getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
106
119
  private getDataAsync;
107
120
  /**
108
121
  * Fetches data for a given node and returns it as a Promise.
@@ -15,17 +15,35 @@ type SsrData = {
15
15
  };
16
16
  /**
17
17
  * Represents the aggregated SSR data for all node data providers.
18
- * It's a map where each key is a provider's name and the value is the {@link SsrData} for that provider.
19
- * This structure is used to hydrate the client-side caches.
18
+ * Each key is a provider's name, and the value contains the fetch status, duration,
19
+ * and a map of node data keys to their prefetched data.
20
20
  *
21
21
  * @example
22
+ * ```
22
23
  * {
23
- * 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
24
- * 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
24
+ * mentionProvider: {
25
+ * success: true,
26
+ * duration: 220,
27
+ * data: {
28
+ * 'mention-1': { id: '1', name: 'John Doe' }
29
+ * }
30
+ * },
31
+ * emojiProvider: {
32
+ * success: true,
33
+ * duration: 110,
34
+ * data: {
35
+ * 'emoji-123': { shortName: ':smile:', representation: '😊' }
36
+ * }
37
+ * }
25
38
  * }
39
+ * ```
26
40
  */
27
41
  type NodeDataProvidersSsrData = {
28
- [providerName: string]: SsrData;
42
+ [providerName: string]: {
43
+ success: boolean;
44
+ duration: number;
45
+ data: SsrData;
46
+ };
29
47
  };
30
48
  interface Props {
31
49
  /**
@@ -91,7 +109,7 @@ interface Props {
91
109
  * },
92
110
  * ];
93
111
  *
94
- * window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
112
+ * const data = await prefetchNodeDataProvidersData({
95
113
  * providers,
96
114
  * doc,
97
115
  * timeout: 1_000,
@@ -101,7 +119,7 @@ interface Props {
101
119
  *
102
120
  * @param props The properties for prefetching node data.
103
121
  * @returns Record of provider names to their respective SSR data,
104
- * where each SSR data is a record of node data keys to the fetched data.
122
+ * success status, and duration of the fetch operation.
105
123
  */
106
124
  export declare function prefetchNodeDataProvidersData({ providers, doc, timeout, maxNodesToVisit, }: Props): Promise<NodeDataProvidersSsrData>;
107
125
  export {};