@player-ui/async-node-plugin 0.15.3 → 0.15.4--canary.881.37421

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.
@@ -3,32 +3,22 @@ import { NodeType as NodeType5, getNodeID } from "@player-ui/player";
3
3
  import { AsyncSeriesBailHook, SyncBailHook } from "tapable-ts";
4
4
  import queueMicrotask from "queue-microtask";
5
5
 
6
- // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/transform.ts
7
- import { Builder } from "@player-ui/player";
8
- var asyncTransform = (assetId, wrapperAssetType, asset, flatten, path = ["values"]) => {
9
- const id = "async-" + assetId;
10
- const asyncNode = Builder.asyncNode(id, flatten);
11
- let multiNode;
12
- let assetNode;
13
- if (asset) {
14
- assetNode = Builder.assetWrapper(asset);
15
- multiNode = Builder.multiNode(assetNode, asyncNode);
16
- } else {
17
- multiNode = Builder.multiNode(asyncNode);
18
- }
19
- const wrapperAsset = Builder.asset({
20
- id: wrapperAssetType + "-" + id,
21
- type: wrapperAssetType
22
- });
23
- Builder.addChild(wrapperAsset, path, multiNode);
24
- return wrapperAsset;
25
- };
26
-
27
- // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/createAsyncTransform.ts
6
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/AsyncNodeError.ts
28
7
  import {
29
- Builder as Builder2,
30
- NodeType as NodeType4
8
+ ErrorSeverity
31
9
  } from "@player-ui/player";
10
+ var ASYNC_ERROR_TYPE = "ASYNC-PLUGIN";
11
+ var AsyncNodeError = class extends Error {
12
+ constructor(node, message, cause) {
13
+ super(message);
14
+ this.cause = cause;
15
+ this.type = ASYNC_ERROR_TYPE;
16
+ this.severity = ErrorSeverity.ERROR;
17
+ this.metadata = {
18
+ node
19
+ };
20
+ }
21
+ };
32
22
 
33
23
  // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/utils/extractNodeFromPath.ts
