@pie-players/pie-players-shared 0.3.73 → 0.3.75
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/README.md +30 -2
- package/dist/components/vendor/nds/README.md +7 -5
- package/dist/config/profile.d.ts +0 -2
- package/dist/config/profile.js +2 -8
- package/dist/i18n/index.d.ts +2 -3
- package/dist/i18n/index.js +2 -3
- package/dist/i18n/messages/en-US.d.ts +11 -24
- package/dist/i18n/messages/en-US.js +13 -26
- package/dist/i18n/messages/nl-NL.d.ts +7 -24
- package/dist/i18n/messages/nl-NL.js +9 -26
- package/dist/i18n/provider.d.ts +4 -5
- package/dist/i18n/provider.js +4 -5
- package/dist/i18n/types.d.ts +4 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/instrumentation/index.d.ts +5 -4
- package/dist/instrumentation/index.js +5 -4
- package/dist/instrumentation/new-relic-agent.d.ts +20 -0
- package/dist/instrumentation/new-relic-agent.js +24 -0
- package/dist/instrumentation/providers/BaseInstrumentationProvider.d.ts +5 -4
- package/dist/instrumentation/providers/NewRelicInstrumentationProvider.d.ts +7 -7
- package/dist/instrumentation/providers/NewRelicInstrumentationProvider.js +21 -32
- package/dist/instrumentation/types.d.ts +7 -3
- package/dist/loader-config.d.ts +16 -6
- package/dist/loaders/controller-loading.d.ts +14 -0
- package/dist/loaders/controller-loading.js +12 -0
- package/dist/loaders/defaults.d.ts +10 -0
- package/dist/loaders/defaults.js +10 -0
- package/dist/loaders/element-loader.d.ts +20 -8
- package/dist/loaders/element-loader.js +102 -36
- package/dist/loaders/element-package-policy.d.ts +2 -0
- package/dist/loaders/element-package-policy.js +2 -1
- package/dist/loaders/esm-adapter.d.ts +29 -0
- package/dist/loaders/esm-adapter.js +635 -102
- package/dist/loaders/iife-adapter.d.ts +0 -5
- package/dist/loaders/iife-adapter.js +3 -9
- package/dist/loaders/index.d.ts +12 -3
- package/dist/loaders/index.js +9 -3
- package/dist/loaders/mathjax-events.d.ts +22 -0
- package/dist/loaders/mathjax-events.js +65 -0
- package/dist/loaders/module-shim.d.ts +12 -0
- package/dist/loaders/module-shim.js +12 -0
- package/dist/loaders/preloaded-alignment.d.ts +24 -0
- package/dist/loaders/preloaded-alignment.js +57 -0
- package/dist/loaders/preloaded-authored-tags.d.ts +26 -0
- package/dist/loaders/preloaded-authored-tags.js +69 -0
- package/dist/loaders/preloaded-registration.d.ts +72 -0
- package/dist/loaders/preloaded-registration.js +141 -0
- package/dist/media/index.d.ts +69 -0
- package/dist/media/index.js +194 -0
- package/dist/pie/authoring.d.ts +1 -1
- package/dist/pie/authoring.js +25 -18
- package/dist/pie/element-announcements.d.ts +39 -0
- package/dist/pie/element-announcements.js +67 -0
- package/dist/pie/element-observer.d.ts +3 -1
- package/dist/pie/element-observer.js +1 -0
- package/dist/pie/elements-rendered.d.ts +25 -0
- package/dist/pie/elements-rendered.js +96 -0
- package/dist/pie/index.d.ts +8 -10
- package/dist/pie/index.js +9 -10
- package/dist/pie/initialization.js +13 -22
- package/dist/pie/initialize-element.d.ts +3 -0
- package/dist/pie/initialize-element.js +3 -4
- package/dist/pie/instrumentation-event-bridge.js +23 -1
- package/dist/pie/instrumentation-event-map.js +11 -25
- package/dist/pie/instrumentation-provider-resolution.d.ts +2 -1
- package/dist/pie/instrumentation-provider-resolution.js +0 -1
- package/dist/pie/item-controller.js +4 -0
- package/dist/pie/item-session-contract.d.ts +8 -0
- package/dist/pie/item-session-contract.js +30 -9
- package/dist/pie/logger.d.ts +6 -0
- package/dist/pie/logger.js +10 -0
- package/dist/pie/markup-math.d.ts +20 -0
- package/dist/pie/markup-math.js +118 -0
- package/dist/pie/math-assets.d.ts +48 -0
- package/dist/pie/math-assets.js +81 -0
- package/dist/pie/math-rendering.d.ts +10 -21
- package/dist/pie/math-rendering.js +50 -35
- package/dist/pie/registry.d.ts +13 -1
- package/dist/pie/registry.js +39 -1
- package/dist/pie/resource-monitor.d.ts +6 -33
- package/dist/pie/resource-monitor.js +14 -213
- package/dist/pie/scoring.d.ts +12 -8
- package/dist/pie/scoring.js +21 -24
- package/dist/pie/session-commit.d.ts +16 -0
- package/dist/pie/session-commit.js +34 -6
- package/dist/pie/session-snapshot.d.ts +80 -0
- package/dist/pie/session-snapshot.js +166 -0
- package/dist/pie/stages.d.ts +10 -47
- package/dist/pie/stages.js +10 -47
- package/dist/pie/tag-names.d.ts +1 -0
- package/dist/pie/tag-names.js +1 -0
- package/dist/pie/types.d.ts +4 -5
- package/dist/pie/types.js +1 -0
- package/dist/pie/updates.d.ts +2 -2
- package/dist/pie/updates.js +33 -15
- package/dist/pie/versioned-tag.d.ts +4 -0
- package/dist/pie/versioned-tag.js +4 -0
- package/dist/security/index.d.ts +2 -3
- package/dist/security/index.js +2 -3
- package/dist/security/sanitize-item-markup.d.ts +4 -2
- package/dist/security/sanitize-item-markup.js +48 -6
- package/dist/security/sanitize-svg-icon.d.ts +0 -2
- package/dist/security/sanitize-svg-icon.js +0 -5
- package/dist/security/wrap-overwide-images.js +19 -0
- package/dist/security/wrap-overwide.d.ts +13 -0
- package/dist/security/wrap-overwide.js +63 -3
- package/dist/timed-media/policy.js +5 -16
- package/dist/types/index.d.ts +67 -423
- package/dist/types/index.js +0 -68
- package/dist/ui/attribute-coercion.d.ts +12 -0
- package/dist/ui/attribute-coercion.js +33 -0
- package/dist/ui/content-styles.d.ts +18 -16
- package/dist/ui/content-styles.js +67 -36
- package/dist/ui/overlay-containment.d.ts +31 -0
- package/dist/ui/overlay-containment.js +63 -0
- package/dist/ui/overlay-placement.d.ts +110 -0
- package/dist/ui/overlay-placement.js +222 -0
- package/dist/ui/pointer-gesture.d.ts +32 -0
- package/dist/ui/pointer-gesture.js +56 -0
- package/dist/ui/pointer-rotate.d.ts +29 -0
- package/dist/ui/pointer-rotate.js +39 -0
- package/package.json +23 -18
- package/dist/pie/component-context.d.ts +0 -21
- package/dist/pie/component-context.js +0 -29
- package/dist/pie/player-initializer.d.ts +0 -54
- package/dist/pie/player-initializer.js +0 -122
- package/dist/pie/stage-tracker.d.ts +0 -50
- package/dist/pie/stage-tracker.js +0 -105
- package/dist/security/wrap-model-rich-content.d.ts +0 -1
- package/dist/security/wrap-model-rich-content.js +0 -40
- package/dist/server/npm-auth-env.d.ts +0 -13
- package/dist/server/npm-auth-env.js +0 -64
- package/dist/server/npm-registry.d.ts +0 -7
- package/dist/server/npm-registry.js +0 -59
- package/dist/ui/debug-panel-persistence.d.ts +0 -17
- package/dist/ui/debug-panel-persistence.js +0 -37
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Default provider for existing New Relic Browser Agent instrumentation.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
31
|
-
*
|
|
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
|
|
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
|
|
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
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
30
|
-
*
|
|
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
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
48
|
+
* @returns true once initialized, while the New Relic agent's API is on the page
|
|
55
49
|
*/
|
|
56
50
|
isReady() {
|
|
57
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
95
|
+
const newrelic = probeNewRelicAgent();
|
|
107
96
|
// Set user ID if method exists
|
|
108
|
-
if (newrelic
|
|
97
|
+
if (typeof newrelic?.setUserId === "function") {
|
|
109
98
|
newrelic.setUserId(userId);
|
|
110
99
|
}
|
|
111
100
|
// Set custom attributes for user
|
|
112
|
-
if (attributes && newrelic
|
|
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 =
|
|
127
|
-
if (newrelic
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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', '
|
|
202
|
+
* Examples: 'pie-item-player', 'resource-monitor'
|
|
199
203
|
*/
|
|
200
204
|
component: string;
|
|
201
205
|
/**
|
package/dist/loader-config.d.ts
CHANGED
|
@@ -24,13 +24,16 @@ export type LoaderConfig = {
|
|
|
24
24
|
/**
|
|
25
25
|
* Instrumentation provider for tracking events and errors.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* - Unset or `undefined`: nothing is reported unless `trackPageActions` is
|
|
28
|
+
* `true`, in which case players fall back to a
|
|
29
|
+
* `NewRelicInstrumentationProvider`, which reports while the New Relic
|
|
30
|
+
* browser agent is on the page.
|
|
31
|
+
* - A provider: players report to it. A value that fails the
|
|
32
|
+
* `InstrumentationProvider` contract is treated as `null`.
|
|
33
|
+
* - `null`: disables instrumentation, whatever `trackPageActions` says.
|
|
30
34
|
*
|
|
31
|
-
* @example Using New Relic (
|
|
35
|
+
* @example Using New Relic (the fallback, no provider needed)
|
|
32
36
|
* ```typescript
|
|
33
|
-
* // Just enable tracking - will use New Relic if window.newrelic is available
|
|
34
37
|
* const loaderConfig = {
|
|
35
38
|
* trackPageActions: true
|
|
36
39
|
* };
|
|
@@ -47,8 +50,15 @@ export type LoaderConfig = {
|
|
|
47
50
|
* instrumentationProvider: provider
|
|
48
51
|
* };
|
|
49
52
|
* ```
|
|
53
|
+
* @example Disabling instrumentation
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const loaderConfig = {
|
|
56
|
+
* trackPageActions: true,
|
|
57
|
+
* instrumentationProvider: null
|
|
58
|
+
* };
|
|
59
|
+
* ```
|
|
50
60
|
*/
|
|
51
|
-
instrumentationProvider?: InstrumentationProvider;
|
|
61
|
+
instrumentationProvider?: InstrumentationProvider | null;
|
|
52
62
|
/**
|
|
53
63
|
* Maximum number of retry attempts for failed resources (images/audio/video).
|
|
54
64
|
*/
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a player's ESM backend fetches controller modules
|
|
3
|
+
* (`EsmBackendConfig.loadControllers`).
|
|
4
|
+
*
|
|
5
|
+
* The host's `loaderOptions.loadControllers` decides when set. Otherwise an
|
|
6
|
+
* author view loads them, and a delivery loads them unless it is hosted: a
|
|
7
|
+
* hosted player takes models and scores from the server and resolves no
|
|
8
|
+
* controller (`findPieController`), so fetching one is wasted.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveLoadControllers(args: {
|
|
11
|
+
loadControllers?: boolean;
|
|
12
|
+
author: boolean;
|
|
13
|
+
hosted: boolean;
|
|
14
|
+
}): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a player's ESM backend fetches controller modules
|
|
3
|
+
* (`EsmBackendConfig.loadControllers`).
|
|
4
|
+
*
|
|
5
|
+
* The host's `loaderOptions.loadControllers` decides when set. Otherwise an
|
|
6
|
+
* author view loads them, and a delivery loads them unless it is hosted: a
|
|
7
|
+
* hosted player takes models and scores from the server and resolves no
|
|
8
|
+
* controller (`findPieController`), so fetching one is wasted.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveLoadControllers(args) {
|
|
11
|
+
return args.loadControllers ?? (args.author || !args.hosted);
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default PIE bundle service base URL. Exported so widgets can use it as
|
|
3
|
+
* the fallback when the host does not supply `loaderOptions.bundleHost`.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DEFAULT_BUNDLE_HOST = "https://proxy.pie-api.com/bundles/";
|
|
6
|
+
/**
|
|
7
|
+
* Default ESM CDN base URL, the fallback when the host does not supply
|
|
8
|
+
* `loaderOptions.esmCdnUrl`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_ESM_CDN_URL = "https://cdn.jsdelivr.net/npm";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default PIE bundle service base URL. Exported so widgets can use it as
|
|
3
|
+
* the fallback when the host does not supply `loaderOptions.bundleHost`.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_BUNDLE_HOST = "https://proxy.pie-api.com/bundles/";
|
|
6
|
+
/**
|
|
7
|
+
* Default ESM CDN base URL, the fallback when the host does not supply
|
|
8
|
+
* `loaderOptions.esmCdnUrl`.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_ESM_CDN_URL = "https://cdn.jsdelivr.net/npm";
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* unregistered tags and a per-tag `RegistrationFailureReason` map.
|
|
11
11
|
*
|
|
12
12
|
* The primitive delegates the actual fetch/register work to a backend
|
|
13
|
-
* adapter (IIFE or ESM)
|
|
13
|
+
* adapter (IIFE or ESM) and verifies the outcome via
|
|
14
14
|
* `customElements.whenDefined`. An adapter cannot silently under-register
|
|
15
|
-
* — the primitive will catch it and surface a timeout reason.
|
|
15
|
+
* — the primitive will catch it and surface a timeout reason. A tag the
|
|
16
|
+
* adapter reports a failed load for is not waited on.
|
|
16
17
|
*
|
|
17
18
|
* See packages/players-shared/tests/element-loader-contract.test.ts for
|
|
18
19
|
* the executable specification of every failure mode this primitive is
|
|
@@ -29,7 +30,7 @@ export type { IifeBackendConfig } from "./iife-adapter.js";
|
|
|
29
30
|
export type { EsmBackendConfig } from "./esm-adapter.js";
|
|
30
31
|
/**
|
|
31
32
|
* Aggregate error thrown by `ensureRegistered` when one or more requested
|
|
32
|
-
* tags were not registered
|
|
33
|
+
* tags were not registered: their loads failed, or verification timed out.
|
|
33
34
|
*/
|
|
34
35
|
export declare class ElementLoaderError extends Error {
|
|
35
36
|
readonly name = "ElementLoaderError";
|
|
@@ -37,17 +38,24 @@ export declare class ElementLoaderError extends Error {
|
|
|
37
38
|
readonly reasons: Map<ElementTag, RegistrationFailureReason>;
|
|
38
39
|
constructor(message: string, unregisteredTags: Set<ElementTag>, reasons: Map<ElementTag, RegistrationFailureReason>);
|
|
39
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Why each tag of an `ElementLoaderError` failed to register, one clause per
|
|
43
|
+
* tag; `undefined` for any other error. Players report it as the `cause` of a
|
|
44
|
+
* load error.
|
|
45
|
+
*/
|
|
46
|
+
export declare function describeRegistrationFailures(error: unknown): string | undefined;
|
|
40
47
|
/**
|
|
41
48
|
* Thrown by `assertRegistered` when any requested tag is missing from
|
|
42
|
-
* `customElements`.
|
|
43
|
-
*
|
|
49
|
+
* `customElements`. The message names, for each missing tag, the tags its
|
|
50
|
+
* package (or, without one, its base tag) is registered under.
|
|
44
51
|
*/
|
|
45
52
|
export declare class ElementAssertionError extends Error {
|
|
46
53
|
readonly name = "ElementAssertionError";
|
|
47
54
|
readonly expectedTags: readonly ElementTag[];
|
|
48
55
|
readonly missingTags: readonly ElementTag[];
|
|
56
|
+
/** The `window.PIE_REGISTRY` tags `customElements` holds. */
|
|
49
57
|
readonly currentlyRegisteredTags: readonly ElementTag[];
|
|
50
|
-
constructor(expected: ElementTag[], missing: ElementTag[], currentlyRegistered: ElementTag[]);
|
|
58
|
+
constructor(expected: ElementTag[], missing: ElementTag[], currentlyRegistered: ElementTag[], packages?: ElementMap);
|
|
51
59
|
}
|
|
52
60
|
export type BackendOption = IifeBackendConfig | EsmBackendConfig | ElementLoaderBackend;
|
|
53
61
|
export type EnsureRegisteredOptions = {
|
|
@@ -85,6 +93,8 @@ export type EnsureRegisteredOptions = {
|
|
|
85
93
|
* - After the adapter's `load` settles, a post-load verification pass
|
|
86
94
|
* (bounded `customElements.whenDefined`) checks every tag. Any missing
|
|
87
95
|
* tag becomes a rejection.
|
|
96
|
+
* - Verification does not wait on a tag the adapter reports a failed load
|
|
97
|
+
* for, so when that covers every missing tag the rejection is immediate.
|
|
88
98
|
*/
|
|
89
99
|
export declare function ensureRegistered(elements: ElementMap, options: EnsureRegisteredOptions): Promise<void>;
|
|
90
100
|
/**
|
|
@@ -92,6 +102,8 @@ export declare function ensureRegistered(elements: ElementMap, options: EnsureRe
|
|
|
92
102
|
* Throws `ElementAssertionError` with diagnostic detail otherwise.
|
|
93
103
|
*
|
|
94
104
|
* Used by hosts that opt into the "preloaded" strategy — they pre-register
|
|
95
|
-
* elements out-of-band and want a loud failure if anything is missing.
|
|
105
|
+
* elements out-of-band and want a loud failure if anything is missing. An
|
|
106
|
+
* element map, tag to package spec, lets the error name what each missing
|
|
107
|
+
* tag's package is registered as.
|
|
96
108
|
*/
|
|
97
|
-
export declare function assertRegistered(tags: ElementTag[]): void;
|
|
109
|
+
export declare function assertRegistered(tags: ElementTag[] | ElementMap): void;
|
|
@@ -10,23 +10,28 @@
|
|
|
10
10
|
* unregistered tags and a per-tag `RegistrationFailureReason` map.
|
|
11
11
|
*
|
|
12
12
|
* The primitive delegates the actual fetch/register work to a backend
|
|
13
|
-
* adapter (IIFE or ESM)
|
|
13
|
+
* adapter (IIFE or ESM) and verifies the outcome via
|
|
14
14
|
* `customElements.whenDefined`. An adapter cannot silently under-register
|
|
15
|
-
* — the primitive will catch it and surface a timeout reason.
|
|
15
|
+
* — the primitive will catch it and surface a timeout reason. A tag the
|
|
16
|
+
* adapter reports a failed load for is not waited on.
|
|
16
17
|
*
|
|
17
18
|
* See packages/players-shared/tests/element-loader-contract.test.ts for
|
|
18
19
|
* the executable specification of every failure mode this primitive is
|
|
19
20
|
* required to catch.
|
|
20
21
|
*/
|
|
21
22
|
import { DEFAULT_IIFE_BUNDLE_RETRY_CONFIG } from "../loader-config.js";
|
|
23
|
+
import { pieRegistry } from "../pie/registry.js";
|
|
24
|
+
import { Status } from "../pie/types.js";
|
|
25
|
+
import { parsePackageName } from "../pie/utils.js";
|
|
26
|
+
import { parseVersionedTagName } from "../pie/versioned-tag.js";
|
|
22
27
|
import { AdapterFailure, } from "./element-loader-types.js";
|
|
23
|
-
import { createEsmBackend } from "./esm-adapter.js";
|
|
28
|
+
import { clearPackageMetadataRequests, createEsmBackend, } from "./esm-adapter.js";
|
|
24
29
|
import { createIifeBackend } from "./iife-adapter.js";
|
|
25
30
|
import { assertElementPackagesAllowed, } from "./element-package-policy.js";
|
|
26
31
|
export { AdapterFailure } from "./element-loader-types.js";
|
|
27
32
|
/**
|
|
28
33
|
* Aggregate error thrown by `ensureRegistered` when one or more requested
|
|
29
|
-
* tags were not registered
|
|
34
|
+
* tags were not registered: their loads failed, or verification timed out.
|
|
30
35
|
*/
|
|
31
36
|
export class ElementLoaderError extends Error {
|
|
32
37
|
name = "ElementLoaderError";
|
|
@@ -38,31 +43,85 @@ export class ElementLoaderError extends Error {
|
|
|
38
43
|
this.reasons = reasons;
|
|
39
44
|
}
|
|
40
45
|
}
|
|
46
|
+
const describeRegistrationFailure = (reason) => {
|
|
47
|
+
switch (reason.kind) {
|
|
48
|
+
case "timeout":
|
|
49
|
+
return `not defined within ${reason.timeoutMs} ms`;
|
|
50
|
+
case "module-load-failed":
|
|
51
|
+
return `${reason.specifier} failed to load: ${reason.cause}`;
|
|
52
|
+
case "bundle-load-failed":
|
|
53
|
+
return `${reason.url} failed to load: ${reason.cause}`;
|
|
54
|
+
case "define-failed":
|
|
55
|
+
case "backend-rejected":
|
|
56
|
+
return reason.cause;
|
|
57
|
+
case "not-a-constructor":
|
|
58
|
+
return `${reason.packageName ?? "its package"} exports no element constructor`;
|
|
59
|
+
case "no-element-class":
|
|
60
|
+
return `${reason.packageName} exports no element class`;
|
|
61
|
+
case "package-not-in-bundle":
|
|
62
|
+
return `${reason.packageName} is not in the bundle, which holds ${reason.availablePackages.join(", ") || "no packages"}`;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Why each tag of an `ElementLoaderError` failed to register, one clause per
|
|
67
|
+
* tag; `undefined` for any other error. Players report it as the `cause` of a
|
|
68
|
+
* load error.
|
|
69
|
+
*/
|
|
70
|
+
export function describeRegistrationFailures(error) {
|
|
71
|
+
if (!(error instanceof ElementLoaderError))
|
|
72
|
+
return undefined;
|
|
73
|
+
return [...error.reasons]
|
|
74
|
+
.map(([tag, reason]) => `${tag} (${reason.kind}): ${describeRegistrationFailure(reason)}`)
|
|
75
|
+
.join("; ");
|
|
76
|
+
}
|
|
41
77
|
/**
|
|
42
78
|
* Thrown by `assertRegistered` when any requested tag is missing from
|
|
43
|
-
* `customElements`.
|
|
44
|
-
*
|
|
79
|
+
* `customElements`. The message names, for each missing tag, the tags its
|
|
80
|
+
* package (or, without one, its base tag) is registered under.
|
|
45
81
|
*/
|
|
46
82
|
export class ElementAssertionError extends Error {
|
|
47
83
|
name = "ElementAssertionError";
|
|
48
84
|
expectedTags;
|
|
49
85
|
missingTags;
|
|
86
|
+
/** The `window.PIE_REGISTRY` tags `customElements` holds. */
|
|
50
87
|
currentlyRegisteredTags;
|
|
51
|
-
constructor(expected, missing, currentlyRegistered) {
|
|
52
|
-
super(buildAssertionMessage(expected, missing, currentlyRegistered));
|
|
88
|
+
constructor(expected, missing, currentlyRegistered, packages = {}) {
|
|
89
|
+
super(buildAssertionMessage(expected, missing, currentlyRegistered, packages));
|
|
53
90
|
this.expectedTags = expected;
|
|
54
91
|
this.missingTags = missing;
|
|
55
92
|
this.currentlyRegisteredTags = currentlyRegistered;
|
|
56
93
|
}
|
|
57
94
|
}
|
|
58
|
-
function buildAssertionMessage(expected, missing, registered) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
function buildAssertionMessage(expected, missing, registered, packages) {
|
|
96
|
+
const details = missing.map((tag) => {
|
|
97
|
+
const packageName = packageNameOf(packages[tag]);
|
|
98
|
+
const baseName = parseVersionedTagName(tag).baseName;
|
|
99
|
+
const related = packageName
|
|
100
|
+
? registered.filter((other) => registeredPackageName(other) === packageName)
|
|
101
|
+
: registered.filter((other) => parseVersionedTagName(other).baseName === baseName);
|
|
102
|
+
if (!related.includes(baseName) && isRegistered(baseName)) {
|
|
103
|
+
related.push(baseName);
|
|
104
|
+
}
|
|
105
|
+
const subject = packageName ?? baseName;
|
|
106
|
+
return related.length > 0
|
|
107
|
+
? `${subject} is registered as [${related.join(", ")}]`
|
|
108
|
+
: `nothing is registered for ${subject}`;
|
|
109
|
+
});
|
|
110
|
+
return (`ElementLoader.assertRegistered: missing [${missing.join(", ")}] ` +
|
|
111
|
+
`of [${expected.join(", ")}]; ${details.join("; ")}.`);
|
|
112
|
+
}
|
|
113
|
+
function packageNameOf(spec) {
|
|
114
|
+
if (!spec)
|
|
115
|
+
return undefined;
|
|
116
|
+
try {
|
|
117
|
+
return parsePackageName(spec).name || undefined;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function registeredPackageName(tag) {
|
|
124
|
+
return packageNameOf(pieRegistry()[tag]?.package);
|
|
66
125
|
}
|
|
67
126
|
const DEFAULT_WHEN_DEFINED_TIMEOUT_MS = 5000;
|
|
68
127
|
const DEFAULT_LOAD_TIMEOUT_MS = DEFAULT_IIFE_BUNDLE_RETRY_CONFIG.timeoutMs;
|
|
@@ -82,6 +141,8 @@ const resolvedBackendOverrides = new Map();
|
|
|
82
141
|
* - After the adapter's `load` settles, a post-load verification pass
|
|
83
142
|
* (bounded `customElements.whenDefined`) checks every tag. Any missing
|
|
84
143
|
* tag becomes a rejection.
|
|
144
|
+
* - Verification does not wait on a tag the adapter reports a failed load
|
|
145
|
+
* for, so when that covers every missing tag the rejection is immediate.
|
|
85
146
|
*/
|
|
86
147
|
export async function ensureRegistered(elements, options) {
|
|
87
148
|
if (!elements || Object.keys(elements).length === 0)
|
|
@@ -121,9 +182,15 @@ async function runEnsureRegistered(elements, tags, backend, context, timeoutMs,
|
|
|
121
182
|
catch (err) {
|
|
122
183
|
adapterError = err instanceof Error ? err : new Error(String(err));
|
|
123
184
|
}
|
|
185
|
+
// A tag whose load failed cannot register any more, so verification waits
|
|
186
|
+
// only on the others. A timed-out load can still register, so its tag waits.
|
|
124
187
|
const verification = await Promise.all(tags.map(async (tag) => {
|
|
125
188
|
if (isRegistered(tag))
|
|
126
189
|
return { tag, ok: true };
|
|
190
|
+
const adapterReason = extractAdapterReason(adapterError, tag);
|
|
191
|
+
if (adapterReason && adapterReason.kind !== "timeout") {
|
|
192
|
+
return { tag, ok: false };
|
|
193
|
+
}
|
|
127
194
|
try {
|
|
128
195
|
await whenDefinedWithTimeout(tag, timeoutMs);
|
|
129
196
|
return { tag, ok: true };
|
|
@@ -184,15 +251,19 @@ async function raceWithLoadTimeout(loadPromise, tags, loadTimeoutMs) {
|
|
|
184
251
|
* Throws `ElementAssertionError` with diagnostic detail otherwise.
|
|
185
252
|
*
|
|
186
253
|
* Used by hosts that opt into the "preloaded" strategy — they pre-register
|
|
187
|
-
* elements out-of-band and want a loud failure if anything is missing.
|
|
254
|
+
* elements out-of-band and want a loud failure if anything is missing. An
|
|
255
|
+
* element map, tag to package spec, lets the error name what each missing
|
|
256
|
+
* tag's package is registered as.
|
|
188
257
|
*/
|
|
189
258
|
export function assertRegistered(tags) {
|
|
190
|
-
|
|
259
|
+
const packages = Array.isArray(tags) ? {} : (tags ?? {});
|
|
260
|
+
const expected = Array.isArray(tags) ? tags : Object.keys(packages);
|
|
261
|
+
if (expected.length === 0)
|
|
191
262
|
return;
|
|
192
|
-
const missing =
|
|
263
|
+
const missing = expected.filter((tag) => !isRegistered(tag));
|
|
193
264
|
if (missing.length === 0)
|
|
194
265
|
return;
|
|
195
|
-
throw new ElementAssertionError(
|
|
266
|
+
throw new ElementAssertionError(expected, missing, snapshotRegisteredTags(), packages);
|
|
196
267
|
}
|
|
197
268
|
// ─── Internals ───────────────────────────────────────────────────────────────
|
|
198
269
|
function resolveBackend(backend) {
|
|
@@ -363,24 +434,18 @@ async function whenDefinedWithTimeout(tag, timeoutMs) {
|
|
|
363
434
|
clearTimeout(timer);
|
|
364
435
|
}
|
|
365
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* `customElements` cannot be enumerated, so the registered tags are the
|
|
439
|
+
* `window.PIE_REGISTRY` entries it holds.
|
|
440
|
+
*/
|
|
366
441
|
function snapshotRegisteredTags() {
|
|
367
|
-
if (typeof
|
|
442
|
+
if (typeof window === "undefined")
|
|
368
443
|
return [];
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const reg = customElements;
|
|
375
|
-
if (typeof reg.__pieSnapshot === "function") {
|
|
376
|
-
try {
|
|
377
|
-
return reg.__pieSnapshot();
|
|
378
|
-
}
|
|
379
|
-
catch {
|
|
380
|
-
return [];
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
return [];
|
|
444
|
+
return Object.values(pieRegistry())
|
|
445
|
+
.filter((entry) => entry?.status === Status.loaded)
|
|
446
|
+
.map((entry) => entry.tagName)
|
|
447
|
+
.filter((tag) => typeof tag === "string" && isRegistered(tag))
|
|
448
|
+
.sort();
|
|
384
449
|
}
|
|
385
450
|
function extractAdapterReason(err, tag) {
|
|
386
451
|
if (!err)
|
|
@@ -401,6 +466,7 @@ export const __testing = {
|
|
|
401
466
|
inFlightRequests.clear();
|
|
402
467
|
resolvedEsmBackends.clear();
|
|
403
468
|
resolvedBackendOverrides.clear();
|
|
469
|
+
clearPackageMetadataRequests();
|
|
404
470
|
},
|
|
405
471
|
inFlightCount() {
|
|
406
472
|
return inFlightRequests.size;
|
|
@@ -12,6 +12,8 @@ export declare class ElementPackagePolicyError extends Error {
|
|
|
12
12
|
readonly name = "ElementPackagePolicyError";
|
|
13
13
|
constructor(tagName: string, packageSpec: string, message: string);
|
|
14
14
|
}
|
|
15
|
+
/** Exact semver: no range, tag, `v` prefix or build metadata. */
|
|
16
|
+
export declare function isExactSemver(version: string): boolean;
|
|
15
17
|
/**
|
|
16
18
|
* Validate an element map only when a host explicitly supplies a policy.
|
|
17
19
|
* Omitting the policy preserves the existing trusted-application behavior.
|
|
@@ -10,7 +10,8 @@ export class ElementPackagePolicyError extends Error {
|
|
|
10
10
|
this.packageSpec = packageSpec;
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
/** Exact semver: no range, tag, `v` prefix or build metadata. */
|
|
14
|
+
export function isExactSemver(version) {
|
|
14
15
|
return validSemver(version) === version;
|
|
15
16
|
}
|
|
16
17
|
function parsePolicyPackageSpec(spec) {
|
|
@@ -27,9 +27,18 @@ export type EsmCdnProviderName = BuiltInEsmCdnProviderName | (string & {});
|
|
|
27
27
|
export type EsmCdnProvider = {
|
|
28
28
|
name: EsmCdnProviderName;
|
|
29
29
|
packageJsonUrl(packageVersion: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* URL of `dist/browser/<view>/index.js`. `view` can be a nested path: an
|
|
32
|
+
* element's editor-runtime variant is `editor-runtime/<view>`.
|
|
33
|
+
*/
|
|
30
34
|
browserViewUrl(packageVersion: string, view: string): string;
|
|
31
35
|
browserControllerUrl(packageVersion: string): string;
|
|
32
36
|
sharedDependencyUrl(dependencyName: string, version: string, subpath?: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* URL of the package's `./runtime-support` module. Without it, the file
|
|
39
|
+
* `dist/runtime-support.js` beside `packageJsonUrl`.
|
|
40
|
+
*/
|
|
41
|
+
runtimeSupportUrl?(packageVersion: string): string;
|
|
33
42
|
};
|
|
34
43
|
export type EsmCdnProviderOption = EsmCdnProviderName | EsmCdnProvider;
|
|
35
44
|
export type EsmBackendConfig = {
|
|
@@ -56,3 +65,23 @@ export type EsmBackendConfig = {
|
|
|
56
65
|
export type EsmBackend = ElementLoaderBackend & {};
|
|
57
66
|
export declare function createEsmBackend(config: EsmBackendConfig): EsmBackend;
|
|
58
67
|
export declare function mapEsmViewElements(elements: ElementMap, view?: string, viewConfig?: ViewConfig): ElementMap;
|
|
68
|
+
/**
|
|
69
|
+
* URL of a package's `./runtime-support` module on the ESM CDN the players load
|
|
70
|
+
* elements from, or `undefined` when a custom provider names no package root.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveEsmRuntimeSupportUrl(packageVersion: string, options: {
|
|
73
|
+
cdnBaseUrl: string;
|
|
74
|
+
cdnProvider?: EsmCdnProviderOption;
|
|
75
|
+
}): string | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* The npm root the ESM CDN the players load elements from serves raw package
|
|
78
|
+
* files under, `<root>/<package>@<version>/<path>`: the base URL for jsDelivr,
|
|
79
|
+
* raw.esm.sh for esm.sh, and for a custom provider whatever its
|
|
80
|
+
* `packageJsonUrl` puts before the package. `undefined` when that URL names
|
|
81
|
+
* no such root.
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveEsmAssetRoot(options: {
|
|
84
|
+
cdnBaseUrl: string;
|
|
85
|
+
cdnProvider?: EsmCdnProviderOption;
|
|
86
|
+
}): string | undefined;
|
|
87
|
+
export declare function pickElementClass(module: any, view: string): unknown;
|