@pie-players/pie-players-shared 0.3.73 → 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 +4 -4
  57. package/dist/pie/index.js +5 -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 +8 -0
  65. package/dist/pie/item-session-contract.js +30 -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 +16 -0
  77. package/dist/pie/session-commit.js +33 -5
  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
package/README.md CHANGED
@@ -21,10 +21,10 @@ Supported subpaths are declared in `package.json`:
21
21
  - `@pie-players/pie-players-shared/types`
22
22
  - `@pie-players/pie-players-shared/formative`
23
23
  - `@pie-players/pie-players-shared/timed-media`
24
+ - `@pie-players/pie-players-shared/media`
24
25
  - `@pie-players/pie-players-shared/pie`
25
26
  - `@pie-players/pie-players-shared/pie/tag-names`
26
27
  - `@pie-players/pie-players-shared/loaders`
27
- - `@pie-players/pie-players-shared/server/npm-registry`
28
28
  - `@pie-players/pie-players-shared/i18n`
29
29
 
30
30
  ## Formative Delivery
@@ -84,6 +84,28 @@ The contract is [`docs/prds/timed-media-section-contract.md`](../../docs/prds/ti
84
84
  including why cue gate conditions name the formative vocabulary and why an
85
85
  unenforceable policy degrades to advisory rather than failing closed.
86
86
 
87
+ ## Media Validation
88
+
89
+ `@pie-players/pie-players-shared/media` validates authored, wire-facing media
90
+ references before they reach a media element: the source-scheme allow-list
91
+ (`isSafeMediaSrc`), source normalization with dedupe by `src`
92
+ (`normalizeMediaSources`), fragment-range normalization, and
93
+ unknown-`MediaAssetRef.version` rejection. `applyMediaFragment` writes a
94
+ fragment range as a Media Fragments URI, and `enforceMediaFragment` holds a
95
+ media element to that range because browsers honour the URI inconsistently.
96
+ Nothing runs at import time, so an element imports it without the assessment
97
+ toolkit; the toolkit root re-exports the same names.
98
+
99
+ ```ts
100
+ import {
101
+ isSafeMediaSrc,
102
+ isUnsupportedMediaAssetVersion,
103
+ normalizeMediaSources,
104
+ } from "@pie-players/pie-players-shared/media";
105
+ ```
106
+
107
+ The media vocabulary it validates is [`docs/prds/shared-contracts/media-asset-contract.md`](../../docs/prds/shared-contracts/media-asset-contract.md).
108
+
87
109
  ## Browser ESM Element Contract
88
110
 
89
111
  The canonical producer-side contract lives with the `pie-elements-ng` package
@@ -94,6 +116,10 @@ The ESM element loader consumes static `@pie-element/*` browser entries such as
94
116
  `dist/browser/delivery/index.js`; it does not transform element packages through
95
117
  CDN `+esm` entry points. Browser ESM elements must publish exact shared runtime
96
118
  metadata in `package.json` under `pie.browserSharedDependencies`.
119
+ Under URL resolution it loads the variant an element declares in
120
+ `pie.browserEditorRuntime` and maps that runtime's `pie.browserModules`, one
121
+ runtime version per page; see
122
+ [Shared editor runtime](../../docs/item-player/loading-strategies.md#shared-editor-runtime).
97
123
 
98
124
  jsDelivr is the default npm CDN provider. Hosts can opt into `esm.sh` with
99
125
  `loaderOptions.esmCdnProvider = "esm.sh"` and `loaderOptions.esmCdnUrl =
@@ -66,11 +66,13 @@ TypeScript program, and is covered by the `!**/src/components/vendor` ignore in
66
66
 
67
67
  Consuming bundlers treat this module per their own externals config:
68
68
 
69
- - `tool-tts-inline` (Vite lib build) does **not** externalize `players-shared`,
70
- so this bundle is inlined into its published output.
71
- - `assessment-toolkit` builds its CE artifacts with `--external=@pie-players/*`,
72
- so this module stays a bare external import in those artifacts — resolved by
73
- the host/loader exactly like every other `@pie-players/*` specifier the
69
+ - `tool-tts-inline` (Vite lib build) externalizes `players-shared` and its
70
+ subpaths, so its published output imports
71
+ `@pie-players/pie-players-shared/nds-icon-button` from the host.
72
+ - `assessment-toolkit` builds its CE artifacts with every dependency and peer
73
+ dependency, plus each one's subpaths, as esbuild externals, so this module
74
+ stays a bare external import in those artifacts — resolved by the
75
+ host/loader exactly like every other `@pie-players/*` specifier the
74
76
  artifacts already emit.
75
77
 
76
78
  ## How to refresh
@@ -6,9 +6,7 @@
6
6
  */
7
7
  declare global {
8
8
  interface Window {
9
- PIE_BUILDER_ORIGIN_URL?: string;
10
9
  PIE_BUILDER_BUNDLE_URL?: string;
11
10
  }
12
11
  }
13
- export declare const BUILDER_ORIGIN_URL: string;
14
12
  export declare const BUILDER_BUNDLE_URL: string;
@@ -4,10 +4,7 @@
4
4
  * In PIEOneer, these come from `$env/dynamic/public`. In `pie-players` we avoid
5
5
  * SvelteKit env dependencies so this can be consumed by any bundler.
6
6
  */
7
- // Default public bundle host. Keep this aligned with the IIFE loader default.
8
- // (We prefer the proxy endpoint, which is stable/cached for browser usage.)
9
- const DEFAULT_BUILDER_ORIGIN_URL = "https://proxy.pie-api.com";
10
- const DEFAULT_BUILDER_BUNDLE_URL = `${DEFAULT_BUILDER_ORIGIN_URL}/bundles/`;
7
+ import { DEFAULT_BUNDLE_HOST } from "../loaders/defaults.js";
11
8
  function readPublicEnv(key) {
12
9
  try {
13
10
  // Vite/SvelteKit-like
@@ -18,9 +15,6 @@ function readPublicEnv(key) {
18
15
  catch { }
19
16
  return undefined;
20
17
  }
21
- export const BUILDER_ORIGIN_URL = (typeof window !== "undefined" && window.PIE_BUILDER_ORIGIN_URL) ||
22
- readPublicEnv("PUBLIC_BUILDER_ORIGIN_URL") ||
23
- DEFAULT_BUILDER_ORIGIN_URL;
24
18
  export const BUILDER_BUNDLE_URL = (typeof window !== "undefined" && window.PIE_BUILDER_BUNDLE_URL) ||
25
19
  readPublicEnv("PUBLIC_BUILDER_BUNDLE_URL") ||
26
- DEFAULT_BUILDER_BUNDLE_URL;
20
+ DEFAULT_BUNDLE_HOST;
@@ -12,9 +12,8 @@
12
12
  * its own chunk.
13
13
  * - **Tools** import `./types.js` as `import type` (fully erased) plus
14
14
  * `getDefaultI18n` from `./provider.js` for the no-publisher default. That
15
- * path never reaches `./catalogs.js`, so no locale chunk is emitted into a
16
- * tool bundle — which matters because every tool `vite.config.ts` sets
17
- * `external: []`.
15
+ * path never reaches `./catalogs.js`, so a host that bundles tools against
16
+ * its own players-shared emits no locale chunk for them.
18
17
  *
19
18
  * @module @pie-players/pie-players-shared/i18n
20
19
  */
@@ -12,9 +12,8 @@
12
12
  * its own chunk.
13
13
  * - **Tools** import `./types.js` as `import type` (fully erased) plus
14
14
  * `getDefaultI18n` from `./provider.js` for the no-publisher default. That
15
- * path never reaches `./catalogs.js`, so no locale chunk is emitted into a
16
- * tool bundle — which matters because every tool `vite.config.ts` sets
17
- * `external: []`.
15
+ * path never reaches `./catalogs.js`, so a host that bundles tools against
16
+ * its own players-shared emits no locale chunk for them.
18
17
  *
19
18
  * @module @pie-players/pie-players-shared/i18n
20
19
  */
@@ -73,6 +73,7 @@ declare const enUS: {
73
73
  items: string;
74
74
  section: string;
75
75
  loadingSection: string;
76
+ sectionLoadError: string;
76
77
  loadingPassage: string;
77
78
  configurationError: string;
78
79
  playerError: string;
@@ -163,6 +164,15 @@ declare const enUS: {
163
164
  centerA11y: string;
164
165
  closeA11y: string;
165
166
  };
167
+ /**
168
+ * The tap controls that move and turn the ruler and protractor without a
169
+ * drag. The move buttons reuse the `window` labels above.
170
+ */
171
+ placement: {
172
+ controlsA11y: string;
173
+ rotateClockwiseA11y: string;
174
+ rotateCounterclockwiseA11y: string;
175
+ };
166
176
  /**
167
177
  * Live-region announcements shared by the draggable tools — ruler,
168
178
  * protractor, line reader. Keyboard movement and rotation read the same in
@@ -73,6 +73,7 @@ const enUS = {
73
73
  items: "Items",
74
74
  section: "Section",
75
75
  loadingSection: "Loading section content…",
76
+ sectionLoadError: "Section content could not be loaded.",
76
77
  loadingPassage: "Loading passage content…",
77
78
  configurationError: "Configuration Error",
78
79
  playerError: "Player Error",
@@ -163,6 +164,15 @@ const enUS = {
163
164
  centerA11y: "Center tool window",
164
165
  closeA11y: "Close tool",
165
166
  },
167
+ /**
168
+ * The tap controls that move and turn the ruler and protractor without a
169
+ * drag. The move buttons reuse the `window` labels above.
170
+ */
171
+ placement: {
172
+ controlsA11y: "Move and rotate",
173
+ rotateClockwiseA11y: "Rotate {degrees}° clockwise",
174
+ rotateCounterclockwiseA11y: "Rotate {degrees}° counterclockwise",
175
+ },
166
176
  /**
167
177
  * Live-region announcements shared by the draggable tools — ruler,
168
178
  * protractor, line reader. Keyboard movement and rotation read the same in
@@ -207,8 +217,8 @@ const enUS = {
207
217
  },
208
218
  graph: {
209
219
  name: "Graph",
210
- description: "Graphing calculator and coordinate plane",
211
- buttonA11y: "Graph, graphing calculator",
220
+ description: "Coordinate plane",
221
+ buttonA11y: "Graph, coordinate plane",
212
222
  tooltip: "Graph",
213
223
  toolA11y: "Graph tool — draw points and lines on a coordinate grid",
214
224
  canvasA11y: "Graph canvas — use tools to add points and draw lines",
@@ -58,6 +58,7 @@ declare const nlNL: {
58
58
  items: string;
59
59
  section: string;
60
60
  loadingSection: string;
61
+ sectionLoadError: string;
61
62
  loadingPassage: string;
62
63
  configurationError: string;
63
64
  playerError: string;
@@ -123,6 +124,11 @@ declare const nlNL: {
123
124
  centerA11y: string;
124
125
  closeA11y: string;
125
126
  };
127
+ placement: {
128
+ controlsA11y: string;
129
+ rotateClockwiseA11y: string;
130
+ rotateCounterclockwiseA11y: string;
131
+ };
126
132
  announce: {
127
133
  movedUp: string;
128
134
  movedDown: string;
@@ -58,6 +58,7 @@ const nlNL = {
58
58
  items: "Vragen",
59
59
  section: "Onderdeel",
60
60
  loadingSection: "Onderdeel wordt geladen…",
61
+ sectionLoadError: "Het onderdeel kon niet worden geladen.",
61
62
  loadingPassage: "Tekst wordt geladen…",
62
63
  configurationError: "Configuratiefout",
63
64
  playerError: "Fout in de speler",
@@ -123,6 +124,11 @@ const nlNL = {
123
124
  centerA11y: "Venster centreren",
124
125
  closeA11y: "Hulpmiddel sluiten",
125
126
  },
127
+ placement: {
128
+ controlsA11y: "Verplaatsen en draaien",
129
+ rotateClockwiseA11y: "{degrees}° rechtsom draaien",
130
+ rotateCounterclockwiseA11y: "{degrees}° linksom draaien",
131
+ },
126
132
  announce: {
127
133
  movedUp: "Omhoog verplaatst naar {position}",
128
134
  movedDown: "Omlaag verplaatst naar {position}",
@@ -150,8 +156,8 @@ const nlNL = {
150
156
  },
151
157
  graph: {
152
158
  name: "Grafiek",
153
- description: "Grafische rekenmachine en assenstelsel",
154
- buttonA11y: "Grafiek, grafische rekenmachine",
159
+ description: "Assenstelsel",
160
+ buttonA11y: "Grafiek, assenstelsel",
155
161
  tooltip: "Grafiek",
156
162
  toolA11y: "Grafiekhulpmiddel — punten en lijnen tekenen in een assenstelsel",
157
163
  canvasA11y: "Tekenvlak — gebruik de hulpmiddelen om punten toe te voegen en lijnen te tekenen",
@@ -2,11 +2,10 @@
2
2
  * The bundled i18n provider.
3
3
  *
4
4
  * Deliberately imports only the English catalog. The dynamic loader map for every
5
- * other locale lives in `./catalogs.js`, which players import and tools do not:
6
- * every player and tool `vite.config.ts` sets `external: []`, so anything
7
- * reachable from a tool's entry inlines into that tool's bundle. Keeping the
8
- * loader map out of this module is what stops a locale chunk from being emitted
9
- * into eighteen tool bundles that will never call `setLocale`.
5
+ * other locale lives in `./catalogs.js`, which players import and tools do not.
6
+ * Tools resolve players-shared from the host's node_modules, so keeping the
7
+ * loader map out of this module keeps locale chunks out of a host bundle that
8
+ * reaches players-shared only through tools.
10
9
  *
11
10
  * @module @pie-players/pie-players-shared/i18n/provider
12
11
  */
@@ -2,11 +2,10 @@
2
2
  * The bundled i18n provider.
3
3
  *
4
4
  * Deliberately imports only the English catalog. The dynamic loader map for every
5
- * other locale lives in `./catalogs.js`, which players import and tools do not:
6
- * every player and tool `vite.config.ts` sets `external: []`, so anything
7
- * reachable from a tool's entry inlines into that tool's bundle. Keeping the
8
- * loader map out of this module is what stops a locale chunk from being emitted
9
- * into eighteen tool bundles that will never call `setLocale`.
5
+ * other locale lives in `./catalogs.js`, which players import and tools do not.
6
+ * Tools resolve players-shared from the host's node_modules, so keeping the
7
+ * loader map out of this module keeps locale chunks out of a host bundle that
8
+ * reaches players-shared only through tools.
10
9
  *
11
10
  * @module @pie-players/pie-players-shared/i18n/provider
12
11
  */
package/dist/index.d.ts CHANGED
@@ -6,14 +6,16 @@ export * from "./security/index.js";
6
6
  export * from "./loaders/index.js";
7
7
  export * from "./object/index.js";
8
8
  export * from "./pie/index.js";
9
- export type { AssessmentEntity, AssessmentItemRef, AssessmentSection, AdvancedItemConfig, ConfigEntity, ConfigResource, Env, FormativeDeliveryPolicy, FormativeItemPolicy, TimedMediaSectionData, ItemConfig, ItemEntity, ItemSession, OutcomeResponse, PassageEntity, PieController, PieContent, PieDefaultModel, PieItemElement, PieModel, QuestionEntity, RubricBlock, TestPart, } from "./types/index.js";
9
+ export type { AssessmentEntity, AssessmentItemRef, AssessmentSection, AdvancedItemConfig, ConfigEntity, ConfigResource, Env, FormativeDeliveryPolicy, FormativeItemPolicy, TimedMediaSectionData, ItemConfig, ItemEntity, ItemSession, OutcomeResponse, PassageEntity, PieController, PieContent, PieDefaultModel, PieItemElement, PieModel, PieUpdateSession, RubricBlock, TestPart, } from "./types/index.js";
10
10
  export { editorPostFix } from "./types/index.js";
11
11
  export * from "./ui/attribute-coercion.js";
12
12
  export * from "./ui/content-styles.js";
13
13
  export * from "./ui/pointer-drag.js";
14
+ export * from "./ui/pointer-gesture.js";
15
+ export * from "./ui/pointer-rotate.js";
14
16
  export * from "./ui/overlay-containment.js";
17
+ export * from "./ui/overlay-placement.js";
15
18
  export * from "./ui/focus-trap.js";
16
19
  export * from "./ui/first-focusable.js";
17
- export * from "./ui/debug-panel-persistence.js";
18
20
  export * from "./ui/safe-storage.js";
19
21
  export * from "./ui/scope-css.js";
package/dist/index.js CHANGED
@@ -11,9 +11,11 @@ export { editorPostFix } from "./types/index.js";
11
11
  export * from "./ui/attribute-coercion.js";
12
12
  export * from "./ui/content-styles.js";
13
13
  export * from "./ui/pointer-drag.js";
14
+ export * from "./ui/pointer-gesture.js";
15
+ export * from "./ui/pointer-rotate.js";
14
16
  export * from "./ui/overlay-containment.js";
17
+ export * from "./ui/overlay-placement.js";
15
18
  export * from "./ui/focus-trap.js";
16
19
  export * from "./ui/first-focusable.js";
17
- export * from "./ui/debug-panel-persistence.js";
18
20
  export * from "./ui/safe-storage.js";
19
21
  export * from "./ui/scope-css.js";
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Provides pluggable instrumentation for PIE players.
5
5
  * Supports multiple providers (New Relic, console logging, custom, etc.)
6
+ * Players take the provider as `loaderConfig.instrumentationProvider`.
6
7
  *
7
8
  * @example Using New Relic (default)
8
9
  * ```typescript
@@ -11,10 +12,10 @@
11
12
  * const provider = new NewRelicInstrumentationProvider();
12
13
  * await provider.initialize();
13
14
  *
14
- * const monitor = new ResourceMonitor({
15
+ * const loaderConfig = {
15
16
  * trackPageActions: true,
16
17
  * instrumentationProvider: provider
17
- * });
18
+ * };
18
19
  * ```
19
20
  * @example Using console logger for development
20
21
  * ```typescript
@@ -23,10 +24,10 @@
23
24
  * const provider = new ConsoleInstrumentationProvider();
24
25
  * await provider.initialize({ debug: true });
25
26
  *
26
- * const monitor = new ResourceMonitor({
27
+ * const loaderConfig = {
27
28
  * trackPageActions: true,
28
29
  * instrumentationProvider: provider
29
- * });
30
+ * };
30
31
  * ```
31
32
  */
32
33
  export * from "./providers/index.js";
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Provides pluggable instrumentation for PIE players.
5
5
  * Supports multiple providers (New Relic, console logging, custom, etc.)
6
+ * Players take the provider as `loaderConfig.instrumentationProvider`.
6
7
  *
7
8
  * @example Using New Relic (default)
8
9
  * ```typescript
@@ -11,10 +12,10 @@
11
12
  * const provider = new NewRelicInstrumentationProvider();
12
13
  * await provider.initialize();
13
14
  *
14
- * const monitor = new ResourceMonitor({
15
+ * const loaderConfig = {
15
16
  * trackPageActions: true,
16
17
  * instrumentationProvider: provider
17
- * });
18
+ * };
18
19
  * ```
19
20
  * @example Using console logger for development
20
21
  * ```typescript
@@ -23,10 +24,10 @@
23
24
  * const provider = new ConsoleInstrumentationProvider();
24
25
  * await provider.initialize({ debug: true });
25
26
  *
26
- * const monitor = new ResourceMonitor({
27
+ * const loaderConfig = {
27
28
  * trackPageActions: true,
28
29
  * instrumentationProvider: provider
29
- * });
30
+ * };
30
31
  * ```
31
32
  */
32
33
  // Providers
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The New Relic browser agent's API, as far as PIE calls it. A local
3
+ * structural type, so no vendor package reaches the published declarations.
4
+ */
5
+ export type NewRelicAgent = {
6
+ noticeError(error: Error, attributes?: Record<string, unknown>): void;
7
+ addPageAction(name: string, attributes?: Record<string, unknown>): void;
8
+ setUserId?(userId: string): void;
9
+ setCustomAttribute?(name: string, value: unknown): void;
10
+ };
11
+ /**
12
+ * Returns the New Relic browser agent's API if it is on the page now.
13
+ *
14
+ * `window.NREUM` is the agent's primary global and `window.newrelic` an alias
15
+ * the loader assigns onto the same object, but the install snippet creates
16
+ * `NREUM` as a configuration container before any agent code runs, so the probe
17
+ * tests the callable shape over both names. Nothing is cached: an agent that
18
+ * loads later is found on the next call.
19
+ */
20
+ export declare function probeNewRelicAgent(): NewRelicAgent | undefined;
@@ -0,0 +1,24 @@
1
+ function hasAgentApi(handle) {
2
+ const candidate = handle;
3
+ return (typeof candidate?.noticeError === "function" &&
4
+ typeof candidate.addPageAction === "function");
5
+ }
6
+ /**
7
+ * Returns the New Relic browser agent's API if it is on the page now.
8
+ *
9
+ * `window.NREUM` is the agent's primary global and `window.newrelic` an alias
10
+ * the loader assigns onto the same object, but the install snippet creates
11
+ * `NREUM` as a configuration container before any agent code runs, so the probe
12
+ * tests the callable shape over both names. Nothing is cached: an agent that
13
+ * loads later is found on the next call.
14
+ */
15
+ export function probeNewRelicAgent() {
16
+ if (typeof window === "undefined")
17
+ return undefined;
18
+ const { newrelic, NREUM } = window;
19
+ if (hasAgentApi(newrelic))
20
+ return newrelic;
21
+ if (hasAgentApi(NREUM))
22
+ return NREUM;
23
+ return undefined;
24
+ }
@@ -27,8 +27,8 @@ export declare abstract class BaseInstrumentationProvider implements Instrumenta
27
27
  /**
28
28
  * Initialize the provider with configuration
29
29
  *
30
- * Concrete providers should override this method to perform provider-specific
31
- * initialization (e.g., loading SDK, checking global objects, etc.)
30
+ * Concrete providers store their configuration here and set `initialized`.
31
+ * Whether the backend is available belongs in `isReady()`.
32
32
  *
33
33
  * @param config Optional configuration
34
34
  */
@@ -36,8 +36,9 @@ export declare abstract class BaseInstrumentationProvider implements Instrumenta
36
36
  /**
37
37
  * Check if provider is ready to track events
38
38
  *
39
- * Concrete providers should override this method to check provider-specific
40
- * readiness (e.g., SDK loaded, global object available, etc.)
39
+ * Concrete providers conjoin `initialized` with a check of their backend
40
+ * made on every call (e.g., the agent's global is on the page now), so a
41
+ * backend that arrives after `initialize()` is picked up.
41
42
  *
42
43
  * @returns true if provider is ready
43
44
  */
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Default provider for existing New Relic Browser Agent instrumentation.
5
5
  *
6
- * This provider wraps the global `window.newrelic` object provided by
7
- * the New Relic Browser Agent.
6
+ * Sends through the New Relic Browser Agent's API on `window.newrelic` or
7
+ * `window.NREUM`, looked up on every call, so an agent that loads after
8
+ * `initialize()` receives everything tracked from then on.
8
9
  *
9
10
  * @example
10
11
  * ```typescript
@@ -27,8 +28,8 @@ export declare class NewRelicInstrumentationProvider extends BaseInstrumentation
27
28
  /**
28
29
  * Initialize the New Relic provider
29
30
  *
30
- * Checks if the New Relic Browser Agent is available via `window.newrelic`.
31
- * If not available, initialization succeeds but `isReady()` will return false.
31
+ * Configures the provider. The agent does not have to be on the page yet:
32
+ * `isReady()` turns true when it arrives.
32
33
  *
33
34
  * @param config Optional configuration
34
35
  */
@@ -36,14 +37,13 @@ export declare class NewRelicInstrumentationProvider extends BaseInstrumentation
36
37
  /**
37
38
  * Check if provider is ready
38
39
  *
39
- * @returns true if New Relic is available and initialized
40
+ * @returns true once initialized, while the New Relic agent's API is on the page
40
41
  */
41
42
  isReady(): boolean;
42
43
  /**
43
44
  * Cleanup provider resources
44
45
  *
45
- * Marks provider as uninitialized. The global `window.newrelic` object
46
- * is not modified.
46
+ * Marks provider as uninitialized. The agent's globals are not modified.
47
47
  */
48
48
  destroy(): void;
49
49
  /**
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * Default provider for existing New Relic Browser Agent instrumentation.
5
5
  *
6
- * This provider wraps the global `window.newrelic` object provided by
7
- * the New Relic Browser Agent.
6
+ * Sends through the New Relic Browser Agent's API on `window.newrelic` or
7
+ * `window.NREUM`, looked up on every call, so an agent that loads after
8
+ * `initialize()` receives everything tracked from then on.
8
9
  *
9
10
  * @example
10
11
  * ```typescript
@@ -19,6 +20,7 @@
19
20
  * }
20
21
  * ```
21
22
  */
23
+ import { probeNewRelicAgent } from "../new-relic-agent.js";
22
24
  import { BaseInstrumentationProvider } from "./BaseInstrumentationProvider.js";
23
25
  export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider {
24
26
  providerId = "newrelic";
@@ -26,43 +28,32 @@ export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider
26
28
  /**
27
29
  * Initialize the New Relic provider
28
30
  *
29
- * Checks if the New Relic Browser Agent is available via `window.newrelic`.
30
- * If not available, initialization succeeds but `isReady()` will return false.
31
+ * Configures the provider. The agent does not have to be on the page yet:
32
+ * `isReady()` turns true when it arrives.
31
33
  *
32
34
  * @param config Optional configuration
33
35
  */
34
36
  async initialize(config) {
35
37
  this.config = config;
36
- // Check if New Relic is available
37
- if (typeof window !== "undefined" && window.newrelic) {
38
- this.initialized = true;
39
- if (this.config?.debug) {
40
- console.log("[NewRelicProvider] Initialized successfully");
41
- }
42
- }
43
- else {
44
- if (this.config?.debug) {
45
- console.warn("[NewRelicProvider] New Relic not available (window.newrelic not found)");
46
- }
47
- // Don't throw - allow graceful degradation
48
- this.initialized = false;
38
+ this.initialized = true;
39
+ if (this.config?.debug) {
40
+ console.log(probeNewRelicAgent()
41
+ ? "[NewRelicProvider] Initialized successfully"
42
+ : "[NewRelicProvider] Initialized; sends once the New Relic agent is on the page");
49
43
  }
50
44
  }
51
45
  /**
52
46
  * Check if provider is ready
53
47
  *
54
- * @returns true if New Relic is available and initialized
48
+ * @returns true once initialized, while the New Relic agent's API is on the page
55
49
  */
56
50
  isReady() {
57
- return (this.initialized &&
58
- typeof window !== "undefined" &&
59
- !!window.newrelic);
51
+ return this.initialized && probeNewRelicAgent() !== undefined;
60
52
  }
61
53
  /**
62
54
  * Cleanup provider resources
63
55
  *
64
- * Marks provider as uninitialized. The global `window.newrelic` object
65
- * is not modified.
56
+ * Marks provider as uninitialized. The agent's globals are not modified.
66
57
  */
67
58
  destroy() {
68
59
  this.initialized = false;
@@ -79,8 +70,7 @@ export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider
79
70
  * @param attributes Transformed attributes (already filtered and transformed by base class)
80
71
  */
81
72
  doTrackError(error, attributes) {
82
- const newrelic = window.newrelic;
83
- newrelic.noticeError(error, attributes);
73
+ probeNewRelicAgent()?.noticeError(error, attributes);
84
74
  }
85
75
  /**
86
76
  * Track a custom event/page action with New Relic
@@ -91,8 +81,7 @@ export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider
91
81
  * @param attributes Transformed attributes (already filtered and transformed by base class)
92
82
  */
93
83
  doTrackEvent(eventName, attributes) {
94
- const newrelic = window.newrelic;
95
- newrelic.addPageAction(eventName, attributes);
84
+ probeNewRelicAgent()?.addPageAction(eventName, attributes);
96
85
  }
97
86
  /**
98
87
  * Set user context for session tracking
@@ -103,13 +92,13 @@ export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider
103
92
  * @param attributes Optional user attributes
104
93
  */
105
94
  doSetUserContext(userId, attributes) {
106
- const newrelic = window.newrelic;
95
+ const newrelic = probeNewRelicAgent();
107
96
  // Set user ID if method exists
108
- if (newrelic.setUserId) {
97
+ if (typeof newrelic?.setUserId === "function") {
109
98
  newrelic.setUserId(userId);
110
99
  }
111
100
  // Set custom attributes for user
112
- if (attributes && newrelic.setCustomAttribute) {
101
+ if (attributes && typeof newrelic?.setCustomAttribute === "function") {
113
102
  for (const [key, value] of Object.entries(attributes)) {
114
103
  newrelic.setCustomAttribute(key, value);
115
104
  }
@@ -123,8 +112,8 @@ export class NewRelicInstrumentationProvider extends BaseInstrumentationProvider
123
112
  * @param attributes Attributes to set globally
124
113
  */
125
114
  doSetGlobalAttributes(attributes) {
126
- const newrelic = window.newrelic;
127
- if (newrelic.setCustomAttribute) {
115
+ const newrelic = probeNewRelicAgent();
116
+ if (typeof newrelic?.setCustomAttribute === "function") {
128
117
  for (const [key, value] of Object.entries(attributes)) {
129
118
  newrelic.setCustomAttribute(key, value);
130
119
  }
@@ -49,7 +49,8 @@ export interface InstrumentationProvider {
49
49
  */
50
50
  readonly providerName: string;
51
51
  /**
52
- * Initialize the provider (load SDKs, configure clients, etc.)
52
+ * Configure the provider. Its backend does not have to be available yet:
53
+ * `isReady()` answers that.
53
54
  *
54
55
  * @param config Optional configuration for the provider
55
56
  */
@@ -105,7 +106,10 @@ export interface InstrumentationProvider {
105
106
  /**
106
107
  * Check if provider is ready to track events
107
108
  *
108
- * @returns true if provider is initialized and ready, false otherwise
109
+ * Evaluated on every call, so a backend that becomes available after
110
+ * `initialize()` makes the provider ready without another call.
111
+ *
112
+ * @returns true if provider is initialized and its backend is available now
109
113
  */
110
114
  isReady(): boolean;
111
115
  }
@@ -195,7 +199,7 @@ export interface ErrorAttributes {
195
199
  /**
196
200
  * Component that generated the error
197
201
  *
198
- * Examples: 'pie-item-player', 'pie-resource-monitor'
202
+ * Examples: 'pie-item-player', 'resource-monitor'
199
203
  */
200
204
  component: string;
201
205
  /**