@pie-players/pie-assessment-toolkit 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 +469 -318
- package/dist/attempt/AssessmentSession.d.ts +1 -5
- package/dist/attempt/AssessmentSession.js +0 -29
- 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.d.ts +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
- 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 +32 -6
- package/dist/index.d.ts +23 -48
- package/dist/index.js +12 -37
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
- package/dist/policy/core/ToolPolicyEngine.js +148 -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 +14 -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 +28 -10
- package/dist/runtime/tool-host-contract.js +31 -10
- 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 +22 -28
- package/dist/services/HighlightCoordinator.js +431 -327
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +130 -69
- package/dist/services/TTSService.js +713 -570
- package/dist/services/ToolCoordinator.d.ts +43 -66
- package/dist/services/ToolCoordinator.js +164 -208
- package/dist/services/ToolRegistry.d.ts +78 -54
- package/dist/services/ToolRegistry.js +107 -105
- package/dist/services/ToolkitCoordinator.d.ts +261 -175
- package/dist/services/ToolkitCoordinator.js +667 -433
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +11 -1
- package/dist/services/catalog-owner.js +25 -0
- package/dist/services/create-tools-config.d.ts +2 -2
- 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 +30 -8
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-controller-types.d.ts +15 -0
- 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 +1 -3
- 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 +14 -4
- package/dist/services/tool-config-validation.js +63 -71
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +29 -25
- 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 +41 -80
- package/dist/services/tool-providers/TTSToolProvider.js +81 -40
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
- package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
- package/dist/services/tool-providers/index.d.ts +0 -9
- package/dist/services/tool-providers/index.js +2 -4
- 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 +37 -23
- 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/catalog-span-alignment.d.ts +2 -17
- package/dist/services/tts/catalog-span-alignment.js +17 -142
- 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/generated-speech/types.d.ts +0 -12
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
- package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
- 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-alignment/index.d.ts +0 -5
- package/dist/services/tts/math-alignment/index.js +5 -25
- package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
- package/dist/services/tts/math-alignment/types.d.ts +4 -2
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +74 -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 +16 -1
- package/dist/services/tts/math-speech.js +55 -19
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/sre-engine.d.ts +7 -0
- package/dist/services/tts/sre-engine.js +11 -0
- package/dist/services/tts/sre-locales.d.ts +14 -0
- package/dist/services/tts/sre-locales.js +57 -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 -1
- package/dist/services/tts/text-processing.js +46 -34
- 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 +44 -18
- package/dist/services/tts-runtime-config.js +22 -93
- 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 +24 -59
- 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-byq80z42.js +0 -40
- package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -51
- 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 -80
- package/dist/runtime/section-runtime-engine-host-context.js +0 -95
- 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/ToolConfigResolver.d.ts +0 -161
- package/dist/services/ToolConfigResolver.js +0 -229
- package/dist/services/catalog-media.d.ts +0 -56
- package/dist/services/catalog-media.js +0 -190
- package/dist/services/createDefaultToolRegistry.d.ts +0 -53
- package/dist/services/createDefaultToolRegistry.js +0 -45
- 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/services/tool-providers/CortexToolProvider.d.ts +0 -13
- package/dist/services/tool-providers/CortexToolProvider.js +0 -32
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
- package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
- package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
- package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
- package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
- package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
- package/dist/services/tts/visual-line-ranges.d.ts +0 -18
- package/dist/services/tts/visual-line-ranges.js +0 -226
- package/dist/tools/client.d.ts +0 -12
- package/dist/tools/client.js +0 -14
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -10
- package/dist/tools/internal.d.ts +0 -43
- package/dist/tools/internal.js +0 -41
- package/dist/tools/response-discovery.d.ts +0 -61
- package/dist/tools/response-discovery.js +0 -113
- package/dist/tools/types.d.ts +0 -337
- package/dist/tools/types.js +0 -12
- package/dist/tools/variant-resolver.d.ts +0 -41
- package/dist/tools/variant-resolver.js +0 -207
package/dist/index.js
CHANGED
|
@@ -6,55 +6,30 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
|
-
export { assessmentToolkitHostRuntimeContext, assessmentToolkitRegionScopeContext, assessmentToolkitRuntimeContext, assessmentToolkitShellContext, } from "./context/assessment-toolkit-context.js";
|
|
10
|
-
export { connectAssessmentToolkitHostRuntimeContext, connectAssessmentToolkitRegionScopeContext, connectAssessmentToolkitRuntimeContext, connectAssessmentToolkitShellContext, } from "./context/runtime-context-consumer.js";
|
|
11
9
|
export { catalogOwnerContextFor, } from "./services/catalog-owner.js";
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
export {
|
|
10
|
+
export { PIE_INTERNAL_FORMATIVE_ACTION_EVENT, PIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT, PIE_INTERNAL_MEDIA_TIME_SOURCE_EVENT, PIE_ITEM_SESSION_CHANGED_EVENT, } from "./runtime/registration-events.js";
|
|
11
|
+
export { createShellScope, } from "./runtime/shell-scope.js";
|
|
12
|
+
// A shell's translation of its player's events into the runtime's, shared by the
|
|
13
|
+
// section player's passage shell and `<pie-item-scope>`.
|
|
14
|
+
export { createShellEventBridge, } from "./runtime/shell-event-bridge.js";
|
|
15
|
+
export { connectToolRuntimeContext, dispatchCrossBoundaryEvent, } from "./runtime/tool-host-contract.js";
|
|
16
|
+
export { AccessibilityCatalogResolver } from "./services/AccessibilityCatalogResolver.js";
|
|
17
17
|
// Element Tool State Store (Element-level ephemeral tool state)
|
|
18
18
|
export { ElementToolStateStore } from "./services/ElementToolStateStore.js";
|
|
19
19
|
export { HighlightColor, HighlightCoordinator, HighlightType, } from "./services/HighlightCoordinator.js";
|
|
20
|
-
export { RangeSerializer } from "./services/RangeSerializer.js";
|
|
21
|
-
export { I18nService } from "./services/I18nService.js";
|
|
22
20
|
export { ToolRegistry } from "./services/ToolRegistry.js";
|
|
23
|
-
export {
|
|
24
|
-
export { extractTextContent, hasChoiceInteraction, hasMathContent, hasReadableText, isAssessmentContext, isElementContext, isItemContext, isPassageContext, isRubricContext, isSectionContext, } from "./services/tool-context.js";
|
|
25
|
-
export { DEFAULT_TOOL_PLACEMENT } from "./services/createDefaultToolRegistry.js";
|
|
21
|
+
export { hasReadableText } from "./services/tool-context.js";
|
|
26
22
|
export { createToolsConfig } from "./services/create-tools-config.js";
|
|
27
|
-
export { createEmptyPersonalNeedsProfile } from "./services/defaultPersonalNeedsProfile.js";
|
|
28
|
-
export { createToolElement, resolveToolTag, toToolIdFromTag, } from "./tools/tool-tag-map.js";
|
|
29
|
-
// QTI 3.0 Standard Access Features
|
|
30
|
-
export { ALL_STANDARD_ACCESS_FEATURES, EXAMPLE_PNP_CONFIGURATIONS, getFeatureCategory, getFeaturesInCategory, isStandardAccessFeature, QTI_STANDARD_ACCESS_FEATURES, } from "./services/pnp-standard-features.js";
|
|
31
|
-
// Media-bearing catalog cards: the generic half, shared by every card form that
|
|
32
|
-
// references a recording rather than carrying text. `applyMediaFragment` reached
|
|
33
|
-
// the public surface through `sign-language-cards.js` until signing moved to
|
|
34
|
-
// `@pie-players/pie-tool-sign-language`; it is exported from its own module now,
|
|
35
|
-
// alongside the validators a capability package needs to read a media payload.
|
|
36
|
-
export { applyMediaFragment, enforceMediaFragment, isSafeMediaSrc, isUnsupportedMediaAssetVersion, normalizeMediaFragment, normalizeMediaSources, SUPPORTED_MEDIA_ASSET_VERSION, trimmedOrUndefined, } from "./services/catalog-media.js";
|
|
37
|
-
export { resolveSpokenAudioMedia, SPOKEN_CATALOG_TYPE, } from "./services/spoken-audio-cards.js";
|
|
38
23
|
export { SSMLExtractor } from "./services/SSMLExtractor.js";
|
|
39
|
-
export { ThemeProvider } from "./services/ThemeProvider.js";
|
|
40
24
|
// Tool Coordinator
|
|
41
25
|
export { ToolCoordinator, ZIndexLayer } from "./services/ToolCoordinator.js";
|
|
42
26
|
export { ToolkitCoordinator } from "./services/ToolkitCoordinator.js";
|
|
43
|
-
export {
|
|
44
|
-
export {
|
|
45
|
-
export { normalizeToolsConfig, normalizeToolAlias, normalizeToolList, parseToolList, } from "./services/tools-config-normalizer.js";
|
|
46
|
-
export { isHostDeniedFeature } from "./policy/core/feature-decision.js";
|
|
47
|
-
export { frameworkErrorFromToolConfigValidation, normalizeAndValidateToolsConfig, } from "./services/tool-config-validation.js";
|
|
48
|
-
export { createScopedToolId, parseScopedToolId, toOverlayToolId, } from "./services/tool-instance-id.js";
|
|
27
|
+
export { frameworkErrorFromUnknown, toFrameworkErrorModel, } from "./services/framework-error.js";
|
|
28
|
+
export { createScopedToolId } from "./services/tool-instance-id.js";
|
|
49
29
|
export { PlaybackState, TTSService } from "./services/TTSService.js";
|
|
50
|
-
export { PIE_TTS_CONTROL_HANDOFF_EVENT, } from "./services/tts-control-events.js";
|
|
51
|
-
export { bindTtsAudioHandoff, pauseTtsForMediaAudio, } from "./services/audio-handoff.js";
|
|
52
30
|
export { BrowserTTSProvider } from "./services/tts/browser-provider.js";
|
|
53
|
-
export {
|
|
54
|
-
export {
|
|
55
|
-
export { createMemoryStorage, createTestAttemptSessionIdentifier, createNewTestAttemptSession, getBrowserLocalStorage, getOrCreateAnonymousDeviceId, getTestAttemptSessionStorageKey, loadTestAttemptSession, saveTestAttemptSession, setCurrentPosition, upsertItemSessionFromPieSessionChange, upsertVisitedItem, } from "./attempt/TestSession.js";
|
|
56
|
-
export { createNewAssessmentSession, getAssessmentSessionStorageKey, loadAssessmentSession, saveAssessmentSession, setCurrentSectionPosition, upsertSectionSession, } from "./attempt/AssessmentSession.js";
|
|
57
|
-
export { buildActivitySessionItemUpdate, buildActivitySessionPatchFromTestAttemptSession, mapActivityToTestAttemptSession, toItemSessionsRecord, } from "./attempt/adapters/activity-to-test-attempt-session.js";
|
|
31
|
+
export { createNewTestAttemptSession, setCurrentPosition, toItemSessionsRecord, upsertItemSessionFromPieSessionChange, upsertVisitedItem, } from "./attempt/TestSession.js";
|
|
32
|
+
export { createNewAssessmentSession, setCurrentSectionPosition, upsertSectionSession, } from "./attempt/AssessmentSession.js";
|
|
58
33
|
// Section Player - Use @pie-players/pie-section-player web component
|
|
59
34
|
// ============================================================================
|
|
60
35
|
// Shared Components
|
|
@@ -57,7 +57,7 @@ export interface PolicySourceResult {
|
|
|
57
57
|
decisions?: PolicySourceProvenanceEntry[];
|
|
58
58
|
}
|
|
59
59
|
export interface PolicySource {
|
|
60
|
-
/** Stable identifier
|
|
60
|
+
/** Stable identifier, recorded as `customSourceId` on the decisions and diagnostics it causes. */
|
|
61
61
|
readonly id: string;
|
|
62
62
|
refine(context: PolicySourceDecisionContext): PolicySourceResult;
|
|
63
63
|
}
|
|
@@ -3,43 +3,40 @@
|
|
|
3
3
|
* `docs/tools-and-accomodations/architecture.md`.
|
|
4
4
|
*
|
|
5
5
|
* Wraps `composeDecision(...)` with engine-instance state:
|
|
6
|
-
* - bound inputs (`tools`, `assessment`, `
|
|
6
|
+
* - bound inputs (`tools`, `assessment`, `pnpEnforcement`) and the
|
|
7
|
+
* settings of the mounted items
|
|
7
8
|
* - registered custom `PolicySource`s
|
|
8
9
|
* - `onPolicyChange` subscriber bus
|
|
9
10
|
* - `dispose()` clean-up
|
|
10
11
|
*
|
|
11
12
|
* The class has no DOM dependency and no Svelte runes. It is safe to
|
|
12
13
|
* instantiate inside a worker, in a Node test, or inside a CE
|
|
13
|
-
* connectedCallback.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* PR 1 ships the engine *without callers*. PR 2 wires it into
|
|
17
|
-
* `ToolkitCoordinator`. PR 3 switches `<pie-item-toolbar>` over.
|
|
14
|
+
* connectedCallback. `ToolkitCoordinator` owns the instance, and
|
|
15
|
+
* `<pie-item-toolbar>` reads its decisions through the coordinator.
|
|
18
16
|
*/
|
|
19
|
-
import type { AssessmentEntity,
|
|
17
|
+
import type { AssessmentEntity, ItemSettings } from "@pie-players/pie-players-shared/types";
|
|
20
18
|
import type { CanonicalToolsConfig, ToolPlacementLevel } from "../../services/tools-config-normalizer.js";
|
|
21
19
|
import type { ToolRegistry } from "../../services/ToolRegistry.js";
|
|
22
|
-
import type { ToolPolicyDecision, ToolPolicyDecisionRequest } from "./decision-types.js";
|
|
20
|
+
import type { ToolPolicyDecision, ToolPolicyDecisionRequest, ToolScope } from "./decision-types.js";
|
|
23
21
|
import type { PolicySource } from "./PolicySource.js";
|
|
24
22
|
import type { FeaturePolicyDecision } from "./feature-decision.js";
|
|
25
23
|
export type PnpEnforcementMode = "on" | "off";
|
|
26
24
|
export interface ToolPolicyEngineInputs {
|
|
27
25
|
tools?: CanonicalToolsConfig | null;
|
|
28
26
|
assessment?: AssessmentEntity | null;
|
|
29
|
-
currentItemRef?: AssessmentItemRef | null;
|
|
30
27
|
/**
|
|
31
|
-
* Explicit PNP/profile override
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
28
|
+
* Explicit PNP/profile override; `null` or omitted is auto-mode. Auto-mode
|
|
29
|
+
* resolves per decision through {@link resolveDefaultPnpEnforcement}: `"on"`
|
|
30
|
+
* when the bound `assessment` carries PNP/profile policy material (PNP,
|
|
31
|
+
* district policy, test administration), and for a decision scoped to an item
|
|
32
|
+
* also when that item's settings carry required/restricted/parameters;
|
|
36
33
|
* `"off"` otherwise. `tests/policy/pnp-default-on.test.ts` locks the rule.
|
|
37
34
|
*
|
|
38
35
|
* Hosts that want to force a mode pass `"on"` or `"off"`
|
|
39
36
|
* explicitly. Embedded under `<pie-section-player-*>` the preferred
|
|
40
37
|
* override flows through `runtime.tools.pnpEnforcement`.
|
|
41
38
|
*/
|
|
42
|
-
pnpEnforcement?: PnpEnforcementMode;
|
|
39
|
+
pnpEnforcement?: PnpEnforcementMode | null;
|
|
43
40
|
}
|
|
44
41
|
export interface ToolPolicyEngineArgs {
|
|
45
42
|
toolRegistry: ToolRegistry;
|
|
@@ -49,28 +46,41 @@ export interface ToolPolicyEngineArgs {
|
|
|
49
46
|
contextId?: string;
|
|
50
47
|
}
|
|
51
48
|
export interface ToolPolicyChangeEvent {
|
|
52
|
-
/**
|
|
53
|
-
|
|
49
|
+
/**
|
|
50
|
+
* What changed in this update. `"item-settings"` is a mounted item's
|
|
51
|
+
* settings changing: it can change which tools that item's own toolbar
|
|
52
|
+
* shows, and nothing else a toolbar renders.
|
|
53
|
+
*/
|
|
54
|
+
reason: "inputs" | "item-settings" | "policy-source-added" | "policy-source-removed" | "pnp-enforcement" | "disposed";
|
|
54
55
|
/** Snapshot of the engine's inputs after the change. */
|
|
55
56
|
inputs: Readonly<ResolvedEngineInputs>;
|
|
56
57
|
}
|
|
57
58
|
export interface ResolvedEngineInputs {
|
|
58
59
|
tools: CanonicalToolsConfig;
|
|
59
60
|
assessment: AssessmentEntity | null;
|
|
60
|
-
|
|
61
|
+
/**
|
|
62
|
+
* The mode a decision not scoped to an item applies. In auto-mode an
|
|
63
|
+
* item-scoped decision also turns on for its item's settings.
|
|
64
|
+
*/
|
|
61
65
|
pnpEnforcement: PnpEnforcementMode;
|
|
66
|
+
/** The host's override of auto-mode, or `null` in auto-mode. */
|
|
67
|
+
pnpEnforcementOverride: PnpEnforcementMode | null;
|
|
62
68
|
}
|
|
63
69
|
export type ToolPolicyChangeListener = (event: ToolPolicyChangeEvent) => void;
|
|
64
70
|
export declare class ToolPolicyEngine {
|
|
65
|
-
private
|
|
71
|
+
private toolRegistry;
|
|
66
72
|
private readonly contextId;
|
|
67
|
-
private
|
|
73
|
+
private pnpPolicySource;
|
|
68
74
|
private readonly customSources;
|
|
69
75
|
private readonly listeners;
|
|
70
76
|
private tools;
|
|
71
77
|
private assessment;
|
|
72
|
-
private
|
|
73
|
-
|
|
78
|
+
private pnpEnforcementOverride;
|
|
79
|
+
/**
|
|
80
|
+
* Mounted items' settings by canonical item id, newest registration last;
|
|
81
|
+
* see {@link registerItemSettings}.
|
|
82
|
+
*/
|
|
83
|
+
private readonly itemSettings;
|
|
74
84
|
private disposed;
|
|
75
85
|
constructor(args: ToolPolicyEngineArgs);
|
|
76
86
|
/**
|
|
@@ -87,10 +97,33 @@ export declare class ToolPolicyEngine {
|
|
|
87
97
|
* values even though the policy decision itself is identical.
|
|
88
98
|
* Hosts that want timestamp-stable provenance should reuse a
|
|
89
99
|
* cached `ToolPolicyDecision` rather than re-call `decide(...)`.
|
|
100
|
+
*
|
|
101
|
+
* An item's registered settings apply to the item's own toolbar: a request
|
|
102
|
+
* at item level whose scope is the item. Every other request — a section,
|
|
103
|
+
* assessment or passage toolbar — is shared by the items it sits beside, so
|
|
104
|
+
* it leaves every item's settings out and reports each tool on its toolbar
|
|
105
|
+
* that one restricts or requires as `tool-policy.itemSettingNotApplied`.
|
|
90
106
|
*/
|
|
91
107
|
decide(request: ToolPolicyDecisionRequest): ToolPolicyDecision;
|
|
92
108
|
/**
|
|
93
|
-
*
|
|
109
|
+
* Whether some surface is granted `featureId`: a decision with no item scope,
|
|
110
|
+
* or one scoped to a registered item. A provider serves every surface, so its
|
|
111
|
+
* failure denies the accommodation wherever one surface is granted it.
|
|
112
|
+
*/
|
|
113
|
+
grantsFeatureAnywhere(featureId: string): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* File a mounted item's settings under its canonical id. They govern the
|
|
116
|
+
* decisions scoped to that item: its own toolbar, and a feature its content
|
|
117
|
+
* asks about with the item's scope. See {@link decide}.
|
|
118
|
+
*
|
|
119
|
+
* The same item mounted twice registers twice; the newest registration
|
|
120
|
+
* applies, and its cleanup hands the item back to the one before. Emits an
|
|
121
|
+
* `"item-settings"` change whenever the settings that apply to the item
|
|
122
|
+
* change.
|
|
123
|
+
*/
|
|
124
|
+
registerItemSettings(itemId: string, settings: ItemSettings): () => void;
|
|
125
|
+
/**
|
|
126
|
+
* Resolve eligibility for one PNP/AfA feature id through the eight-level
|
|
94
127
|
* precedence, independent of toolbar placement.
|
|
95
128
|
*
|
|
96
129
|
* For capabilities that render as their own surface rather than a toolbar
|
|
@@ -111,8 +144,11 @@ export declare class ToolPolicyEngine {
|
|
|
111
144
|
* The decision reports whether an assessment was bound, which is the engine's
|
|
112
145
|
* to answer rather than the policy source's — see
|
|
113
146
|
* {@link FeaturePolicyDecision.assessmentBound}.
|
|
147
|
+
*
|
|
148
|
+
* `scope` is the surface asking. An item's scope brings in the item's
|
|
149
|
+
* registered settings, as {@link decide} does for the item's toolbar.
|
|
114
150
|
*/
|
|
115
|
-
decideFeature(featureId: string): FeaturePolicyDecision;
|
|
151
|
+
decideFeature(featureId: string, scope?: ToolScope): FeaturePolicyDecision;
|
|
116
152
|
/**
|
|
117
153
|
* The host gates that hold for a feature id, or `null` when none fires.
|
|
118
154
|
*
|
|
@@ -133,24 +169,39 @@ export declare class ToolPolicyEngine {
|
|
|
133
169
|
/**
|
|
134
170
|
* Apply a partial input update.
|
|
135
171
|
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* `PieAssessmentToolkit.svelte`'s prop-forwarding effect and by the
|
|
141
|
-
* coordinator's `decideToolPolicy()` tests.
|
|
172
|
+
* A key that did not change does not fire `onPolicyChange` listeners.
|
|
173
|
+
* `tools` is diffed with `Object.is`. `assessment` is diffed structurally,
|
|
174
|
+
* because hosts rebuild it from their own state on every render; the latest
|
|
175
|
+
* reference is stored either way.
|
|
142
176
|
*
|
|
143
|
-
* `pnpEnforcement`
|
|
144
|
-
* a distinct `"pnp-enforcement"` reason when no
|
|
145
|
-
*
|
|
146
|
-
* event channel.
|
|
177
|
+
* `pnpEnforcement` sets the override, `null` or `undefined` returning to
|
|
178
|
+
* auto-mode, and emits with a distinct `"pnp-enforcement"` reason when no
|
|
179
|
+
* other key changed.
|
|
147
180
|
*/
|
|
148
181
|
updateInputs(patch: Partial<ToolPolicyEngineInputs>): void;
|
|
182
|
+
/**
|
|
183
|
+
* Swap the registry PNP support ids resolve against, together with the tools
|
|
184
|
+
* config validated against it, and emit an `"inputs"` change. For a
|
|
185
|
+
* coordinator adopting its toolkit's registry.
|
|
186
|
+
*/
|
|
187
|
+
replaceToolRegistry(toolRegistry: ToolRegistry, tools: CanonicalToolsConfig): void;
|
|
149
188
|
registerPolicySource(source: PolicySource): () => void;
|
|
150
189
|
onPolicyChange(listener: ToolPolicyChangeListener): () => void;
|
|
151
190
|
getInputs(): Readonly<ResolvedEngineInputs>;
|
|
152
191
|
dispose(): void;
|
|
153
192
|
private snapshotInputs;
|
|
193
|
+
/** The override, else auto-mode over the assessment and `item`'s settings. */
|
|
194
|
+
private enforcementFor;
|
|
195
|
+
/** The settings that apply to `itemId`: its newest registration's. */
|
|
196
|
+
private itemSettingsFor;
|
|
197
|
+
private emitIfItemSettingsChanged;
|
|
198
|
+
/**
|
|
199
|
+
* The registered item an item scope names, by its canonical id. A scope
|
|
200
|
+
* of any other level names none.
|
|
201
|
+
*/
|
|
202
|
+
private itemForScope;
|
|
203
|
+
/** The registered items whose settings their own toolbar enforces. */
|
|
204
|
+
private enforcedItems;
|
|
154
205
|
private emit;
|
|
155
206
|
private assertNotDisposed;
|
|
156
207
|
}
|
|
@@ -3,24 +3,23 @@
|
|
|
3
3
|
* `docs/tools-and-accomodations/architecture.md`.
|
|
4
4
|
*
|
|
5
5
|
* Wraps `composeDecision(...)` with engine-instance state:
|
|
6
|
-
* - bound inputs (`tools`, `assessment`, `
|
|
6
|
+
* - bound inputs (`tools`, `assessment`, `pnpEnforcement`) and the
|
|
7
|
+
* settings of the mounted items
|
|
7
8
|
* - registered custom `PolicySource`s
|
|
8
9
|
* - `onPolicyChange` subscriber bus
|
|
9
10
|
* - `dispose()` clean-up
|
|
10
11
|
*
|
|
11
12
|
* The class has no DOM dependency and no Svelte runes. It is safe to
|
|
12
13
|
* instantiate inside a worker, in a Node test, or inside a CE
|
|
13
|
-
* connectedCallback.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* PR 1 ships the engine *without callers*. PR 2 wires it into
|
|
17
|
-
* `ToolkitCoordinator`. PR 3 switches `<pie-item-toolbar>` over.
|
|
14
|
+
* connectedCallback. `ToolkitCoordinator` owns the instance, and
|
|
15
|
+
* `<pie-item-toolbar>` reads its decisions through the coordinator.
|
|
18
16
|
*/
|
|
19
17
|
import { normalizeToolList, normalizeToolsConfig, } from "../../services/tools-config-normalizer.js";
|
|
20
18
|
import { hostFeatureDenial, interpretFeatureResult, } from "./feature-decision.js";
|
|
21
19
|
import { composeDecision } from "./compose-decision.js";
|
|
22
20
|
import { resolveDefaultPnpEnforcement } from "./pnp-policy-inputs.js";
|
|
23
|
-
import {
|
|
21
|
+
import { structurallyEqual } from "../../utils/structural-equality.js";
|
|
22
|
+
import { PnpPolicySource, } from "../sources/PnpPolicySource.js";
|
|
24
23
|
const DEFAULT_TOOLS = normalizeToolsConfig({
|
|
25
24
|
policy: { allowed: [], blocked: [] },
|
|
26
25
|
placement: { section: [], item: [], passage: [] },
|
|
@@ -34,8 +33,12 @@ export class ToolPolicyEngine {
|
|
|
34
33
|
listeners = new Set();
|
|
35
34
|
tools;
|
|
36
35
|
assessment;
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
pnpEnforcementOverride;
|
|
37
|
+
/**
|
|
38
|
+
* Mounted items' settings by canonical item id, newest registration last;
|
|
39
|
+
* see {@link registerItemSettings}.
|
|
40
|
+
*/
|
|
41
|
+
itemSettings = new Map();
|
|
39
42
|
disposed = false;
|
|
40
43
|
constructor(args) {
|
|
41
44
|
this.toolRegistry = args.toolRegistry;
|
|
@@ -45,13 +48,7 @@ export class ToolPolicyEngine {
|
|
|
45
48
|
const inputs = args.inputs ?? {};
|
|
46
49
|
this.tools = inputs.tools ?? DEFAULT_TOOLS;
|
|
47
50
|
this.assessment = inputs.assessment ?? null;
|
|
48
|
-
this.
|
|
49
|
-
this.pnpEnforcement =
|
|
50
|
-
inputs.pnpEnforcement ??
|
|
51
|
-
resolveDefaultPnpEnforcement({
|
|
52
|
-
assessment: this.assessment,
|
|
53
|
-
currentItemRef: this.currentItemRef,
|
|
54
|
-
});
|
|
51
|
+
this.pnpEnforcementOverride = inputs.pnpEnforcement ?? null;
|
|
55
52
|
}
|
|
56
53
|
/**
|
|
57
54
|
* Resolve the visible tool set for a given placement level and
|
|
@@ -67,27 +64,85 @@ export class ToolPolicyEngine {
|
|
|
67
64
|
* values even though the policy decision itself is identical.
|
|
68
65
|
* Hosts that want timestamp-stable provenance should reuse a
|
|
69
66
|
* cached `ToolPolicyDecision` rather than re-call `decide(...)`.
|
|
67
|
+
*
|
|
68
|
+
* An item's registered settings apply to the item's own toolbar: a request
|
|
69
|
+
* at item level whose scope is the item. Every other request — a section,
|
|
70
|
+
* assessment or passage toolbar — is shared by the items it sits beside, so
|
|
71
|
+
* it leaves every item's settings out and reports each tool on its toolbar
|
|
72
|
+
* that one restricts or requires as `tool-policy.itemSettingNotApplied`.
|
|
70
73
|
*/
|
|
71
74
|
decide(request) {
|
|
72
75
|
this.assertNotDisposed();
|
|
73
76
|
const requestContextId = request.scope.scopeId
|
|
74
77
|
? `${this.contextId}:${request.level}:${request.scope.scopeId}`
|
|
75
78
|
: `${this.contextId}:${request.level}`;
|
|
79
|
+
const item = request.level === "item" ? this.itemForScope(request.scope) : undefined;
|
|
80
|
+
const shared = request.level !== "item" ||
|
|
81
|
+
request.scope.level === "section" ||
|
|
82
|
+
request.scope.level === "assessment";
|
|
76
83
|
return composeDecision({
|
|
77
84
|
request,
|
|
78
85
|
tools: this.tools,
|
|
79
86
|
pnpPolicy: {
|
|
80
87
|
source: this.pnpPolicySource,
|
|
81
88
|
assessment: this.assessment ?? undefined,
|
|
82
|
-
|
|
83
|
-
enforcement: this.
|
|
89
|
+
item,
|
|
90
|
+
enforcement: this.enforcementFor(item),
|
|
84
91
|
},
|
|
92
|
+
unappliedItems: shared ? this.enforcedItems() : undefined,
|
|
85
93
|
customSources: this.customSources,
|
|
86
94
|
contextId: requestContextId,
|
|
87
95
|
});
|
|
88
96
|
}
|
|
89
97
|
/**
|
|
90
|
-
*
|
|
98
|
+
* Whether some surface is granted `featureId`: a decision with no item scope,
|
|
99
|
+
* or one scoped to a registered item. A provider serves every surface, so its
|
|
100
|
+
* failure denies the accommodation wherever one surface is granted it.
|
|
101
|
+
*/
|
|
102
|
+
grantsFeatureAnywhere(featureId) {
|
|
103
|
+
if (this.decideFeature(featureId).granted)
|
|
104
|
+
return true;
|
|
105
|
+
for (const id of this.itemSettings.keys()) {
|
|
106
|
+
if (this.decideFeature(featureId, { level: "item", scopeId: id }).granted) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* File a mounted item's settings under its canonical id. They govern the
|
|
114
|
+
* decisions scoped to that item: its own toolbar, and a feature its content
|
|
115
|
+
* asks about with the item's scope. See {@link decide}.
|
|
116
|
+
*
|
|
117
|
+
* The same item mounted twice registers twice; the newest registration
|
|
118
|
+
* applies, and its cleanup hands the item back to the one before. Emits an
|
|
119
|
+
* `"item-settings"` change whenever the settings that apply to the item
|
|
120
|
+
* change.
|
|
121
|
+
*/
|
|
122
|
+
registerItemSettings(itemId, settings) {
|
|
123
|
+
this.assertNotDisposed();
|
|
124
|
+
const entry = { settings };
|
|
125
|
+
const before = this.itemSettingsFor(itemId);
|
|
126
|
+
const entries = this.itemSettings.get(itemId) ?? [];
|
|
127
|
+
entries.push(entry);
|
|
128
|
+
this.itemSettings.set(itemId, entries);
|
|
129
|
+
this.emitIfItemSettingsChanged(itemId, before);
|
|
130
|
+
return () => {
|
|
131
|
+
if (this.disposed)
|
|
132
|
+
return;
|
|
133
|
+
const current = this.itemSettings.get(itemId);
|
|
134
|
+
const index = current?.indexOf(entry) ?? -1;
|
|
135
|
+
if (!current || index < 0)
|
|
136
|
+
return;
|
|
137
|
+
const previous = this.itemSettingsFor(itemId);
|
|
138
|
+
current.splice(index, 1);
|
|
139
|
+
if (current.length === 0)
|
|
140
|
+
this.itemSettings.delete(itemId);
|
|
141
|
+
this.emitIfItemSettingsChanged(itemId, previous);
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Resolve eligibility for one PNP/AfA feature id through the eight-level
|
|
91
146
|
* precedence, independent of toolbar placement.
|
|
92
147
|
*
|
|
93
148
|
* For capabilities that render as their own surface rather than a toolbar
|
|
@@ -108,15 +163,18 @@ export class ToolPolicyEngine {
|
|
|
108
163
|
* The decision reports whether an assessment was bound, which is the engine's
|
|
109
164
|
* to answer rather than the policy source's — see
|
|
110
165
|
* {@link FeaturePolicyDecision.assessmentBound}.
|
|
166
|
+
*
|
|
167
|
+
* `scope` is the surface asking. An item's scope brings in the item's
|
|
168
|
+
* registered settings, as {@link decide} does for the item's toolbar.
|
|
111
169
|
*/
|
|
112
|
-
decideFeature(featureId) {
|
|
170
|
+
decideFeature(featureId, scope) {
|
|
113
171
|
this.assertNotDisposed();
|
|
114
172
|
const hostDenial = this.hostFeatureGate(featureId);
|
|
115
173
|
if (hostDenial)
|
|
116
174
|
return hostDenial;
|
|
117
175
|
return interpretFeatureResult(featureId, this.pnpPolicySource.resolveFeature(featureId, {
|
|
118
176
|
assessment: this.assessment ?? undefined,
|
|
119
|
-
|
|
177
|
+
item: this.itemForScope(scope),
|
|
120
178
|
}),
|
|
121
179
|
// `resolveFeature` takes the assessment as `undefined` either way, so the
|
|
122
180
|
// source cannot tell an unbound host from one whose profile is silent.
|
|
@@ -159,17 +217,14 @@ export class ToolPolicyEngine {
|
|
|
159
217
|
/**
|
|
160
218
|
* Apply a partial input update.
|
|
161
219
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* `PieAssessmentToolkit.svelte`'s prop-forwarding effect and by the
|
|
167
|
-
* coordinator's `decideToolPolicy()` tests.
|
|
220
|
+
* A key that did not change does not fire `onPolicyChange` listeners.
|
|
221
|
+
* `tools` is diffed with `Object.is`. `assessment` is diffed structurally,
|
|
222
|
+
* because hosts rebuild it from their own state on every render; the latest
|
|
223
|
+
* reference is stored either way.
|
|
168
224
|
*
|
|
169
|
-
* `pnpEnforcement`
|
|
170
|
-
* a distinct `"pnp-enforcement"` reason when no
|
|
171
|
-
*
|
|
172
|
-
* event channel.
|
|
225
|
+
* `pnpEnforcement` sets the override, `null` or `undefined` returning to
|
|
226
|
+
* auto-mode, and emits with a distinct `"pnp-enforcement"` reason when no
|
|
227
|
+
* other key changed.
|
|
173
228
|
*/
|
|
174
229
|
updateInputs(patch) {
|
|
175
230
|
this.assertNotDisposed();
|
|
@@ -184,21 +239,14 @@ export class ToolPolicyEngine {
|
|
|
184
239
|
}
|
|
185
240
|
if ("assessment" in patch) {
|
|
186
241
|
const next = patch.assessment ?? null;
|
|
187
|
-
if (!
|
|
188
|
-
this.assessment = next;
|
|
242
|
+
if (!structurallyEqual(this.assessment, next))
|
|
189
243
|
changed = true;
|
|
190
|
-
|
|
244
|
+
this.assessment = next;
|
|
191
245
|
}
|
|
192
|
-
if ("
|
|
193
|
-
const next = patch.
|
|
194
|
-
if (
|
|
195
|
-
this.
|
|
196
|
-
changed = true;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
if ("pnpEnforcement" in patch && patch.pnpEnforcement) {
|
|
200
|
-
if (this.pnpEnforcement !== patch.pnpEnforcement) {
|
|
201
|
-
this.pnpEnforcement = patch.pnpEnforcement;
|
|
246
|
+
if ("pnpEnforcement" in patch) {
|
|
247
|
+
const next = patch.pnpEnforcement ?? null;
|
|
248
|
+
if (this.pnpEnforcementOverride !== next) {
|
|
249
|
+
this.pnpEnforcementOverride = next;
|
|
202
250
|
pnpChanged = true;
|
|
203
251
|
}
|
|
204
252
|
}
|
|
@@ -209,6 +257,18 @@ export class ToolPolicyEngine {
|
|
|
209
257
|
});
|
|
210
258
|
}
|
|
211
259
|
}
|
|
260
|
+
/**
|
|
261
|
+
* Swap the registry PNP support ids resolve against, together with the tools
|
|
262
|
+
* config validated against it, and emit an `"inputs"` change. For a
|
|
263
|
+
* coordinator adopting its toolkit's registry.
|
|
264
|
+
*/
|
|
265
|
+
replaceToolRegistry(toolRegistry, tools) {
|
|
266
|
+
this.assertNotDisposed();
|
|
267
|
+
this.toolRegistry = toolRegistry;
|
|
268
|
+
this.pnpPolicySource = new PnpPolicySource(toolRegistry);
|
|
269
|
+
this.tools = tools;
|
|
270
|
+
this.emit({ reason: "inputs", inputs: this.snapshotInputs() });
|
|
271
|
+
}
|
|
212
272
|
registerPolicySource(source) {
|
|
213
273
|
this.assertNotDisposed();
|
|
214
274
|
this.customSources.push(source);
|
|
@@ -247,16 +307,58 @@ export class ToolPolicyEngine {
|
|
|
247
307
|
inputs: this.snapshotInputs(),
|
|
248
308
|
});
|
|
249
309
|
this.listeners.clear();
|
|
310
|
+
this.itemSettings.clear();
|
|
250
311
|
this.customSources.length = 0;
|
|
251
312
|
}
|
|
252
313
|
snapshotInputs() {
|
|
253
314
|
return Object.freeze({
|
|
254
315
|
tools: this.tools,
|
|
255
316
|
assessment: this.assessment,
|
|
256
|
-
|
|
257
|
-
|
|
317
|
+
pnpEnforcement: this.enforcementFor(),
|
|
318
|
+
pnpEnforcementOverride: this.pnpEnforcementOverride,
|
|
258
319
|
});
|
|
259
320
|
}
|
|
321
|
+
/** The override, else auto-mode over the assessment and `item`'s settings. */
|
|
322
|
+
enforcementFor(item) {
|
|
323
|
+
return (this.pnpEnforcementOverride ??
|
|
324
|
+
resolveDefaultPnpEnforcement({
|
|
325
|
+
assessment: this.assessment,
|
|
326
|
+
itemSettings: item?.settings,
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
/** The settings that apply to `itemId`: its newest registration's. */
|
|
330
|
+
itemSettingsFor(itemId) {
|
|
331
|
+
return this.itemSettings.get(itemId)?.at(-1)?.settings;
|
|
332
|
+
}
|
|
333
|
+
emitIfItemSettingsChanged(itemId, before) {
|
|
334
|
+
if (structurallyEqual(before, this.itemSettingsFor(itemId)))
|
|
335
|
+
return;
|
|
336
|
+
this.emit({ reason: "item-settings", inputs: this.snapshotInputs() });
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* The registered item an item scope names, by its canonical id. A scope
|
|
340
|
+
* of any other level names none.
|
|
341
|
+
*/
|
|
342
|
+
itemForScope(scope) {
|
|
343
|
+
if (scope?.level !== "item")
|
|
344
|
+
return undefined;
|
|
345
|
+
const id = scope.canonicalItemId || scope.itemId || scope.scopeId;
|
|
346
|
+
const settings = id ? this.itemSettingsFor(id) : undefined;
|
|
347
|
+
return settings ? { id, settings } : undefined;
|
|
348
|
+
}
|
|
349
|
+
/** The registered items whose settings their own toolbar enforces. */
|
|
350
|
+
enforcedItems() {
|
|
351
|
+
const items = [];
|
|
352
|
+
for (const id of this.itemSettings.keys()) {
|
|
353
|
+
const settings = this.itemSettingsFor(id);
|
|
354
|
+
if (!settings)
|
|
355
|
+
continue;
|
|
356
|
+
const item = { id, settings };
|
|
357
|
+
if (this.enforcementFor(item) === "on")
|
|
358
|
+
items.push(item);
|
|
359
|
+
}
|
|
360
|
+
return items;
|
|
361
|
+
}
|
|
260
362
|
emit(event) {
|
|
261
363
|
for (const listener of Array.from(this.listeners)) {
|
|
262
364
|
try {
|
|
@@ -11,27 +11,48 @@
|
|
|
11
11
|
* The tests in
|
|
12
12
|
* `tests/policy/compose-decision.test.ts` lock the orchestration in.
|
|
13
13
|
*/
|
|
14
|
-
import type { AssessmentEntity
|
|
15
|
-
import { type CanonicalToolsConfig } from "../../services/tools-config-normalizer.js";
|
|
16
|
-
import type { ToolPolicyDecision, ToolPolicyDecisionRequest } from "./decision-types.js";
|
|
14
|
+
import type { AssessmentEntity } from "@pie-players/pie-players-shared/types";
|
|
15
|
+
import { type CanonicalToolsConfig, type ToolPlacementLevel } from "../../services/tools-config-normalizer.js";
|
|
16
|
+
import type { OverrideBlockedDetails, ToolPolicyDecision, ToolPolicyDecisionRequest, ToolPolicyDiagnostic } from "./decision-types.js";
|
|
17
17
|
import type { PolicySource } from "./PolicySource.js";
|
|
18
|
-
import type
|
|
18
|
+
import { type PnpPolicySourceRule } from "./provenance.js";
|
|
19
|
+
import type { PnpPolicyItem, PnpPolicySource } from "../sources/PnpPolicySource.js";
|
|
19
20
|
export interface ComposeDecisionInputs {
|
|
20
21
|
request: ToolPolicyDecisionRequest;
|
|
21
22
|
tools: CanonicalToolsConfig;
|
|
22
23
|
pnpPolicy: {
|
|
23
24
|
source: PnpPolicySource | null;
|
|
24
25
|
assessment?: AssessmentEntity;
|
|
25
|
-
|
|
26
|
+
/** The item an item-scoped decision is for; see {@link PnpPolicyItem}. */
|
|
27
|
+
item?: PnpPolicyItem;
|
|
26
28
|
/**
|
|
27
29
|
* "on" applies the PNP/profile precedence rules; "off" skips step 5
|
|
28
|
-
* entirely.
|
|
29
|
-
*
|
|
30
|
+
* entirely. The engine resolves it from the enforcement override, or
|
|
31
|
+
* from whether the assessment or item carries PNP/profile material.
|
|
30
32
|
*/
|
|
31
33
|
enforcement: "on" | "off";
|
|
32
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Mounted items whose settings this decision leaves out: set for a section-
|
|
37
|
+
* or assessment-level toolbar. A tool on that toolbar that one of them
|
|
38
|
+
* restricts or requires gets a `tool-policy.itemSettingNotApplied`
|
|
39
|
+
* diagnostic.
|
|
40
|
+
*/
|
|
41
|
+
unappliedItems?: readonly PnpPolicyItem[];
|
|
33
42
|
customSources: readonly PolicySource[];
|
|
34
43
|
/** Stable identifier used as the provenance `contextId`. */
|
|
35
44
|
contextId: string;
|
|
36
45
|
}
|
|
37
46
|
export declare function composeDecision(inputs: ComposeDecisionInputs): ToolPolicyDecision;
|
|
47
|
+
/**
|
|
48
|
+
* A `tool-policy.overrideBlocked` diagnostic for a tool a `true` test
|
|
49
|
+
* administration override grants and `rule` withdraws. `level` is absent on a
|
|
50
|
+
* feature decision, which has no toolbar level.
|
|
51
|
+
*/
|
|
52
|
+
export declare function overrideBlockedDiagnostic(toolId: string, rule: OverrideBlockedDetails["rule"], level?: ToolPlacementLevel): ToolPolicyDiagnostic;
|
|
53
|
+
/**
|
|
54
|
+
* A `tool-policy.unknownSupportId` diagnostic for an id the registry lacks,
|
|
55
|
+
* attributed to the highest-precedence rule naming it. `level` is absent on a
|
|
56
|
+
* feature decision, which has no toolbar level.
|
|
57
|
+
*/
|
|
58
|
+
export declare function unknownSupportIdDiagnostic(supportId: string, origins: readonly PnpPolicySourceRule[], level?: ToolPlacementLevel): ToolPolicyDiagnostic;
|