@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
@@ -24,13 +24,16 @@ export type LoaderConfig = {
24
24
  /**
25
25
  * Instrumentation provider for tracking events and errors.
26
26
  *
27
- * Optional. If not provided, defaults to NewRelicInstrumentationProvider.
28
- * The provider handles instrumentation gracefully - if New Relic (or the configured
29
- * backend) is not available, it will simply not track events (no errors thrown).
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 (default - no configuration needed)
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) but always verifies the outcome via
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 by the time verification timed out.
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`. Carries enough detail for the host to diagnose what
43
- * pre-registration step was skipped.
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) but always verifies the outcome via
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 by the time verification timed out.
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`. Carries enough detail for the host to diagnose what
44
- * pre-registration step was skipped.
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 expectedStr = expected.join(", ");
60
- const missingStr = missing.join(", ");
61
- const registeredStr = registered.length
62
- ? registered.join(", ")
63
- : "(none enumerable)";
64
- return (`ElementLoader.assertRegistered: expected [${expectedStr}], ` +
65
- `missing [${missingStr}]. customElements contains: [${registeredStr}].`);
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
- if (!tags || tags.length === 0)
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 = tags.filter((tag) => !isRegistered(tag));
263
+ const missing = expected.filter((tag) => !isRegistered(tag));
193
264
  if (missing.length === 0)
194
265
  return;
195
- throw new ElementAssertionError(tags, missing, snapshotRegisteredTags());
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 customElements === "undefined")
442
+ if (typeof window === "undefined")
368
443
  return [];
369
- // Standard `CustomElementRegistry` does not expose iteration. Tests install
370
- // a scripted registry with a `__pieSnapshot` extension to make diagnostic
371
- // messages assertable. Production falls through to an empty list —
372
- // still strictly better than today's "missing tags: X" error which leaks
373
- // no registry state at all.
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
- function isExactSemver(version) {
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,12 @@ 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
+ export declare function pickElementClass(module: any, view: string): unknown;