@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.
Files changed (274) hide show
  1. package/README.md +469 -318
  2. package/dist/attempt/AssessmentSession.d.ts +1 -5
  3. package/dist/attempt/AssessmentSession.js +0 -29
  4. package/dist/attempt/TestSession.d.ts +1 -20
  5. package/dist/attempt/TestSession.js +8 -99
  6. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  7. package/dist/components/ItemScope.custom-element.js +1 -0
  8. package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
  9. package/dist/components/ItemToolBar.custom-element.js +1 -1
  10. package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
  11. package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
  12. package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
  13. package/dist/components/SectionToolBar.custom-element.js +1 -1
  14. package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
  15. package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
  16. package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
  17. package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
  18. package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
  19. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  20. package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
  21. package/dist/components/item-scope-element.d.ts +2 -0
  22. package/dist/components/item-scope-element.js +2 -0
  23. package/dist/context/assessment-toolkit-context.d.ts +32 -6
  24. package/dist/index.d.ts +23 -48
  25. package/dist/index.js +12 -37
  26. package/dist/policy/core/PolicySource.d.ts +1 -1
  27. package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
  28. package/dist/policy/core/ToolPolicyEngine.js +148 -46
  29. package/dist/policy/core/compose-decision.d.ts +28 -7
  30. package/dist/policy/core/compose-decision.js +75 -54
  31. package/dist/policy/core/decision-types.d.ts +65 -34
  32. package/dist/policy/core/feature-decision.d.ts +16 -9
  33. package/dist/policy/core/feature-decision.js +14 -8
  34. package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
  35. package/dist/policy/core/pnp-policy-inputs.js +28 -56
  36. package/dist/policy/core/provenance.d.ts +9 -4
  37. package/dist/policy/core/provenance.js +1 -1
  38. package/dist/policy/engine.d.ts +7 -23
  39. package/dist/policy/engine.js +5 -20
  40. package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
  41. package/dist/policy/sources/PnpPolicySource.js +117 -118
  42. package/dist/runtime/SectionControllerBinding.d.ts +279 -0
  43. package/dist/runtime/SectionControllerBinding.js +450 -0
  44. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  45. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  46. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  47. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  48. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  49. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  50. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
  51. package/dist/runtime/adapter/subscriber-fanout.js +1 -2
  52. package/dist/runtime/catalog-context.d.ts +19 -0
  53. package/dist/runtime/catalog-context.js +28 -0
  54. package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
  55. package/dist/runtime/composition-emit-scheduler.js +9 -15
  56. package/dist/runtime/content-language.d.ts +32 -0
  57. package/dist/runtime/content-language.js +46 -0
  58. package/dist/runtime/content-region.d.ts +17 -0
  59. package/dist/runtime/content-region.js +29 -0
  60. package/dist/runtime/content-registration.d.ts +13 -0
  61. package/dist/runtime/content-registration.js +25 -0
  62. package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
  63. package/dist/runtime/core/SectionEngineCore.js +2 -2
  64. package/dist/runtime/core/cohort.d.ts +1 -1
  65. package/dist/runtime/core/cohort.js +1 -1
  66. package/dist/runtime/core/engine-input.d.ts +18 -30
  67. package/dist/runtime/core/engine-input.js +11 -12
  68. package/dist/runtime/core/engine-output.d.ts +16 -40
  69. package/dist/runtime/core/engine-output.js +9 -21
  70. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  71. package/dist/runtime/core/engine-readiness.js +8 -41
  72. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  73. package/dist/runtime/core/engine-resolver.js +18 -43
  74. package/dist/runtime/core/engine-state.d.ts +28 -36
  75. package/dist/runtime/core/engine-state.js +18 -21
  76. package/dist/runtime/core/engine-transition.d.ts +14 -19
  77. package/dist/runtime/core/engine-transition.js +71 -51
  78. package/dist/runtime/engine.d.ts +16 -19
  79. package/dist/runtime/engine.js +12 -19
  80. package/dist/runtime/page-warnings.d.ts +13 -0
  81. package/dist/runtime/page-warnings.js +22 -0
  82. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  83. package/dist/runtime/policy-input-forwarding.js +25 -0
  84. package/dist/runtime/registration-events.d.ts +14 -0
  85. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  86. package/dist/runtime/runtime-event-claim.js +15 -0
  87. package/dist/runtime/shell-event-bridge.d.ts +45 -0
  88. package/dist/runtime/shell-event-bridge.js +127 -0
  89. package/dist/runtime/shell-registration.d.ts +73 -0
  90. package/dist/runtime/shell-registration.js +95 -0
  91. package/dist/runtime/shell-scope.d.ts +68 -0
  92. package/dist/runtime/shell-scope.js +188 -0
  93. package/dist/runtime/tool-host-contract.d.ts +28 -10
  94. package/dist/runtime/tool-host-contract.js +31 -10
  95. package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
  96. package/dist/runtime/unclaimed-registration-watch.js +23 -0
  97. package/dist/services/ElementToolStateStore.d.ts +14 -10
  98. package/dist/services/ElementToolStateStore.js +37 -13
  99. package/dist/services/HighlightCoordinator.d.ts +22 -28
  100. package/dist/services/HighlightCoordinator.js +431 -327
  101. package/dist/services/RangeSerializer.d.ts +10 -1
  102. package/dist/services/RangeSerializer.js +87 -14
  103. package/dist/services/TTSService.d.ts +130 -69
  104. package/dist/services/TTSService.js +713 -570
  105. package/dist/services/ToolCoordinator.d.ts +43 -66
  106. package/dist/services/ToolCoordinator.js +164 -208
  107. package/dist/services/ToolRegistry.d.ts +78 -54
  108. package/dist/services/ToolRegistry.js +107 -105
  109. package/dist/services/ToolkitCoordinator.d.ts +261 -175
  110. package/dist/services/ToolkitCoordinator.js +667 -433
  111. package/dist/services/audio-handoff.d.ts +6 -7
  112. package/dist/services/audio-handoff.js +20 -14
  113. package/dist/services/catalog-owner.d.ts +11 -1
  114. package/dist/services/catalog-owner.js +25 -0
  115. package/dist/services/create-tools-config.d.ts +2 -2
  116. package/dist/services/framework-error-bus.d.ts +3 -6
  117. package/dist/services/framework-error-bus.js +3 -6
  118. package/dist/services/framework-error.d.ts +30 -8
  119. package/dist/services/framework-error.js +9 -7
  120. package/dist/services/interfaces.d.ts +158 -129
  121. package/dist/services/section-controller-types.d.ts +15 -0
  122. package/dist/services/section-session-assignment.d.ts +21 -0
  123. package/dist/services/section-session-assignment.js +82 -0
  124. package/dist/services/spoken-audio-cards.d.ts +0 -2
  125. package/dist/services/spoken-audio-cards.js +1 -3
  126. package/dist/services/tool-config-defaults.d.ts +3 -3
  127. package/dist/services/tool-config-defaults.js +3 -3
  128. package/dist/services/tool-config-validation.d.ts +14 -4
  129. package/dist/services/tool-config-validation.js +63 -71
  130. package/dist/services/tool-context.d.ts +0 -8
  131. package/dist/services/tool-context.js +29 -25
  132. package/dist/services/tool-icons.d.ts +4 -3
  133. package/dist/services/tool-icons.js +4 -3
  134. package/dist/services/tool-instance-id.d.ts +0 -1
  135. package/dist/services/tool-instance-id.js +0 -6
  136. package/dist/services/tool-providers/TTSToolProvider.d.ts +41 -80
  137. package/dist/services/tool-providers/TTSToolProvider.js +81 -40
  138. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
  139. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
  140. package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
  141. package/dist/services/tool-providers/index.d.ts +0 -9
  142. package/dist/services/tool-providers/index.js +2 -4
  143. package/dist/services/tool-request.d.ts +27 -12
  144. package/dist/services/tool-request.js +24 -14
  145. package/dist/services/toolbar-decided-tools.d.ts +15 -0
  146. package/dist/services/toolbar-decided-tools.js +28 -0
  147. package/dist/services/tools-config-normalizer.d.ts +37 -23
  148. package/dist/services/tools-config-normalizer.js +2 -10
  149. package/dist/services/tts/browser-provider.d.ts +38 -2
  150. package/dist/services/tts/browser-provider.js +276 -140
  151. package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
  152. package/dist/services/tts/catalog-span-alignment.js +17 -142
  153. package/dist/services/tts/flat-tree.d.ts +71 -0
  154. package/dist/services/tts/flat-tree.js +269 -0
  155. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  156. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  157. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  158. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  159. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  160. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  161. package/dist/services/tts/generated-speech/types.d.ts +0 -12
  162. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
  163. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
  164. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
  165. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  166. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  167. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  168. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  169. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  170. package/dist/services/tts/math-alignment/index.d.ts +0 -5
  171. package/dist/services/tts/math-alignment/index.js +5 -25
  172. package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
  173. package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
  174. package/dist/services/tts/math-alignment/types.d.ts +4 -2
  175. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  176. package/dist/services/tts/math-aware-text-processing.js +74 -18
  177. package/dist/services/tts/math-control-names.d.ts +21 -0
  178. package/dist/services/tts/math-control-names.js +142 -0
  179. package/dist/services/tts/math-speech.d.ts +16 -1
  180. package/dist/services/tts/math-speech.js +55 -19
  181. package/dist/services/tts/provider-options.d.ts +41 -0
  182. package/dist/services/tts/provider-options.js +1 -0
  183. package/dist/services/tts/sre-engine.d.ts +7 -0
  184. package/dist/services/tts/sre-engine.js +11 -0
  185. package/dist/services/tts/sre-locales.d.ts +14 -0
  186. package/dist/services/tts/sre-locales.js +57 -0
  187. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  188. package/dist/services/tts/ssml/spoken-text.js +29 -0
  189. package/dist/services/tts/start-failure.d.ts +11 -0
  190. package/dist/services/tts/start-failure.js +19 -0
  191. package/dist/services/tts/text-processing.d.ts +9 -1
  192. package/dist/services/tts/text-processing.js +46 -34
  193. package/dist/services/tts/text-segmentation.d.ts +7 -0
  194. package/dist/services/tts/text-segmentation.js +47 -0
  195. package/dist/services/tts-runtime-config.d.ts +44 -18
  196. package/dist/services/tts-runtime-config.js +22 -93
  197. package/dist/tools/content-capability-resolution.d.ts +7 -9
  198. package/dist/tools/content-capability-resolution.js +8 -45
  199. package/dist/tools/registration.d.ts +58 -0
  200. package/dist/tools/registration.js +54 -0
  201. package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
  202. package/dist/tools/tool-surface-host.d.ts +6 -10
  203. package/dist/tools/tool-surface-host.js +44 -42
  204. package/dist/tools/tool-tag-map.d.ts +5 -15
  205. package/dist/tools/tool-tag-map.js +6 -20
  206. package/dist/utils/structural-equality.d.ts +11 -0
  207. package/dist/utils/structural-equality.js +47 -0
  208. package/package.json +24 -59
  209. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  210. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  211. package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
  212. package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
  213. package/dist/context/runtime-context-consumer.d.ts +0 -13
  214. package/dist/context/runtime-context-consumer.js +0 -51
  215. package/dist/item-loader.d.ts +0 -44
  216. package/dist/item-loader.js +0 -61
  217. package/dist/policy/core/engine-context.d.ts +0 -29
  218. package/dist/policy/core/engine-context.js +0 -27
  219. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  220. package/dist/policy/core/policy-source-tag.js +0 -28
  221. package/dist/policy/internal.d.ts +0 -25
  222. package/dist/policy/internal.js +0 -25
  223. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  224. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  225. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  226. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  227. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  228. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  229. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  230. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  231. package/dist/runtime/engine-context.d.ts +0 -39
  232. package/dist/runtime/engine-context.js +0 -31
  233. package/dist/runtime/internal.d.ts +0 -43
  234. package/dist/runtime/internal.js +0 -45
  235. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -80
  236. package/dist/runtime/section-runtime-engine-host-context.js +0 -95
  237. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  238. package/dist/runtime/stage-emit-gate.js +0 -82
  239. package/dist/services/I18nService.d.ts +0 -47
  240. package/dist/services/I18nService.js +0 -84
  241. package/dist/services/ThemeProvider.d.ts +0 -95
  242. package/dist/services/ThemeProvider.js +0 -334
  243. package/dist/services/ToolConfigResolver.d.ts +0 -161
  244. package/dist/services/ToolConfigResolver.js +0 -229
  245. package/dist/services/catalog-media.d.ts +0 -56
  246. package/dist/services/catalog-media.js +0 -190
  247. package/dist/services/createDefaultToolRegistry.d.ts +0 -53
  248. package/dist/services/createDefaultToolRegistry.js +0 -45
  249. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  250. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  251. package/dist/services/pnp-standard-features.d.ts +0 -238
  252. package/dist/services/pnp-standard-features.js +0 -338
  253. package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
  254. package/dist/services/tool-providers/CortexToolProvider.js +0 -32
  255. package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
  256. package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
  257. package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
  258. package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
  259. package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
  260. package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
  261. package/dist/services/tts/visual-line-ranges.d.ts +0 -18
  262. package/dist/services/tts/visual-line-ranges.js +0 -226
  263. package/dist/tools/client.d.ts +0 -12
  264. package/dist/tools/client.js +0 -14
  265. package/dist/tools/index.d.ts +0 -8
  266. package/dist/tools/index.js +0 -10
  267. package/dist/tools/internal.d.ts +0 -43
  268. package/dist/tools/internal.js +0 -41
  269. package/dist/tools/response-discovery.d.ts +0 -61
  270. package/dist/tools/response-discovery.js +0 -113
  271. package/dist/tools/types.d.ts +0 -337
  272. package/dist/tools/types.js +0 -12
  273. package/dist/tools/variant-resolver.d.ts +0 -41
  274. package/dist/tools/variant-resolver.js +0 -207
