@pie-players/pie-players-shared 0.3.72 → 0.3.74

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.
Files changed (123) hide show
  1. package/README.md +27 -1
  2. package/dist/components/vendor/nds/README.md +7 -5
  3. package/dist/config/profile.d.ts +0 -2
  4. package/dist/config/profile.js +2 -8
  5. package/dist/i18n/index.d.ts +2 -3
  6. package/dist/i18n/index.js +2 -3
  7. package/dist/i18n/messages/en-US.d.ts +10 -0
  8. package/dist/i18n/messages/en-US.js +12 -2
  9. package/dist/i18n/messages/nl-NL.d.ts +6 -0
  10. package/dist/i18n/messages/nl-NL.js +8 -2
  11. package/dist/i18n/provider.d.ts +4 -5
  12. package/dist/i18n/provider.js +4 -5
  13. package/dist/index.d.ts +4 -2
  14. package/dist/index.js +3 -1
  15. package/dist/instrumentation/index.d.ts +5 -4
  16. package/dist/instrumentation/index.js +5 -4
  17. package/dist/instrumentation/new-relic-agent.d.ts +20 -0
  18. package/dist/instrumentation/new-relic-agent.js +24 -0
  19. package/dist/instrumentation/providers/BaseInstrumentationProvider.d.ts +5 -4
  20. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.d.ts +7 -7
  21. package/dist/instrumentation/providers/NewRelicInstrumentationProvider.js +21 -32
  22. package/dist/instrumentation/types.d.ts +7 -3
  23. package/dist/loader-config.d.ts +16 -6
  24. package/dist/loaders/controller-loading.d.ts +14 -0
  25. package/dist/loaders/controller-loading.js +12 -0
  26. package/dist/loaders/defaults.d.ts +10 -0
  27. package/dist/loaders/defaults.js +10 -0
  28. package/dist/loaders/element-loader.d.ts +20 -8
  29. package/dist/loaders/element-loader.js +102 -36
  30. package/dist/loaders/element-package-policy.d.ts +2 -0
  31. package/dist/loaders/element-package-policy.js +2 -1
  32. package/dist/loaders/esm-adapter.d.ts +18 -0
  33. package/dist/loaders/esm-adapter.js +617 -102
  34. package/dist/loaders/iife-adapter.d.ts +0 -5
  35. package/dist/loaders/iife-adapter.js +3 -9
  36. package/dist/loaders/index.d.ts +10 -3
  37. package/dist/loaders/index.js +8 -3
  38. package/dist/loaders/mathjax-version-conflict.d.ts +17 -0
  39. package/dist/loaders/mathjax-version-conflict.js +51 -0
  40. package/dist/loaders/module-shim.d.ts +12 -0
  41. package/dist/loaders/module-shim.js +12 -0
  42. package/dist/loaders/preloaded-alignment.d.ts +24 -0
  43. package/dist/loaders/preloaded-alignment.js +57 -0
  44. package/dist/loaders/preloaded-authored-tags.d.ts +26 -0
  45. package/dist/loaders/preloaded-authored-tags.js +69 -0
  46. package/dist/loaders/preloaded-registration.d.ts +56 -0
  47. package/dist/loaders/preloaded-registration.js +129 -0
  48. package/dist/media/index.d.ts +69 -0
  49. package/dist/media/index.js +194 -0
  50. package/dist/pie/authoring.d.ts +1 -1
  51. package/dist/pie/authoring.js +25 -18
  52. package/dist/pie/element-announcements.d.ts +39 -0
  53. package/dist/pie/element-announcements.js +67 -0
  54. package/dist/pie/element-observer.d.ts +3 -1
  55. package/dist/pie/element-observer.js +1 -0
  56. package/dist/pie/index.d.ts +6 -4
  57. package/dist/pie/index.js +6 -3
  58. package/dist/pie/initialization.js +13 -22
  59. package/dist/pie/initialize-element.d.ts +3 -0
  60. package/dist/pie/initialize-element.js +3 -4
  61. package/dist/pie/instrumentation-event-map.js +2 -9
  62. package/dist/pie/instrumentation-provider-resolution.d.ts +2 -1
  63. package/dist/pie/instrumentation-provider-resolution.js +0 -1
  64. package/dist/pie/item-session-contract.d.ts +47 -0
  65. package/dist/pie/item-session-contract.js +196 -9
  66. package/dist/pie/markup-math.d.ts +20 -0
  67. package/dist/pie/markup-math.js +118 -0
  68. package/dist/pie/math-rendering.d.ts +10 -21
  69. package/dist/pie/math-rendering.js +50 -35
  70. package/dist/pie/registry.d.ts +13 -1
  71. package/dist/pie/registry.js +39 -1
  72. package/dist/pie/resource-monitor.d.ts +6 -33
  73. package/dist/pie/resource-monitor.js +14 -213
  74. package/dist/pie/scoring.d.ts +11 -2
  75. package/dist/pie/scoring.js +18 -16
  76. package/dist/pie/session-commit.d.ts +121 -0
  77. package/dist/pie/session-commit.js +420 -0
  78. package/dist/pie/session-snapshot.d.ts +80 -0
  79. package/dist/pie/session-snapshot.js +166 -0
  80. package/dist/pie/tag-names.d.ts +1 -0
  81. package/dist/pie/tag-names.js +1 -0
  82. package/dist/pie/types.d.ts +4 -5
  83. package/dist/pie/types.js +1 -0
  84. package/dist/pie/updates.d.ts +2 -2
  85. package/dist/pie/updates.js +33 -15
  86. package/dist/pie/versioned-tag.d.ts +4 -0
  87. package/dist/pie/versioned-tag.js +4 -0
  88. package/dist/security/index.d.ts +2 -3
  89. package/dist/security/index.js +2 -3
  90. package/dist/security/sanitize-item-markup.d.ts +0 -2
  91. package/dist/security/sanitize-item-markup.js +0 -4
  92. package/dist/security/sanitize-svg-icon.d.ts +0 -2
  93. package/dist/security/sanitize-svg-icon.js +0 -5
  94. package/dist/security/wrap-overwide.d.ts +5 -0
  95. package/dist/security/wrap-overwide.js +16 -0
  96. package/dist/timed-media/policy.js +5 -16
  97. package/dist/types/index.d.ts +30 -311
  98. package/dist/types/index.js +0 -68
  99. package/dist/ui/attribute-coercion.d.ts +12 -0
  100. package/dist/ui/attribute-coercion.js +33 -0
  101. package/dist/ui/content-styles.d.ts +18 -16
  102. package/dist/ui/content-styles.js +67 -36
  103. package/dist/ui/overlay-containment.d.ts +31 -0
  104. package/dist/ui/overlay-containment.js +63 -0
  105. package/dist/ui/overlay-placement.d.ts +110 -0
  106. package/dist/ui/overlay-placement.js +222 -0
  107. package/dist/ui/pointer-gesture.d.ts +32 -0
  108. package/dist/ui/pointer-gesture.js +56 -0
  109. package/dist/ui/pointer-rotate.d.ts +29 -0
  110. package/dist/ui/pointer-rotate.js +39 -0
  111. package/package.json +21 -17
  112. package/dist/pie/component-context.d.ts +0 -21
  113. package/dist/pie/component-context.js +0 -29
  114. package/dist/pie/player-initializer.d.ts +0 -54
  115. package/dist/pie/player-initializer.js +0 -122
  116. package/dist/security/wrap-model-rich-content.d.ts +0 -1
  117. package/dist/security/wrap-model-rich-content.js +0 -40
  118. package/dist/server/npm-auth-env.d.ts +0 -13
  119. package/dist/server/npm-auth-env.js +0 -64
  120. package/dist/server/npm-registry.d.ts +0 -7
  121. package/dist/server/npm-registry.js +0 -59
  122. package/dist/ui/debug-panel-persistence.d.ts +0 -17
  123. package/dist/ui/debug-panel-persistence.js +0 -37
