@atlaskit/node-data-provider 7.3.0 → 7.4.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 +12 -0
- package/dist/cjs/index.js +0 -6
- package/dist/cjs/node-data-provider.js +75 -65
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/node-data-provider.js +65 -49
- package/dist/esm/index.js +1 -1
- package/dist/esm/node-data-provider.js +75 -65
- 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,17 @@
|
|
|
1
1
|
# @atlaskit/node-data-provider
|
|
2
2
|
|
|
3
|
+
## 7.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`fdba2e94783b7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fdba2e94783b7) -
|
|
8
|
+
[https://product-fabric.atlassian.net/browse/ED-29638](ED-29638) - fix editor NodeDataProvider
|
|
9
|
+
network requests deduplication
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
3
15
|
## 7.3.0
|
|
4
16
|
|
|
5
17
|
### 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,114 @@ 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[
|
|
151
|
+
case 4:
|
|
152
|
+
dataKey = this.nodeDataKey(jsonNode);
|
|
153
|
+
dataFromCache = this.cache[dataKey];
|
|
156
154
|
if (!(dataFromCache !== undefined)) {
|
|
157
|
-
_context.next =
|
|
155
|
+
_context.next = 10;
|
|
158
156
|
break;
|
|
159
157
|
}
|
|
160
|
-
|
|
161
|
-
_context.next = 17;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
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:
|
|
158
|
+
// If we have the data in the SSR data, we can use it directly
|
|
176
159
|
callback({
|
|
177
160
|
data: dataFromCache.data
|
|
178
161
|
});
|
|
179
|
-
case 18:
|
|
180
162
|
if (!(0, _coreUtils.isSSR)()) {
|
|
181
|
-
_context.next =
|
|
163
|
+
_context.next = 10;
|
|
182
164
|
break;
|
|
183
165
|
}
|
|
184
166
|
return _context.abrupt("return");
|
|
185
|
-
case
|
|
167
|
+
case 10:
|
|
186
168
|
if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
|
|
187
|
-
_context.next =
|
|
169
|
+
_context.next = 42;
|
|
188
170
|
break;
|
|
189
171
|
}
|
|
190
172
|
// Store the current cache version before making the request,
|
|
191
173
|
// so we can check if the cache has changed while we are waiting for the network response.
|
|
192
|
-
cacheVersionBeforeRequest = this.cacheVersion;
|
|
174
|
+
cacheVersionBeforeRequest = this.cacheVersion; // Create a unique key for the in-flight network request
|
|
175
|
+
// based on the cache version and the data key.
|
|
176
|
+
networkRequestInFlightKey = "".concat(cacheVersionBeforeRequest, "-").concat(dataKey); // Check if there is already a network request in flight for this data
|
|
177
|
+
// to avoid duplicate requests.
|
|
178
|
+
networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
179
|
+
if (!networkRequestInFlight) {
|
|
180
|
+
_context.next = 26;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
_context.prev = 15;
|
|
184
|
+
_context.next = 18;
|
|
185
|
+
return networkRequestInFlight;
|
|
186
|
+
case 18:
|
|
187
|
+
data = _context.sent;
|
|
188
|
+
callback({
|
|
189
|
+
data: data
|
|
190
|
+
});
|
|
191
|
+
_context.next = 25;
|
|
192
|
+
break;
|
|
193
|
+
case 22:
|
|
194
|
+
_context.prev = 22;
|
|
195
|
+
_context.t0 = _context["catch"](15);
|
|
196
|
+
callback({
|
|
197
|
+
error: _context.t0 instanceof Error ? _context.t0 : new Error(String(_context.t0))
|
|
198
|
+
});
|
|
199
|
+
case 25:
|
|
200
|
+
return _context.abrupt("return");
|
|
201
|
+
case 26:
|
|
202
|
+
_context.prev = 26;
|
|
193
203
|
dataPromise = this.fetchNodesData([jsonNode]).then(function (_ref3) {
|
|
194
204
|
var _ref4 = (0, _slicedToArray2.default)(_ref3, 1),
|
|
195
205
|
value = _ref4[0];
|
|
196
206
|
return value;
|
|
197
|
-
}); // Store the promise in the
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
data: dataPromise
|
|
201
|
-
};
|
|
202
|
-
_context.next = 26;
|
|
207
|
+
}); // Store the promise in the in-flight requests map
|
|
208
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
209
|
+
_context.next = 31;
|
|
203
210
|
return dataPromise;
|
|
204
|
-
case
|
|
205
|
-
|
|
211
|
+
case 31:
|
|
212
|
+
_data = _context.sent;
|
|
206
213
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
207
214
|
// so all promises that are waiting for the data can resolve.
|
|
208
215
|
callback({
|
|
209
|
-
data:
|
|
216
|
+
data: _data
|
|
210
217
|
});
|
|
211
218
|
|
|
212
219
|
// If the cache version has changed, we don't want to use the data from the network
|
|
213
220
|
// because it could be stale data.
|
|
214
221
|
if (cacheVersionBeforeRequest === this.cacheVersion) {
|
|
215
222
|
// Replace promise with the resolved data in the cache
|
|
216
|
-
this.cache[
|
|
223
|
+
this.cache[dataKey] = {
|
|
217
224
|
source: 'network',
|
|
218
|
-
data:
|
|
225
|
+
data: _data
|
|
219
226
|
};
|
|
220
227
|
}
|
|
221
|
-
|
|
222
|
-
_context.next = 34;
|
|
228
|
+
_context.next = 39;
|
|
223
229
|
break;
|
|
224
|
-
case
|
|
225
|
-
_context.prev =
|
|
226
|
-
_context.
|
|
230
|
+
case 36:
|
|
231
|
+
_context.prev = 36;
|
|
232
|
+
_context.t1 = _context["catch"](26);
|
|
227
233
|
// If an error occurs, we call the callback with the error
|
|
228
234
|
callback({
|
|
229
|
-
error: _context.
|
|
235
|
+
error: _context.t1 instanceof Error ? _context.t1 : new Error(String(_context.t1))
|
|
230
236
|
});
|
|
231
|
-
case
|
|
237
|
+
case 39:
|
|
238
|
+
_context.prev = 39;
|
|
239
|
+
// Ensure we clean up the in-flight request entry
|
|
240
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
241
|
+
return _context.finish(39);
|
|
242
|
+
case 42:
|
|
232
243
|
case "end":
|
|
233
244
|
return _context.stop();
|
|
234
245
|
}
|
|
235
|
-
}, _callee, this, [[
|
|
246
|
+
}, _callee, this, [[15, 22], [26, 36, 39, 42]]);
|
|
236
247
|
}));
|
|
237
248
|
function getDataAsync(_x, _x2) {
|
|
238
249
|
return _getDataAsync.apply(this, arguments);
|
|
@@ -288,28 +299,27 @@ var NodeDataProvider = exports.NodeDataProvider = /*#__PURE__*/function () {
|
|
|
288
299
|
}, {
|
|
289
300
|
key: "getCacheStatusForNode",
|
|
290
301
|
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];
|
|
302
|
+
var dataFromCache = this.getNodeDataFromCache(node);
|
|
299
303
|
return dataFromCache ? dataFromCache.source : false;
|
|
300
304
|
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Retrieves the cached data for a given node, if available.
|
|
308
|
+
*
|
|
309
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
310
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
311
|
+
*/
|
|
301
312
|
}, {
|
|
302
313
|
key: "getNodeDataFromCache",
|
|
303
314
|
value: function getNodeDataFromCache(node) {
|
|
304
315
|
var jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
316
|
+
if (!this.isNodeSupported(jsonNode)) {
|
|
317
|
+
// eslint-disable-next-line no-console
|
|
318
|
+
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
305
321
|
var dataKey = this.nodeDataKey(jsonNode);
|
|
306
322
|
return this.cache[dataKey];
|
|
307
323
|
}
|
|
308
324
|
}]);
|
|
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
|
-
}
|
|
325
|
+
}();
|
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,59 @@ export class NodeDataProvider {
|
|
|
137
138
|
void this.getDataAsync(node, callback);
|
|
138
139
|
}
|
|
139
140
|
async getDataAsync(node, callback) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
+
if (isSSR()) {
|
|
155
|
+
// If we are in SSR, we don't want to fetch the data again, as it is already available in the SSR data
|
|
145
156
|
return;
|
|
146
157
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If no data is available in the cache, or the data is from the network,
|
|
161
|
+
// we need to fetch it from the network.
|
|
162
|
+
if ((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network') {
|
|
163
|
+
// Store the current cache version before making the request,
|
|
164
|
+
// so we can check if the cache has changed while we are waiting for the network response.
|
|
165
|
+
const cacheVersionBeforeRequest = this.cacheVersion;
|
|
166
|
+
|
|
167
|
+
// Create a unique key for the in-flight network request
|
|
168
|
+
// based on the cache version and the data key.
|
|
169
|
+
const networkRequestInFlightKey = `${cacheVersionBeforeRequest}-${dataKey}`;
|
|
170
|
+
|
|
171
|
+
// Check if there is already a network request in flight for this data
|
|
172
|
+
// to avoid duplicate requests.
|
|
173
|
+
const networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
174
|
+
if (networkRequestInFlight) {
|
|
175
|
+
try {
|
|
176
|
+
const data = await networkRequestInFlight;
|
|
152
177
|
callback({
|
|
153
|
-
data
|
|
178
|
+
data
|
|
154
179
|
});
|
|
155
|
-
}
|
|
180
|
+
} catch (error) {
|
|
156
181
|
callback({
|
|
157
|
-
|
|
182
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
158
183
|
});
|
|
159
184
|
}
|
|
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
|
-
}
|
|
185
|
+
return;
|
|
164
186
|
}
|
|
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;
|
|
187
|
+
try {
|
|
172
188
|
const dataPromise = this.fetchNodesData([jsonNode]).then(([value]) => value);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
data: dataPromise
|
|
177
|
-
};
|
|
189
|
+
|
|
190
|
+
// Store the promise in the in-flight requests map
|
|
191
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
178
192
|
const data = await dataPromise;
|
|
193
|
+
|
|
179
194
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
180
195
|
// so all promises that are waiting for the data can resolve.
|
|
181
196
|
callback({
|
|
@@ -191,12 +206,15 @@ export class NodeDataProvider {
|
|
|
191
206
|
data
|
|
192
207
|
};
|
|
193
208
|
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
// If an error occurs, we call the callback with the error
|
|
211
|
+
callback({
|
|
212
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
213
|
+
});
|
|
214
|
+
} finally {
|
|
215
|
+
// Ensure we clean up the in-flight request entry
|
|
216
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
194
217
|
}
|
|
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
218
|
}
|
|
201
219
|
}
|
|
202
220
|
|
|
@@ -244,26 +262,24 @@ export class NodeDataProvider {
|
|
|
244
262
|
* @returns The cache status: `false`, `'ssr'`, or `'network'`.
|
|
245
263
|
*/
|
|
246
264
|
getCacheStatusForNode(node) {
|
|
265
|
+
const dataFromCache = this.getNodeDataFromCache(node);
|
|
266
|
+
return dataFromCache ? dataFromCache.source : false;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Retrieves the cached data for a given node, if available.
|
|
271
|
+
*
|
|
272
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
273
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
274
|
+
*/
|
|
275
|
+
getNodeDataFromCache(node) {
|
|
247
276
|
const jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
248
277
|
if (!this.isNodeSupported(jsonNode)) {
|
|
249
278
|
// eslint-disable-next-line no-console
|
|
250
279
|
console.error(`The ${this.constructor.name} doesn't support Node ${jsonNode.type}.`);
|
|
251
|
-
return
|
|
280
|
+
return undefined;
|
|
252
281
|
}
|
|
253
282
|
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
283
|
return this.cache[dataKey];
|
|
261
284
|
}
|
|
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
285
|
}
|
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,114 @@ 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[
|
|
148
|
+
case 4:
|
|
149
|
+
dataKey = this.nodeDataKey(jsonNode);
|
|
150
|
+
dataFromCache = this.cache[dataKey];
|
|
152
151
|
if (!(dataFromCache !== undefined)) {
|
|
153
|
-
_context.next =
|
|
152
|
+
_context.next = 10;
|
|
154
153
|
break;
|
|
155
154
|
}
|
|
156
|
-
|
|
157
|
-
_context.next = 17;
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
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:
|
|
155
|
+
// If we have the data in the SSR data, we can use it directly
|
|
172
156
|
callback({
|
|
173
157
|
data: dataFromCache.data
|
|
174
158
|
});
|
|
175
|
-
case 18:
|
|
176
159
|
if (!isSSR()) {
|
|
177
|
-
_context.next =
|
|
160
|
+
_context.next = 10;
|
|
178
161
|
break;
|
|
179
162
|
}
|
|
180
163
|
return _context.abrupt("return");
|
|
181
|
-
case
|
|
164
|
+
case 10:
|
|
182
165
|
if (!((dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.source) !== 'network')) {
|
|
183
|
-
_context.next =
|
|
166
|
+
_context.next = 42;
|
|
184
167
|
break;
|
|
185
168
|
}
|
|
186
169
|
// Store the current cache version before making the request,
|
|
187
170
|
// so we can check if the cache has changed while we are waiting for the network response.
|
|
188
|
-
cacheVersionBeforeRequest = this.cacheVersion;
|
|
171
|
+
cacheVersionBeforeRequest = this.cacheVersion; // Create a unique key for the in-flight network request
|
|
172
|
+
// based on the cache version and the data key.
|
|
173
|
+
networkRequestInFlightKey = "".concat(cacheVersionBeforeRequest, "-").concat(dataKey); // Check if there is already a network request in flight for this data
|
|
174
|
+
// to avoid duplicate requests.
|
|
175
|
+
networkRequestInFlight = this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
176
|
+
if (!networkRequestInFlight) {
|
|
177
|
+
_context.next = 26;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
_context.prev = 15;
|
|
181
|
+
_context.next = 18;
|
|
182
|
+
return networkRequestInFlight;
|
|
183
|
+
case 18:
|
|
184
|
+
data = _context.sent;
|
|
185
|
+
callback({
|
|
186
|
+
data: data
|
|
187
|
+
});
|
|
188
|
+
_context.next = 25;
|
|
189
|
+
break;
|
|
190
|
+
case 22:
|
|
191
|
+
_context.prev = 22;
|
|
192
|
+
_context.t0 = _context["catch"](15);
|
|
193
|
+
callback({
|
|
194
|
+
error: _context.t0 instanceof Error ? _context.t0 : new Error(String(_context.t0))
|
|
195
|
+
});
|
|
196
|
+
case 25:
|
|
197
|
+
return _context.abrupt("return");
|
|
198
|
+
case 26:
|
|
199
|
+
_context.prev = 26;
|
|
189
200
|
dataPromise = this.fetchNodesData([jsonNode]).then(function (_ref3) {
|
|
190
201
|
var _ref4 = _slicedToArray(_ref3, 1),
|
|
191
202
|
value = _ref4[0];
|
|
192
203
|
return value;
|
|
193
|
-
}); // Store the promise in the
|
|
194
|
-
this.
|
|
195
|
-
|
|
196
|
-
data: dataPromise
|
|
197
|
-
};
|
|
198
|
-
_context.next = 26;
|
|
204
|
+
}); // Store the promise in the in-flight requests map
|
|
205
|
+
this.networkRequestsInFlight[networkRequestInFlightKey] = dataPromise;
|
|
206
|
+
_context.next = 31;
|
|
199
207
|
return dataPromise;
|
|
200
|
-
case
|
|
201
|
-
|
|
208
|
+
case 31:
|
|
209
|
+
_data = _context.sent;
|
|
202
210
|
// We need to call the callback with the data with result even if the cache version has changed,
|
|
203
211
|
// so all promises that are waiting for the data can resolve.
|
|
204
212
|
callback({
|
|
205
|
-
data:
|
|
213
|
+
data: _data
|
|
206
214
|
});
|
|
207
215
|
|
|
208
216
|
// If the cache version has changed, we don't want to use the data from the network
|
|
209
217
|
// because it could be stale data.
|
|
210
218
|
if (cacheVersionBeforeRequest === this.cacheVersion) {
|
|
211
219
|
// Replace promise with the resolved data in the cache
|
|
212
|
-
this.cache[
|
|
220
|
+
this.cache[dataKey] = {
|
|
213
221
|
source: 'network',
|
|
214
|
-
data:
|
|
222
|
+
data: _data
|
|
215
223
|
};
|
|
216
224
|
}
|
|
217
|
-
|
|
218
|
-
_context.next = 34;
|
|
225
|
+
_context.next = 39;
|
|
219
226
|
break;
|
|
220
|
-
case
|
|
221
|
-
_context.prev =
|
|
222
|
-
_context.
|
|
227
|
+
case 36:
|
|
228
|
+
_context.prev = 36;
|
|
229
|
+
_context.t1 = _context["catch"](26);
|
|
223
230
|
// If an error occurs, we call the callback with the error
|
|
224
231
|
callback({
|
|
225
|
-
error: _context.
|
|
232
|
+
error: _context.t1 instanceof Error ? _context.t1 : new Error(String(_context.t1))
|
|
226
233
|
});
|
|
227
|
-
case
|
|
234
|
+
case 39:
|
|
235
|
+
_context.prev = 39;
|
|
236
|
+
// Ensure we clean up the in-flight request entry
|
|
237
|
+
delete this.networkRequestsInFlight[networkRequestInFlightKey];
|
|
238
|
+
return _context.finish(39);
|
|
239
|
+
case 42:
|
|
228
240
|
case "end":
|
|
229
241
|
return _context.stop();
|
|
230
242
|
}
|
|
231
|
-
}, _callee, this, [[
|
|
243
|
+
}, _callee, this, [[15, 22], [26, 36, 39, 42]]);
|
|
232
244
|
}));
|
|
233
245
|
function getDataAsync(_x, _x2) {
|
|
234
246
|
return _getDataAsync.apply(this, arguments);
|
|
@@ -284,29 +296,27 @@ export var NodeDataProvider = /*#__PURE__*/function () {
|
|
|
284
296
|
}, {
|
|
285
297
|
key: "getCacheStatusForNode",
|
|
286
298
|
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];
|
|
299
|
+
var dataFromCache = this.getNodeDataFromCache(node);
|
|
295
300
|
return dataFromCache ? dataFromCache.source : false;
|
|
296
301
|
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Retrieves the cached data for a given node, if available.
|
|
305
|
+
*
|
|
306
|
+
* @param node The node (or its ProseMirror representation) for which to retrieve cached data.
|
|
307
|
+
* @returns The cached data object containing `data` and `source`, or `undefined` if no cache entry exists.
|
|
308
|
+
*/
|
|
297
309
|
}, {
|
|
298
310
|
key: "getNodeDataFromCache",
|
|
299
311
|
value: function getNodeDataFromCache(node) {
|
|
300
312
|
var jsonNode = 'toJSON' in node ? node.toJSON() : node;
|
|
313
|
+
if (!this.isNodeSupported(jsonNode)) {
|
|
314
|
+
// eslint-disable-next-line no-console
|
|
315
|
+
console.error("The ".concat(this.constructor.name, " doesn't support Node ").concat(jsonNode.type, "."));
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
301
318
|
var dataKey = this.nodeDataKey(jsonNode);
|
|
302
319
|
return this.cache[dataKey];
|
|
303
320
|
}
|
|
304
321
|
}]);
|
|
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
|
-
}
|
|
322
|
+
}();
|
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.4.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.21.0"
|
|
30
30
|
},
|
|
31
31
|
"techstack": {
|
|
32
32
|
"@atlassian/frontend": {
|