@player-ui/async-node-plugin 1.1.1--canary.934.41671 → 1.1.1--canary.937.41794
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/dist/AsyncNodePlugin.native.js +2649 -3270
- package/dist/AsyncNodePlugin.native.js.map +1 -1
- package/dist/cjs/index.cjs +70 -224
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +61 -217
- package/dist/index.mjs +61 -217
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -4
- package/src/__tests__/index.test.ts +4 -414
- package/src/index.ts +69 -207
- package/src/utils/index.ts +0 -2
- package/types/index.d.ts +18 -3
- package/types/utils/index.d.ts +0 -2
- package/src/AsyncNodeError.ts +0 -30
- package/src/internal-types.ts +0 -30
- package/src/utils/__tests__/getNodeFromError.test.ts +0 -219
- package/src/utils/__tests__/isAsyncPlayerError.test.ts +0 -33
- package/src/utils/getNodeFromError.ts +0 -34
- package/src/utils/isAsyncPlayerError.ts +0 -8
- package/types/AsyncNodeError.d.ts +0 -13
- package/types/internal-types.d.ts +0 -29
- package/types/utils/getNodeFromError.d.ts +0 -5
- package/types/utils/isAsyncPlayerError.d.ts +0 -4
package/src/index.ts
CHANGED
|
@@ -10,17 +10,33 @@ import type {
|
|
|
10
10
|
ViewPlugin,
|
|
11
11
|
Resolver,
|
|
12
12
|
Resolve,
|
|
13
|
+
ViewController,
|
|
13
14
|
} from "@player-ui/player";
|
|
14
15
|
import { AsyncSeriesBailHook, SyncBailHook } from "tapable-ts";
|
|
15
16
|
import queueMicrotask from "queue-microtask";
|
|
16
|
-
import { AsyncNodeError } from "./AsyncNodeError";
|
|
17
|
-
import { AsyncNodeInfo, AsyncPluginContext } from "./internal-types";
|
|
18
|
-
import { getNodeFromError } from "./utils";
|
|
19
17
|
|
|
20
18
|
export * from "./types";
|
|
21
19
|
export * from "./transform";
|
|
22
20
|
export * from "./createAsyncTransform";
|
|
23
21
|
|
|
22
|
+
/** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
|
|
23
|
+
* This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
|
|
24
|
+
*/
|
|
25
|
+
type AsyncPluginContext = {
|
|
26
|
+
/** Map of async node id to resolved content */
|
|
27
|
+
nodeResolveCache: Map<string, Node.Node>;
|
|
28
|
+
/** The view instance this context is attached to. */
|
|
29
|
+
view: ViewInstance;
|
|
30
|
+
/** The view controller this context is attached to. */
|
|
31
|
+
viewController: ViewController;
|
|
32
|
+
/** Map of async node id to promises being used to resolve them */
|
|
33
|
+
inProgressNodes: Set<string>;
|
|
34
|
+
/** Map of async node ids to the original node they represent.
|
|
35
|
+
* In some cases, async nodes are transformed into from other node types so the original reference is needed in order to trigger an update on the view when the async node changes.
|
|
36
|
+
*/
|
|
37
|
+
originalNodeCache: Map<string, Set<Node.Node>>;
|
|
38
|
+
};
|
|
39
|
+
|
|
24
40
|
export interface AsyncNodePluginOptions {
|
|
25
41
|
/** A set of plugins to load */
|
|
26
42
|
plugins?: AsyncNodeViewPlugin[];
|
|
@@ -126,10 +142,10 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
126
142
|
node: Node.Async,
|
|
127
143
|
context: AsyncPluginContext,
|
|
128
144
|
result: any,
|
|
129
|
-
|
|
145
|
+
options: Resolve.NodeResolveOptions,
|
|
130
146
|
) {
|
|
131
147
|
let parsedNode =
|
|
132
|
-
|
|
148
|
+
options.parseNode && result ? options.parseNode(result) : undefined;
|
|
133
149
|
|
|
134
150
|
if (parsedNode && node.onValueReceived) {
|
|
135
151
|
parsedNode = node.onValueReceived(parsedNode);
|
|
@@ -152,41 +168,22 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
152
168
|
context: AsyncPluginContext,
|
|
153
169
|
newNode?: Node.Node | null,
|
|
154
170
|
) {
|
|
155
|
-
const {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (entry.resolvedContent !== newNode) {
|
|
161
|
-
entry.resolvedContent = newNode ? newNode : entry.asyncNode;
|
|
162
|
-
viewController.updateViewAST(entry.updateNodes);
|
|
171
|
+
const { nodeResolveCache, viewController, originalNodeCache } = context;
|
|
172
|
+
if (nodeResolveCache.get(node.id) !== newNode) {
|
|
173
|
+
nodeResolveCache.set(node.id, newNode ? newNode : node);
|
|
174
|
+
const originalNode = originalNodeCache.get(node.id) ?? new Set([node]);
|
|
175
|
+
viewController.updateViewAST(originalNode);
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
178
|
|
|
166
179
|
private hasValidMapping(
|
|
167
|
-
cacheEntry: AsyncNodeInfo,
|
|
168
|
-
): cacheEntry is Required<AsyncNodeInfo> {
|
|
169
|
-
return (
|
|
170
|
-
cacheEntry.resolvedContent !== undefined &&
|
|
171
|
-
cacheEntry.resolvedContent !== cacheEntry.asyncNode
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private getOrCreateAsyncNodeCacheEntry(
|
|
176
180
|
node: Node.Async,
|
|
177
181
|
context: AsyncPluginContext,
|
|
178
|
-
):
|
|
179
|
-
const {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
asyncNode: node,
|
|
184
|
-
updateNodes: new Set(),
|
|
185
|
-
};
|
|
186
|
-
asyncNodeInfo.set(node.id, entry);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return entry;
|
|
182
|
+
): boolean {
|
|
183
|
+
const { nodeResolveCache } = context;
|
|
184
|
+
return (
|
|
185
|
+
nodeResolveCache.has(node.id) && nodeResolveCache.get(node.id) !== node
|
|
186
|
+
);
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
/**
|
|
@@ -196,32 +193,17 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
196
193
|
* @param view
|
|
197
194
|
*/
|
|
198
195
|
applyResolver(resolver: Resolver, context: AsyncPluginContext): void {
|
|
199
|
-
const { assetIdCache } = context;
|
|
200
|
-
resolver.hooks.afterNodeUpdate.tap(this.name, (original, _, update) => {
|
|
201
|
-
if (
|
|
202
|
-
update.node.type !== NodeType.Asset &&
|
|
203
|
-
update.node.type !== NodeType.View
|
|
204
|
-
) {
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
assetIdCache.set(update.value.id, original);
|
|
209
|
-
});
|
|
210
|
-
|
|
211
196
|
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
212
197
|
if (!this.isAsync(node)) {
|
|
213
198
|
return node === null ? node : this.resolveAsyncChildren(node, context);
|
|
214
199
|
}
|
|
215
|
-
|
|
216
|
-
const entry = this.getOrCreateAsyncNodeCacheEntry(node, context);
|
|
217
|
-
|
|
218
200
|
if (options.node) {
|
|
219
|
-
|
|
220
|
-
context.generatedByMap.set(options.node, node.id);
|
|
201
|
+
context.originalNodeCache.set(node.id, new Set([options.node]));
|
|
221
202
|
}
|
|
222
203
|
|
|
223
|
-
|
|
224
|
-
|
|
204
|
+
const resolvedNode = context.nodeResolveCache.get(node.id);
|
|
205
|
+
if (resolvedNode !== undefined) {
|
|
206
|
+
return this.resolveAsyncChildren(resolvedNode, context);
|
|
225
207
|
}
|
|
226
208
|
|
|
227
209
|
if (context.inProgressNodes.has(node.id)) {
|
|
@@ -254,24 +236,20 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
254
236
|
let index = 0;
|
|
255
237
|
while (index < node.values.length) {
|
|
256
238
|
const childNode = node.values[index];
|
|
257
|
-
if (
|
|
239
|
+
if (
|
|
240
|
+
childNode?.type !== NodeType.Async ||
|
|
241
|
+
!this.hasValidMapping(childNode, context)
|
|
242
|
+
) {
|
|
258
243
|
index++;
|
|
259
244
|
continue;
|
|
260
245
|
}
|
|
261
|
-
const entry = this.getOrCreateAsyncNodeCacheEntry(childNode, context);
|
|
262
246
|
|
|
263
|
-
|
|
264
|
-
index++;
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const mappedNode = entry.resolvedContent;
|
|
247
|
+
const mappedNode = context.nodeResolveCache.get(childNode.id)!;
|
|
269
248
|
const nodeSet = new Set<Node.Node>();
|
|
270
249
|
if (mappedNode.type === NodeType.MultiNode && childNode.flatten) {
|
|
271
250
|
mappedNode.values.forEach((v: Node.Node) => {
|
|
272
251
|
v.parent = node;
|
|
273
252
|
nodeSet.add(v);
|
|
274
|
-
context.originalParentMap.set(v, childNode);
|
|
275
253
|
});
|
|
276
254
|
node.values = [
|
|
277
255
|
...node.values.slice(0, index),
|
|
@@ -283,23 +261,17 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
283
261
|
mappedNode.parent = node;
|
|
284
262
|
nodeSet.add(mappedNode);
|
|
285
263
|
}
|
|
286
|
-
|
|
287
|
-
for (const n of nodeSet) {
|
|
288
|
-
context.generatedByMap.set(n, childNode.id);
|
|
289
|
-
}
|
|
264
|
+
context.originalNodeCache.set(childNode.id, nodeSet);
|
|
290
265
|
}
|
|
291
266
|
} else if ("children" in node) {
|
|
292
267
|
node.children?.forEach((c) => {
|
|
293
268
|
// Similar to above, using a while loop lets us handle when async nodes produce more async nodes.
|
|
294
|
-
while (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const mappedNode = entry.resolvedContent;
|
|
301
|
-
entry.updateNodes = new Set([mappedNode]);
|
|
302
|
-
context.generatedByMap.set(mappedNode, c.value.id);
|
|
269
|
+
while (
|
|
270
|
+
c.value.type === NodeType.Async &&
|
|
271
|
+
this.hasValidMapping(c.value, context)
|
|
272
|
+
) {
|
|
273
|
+
const mappedNode = context.nodeResolveCache.get(c.value.id)!;
|
|
274
|
+
context.originalNodeCache.set(c.value.id, new Set([mappedNode]));
|
|
303
275
|
c.value = mappedNode;
|
|
304
276
|
c.value.parent = node;
|
|
305
277
|
}
|
|
@@ -315,51 +287,38 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
315
287
|
options: Resolve.NodeResolveOptions,
|
|
316
288
|
) {
|
|
317
289
|
try {
|
|
318
|
-
// Track whether the callback pushed content while the hook was pending;
|
|
319
|
-
// if so it wins over the bail return (avoids the last-writer-wins race
|
|
320
|
-
// that intermittently dropped streamed rows).
|
|
321
|
-
let deliveredViaCallback = false;
|
|
322
|
-
|
|
323
290
|
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
324
291
|
node,
|
|
325
|
-
(
|
|
326
|
-
|
|
327
|
-
this.parseNodeAndUpdate(
|
|
328
|
-
node,
|
|
329
|
-
context,
|
|
330
|
-
streamedResult,
|
|
331
|
-
options.parseNode,
|
|
332
|
-
);
|
|
292
|
+
(result) => {
|
|
293
|
+
this.parseNodeAndUpdate(node, context, result, options);
|
|
333
294
|
},
|
|
334
295
|
);
|
|
335
296
|
|
|
336
297
|
// Stop tracking before the next update is triggered
|
|
337
298
|
context.inProgressNodes.delete(node.id);
|
|
338
|
-
|
|
339
|
-
// Once the callback has delivered content it is the source of truth, so a
|
|
340
|
-
// stale/empty bail return must not clobber it. Skip unless no callback ran
|
|
341
|
-
// (!deliveredViaCallback) and the return carries content (result != null).
|
|
342
|
-
if (!deliveredViaCallback && result != null) {
|
|
343
|
-
this.parseNodeAndUpdate(node, context, result, options.parseNode);
|
|
344
|
-
}
|
|
299
|
+
this.parseNodeAndUpdate(node, context, result, options);
|
|
345
300
|
} catch (e: unknown) {
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
if (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
301
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
302
|
+
const result = this.basePlugin?.hooks.onAsyncNodeError.call(error, node);
|
|
303
|
+
|
|
304
|
+
if (result === undefined) {
|
|
305
|
+
const playerState = this.basePlugin?.getPlayerInstance()?.getState();
|
|
306
|
+
|
|
307
|
+
if (playerState?.status === "in-progress") {
|
|
308
|
+
playerState.fail(error);
|
|
309
|
+
}
|
|
310
|
+
|
|
354
311
|
return;
|
|
355
312
|
}
|
|
356
313
|
|
|
357
|
-
|
|
358
|
-
node,
|
|
359
|
-
|
|
360
|
-
cause,
|
|
314
|
+
options.logger?.error(
|
|
315
|
+
"Async node handling failed and resolved with a fallback. Error:",
|
|
316
|
+
error,
|
|
361
317
|
);
|
|
362
|
-
|
|
318
|
+
|
|
319
|
+
// Stop tracking before the next update is triggered
|
|
320
|
+
context.inProgressNodes.delete(node.id);
|
|
321
|
+
this.parseNodeAndUpdate(node, context, result, options);
|
|
363
322
|
}
|
|
364
323
|
}
|
|
365
324
|
|
|
@@ -426,112 +385,15 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
426
385
|
}
|
|
427
386
|
|
|
428
387
|
applyPlayer(player: Player): void {
|
|
429
|
-
// TODO: Need a better mechanism for storing the current context.
|
|
430
|
-
let currentContext: AsyncPluginContext | undefined = undefined;
|
|
431
|
-
let parser: Parser | undefined = undefined;
|
|
432
|
-
|
|
433
|
-
player.hooks.errorController.tap("async", (errorController) => {
|
|
434
|
-
errorController.hooks.onError.tap("async", (playerError) => {
|
|
435
|
-
if (currentContext === undefined) {
|
|
436
|
-
return undefined;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/** Try to handle the error using the onAsyncNodeError hook. Returns true if new content is provided. */
|
|
440
|
-
const tryHandleError = (asyncNode: Node.Async): boolean => {
|
|
441
|
-
if (this.basePlugin === undefined) {
|
|
442
|
-
player.logger.warn(
|
|
443
|
-
`[AsyncNodePlugin]: No plugin detected. Error handling will fail`,
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
let result: any = undefined;
|
|
448
|
-
result = this.basePlugin?.hooks.onAsyncNodeError.call(
|
|
449
|
-
playerError,
|
|
450
|
-
asyncNode,
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
if (result === undefined) {
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
player.logger?.warn(
|
|
458
|
-
"[AsyncNodePlugin]: Async node handling failed and resolved with a fallback. Cause:",
|
|
459
|
-
playerError.message,
|
|
460
|
-
);
|
|
461
|
-
|
|
462
|
-
// Stop tracking before the next update is triggered
|
|
463
|
-
currentContext!.inProgressNodes.delete(asyncNode.id);
|
|
464
|
-
this.parseNodeAndUpdate(
|
|
465
|
-
asyncNode,
|
|
466
|
-
currentContext!,
|
|
467
|
-
result,
|
|
468
|
-
parser?.parseObject.bind(parser),
|
|
469
|
-
);
|
|
470
|
-
|
|
471
|
-
return true;
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
const getNextNode = (node: Node.Node): Node.Node | undefined => {
|
|
475
|
-
const parent =
|
|
476
|
-
currentContext?.originalParentMap.get(node) ?? node.parent;
|
|
477
|
-
|
|
478
|
-
if (!parent) {
|
|
479
|
-
return undefined;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// asyncNodeCache has current asyncNode reference more up to date with what's happening in the resolver. Sometimes AsyncNodeError has old references so this helps us move up the tree more accurately
|
|
483
|
-
return this.isAsync(parent)
|
|
484
|
-
? currentContext?.asyncNodeCache.get(parent.id)?.asyncNode
|
|
485
|
-
: parent;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
let node = getNodeFromError(playerError, currentContext);
|
|
489
|
-
// If the node is an async node try, to handle errors with it first.
|
|
490
|
-
if (node?.type === NodeType.Async && tryHandleError(node)) {
|
|
491
|
-
return true;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Loop through the nodes to see if something is generated by something else. Continue until the error is handled or there are no more nodes to check
|
|
495
|
-
while (node !== undefined) {
|
|
496
|
-
const generatedBy = currentContext.generatedByMap.get(node);
|
|
497
|
-
if (generatedBy) {
|
|
498
|
-
const entry = currentContext.asyncNodeCache.get(generatedBy);
|
|
499
|
-
|
|
500
|
-
if (!entry) {
|
|
501
|
-
node = getNextNode(node);
|
|
502
|
-
continue;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
const { asyncNode } = entry;
|
|
506
|
-
|
|
507
|
-
// Don't return false when the error isn't handled to allow for cases where one async is generated by another. Give different nodes a chance to try to recover from the error.
|
|
508
|
-
if (tryHandleError(asyncNode)) {
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
node = getNextNode(node);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
return undefined;
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
|
|
520
388
|
player.hooks.viewController.tap("async", (viewController) => {
|
|
521
389
|
viewController.hooks.view.tap("async", (view) => {
|
|
522
|
-
view.hooks.parser.tap(this.name, (p) => {
|
|
523
|
-
parser = p;
|
|
524
|
-
});
|
|
525
390
|
const context: AsyncPluginContext = {
|
|
391
|
+
nodeResolveCache: new Map(),
|
|
526
392
|
inProgressNodes: new Set(),
|
|
527
393
|
view,
|
|
528
394
|
viewController,
|
|
529
|
-
|
|
530
|
-
assetIdCache: new Map(),
|
|
531
|
-
asyncNodeCache: new Map(),
|
|
532
|
-
originalParentMap: new Map(),
|
|
395
|
+
originalNodeCache: new Map(),
|
|
533
396
|
};
|
|
534
|
-
currentContext = context;
|
|
535
397
|
|
|
536
398
|
view.hooks.resolver.tap("async", (resolver) => {
|
|
537
399
|
this.applyResolver(resolver, context);
|
package/src/utils/index.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver } from "@player-ui/player";
|
|
1
|
+
import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver, ViewController } from "@player-ui/player";
|
|
2
2
|
import { AsyncSeriesBailHook, SyncBailHook } from "tapable-ts";
|
|
3
|
-
import { AsyncPluginContext } from "./internal-types";
|
|
4
3
|
export * from "./types";
|
|
5
4
|
export * from "./transform";
|
|
6
5
|
export * from "./createAsyncTransform";
|
|
6
|
+
/** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
|
|
7
|
+
* This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
|
|
8
|
+
*/
|
|
9
|
+
type AsyncPluginContext = {
|
|
10
|
+
/** Map of async node id to resolved content */
|
|
11
|
+
nodeResolveCache: Map<string, Node.Node>;
|
|
12
|
+
/** The view instance this context is attached to. */
|
|
13
|
+
view: ViewInstance;
|
|
14
|
+
/** The view controller this context is attached to. */
|
|
15
|
+
viewController: ViewController;
|
|
16
|
+
/** Map of async node id to promises being used to resolve them */
|
|
17
|
+
inProgressNodes: Set<string>;
|
|
18
|
+
/** Map of async node ids to the original node they represent.
|
|
19
|
+
* In some cases, async nodes are transformed into from other node types so the original reference is needed in order to trigger an update on the view when the async node changes.
|
|
20
|
+
*/
|
|
21
|
+
originalNodeCache: Map<string, Set<Node.Node>>;
|
|
22
|
+
};
|
|
7
23
|
export interface AsyncNodePluginOptions {
|
|
8
24
|
/** A set of plugins to load */
|
|
9
25
|
plugins?: AsyncNodeViewPlugin[];
|
|
@@ -64,7 +80,6 @@ export declare class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
64
80
|
*/
|
|
65
81
|
private handleAsyncUpdate;
|
|
66
82
|
private hasValidMapping;
|
|
67
|
-
private getOrCreateAsyncNodeCacheEntry;
|
|
68
83
|
/**
|
|
69
84
|
* Handles the asynchronous API integration for resolving nodes.
|
|
70
85
|
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
package/types/utils/index.d.ts
CHANGED
package/src/AsyncNodeError.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ErrorSeverity,
|
|
3
|
-
type Node,
|
|
4
|
-
type PlayerErrorMetadata,
|
|
5
|
-
} from "@player-ui/player";
|
|
6
|
-
|
|
7
|
-
export const ASYNC_ERROR_TYPE = "ASYNC-PLUGIN";
|
|
8
|
-
export type AsyncErrorMetadata = {
|
|
9
|
-
node: Node.Async;
|
|
10
|
-
};
|
|
11
|
-
export class AsyncNodeError
|
|
12
|
-
extends Error
|
|
13
|
-
implements PlayerErrorMetadata<AsyncErrorMetadata>
|
|
14
|
-
{
|
|
15
|
-
readonly type: string = ASYNC_ERROR_TYPE;
|
|
16
|
-
readonly severity: ErrorSeverity = ErrorSeverity.ERROR;
|
|
17
|
-
readonly metadata: AsyncErrorMetadata;
|
|
18
|
-
|
|
19
|
-
constructor(
|
|
20
|
-
node: Node.Async,
|
|
21
|
-
message?: string,
|
|
22
|
-
public readonly cause?: Error | undefined,
|
|
23
|
-
) {
|
|
24
|
-
super(message);
|
|
25
|
-
|
|
26
|
-
this.metadata = {
|
|
27
|
-
node,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
}
|
package/src/internal-types.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { Node, ViewController, ViewInstance } from "@player-ui/player";
|
|
2
|
-
|
|
3
|
-
export type AsyncNodeInfo = {
|
|
4
|
-
/** The async node */
|
|
5
|
-
asyncNode: Node.Async;
|
|
6
|
-
/** All nodes that need to be updated when the async content changes. This could be the async node itself, or a node that created it (i.e. an asset node that transformed into an async node). */
|
|
7
|
-
updateNodes: Set<Node.Node>;
|
|
8
|
-
/** The resolved content for this async node */
|
|
9
|
-
resolvedContent?: Node.Node;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
|
|
13
|
-
* This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
|
|
14
|
-
*/
|
|
15
|
-
export type AsyncPluginContext = {
|
|
16
|
-
/** The view instance this context is attached to. */
|
|
17
|
-
view: ViewInstance;
|
|
18
|
-
/** The view controller this context is attached to. */
|
|
19
|
-
viewController: ViewController;
|
|
20
|
-
/** Set of async node ids that are currently being managed by an incomplete promise. */
|
|
21
|
-
inProgressNodes: Set<string>;
|
|
22
|
-
/** Map of async node ids to related info for that node. */
|
|
23
|
-
asyncNodeCache: Map<string, AsyncNodeInfo>;
|
|
24
|
-
/** Maps asset ids to its original node. Used to then search for what if could be generated by. */
|
|
25
|
-
assetIdCache: Map<string, Node.Node>;
|
|
26
|
-
/** Maps nodes to the async id that generated them. */
|
|
27
|
-
generatedByMap: Map<Node.Node, string>;
|
|
28
|
-
/** Map to track the original parent of nodes that were flattened into another. This is needed to track which async nodes actually generated these nodes. */
|
|
29
|
-
originalParentMap: Map<Node.Node, Node.Node>;
|
|
30
|
-
};
|