@@ -4,7 +4,7 @@
4
4
  * PIE elements expect @pie-lib/math-rendering to be available on window.
5
5
  * This module ensures required globals are populated from the upstream
6
6
  * @pie-lib/math-rendering-module package, and also supports overriding with
7
- * a custom renderer object when needed.
7
+ * a custom renderer object through setMathRenderer().
8
8
  */
9
9
  export type MathRenderer = (element: HTMLElement) => void | Promise<void>;
10
10
  export interface MathRenderingAPI {
@@ -14,32 +14,30 @@ export interface MathRenderingAPI {
14
14
  mmlToLatex?: (mathml: string) => string;
15
15
  }
16
16
  /**
17
- * Initialize math rendering with optional custom renderer
18
- *
19
- * If no custom renderer is provided, defaults to MathJax.
17
+ * The page's renderer: the one `initializeMathRendering` installed, or a
18
+ * host's. IIFE elements render with it, and so do ESM elements when the page
19
+ * has one.
20
+ */
21
+ export declare const getMathRenderer: () => MathRenderingAPI | null;
22
+ /**
23
+ * Initialize math rendering, defaulting to MathJax.
20
24
  * For custom renderers, use setMathRenderer() before calling this function.
21
25
  *
22
26
  * Sets TWO window globals that PIE elements expect:
23
27
  * - window["@pie-lib/math-rendering"] (standard key)
24
28
  * - window["_dll_pie_lib__math_rendering"] (SystemJS/DLL key for IIFE bundles)
25
29
  *
26
- * @param customRenderer - Optional custom renderer to use instead of default MathJax
27
- *
28
30
  * @example
29
31
  * ```typescript
30
32
  * // Default MathJax
31
33
  * await initializeMathRendering();
32
34
  *
33
- * // Custom renderer instance implementing MathRenderingAPI
34
- * const customRenderer = await createCustomRenderer();
35
- * await initializeMathRendering(customRenderer);
36
- *
37
- * // Or use setMathRenderer first
35
+ * // Custom renderer: install it first
38
36
  * setMathRenderer(katexRenderer);
39
37
  * await initializeMathRendering();
40
38
  * ```
41
39
  */
42
- export declare function initializeMathRendering(customRenderer?: MathRenderingAPI): Promise<void>;
40
+ export declare function initializeMathRendering(): Promise<void>;
43
41
  /**
44
42
  * Set custom math renderer programmatically
45
43
  *
@@ -60,12 +58,3 @@ export declare function initializeMathRendering(customRenderer?: MathRenderingAP
60
58
  * ```
61
59
  */
62
60
  export declare function setMathRenderer(renderer: MathRenderingAPI): void;
63
- /**
64
- * Render math in the given element
65
- *
66
- * Convenience wrapper that calls the active renderer's renderMath() function.
67
- * Typically called after PIE elements are rendered.
68
- *
69
- * @param element - The element to render math within
70
- */
71
- export declare function renderMath(element: HTMLElement): void;
@@ -4,15 +4,23 @@
4
4
  * PIE elements expect @pie-lib/math-rendering to be available on window.
5
5
  * This module ensures required globals are populated from the upstream
6
6
  * @pie-lib/math-rendering-module package, and also supports overriding with
7
- * a custom renderer object when needed.
7
+ * a custom renderer object through setMathRenderer().
8
8
  */
9
9
  /// <reference path="../shims.d.ts" />
10
10
  import { createPieLogger, isGlobalDebugEnabled } from "./logger.js";
11
11
  const GLOBAL_KEY = "@pie-lib/math-rendering";
12
12
  const GLOBAL_DLL_KEY = "_dll_pie_lib__math_rendering";
13
+ // Every copy of @pie-lib/math-rendering on a page typesets through the MathJax
14
+ // instance kept here, and the first copy to typeset creates it.
15
+ const SHARED_INSTANCE_KEY = "@pie-lib/math-rendering@2";
13
16
  let initPromise = null;
14
17
  const logger = createPieLogger("math-rendering", () => isGlobalDebugEnabled());
15
- const getWindowRenderer = () => {
18
+ /**
19
+ * The page's renderer: the one `initializeMathRendering` installed, or a
20
+ * host's. IIFE elements render with it, and so do ESM elements when the page
21
+ * has one.
22
+ */
23
+ export const getMathRenderer = () => {
16
24
  if (typeof window === "undefined") {
17
25
  return null;
18
26
  }
@@ -26,43 +34,55 @@ const setWindowRenderer = (renderer) => {
26
34
  window[GLOBAL_DLL_KEY] = renderer;
27
35
  };
28
36
  /**
29
- * Initialize math rendering with optional custom renderer
37
+ * Creates the shared MathJax instance from `renderer`, unless the page already
38
+ * holds one.
30
39
  *
31
- * If no custom renderer is provided, defaults to MathJax.
40
+ * Legacy element bundles carry their own copy of math-rendering. A copy that
41
+ * predates the assistive-MathML guard, such as the one in multiple-choice
42
+ * 9.9.1, re-typesets the hidden `<math>` inside `mjx-assistive-mml` on every
43
+ * pass, so if it creates the instance, each re-render nests the expression
44
+ * again for every element on the page. Typesetting a detached element makes the
45
+ * guarded module create it first. Failure leaves the instance to the first
46
+ * element, as before, so it is logged and never fails initialization.
47
+ */
48
+ const createSharedInstance = (renderer) => {
49
+ if (window[SHARED_INSTANCE_KEY]?.instance)
50
+ return;
51
+ if (typeof document === "undefined" || !document.body)
52
+ return;
53
+ const warn = (error) => logger.warn("Could not create the shared MathJax instance:", error);
54
+ try {
55
+ Promise.resolve(renderer.renderMath(document.createElement("div"))).catch(warn);
56
+ }
57
+ catch (error) {
58
+ warn(error);
59
+ }
60
+ };
61
+ /**
62
+ * Initialize math rendering, defaulting to MathJax.
32
63
  * For custom renderers, use setMathRenderer() before calling this function.
33
64
  *
34
65
  * Sets TWO window globals that PIE elements expect:
35
66
  * - window["@pie-lib/math-rendering"] (standard key)
36
67
  * - window["_dll_pie_lib__math_rendering"] (SystemJS/DLL key for IIFE bundles)
37
68
  *
38
- * @param customRenderer - Optional custom renderer to use instead of default MathJax
39
- *
40
69
  * @example
41
70
  * ```typescript
42
71
  * // Default MathJax
43
72
  * await initializeMathRendering();
44
73
  *
45
- * // Custom renderer instance implementing MathRenderingAPI
46
- * const customRenderer = await createCustomRenderer();
47
- * await initializeMathRendering(customRenderer);
48
- *
49
- * // Or use setMathRenderer first
74
+ * // Custom renderer: install it first
50
75
  * setMathRenderer(katexRenderer);
51
76
  * await initializeMathRendering();
52
77
  * ```
53
78
  */
54
- export async function initializeMathRendering(customRenderer) {
79
+ export async function initializeMathRendering() {
55
80
  // Only run in browser
56
81
  if (typeof window === "undefined") {
57
82
  return;
58
83
  }
59
- // Explicit override always wins.
60
- if (customRenderer) {
61
- setWindowRenderer(customRenderer);
62
- return;
63
- }
64
84
  // Already initialized - skip.
65
- if (getWindowRenderer()) {
85
+ if (getMathRenderer()) {
66
86
  return;
67
87
  }
68
88
  if (initPromise) {
@@ -71,11 +91,20 @@ export async function initializeMathRendering(customRenderer) {
71
91
  }
72
92
  initPromise = (async () => {
73
93
  try {
74
- const { _dll_pie_lib__math_rendering } = await import("@pie-lib/math-rendering-module/module");
94
+ // The package has no exports map, so the file is named in full for
95
+ // resolvers that do not complete a directory, such as webpack's
96
+ // fully-specified ESM resolution.
97
+ const mathRenderingModule = await import("@pie-lib/math-rendering-module/module/index.js");
98
+ // The player builds defer the module's evaluation to this call (see
99
+ // math-rendering-module-deferral.mjs); unbundled, it evaluated on import.
100
+ const renderer = mathRenderingModule.evaluateMathRenderingModule
101
+ ? mathRenderingModule.evaluateMathRenderingModule()
102
+ : mathRenderingModule._dll_pie_lib__math_rendering;
75
103
  // A host may install its renderer while the default module is in flight.
76
104
  // The explicit renderer remains authoritative when that happens.
77
- if (!getWindowRenderer()) {
78
- setWindowRenderer(_dll_pie_lib__math_rendering);
105
+ if (!getMathRenderer()) {
106
+ setWindowRenderer(renderer);
107
+ createSharedInstance(renderer);
79
108
  logger.debug("Math rendering module initialized (both globals set)");
80
109
  }
81
110
  }
@@ -113,17 +142,3 @@ export async function initializeMathRendering(customRenderer) {
113
142
  export function setMathRenderer(renderer) {
114
143
  setWindowRenderer(renderer);
115
144
  }
116
- /**
117
- * Render math in the given element
118
- *
119
- * Convenience wrapper that calls the active renderer's renderMath() function.
120
- * Typically called after PIE elements are rendered.
121
- *
122
- * @param element - The element to render math within
123
- */
124
- export function renderMath(element) {
125
- const renderer = getWindowRenderer();
126
- if (renderer && typeof renderer.renderMath === "function") {
127
- renderer.renderMath(element);
128
- }
129
- }
@@ -3,8 +3,20 @@
3
3
  *
4
4
  * Manages the global PIE registry that tracks loaded elements.
5
5
  */
6
- import type { PieRegistry } from "./types.js";
6
+ import type { Entry, PieRegistry } from "./types.js";
7
7
  /**
8
8
  * Get or create the global PIE registry
9
9
  */
10
10
  export declare const pieRegistry: () => PieRegistry;
11
+ /**
12
+ * Record a tag in `window.PIE_REGISTRY`. Every registration path writes through
13
+ * here: the IIFE and ESM loaders, bundle initialization, and
14
+ * `registerPreloadedElements`.
15
+ *
16
+ * The first loaded entry for a tag `customElements` holds describes that
17
+ * definition, which no later load replaces, so it keeps its package and
18
+ * element. A later write fills only what it left empty: a controller, with the
19
+ * bundle type that supplied it, and a config. Any other entry is replaced.
20
+ * Returns the entry the registry holds afterwards.
21
+ */
22
+ export declare function writeRegistryEntry(entry: Entry): Entry;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Manages the global PIE registry that tracks loaded elements.
5
5
  */
6
- import { isPieRegistryAvailable } from "./types.js";
6
+ import { isPieRegistryAvailable, Status } from "./types.js";
7
7
  /**
8
8
  * Get or create the global PIE registry
9
9
  */
@@ -18,3 +18,41 @@ export const pieRegistry = () => {
18
18
  }
19
19
  return registry;
20
20
  };
21
+ /**
22
+ * Record a tag in `window.PIE_REGISTRY`. Every registration path writes through
23
+ * here: the IIFE and ESM loaders, bundle initialization, and
24
+ * `registerPreloadedElements`.
25
+ *
26
+ * The first loaded entry for a tag `customElements` holds describes that
27
+ * definition, which no later load replaces, so it keeps its package and
28
+ * element. A later write fills only what it left empty: a controller, with the
29
+ * bundle type that supplied it, and a config. Any other entry is replaced.
30
+ * Returns the entry the registry holds afterwards.
31
+ */
32
+ export function writeRegistryEntry(entry) {
33
+ const registry = pieRegistry();
34
+ const existing = registry[entry.tagName];
35
+ if (!existing ||
36
+ existing.status !== Status.loaded ||
37
+ !isDefinedTag(entry.tagName)) {
38
+ registry[entry.tagName] = entry;
39
+ return entry;
40
+ }
41
+ const fillsController = !existing.controller && !!entry.controller;
42
+ const fillsConfig = existing.config == null && entry.config != null;
43
+ if (!fillsController && !fillsConfig)
44
+ return existing;
45
+ const filled = { ...existing };
46
+ if (fillsController) {
47
+ filled.controller = entry.controller;
48
+ filled.bundleType = entry.bundleType;
49
+ }
50
+ if (fillsConfig)
51
+ filled.config = entry.config;
52
+ registry[entry.tagName] = filled;
53
+ return filled;
54
+ }
55
+ function isDefinedTag(tagName) {
56
+ return (typeof customElements !== "undefined" &&
57
+ customElements.get(tagName) !== undefined);
58
+ }
@@ -7,11 +7,11 @@
7
7
  * Features:
8
8
  * - Tracks resource load timing with PerformanceObserver
9
9
  * - Detects and retries failed resource loads
10
- * - Sends instrumentation to New Relic
10
+ * - With `trackPageActions`, reports loads, retries and failures to the
11
+ * instrumentation provider it is given
11
12
  * - Works with all resource types (audio, video, img, link)
12
13
  */
13
14
  import type { InstrumentationProvider } from "../instrumentation/types.js";
14
- import type { ComponentContext } from "./component-context.js";
15
15
  export type ResourceMonitorConfig = {
16
16
  /**
17
17
  * Enable tracking page actions/events
@@ -22,29 +22,15 @@ export type ResourceMonitorConfig = {
22
22
  /**
23
23
  * Instrumentation provider for tracking events and errors
24
24
  *
25
- * Optional. If not provided, defaults to NewRelicInstrumentationProvider.
26
- * The provider handles instrumentation gracefully - if New Relic is not available,
27
- * it will simply not track events (no errors thrown).
28
- *
29
- * To use a different provider, pass it here:
30
- *
31
- * @example
32
- * ```typescript
33
- * const provider = new ConsoleInstrumentationProvider();
34
- * await provider.initialize({ debug: true });
35
- *
36
- * const monitor = new ResourceMonitor({
37
- * trackPageActions: true,
38
- * instrumentationProvider: provider
39
- * });
40
- * ```
25
+ * The monitor constructs no provider of its own: without one it only
26
+ * retries. Players pass what `resolveInstrumentationProvider` resolves from
27
+ * their `loaderConfig`.
41
28
  */
42
29
  instrumentationProvider?: InstrumentationProvider;
43
30
  /**
44
31
  * Whether ResourceMonitor should initialize/destroy the instrumentation provider.
45
32
  *
46
- * Defaults to `true` when ResourceMonitor creates the provider internally, and
47
- * `false` when a provider is injected by the host.
33
+ * Defaults to `false`: the provider belongs to whoever passed it in.
48
34
  */
49
35
  manageProviderLifecycle?: boolean;
50
36
  /**
@@ -97,8 +83,6 @@ export declare class ResourceMonitor {
97
83
  private isBrowser;
98
84
  private containerResources;
99
85
  private provider;
100
- private readonly ownsProvider;
101
- private readonly manageProviderLifecycle;
102
86
  private started;
103
87
  private lifecycleVersion;
104
88
  private pendingRetryTimers;
@@ -229,14 +213,3 @@ export declare class ResourceMonitor {
229
213
  }>;
230
214
  };
231
215
  }
232
- /**
233
- * Create and start a resource monitor for a container
234
- */
235
- export declare function createResourceMonitor(container: HTMLElement, config?: ResourceMonitorConfig): ResourceMonitor;
236
- /**
237
- * Initialize global resource request tracking (404s for fonts/images/etc.)
238
- * Call this once when the app loads (client-side only).
239
- */
240
- export declare function initializeResourceRequestTracking(): void;
241
- export declare function getTrackedResourceRequests(): Map<string, ComponentContext[]>;
242
- export declare function clearTrackedResourceRequests(): void;
@@ -7,17 +7,15 @@
7
7
  * Features:
8
8
  * - Tracks resource load timing with PerformanceObserver
9
9
  * - Detects and retries failed resource loads
10
- * - Sends instrumentation to New Relic
10
+ * - With `trackPageActions`, reports loads, retries and failures to the
11
+ * instrumentation provider it is given
11
12
  * - Works with all resource types (audio, video, img, link)
12
13
  */
13
- import { NewRelicInstrumentationProvider } from "../instrumentation/providers/NewRelicInstrumentationProvider.js";
14
14
  import { isInstrumentationProvider } from "../instrumentation/provider-guards.js";
15
- import { getCurrentComponentContext } from "./component-context.js";
16
15
  import { createPieLogger, isGlobalDebugEnabled } from "./logger.js";
17
16
  const DEFAULT_CONFIG = {
18
17
  trackPageActions: false,
19
- instrumentationProvider: undefined,
20
- manageProviderLifecycle: undefined,
18
+ manageProviderLifecycle: false,
21
19
  maxRetries: 3,
22
20
  initialRetryDelay: 500,
23
21
  maxRetryDelay: 5000,
@@ -43,49 +41,39 @@ export class ResourceMonitor {
43
41
  isBrowser;
44
42
  containerResources = new Set(); // Track resources within our container
45
43
  provider;
46
- ownsProvider;
47
- manageProviderLifecycle;
48
44
  started = false;
49
45
  lifecycleVersion = 0;
50
46
  pendingRetryTimers = new Map();
51
47
  retryInFlight = new Set();
52
48
  pendingMediaChecks = new Map();
53
49
  constructor(config = {}) {
54
- const validInjectedProvider = isInstrumentationProvider(config.instrumentationProvider)
55
- ? config.instrumentationProvider
56
- : undefined;
57
- const hasInjectedProvider = !!validInjectedProvider;
58
- const manageProviderLifecycle = config.manageProviderLifecycle ?? !hasInjectedProvider;
59
50
  this.config = {
60
51
  trackPageActions: config.trackPageActions ?? DEFAULT_CONFIG.trackPageActions,
61
- instrumentationProvider: validInjectedProvider,
62
- manageProviderLifecycle,
52
+ manageProviderLifecycle: config.manageProviderLifecycle ??
53
+ DEFAULT_CONFIG.manageProviderLifecycle,
63
54
  maxRetries: config.maxRetries ?? DEFAULT_CONFIG.maxRetries,
64
55
  initialRetryDelay: config.initialRetryDelay ?? DEFAULT_CONFIG.initialRetryDelay,
65
56
  maxRetryDelay: config.maxRetryDelay ?? DEFAULT_CONFIG.maxRetryDelay,
66
57
  debug: config.debug ?? DEFAULT_CONFIG.debug,
67
58
  };
68
59
  this.logger = createPieLogger("resource-monitor", () => this.isDebugEnabled());
69
- if (config.instrumentationProvider && !validInjectedProvider) {
60
+ this.provider = isInstrumentationProvider(config.instrumentationProvider)
61
+ ? config.instrumentationProvider
62
+ : undefined;
63
+ if (config.instrumentationProvider && !this.provider) {
70
64
  if (this.isDebugEnabled()) {
71
65
  this.logger.warn("Ignoring invalid instrumentation provider; expected InstrumentationProvider shape");
72
66
  }
73
67
  }
74
- // Always use a provider - default to NewRelic if not specified
75
- this.ownsProvider = !this.config.instrumentationProvider;
76
- this.provider =
77
- this.config.instrumentationProvider ??
78
- new NewRelicInstrumentationProvider();
79
- this.manageProviderLifecycle = this.config.manageProviderLifecycle;
80
68
  // Initialize the provider (async, but don't block constructor)
81
- if (this.manageProviderLifecycle) {
69
+ if (this.provider && this.config.manageProviderLifecycle) {
82
70
  this.provider.initialize().catch((err) => {
83
71
  if (this.isDebugEnabled()) {
84
72
  this.logger.warn("Failed to initialize instrumentation provider:", err);
85
73
  }
86
74
  });
87
75
  }
88
- else if (this.isDebugEnabled()) {
76
+ else if (this.provider && this.isDebugEnabled()) {
89
77
  this.logger.debug("Skipping provider lifecycle management for injected provider");
90
78
  }
91
79
  this.isBrowser =
@@ -186,7 +174,7 @@ export class ResourceMonitor {
186
174
  * Track event with instrumentation provider if enabled
187
175
  */
188
176
  trackInstrumentationEvent(eventName, attributes) {
189
- if (!this.config.trackPageActions || !this.provider.isReady()) {
177
+ if (!this.config.trackPageActions || !this.provider?.isReady()) {
190
178
  return;
191
179
  }
192
180
  this.provider.trackEvent(eventName, {
@@ -199,7 +187,7 @@ export class ResourceMonitor {
199
187
  * Track error with instrumentation provider if enabled
200
188
  */
201
189
  trackInstrumentationError(error, attributes) {
202
- if (!this.config.trackPageActions || !this.provider.isReady()) {
190
+ if (!this.config.trackPageActions || !this.provider?.isReady()) {
203
191
  return;
204
192
  }
205
193
  this.provider.trackError(error, {
@@ -264,7 +252,7 @@ export class ResourceMonitor {
264
252
  this.containerResources.clear();
265
253
  this.container = null;
266
254
  this.started = false;
267
- if (this.manageProviderLifecycle) {
255
+ if (this.provider && this.config.manageProviderLifecycle) {
268
256
  try {
269
257
  this.provider.destroy();
270
258
  }
@@ -1162,190 +1150,3 @@ export class ResourceMonitor {
1162
1150
  };
1163
1151
  }
1164
1152
  }
1165
- /**
1166
- * Create and start a resource monitor for a container
1167
- */
1168
- export function createResourceMonitor(container, config = {}) {
1169
- const monitor = new ResourceMonitor(config);
1170
- monitor.start(container);
1171
- return monitor;
1172
- }
1173
- // =============================================================================
1174
- // Global resource request tracking (consolidated from the old font-request-tracker)
1175
- // =============================================================================
1176
- // Track failed resource requests (by URL)
1177
- const failedRequests = new Map();
1178
- function isResourceFile(url) {
1179
- const resourceExtensions = [
1180
- // Fonts
1181
- ".woff",
1182
- ".woff2",
1183
- ".ttf",
1184
- ".otf",
1185
- ".eot",
1186
- // Images
1187
- ".gif",
1188
- ".jpg",
1189
- ".jpeg",
1190
- ".png",
1191
- ".svg",
1192
- ".webp",
1193
- ".ico",
1194
- // Audio/Video
1195
- ".mp3",
1196
- ".mp4",
1197
- ".wav",
1198
- ".ogg",
1199
- ".webm",
1200
- // Other assets
1201
- ".pdf",
1202
- ".css",
1203
- ".js",
1204
- ];
1205
- return resourceExtensions.some((ext) => url.toLowerCase().includes(ext));
1206
- }
1207
- function getResourceType(url) {
1208
- if (url.match(/\.(woff|woff2|ttf|otf|eot)/i))
1209
- return "Font";
1210
- if (url.match(/\.(gif|jpg|jpeg|png|svg|webp|ico)/i))
1211
- return "Image";
1212
- if (url.match(/\.(mp3|mp4|wav|ogg|webm)/i))
1213
- return "Media";
1214
- if (url.match(/\.(css)/i))
1215
- return "Stylesheet";
1216
- if (url.match(/\.(js)/i))
1217
- return "Script";
1218
- return "Resource";
1219
- }
1220
- function logFailedRequest(url, status, context) {
1221
- // Only log 404s and other failures (status 0 for network errors)
1222
- if (status !== 404 && status !== 0) {
1223
- return;
1224
- }
1225
- const key = url;
1226
- if (!failedRequests.has(key)) {
1227
- failedRequests.set(key, []);
1228
- }
1229
- const contexts = failedRequests.get(key);
1230
- contexts.push({
1231
- ...(context || { componentName: "Unknown", timestamp: Date.now() }),
1232
- timestamp: Date.now(),
1233
- });
1234
- const resourceType = getResourceType(url);
1235
- const filename = url.split("/").pop() || url;
1236
- const itemId = context?.itemId || "Unknown";
1237
- const componentName = context?.componentName || "Unknown component";
1238
- const elementType = context?.elementType || "";
1239
- console.warn(`Failed ${resourceType} request`, `\n Resource: ${filename}`, `\n URL: ${url}`, `\n Item ID: ${itemId}`, `\n Mini-Player: ${componentName}`, elementType ? `\n Element Type: ${elementType}` : "", `\n Status: ${status}`, context
1240
- ? ""
1241
- : "\n Note: Component not tracked - may be from item markup or PIE element");
1242
- }
1243
- /**
1244
- * Initialize global resource request tracking (404s for fonts/images/etc.)
1245
- * Call this once when the app loads (client-side only).
1246
- */
1247
- export function initializeResourceRequestTracking() {
1248
- if (typeof window === "undefined")
1249
- return;
1250
- // Track fetch requests
1251
- const originalFetch = window.fetch;
1252
- window.fetch = async function (...args) {
1253
- // Extract URL from first argument (can be string, URL, or Request)
1254
- let url = "";
1255
- if (typeof args[0] === "string") {
1256
- url = args[0];
1257
- }
1258
- else if (args[0] instanceof URL) {
1259
- url = args[0].toString();
1260
- }
1261
- else if (args[0] instanceof Request) {
1262
- url = args[0].url;
1263
- }
1264
- if (isResourceFile(url) || url.startsWith("/")) {
1265
- const context = getCurrentComponentContext();
1266
- try {
1267
- const response = await originalFetch(...args);
1268
- if (response.status === 404) {
1269
- logFailedRequest(url, response.status, context);
1270
- }
1271
- return response;
1272
- }
1273
- catch (error) {
1274
- logFailedRequest(url, 0, context);
1275
- throw error;
1276
- }
1277
- }
1278
- return originalFetch(...args);
1279
- };
1280
- // Track XMLHttpRequest
1281
- const originalXHROpen = XMLHttpRequest.prototype.open;
1282
- XMLHttpRequest.prototype.open = function (method, url, async, username, password) {
1283
- const urlString = typeof url === "string" ? url : url.toString();
1284
- if (isResourceFile(urlString) || urlString.startsWith("/")) {
1285
- const context = getCurrentComponentContext();
1286
- this.addEventListener("load", function () {
1287
- if (this.status === 404) {
1288
- logFailedRequest(urlString, this.status, context);
1289
- }
1290
- });
1291
- this.addEventListener("error", function () {
1292
- logFailedRequest(urlString, 0, context);
1293
- });
1294
- }
1295
- return originalXHROpen.call(this, method, url, async ?? true, username ?? null, password ?? null);
1296
- };
1297
- // Intercept img tag error events (most reliable way to catch failed image loads)
1298
- const errorHandler = (event) => {
1299
- const target = event.target;
1300
- if (target instanceof HTMLImageElement && target.src) {
1301
- const url = target.src;
1302
- if (isResourceFile(url) ||
1303
- url.startsWith("/") ||
1304
- url.startsWith(window.location.origin + "/")) {
1305
- const context = getCurrentComponentContext();
1306
- const relativeUrl = url.startsWith(window.location.origin)
1307
- ? url.replace(window.location.origin, "")
1308
- : url;
1309
- logFailedRequest(relativeUrl, 404, context);
1310
- }
1311
- }
1312
- };
1313
- document.addEventListener("error", errorHandler, true);
1314
- // Track resource requests via PerformanceObserver (fonts, CSS resources, etc.)
1315
- const observer = new PerformanceObserver((list) => {
1316
- for (const entry of list.getEntries()) {
1317
- if (entry.entryType !== "resource")
1318
- continue;
1319
- const resourceEntry = entry;
1320
- const url = resourceEntry.name;
1321
- if (isResourceFile(url) ||
1322
- url.startsWith("/") ||
1323
- url.startsWith(window.location.origin + "/")) {
1324
- const perf = resourceEntry;
1325
- const failed = perf.responseEnd === 0 && perf.duration > 0;
1326
- const mightBe404 = perf.transferSize === 0 &&
1327
- perf.responseEnd > 0 &&
1328
- perf.responseStart === 0;
1329
- if (failed || mightBe404) {
1330
- const context = getCurrentComponentContext();
1331
- const relativeUrl = url.startsWith(window.location.origin)
1332
- ? url.replace(window.location.origin, "")
1333
- : url;
1334
- logFailedRequest(relativeUrl, 404, context);
1335
- }
1336
- }
1337
- }
1338
- });
1339
- try {
1340
- observer.observe({ type: "resource", buffered: true });
1341
- }
1342
- catch (e) {
1343
- console.warn("Failed to set up PerformanceObserver for resource tracking:", e);
1344
- }
1345
- }
1346
- export function getTrackedResourceRequests() {
1347
- return new Map(failedRequests);
1348
- }
1349
- export function clearTrackedResourceRequests() {
1350
- failedRequests.clear();
1351
- }
@@ -4,10 +4,17 @@
4
4
  * Scoring and outcome calculation for PIE elements.
5
5
  */
6
6
  import type { ConfigEntity, Env, OutcomeResponse, PieController, PieModel } from "../types/index.js";
7
+ import { BundleType } from "./types.js";
7
8
  /**
8
- * Find the controller for a PIE element
9
+ * Find the controller for a PIE element.
10
+ *
11
+ * `deliveryBundleType` is the bundle type of the player asking. A `player.js`
12
+ * delivery, which is what a hosted player is, resolves no controller: its
13
+ * models and scores come from the server, and the registry is shared with
14
+ * every other loader on the page, so a registered controller is no evidence
15
+ * that this player may run one.
9
16
  */
10
- export declare const findPieController: (elementName: string) => PieController | undefined;
17
+ export declare const findPieController: (elementName: string, deliveryBundleType?: BundleType) => PieController | undefined;
11
18
  export type ScorePieItemOptions = {
12
19
  /** Scope element lookup to a specific player/root. Defaults to document for existing callers. */
13
20
  container?: Pick<ParentNode, "querySelector">;
@@ -23,6 +30,8 @@ export type ScorePieItemOptions = {
23
30
  * Existing scorePieItem callers keep the filtered result shape by default.
24
31
  */
25
32
  includeMissingResults?: boolean;
33
+ /** The scoring player's bundle type; `player.js` scores nothing locally. */
34
+ bundleType?: BundleType;
26
35
  };
27
36
  export declare function scorePieItem(config: ConfigEntity, sessionData: any[], options: ScorePieItemOptions & {
28
37
  includeMissingResults: true;