@@ -1,229 +0,0 @@
1
- /**
2
- * ToolConfigResolver
3
- *
4
- * Implements 3-tier hierarchy for tool configuration:
5
- * Item requirements > Roster allowances > Student accommodations
6
- *
7
- * Ensures IEP/504 compliance by properly handling accommodation requirements
8
- * while respecting item-level and test-level restrictions.
9
- *
10
- * Features:
11
- * - 3-tier configuration hierarchy
12
- * - IEP/504 accommodation support
13
- * - Item-specific tool requirements
14
- * - Test-level tool restrictions
15
- * - Type-safe configuration
16
- *
17
- * Part of PIE Assessment Toolkit.
18
- */
19
- export class ToolConfigResolver {
20
- /**
21
- * Resolve configuration for a specific tool
22
- *
23
- * Hierarchy (highest to lowest priority):
24
- * 1. Item level: Item requires scientific calculator → must provide
25
- * 2. Roster level: Test blocks a tool → blocked regardless of accommodation
26
- * 3. Student level: IEP requires TTS → enabled unless blocked above
27
- *
28
- * @param toolId Tool identifier
29
- * @param itemConfig Item-level tool configuration
30
- * @param rosterConfig Roster-level tool allowances
31
- * @param studentProfile Student accommodation profile
32
- * @returns Resolved configuration or null if tool not available
33
- */
34
- resolveTool(toolId, itemConfig, rosterConfig, studentProfile) {
35
- // Check item level (highest priority)
36
- const itemTool = itemConfig?.[toolId];
37
- if (itemTool) {
38
- // Item explicitly configures this tool
39
- return {
40
- enabled: true,
41
- type: itemTool.type,
42
- required: itemTool.required ?? false,
43
- settings: itemTool.settings,
44
- source: "item",
45
- };
46
- }
47
- // Check roster level (blocks take precedence)
48
- const rosterAllowance = rosterConfig?.[toolId];
49
- if (rosterAllowance === "0") {
50
- // Roster explicitly blocks this tool
51
- return null;
52
- }
53
- if (rosterAllowance === "1") {
54
- // Roster allows this tool
55
- return {
56
- enabled: true,
57
- required: false,
58
- source: "roster",
59
- };
60
- }
61
- // Check student level (lowest priority)
62
- const hasAccommodation = studentProfile?.accommodations.includes(toolId) ?? false;
63
- if (hasAccommodation) {
64
- // Student has accommodation for this tool
65
- return {
66
- enabled: true,
67
- required: false,
68
- source: "student",
69
- };
70
- }
71
- // Tool not configured at any level
72
- return null;
73
- }
74
- /**
75
- * Resolve all tools from configuration
76
- *
77
- * @param input Configuration input
78
- * @returns Map of tool ID to resolved configuration
79
- */
80
- resolveAll(input) {
81
- const resolved = new Map();
82
- // Collect all tool IDs from all levels
83
- const allToolIds = new Set();
84
- // From item config
85
- if (input.itemConfig) {
86
- Object.keys(input.itemConfig).forEach((id) => allToolIds.add(id));
87
- }
88
- // From roster config
89
- if (input.rosterConfig) {
90
- Object.keys(input.rosterConfig).forEach((id) => allToolIds.add(id));
91
- }
92
- // From student accommodations
93
- if (input.studentProfile) {
94
- input.studentProfile.accommodations.forEach((id) => allToolIds.add(id));
95
- }
96
- // Resolve each tool
97
- for (const toolId of allToolIds) {
98
- const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
99
- if (config) {
100
- resolved.set(toolId, config);
101
- }
102
- }
103
- return resolved;
104
- }
105
- /**
106
- * Check if a tool is enabled
107
- *
108
- * @param toolId Tool identifier
109
- * @param input Configuration input
110
- * @returns true if tool is enabled
111
- */
112
- isToolEnabled(toolId, input) {
113
- const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
114
- return config?.enabled ?? false;
115
- }
116
- /**
117
- * Check if a tool is required
118
- *
119
- * @param toolId Tool identifier
120
- * @param input Configuration input
121
- * @returns true if tool is required
122
- */
123
- isToolRequired(toolId, input) {
124
- const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
125
- return config?.required ?? false;
126
- }
127
- /**
128
- * Get tool type (e.g., 'scientific' for calculator)
129
- *
130
- * @param toolId Tool identifier
131
- * @param input Configuration input
132
- * @returns Tool type or null
133
- */
134
- getToolType(toolId, input) {
135
- const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
136
- return config?.type ?? null;
137
- }
138
- /**
139
- * Get tool settings
140
- *
141
- * @param toolId Tool identifier
142
- * @param input Configuration input
143
- * @returns Tool settings or null
144
- */
145
- getToolSettings(toolId, input) {
146
- const config = this.resolveTool(toolId, input.itemConfig, input.rosterConfig, input.studentProfile);
147
- return config?.settings ?? null;
148
- }
149
- /**
150
- * Get list of all enabled tools
151
- *
152
- * @param input Configuration input
153
- * @returns Array of enabled tool IDs
154
- */
155
- getEnabledTools(input) {
156
- const resolved = this.resolveAll(input);
157
- return Array.from(resolved.entries())
158
- .filter(([_, config]) => config.enabled)
159
- .map(([toolId]) => toolId);
160
- }
161
- /**
162
- * Get list of required tools
163
- *
164
- * @param input Configuration input
165
- * @returns Array of required tool IDs
166
- */
167
- getRequiredTools(input) {
168
- const resolved = this.resolveAll(input);
169
- return Array.from(resolved.entries())
170
- .filter(([_, config]) => config.required)
171
- .map(([toolId]) => toolId);
172
- }
173
- /**
174
- * Validate that all required tools are available
175
- *
176
- * @param availableTools Set of available tool IDs
177
- * @param input Configuration input
178
- * @returns Object with validation result
179
- */
180
- validate(availableTools, input) {
181
- const requiredTools = this.getRequiredTools(input);
182
- const missingTools = requiredTools.filter((toolId) => !availableTools.has(toolId));
183
- return {
184
- valid: missingTools.length === 0,
185
- missingTools,
186
- };
187
- }
188
- /**
189
- * Merge multiple roster configurations (for complex assessments)
190
- *
191
- * More restrictive settings win (blocked > allowed).
192
- *
193
- * @param configs Array of roster configurations
194
- * @returns Merged configuration
195
- */
196
- mergeRosterConfigs(...configs) {
197
- const merged = {};
198
- for (const config of configs) {
199
- for (const [toolId, allowance] of Object.entries(config)) {
200
- // If any config blocks the tool, it's blocked
201
- if (allowance === "0") {
202
- merged[toolId] = "0";
203
- }
204
- else if (!merged[toolId]) {
205
- // If not already set, use this allowance
206
- merged[toolId] = allowance;
207
- }
208
- }
209
- }
210
- return merged;
211
- }
212
- /**
213
- * Merge multiple student accommodation profiles
214
- *
215
- * Union of all accommodations.
216
- *
217
- * @param profiles Array of student profiles
218
- * @returns Merged profile
219
- */
220
- mergeStudentProfiles(...profiles) {
221
- const allAccommodations = new Set();
222
- for (const profile of profiles) {
223
- profile.accommodations.forEach((acc) => allAccommodations.add(acc));
224
- }
225
- return {
226
- accommodations: Array.from(allAccommodations),
227
- };
228
- }
229
- }
@@ -1,56 +0,0 @@
1
- /**
2
- * Validation primitives shared by every catalog card whose payload references
3
- * media.
4
- *
5
- * Extracted from `sign-language-cards.ts` when `spoken` cards gained a recorded
6
- * audio form: both card types take authored, wire-facing URLs and hand them to a
7
- * media element in the learner's browser, so both need the same scheme
8
- * allow-list and the same "treat as absent, never as partially valid" posture.
9
- * Two copies of a URL allow-list is one copy that gets a fix and one that does
10
- * not.
11
- *
12
- * Part of PIE Assessment Toolkit.
13
- */
14
- import type { MediaFragmentRange, MediaSource } from "@pie-players/pie-players-shared/types";
15
- /**
16
- * The only `MediaAssetRef.version` this build renders.
17
- *
18
- * `media-asset-contract.md` requires unknown-version rejection for runtime
19
- * rendering: bumping to `2` obliges every consumer to accept both for as long as
20
- * any producer emits `1`, so a card claiming a version this build does not
21
- * implement must not be rendered on a guess at which fields still mean what they
22
- * did.
23
- */
24
- export declare const SUPPORTED_MEDIA_ASSET_VERSION = 1;
25
- /**
26
- * Whether a media reference claims a version this build cannot render.
27
- *
28
- * An absent `version` is accepted rather than rejected — the same posture the
29
- * rest of this module takes toward absent fields, and the one `media.kind` and
30
- * `matchesRequestedSignLanguage` already take: only a positive claim of
31
- * something else is refused. Producers predate the field, and treating its
32
- * absence as a rejection would drop cards that are otherwise wholly valid.
33
- */
34
- export declare function isUnsupportedMediaAssetVersion(version: unknown): boolean;
35
- export declare function isSafeMediaSrc(raw: unknown): raw is string;
36
- export declare function normalizeMediaSources(raw: unknown): MediaSource[];
37
- export declare function normalizeMediaFragment(raw: unknown): MediaFragmentRange | undefined;
38
- export declare function trimmedOrUndefined(value: unknown): string | undefined;
39
- /**
40
- * Hold a media element to one fragment's range, and return the disposer.
41
- *
42
- * The `#t=` URI `applyMediaFragment` writes is a hint browsers honour at neither
43
- * bound reliably, so every consumer that means "play only this slice" enforces it
44
- * here instead of reimplementing the pair. Both shipped consumers do —
45
- * `SignLanguageMediaRegion` pausing at the end, `TTSService.playRecordedAudio`
46
- * ending the clip so the chunk sequence advances — which is why the end action is
47
- * the caller's and only the arithmetic is shared.
48
- *
49
- * The start seek is forward only: a browser that did honour the URI has already
50
- * positioned past the start, and seeking back would replay audio the learner has
51
- * heard. `onReachedEnd` may fire more than once and must tolerate it; polling
52
- * stops while the element is paused, so an element left sitting past its end bound
53
- * goes quiet rather than being told repeatedly.
54
- */
55
- export declare function enforceMediaFragment(element: HTMLMediaElement, fragment: MediaFragmentRange | undefined, onReachedEnd: () => void): () => void;
56
- export declare function applyMediaFragment(src: string, fragment?: MediaFragmentRange): string;
@@ -1,190 +0,0 @@
1
- /**
2
- * Validation primitives shared by every catalog card whose payload references
3
- * media.
4
- *
5
- * Extracted from `sign-language-cards.ts` when `spoken` cards gained a recorded
6
- * audio form: both card types take authored, wire-facing URLs and hand them to a
7
- * media element in the learner's browser, so both need the same scheme
8
- * allow-list and the same "treat as absent, never as partially valid" posture.
9
- * Two copies of a URL allow-list is one copy that gets a fix and one that does
10
- * not.
11
- *
12
- * Part of PIE Assessment Toolkit.
13
- */
14
- /**
15
- * Media source URLs are handed to a media element in the learner's browser. Only
16
- * schemes such an element can actually fetch are allowed; anything else is
17
- * dropped so an authored `javascript:` / `file:` URL cannot ride into the DOM.
18
- * Relative and protocol-relative URLs are allowed — host content is commonly
19
- * served from the same origin as the player.
20
- */
21
- const DISALLOWED_SRC_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
22
- const ALLOWED_SRC_SCHEMES = new Set(["http:", "https:", "data:", "blob:"]);
23
- /**
24
- * The only `MediaAssetRef.version` this build renders.
25
- *
26
- * `media-asset-contract.md` requires unknown-version rejection for runtime
27
- * rendering: bumping to `2` obliges every consumer to accept both for as long as
28
- * any producer emits `1`, so a card claiming a version this build does not
29
- * implement must not be rendered on a guess at which fields still mean what they
30
- * did.
31
- */
32
- export const SUPPORTED_MEDIA_ASSET_VERSION = 1;
33
- /**
34
- * Whether a media reference claims a version this build cannot render.
35
- *
36
- * An absent `version` is accepted rather than rejected — the same posture the
37
- * rest of this module takes toward absent fields, and the one `media.kind` and
38
- * `matchesRequestedSignLanguage` already take: only a positive claim of
39
- * something else is refused. Producers predate the field, and treating its
40
- * absence as a rejection would drop cards that are otherwise wholly valid.
41
- */
42
- export function isUnsupportedMediaAssetVersion(version) {
43
- return version !== undefined && version !== SUPPORTED_MEDIA_ASSET_VERSION;
44
- }
45
- export function isSafeMediaSrc(raw) {
46
- if (typeof raw !== "string")
47
- return false;
48
- const src = raw.trim();
49
- if (!src)
50
- return false;
51
- // Relative ("/video.mp4", "video.mp4") and protocol-relative ("//cdn/x.mp4")
52
- // forms carry no scheme to check and inherit the document's.
53
- if (src.startsWith("//") || !DISALLOWED_SRC_SCHEME.test(src))
54
- return true;
55
- const scheme = src.slice(0, src.indexOf(":") + 1).toLowerCase();
56
- return ALLOWED_SRC_SCHEMES.has(scheme);
57
- }
58
- export function normalizeMediaSources(raw) {
59
- if (!Array.isArray(raw))
60
- return [];
61
- const sources = [];
62
- for (const entry of raw) {
63
- if (!entry || typeof entry !== "object")
64
- continue;
65
- const candidate = entry;
66
- if (!isSafeMediaSrc(candidate.src))
67
- continue;
68
- const source = { src: candidate.src.trim() };
69
- if (typeof candidate.type === "string" && candidate.type.trim()) {
70
- source.type = candidate.type.trim();
71
- }
72
- if (Number.isFinite(candidate.width))
73
- source.width = candidate.width;
74
- if (Number.isFinite(candidate.height))
75
- source.height = candidate.height;
76
- // Deduplicated by `src`, because the signing region renders `<source>`
77
- // elements in an `{#each}` keyed on exactly that: an authored card listing
78
- // one URL twice — the same file under two MIME types is the plausible way —
79
- // would otherwise throw Svelte's duplicate-key error and take the whole
80
- // region down rather than degrade. The first entry wins, so authored order
81
- // still decides which encoding the browser is offered first.
82
- if (sources.some((existing) => existing.src === source.src))
83
- continue;
84
- sources.push(source);
85
- }
86
- return sources;
87
- }
88
- export function normalizeMediaFragment(raw) {
89
- if (!raw || typeof raw !== "object")
90
- return undefined;
91
- const candidate = raw;
92
- const start = Number(candidate.startSeconds);
93
- if (!Number.isFinite(start) || start < 0)
94
- return undefined;
95
- const end = Number(candidate.endSeconds);
96
- // An end at or before the start would produce a zero/negative slice; treat
97
- // it as "no end" rather than a range that can never play.
98
- if (!Number.isFinite(end) || end <= start)
99
- return { startSeconds: start };
100
- return { startSeconds: start, endSeconds: end };
101
- }
102
- export function trimmedOrUndefined(value) {
103
- if (typeof value !== "string")
104
- return undefined;
105
- const trimmed = value.trim();
106
- return trimmed || undefined;
107
- }
108
- /**
109
- * Apply a fragment range to a source URL as a Media Fragments URI, so one
110
- * recording can serve several content nodes.
111
- *
112
- * The URI is a hint only: browsers honour both bounds inconsistently, so the
113
- * caller enforces the range itself — seek forward to the start once metadata is
114
- * available, and stop at the end. `SignLanguageMediaRegion` and
115
- * `TTSService.playRecordedAudio` are the two shipped consumers that do so.
116
- */
117
- /**
118
- * How often the end bound is re-checked while a slice is playing. `timeupdate`
119
- * alone fires about four times a second, which is loose enough to leak a sliver
120
- * of the next node's recording.
121
- */
122
- const END_CHECK_INTERVAL_MS = 100;
123
- /** `HTMLMediaElement.HAVE_METADATA`, which not every DOM implementation exposes. */
124
- const HAVE_METADATA = 1;
125
- /**
126
- * Hold a media element to one fragment's range, and return the disposer.
127
- *
128
- * The `#t=` URI `applyMediaFragment` writes is a hint browsers honour at neither
129
- * bound reliably, so every consumer that means "play only this slice" enforces it
130
- * here instead of reimplementing the pair. Both shipped consumers do —
131
- * `SignLanguageMediaRegion` pausing at the end, `TTSService.playRecordedAudio`
132
- * ending the clip so the chunk sequence advances — which is why the end action is
133
- * the caller's and only the arithmetic is shared.
134
- *
135
- * The start seek is forward only: a browser that did honour the URI has already
136
- * positioned past the start, and seeking back would replay audio the learner has
137
- * heard. `onReachedEnd` may fire more than once and must tolerate it; polling
138
- * stops while the element is paused, so an element left sitting past its end bound
139
- * goes quiet rather than being told repeatedly.
140
- */
141
- export function enforceMediaFragment(element, fragment, onReachedEnd) {
142
- if (!fragment)
143
- return () => { };
144
- const { startSeconds, endSeconds } = fragment;
145
- let seekToStart;
146
- if (startSeconds > 0) {
147
- seekToStart = () => {
148
- if (element.currentTime < startSeconds) {
149
- element.currentTime = startSeconds;
150
- }
151
- };
152
- // Seeking before metadata is available only sets the default start
153
- // position, so wait for it unless it already landed.
154
- if (element.readyState >= HAVE_METADATA)
155
- seekToStart();
156
- else
157
- element.addEventListener("loadedmetadata", seekToStart);
158
- }
159
- let checkEnd;
160
- let endPoll;
161
- if (endSeconds !== undefined) {
162
- checkEnd = () => {
163
- if (element.currentTime >= endSeconds)
164
- onReachedEnd();
165
- };
166
- element.addEventListener("timeupdate", checkEnd);
167
- endPoll = setInterval(() => {
168
- if (!element.paused)
169
- checkEnd?.();
170
- }, END_CHECK_INTERVAL_MS);
171
- }
172
- return () => {
173
- if (seekToStart)
174
- element.removeEventListener("loadedmetadata", seekToStart);
175
- if (checkEnd)
176
- element.removeEventListener("timeupdate", checkEnd);
177
- if (endPoll !== undefined)
178
- clearInterval(endPoll);
179
- };
180
- }
181
- export function applyMediaFragment(src, fragment) {
182
- if (!fragment)
183
- return src;
184
- // Never stack a second fragment onto a URL that already carries one — the
185
- // authored value wins.
186
- if (src.includes("#"))
187
- return src;
188
- const end = fragment.endSeconds !== undefined ? `,${fragment.endSeconds}` : "";
189
- return `${src}#t=${fragment.startSeconds}${end}`;
190
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * Tool Registry Factory
3
- *
4
- * Creates an empty `ToolRegistry` and installs whatever component overrides and
5
- * lazy module loaders the caller supplies.
6
- *
7
- * It registers nothing by itself, deliberately. Eleven concrete registrations
8
- * used to live in this package, which made the policy and registry core know
9
- * every capability by name and left a host unable to contribute one without a PR
10
- * against this package. The packaged set now lives in the composition layer:
11
- * `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
12
- */
13
- import type { ToolRegistration, ToolModuleLoader } from "./ToolRegistry.js";
14
- import { ToolRegistry } from "./ToolRegistry.js";
15
- import type { ToolComponentFactory, ToolComponentFactoryMap, ToolTagMap } from "../tools/tool-tag-map.js";
16
- import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
17
- export interface DefaultToolRegistryOptions {
18
- /**
19
- * Registrations to register, keyed by toolId. Nothing is registered when this
20
- * is absent.
21
- */
22
- registrations?: Partial<Record<string, ToolRegistration>>;
23
- /**
24
- * Element tag mapping for the registrations being installed. There is no
25
- * built-in default: a tag map names capabilities, so it belongs to whoever
26
- * decides which capabilities exist.
27
- */
28
- toolTagMap?: Partial<ToolTagMap>;
29
- /**
30
- * Override component creation globally (all tools) or per tool.
31
- */
32
- toolComponentFactory?: ToolComponentFactory;
33
- toolComponentFactories?: Partial<ToolComponentFactoryMap>;
34
- /**
35
- * Optional lazy module loaders keyed by toolId.
36
- */
37
- toolModuleLoaders?: Partial<Record<string, ToolModuleLoader>>;
38
- }
39
- /**
40
- * Create a tool registry.
41
- *
42
- * @returns an empty `ToolRegistry` unless `registrations` is supplied
43
- */
44
- export declare function createDefaultToolRegistry(options?: DefaultToolRegistryOptions): ToolRegistry;
45
- /**
46
- * Placement configuration with every level empty.
47
- *
48
- * The only placement default this package can hold: a populated one would name
49
- * capabilities. `PACKAGED_TOOL_PLACEMENT` and
50
- * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
51
- * `@pie-players/pie-default-tool-loaders`.
52
- */
53
- export { DEFAULT_TOOL_PLACEMENT };
@@ -1,45 +0,0 @@
1
- /**
2
- * Tool Registry Factory
3
- *
4
- * Creates an empty `ToolRegistry` and installs whatever component overrides and
5
- * lazy module loaders the caller supplies.
6
- *
7
- * It registers nothing by itself, deliberately. Eleven concrete registrations
8
- * used to live in this package, which made the policy and registry core know
9
- * every capability by name and left a host unable to contribute one without a PR
10
- * against this package. The packaged set now lives in the composition layer:
11
- * `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
12
- */
13
- import { ToolRegistry } from "./ToolRegistry.js";
14
- import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
15
- /**
16
- * Create a tool registry.
17
- *
18
- * @returns an empty `ToolRegistry` unless `registrations` is supplied
19
- */
20
- export function createDefaultToolRegistry(options = {}) {
21
- const registry = new ToolRegistry();
22
- for (const registration of Object.values(options.registrations ?? {})) {
23
- if (registration)
24
- registry.register(registration);
25
- }
26
- if (options.toolModuleLoaders &&
27
- Object.keys(options.toolModuleLoaders).length > 0) {
28
- registry.setToolModuleLoaders(options.toolModuleLoaders);
29
- }
30
- registry.setComponentOverrides({
31
- toolTagMap: options.toolTagMap,
32
- toolComponentFactory: options.toolComponentFactory,
33
- toolComponentFactories: options.toolComponentFactories,
34
- });
35
- return registry;
36
- }
37
- /**
38
- * Placement configuration with every level empty.
39
- *
40
- * The only placement default this package can hold: a populated one would name
41
- * capabilities. `PACKAGED_TOOL_PLACEMENT` and
42
- * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
43
- * `@pie-players/pie-default-tool-loaders`.
44
- */
45
- export { DEFAULT_TOOL_PLACEMENT };
@@ -1,21 +0,0 @@
1
- import type { PersonalNeedsProfile } from "@pie-players/pie-players-shared/types";
2
- /**
3
- * An empty personal-needs profile: nothing granted, nothing prohibited, nothing
4
- * activated at init.
5
- *
6
- * The core ships no populated default on purpose. It once derived one from every
7
- * registered tool's `pnpSupportIds`, which read *registry membership* as
8
- * *eligibility tier* — registration means "policy-addressable", not "universal,
9
- * on by default" — so an accommodation-tier capability was granted to every
10
- * student of every host that supplied no profile. The remedy at the time was a
11
- * compile-time list of ids to exclude, which a host could not extend for its own
12
- * accommodation.
13
- *
14
- * Which capabilities a deployment grants by default is a property of the
15
- * program, not of this package: TTS is a universal feature in one program and a
16
- * documented accommodation in another. That belongs in policy configuration
17
- * alongside the district and test-administration levels. A named preset of
18
- * today's universal set ships as data from
19
- * `@pie-players/pie-default-tool-loaders`, for hosts that want it.
20
- */
21
- export declare function createEmptyPersonalNeedsProfile(): PersonalNeedsProfile;
@@ -1,26 +0,0 @@
1
- /**
2
- * An empty personal-needs profile: nothing granted, nothing prohibited, nothing
3
- * activated at init.
4
- *
5
- * The core ships no populated default on purpose. It once derived one from every
6
- * registered tool's `pnpSupportIds`, which read *registry membership* as
7
- * *eligibility tier* — registration means "policy-addressable", not "universal,
8
- * on by default" — so an accommodation-tier capability was granted to every
9
- * student of every host that supplied no profile. The remedy at the time was a
10
- * compile-time list of ids to exclude, which a host could not extend for its own
11
- * accommodation.
12
- *
13
- * Which capabilities a deployment grants by default is a property of the
14
- * program, not of this package: TTS is a universal feature in one program and a
15
- * documented accommodation in another. That belongs in policy configuration
16
- * alongside the district and test-administration levels. A named preset of
17
- * today's universal set ships as data from
18
- * `@pie-players/pie-default-tool-loaders`, for hosts that want it.
19
- */
20
- export function createEmptyPersonalNeedsProfile() {
21
- return {
22
- supports: [],
23
- prohibitedSupports: [],
24
- activateAtInit: [],
25
- };
26
- }