@atlaskit/node-data-provider 7.3.0 → 7.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.
- package/CHANGELOG.md +20 -0
- package/dist/cjs/index.js +0 -6
- package/dist/cjs/node-data-provider.js +78 -70
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/node-data-provider.js +68 -51
- package/dist/esm/index.js +1 -1
- package/dist/esm/node-data-provider.js +78 -70
- package/dist/types/index.d.ts +1 -1
- package/dist/types/node-data-provider.d.ts +25 -9
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/dist/types-ts4.5/node-data-provider.d.ts +25 -9
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/node-data-provider
|
|
2
2
|
|
|
3
|
+
## 7.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`e3f45edd75547`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e3f45edd75547) -
|
|
8
|
+
[https://product-fabric.atlassian.net/browse/ED-29647](ED-29647) - OTP will not use network data
|
|
9
|
+
if preloaded data is unavailable during SSR rendering
|
|
10
|
+
|
|
11
|
+
## 7.4.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`fdba2e94783b7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fdba2e94783b7) -
|
|
16
|
+
[https://product-fabric.atlassian.net/browse/ED-29638](ED-29638) - fix editor NodeDataProvider
|
|
17
|
+
network requests deduplication
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
|
|
3
23
|
## 7.3.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/dist/cjs/index.js
CHANGED
|
@@ -15,12 +15,6 @@ Object.defineProperty(exports, "findNodesToPrefetch", {
|
|
|
15
15
|
return _findNodesToPrefetch.findNodesToPrefetch;
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
|
-
Object.defineProperty(exports, "isPromise", {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: function get() {
|
|
21
|
-
return _nodeDataProvider.isPromise;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
18
|
Object.defineProperty(exports, "prefetchNodeDataProvidersData", {
|
|
25
19
|
enumerable: true,
|
|
26
20
|
get: function get() {
|
|
@@ -5,9 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.NodeDataProvider = void 0;
|
|
8
|
-
exports.isPromise = isPromise;
|
|
9
8
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
10
|
-
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
11
9
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
12
10
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
11
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
@@ -32,7 +30,7 @@ var _coreUtils = require("@atlaskit/editor-common/core-utils");
|
|
|
32
30
|
* @example
|
|
33
31
|
* {
|
|
34
32
|
* 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
|
|
35
|
-
* 'node-id-2': { source: 'network', data:
|
|
33
|
+
* 'node-id-2': { source: 'network', data: { value: 'other data' } }
|
|
36
34
|
* }
|
|
37
35
|
*/
|
|
38
36
|
/**
|
|
@@ -51,6 +49,7 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
|
|
|
51
49
|
(0, _classCallCheck2.default)(this, NodeDataProvider);
|
|
52
50
|
this.cacheVersion = 0;
|
|
53
51
|
this.cache = {};
|
|
52
|
+
this.networkRequestsInFlight = {};
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
/**
|
|
@@ -137,102 +136,112 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
|
|
|
137
136
|
key: "getDataAsync",
|
|
138
137
|
value: function () {
|
|
139
138
|
var _getDataAsync = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(node, callback) {
|
|
140
|
-
var jsonNode,
|
|
139
|
+
var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, networkRequestInFlightKey, networkRequestInFlight, data, dataPromise, _data;
|
|
141
140
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
142
141
|
while (1) switch (_context.prev = _context.next) {
|
|
143
142
|
case 0:
|
|
144
|
-
_context.prev = 0;
|
|
145
143
|
jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
146
144
|
if (this.isNodeSupported(jsonNode)) {
|
|
147
|
-
_context.next =
|
|
145
|
+
_context.next = 4;
|
|
148
146
|
break;
|
|
149
147
|
}
|
|
150
148
|
// eslint-disable-next-line no-console
|
|
151
149
|
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
152
150
|
return _context.abrupt("return");
|
|
153
|
-
case
|
|
154
|
-
|
|
155
|
-
dataFromCache = this.cache[
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
_context.next = 17;
|
|
162
|
-
break;
|
|
151
|
+
case 4:
|
|
152
|
+
dataKey = this.nodeDataKey(jsonNode);
|
|
153
|
+
dataFromCache = this.cache[dataKey];
|
|
154
|
+
if (dataFromCache !== undefined) {
|
|
155
|
+
// If we have the data in the SSR data, we can use it directly
|
|
156
|
+
callback({
|
|
157
|
+
data: dataFromCache.data
|
|
158
|
+
});
|
|
163
159
|
}
|
|
164
|
-
_context.t0 = callback;
|
|
165
|
-
_context.next = 12;
|
|
166
|
-
return dataFromCache.data;
|
|
167
|
-
case 12:
|
|
168
|
-
_context.t1 = _context.sent;
|
|
169
|
-
_context.t2 = {
|
|
170
|
-
data: _context.t1
|
|
171
|
-
};
|
|
172
|
-
(0, _context.t0)(_context.t2);
|
|
173
|
-
_context.next = 18;
|
|
174
|
-
break;
|
|
175
|
-
case 17:
|
|
176
|
-
callback({
|
|
177
|
-
data: dataFromCache.data
|
|
178
|
-
});
|
|
179
|
-
case 18:
|
|
180
160
|
if (!(0, _coreUtils.isSSR)()) {
|
|
181
|
-
_context.next =
|
|
161
|
+
_context.next = 9;
|
|
182
162
|
break;
|
|
183
163
|
}
|
|
184
164
|
return _context.abrupt("return");
|
|
185
|
-
case
|
|
165
|
+
case 9:
|
|
186
166
|
if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
|
|
187
|
-
_context.next =
|
|
167
|
+
_context.next = 41;
|
|
188
168
|
break;
|
|
189
169
|
}
|
|
190
170
|
// Store the current cache version before making the request,
|
|
191
171
|
// so we can check if the cache has changed while we are waiting for the network response.
|
|
192
|
-
cacheVersionBeforeRequest = this.cacheVersion;
|
|
172
|
+
cacheVersionBeforeRequest = this.cacheVersion; // Create a unique key for the in-flight network request
|
|
173
|
+
// based on the cache version and the data key.
|
|
174
|
+
networkRequestInFlightKey = "".concat(cacheVersionBeforeRequest, "-").concat(dataKey); // Check if there is already a network request in flight for this data
|
|
175
|
+
// to avoid duplicate requests.
|
|
176
|
+
networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
177
|
+
if (!networkRequestInFlight) {
|
|
178
|
+
_context.next = 25;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
_context.prev = 14;
|
|
182
|
+
_context.next = 17;
|
|
183
|
+
return networkRequestInFlight;
|
|
184
|
+
case 17:
|
|
185
|
+
data = _context.sent;
|
|
186
|
+
callback({
|
|
187
|
+
data: data
|
|
188
|
+
});
|
|
189
|
+
_context.next = 24;
|
|
190
|
+
break;
|
|
191
|
+
case 21:
|
|
192
|
+
_context.prev = 21;
|
|
193
|
+
_context.t0 = _context["catch"](14);
|
|
194
|
+
callback({
|
|
195
|
+
error: _context.t0 instanceof Error ? _context.t0 : new Error(String(_context.t0))
|
|
196
|
+
});
|
|
197
|
+
case 24:
|
|
198
|
+
return _context.abrupt("return");
|
|
199
|
+
case 25:
|
|
200
|
+
_context.prev = 25;
|
|
193
201
|
dataPromise = this.fetchNodesData([jsonNode]).then(function (_ref3) {
|
|
194
202
|
var _ref4 = (0, _slicedToArray2.default)(_ref3, 1),
|
|
195
203
|
value = _ref4[0];
|
|
196
204
|
return value;
|
|
197
|
-
}); // Store the promise in the
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
data: dataPromise
|
|
201
|
-
};
|
|
202
|
-
_context.next = 26;
|
|
205
|
+
}); // Store the promise in the in-flight requests map
|
|
206
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
207
|
+
_context.next = 30;
|
|
203
208
|
return dataPromise;
|
|
204
|
-
case
|
|
205
|
-
|
|
209
|
+
case 30:
|
|
210
|
+
_data = _context.sent;
|
|
206
211
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
207
212
|
// so all promises that are waiting for the data can resolve.
|
|
208
213
|
callback({
|
|
209
|
-
data:
|
|
214
|
+
data: _data
|
|
210
215
|
});
|
|
211
216
|
|
|
212
217
|
// If the cache version has changed, we don't want to use the data from the network
|
|
213
218
|
// because it could be stale data.
|
|
214
219
|
if (cacheVersionBeforeRequest === this.cacheVersion) {
|
|
215
220
|
// Replace promise with the resolved data in the cache
|
|
216
|
-
this.cache[
|
|
221
|
+
this.cache[dataKey] = {
|
|
217
222
|
source: 'network',
|
|
218
|
-
data:
|
|
223
|
+
data: _data
|
|
219
224
|
};
|
|
220
225
|
}
|
|
221
|
-
|
|
222
|
-
_context.next = 34;
|
|
226
|
+
_context.next = 38;
|
|
223
227
|
break;
|
|
224
|
-
case
|
|
225
|
-
_context.prev =
|
|
226
|
-
_context.
|
|
228
|
+
case 35:
|
|
229
|
+
_context.prev = 35;
|
|
230
|
+
_context.t1 = _context["catch"](25);
|
|
227
231
|
// If an error occurs, we call the callback with the error
|
|
228
232
|
callback({
|
|
229
|
-
error: _context.
|
|
233
|
+
error: _context.t1 instanceof Error ? _context.t1 : new Error(String(_context.t1))
|
|
230
234
|
});
|
|
231
|
-
case
|
|
235
|
+
case 38:
|
|
236
|
+
_context.prev = 38;
|
|
237
|
+
// Ensure we clean up the in-flight request entry
|
|
238
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
239
|
+
return _context.finish(38);
|
|
240
|
+
case 41:
|
|
232
241
|
case "end":
|
|
233
242
|
return _context.stop();
|
|
234
243
|
}
|
|
235
|
-
}, _callee, this, [[
|
|
244
|
+
}, _callee, this, [[14, 21], [25, 35, 38, 41]]);
|
|
236
245
|
}));
|
|
237
246
|
function getDataAsync(_x, _x2) {
|
|
238
247
|
return _getDataAsync.apply(this, arguments);
|
|
@@ -288,28 +297,27 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
|
|
|
288
297
|
}, {
|
|
289
298
|
key: "getCacheStatusForNode",
|
|
290
299
|
value: function getCacheStatusForNode(node) {
|
|
291
|
-
var
|
|
292
|
-
if (!this.isNodeSupported(jsonNode)) {
|
|
293
|
-
// eslint-disable-next-line no-console
|
|
294
|
-
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
var dataKey = this.nodeDataKey(jsonNode);
|
|
298
|
-
var dataFromCache = this.cache[dataKey];
|
|
300
|
+
var dataFromCache = this.getNodeDataFromCache(node);
|
|
299
301
|
return dataFromCache ? dataFromCache.source : false;
|
|
300
302
|
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Retrieves the cached data for a given node, if available.
|
|
306
|
+
*
|
|
307
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
308
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
309
|
+
*/
|
|
301
310
|
}, {
|
|
302
311
|
key: "getNodeDataFromCache",
|
|
303
312
|
value: function getNodeDataFromCache(node) {
|
|
304
313
|
var jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
314
|
+
if (!this.isNodeSupported(jsonNode)) {
|
|
315
|
+
// eslint-disable-next-line no-console
|
|
316
|
+
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
305
319
|
var dataKey = this.nodeDataKey(jsonNode);
|
|
306
320
|
return this.cache[dataKey];
|
|
307
321
|
}
|
|
308
322
|
}]);
|
|
309
|
-
}();
|
|
310
|
-
/**
|
|
311
|
-
* Checks if value is a promise using hacky heuristics.
|
|
312
|
-
*/
|
|
313
|
-
function isPromise(value) {
|
|
314
|
-
return (0, _typeof2.default)(value) === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
|
|
315
|
-
}
|
|
323
|
+
}();
|
package/dist/es2019/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
2
|
|
|
3
|
-
export { NodeDataProvider
|
|
3
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
4
4
|
export { findNodesToPrefetch } from './utils/find-nodes-to-prefetch';
|
|
5
5
|
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|
|
@@ -20,7 +20,7 @@ import { isSSR } from '@atlaskit/editor-common/core-utils';
|
|
|
20
20
|
* @example
|
|
21
21
|
* {
|
|
22
22
|
* 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
|
|
23
|
-
* 'node-id-2': { source: 'network', data:
|
|
23
|
+
* 'node-id-2': { source: 'network', data: { value: 'other data' } }
|
|
24
24
|
* }
|
|
25
25
|
*/
|
|
26
26
|
|
|
@@ -66,6 +66,7 @@ export class NodeDataProvider {
|
|
|
66
66
|
constructor() {
|
|
67
67
|
this.cacheVersion = 0;
|
|
68
68
|
this.cache = {};
|
|
69
|
+
this.networkRequestsInFlight = {};
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
/**
|
|
@@ -137,45 +138,60 @@ export class NodeDataProvider {
|
|
|
137
138
|
void this.getDataAsync(node, callback);
|
|
138
139
|
}
|
|
139
140
|
async getDataAsync(node, callback) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
141
|
+
const jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
142
|
+
if (!this.isNodeSupported(jsonNode)) {
|
|
143
|
+
// eslint-disable-next-line no-console
|
|
144
|
+
console.error(`The ${this.constructor.name} doesn't support Node ${jsonNode.type}.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const dataKey = this.nodeDataKey(jsonNode);
|
|
148
|
+
const dataFromCache = this.cache[dataKey];
|
|
149
|
+
if (dataFromCache !== undefined) {
|
|
150
|
+
// If we have the data in the SSR data, we can use it directly
|
|
151
|
+
callback({
|
|
152
|
+
data: dataFromCache.data
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (isSSR()) {
|
|
156
|
+
// During SSR, we only use the cache and never fetch from the network.
|
|
157
|
+
// Use loading state instead.
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// If no data is available in the cache, or the data is from the network,
|
|
162
|
+
// we need to fetch it from the network.
|
|
163
|
+
if ((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network') {
|
|
164
|
+
// Store the current cache version before making the request,
|
|
165
|
+
// so we can check if the cache has changed while we are waiting for the network response.
|
|
166
|
+
const cacheVersionBeforeRequest = this.cacheVersion;
|
|
167
|
+
|
|
168
|
+
// Create a unique key for the in-flight network request
|
|
169
|
+
// based on the cache version and the data key.
|
|
170
|
+
const networkRequestInFlightKey = `${cacheVersionBeforeRequest}-${dataKey}`;
|
|
171
|
+
|
|
172
|
+
// Check if there is already a network request in flight for this data
|
|
173
|
+
// to avoid duplicate requests.
|
|
174
|
+
const networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
175
|
+
if (networkRequestInFlight) {
|
|
176
|
+
try {
|
|
177
|
+
const data = await networkRequestInFlight;
|
|
152
178
|
callback({
|
|
153
|
-
data
|
|
179
|
+
data
|
|
154
180
|
});
|
|
155
|
-
}
|
|
181
|
+
} catch (error) {
|
|
156
182
|
callback({
|
|
157
|
-
|
|
183
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
158
184
|
});
|
|
159
185
|
}
|
|
160
|
-
|
|
161
|
-
// If we are in SSR, we don't want to fetch the data again, as it is already available in the SSR data
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
186
|
+
return;
|
|
164
187
|
}
|
|
165
|
-
|
|
166
|
-
// If no data is available in the cache or the data is from the network,
|
|
167
|
-
// we need to fetch it from the network.
|
|
168
|
-
if ((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network') {
|
|
169
|
-
// Store the current cache version before making the request,
|
|
170
|
-
// so we can check if the cache has changed while we are waiting for the network response.
|
|
171
|
-
const cacheVersionBeforeRequest = this.cacheVersion;
|
|
188
|
+
try {
|
|
172
189
|
const dataPromise = this.fetchNodesData([jsonNode]).then(([value]) => value);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
data: dataPromise
|
|
177
|
-
};
|
|
190
|
+
|
|
191
|
+
// Store the promise in the in-flight requests map
|
|
192
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
178
193
|
const data = await dataPromise;
|
|
194
|
+
|
|
179
195
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
180
196
|
// so all promises that are waiting for the data can resolve.
|
|
181
197
|
callback({
|
|
@@ -191,12 +207,15 @@ export class NodeDataProvider {
|
|
|
191
207
|
data
|
|
192
208
|
};
|
|
193
209
|
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
// If an error occurs, we call the callback with the error
|
|
212
|
+
callback({
|
|
213
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
214
|
+
});
|
|
215
|
+
} finally {
|
|
216
|
+
// Ensure we clean up the in-flight request entry
|
|
217
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
194
218
|
}
|
|
195
|
-
} catch (error) {
|
|
196
|
-
// If an error occurs, we call the callback with the error
|
|
197
|
-
callback({
|
|
198
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
199
|
-
});
|
|
200
219
|
}
|
|
201
220
|
}
|
|
202
221
|
|
|
@@ -244,26 +263,24 @@ export class NodeDataProvider {
|
|
|
244
263
|
* @returns The cache status: `false`, `'ssr'`, or `'network'`.
|
|
245
264
|
*/
|
|
246
265
|
getCacheStatusForNode(node) {
|
|
266
|
+
const dataFromCache = this.getNodeDataFromCache(node);
|
|
267
|
+
return dataFromCache ? dataFromCache.source : false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Retrieves the cached data for a given node, if available.
|
|
272
|
+
*
|
|
273
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
274
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
275
|
+
*/
|
|
276
|
+
getNodeDataFromCache(node) {
|
|
247
277
|
const jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
248
278
|
if (!this.isNodeSupported(jsonNode)) {
|
|
249
279
|
// eslint-disable-next-line no-console
|
|
250
280
|
console.error(`The ${this.constructor.name} doesn't support Node ${jsonNode.type}.`);
|
|
251
|
-
return
|
|
281
|
+
return undefined;
|
|
252
282
|
}
|
|
253
283
|
const dataKey = this.nodeDataKey(jsonNode);
|
|
254
|
-
const dataFromCache = this.cache[dataKey];
|
|
255
|
-
return dataFromCache ? dataFromCache.source : false;
|
|
256
|
-
}
|
|
257
|
-
getNodeDataFromCache(node) {
|
|
258
|
-
const jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
259
|
-
const dataKey = this.nodeDataKey(jsonNode);
|
|
260
284
|
return this.cache[dataKey];
|
|
261
285
|
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Checks if value is a promise using hacky heuristics.
|
|
266
|
-
*/
|
|
267
|
-
export function isPromise(value) {
|
|
268
|
-
return typeof value === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
|
|
269
286
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @atlaskit/editor/no-re-export */
|
|
2
2
|
|
|
3
|
-
export { NodeDataProvider
|
|
3
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
4
4
|
export { findNodesToPrefetch } from './utils/find-nodes-to-prefetch';
|
|
5
5
|
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import _typeof from "@babel/runtime/helpers/typeof";
|
|
2
1
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
4
3
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
@@ -26,7 +25,7 @@ import { isSSR } from '@atlaskit/editor-common/core-utils';
|
|
|
26
25
|
* @example
|
|
27
26
|
* {
|
|
28
27
|
* 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
|
|
29
|
-
* 'node-id-2': { source: 'network', data:
|
|
28
|
+
* 'node-id-2': { source: 'network', data: { value: 'other data' } }
|
|
30
29
|
* }
|
|
31
30
|
*/
|
|
32
31
|
|
|
@@ -47,6 +46,7 @@ export var NodeDataProvider = /*#__PURE__*/function () {
|
|
|
47
46
|
_classCallCheck(this, NodeDataProvider);
|
|
48
47
|
this.cacheVersion = 0;
|
|
49
48
|
this.cache = {};
|
|
49
|
+
this.networkRequestsInFlight = {};
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -133,102 +133,112 @@ export var NodeDataProvider = /*#__PURE__*/function () {
|
|
|
133
133
|
key: "getDataAsync",
|
|
134
134
|
value: function () {
|
|
135
135
|
var _getDataAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(node, callback) {
|
|
136
|
-
var jsonNode,
|
|
136
|
+
var jsonNode, dataKey, dataFromCache, cacheVersionBeforeRequest, networkRequestInFlightKey, networkRequestInFlight, data, dataPromise, _data;
|
|
137
137
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
138
138
|
while (1) switch (_context.prev = _context.next) {
|
|
139
139
|
case 0:
|
|
140
|
-
_context.prev = 0;
|
|
141
140
|
jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
142
141
|
if (this.isNodeSupported(jsonNode)) {
|
|
143
|
-
_context.next =
|
|
142
|
+
_context.next = 4;
|
|
144
143
|
break;
|
|
145
144
|
}
|
|
146
145
|
// eslint-disable-next-line no-console
|
|
147
146
|
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
148
147
|
return _context.abrupt("return");
|
|
149
|
-
case
|
|
150
|
-
|
|
151
|
-
dataFromCache = this.cache[
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
_context.next = 17;
|
|
158
|
-
break;
|
|
148
|
+
case 4:
|
|
149
|
+
dataKey = this.nodeDataKey(jsonNode);
|
|
150
|
+
dataFromCache = this.cache[dataKey];
|
|
151
|
+
if (dataFromCache !== undefined) {
|
|
152
|
+
// If we have the data in the SSR data, we can use it directly
|
|
153
|
+
callback({
|
|
154
|
+
data: dataFromCache.data
|
|
155
|
+
});
|
|
159
156
|
}
|
|
160
|
-
_context.t0 = callback;
|
|
161
|
-
_context.next = 12;
|
|
162
|
-
return dataFromCache.data;
|
|
163
|
-
case 12:
|
|
164
|
-
_context.t1 = _context.sent;
|
|
165
|
-
_context.t2 = {
|
|
166
|
-
data: _context.t1
|
|
167
|
-
};
|
|
168
|
-
(0, _context.t0)(_context.t2);
|
|
169
|
-
_context.next = 18;
|
|
170
|
-
break;
|
|
171
|
-
case 17:
|
|
172
|
-
callback({
|
|
173
|
-
data: dataFromCache.data
|
|
174
|
-
});
|
|
175
|
-
case 18:
|
|
176
157
|
if (!isSSR()) {
|
|
177
|
-
_context.next =
|
|
158
|
+
_context.next = 9;
|
|
178
159
|
break;
|
|
179
160
|
}
|
|
180
161
|
return _context.abrupt("return");
|
|
181
|
-
case
|
|
162
|
+
case 9:
|
|
182
163
|
if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
|
|
183
|
-
_context.next =
|
|
164
|
+
_context.next = 41;
|
|
184
165
|
break;
|
|
185
166
|
}
|
|
186
167
|
// Store the current cache version before making the request,
|
|
187
168
|
// so we can check if the cache has changed while we are waiting for the network response.
|
|
188
|
-
cacheVersionBeforeRequest = this.cacheVersion;
|
|
169
|
+
cacheVersionBeforeRequest = this.cacheVersion; // Create a unique key for the in-flight network request
|
|
170
|
+
// based on the cache version and the data key.
|
|
171
|
+
networkRequestInFlightKey = "".concat(cacheVersionBeforeRequest, "-").concat(dataKey); // Check if there is already a network request in flight for this data
|
|
172
|
+
// to avoid duplicate requests.
|
|
173
|
+
networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
174
|
+
if (!networkRequestInFlight) {
|
|
175
|
+
_context.next = 25;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
_context.prev = 14;
|
|
179
|
+
_context.next = 17;
|
|
180
|
+
return networkRequestInFlight;
|
|
181
|
+
case 17:
|
|
182
|
+
data = _context.sent;
|
|
183
|
+
callback({
|
|
184
|
+
data: data
|
|
185
|
+
});
|
|
186
|
+
_context.next = 24;
|
|
187
|
+
break;
|
|
188
|
+
case 21:
|
|
189
|
+
_context.prev = 21;
|
|
190
|
+
_context.t0 = _context["catch"](14);
|
|
191
|
+
callback({
|
|
192
|
+
error: _context.t0 instanceof Error ? _context.t0 : new Error(String(_context.t0))
|
|
193
|
+
});
|
|
194
|
+
case 24:
|
|
195
|
+
return _context.abrupt("return");
|
|
196
|
+
case 25:
|
|
197
|
+
_context.prev = 25;
|
|
189
198
|
dataPromise = this.fetchNodesData([jsonNode]).then(function (_ref3) {
|
|
190
199
|
var _ref4 = _slicedToArray(_ref3, 1),
|
|
191
200
|
value = _ref4[0];
|
|
192
201
|
return value;
|
|
193
|
-
}); // Store the promise in the
|
|
194
|
-
this.
|
|
195
|
-
|
|
196
|
-
data: dataPromise
|
|
197
|
-
};
|
|
198
|
-
_context.next = 26;
|
|
202
|
+
}); // Store the promise in the in-flight requests map
|
|
203
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
204
|
+
_context.next = 30;
|
|
199
205
|
return dataPromise;
|
|
200
|
-
case
|
|
201
|
-
|
|
206
|
+
case 30:
|
|
207
|
+
_data = _context.sent;
|
|
202
208
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
203
209
|
// so all promises that are waiting for the data can resolve.
|
|
204
210
|
callback({
|
|
205
|
-
data:
|
|
211
|
+
data: _data
|
|
206
212
|
});
|
|
207
213
|
|
|
208
214
|
// If the cache version has changed, we don't want to use the data from the network
|
|
209
215
|
// because it could be stale data.
|
|
210
216
|
if (cacheVersionBeforeRequest === this.cacheVersion) {
|
|
211
217
|
// Replace promise with the resolved data in the cache
|
|
212
|
-
this.cache[
|
|
218
|
+
this.cache[dataKey] = {
|
|
213
219
|
source: 'network',
|
|
214
|
-
data:
|
|
220
|
+
data: _data
|
|
215
221
|
};
|
|
216
222
|
}
|
|
217
|
-
|
|
218
|
-
_context.next = 34;
|
|
223
|
+
_context.next = 38;
|
|
219
224
|
break;
|
|
220
|
-
case
|
|
221
|
-
_context.prev =
|
|
222
|
-
_context.
|
|
225
|
+
case 35:
|
|
226
|
+
_context.prev = 35;
|
|
227
|
+
_context.t1 = _context["catch"](25);
|
|
223
228
|
// If an error occurs, we call the callback with the error
|
|
224
229
|
callback({
|
|
225
|
-
error: _context.
|
|
230
|
+
error: _context.t1 instanceof Error ? _context.t1 : new Error(String(_context.t1))
|
|
226
231
|
});
|
|
227
|
-
case
|
|
232
|
+
case 38:
|
|
233
|
+
_context.prev = 38;
|
|
234
|
+
// Ensure we clean up the in-flight request entry
|
|
235
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
236
|
+
return _context.finish(38);
|
|
237
|
+
case 41:
|
|
228
238
|
case "end":
|
|
229
239
|
return _context.stop();
|
|
230
240
|
}
|
|
231
|
-
}, _callee, this, [[
|
|
241
|
+
}, _callee, this, [[14, 21], [25, 35, 38, 41]]);
|
|
232
242
|
}));
|
|
233
243
|
function getDataAsync(_x, _x2) {
|
|
234
244
|
return _getDataAsync.apply(this, arguments);
|
|
@@ -284,29 +294,27 @@ export var NodeDataProvider = /*#__PURE__*/function () {
|
|
|
284
294
|
}, {
|
|
285
295
|
key: "getCacheStatusForNode",
|
|
286
296
|
value: function getCacheStatusForNode(node) {
|
|
287
|
-
var
|
|
288
|
-
if (!this.isNodeSupported(jsonNode)) {
|
|
289
|
-
// eslint-disable-next-line no-console
|
|
290
|
-
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
var dataKey = this.nodeDataKey(jsonNode);
|
|
294
|
-
var dataFromCache = this.cache[dataKey];
|
|
297
|
+
var dataFromCache = this.getNodeDataFromCache(node);
|
|
295
298
|
return dataFromCache ? dataFromCache.source : false;
|
|
296
299
|
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Retrieves the cached data for a given node, if available.
|
|
303
|
+
*
|
|
304
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
305
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
306
|
+
*/
|
|
297
307
|
}, {
|
|
298
308
|
key: "getNodeDataFromCache",
|
|
299
309
|
value: function getNodeDataFromCache(node) {
|
|
300
310
|
var jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
311
|
+
if (!this.isNodeSupported(jsonNode)) {
|
|
312
|
+
// eslint-disable-next-line no-console
|
|
313
|
+
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
301
316
|
var dataKey = this.nodeDataKey(jsonNode);
|
|
302
317
|
return this.cache[dataKey];
|
|
303
318
|
}
|
|
304
319
|
}]);
|
|
305
|
-
}();
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Checks if value is a promise using hacky heuristics.
|
|
309
|
-
*/
|
|
310
|
-
export function isPromise(value) {
|
|
311
|
-
return _typeof(value) === 'object' && value !== null && 'then' in value && typeof value.then === 'function';
|
|
312
|
-
}
|
|
320
|
+
}();
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { NodeDataProvider
|
|
1
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
2
2
|
export { findNodesToPrefetch } from './utils/find-nodes-to-prefetch';
|
|
3
3
|
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|
|
@@ -13,6 +13,22 @@ 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 cached data for a Node Data Provider.
|
|
18
|
+
* Each key is a unique node data key, and the value is an object containing:
|
|
19
|
+
* - `source`: Indicates whether the data was fetched from SSR or the network.
|
|
20
|
+
* - `data`: The actual data, which can be either a resolved value or a Promise.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* {
|
|
24
|
+
* 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
|
|
25
|
+
* 'node-id-2': { source: 'network', data: { value: 'other data' } }
|
|
26
|
+
* }
|
|
27
|
+
*/
|
|
28
|
+
type CacheData<Data> = Record<string, {
|
|
29
|
+
data: Data;
|
|
30
|
+
source: 'ssr' | 'network';
|
|
31
|
+
}>;
|
|
16
32
|
/**
|
|
17
33
|
* Represents the payload passed to the callback function when data is fetched.
|
|
18
34
|
* It can either contain an error or the fetched data.
|
|
@@ -36,6 +52,7 @@ type CallbackPayload<Data> = {
|
|
|
36
52
|
export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
37
53
|
private cacheVersion;
|
|
38
54
|
private cache;
|
|
55
|
+
private readonly networkRequestsInFlight;
|
|
39
56
|
/**
|
|
40
57
|
* A unique name for the provider. Used for identification in SSR.
|
|
41
58
|
*/
|
|
@@ -116,7 +133,7 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
|
116
133
|
* @param callback The callback function to call with the fetched data or an error.
|
|
117
134
|
*/
|
|
118
135
|
getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
|
|
119
|
-
getDataAsync(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): Promise<void>;
|
|
136
|
+
protected getDataAsync(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): Promise<void>;
|
|
120
137
|
/**
|
|
121
138
|
* Fetches data for a given node and returns it as a Promise.
|
|
122
139
|
* This is a convenience wrapper around the `data` method for use with async/await.
|
|
@@ -146,13 +163,12 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
|
146
163
|
* @returns The cache status: `false`, `'ssr'`, or `'network'`.
|
|
147
164
|
*/
|
|
148
165
|
getCacheStatusForNode(node: Node | PMNode): false | 'ssr' | 'network';
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Retrieves the cached data for a given node, if available.
|
|
168
|
+
*
|
|
169
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
170
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
171
|
+
*/
|
|
172
|
+
getNodeDataFromCache(node: JSONNode | PMNode): CacheData<Data>[string] | undefined;
|
|
153
173
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Checks if value is a promise using hacky heuristics.
|
|
156
|
-
*/
|
|
157
|
-
export declare function isPromise<T>(value: T | Promise<T>): value is Promise<T>;
|
|
158
174
|
export {};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { NodeDataProvider
|
|
1
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
2
2
|
export { findNodesToPrefetch } from './utils/find-nodes-to-prefetch';
|
|
3
3
|
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|
|
@@ -13,6 +13,22 @@ 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 cached data for a Node Data Provider.
|
|
18
|
+
* Each key is a unique node data key, and the value is an object containing:
|
|
19
|
+
* - `source`: Indicates whether the data was fetched from SSR or the network.
|
|
20
|
+
* - `data`: The actual data, which can be either a resolved value or a Promise.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* {
|
|
24
|
+
* 'node-id-1': { source: 'ssr', data: { value: 'some data' } },
|
|
25
|
+
* 'node-id-2': { source: 'network', data: { value: 'other data' } }
|
|
26
|
+
* }
|
|
27
|
+
*/
|
|
28
|
+
type CacheData<Data> = Record<string, {
|
|
29
|
+
data: Data;
|
|
30
|
+
source: 'ssr' | 'network';
|
|
31
|
+
}>;
|
|
16
32
|
/**
|
|
17
33
|
* Represents the payload passed to the callback function when data is fetched.
|
|
18
34
|
* It can either contain an error or the fetched data.
|
|
@@ -36,6 +52,7 @@ type CallbackPayload<Data> = {
|
|
|
36
52
|
export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
37
53
|
private cacheVersion;
|
|
38
54
|
private cache;
|
|
55
|
+
private readonly networkRequestsInFlight;
|
|
39
56
|
/**
|
|
40
57
|
* A unique name for the provider. Used for identification in SSR.
|
|
41
58
|
*/
|
|
@@ -116,7 +133,7 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
|
116
133
|
* @param callback The callback function to call with the fetched data or an error.
|
|
117
134
|
*/
|
|
118
135
|
getData(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): void;
|
|
119
|
-
getDataAsync(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): Promise<void>;
|
|
136
|
+
protected getDataAsync(node: Node | PMNode, callback: (payload: CallbackPayload<Data>) => void): Promise<void>;
|
|
120
137
|
/**
|
|
121
138
|
* Fetches data for a given node and returns it as a Promise.
|
|
122
139
|
* This is a convenience wrapper around the `data` method for use with async/await.
|
|
@@ -146,13 +163,12 @@ export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
|
146
163
|
* @returns The cache status: `false`, `'ssr'`, or `'network'`.
|
|
147
164
|
*/
|
|
148
165
|
getCacheStatusForNode(node: Node | PMNode): false | 'ssr' | 'network';
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Retrieves the cached data for a given node, if available.
|
|
168
|
+
*
|
|
169
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
170
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
171
|
+
*/
|
|
172
|
+
getNodeDataFromCache(node: JSONNode | PMNode): CacheData<Data>[string] | undefined;
|
|
153
173
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Checks if value is a promise using hacky heuristics.
|
|
156
|
-
*/
|
|
157
|
-
export declare function isPromise<T>(value: T | Promise<T>): value is Promise<T>;
|
|
158
174
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/node-data-provider",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0",
|
|
4
4
|
"description": "Node data provider for @atlaskit/editor-core plugins and @atlaskit/renderer",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@babel/runtime": "^7.0.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"@atlaskit/editor-common": "^110.
|
|
29
|
+
"@atlaskit/editor-common": "^110.22.0"
|
|
30
30
|
},
|
|
31
31
|
"techstack": {
|
|
32
32
|
"@atlassian/frontend": {
|