34
24
  var getMatchValue = (pathA, pathB) => {
@@ -125,7 +115,59 @@ var requiresAssetWrapper = (node) => {
125
115
  return node.value.type === NodeType3.Asset;
126
116
  };
127
117
 
118
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/utils/isAsyncPlayerError.ts
119
+ var isAsyncPlayerError = (error) => {
120
+ return error.type === ASYNC_ERROR_TYPE;
121
+ };
122
+
123
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/utils/getNodeFromError.ts
124
+ import { ErrorTypes } from "@player-ui/player";
125
+ var getNodeFromError = (playerError, context) => {
126
+ if (playerError.type === ErrorTypes.RENDER) {
127
+ const { assetId } = playerError.metadata ?? {};
128
+ if (typeof assetId !== "string") {
129
+ return void 0;
130
+ }
131
+ return context.assetIdCache.get(assetId);
132
+ }
133
+ if (playerError.type === ErrorTypes.VIEW) {
134
+ const { node } = playerError.metadata ?? {};
135
+ if (typeof node === "object" && node !== null && !Array.isArray(node)) {
136
+ return node;
137
+ }
138
+ }
139
+ if (isAsyncPlayerError(playerError) && playerError.metadata !== void 0) {
140
+ return context.asyncNodeCache.get(playerError.metadata.node.id)?.asyncNode;
141
+ }
142
+ return void 0;
143
+ };
144
+
145
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/transform.ts
146
+ import { Builder } from "@player-ui/player";
147
+ var asyncTransform = (assetId, wrapperAssetType, asset, flatten, path = ["values"]) => {
148
+ const id = "async-" + assetId;
149
+ const asyncNode = Builder.asyncNode(id, flatten);
150
+ let multiNode;
151
+ let assetNode;
152
+ if (asset) {
153
+ assetNode = Builder.assetWrapper(asset);
154
+ multiNode = Builder.multiNode(assetNode, asyncNode);
155
+ } else {
156
+ multiNode = Builder.multiNode(asyncNode);
157
+ }
158
+ const wrapperAsset = Builder.asset({
159
+ id: wrapperAssetType + "-" + id,
160
+ type: wrapperAssetType
161
+ });
162
+ Builder.addChild(wrapperAsset, path, multiNode);
163
+ return wrapperAsset;
164
+ };
165
+
128
166
  // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/createAsyncTransform.ts
167
+ import {
168
+ Builder as Builder2,
169
+ NodeType as NodeType4
170
+ } from "@player-ui/player";
129
171
  var defaultGetNodeId = (node) => {
130
172
  return `async-${node.value.id}`;
131
173
  };
@@ -235,8 +277,8 @@ var AsyncNodePluginPlugin = class {
235
277
  * @param options Options provided for node resolution, including a potential parseNode function to process the result.
236
278
  * @param view The view instance where the node resides. This can be undefined if the view is not currently active.
237
279
  */
238
- parseNodeAndUpdate(node, context, result, options) {
239
- let parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
280
+ parseNodeAndUpdate(node, context, result, parseFunction) {
281
+ let parsedNode = parseFunction && result ? parseFunction(result) : void 0;
240
282
  if (parsedNode && node.onValueReceived) {
241
283
  parsedNode = node.onValueReceived(parsedNode);
242
284
  }
@@ -252,16 +294,30 @@ var AsyncNodePluginPlugin = class {
252
294
  * @param view The view instance where the node resides. This can be undefined if the view is not currently active.
253
295
  */
254
296
  handleAsyncUpdate(node, context, newNode) {
255
- const { nodeResolveCache, viewController, originalNodeCache } = context;
256
- if (nodeResolveCache.get(node.id) !== newNode) {
257
- nodeResolveCache.set(node.id, newNode ? newNode : node);
258
- const originalNode = originalNodeCache.get(node.id) ?? /* @__PURE__ */ new Set([node]);
259
- viewController.updateViewAST(originalNode);
297
+ const { asyncNodeCache: asyncNodeInfo, viewController } = context;
298
+ const entry = asyncNodeInfo.get(node.id);
299
+ if (!entry) {
300
+ throw new Error("Failed to update async content. Cache entry not found");
301
+ }
302
+ if (entry.resolvedContent !== newNode) {
303
+ entry.resolvedContent = newNode ? newNode : entry.asyncNode;
304
+ viewController.updateViewAST(entry.updateNodes);
260
305
  }
261
306
  }
262
- hasValidMapping(node, context) {
263
- const { nodeResolveCache } = context;
264
- return nodeResolveCache.has(node.id) && nodeResolveCache.get(node.id) !== node;
307
+ hasValidMapping(cacheEntry) {
308
+ return cacheEntry.resolvedContent !== void 0 && cacheEntry.resolvedContent !== cacheEntry.asyncNode;
309
+ }
310
+ getOrCreateAsyncNodeCacheEntry(node, context) {
311
+ const { asyncNodeCache: asyncNodeInfo } = context;
312
+ let entry = asyncNodeInfo.get(node.id);
313
+ if (!entry) {
314
+ entry = {
315
+ asyncNode: node,
316
+ updateNodes: /* @__PURE__ */ new Set()
317
+ };
318
+ asyncNodeInfo.set(node.id, entry);
319
+ }
320
+ return entry;
265
321
  }
266
322
  /**
267
323
  * Handles the asynchronous API integration for resolving nodes.
@@ -270,16 +326,24 @@ var AsyncNodePluginPlugin = class {
270
326
  * @param view
271
327
  */
272
328
  applyResolver(resolver, context) {
329
+ const { assetIdCache } = context;
330
+ resolver.hooks.afterNodeUpdate.tap(this.name, (original, _, update) => {
331
+ if (update.node.type !== NodeType5.Asset && update.node.type !== NodeType5.View) {
332
+ return;
333
+ }
334
+ assetIdCache.set(update.value.id, original);
335
+ });
273
336
  resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
274
337
  if (!this.isAsync(node)) {
275
338
  return node === null ? node : this.resolveAsyncChildren(node, context);
276
339
  }
340
+ const entry = this.getOrCreateAsyncNodeCacheEntry(node, context);
277
341
  if (options.node) {
278
- context.originalNodeCache.set(node.id, /* @__PURE__ */ new Set([options.node]));
342
+ entry.updateNodes = /* @__PURE__ */ new Set([options.node]);
343
+ context.generatedByMap.set(options.node, node.id);
279
344
  }
280
- const resolvedNode = context.nodeResolveCache.get(node.id);
281
- if (resolvedNode !== void 0) {
282
- return this.resolveAsyncChildren(resolvedNode, context);
345
+ if (entry.resolvedContent !== void 0) {
346
+ return this.resolveAsyncChildren(entry.resolvedContent, context);
283
347
  }
284
348
  if (context.inProgressNodes.has(node.id)) {
285
349
  return node;
@@ -303,16 +367,22 @@ var AsyncNodePluginPlugin = class {
303
367
  let index = 0;
304
368
  while (index < node.values.length) {
305
369
  const childNode = node.values[index];
306
- if (childNode?.type !== NodeType5.Async || !this.hasValidMapping(childNode, context)) {
370
+ if (childNode?.type !== NodeType5.Async) {
307
371
  index++;
308
372
  continue;
309
373
  }
310
- const mappedNode = context.nodeResolveCache.get(childNode.id);
374
+ const entry = this.getOrCreateAsyncNodeCacheEntry(childNode, context);
375
+ if (!this.hasValidMapping(entry)) {
376
+ index++;
377
+ continue;
378
+ }
379
+ const mappedNode = entry.resolvedContent;
311
380
  const nodeSet = /* @__PURE__ */ new Set();
312
381
  if (mappedNode.type === NodeType5.MultiNode && childNode.flatten) {
313
382
  mappedNode.values.forEach((v) => {
314
383
  v.parent = node;
315
384
  nodeSet.add(v);
385
+ context.originalParentMap.set(v, childNode);
316
386
  });
317
387
  node.values = [
318
388
  ...node.values.slice(0, index),
@@ -324,13 +394,21 @@ var AsyncNodePluginPlugin = class {
324
394
  mappedNode.parent = node;
325
395
  nodeSet.add(mappedNode);
326
396
  }
327
- context.originalNodeCache.set(childNode.id, nodeSet);
397
+ entry.updateNodes = nodeSet;
398
+ for (const n of nodeSet) {
399
+ context.generatedByMap.set(n, childNode.id);
400
+ }
328
401
  }
329
402
  } else if ("children" in node) {
330
403
  node.children?.forEach((c) => {
331
- while (c.value.type === NodeType5.Async && this.hasValidMapping(c.value, context)) {
332
- const mappedNode = context.nodeResolveCache.get(c.value.id);
333
- context.originalNodeCache.set(c.value.id, /* @__PURE__ */ new Set([mappedNode]));
404
+ while (c.value.type === NodeType5.Async) {
405
+ const entry = this.getOrCreateAsyncNodeCacheEntry(c.value, context);
406
+ if (!this.hasValidMapping(entry)) {
407
+ break;
408
+ }
409
+ const mappedNode = entry.resolvedContent;
410
+ entry.updateNodes = /* @__PURE__ */ new Set([mappedNode]);
411
+ context.generatedByMap.set(mappedNode, c.value.id);
334
412
  c.value = mappedNode;
335
413
  c.value.parent = node;
336
414
  }
@@ -343,27 +421,27 @@ var AsyncNodePluginPlugin = class {
343
421
  const result = await this.basePlugin?.hooks.onAsyncNode.call(
344
422
  node,
345
423
  (result2) => {
346
- this.parseNodeAndUpdate(node, context, result2, options);
424
+ this.parseNodeAndUpdate(node, context, result2, options.parseNode);
347
425
  }
348
426
  );
349
427
  context.inProgressNodes.delete(node.id);
350
- this.parseNodeAndUpdate(node, context, result, options);
428
+ this.parseNodeAndUpdate(node, context, result, options.parseNode);
351
429
  } catch (e) {
352
- const error = e instanceof Error ? e : new Error(String(e));
353
- const result = this.basePlugin?.hooks.onAsyncNodeError.call(error, node);
354
- if (result === void 0) {
355
- const playerState = this.basePlugin?.getPlayerInstance()?.getState();
356
- if (playerState?.status === "in-progress") {
357
- playerState.fail(error);
358
- }
430
+ const cause = e instanceof Error ? e : new Error(String(e));
431
+ const playerState = this.basePlugin?.getPlayerInstance()?.getState();
432
+ if (playerState?.status !== "in-progress") {
433
+ options.logger?.warn(
434
+ "[AsyncNodePlugin]: An error occured during async node resolution, but the player instance is no londer running. Exception: ",
435
+ cause
436
+ );
359
437
  return;
360
438
  }
361
- options.logger?.error(
362
- "Async node handling failed and resolved with a fallback. Error:",
363
- error
439
+ const error = new AsyncNodeError(
440
+ node,
441
+ "An error occured during async node resolution. See cause for details.",
442
+ cause
364
443
  );
365
- context.inProgressNodes.delete(node.id);
366
- this.parseNodeAndUpdate(node, context, result, options);
444
+ playerState.controllers.error.captureError(error);
367
445
  }
368
446
  }
369
447
  isAsync(node) {
@@ -409,15 +487,84 @@ var AsyncNodePluginPlugin = class {
409
487
  view.hooks.parser.tap("async", this.applyParser.bind(this));
410
488
  }
411
489
  applyPlayer(player) {
490
+ let currentContext = void 0;
491
+ let parser = void 0;
492
+ player.hooks.errorController.tap("async", (errorController) => {
493
+ errorController.hooks.onError.tap("async", (playerError) => {
494
+ if (currentContext === void 0) {
495
+ return void 0;
496
+ }
497
+ const tryHandleError = (asyncNode) => {
498
+ if (this.basePlugin === void 0) {
499
+ player.logger.warn(
500
+ `[AsyncNodePlugin]: No plugin detected. Error handling will fail`
501
+ );
502
+ }
503
+ let result = void 0;
504
+ result = this.basePlugin?.hooks.onAsyncNodeError.call(
505
+ playerError,
506
+ asyncNode
507
+ );
508
+ if (result === void 0) {
509
+ return false;
510
+ }
511
+ player.logger?.warn(
512
+ "[AsyncNodePlugin]: Async node handling failed and resolved with a fallback. Cause:",
513
+ playerError.message
514
+ );
515
+ currentContext.inProgressNodes.delete(asyncNode.id);
516
+ this.parseNodeAndUpdate(
517
+ asyncNode,
518
+ currentContext,
519
+ result,
520
+ parser?.parseObject.bind(parser)
521
+ );
522
+ return true;
523
+ };
524
+ const getNextNode = (node2) => {
525
+ const parent = currentContext?.originalParentMap.get(node2) ?? node2.parent;
526
+ if (!parent) {
527
+ return void 0;
528
+ }
529
+ return this.isAsync(parent) ? currentContext?.asyncNodeCache.get(parent.id)?.asyncNode : parent;
530
+ };
531
+ let node = getNodeFromError(playerError, currentContext);
532
+ if (node?.type === NodeType5.Async && tryHandleError(node)) {
533
+ return true;
534
+ }
535
+ while (node !== void 0) {
536
+ const generatedBy = currentContext.generatedByMap.get(node);
537
+ if (generatedBy) {
538
+ const entry = currentContext.asyncNodeCache.get(generatedBy);
539
+ if (!entry) {
540
+ node = getNextNode(node);
541
+ continue;
542
+ }
543
+ const { asyncNode } = entry;
544
+ if (tryHandleError(asyncNode)) {
545
+ return true;
546
+ }
547
+ }
548
+ node = getNextNode(node);
549
+ }
550
+ return void 0;
551
+ });
552
+ });
412
553
  player.hooks.viewController.tap("async", (viewController) => {
413
554
  viewController.hooks.view.tap("async", (view) => {
555
+ view.hooks.parser.tap(this.name, (p) => {
556
+ parser = p;
557
+ });
414
558
  const context = {
415
- nodeResolveCache: /* @__PURE__ */ new Map(),
416
559
  inProgressNodes: /* @__PURE__ */ new Set(),
417
560
  view,
418
561
  viewController,
419
- originalNodeCache: /* @__PURE__ */ new Map()
562
+ generatedByMap: /* @__PURE__ */ new Map(),
563
+ assetIdCache: /* @__PURE__ */ new Map(),
564
+ asyncNodeCache: /* @__PURE__ */ new Map(),
565
+ originalParentMap: /* @__PURE__ */ new Map()
420
566
  };
567
+ currentContext = context;
421
568
  view.hooks.resolver.tap("async", (resolver) => {
422
569
  this.applyResolver(resolver, context);
423
570
  });