@pie-players/pie-assessment-toolkit 0.3.74 → 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 +349 -313
- package/dist/attempt/TestSession.d.ts +1 -20
- package/dist/attempt/TestSession.js +8 -99
- package/dist/components/ItemScope.custom-element.d.ts +1 -0
- package/dist/components/ItemScope.custom-element.js +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-97hx60z4.js} +1 -1
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
- package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
- package/dist/components/item-scope-element.d.ts +2 -0
- package/dist/components/item-scope-element.js +2 -0
- package/dist/context/assessment-toolkit-context.d.ts +27 -6
- package/dist/index.d.ts +22 -47
- package/dist/index.js +12 -36
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +77 -32
- package/dist/policy/core/ToolPolicyEngine.js +136 -46
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +75 -54
- package/dist/policy/core/decision-types.d.ts +65 -34
- package/dist/policy/core/feature-decision.d.ts +16 -9
- package/dist/policy/core/feature-decision.js +14 -8
- package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
- package/dist/policy/core/pnp-policy-inputs.js +28 -56
- package/dist/policy/core/provenance.d.ts +9 -4
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
- package/dist/policy/sources/PnpPolicySource.js +117 -118
- package/dist/runtime/SectionControllerBinding.d.ts +279 -0
- package/dist/runtime/SectionControllerBinding.js +450 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
- package/dist/runtime/SectionRuntimeEngine.js +30 -372
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
- package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
- package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
- package/dist/runtime/adapter/dom-event-bridge.js +17 -44
- package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
- package/dist/runtime/adapter/subscriber-fanout.js +1 -2
- package/dist/runtime/catalog-context.d.ts +19 -0
- package/dist/runtime/catalog-context.js +28 -0
- package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
- package/dist/runtime/composition-emit-scheduler.js +9 -15
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +17 -0
- package/dist/runtime/content-region.js +29 -0
- package/dist/runtime/content-registration.d.ts +13 -0
- package/dist/runtime/content-registration.js +25 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
- package/dist/runtime/core/SectionEngineCore.js +2 -2
- package/dist/runtime/core/cohort.d.ts +1 -1
- package/dist/runtime/core/cohort.js +1 -1
- package/dist/runtime/core/engine-input.d.ts +18 -30
- package/dist/runtime/core/engine-input.js +11 -12
- package/dist/runtime/core/engine-output.d.ts +16 -40
- package/dist/runtime/core/engine-output.js +9 -21
- package/dist/runtime/core/engine-readiness.d.ts +5 -37
- package/dist/runtime/core/engine-readiness.js +8 -41
- package/dist/runtime/core/engine-resolver.d.ts +46 -74
- package/dist/runtime/core/engine-resolver.js +18 -43
- package/dist/runtime/core/engine-state.d.ts +28 -36
- package/dist/runtime/core/engine-state.js +18 -21
- package/dist/runtime/core/engine-transition.d.ts +14 -19
- package/dist/runtime/core/engine-transition.js +71 -51
- package/dist/runtime/engine.d.ts +16 -19
- package/dist/runtime/engine.js +12 -19
- package/dist/runtime/page-warnings.d.ts +13 -0
- package/dist/runtime/page-warnings.js +22 -0
- package/dist/runtime/policy-input-forwarding.d.ts +25 -0
- package/dist/runtime/policy-input-forwarding.js +25 -0
- package/dist/runtime/registration-events.d.ts +11 -0
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/shell-event-bridge.d.ts +45 -0
- package/dist/runtime/shell-event-bridge.js +127 -0
- package/dist/runtime/shell-registration.d.ts +73 -0
- package/dist/runtime/shell-registration.js +95 -0
- package/dist/runtime/shell-scope.d.ts +68 -0
- package/dist/runtime/shell-scope.js +188 -0
- package/dist/runtime/tool-host-contract.d.ts +8 -10
- package/dist/runtime/tool-host-contract.js +11 -11
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/ElementToolStateStore.d.ts +14 -10
- package/dist/services/ElementToolStateStore.js +37 -13
- package/dist/services/HighlightCoordinator.d.ts +21 -21
- package/dist/services/HighlightCoordinator.js +431 -325
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +117 -70
- package/dist/services/TTSService.js +668 -578
- package/dist/services/ToolCoordinator.d.ts +43 -60
- package/dist/services/ToolCoordinator.js +164 -206
- package/dist/services/ToolRegistry.d.ts +74 -57
- package/dist/services/ToolRegistry.js +104 -114
- package/dist/services/ToolkitCoordinator.d.ts +183 -189
- package/dist/services/ToolkitCoordinator.js +477 -431
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +0 -1
- package/dist/services/framework-error-bus.d.ts +3 -6
- package/dist/services/framework-error-bus.js +3 -6
- package/dist/services/framework-error.d.ts +22 -7
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +82 -0
- package/dist/services/spoken-audio-cards.d.ts +0 -2
- package/dist/services/spoken-audio-cards.js +0 -2
- package/dist/services/tool-config-defaults.d.ts +3 -3
- package/dist/services/tool-config-defaults.js +3 -3
- package/dist/services/tool-config-validation.d.ts +4 -5
- package/dist/services/tool-config-validation.js +36 -61
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +0 -12
- package/dist/services/tool-icons.d.ts +4 -3
- package/dist/services/tool-icons.js +4 -3
- package/dist/services/tool-instance-id.d.ts +0 -1
- package/dist/services/tool-instance-id.js +0 -6
- package/dist/services/tool-providers/TTSToolProvider.d.ts +18 -19
- package/dist/services/tool-providers/TTSToolProvider.js +37 -34
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +30 -26
- package/dist/services/tool-providers/ToolProviderRegistry.js +119 -93
- package/dist/services/tool-request.d.ts +27 -12
- package/dist/services/tool-request.js +24 -14
- package/dist/services/toolbar-decided-tools.d.ts +15 -0
- package/dist/services/toolbar-decided-tools.js +28 -0
- package/dist/services/tools-config-normalizer.d.ts +17 -22
- package/dist/services/tools-config-normalizer.js +2 -10
- package/dist/services/tts/browser-provider.d.ts +38 -2
- package/dist/services/tts/browser-provider.js +276 -140
- package/dist/services/tts/flat-tree.d.ts +71 -0
- package/dist/services/tts/flat-tree.js +269 -0
- package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
- package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
- package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
- package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +12 -4
- package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
- package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
- package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +32 -18
- package/dist/services/tts/math-control-names.d.ts +21 -0
- package/dist/services/tts/math-control-names.js +142 -0
- package/dist/services/tts/math-speech.d.ts +11 -0
- package/dist/services/tts/math-speech.js +51 -18
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
- package/dist/services/tts/ssml/spoken-text.js +29 -0
- package/dist/services/tts/start-failure.d.ts +11 -0
- package/dist/services/tts/start-failure.js +19 -0
- package/dist/services/tts/text-processing.d.ts +9 -0
- package/dist/services/tts/text-processing.js +46 -33
- package/dist/services/tts/text-segmentation.d.ts +7 -0
- package/dist/services/tts/text-segmentation.js +47 -0
- package/dist/services/tts-runtime-config.d.ts +25 -17
- package/dist/services/tts-runtime-config.js +16 -95
- package/dist/tools/content-capability-resolution.d.ts +7 -9
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +58 -0
- package/dist/tools/registration.js +54 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +44 -42
- package/dist/tools/tool-tag-map.d.ts +5 -15
- package/dist/tools/tool-tag-map.js +6 -20
- package/dist/utils/structural-equality.d.ts +11 -0
- package/dist/utils/structural-equality.js +47 -0
- package/package.json +13 -29
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
- package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
- package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
- package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
- package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -18
- package/dist/item-loader.d.ts +0 -44
- package/dist/item-loader.js +0 -61
- package/dist/policy/core/engine-context.d.ts +0 -29
- package/dist/policy/core/engine-context.js +0 -27
- package/dist/policy/core/policy-source-tag.d.ts +0 -31
- package/dist/policy/core/policy-source-tag.js +0 -28
- package/dist/policy/internal.d.ts +0 -25
- package/dist/policy/internal.js +0 -25
- package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
- package/dist/runtime/adapter/coordinator-bridge.js +0 -126
- package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
- package/dist/runtime/adapter/framework-error-bridge.js +0 -46
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
- package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
- package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
- package/dist/runtime/core/engine-stage-derivation.js +0 -29
- package/dist/runtime/engine-context.d.ts +0 -39
- package/dist/runtime/engine-context.js +0 -31
- package/dist/runtime/internal.d.ts +0 -43
- package/dist/runtime/internal.js +0 -45
- package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
- package/dist/runtime/section-runtime-engine-host-context.js +0 -57
- package/dist/runtime/stage-emit-gate.d.ts +0 -92
- package/dist/runtime/stage-emit-gate.js +0 -82
- package/dist/services/I18nService.d.ts +0 -47
- package/dist/services/I18nService.js +0 -84
- package/dist/services/ThemeProvider.d.ts +0 -95
- package/dist/services/ThemeProvider.js +0 -334
- package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
- package/dist/services/defaultPersonalNeedsProfile.js +0 -26
- package/dist/services/pnp-standard-features.d.ts +0 -238
- package/dist/services/pnp-standard-features.js +0 -338
- package/dist/tools/client.d.ts +0 -10
- package/dist/tools/client.js +0 -10
- package/dist/tools/internal.d.ts +0 -44
- package/dist/tools/internal.js +0 -39
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { I18nProvider } from "@pie-players/pie-players-shared/i18n/types";
|
|
8
8
|
import type { CatalogOwnerSnapshot } from "./AccessibilityCatalogResolver.js";
|
|
9
9
|
import type { ToolContext, ToolLevel } from "./tool-context.js";
|
|
10
|
-
import type
|
|
10
|
+
import { type ToolComponentOverrides } from "../tools/tool-tag-map.js";
|
|
11
11
|
import type { AccessibilityCatalogResolverApi, ElementToolStateStoreApi, ToolCoordinatorApi, ToolkitCoordinatorApi, TtsServiceApi } from "./interfaces.js";
|
|
12
12
|
import type { ToolProviderApi } from "./tool-providers/ToolProviderApi.js";
|
|
13
13
|
import type { ToolProviderConfig as ToolRuntimeConfig } from "./tools-config-normalizer.js";
|
|
@@ -65,9 +65,10 @@ export interface ToolbarContext {
|
|
|
65
65
|
* Content-alternate language: which authored alternate the catalog resolver
|
|
66
66
|
* should select. Not the interface locale — see {@link ToolbarContext.i18n}. The
|
|
67
67
|
* two are independent by QTI 3's own statement, and conflating them is how a
|
|
68
|
-
* Spanish passage ends up forcing Spanish widget chrome.
|
|
68
|
+
* Spanish passage ends up forcing Spanish widget chrome. Absent when neither
|
|
69
|
+
* the toolbar's `language` nor the host's `content-language` names one.
|
|
69
70
|
*/
|
|
70
|
-
language
|
|
71
|
+
language?: string;
|
|
71
72
|
/**
|
|
72
73
|
* Interface-locale provider for this capability's own UI strings.
|
|
73
74
|
*
|
|
@@ -83,12 +84,19 @@ export interface ToolbarContext {
|
|
|
83
84
|
size?: string;
|
|
84
85
|
};
|
|
85
86
|
getScopeElement?: () => HTMLElement | null;
|
|
86
|
-
|
|
87
|
+
/**
|
|
88
|
+
* State key of one PIE element in this toolbar's item, by its model id, for
|
|
89
|
+
* `elementToolStateStore`. `null` until the store and the ids it needs are
|
|
90
|
+
* known.
|
|
91
|
+
*/
|
|
92
|
+
getGlobalElementId?: (elementId: string) => string | null;
|
|
87
93
|
toolCoordinator: ToolCoordinatorApi | null;
|
|
88
94
|
toolkitCoordinator: ToolkitCoordinatorApi | null;
|
|
89
95
|
ttsService: TtsServiceApi | null;
|
|
90
96
|
elementToolStateStore: ElementToolStateStoreApi | null;
|
|
97
|
+
/** Toggles this toolbar's instance of a base tool id. */
|
|
91
98
|
toggleTool: (toolId: string) => void;
|
|
99
|
+
/** Whether this toolbar's instance of a base tool id is shown. */
|
|
92
100
|
isToolVisible: (toolId: string) => boolean;
|
|
93
101
|
subscribeVisibility: ((listener: () => void) => () => void) | null;
|
|
94
102
|
componentOverrides?: ToolComponentOverrides;
|
|
@@ -207,24 +215,18 @@ export interface HostedToolSize {
|
|
|
207
215
|
width: number;
|
|
208
216
|
height: number;
|
|
209
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* How the coordinator builds a tool's provider from the tool's config. The
|
|
220
|
+
* provider registers under the tool's own id, so `ensureProviderReady(toolId)`
|
|
221
|
+
* finds it; `provider.id` in the config selects an implementation and never
|
|
222
|
+
* renames the registration.
|
|
223
|
+
*/
|
|
210
224
|
export interface ToolProviderDescriptor {
|
|
211
|
-
getProviderId?: (config: ToolRuntimeConfig | undefined) => string;
|
|
212
225
|
createProvider: (config: ToolRuntimeConfig | undefined) => ToolProviderApi;
|
|
213
226
|
getInitConfig?: (config: ToolRuntimeConfig | undefined) => Record<string, unknown>;
|
|
214
|
-
sanitizeConfig?: (config: ToolRuntimeConfig) => ToolRuntimeConfig;
|
|
215
|
-
validateConfig?: (config: ToolRuntimeConfig) => ToolConfigDiagnostic[];
|
|
216
227
|
getAuthFetcher?: (config: ToolRuntimeConfig | undefined) => (() => Promise<Record<string, unknown>>) | undefined;
|
|
217
228
|
lazy?: boolean;
|
|
218
229
|
}
|
|
219
|
-
/**
|
|
220
|
-
* The id a registration's provider registers under for one tool config: the
|
|
221
|
-
* descriptor's answer, then the config's `provider.id`, then the tool id. `null`
|
|
222
|
-
* when the registration carries no provider.
|
|
223
|
-
*
|
|
224
|
-
* The coordinator registers providers under this id and the section player looks
|
|
225
|
-
* for them in a host-supplied coordinator by it, so the two resolve it one way.
|
|
226
|
-
*/
|
|
227
|
-
export declare function resolveToolProviderId(registration: Pick<ToolRegistration, "toolId" | "provider">, config: ToolRuntimeConfig | undefined): string | null;
|
|
228
230
|
export interface ToolToolbarRenderResult {
|
|
229
231
|
toolId: string;
|
|
230
232
|
elements?: ToolRenderElement[];
|
|
@@ -280,8 +282,14 @@ export interface ToolSurfaceServices {
|
|
|
280
282
|
*/
|
|
281
283
|
export interface ToolSurfaceRenderContext {
|
|
282
284
|
toolId: string;
|
|
283
|
-
/**
|
|
284
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Whether a PNP support, a requirement or a test-administration override
|
|
287
|
+
* granted the capability. `false` for a capability rendered because it is
|
|
288
|
+
* placed with no grant, and for a
|
|
289
|
+
* {@link ToolRegistration.resolvesWithoutGrant} capability answering from
|
|
290
|
+
* content alone.
|
|
291
|
+
*/
|
|
292
|
+
granted: boolean;
|
|
285
293
|
/** Host slot being filled. */
|
|
286
294
|
surface: string;
|
|
287
295
|
/** Feature parameters from the policy decision, if any. */
|
|
@@ -296,8 +304,6 @@ export interface ToolSurfaceRenderContext {
|
|
|
296
304
|
* present.
|
|
297
305
|
*/
|
|
298
306
|
export interface ToolContentDependencyContext {
|
|
299
|
-
/** The PNP/AfA support id being resolved. */
|
|
300
|
-
featureId: string;
|
|
301
307
|
/** Feature parameters from the policy decision, if any. */
|
|
302
308
|
parameters?: unknown;
|
|
303
309
|
/**
|
|
@@ -309,7 +315,7 @@ export interface ToolContentDependencyContext {
|
|
|
309
315
|
*/
|
|
310
316
|
catalogs: CatalogOwnerSnapshot | null;
|
|
311
317
|
/**
|
|
312
|
-
* Whether policy granted
|
|
318
|
+
* Whether policy granted this capability's support id.
|
|
313
319
|
*
|
|
314
320
|
* `false` reaches `resolve` only for a capability that declares
|
|
315
321
|
* {@link ToolRegistration.resolvesWithoutGrant}, and it is the signal that the
|
|
@@ -448,12 +454,6 @@ export interface ToolRegistration {
|
|
|
448
454
|
* Optional singleton scope for activation models that mount exactly one instance.
|
|
449
455
|
*/
|
|
450
456
|
singletonScope?: ToolSingletonScope;
|
|
451
|
-
/**
|
|
452
|
-
* PNP support IDs that enable this tool (optional)
|
|
453
|
-
* Used by the tool policy engine to determine if a PNP support enables this tool.
|
|
454
|
-
* Example: ['calculator', 'basic-calculator', 'scientific-calculator']
|
|
455
|
-
*/
|
|
456
|
-
pnpSupportIds?: string[];
|
|
457
457
|
/**
|
|
458
458
|
* Authored content this capability needs before it has anything to show.
|
|
459
459
|
*
|
|
@@ -484,6 +484,16 @@ export interface ToolRegistration {
|
|
|
484
484
|
* without hardcoded tool-specific branches.
|
|
485
485
|
*/
|
|
486
486
|
provider?: ToolProviderDescriptor;
|
|
487
|
+
/**
|
|
488
|
+
* Normalize this tool's `tools.providers.<toolId>` entry. Tools-config
|
|
489
|
+
* validation runs it before {@link ToolRegistration.validateConfig}; a throw is
|
|
490
|
+
* reported as a diagnostic and the entry passes through unchanged.
|
|
491
|
+
*/
|
|
492
|
+
sanitizeConfig?: (config: ToolRuntimeConfig) => ToolRuntimeConfig;
|
|
493
|
+
/**
|
|
494
|
+
* Diagnostics for this tool's sanitized `tools.providers.<toolId>` entry.
|
|
495
|
+
*/
|
|
496
|
+
validateConfig?: (config: ToolRuntimeConfig) => ToolConfigDiagnostic[];
|
|
487
497
|
/**
|
|
488
498
|
* Optional shell-host lifecycle hooks for hosted (floating) tools.
|
|
489
499
|
*/
|
|
@@ -547,10 +557,12 @@ export interface ToolRegistration {
|
|
|
547
557
|
*/
|
|
548
558
|
export declare class ToolRegistry {
|
|
549
559
|
private tools;
|
|
550
|
-
private pnpIndex;
|
|
551
560
|
private componentOverrides;
|
|
561
|
+
private watchedUndefinedToolElements;
|
|
552
562
|
private moduleLoaders;
|
|
553
563
|
private loadedToolModules;
|
|
564
|
+
private warnedLoaderReplacements;
|
|
565
|
+
private warnedUnregisteredAllowedTools;
|
|
554
566
|
private moduleLoadPromises;
|
|
555
567
|
private changeListeners;
|
|
556
568
|
private emitChange;
|
|
@@ -560,11 +572,11 @@ export declare class ToolRegistry {
|
|
|
560
572
|
*/
|
|
561
573
|
onRegistryChange(listener: ToolRegistryChangeListener): () => void;
|
|
562
574
|
/**
|
|
563
|
-
* Normalize a single tool
|
|
575
|
+
* Normalize a single tool id (trims surrounding whitespace).
|
|
564
576
|
*/
|
|
565
577
|
normalizeToolId(toolId: string): string;
|
|
566
578
|
/**
|
|
567
|
-
* Normalize a list of tool
|
|
579
|
+
* Normalize a list of tool ids (trims surrounding whitespace).
|
|
568
580
|
*/
|
|
569
581
|
normalizeToolIds(toolIds: string[]): string[];
|
|
570
582
|
/**
|
|
@@ -612,13 +624,6 @@ export declare class ToolRegistry {
|
|
|
612
624
|
* @returns Array of tool registrations
|
|
613
625
|
*/
|
|
614
626
|
getAllTools(): ToolRegistration[];
|
|
615
|
-
/**
|
|
616
|
-
* Find tool IDs that support a given PNP support ID
|
|
617
|
-
*
|
|
618
|
-
* @param pnpSupportId - PNP support ID (e.g., 'calculator')
|
|
619
|
-
* @returns Set of tool IDs that support this PNP ID
|
|
620
|
-
*/
|
|
621
|
-
getToolsByPNPSupport(pnpSupportId: string): Set<string>;
|
|
622
627
|
/**
|
|
623
628
|
* Get tools that support a specific level
|
|
624
629
|
*
|
|
@@ -644,11 +649,12 @@ export declare class ToolRegistry {
|
|
|
644
649
|
*/
|
|
645
650
|
getToolsBySurface(surface: string): ToolRegistration[];
|
|
646
651
|
/**
|
|
647
|
-
* Support ids
|
|
652
|
+
* Support ids, which are tool ids, of the capabilities that need authored
|
|
653
|
+
* content.
|
|
648
654
|
*
|
|
649
|
-
* What a host filters a default grant list on
|
|
650
|
-
*
|
|
651
|
-
*
|
|
655
|
+
* What a host filters a default grant list on: granting one of these
|
|
656
|
+
* wholesale grants an accommodation to learners with no documented need
|
|
657
|
+
* for it.
|
|
652
658
|
*/
|
|
653
659
|
getContentDependentSupportIds(): string[];
|
|
654
660
|
/**
|
|
@@ -658,7 +664,7 @@ export declare class ToolRegistry {
|
|
|
658
664
|
/**
|
|
659
665
|
* Filter tools by visibility in a given context
|
|
660
666
|
*
|
|
661
|
-
* Pass 2 of the
|
|
667
|
+
* Pass 2 of the three-pass model: Given a list of allowed tool IDs (from Pass 1),
|
|
662
668
|
* ask each tool if it's relevant in this context.
|
|
663
669
|
*
|
|
664
670
|
* @param allowedToolIds - Tool IDs that passed Pass 1 (orchestrator approval)
|
|
@@ -684,13 +690,12 @@ export declare class ToolRegistry {
|
|
|
684
690
|
* Get tool metadata for building UIs
|
|
685
691
|
* Useful for building PNP configuration interfaces
|
|
686
692
|
*
|
|
687
|
-
* @returns Array of tool metadata (id, name, description,
|
|
693
|
+
* @returns Array of tool metadata (id, name, description, levels, activation)
|
|
688
694
|
*/
|
|
689
695
|
getToolMetadata(): Array<{
|
|
690
696
|
toolId: string;
|
|
691
697
|
name: string;
|
|
692
698
|
description: string;
|
|
693
|
-
pnpSupportIds: string[];
|
|
694
699
|
supportedLevels: ToolLevel[];
|
|
695
700
|
activation: ToolActivation;
|
|
696
701
|
singletonScope: ToolSingletonScope | null;
|
|
@@ -698,14 +703,6 @@ export declare class ToolRegistry {
|
|
|
698
703
|
requiresAuthoredContent: boolean;
|
|
699
704
|
contentDependencyDescription: string | null;
|
|
700
705
|
}>;
|
|
701
|
-
/**
|
|
702
|
-
* Generate PNP support IDs from enabled tools
|
|
703
|
-
* Useful for creating PNP profiles
|
|
704
|
-
*
|
|
705
|
-
* @param enabledToolIds - Tool IDs to enable
|
|
706
|
-
* @returns Array of unique PNP support IDs
|
|
707
|
-
*/
|
|
708
|
-
generatePNPSupportsFromTools(enabledToolIds: string[]): string[];
|
|
709
706
|
/**
|
|
710
707
|
* Clear all registrations (useful for testing)
|
|
711
708
|
*/
|
|
@@ -717,17 +714,39 @@ export declare class ToolRegistry {
|
|
|
717
714
|
/**
|
|
718
715
|
* Register lazy module loaders by toolId.
|
|
719
716
|
* Toolbars call ensureToolModuleLoaded(toolId) before instance creation.
|
|
717
|
+
* A tool whose module has loaded, or is loading, keeps its loader: its
|
|
718
|
+
* elements are already defined, so a replacement could never take effect.
|
|
720
719
|
*/
|
|
721
720
|
setToolModuleLoaders(loaders: Partial<Record<string, ToolModuleLoader>>): void;
|
|
721
|
+
private warnLoaderReplacedAfterLoad;
|
|
722
722
|
/**
|
|
723
723
|
* Ensure tool module side-effects are loaded exactly once.
|
|
724
724
|
* Safe to call repeatedly; concurrent callers share the same promise.
|
|
725
725
|
*/
|
|
726
726
|
ensureToolModuleLoaded(toolId: string): Promise<void>;
|
|
727
727
|
/**
|
|
728
|
-
*
|
|
728
|
+
* The undefined element tag a tool would render, or `null` when the tool is
|
|
729
|
+
* built by a component factory, its element is defined, or there is no DOM.
|
|
730
|
+
*/
|
|
731
|
+
private undefinedToolElementTag;
|
|
732
|
+
/**
|
|
733
|
+
* Warn when a tool's module loader finished without defining the element the
|
|
734
|
+
* tag map points the tool at, as when a host remaps the tag but keeps a
|
|
735
|
+
* loader that defines the packaged element. The tool otherwise renders blank.
|
|
736
|
+
*/
|
|
737
|
+
private warnIfLoadedToolElementUndefined;
|
|
738
|
+
/**
|
|
739
|
+
* Warn when a tool with no module loader still has no element definition
|
|
740
|
+
* after the pending-input delay. A registry built without loaders otherwise
|
|
741
|
+
* renders the tool as an unknown element with no error.
|
|
742
|
+
*/
|
|
743
|
+
private watchUndefinedToolElement;
|
|
744
|
+
/**
|
|
745
|
+
* Load a set of tool modules, each to completion, and resolve with the error
|
|
746
|
+
* of every tool whose module failed, by tool id. One failure leaves the other
|
|
747
|
+
* tools loaded and usable. A failed tool is retried on the next call.
|
|
729
748
|
*/
|
|
730
|
-
ensureToolModulesLoaded(toolIds: string[]): Promise<
|
|
749
|
+
ensureToolModulesLoaded(toolIds: string[]): Promise<Map<string, unknown>>;
|
|
731
750
|
/**
|
|
732
751
|
* Whether a tool module has already been loaded.
|
|
733
752
|
*/
|
|
@@ -745,7 +764,5 @@ export declare class ToolRegistry {
|
|
|
745
764
|
* nothing and fail on every packaged capability. Overrides passed in the
|
|
746
765
|
* context still win, matching the toolbar path's precedence.
|
|
747
766
|
*/
|
|
748
|
-
renderForSurface(toolId: string, context:
|
|
749
|
-
componentOverrides?: ToolComponentOverrides;
|
|
750
|
-
}): ToolSurfaceRenderResult | null;
|
|
767
|
+
renderForSurface(toolId: string, context: ToolSurfaceRenderContext): ToolSurfaceRenderResult | null;
|
|
751
768
|
}
|
|
@@ -5,23 +5,8 @@
|
|
|
5
5
|
* and button/instance creation. Supports dynamic registration and override by integrators.
|
|
6
6
|
*/
|
|
7
7
|
import { dynamicMessageKey } from "@pie-players/pie-players-shared/i18n/provider";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
* The id a registration's provider registers under for one tool config: the
|
|
11
|
-
* descriptor's answer, then the config's `provider.id`, then the tool id. `null`
|
|
12
|
-
* when the registration carries no provider.
|
|
13
|
-
*
|
|
14
|
-
* The coordinator registers providers under this id and the section player looks
|
|
15
|
-
* for them in a host-supplied coordinator by it, so the two resolve it one way.
|
|
16
|
-
*/
|
|
17
|
-
export function resolveToolProviderId(registration, config) {
|
|
18
|
-
const descriptor = registration.provider;
|
|
19
|
-
if (!descriptor)
|
|
20
|
-
return null;
|
|
21
|
-
return (descriptor.getProviderId?.(config) ??
|
|
22
|
-
config?.provider?.id ??
|
|
23
|
-
registration.toolId);
|
|
24
|
-
}
|
|
8
|
+
import { resolveToolTag, } from "../tools/tool-tag-map.js";
|
|
9
|
+
import { PENDING_INPUT_WARNING_DELAY_MS, warnOncePerDocument, } from "../runtime/page-warnings.js";
|
|
25
10
|
/**
|
|
26
11
|
* A registration's display name in the interface locale.
|
|
27
12
|
*
|
|
@@ -163,11 +148,6 @@ function assertToolRegistrationShape(registration) {
|
|
|
163
148
|
registration.singletonScope !== "section") {
|
|
164
149
|
throw new Error(`Invalid tool registration "${registration.toolId}": selection-gateway tools must declare singletonScope "section".`);
|
|
165
150
|
}
|
|
166
|
-
if (registration.pnpSupportIds !== undefined &&
|
|
167
|
-
(!Array.isArray(registration.pnpSupportIds) ||
|
|
168
|
-
registration.pnpSupportIds.some((pnpId) => typeof pnpId !== "string" || pnpId.trim().length === 0))) {
|
|
169
|
-
throw new Error(`Invalid tool registration "${registration.toolId}": "pnpSupportIds" must be an array of non-empty strings.`);
|
|
170
|
-
}
|
|
171
151
|
if (registration.activation !== "region" &&
|
|
172
152
|
typeof registration.isVisibleInContext !== "function") {
|
|
173
153
|
throw new Error(`Invalid tool registration "${registration.toolId}": "isVisibleInContext" must be a function.`);
|
|
@@ -186,12 +166,6 @@ function assertToolRegistrationShape(registration) {
|
|
|
186
166
|
typeof registration.requiresAuthoredContent.resolve !== "function") {
|
|
187
167
|
throw new Error(`Invalid tool registration "${registration.toolId}": "requiresAuthoredContent" must be an object with a "resolve" function.`);
|
|
188
168
|
}
|
|
189
|
-
if (!registration.pnpSupportIds?.length) {
|
|
190
|
-
// A content dependency's second job is keeping the capability out of a
|
|
191
|
-
// wholesale grant, and a host filters that by support id. Declaring one
|
|
192
|
-
// with no id to filter on would silently drop that guarantee.
|
|
193
|
-
throw new Error(`Invalid tool registration "${registration.toolId}": "requiresAuthoredContent" requires at least one entry in "pnpSupportIds", which is what a host filters a default grant list on.`);
|
|
194
|
-
}
|
|
195
169
|
}
|
|
196
170
|
if (registration.renderToolbar !== undefined) {
|
|
197
171
|
if (typeof registration.renderToolbar !== "function") {
|
|
@@ -209,10 +183,12 @@ function assertToolRegistrationShape(registration) {
|
|
|
209
183
|
*/
|
|
210
184
|
export class ToolRegistry {
|
|
211
185
|
tools = new Map();
|
|
212
|
-
pnpIndex = new Map(); // pnpSupportId → Set<toolId>
|
|
213
186
|
componentOverrides = {};
|
|
187
|
+
watchedUndefinedToolElements = new Set();
|
|
214
188
|
moduleLoaders = new Map();
|
|
215
189
|
loadedToolModules = new Set();
|
|
190
|
+
warnedLoaderReplacements = new Set();
|
|
191
|
+
warnedUnregisteredAllowedTools = new Set();
|
|
216
192
|
moduleLoadPromises = new Map();
|
|
217
193
|
changeListeners = new Set();
|
|
218
194
|
emitChange(event) {
|
|
@@ -240,13 +216,13 @@ export class ToolRegistry {
|
|
|
240
216
|
};
|
|
241
217
|
}
|
|
242
218
|
/**
|
|
243
|
-
* Normalize a single tool
|
|
219
|
+
* Normalize a single tool id (trims surrounding whitespace).
|
|
244
220
|
*/
|
|
245
221
|
normalizeToolId(toolId) {
|
|
246
|
-
return
|
|
222
|
+
return toolId.trim();
|
|
247
223
|
}
|
|
248
224
|
/**
|
|
249
|
-
* Normalize a list of tool
|
|
225
|
+
* Normalize a list of tool ids (trims surrounding whitespace).
|
|
250
226
|
*/
|
|
251
227
|
normalizeToolIds(toolIds) {
|
|
252
228
|
return toolIds.map((toolId) => this.normalizeToolId(toolId));
|
|
@@ -263,15 +239,6 @@ export class ToolRegistry {
|
|
|
263
239
|
throw new Error(`Tool '${registration.toolId}' is already registered`);
|
|
264
240
|
}
|
|
265
241
|
this.tools.set(registration.toolId, registration);
|
|
266
|
-
// Index PNP support IDs
|
|
267
|
-
if (registration.pnpSupportIds) {
|
|
268
|
-
for (const pnpId of registration.pnpSupportIds) {
|
|
269
|
-
if (!this.pnpIndex.has(pnpId)) {
|
|
270
|
-
this.pnpIndex.set(pnpId, new Set());
|
|
271
|
-
}
|
|
272
|
-
this.pnpIndex.get(pnpId).add(registration.toolId);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
242
|
this.emitChange({ kind: "register", toolIds: [registration.toolId] });
|
|
276
243
|
}
|
|
277
244
|
/**
|
|
@@ -284,24 +251,7 @@ export class ToolRegistry {
|
|
|
284
251
|
if (!this.tools.has(registration.toolId)) {
|
|
285
252
|
throw new Error(`Cannot override non-existent tool '${registration.toolId}'`);
|
|
286
253
|
}
|
|
287
|
-
// Remove old PNP index entries
|
|
288
|
-
const oldReg = this.tools.get(registration.toolId);
|
|
289
|
-
if (oldReg.pnpSupportIds) {
|
|
290
|
-
for (const pnpId of oldReg.pnpSupportIds) {
|
|
291
|
-
this.pnpIndex.get(pnpId)?.delete(registration.toolId);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
// Add new registration
|
|
295
254
|
this.tools.set(registration.toolId, registration);
|
|
296
|
-
// Re-index PNP support IDs
|
|
297
|
-
if (registration.pnpSupportIds) {
|
|
298
|
-
for (const pnpId of registration.pnpSupportIds) {
|
|
299
|
-
if (!this.pnpIndex.has(pnpId)) {
|
|
300
|
-
this.pnpIndex.set(pnpId, new Set());
|
|
301
|
-
}
|
|
302
|
-
this.pnpIndex.get(pnpId).add(registration.toolId);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
255
|
this.emitChange({ kind: "override", toolIds: [registration.toolId] });
|
|
306
256
|
}
|
|
307
257
|
/**
|
|
@@ -310,15 +260,8 @@ export class ToolRegistry {
|
|
|
310
260
|
* @param toolId - Tool ID to remove
|
|
311
261
|
*/
|
|
312
262
|
unregister(toolId) {
|
|
313
|
-
|
|
314
|
-
if (!reg)
|
|
263
|
+
if (!this.tools.has(toolId))
|
|
315
264
|
return;
|
|
316
|
-
// Remove PNP index entries
|
|
317
|
-
if (reg.pnpSupportIds) {
|
|
318
|
-
for (const pnpId of reg.pnpSupportIds) {
|
|
319
|
-
this.pnpIndex.get(pnpId)?.delete(toolId);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
265
|
this.tools.delete(toolId);
|
|
323
266
|
this.emitChange({ kind: "unregister", toolIds: [toolId] });
|
|
324
267
|
}
|
|
@@ -356,15 +299,6 @@ export class ToolRegistry {
|
|
|
356
299
|
getAllTools() {
|
|
357
300
|
return Array.from(this.tools.values());
|
|
358
301
|
}
|
|
359
|
-
/**
|
|
360
|
-
* Find tool IDs that support a given PNP support ID
|
|
361
|
-
*
|
|
362
|
-
* @param pnpSupportId - PNP support ID (e.g., 'calculator')
|
|
363
|
-
* @returns Set of tool IDs that support this PNP ID
|
|
364
|
-
*/
|
|
365
|
-
getToolsByPNPSupport(pnpSupportId) {
|
|
366
|
-
return this.pnpIndex.get(pnpSupportId) || new Set();
|
|
367
|
-
}
|
|
368
302
|
/**
|
|
369
303
|
* Get tools that support a specific level
|
|
370
304
|
*
|
|
@@ -401,21 +335,18 @@ export class ToolRegistry {
|
|
|
401
335
|
tool.surfaces?.includes(surface));
|
|
402
336
|
}
|
|
403
337
|
/**
|
|
404
|
-
* Support ids
|
|
338
|
+
* Support ids, which are tool ids, of the capabilities that need authored
|
|
339
|
+
* content.
|
|
405
340
|
*
|
|
406
|
-
* What a host filters a default grant list on
|
|
407
|
-
*
|
|
408
|
-
*
|
|
341
|
+
* What a host filters a default grant list on: granting one of these
|
|
342
|
+
* wholesale grants an accommodation to learners with no documented need
|
|
343
|
+
* for it.
|
|
409
344
|
*/
|
|
410
345
|
getContentDependentSupportIds() {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
for (const supportId of tool.pnpSupportIds || [])
|
|
416
|
-
ids.add(supportId);
|
|
417
|
-
}
|
|
418
|
-
return [...ids].sort();
|
|
346
|
+
return this.getAllTools()
|
|
347
|
+
.filter((tool) => tool.requiresAuthoredContent)
|
|
348
|
+
.map((tool) => tool.toolId)
|
|
349
|
+
.sort();
|
|
419
350
|
}
|
|
420
351
|
/**
|
|
421
352
|
* Filter tool IDs by activation type.
|
|
@@ -426,7 +357,7 @@ export class ToolRegistry {
|
|
|
426
357
|
/**
|
|
427
358
|
* Filter tools by visibility in a given context
|
|
428
359
|
*
|
|
429
|
-
* Pass 2 of the
|
|
360
|
+
* Pass 2 of the three-pass model: Given a list of allowed tool IDs (from Pass 1),
|
|
430
361
|
* ask each tool if it's relevant in this context.
|
|
431
362
|
*
|
|
432
363
|
* @param allowedToolIds - Tool IDs that passed Pass 1 (orchestrator approval)
|
|
@@ -438,7 +369,11 @@ export class ToolRegistry {
|
|
|
438
369
|
for (const toolId of allowedToolIds) {
|
|
439
370
|
const tool = this.get(toolId);
|
|
440
371
|
if (!tool) {
|
|
441
|
-
|
|
372
|
+
// Toolbars filter on every render; one warning per id carries it.
|
|
373
|
+
if (!this.warnedUnregisteredAllowedTools.has(toolId)) {
|
|
374
|
+
this.warnedUnregisteredAllowedTools.add(toolId);
|
|
375
|
+
console.warn(`Tool '${toolId}' is allowed but not registered`);
|
|
376
|
+
}
|
|
442
377
|
continue;
|
|
443
378
|
}
|
|
444
379
|
// Check if tool supports this level
|
|
@@ -492,14 +427,13 @@ export class ToolRegistry {
|
|
|
492
427
|
* Get tool metadata for building UIs
|
|
493
428
|
* Useful for building PNP configuration interfaces
|
|
494
429
|
*
|
|
495
|
-
* @returns Array of tool metadata (id, name, description,
|
|
430
|
+
* @returns Array of tool metadata (id, name, description, levels, activation)
|
|
496
431
|
*/
|
|
497
432
|
getToolMetadata() {
|
|
498
433
|
return this.getAllTools().map((tool) => ({
|
|
499
434
|
toolId: tool.toolId,
|
|
500
435
|
name: tool.name,
|
|
501
436
|
description: tool.description,
|
|
502
|
-
pnpSupportIds: tool.pnpSupportIds || [],
|
|
503
437
|
supportedLevels: tool.supportedLevels,
|
|
504
438
|
activation: tool.activation || "toolbar-toggle",
|
|
505
439
|
singletonScope: tool.singletonScope || null,
|
|
@@ -508,25 +442,6 @@ export class ToolRegistry {
|
|
|
508
442
|
contentDependencyDescription: tool.requiresAuthoredContent?.description ?? null,
|
|
509
443
|
}));
|
|
510
444
|
}
|
|
511
|
-
/**
|
|
512
|
-
* Generate PNP support IDs from enabled tools
|
|
513
|
-
* Useful for creating PNP profiles
|
|
514
|
-
*
|
|
515
|
-
* @param enabledToolIds - Tool IDs to enable
|
|
516
|
-
* @returns Array of unique PNP support IDs
|
|
517
|
-
*/
|
|
518
|
-
generatePNPSupportsFromTools(enabledToolIds) {
|
|
519
|
-
const pnpSupports = new Set();
|
|
520
|
-
for (const toolId of enabledToolIds) {
|
|
521
|
-
const tool = this.get(toolId);
|
|
522
|
-
if (tool?.pnpSupportIds) {
|
|
523
|
-
for (const pnpId of tool.pnpSupportIds) {
|
|
524
|
-
pnpSupports.add(pnpId);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
return Array.from(pnpSupports);
|
|
529
|
-
}
|
|
530
445
|
/**
|
|
531
446
|
* Clear all registrations (useful for testing)
|
|
532
447
|
*/
|
|
@@ -535,7 +450,6 @@ export class ToolRegistry {
|
|
|
535
450
|
if (toolIds.length === 0)
|
|
536
451
|
return;
|
|
537
452
|
this.tools.clear();
|
|
538
|
-
this.pnpIndex.clear();
|
|
539
453
|
this.emitChange({ kind: "clear", toolIds });
|
|
540
454
|
}
|
|
541
455
|
/**
|
|
@@ -550,6 +464,8 @@ export class ToolRegistry {
|
|
|
550
464
|
/**
|
|
551
465
|
* Register lazy module loaders by toolId.
|
|
552
466
|
* Toolbars call ensureToolModuleLoaded(toolId) before instance creation.
|
|
467
|
+
* A tool whose module has loaded, or is loading, keeps its loader: its
|
|
468
|
+
* elements are already defined, so a replacement could never take effect.
|
|
553
469
|
*/
|
|
554
470
|
setToolModuleLoaders(loaders) {
|
|
555
471
|
const entries = Object.entries(loaders).filter((entry) => entry[1] !== undefined);
|
|
@@ -563,6 +479,11 @@ export class ToolRegistry {
|
|
|
563
479
|
for (const [toolId, loader] of entries) {
|
|
564
480
|
if (this.moduleLoaders.get(toolId) === loader)
|
|
565
481
|
continue;
|
|
482
|
+
if (this.loadedToolModules.has(toolId) ||
|
|
483
|
+
this.moduleLoadPromises.has(toolId)) {
|
|
484
|
+
this.warnLoaderReplacedAfterLoad(toolId);
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
566
487
|
this.moduleLoaders.set(toolId, loader);
|
|
567
488
|
changedToolIds.push(toolId);
|
|
568
489
|
}
|
|
@@ -570,6 +491,12 @@ export class ToolRegistry {
|
|
|
570
491
|
this.emitChange({ kind: "module-loaders", toolIds: changedToolIds });
|
|
571
492
|
}
|
|
572
493
|
}
|
|
494
|
+
warnLoaderReplacedAfterLoad(toolId) {
|
|
495
|
+
if (this.warnedLoaderReplacements.has(toolId))
|
|
496
|
+
return;
|
|
497
|
+
this.warnedLoaderReplacements.add(toolId);
|
|
498
|
+
console.warn(`[ToolRegistry] Ignored a new module loader for "${toolId}": its module already loaded, so the elements it defines stay in place. Register loaders before the tool first renders.`);
|
|
499
|
+
}
|
|
573
500
|
/**
|
|
574
501
|
* Ensure tool module side-effects are loaded exactly once.
|
|
575
502
|
* Safe to call repeatedly; concurrent callers share the same promise.
|
|
@@ -583,11 +510,14 @@ export class ToolRegistry {
|
|
|
583
510
|
return;
|
|
584
511
|
}
|
|
585
512
|
const loader = this.moduleLoaders.get(toolId);
|
|
586
|
-
if (!loader)
|
|
513
|
+
if (!loader) {
|
|
514
|
+
this.watchUndefinedToolElement(toolId);
|
|
587
515
|
return;
|
|
516
|
+
}
|
|
588
517
|
const loadPromise = (async () => {
|
|
589
518
|
await loader();
|
|
590
519
|
this.loadedToolModules.add(toolId);
|
|
520
|
+
this.warnIfLoadedToolElementUndefined(toolId);
|
|
591
521
|
})();
|
|
592
522
|
this.moduleLoadPromises.set(toolId, loadPromise);
|
|
593
523
|
try {
|
|
@@ -598,10 +528,70 @@ export class ToolRegistry {
|
|
|
598
528
|
}
|
|
599
529
|
}
|
|
600
530
|
/**
|
|
601
|
-
*
|
|
531
|
+
* The undefined element tag a tool would render, or `null` when the tool is
|
|
532
|
+
* built by a component factory, its element is defined, or there is no DOM.
|
|
533
|
+
*/
|
|
534
|
+
undefinedToolElementTag(toolId) {
|
|
535
|
+
if (typeof customElements === "undefined" || typeof document === "undefined") {
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
const overrides = this.componentOverrides;
|
|
539
|
+
if (overrides.toolComponentFactories?.[toolId])
|
|
540
|
+
return null;
|
|
541
|
+
let tagName;
|
|
542
|
+
try {
|
|
543
|
+
tagName = resolveToolTag(toolId, overrides);
|
|
544
|
+
}
|
|
545
|
+
catch {
|
|
546
|
+
// Element creation reports the missing tag mapping.
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
return customElements.get(tagName) ? null : tagName;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Warn when a tool's module loader finished without defining the element the
|
|
553
|
+
* tag map points the tool at, as when a host remaps the tag but keeps a
|
|
554
|
+
* loader that defines the packaged element. The tool otherwise renders blank.
|
|
555
|
+
*/
|
|
556
|
+
warnIfLoadedToolElementUndefined(toolId) {
|
|
557
|
+
const tagName = this.undefinedToolElementTag(toolId);
|
|
558
|
+
if (!tagName)
|
|
559
|
+
return;
|
|
560
|
+
warnOncePerDocument(document, `loadedToolElementUndefined.${toolId}.${tagName}`, `[ToolRegistry] Tool "${toolId}" renders <${tagName}>, but its module loader finished without defining it, so the tool renders blank. The tag map and the loader disagree: map "${toolId}" to the tag its loader defines, or register a loader that defines <${tagName}>. Reported once per page.`);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Warn when a tool with no module loader still has no element definition
|
|
564
|
+
* after the pending-input delay. A registry built without loaders otherwise
|
|
565
|
+
* renders the tool as an unknown element with no error.
|
|
566
|
+
*/
|
|
567
|
+
watchUndefinedToolElement(toolId) {
|
|
568
|
+
if (this.watchedUndefinedToolElements.has(toolId))
|
|
569
|
+
return;
|
|
570
|
+
const tagName = this.undefinedToolElementTag(toolId);
|
|
571
|
+
if (!tagName)
|
|
572
|
+
return;
|
|
573
|
+
this.watchedUndefinedToolElements.add(toolId);
|
|
574
|
+
const doc = document;
|
|
575
|
+
const timer = setTimeout(() => {
|
|
576
|
+
if (customElements.get(tagName))
|
|
577
|
+
return;
|
|
578
|
+
warnOncePerDocument(doc, `undefinedToolElement.${toolId}`, `[ToolRegistry] Tool "${toolId}" renders <${tagName}>, which is still undefined after ${PENDING_INPUT_WARNING_DELAY_MS / 1000} s, and its registry has no module loader for it. Pass toolModuleLoaders to createPackagedToolRegistry (DEFAULT_TOOL_MODULE_LOADERS from @pie-players/pie-default-tool-loaders loads the stock tools), register one with setToolModuleLoaders, or import the tool's package before it renders. Reported once per page.`);
|
|
579
|
+
}, PENDING_INPUT_WARNING_DELAY_MS);
|
|
580
|
+
void customElements.whenDefined(tagName).then(() => clearTimeout(timer));
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Load a set of tool modules, each to completion, and resolve with the error
|
|
584
|
+
* of every tool whose module failed, by tool id. One failure leaves the other
|
|
585
|
+
* tools loaded and usable. A failed tool is retried on the next call.
|
|
602
586
|
*/
|
|
603
587
|
async ensureToolModulesLoaded(toolIds) {
|
|
604
|
-
await Promise.
|
|
588
|
+
const results = await Promise.allSettled(toolIds.map((toolId) => this.ensureToolModuleLoaded(toolId)));
|
|
589
|
+
const failures = new Map();
|
|
590
|
+
results.forEach((result, index) => {
|
|
591
|
+
if (result.status === "rejected")
|
|
592
|
+
failures.set(toolIds[index], result.reason);
|
|
593
|
+
});
|
|
594
|
+
return failures;
|
|
605
595
|
}
|
|
606
596
|
/**
|
|
607
597
|
* Whether a tool module has already been loaded.
|