@atlaskit/node-data-provider 4.1.2 → 4.3.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 +22 -0
- package/dist/cjs/index.js +13 -226
- package/dist/cjs/node-data-provider.js +252 -0
- package/dist/cjs/utils/find-nodes-to-prefetch.js +68 -0
- package/dist/cjs/utils/prefetch-node-data-providers-data.js +165 -0
- package/dist/es2019/index.js +3 -190
- package/dist/es2019/node-data-provider.js +216 -0
- package/dist/es2019/utils/find-nodes-to-prefetch.js +57 -0
- package/dist/es2019/utils/prefetch-node-data-providers-data.js +128 -0
- package/dist/esm/index.js +3 -226
- package/dist/esm/node-data-provider.js +248 -0
- package/dist/esm/utils/find-nodes-to-prefetch.js +61 -0
- package/dist/esm/utils/prefetch-node-data-providers-data.js +161 -0
- package/dist/types/index.d.ts +2 -134
- package/dist/types/node-data-provider.d.ts +125 -0
- package/dist/types/utils/find-nodes-to-prefetch.d.ts +21 -0
- package/dist/types/utils/prefetch-node-data-providers-data.d.ts +107 -0
- package/dist/types-ts4.5/index.d.ts +2 -134
- package/dist/types-ts4.5/node-data-provider.d.ts +125 -0
- package/dist/types-ts4.5/utils/find-nodes-to-prefetch.d.ts +21 -0
- package/dist/types-ts4.5/utils/prefetch-node-data-providers-data.d.ts +107 -0
- package/package.json +6 -13
- package/cache/package.json +0 -15
- package/content/package.json +0 -15
- package/dist/cjs/cache.js +0 -145
- package/dist/cjs/consumption/_global-ndp-caches.js +0 -21
- package/dist/cjs/consumption/_internal-context.js +0 -77
- package/dist/cjs/consumption/_lru-cache.js +0 -45
- package/dist/cjs/consumption/content.js +0 -56
- package/dist/cjs/get-providers/confluence-page.js +0 -15
- package/dist/cjs/internal-types.js +0 -5
- package/dist/cjs/plugin-hooks.js +0 -100
- package/dist/cjs/providers/emoji.js +0 -54
- package/dist/es2019/cache.js +0 -96
- package/dist/es2019/consumption/_global-ndp-caches.js +0 -13
- package/dist/es2019/consumption/_internal-context.js +0 -71
- package/dist/es2019/consumption/_lru-cache.js +0 -30
- package/dist/es2019/consumption/content.js +0 -49
- package/dist/es2019/get-providers/confluence-page.js +0 -10
- package/dist/es2019/internal-types.js +0 -1
- package/dist/es2019/plugin-hooks.js +0 -69
- package/dist/es2019/providers/emoji.js +0 -26
- package/dist/esm/cache.js +0 -141
- package/dist/esm/consumption/_global-ndp-caches.js +0 -13
- package/dist/esm/consumption/_internal-context.js +0 -71
- package/dist/esm/consumption/_lru-cache.js +0 -38
- package/dist/esm/consumption/content.js +0 -49
- package/dist/esm/get-providers/confluence-page.js +0 -9
- package/dist/esm/internal-types.js +0 -1
- package/dist/esm/plugin-hooks.js +0 -93
- package/dist/esm/providers/emoji.js +0 -47
- package/dist/types/cache.d.ts +0 -61
- package/dist/types/consumption/_global-ndp-caches.d.ts +0 -8
- package/dist/types/consumption/_internal-context.d.ts +0 -32
- package/dist/types/consumption/_lru-cache.d.ts +0 -7
- package/dist/types/consumption/content.d.ts +0 -65
- package/dist/types/get-providers/confluence-page.d.ts +0 -6
- package/dist/types/internal-types.d.ts +0 -2
- package/dist/types/plugin-hooks.d.ts +0 -32
- package/dist/types/providers/emoji.d.ts +0 -10
- package/dist/types-ts4.5/cache.d.ts +0 -61
- package/dist/types-ts4.5/consumption/_global-ndp-caches.d.ts +0 -8
- package/dist/types-ts4.5/consumption/_internal-context.d.ts +0 -32
- package/dist/types-ts4.5/consumption/_lru-cache.d.ts +0 -7
- package/dist/types-ts4.5/consumption/content.d.ts +0 -65
- package/dist/types-ts4.5/get-providers/confluence-page.d.ts +0 -6
- package/dist/types-ts4.5/internal-types.d.ts +0 -2
- package/dist/types-ts4.5/plugin-hooks.d.ts +0 -32
- package/dist/types-ts4.5/providers/emoji.d.ts +0 -10
- package/emoji-provider/package.json +0 -15
- package/get-confluence-page-providers/package.json +0 -15
- package/plugin-hooks/package.json +0 -15
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
import { findNodesToPrefetch } from './find-nodes-to-prefetch';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents the SSR data for a single provider.
|
|
7
|
+
* It's a map where each key is a unique node data key and the value is the prefetched data for that node.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* {
|
|
11
|
+
* 'node-id-1': { value: 'some data' },
|
|
12
|
+
* 'node-id-2': { value: 'other data' }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
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.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* {
|
|
23
|
+
* 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
|
|
24
|
+
* 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Fetches data for nodes in the document that are supported by the given providers.
|
|
30
|
+
* This function will traverse the document and call the `fetchData` method for each node that is supported by the providers.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```
|
|
34
|
+
* const doc = JSON.parse('{"type": "doc", "content": [...] }');
|
|
35
|
+
* const providers = [
|
|
36
|
+
* {
|
|
37
|
+
* provider: new EditorCardProvider(),
|
|
38
|
+
* maxNodesToPrefetch: 10,
|
|
39
|
+
* timeout: 500,
|
|
40
|
+
* },
|
|
41
|
+
* {
|
|
42
|
+
* provider: new EditorMentionsProvider(),
|
|
43
|
+
* maxNodesToPrefetch: 50,
|
|
44
|
+
* timeout: 500,
|
|
45
|
+
* },
|
|
46
|
+
* ];
|
|
47
|
+
*
|
|
48
|
+
* window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
|
|
49
|
+
* providers,
|
|
50
|
+
* doc,
|
|
51
|
+
* timeout: 1_000,
|
|
52
|
+
* maxNodesToVisit: 2_000
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @param props The properties for prefetching node data.
|
|
57
|
+
* @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.
|
|
59
|
+
*/
|
|
60
|
+
export function prefetchNodeDataProvidersData(_x) {
|
|
61
|
+
return _prefetchNodeDataProvidersData.apply(this, arguments);
|
|
62
|
+
}
|
|
63
|
+
function _prefetchNodeDataProvidersData() {
|
|
64
|
+
_prefetchNodeDataProvidersData = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(_ref) {
|
|
65
|
+
var providers, doc, timeout, _ref$maxNodesToVisit, maxNodesToVisit, providersWithDefaults, providerTimeouts, nodesWithProviders, promises, results;
|
|
66
|
+
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
67
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
68
|
+
case 0:
|
|
69
|
+
providers = _ref.providers, doc = _ref.doc, timeout = _ref.timeout, _ref$maxNodesToVisit = _ref.maxNodesToVisit, maxNodesToVisit = _ref$maxNodesToVisit === void 0 ? Infinity : _ref$maxNodesToVisit;
|
|
70
|
+
providersWithDefaults = providers.map(function (_ref2) {
|
|
71
|
+
var provider = _ref2.provider,
|
|
72
|
+
_ref2$maxNodesToPrefe = _ref2.maxNodesToPrefetch,
|
|
73
|
+
maxNodesToPrefetch = _ref2$maxNodesToPrefe === void 0 ? Infinity : _ref2$maxNodesToPrefe,
|
|
74
|
+
_ref2$timeout = _ref2.timeout,
|
|
75
|
+
providerTimeout = _ref2$timeout === void 0 ? Infinity : _ref2$timeout;
|
|
76
|
+
return {
|
|
77
|
+
provider: provider,
|
|
78
|
+
maxNodesToPrefetch: maxNodesToPrefetch,
|
|
79
|
+
// Use the minimum of the global timeout and the provider-specific timeout
|
|
80
|
+
timeout: Math.min(providerTimeout, timeout)
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
providerTimeouts = providersWithDefaults.reduce(function (acc, _ref3) {
|
|
84
|
+
var provider = _ref3.provider,
|
|
85
|
+
timeout = _ref3.timeout;
|
|
86
|
+
acc[provider.name] = timeout;
|
|
87
|
+
return acc;
|
|
88
|
+
}, {});
|
|
89
|
+
nodesWithProviders = findNodesToPrefetch(doc, providersWithDefaults, maxNodesToVisit).map(function (_ref4) {
|
|
90
|
+
var provider = _ref4.provider,
|
|
91
|
+
nodes = _ref4.nodes;
|
|
92
|
+
return {
|
|
93
|
+
provider: provider,
|
|
94
|
+
nodes: nodes,
|
|
95
|
+
timeout: providerTimeouts[provider.name]
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
promises = nodesWithProviders.map( /*#__PURE__*/function () {
|
|
99
|
+
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(_ref5) {
|
|
100
|
+
var nodes, provider, timeout, timeoutPromise, data;
|
|
101
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
102
|
+
while (1) switch (_context.prev = _context.next) {
|
|
103
|
+
case 0:
|
|
104
|
+
nodes = _ref5.nodes, provider = _ref5.provider, timeout = _ref5.timeout;
|
|
105
|
+
_context.prev = 1;
|
|
106
|
+
timeoutPromise = new Promise(function (resolve) {
|
|
107
|
+
setTimeout(function () {
|
|
108
|
+
resolve([]);
|
|
109
|
+
}, timeout);
|
|
110
|
+
});
|
|
111
|
+
_context.next = 5;
|
|
112
|
+
return Promise.race([provider.fetchNodesData(nodes), timeoutPromise]);
|
|
113
|
+
case 5:
|
|
114
|
+
data = _context.sent;
|
|
115
|
+
return _context.abrupt("return", {
|
|
116
|
+
provider: provider,
|
|
117
|
+
nodes: nodes,
|
|
118
|
+
data: data
|
|
119
|
+
});
|
|
120
|
+
case 9:
|
|
121
|
+
_context.prev = 9;
|
|
122
|
+
_context.t0 = _context["catch"](1);
|
|
123
|
+
return _context.abrupt("return", {
|
|
124
|
+
provider: provider,
|
|
125
|
+
nodes: nodes,
|
|
126
|
+
data: []
|
|
127
|
+
});
|
|
128
|
+
case 12:
|
|
129
|
+
case "end":
|
|
130
|
+
return _context.stop();
|
|
131
|
+
}
|
|
132
|
+
}, _callee, null, [[1, 9]]);
|
|
133
|
+
}));
|
|
134
|
+
return function (_x2) {
|
|
135
|
+
return _ref6.apply(this, arguments);
|
|
136
|
+
};
|
|
137
|
+
}());
|
|
138
|
+
_context2.next = 7;
|
|
139
|
+
return Promise.all(promises);
|
|
140
|
+
case 7:
|
|
141
|
+
results = _context2.sent;
|
|
142
|
+
return _context2.abrupt("return", results.reduce(function (acc, _ref7) {
|
|
143
|
+
var provider = _ref7.provider,
|
|
144
|
+
nodes = _ref7.nodes,
|
|
145
|
+
data = _ref7.data;
|
|
146
|
+
acc[provider.name] = data.reduce(function (providerSsrData, nodeData, nodeIndex) {
|
|
147
|
+
var node = nodes[nodeIndex];
|
|
148
|
+
var nodeDataKey = provider.nodeDataKey(node);
|
|
149
|
+
providerSsrData[nodeDataKey] = nodeData;
|
|
150
|
+
return providerSsrData;
|
|
151
|
+
}, {});
|
|
152
|
+
return acc;
|
|
153
|
+
}, {}));
|
|
154
|
+
case 9:
|
|
155
|
+
case "end":
|
|
156
|
+
return _context2.stop();
|
|
157
|
+
}
|
|
158
|
+
}, _callee2);
|
|
159
|
+
}));
|
|
160
|
+
return _prefetchNodeDataProvidersData.apply(this, arguments);
|
|
161
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,134 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* ## Usage
|
|
5
|
-
*
|
|
6
|
-
* ### Create a provider
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* class EmojiNodeDataProvider extends NodeDataProvider<
|
|
11
|
-
* { attrs: EmojiAttributes },
|
|
12
|
-
* { resolvedData: string }
|
|
13
|
-
* > {
|
|
14
|
-
* constructor({ existingCache }?: { existingCache: Record<string, { resolvedData: string }> }) {
|
|
15
|
-
* super({ existingCache, nodeName: 'emoji' });
|
|
16
|
-
* }
|
|
17
|
-
* nodeToKey(node: { attrs: EmojiAttributes }): string {
|
|
18
|
-
* return `${node.attrs.shortName}-${node.attrs.text}-${node.attrs.id}`;
|
|
19
|
-
* }
|
|
20
|
-
* resolve(node: { attrs: EmojiAttributes }, _?: { signal: AbortSignal }) {
|
|
21
|
-
* return Promise.resolve({ resolvedData: 'resolved' });
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* ### Use the provider
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* const emojiNodeDataProvider = new EmojiNodeDataProvider();
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* ### Caching
|
|
34
|
-
*
|
|
35
|
-
* @see {@link buildCaches} for more information on building caches.
|
|
36
|
-
*
|
|
37
|
-
* #### Load an existing provider with a cache
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```
|
|
41
|
-
* await buildCaches({
|
|
42
|
-
* adf: docFromSomewhere,
|
|
43
|
-
* nodeDataProviders: [emojiNodeDataProvider],
|
|
44
|
-
* signal: AbortSignal.timeout(5000),
|
|
45
|
-
* });
|
|
46
|
-
* emojiNodeDataProvider // { 'key': 'value' }
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* ### Load an new provider with an existing cache
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```
|
|
53
|
-
* const provider1 = new ExampleNodeDataProvider();
|
|
54
|
-
* await buildCaches({adf, nodeDataProviders: [provider1]})
|
|
55
|
-
* provider1.cache // { 'key': 'value' }
|
|
56
|
-
*
|
|
57
|
-
* const provider2 = new ExampleNodeDataProvider({existingCache: provider1.cache});
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
export declare class NodeDataProvider<INode extends ReceivableNode, Result extends unknown> {
|
|
61
|
-
/**
|
|
62
|
-
* This is added to ease building types
|
|
63
|
-
*/
|
|
64
|
-
__node: INode;
|
|
65
|
-
private __cache;
|
|
66
|
-
/**
|
|
67
|
-
* This takes a node and returns a key that can be used to cache the result of the resolve function.
|
|
68
|
-
*/
|
|
69
|
-
nodeToKey: (node: INode) => string;
|
|
70
|
-
/**
|
|
71
|
-
* This returns the information required to render a node.
|
|
72
|
-
*
|
|
73
|
-
* If unresolvable, this method will throw an error.
|
|
74
|
-
*
|
|
75
|
-
* If signal is aborted, this method will return undefined.
|
|
76
|
-
*/
|
|
77
|
-
resolve: (node: INode, _?: {
|
|
78
|
-
signal?: AbortSignal;
|
|
79
|
-
}) => Promise<Result | undefined>;
|
|
80
|
-
/**
|
|
81
|
-
* The adf node name this provider is responsible for.
|
|
82
|
-
*/
|
|
83
|
-
nodeName: string;
|
|
84
|
-
constructor({ existingCache, nodeName, nodeToKey, resolve, }: {
|
|
85
|
-
/**
|
|
86
|
-
* A cache to load the provider with.
|
|
87
|
-
*
|
|
88
|
-
* @see {@link buildCaches} for more information on building caches.
|
|
89
|
-
*/
|
|
90
|
-
existingCache?: Record<string, Result>;
|
|
91
|
-
/**
|
|
92
|
-
* The adf node name this provider is responsible for.
|
|
93
|
-
*
|
|
94
|
-
* It is used for;
|
|
95
|
-
* - determining if the traverser should use this provider to resolve a node when building caches
|
|
96
|
-
* - identifying the node when submitting analytics events via the helper react hooks
|
|
97
|
-
*/
|
|
98
|
-
nodeName: string;
|
|
99
|
-
nodeToKey: typeof NodeDataProvider.prototype.nodeToKey;
|
|
100
|
-
resolve: typeof NodeDataProvider.prototype.resolve;
|
|
101
|
-
});
|
|
102
|
-
/**
|
|
103
|
-
* Updates the providers cache.
|
|
104
|
-
*
|
|
105
|
-
* Useful in scenarios such as SSR where the cache is built on the server and then passed to the client.
|
|
106
|
-
*
|
|
107
|
-
* Avoids the need to provide the cache to the constructor (to allow decoupling creation of node data providers from cache building),
|
|
108
|
-
* and allow for caching to be managed at a group level across multiple providers.
|
|
109
|
-
*
|
|
110
|
-
* This is not expected to be used by consumers, for internal consumption examples;
|
|
111
|
-
* @see {@link buildCaches}
|
|
112
|
-
*
|
|
113
|
-
*/
|
|
114
|
-
updateCache(cache: Record<string, Result>, options: {
|
|
115
|
-
strategy: 'merge-override' | 'replace';
|
|
116
|
-
}): void;
|
|
117
|
-
/**
|
|
118
|
-
* This is the cache for the provider.
|
|
119
|
-
*/
|
|
120
|
-
get cache(): Record<string, Result>;
|
|
121
|
-
private pending;
|
|
122
|
-
get(node: INode, _?: {
|
|
123
|
-
signal: AbortSignal;
|
|
124
|
-
}): Promise<Result | undefined> | Result;
|
|
125
|
-
}
|
|
126
|
-
export type ReceivableNode = {
|
|
127
|
-
[key: string]: any;
|
|
128
|
-
attrs: {
|
|
129
|
-
[key: string]: any;
|
|
130
|
-
};
|
|
131
|
-
};
|
|
132
|
-
export type ResolveOptions = {
|
|
133
|
-
signal: AbortSignal;
|
|
134
|
-
};
|
|
1
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
2
|
+
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { JSONNode } from '@atlaskit/editor-json-transformer';
|
|
2
|
+
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
/**
|
|
4
|
+
* Represents the SSR data for a single provider.
|
|
5
|
+
* It's a map where each key is a unique node data key and the value is the prefetched data for that node.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* {
|
|
9
|
+
* 'node-id-1': { value: 'some data' },
|
|
10
|
+
* 'node-id-2': { value: 'other data' }
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
type SSRData<Data> = {
|
|
14
|
+
[dataKey: string]: Data;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A Node Data Provider is responsible for fetching and caching data associated with specific ProseMirror nodes.
|
|
18
|
+
* It supports a cache-first-then-network strategy, with initial data potentially provided via SSR.
|
|
19
|
+
*
|
|
20
|
+
* @template Node The specific type of JSONNode this provider supports.
|
|
21
|
+
* @template Data The type of data this provider fetches and manages.
|
|
22
|
+
*/
|
|
23
|
+
export declare abstract class NodeDataProvider<Node extends JSONNode, Data> {
|
|
24
|
+
private cacheVersion;
|
|
25
|
+
private cache;
|
|
26
|
+
/**
|
|
27
|
+
* A unique name for the provider. Used for identification in SSR.
|
|
28
|
+
*/
|
|
29
|
+
abstract readonly name: string;
|
|
30
|
+
/**
|
|
31
|
+
* A type guard to check if a given JSONNode is supported by this provider.
|
|
32
|
+
* Used to ensure that the provider can handle the node type before attempting to fetch data.
|
|
33
|
+
*
|
|
34
|
+
* @param node The node to check.
|
|
35
|
+
* @returns `true` if the node is of the type supported by this provider, otherwise `false`.
|
|
36
|
+
*/
|
|
37
|
+
abstract isNodeSupported(node: JSONNode): node is Node;
|
|
38
|
+
/**
|
|
39
|
+
* Generates a unique key for a given node to be used for caching.
|
|
40
|
+
*
|
|
41
|
+
* @param node The node for which to generate a data key.
|
|
42
|
+
* @returns A unique string key for the node's data.
|
|
43
|
+
*/
|
|
44
|
+
abstract nodeDataKey(node: Node): string;
|
|
45
|
+
/**
|
|
46
|
+
* Fetches data for a batch of nodes from the network or another asynchronous source.
|
|
47
|
+
*
|
|
48
|
+
* @param nodes An array of nodes for which to fetch data.
|
|
49
|
+
* @returns A promise that resolves to an array of data corresponding to the input nodes.
|
|
50
|
+
*/
|
|
51
|
+
abstract fetchNodesData(nodes: Node[]): Promise<Data[]>;
|
|
52
|
+
protected constructor();
|
|
53
|
+
/**
|
|
54
|
+
* Sets the SSR data for the provider.
|
|
55
|
+
* This pre-populates the cache with data rendered on the server, preventing redundant network requests on the client.
|
|
56
|
+
* Calling this method will invalidate the existing cache.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```
|
|
60
|
+
* const ssrData = window.__SSR_NODE_DATA__ || {};
|
|
61
|
+
* nodeDataProvider.setSSRData(ssrData);
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @param ssrData A map of node data keys to their corresponding data.
|
|
65
|
+
*/
|
|
66
|
+
setSSRData(ssrData?: SSRData<Data>): void;
|
|
67
|
+
/**
|
|
68
|
+
* Clears all cached data.
|
|
69
|
+
* This increments the internal cache version, invalidating any pending network requests.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```
|
|
73
|
+
* function useMyNodeDataProvider(contentId: string) {
|
|
74
|
+
* const nodeDataProvider = new MyNodeDataProvider();
|
|
75
|
+
*
|
|
76
|
+
* // Reset the cache when the contentId changes (e.g., when the user navigates to a different page).
|
|
77
|
+
* useEffect(() => {
|
|
78
|
+
* nodeDataProvider.resetCache();
|
|
79
|
+
* }, [contentId]);
|
|
80
|
+
*
|
|
81
|
+
* return nodeDataProvider;
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
resetCache(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Fetches data for a given node using a cache-first-then-network strategy.
|
|
88
|
+
*
|
|
89
|
+
* The provided callback may be called multiple times:
|
|
90
|
+
* 1. Immediately with data from the SSR cache, if available.
|
|
91
|
+
* 2. Asynchronously with data fetched from the network.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```
|
|
95
|
+
* const nodeDataProvider = new MyNodeDataProvider();
|
|
96
|
+
*
|
|
97
|
+
* nodeDataProvider.getData(node, (data) => {
|
|
98
|
+
* console.log('Node data:', data);
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @param node The node (or its ProseMirror representation) for which to fetch data.
|
|
103
|
+
* @param callback The function to call when data is available.
|
|
104
|
+
*/
|
|
105
|
+
getData(node: Node | PMNode, callback: (data: Data) => void): void;
|
|
106
|
+
private getDataAsync;
|
|
107
|
+
/**
|
|
108
|
+
* Fetches data for a given node and returns it as a Promise.
|
|
109
|
+
* This is a convenience wrapper around the `data` method for use with async/await.
|
|
110
|
+
*
|
|
111
|
+
* Note: This promise resolves with the *first* available data, which could be from the SSR cache or the network.
|
|
112
|
+
* It may not provide the most up-to-date data if a network fetch is in progress.
|
|
113
|
+
*
|
|
114
|
+
* Note: This method is only for migration purposes. Use {@link getData} in new code instead.
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
* @deprecated Don't use this method, use {@link getData} method instead.
|
|
118
|
+
* This method is only for migration purposes.
|
|
119
|
+
*
|
|
120
|
+
* @param node The node (or its ProseMirror representation) for which to fetch data.
|
|
121
|
+
* @returns A promise that resolves with the node's data.
|
|
122
|
+
*/
|
|
123
|
+
getDataAsPromise_DO_NOT_USE_OUTSIDE_MIGRATIONS(node: Node | PMNode): Promise<Data>;
|
|
124
|
+
}
|
|
125
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { JSONDocNode, JSONNode } from '@atlaskit/editor-json-transformer';
|
|
2
|
+
import type { NodeDataProvider } from '../node-data-provider';
|
|
3
|
+
interface ProviderWithNodes {
|
|
4
|
+
/** The provider that supports the nodes. */
|
|
5
|
+
provider: NodeDataProvider<JSONNode, unknown>;
|
|
6
|
+
/** The nodes that are supported by the provider. */
|
|
7
|
+
nodes: JSONNode[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Finds nodes in the document that are supported by the given providers, up to a maximum number of nodes.
|
|
11
|
+
*
|
|
12
|
+
* @param doc The document to search for nodes.
|
|
13
|
+
* @param providers An array of providers with their maximum nodes to prefetch.
|
|
14
|
+
* @param maxNodesToVisit The maximum number of nodes to visit in the document.
|
|
15
|
+
* @returns An array of objects, each containing a provider and the nodes that are supported by that provider.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findNodesToPrefetch(doc: JSONDocNode, providers: {
|
|
18
|
+
provider: NodeDataProvider<JSONNode, unknown>;
|
|
19
|
+
maxNodesToPrefetch: number;
|
|
20
|
+
}[], maxNodesToVisit: number): ProviderWithNodes[];
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { JSONDocNode, JSONNode } from '@atlaskit/editor-json-transformer';
|
|
2
|
+
import type { NodeDataProvider } from '../node-data-provider';
|
|
3
|
+
/**
|
|
4
|
+
* Represents the SSR data for a single provider.
|
|
5
|
+
* It's a map where each key is a unique node data key and the value is the prefetched data for that node.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* {
|
|
9
|
+
* 'node-id-1': { value: 'some data' },
|
|
10
|
+
* 'node-id-2': { value: 'other data' }
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
type SsrData = {
|
|
14
|
+
[dataKey: string]: unknown;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
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.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* {
|
|
23
|
+
* 'mentionProvider': { 'mention-1': { id: '1', name: 'John Doe' } },
|
|
24
|
+
* 'emojiProvider': { 'emoji-123': { shortName: ':smile:', representation: '😊' } }
|
|
25
|
+
* }
|
|
26
|
+
*/
|
|
27
|
+
type NodeDataProvidersSsrData = {
|
|
28
|
+
[providerName: string]: SsrData;
|
|
29
|
+
};
|
|
30
|
+
interface Props {
|
|
31
|
+
/**
|
|
32
|
+
* The document for which to prefetch data.
|
|
33
|
+
*/
|
|
34
|
+
doc: JSONDocNode;
|
|
35
|
+
/**
|
|
36
|
+
* A global timeout in milliseconds for all fetch requests.
|
|
37
|
+
*
|
|
38
|
+
* Each provider will use the minimum of this value and its own specific timeout.
|
|
39
|
+
*/
|
|
40
|
+
timeout: number;
|
|
41
|
+
/**
|
|
42
|
+
* The maximum number of nodes to visit when searching for nodes to prefetch.
|
|
43
|
+
* This is a performance safeguard for very large documents.
|
|
44
|
+
*
|
|
45
|
+
* @default If not specified, the entire document will be traversed.
|
|
46
|
+
*/
|
|
47
|
+
maxNodesToVisit?: number;
|
|
48
|
+
/**
|
|
49
|
+
* A list of node data providers to use for prefetching, along with their
|
|
50
|
+
* individual configurations.
|
|
51
|
+
*/
|
|
52
|
+
providers: {
|
|
53
|
+
/**
|
|
54
|
+
* The provider instance to use for prefetching.
|
|
55
|
+
*/
|
|
56
|
+
provider: NodeDataProvider<JSONNode, unknown>;
|
|
57
|
+
/**
|
|
58
|
+
* The maximum number of nodes to prefetch for this specific provider.
|
|
59
|
+
* This helps prevent performance issues with documents containing many
|
|
60
|
+
* nodes of the same type.
|
|
61
|
+
*
|
|
62
|
+
* @default If not specified, all nodes supported by the provider will be prefetched.
|
|
63
|
+
*/
|
|
64
|
+
maxNodesToPrefetch?: number;
|
|
65
|
+
/**
|
|
66
|
+
* The timeout in milliseconds for the fetch request for this specific provider.
|
|
67
|
+
* If the request takes longer than this, it will be aborted and return no data.
|
|
68
|
+
*
|
|
69
|
+
* @default If not specified, the global timeout will be used.
|
|
70
|
+
*/
|
|
71
|
+
timeout?: number;
|
|
72
|
+
}[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Fetches data for nodes in the document that are supported by the given providers.
|
|
76
|
+
* This function will traverse the document and call the `fetchData` method for each node that is supported by the providers.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```
|
|
80
|
+
* const doc = JSON.parse('{"type": "doc", "content": [...] }');
|
|
81
|
+
* const providers = [
|
|
82
|
+
* {
|
|
83
|
+
* provider: new EditorCardProvider(),
|
|
84
|
+
* maxNodesToPrefetch: 10,
|
|
85
|
+
* timeout: 500,
|
|
86
|
+
* },
|
|
87
|
+
* {
|
|
88
|
+
* provider: new EditorMentionsProvider(),
|
|
89
|
+
* maxNodesToPrefetch: 50,
|
|
90
|
+
* timeout: 500,
|
|
91
|
+
* },
|
|
92
|
+
* ];
|
|
93
|
+
*
|
|
94
|
+
* window['__SSR_EDITOR_NODE_DATA_PROVIDERS_DATA__'] = await prefetchNodeDataProvidersData({
|
|
95
|
+
* providers,
|
|
96
|
+
* doc,
|
|
97
|
+
* timeout: 1_000,
|
|
98
|
+
* maxNodesToVisit: 2_000
|
|
99
|
+
* });
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* @param props The properties for prefetching node data.
|
|
103
|
+
* @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.
|
|
105
|
+
*/
|
|
106
|
+
export declare function prefetchNodeDataProvidersData({ providers, doc, timeout, maxNodesToVisit, }: Props): Promise<NodeDataProvidersSsrData>;
|
|
107
|
+
export {};
|
|
@@ -1,134 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* ## Usage
|
|
5
|
-
*
|
|
6
|
-
* ### Create a provider
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* class EmojiNodeDataProvider extends NodeDataProvider<
|
|
11
|
-
* { attrs: EmojiAttributes },
|
|
12
|
-
* { resolvedData: string }
|
|
13
|
-
* > {
|
|
14
|
-
* constructor({ existingCache }?: { existingCache: Record<string, { resolvedData: string }> }) {
|
|
15
|
-
* super({ existingCache, nodeName: 'emoji' });
|
|
16
|
-
* }
|
|
17
|
-
* nodeToKey(node: { attrs: EmojiAttributes }): string {
|
|
18
|
-
* return `${node.attrs.shortName}-${node.attrs.text}-${node.attrs.id}`;
|
|
19
|
-
* }
|
|
20
|
-
* resolve(node: { attrs: EmojiAttributes }, _?: { signal: AbortSignal }) {
|
|
21
|
-
* return Promise.resolve({ resolvedData: 'resolved' });
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* ### Use the provider
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* const emojiNodeDataProvider = new EmojiNodeDataProvider();
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* ### Caching
|
|
34
|
-
*
|
|
35
|
-
* @see {@link buildCaches} for more information on building caches.
|
|
36
|
-
*
|
|
37
|
-
* #### Load an existing provider with a cache
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* ```
|
|
41
|
-
* await buildCaches({
|
|
42
|
-
* adf: docFromSomewhere,
|
|
43
|
-
* nodeDataProviders: [emojiNodeDataProvider],
|
|
44
|
-
* signal: AbortSignal.timeout(5000),
|
|
45
|
-
* });
|
|
46
|
-
* emojiNodeDataProvider // { 'key': 'value' }
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* ### Load an new provider with an existing cache
|
|
50
|
-
*
|
|
51
|
-
* @example
|
|
52
|
-
* ```
|
|
53
|
-
* const provider1 = new ExampleNodeDataProvider();
|
|
54
|
-
* await buildCaches({adf, nodeDataProviders: [provider1]})
|
|
55
|
-
* provider1.cache // { 'key': 'value' }
|
|
56
|
-
*
|
|
57
|
-
* const provider2 = new ExampleNodeDataProvider({existingCache: provider1.cache});
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
export declare class NodeDataProvider<INode extends ReceivableNode, Result extends unknown> {
|
|
61
|
-
/**
|
|
62
|
-
* This is added to ease building types
|
|
63
|
-
*/
|
|
64
|
-
__node: INode;
|
|
65
|
-
private __cache;
|
|
66
|
-
/**
|
|
67
|
-
* This takes a node and returns a key that can be used to cache the result of the resolve function.
|
|
68
|
-
*/
|
|
69
|
-
nodeToKey: (node: INode) => string;
|
|
70
|
-
/**
|
|
71
|
-
* This returns the information required to render a node.
|
|
72
|
-
*
|
|
73
|
-
* If unresolvable, this method will throw an error.
|
|
74
|
-
*
|
|
75
|
-
* If signal is aborted, this method will return undefined.
|
|
76
|
-
*/
|
|
77
|
-
resolve: (node: INode, _?: {
|
|
78
|
-
signal?: AbortSignal;
|
|
79
|
-
}) => Promise<Result | undefined>;
|
|
80
|
-
/**
|
|
81
|
-
* The adf node name this provider is responsible for.
|
|
82
|
-
*/
|
|
83
|
-
nodeName: string;
|
|
84
|
-
constructor({ existingCache, nodeName, nodeToKey, resolve, }: {
|
|
85
|
-
/**
|
|
86
|
-
* A cache to load the provider with.
|
|
87
|
-
*
|
|
88
|
-
* @see {@link buildCaches} for more information on building caches.
|
|
89
|
-
*/
|
|
90
|
-
existingCache?: Record<string, Result>;
|
|
91
|
-
/**
|
|
92
|
-
* The adf node name this provider is responsible for.
|
|
93
|
-
*
|
|
94
|
-
* It is used for;
|
|
95
|
-
* - determining if the traverser should use this provider to resolve a node when building caches
|
|
96
|
-
* - identifying the node when submitting analytics events via the helper react hooks
|
|
97
|
-
*/
|
|
98
|
-
nodeName: string;
|
|
99
|
-
nodeToKey: typeof NodeDataProvider.prototype.nodeToKey;
|
|
100
|
-
resolve: typeof NodeDataProvider.prototype.resolve;
|
|
101
|
-
});
|
|
102
|
-
/**
|
|
103
|
-
* Updates the providers cache.
|
|
104
|
-
*
|
|
105
|
-
* Useful in scenarios such as SSR where the cache is built on the server and then passed to the client.
|
|
106
|
-
*
|
|
107
|
-
* Avoids the need to provide the cache to the constructor (to allow decoupling creation of node data providers from cache building),
|
|
108
|
-
* and allow for caching to be managed at a group level across multiple providers.
|
|
109
|
-
*
|
|
110
|
-
* This is not expected to be used by consumers, for internal consumption examples;
|
|
111
|
-
* @see {@link buildCaches}
|
|
112
|
-
*
|
|
113
|
-
*/
|
|
114
|
-
updateCache(cache: Record<string, Result>, options: {
|
|
115
|
-
strategy: 'merge-override' | 'replace';
|
|
116
|
-
}): void;
|
|
117
|
-
/**
|
|
118
|
-
* This is the cache for the provider.
|
|
119
|
-
*/
|
|
120
|
-
get cache(): Record<string, Result>;
|
|
121
|
-
private pending;
|
|
122
|
-
get(node: INode, _?: {
|
|
123
|
-
signal: AbortSignal;
|
|
124
|
-
}): Promise<Result | undefined> | Result;
|
|
125
|
-
}
|
|
126
|
-
export type ReceivableNode = {
|
|
127
|
-
[key: string]: any;
|
|
128
|
-
attrs: {
|
|
129
|
-
[key: string]: any;
|
|
130
|
-
};
|
|
131
|
-
};
|
|
132
|
-
export type ResolveOptions = {
|
|
133
|
-
signal: AbortSignal;
|
|
134
|
-
};
|
|
1
|
+
export { NodeDataProvider } from './node-data-provider';
|
|
2
|
+
export { prefetchNodeDataProvidersData } from './utils/prefetch-node-data-providers-data';
|