@pie-players/pie-assessment-toolkit 0.3.74 → 1.0.0-beta.0

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 (257) hide show
  1. package/README.md +658 -714
  2. package/custom-elements.json +1315 -0
  3. package/dist/attempt/TestSession.d.ts +1 -21
  4. package/dist/attempt/TestSession.js +16 -102
  5. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  6. package/dist/components/ItemScope.custom-element.js +1 -0
  7. package/dist/components/ItemToolBar.custom-element.js +1 -1
  8. package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
  9. package/dist/components/SectionToolBar.custom-element.js +1 -1
  10. package/dist/components/chunks/ItemToolBar-3zrc4p3d.js +4 -0
  11. package/dist/components/chunks/ItemToolBar-66hcwmfw.js +2 -0
  12. package/dist/components/chunks/ItemToolBar-9gqhfxtn.js +40 -0
  13. package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
  14. package/dist/components/chunks/{ItemToolBar-gmrryv2v.js → ItemToolBar-kkj69ptr.js} +1 -1
  15. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  16. package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
  17. package/dist/components/item-scope-element.d.ts +2 -0
  18. package/dist/components/item-scope-element.js +2 -0
  19. package/dist/context/assessment-toolkit-context.d.ts +33 -6
  20. package/dist/index.d.ts +25 -50
  21. package/dist/index.js +15 -45
  22. package/dist/policy/core/PolicySource.d.ts +2 -2
  23. package/dist/policy/core/ToolPolicyEngine.d.ts +118 -34
  24. package/dist/policy/core/ToolPolicyEngine.js +203 -56
  25. package/dist/policy/core/compose-decision.d.ts +28 -7
  26. package/dist/policy/core/compose-decision.js +95 -74
  27. package/dist/policy/core/decision-types.d.ts +98 -55
  28. package/dist/policy/core/feature-decision.d.ts +28 -19
  29. package/dist/policy/core/feature-decision.js +15 -11
  30. package/dist/policy/core/pnp-policy-inputs.d.ts +29 -35
  31. package/dist/policy/core/pnp-policy-inputs.js +40 -88
  32. package/dist/policy/core/provenance.d.ts +10 -5
  33. package/dist/policy/core/provenance.js +1 -1
  34. package/dist/policy/core/tool-parameters.d.ts +11 -0
  35. package/dist/policy/core/tool-parameters.js +15 -0
  36. package/dist/policy/engine.d.ts +7 -23
  37. package/dist/policy/engine.js +5 -20
  38. package/dist/policy/sources/PnpPolicySource.d.ts +43 -68
  39. package/dist/policy/sources/PnpPolicySource.js +133 -132
  40. package/dist/runtime/SectionControllerBinding.d.ts +283 -0
  41. package/dist/runtime/SectionControllerBinding.js +456 -0
  42. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  43. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  44. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  45. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  46. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  47. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  48. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -3
  49. package/dist/runtime/adapter/subscriber-fanout.js +2 -6
  50. package/dist/runtime/catalog-context.d.ts +19 -0
  51. package/dist/runtime/catalog-context.js +28 -0
  52. package/dist/runtime/composition-emit-scheduler.d.ts +12 -18
  53. package/dist/runtime/composition-emit-scheduler.js +10 -16
  54. package/dist/runtime/content-language.d.ts +32 -0
  55. package/dist/runtime/content-language.js +46 -0
  56. package/dist/runtime/content-region.d.ts +13 -0
  57. package/dist/runtime/content-region.js +29 -0
  58. package/dist/runtime/content-registration.d.ts +13 -0
  59. package/dist/runtime/content-registration.js +25 -0
  60. package/dist/runtime/core/SectionEngineCore.d.ts +2 -4
  61. package/dist/runtime/core/SectionEngineCore.js +2 -6
  62. package/dist/runtime/core/cohort.d.ts +1 -6
  63. package/dist/runtime/core/cohort.js +1 -10
  64. package/dist/runtime/core/engine-input.d.ts +18 -30
  65. package/dist/runtime/core/engine-input.js +11 -12
  66. package/dist/runtime/core/engine-output.d.ts +17 -40
  67. package/dist/runtime/core/engine-output.js +9 -21
  68. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  69. package/dist/runtime/core/engine-readiness.js +8 -41
  70. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  71. package/dist/runtime/core/engine-resolver.js +18 -43
  72. package/dist/runtime/core/engine-state.d.ts +28 -36
  73. package/dist/runtime/core/engine-state.js +18 -21
  74. package/dist/runtime/core/engine-transition.d.ts +14 -19
  75. package/dist/runtime/core/engine-transition.js +74 -53
  76. package/dist/runtime/engine.d.ts +16 -19
  77. package/dist/runtime/engine.js +12 -19
  78. package/dist/runtime/page-warnings.d.ts +13 -0
  79. package/dist/runtime/page-warnings.js +22 -0
  80. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  81. package/dist/runtime/policy-input-forwarding.js +25 -0
  82. package/dist/runtime/registration-events.d.ts +22 -14
  83. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  84. package/dist/runtime/runtime-event-claim.js +15 -0
  85. package/dist/runtime/runtime-id.d.ts +1 -1
  86. package/dist/runtime/runtime-id.js +1 -1
  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 +194 -0
  93. package/dist/runtime/tool-host-contract.d.ts +8 -14
  94. package/dist/runtime/tool-host-contract.js +12 -12
  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/AccessibilityCatalogResolver.d.ts +21 -31
  98. package/dist/services/AccessibilityCatalogResolver.js +29 -42
  99. package/dist/services/ElementToolStateStore.d.ts +42 -67
  100. package/dist/services/ElementToolStateStore.js +65 -71
  101. package/dist/services/HighlightCoordinator.d.ts +28 -40
  102. package/dist/services/HighlightCoordinator.js +459 -381
  103. package/dist/services/RangeSerializer.d.ts +11 -33
  104. package/dist/services/RangeSerializer.js +88 -59
  105. package/dist/services/SSMLExtractor.d.ts +8 -31
  106. package/dist/services/SSMLExtractor.js +18 -40
  107. package/dist/services/TTSService.d.ts +159 -119
  108. package/dist/services/TTSService.js +937 -822
  109. package/dist/services/ToolCoordinator.d.ts +42 -102
  110. package/dist/services/ToolCoordinator.js +178 -256
  111. package/dist/services/ToolRegistry.d.ts +152 -133
  112. package/dist/services/ToolRegistry.js +192 -178
  113. package/dist/services/ToolkitCoordinator.d.ts +233 -237
  114. package/dist/services/ToolkitCoordinator.js +615 -557
  115. package/dist/services/audio-handoff.d.ts +6 -7
  116. package/dist/services/audio-handoff.js +20 -14
  117. package/dist/services/catalog-owner.d.ts +0 -1
  118. package/dist/services/framework-error-bus.d.ts +3 -6
  119. package/dist/services/framework-error-bus.js +3 -6
  120. package/dist/services/framework-error.d.ts +51 -13
  121. package/dist/services/framework-error.js +19 -20
  122. package/dist/services/interfaces.d.ts +189 -184
  123. package/dist/services/section-controller-types.d.ts +7 -7
  124. package/dist/services/section-session-assignment.d.ts +21 -0
  125. package/dist/services/section-session-assignment.js +80 -0
  126. package/dist/services/spoken-audio-cards.d.ts +2 -6
  127. package/dist/services/spoken-audio-cards.js +2 -6
  128. package/dist/services/tool-config-defaults.d.ts +3 -3
  129. package/dist/services/tool-config-defaults.js +3 -3
  130. package/dist/services/tool-config-validation.d.ts +9 -12
  131. package/dist/services/tool-config-validation.js +47 -87
  132. package/dist/services/tool-context.d.ts +7 -31
  133. package/dist/services/tool-context.js +99 -65
  134. package/dist/services/tool-failure.d.ts +30 -0
  135. package/dist/services/tool-failure.js +11 -0
  136. package/dist/services/tool-icons.d.ts +5 -5
  137. package/dist/services/tool-icons.js +6 -5
  138. package/dist/services/tool-instance-id.d.ts +8 -7
  139. package/dist/services/tool-instance-id.js +12 -24
  140. package/dist/services/tool-providers/TTSToolProvider.d.ts +20 -58
  141. package/dist/services/tool-providers/TTSToolProvider.js +32 -85
  142. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -11
  143. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +29 -60
  144. package/dist/services/tool-providers/ToolProviderRegistry.js +128 -144
  145. package/dist/services/tool-request.d.ts +31 -12
  146. package/dist/services/tool-request.js +31 -16
  147. package/dist/services/toolbar-decided-tools.d.ts +16 -0
  148. package/dist/services/toolbar-decided-tools.js +29 -0
  149. package/dist/services/toolbar-items.js +2 -5
  150. package/dist/services/tools-config-normalizer.d.ts +33 -29
  151. package/dist/services/tools-config-normalizer.js +26 -28
  152. package/dist/services/tts/browser-provider.d.ts +39 -6
  153. package/dist/services/tts/browser-provider.js +280 -160
  154. package/dist/services/tts/catalog-span-alignment.js +14 -7
  155. package/dist/services/tts/flat-tree.d.ts +64 -0
  156. package/dist/services/tts/flat-tree.js +269 -0
  157. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  158. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  159. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  160. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  161. package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
  162. package/dist/services/tts/generated-speech/index.d.ts +1 -1
  163. package/dist/services/tts/generated-speech/index.js +1 -1
  164. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  165. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  166. package/dist/services/tts/generated-speech/types.d.ts +1 -1
  167. package/dist/services/tts/generated-speech/types.js +1 -1
  168. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +22 -16
  169. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  170. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  171. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  172. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  173. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  174. package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
  175. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  176. package/dist/services/tts/math-aware-text-processing.js +42 -47
  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 +12 -1
  180. package/dist/services/tts/math-speech.js +54 -18
  181. package/dist/services/tts/mathml-sanitization.d.ts +7 -0
  182. package/dist/services/tts/mathml-sanitization.js +9 -1
  183. package/dist/services/tts/provider-options.d.ts +52 -0
  184. package/dist/services/tts/provider-options.js +1 -0
  185. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  186. package/dist/services/tts/ssml/spoken-text.js +29 -0
  187. package/dist/services/tts/start-failure.d.ts +4 -0
  188. package/dist/services/tts/start-failure.js +19 -0
  189. package/dist/services/tts/text-processing.d.ts +9 -0
  190. package/dist/services/tts/text-processing.js +46 -33
  191. package/dist/services/tts/text-segmentation.d.ts +12 -0
  192. package/dist/services/tts/text-segmentation.js +60 -10
  193. package/dist/services/tts-runtime-config.d.ts +54 -26
  194. package/dist/services/tts-runtime-config.js +27 -112
  195. package/dist/tools/content-capability-resolution.d.ts +9 -11
  196. package/dist/tools/content-capability-resolution.js +8 -45
  197. package/dist/tools/registration.d.ts +59 -0
  198. package/dist/tools/registration.js +55 -0
  199. package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
  200. package/dist/tools/registrations/toolbar-registration-helpers.js +8 -2
  201. package/dist/tools/tool-surface-host.d.ts +6 -10
  202. package/dist/tools/tool-surface-host.js +45 -50
  203. package/dist/tools/tool-tag-map.d.ts +5 -15
  204. package/dist/tools/tool-tag-map.js +6 -20
  205. package/dist/utils/structural-equality.d.ts +11 -0
  206. package/dist/utils/structural-equality.js +47 -0
  207. package/package.json +15 -29
  208. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  209. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  210. package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +0 -40
  211. package/dist/components/chunks/ItemToolBar-h4xap0t0.js +0 -4
  212. package/dist/components/chunks/ItemToolBar-wr2myaah.js +0 -2
  213. package/dist/components/chunks/sre-engine-wf9s43gg.js +0 -1
  214. package/dist/context/runtime-context-consumer.d.ts +0 -13
  215. package/dist/context/runtime-context-consumer.js +0 -18
  216. package/dist/item-loader.d.ts +0 -44
  217. package/dist/item-loader.js +0 -61
  218. package/dist/policy/core/engine-context.d.ts +0 -29
  219. package/dist/policy/core/engine-context.js +0 -27
  220. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  221. package/dist/policy/core/policy-source-tag.js +0 -28
  222. package/dist/policy/internal.d.ts +0 -25
  223. package/dist/policy/internal.js +0 -25
  224. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  225. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  226. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  227. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  228. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  229. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  230. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  231. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  232. package/dist/runtime/engine-context.d.ts +0 -39
  233. package/dist/runtime/engine-context.js +0 -31
  234. package/dist/runtime/internal.d.ts +0 -43
  235. package/dist/runtime/internal.js +0 -45
  236. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -74
  237. package/dist/runtime/section-runtime-engine-host-context.js +0 -57
  238. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  239. package/dist/runtime/stage-emit-gate.js +0 -82
  240. package/dist/services/ContextVariableStore.d.ts +0 -113
  241. package/dist/services/ContextVariableStore.js +0 -206
  242. package/dist/services/I18nService.d.ts +0 -47
  243. package/dist/services/I18nService.js +0 -84
  244. package/dist/services/ThemeProvider.d.ts +0 -95
  245. package/dist/services/ThemeProvider.js +0 -334
  246. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  247. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  248. package/dist/services/pnp-standard-features.d.ts +0 -238
  249. package/dist/services/pnp-standard-features.js +0 -338
  250. package/dist/services/tts-control-events.d.ts +0 -13
  251. package/dist/services/tts-control-events.js +0 -7
  252. package/dist/tools/client.d.ts +0 -10
  253. package/dist/tools/client.js +0 -10
  254. package/dist/tools/internal.d.ts +0 -44
  255. package/dist/tools/internal.js +0 -39
  256. package/dist/utils/logger.d.ts +0 -6
  257. package/dist/utils/logger.js +0 -10
@@ -1,5 +1,11 @@
1
1
  import type { ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolbarContext } from "../../services/ToolRegistry.js";
2
2
  export type ToolOverlaySurface = "default" | "frameless";
3
+ /**
4
+ * The event a tool element dispatches, bubbling and composed, with
5
+ * `{ active: boolean }` as its detail when it opens or closes its own panel.
6
+ * A registration relays it as the toolbar button's active state.
7
+ */
8
+ export declare const TOOL_ACTIVE_CHANGE_EVENT = "pie-tool-active-change";
3
9
  export declare function createScopedVisibilityBinding(toolId: string, toolbarContext: ToolbarContext): {
4
10
  fullToolId: string;
5
11
  isActive: () => boolean;
@@ -1,14 +1,20 @@
1
1
  import { createScopedToolId } from "../../services/tool-instance-id.js";
2
+ /**
3
+ * The event a tool element dispatches, bubbling and composed, with
4
+ * `{ active: boolean }` as its detail when it opens or closes its own panel.
5
+ * A registration relays it as the toolbar button's active state.
6
+ */
7
+ export const TOOL_ACTIVE_CHANGE_EVENT = "pie-tool-active-change";
2
8
  export function createScopedVisibilityBinding(toolId, toolbarContext) {
3
9
  const fullToolId = createScopedToolId(toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
4
10
  return {
5
11
  fullToolId,
6
- isActive: () => toolbarContext.isToolVisible(fullToolId),
12
+ isActive: () => toolbarContext.isToolVisible(toolId),
7
13
  subscribeActive: (callback) => {
8
14
  if (!toolbarContext.subscribeVisibility)
9
15
  return () => { };
10
16
  return toolbarContext.subscribeVisibility(() => {
11
- callback(toolbarContext.isToolVisible(fullToolId));
17
+ callback(toolbarContext.isToolVisible(toolId));
12
18
  });
13
19
  },
14
20
  };
@@ -1,19 +1,15 @@
1
1
  /**
2
2
  * Headless host for capabilities that render into a renderer's surfaces.
3
3
  *
4
- * The interface deliberately exposes only current input, a two-boolean snapshot,
5
- * and teardown. Discovery, policy/catalog invalidation, content resolution, lazy
4
+ * The interface exposes only current input, a two-boolean snapshot, and
5
+ * teardown. Discovery, policy/catalog invalidation, content resolution, lazy
6
6
  * loading, DOM reconciliation, error isolation, and registry observation stay
7
7
  * inside this module. Svelte callers are geometry adapters over this seam.
8
8
  *
9
- * It lives here rather than in `section-player`, where it was written, because a
10
- * second renderer now opens a surface: the annotation toolbar hosts the
11
- * capabilities that act on a text selection. Two copies of mount/reconcile/
12
- * registry-observation would drift, and the drift would be invisible until one
13
- * renderer stopped honouring the grant-AND-content rule. Nothing about the module
14
- * was section-shaped — it already imported only from this package — so the move
15
- * is a relocation, not a rewrite. The one thing that *was* section-shaped is the
16
- * name it reported errors under, which is now {@link ToolSurfaceHostOptions.hostLabel}.
9
+ * Every renderer that opens a surface shares this one host, so each honours the
10
+ * grant-AND-content rule the same way: the section player's cards and the
11
+ * annotation toolbar's selection surface. Errors are reported under
12
+ * {@link ToolSurfaceHostOptions.hostLabel}.
17
13
  */
18
14
  import type { CatalogOwnerContext } from "../services/catalog-owner.js";
19
15
  import type { ToolRegistry, ToolSurfaceServices } from "../services/ToolRegistry.js";
@@ -1,23 +1,33 @@
1
1
  /**
2
2
  * Headless host for capabilities that render into a renderer's surfaces.
3
3
  *
4
- * The interface deliberately exposes only current input, a two-boolean snapshot,
5
- * and teardown. Discovery, policy/catalog invalidation, content resolution, lazy
4
+ * The interface exposes only current input, a two-boolean snapshot, and
5
+ * teardown. Discovery, policy/catalog invalidation, content resolution, lazy
6
6
  * loading, DOM reconciliation, error isolation, and registry observation stay
7
7
  * inside this module. Svelte callers are geometry adapters over this seam.
8
8
  *
9
- * It lives here rather than in `section-player`, where it was written, because a
10
- * second renderer now opens a surface: the annotation toolbar hosts the
11
- * capabilities that act on a text selection. Two copies of mount/reconcile/
12
- * registry-observation would drift, and the drift would be invisible until one
13
- * renderer stopped honouring the grant-AND-content rule. Nothing about the module
14
- * was section-shaped — it already imported only from this package — so the move
15
- * is a relocation, not a rewrite. The one thing that *was* section-shaped is the
16
- * name it reported errors under, which is now {@link ToolSurfaceHostOptions.hostLabel}.
9
+ * Every renderer that opens a surface shares this one host, so each honours the
10
+ * grant-AND-content rule the same way: the section player's cards and the
11
+ * annotation toolbar's selection surface. Errors are reported under
12
+ * {@link ToolSurfaceHostOptions.hostLabel}.
17
13
  */
18
14
  import { isHostDeniedFeature } from "../policy/core/feature-decision.js";
19
15
  import { toFrameworkErrorModel } from "../services/framework-error.js";
20
16
  import { resolveContentCapabilities } from "./content-capability-resolution.js";
17
+ /**
18
+ * The scope an item's content asks feature policy with, which brings in the
19
+ * item's settings; other owners ask unscoped.
20
+ */
21
+ function itemFeatureScope(owner) {
22
+ if (owner.ownerKind !== "itemModel")
23
+ return undefined;
24
+ return {
25
+ level: "item",
26
+ scopeId: owner.canonicalItemId || owner.itemId,
27
+ itemId: owner.itemId,
28
+ canonicalItemId: owner.canonicalItemId,
29
+ };
30
+ }
21
31
  const SECTION_POLICY_LEVELS = ["section", "item", "passage"];
22
32
  function stableSerializableJson(value) {
23
33
  const seen = new Set();
@@ -33,12 +43,6 @@ function stableSerializableJson(value) {
33
43
  if (typeof current === "undefined") {
34
44
  return undefined;
35
45
  }
36
- if (typeof current === "function" || typeof current === "symbol") {
37
- throw new TypeError(`${path} is not JSON-serializable`);
38
- }
39
- if (typeof current === "bigint") {
40
- throw new TypeError(`${path} is not JSON-serializable`);
41
- }
42
46
  if (typeof current !== "object") {
43
47
  throw new TypeError(`${path} is not JSON-serializable`);
44
48
  }
@@ -112,7 +116,7 @@ function contextSignature(context) {
112
116
  try {
113
117
  return stableSerializableJson({
114
118
  toolId: context.toolId,
115
- featureId: context.featureId,
119
+ granted: context.granted,
116
120
  surface: context.surface,
117
121
  parameters: context.parameters ?? null,
118
122
  content: context.content ?? null,
@@ -235,26 +239,22 @@ export function createToolSurfaceHost(onSnapshot, options) {
235
239
  if (current.scope.kind !== "content")
236
240
  return null;
237
241
  const coordinator = current.services.toolkitCoordinator;
242
+ const featureScope = itemFeatureScope(current.scope.ownerContext);
238
243
  const [resolved] = resolveContentCapabilities({
239
244
  registrations: [registration],
240
245
  catalogs,
241
- // One decision per feature id, in the rule's three states. The scan across
242
- // a capability's support ids, the gate-only probe of its tool id, and
243
- // denial's precedence over both a grant and `resolvesWithoutGrant` live in
244
- // the rule, so this host and print cannot answer differently. All this
245
- // adapter owns is reading a `FeaturePolicyDecision`: `granted` is not
246
- // enough on its own, because a host gate and an unconfigured feature are
247
- // both `granted: false` and only one of them may be reopened by content.
248
- policyFor: (featureId) => {
249
- const decision = coordinator?.decideFeaturePolicy?.(featureId);
246
+ // One decision per support id, in the rule's three states. Denial's
247
+ // precedence over both a grant and `resolvesWithoutGrant` lives in the
248
+ // rule, so this host and print cannot answer differently. All this adapter
249
+ // owns is reading a `FeaturePolicyDecision`: `granted` is not enough on its
250
+ // own, because a host gate and an unconfigured feature are both
251
+ // `granted: false` and only one of them may be reopened by content.
252
+ policyFor: (supportId) => {
253
+ const decision = coordinator?.decideFeaturePolicy?.(supportId, featureScope);
250
254
  if (isHostDeniedFeature(decision))
251
255
  return { outcome: "denied" };
252
256
  if (decision?.granted === true) {
253
- return {
254
- outcome: "granted",
255
- featureId,
256
- parameters: decision.parameters,
257
- };
257
+ return { outcome: "granted", parameters: decision.parameters };
258
258
  }
259
259
  return { outcome: "silent" };
260
260
  },
@@ -281,7 +281,7 @@ export function createToolSurfaceHost(onSnapshot, options) {
281
281
  }
282
282
  const context = {
283
283
  toolId: registration.toolId,
284
- featureId: resolved.featureId,
284
+ granted: resolved.granted,
285
285
  surface: current.surface,
286
286
  parameters: resolved.parameters,
287
287
  content: resolved.content,
@@ -303,26 +303,19 @@ export function createToolSurfaceHost(onSnapshot, options) {
303
303
  const coordinator = current.services.toolkitCoordinator;
304
304
  if (!coordinator)
305
305
  return null;
306
- const supportIds = registration.pnpSupportIds?.length
307
- ? registration.pnpSupportIds
308
- : [registration.toolId];
309
- let featureId = "";
306
+ let granted = false;
310
307
  let parameters;
311
308
  try {
312
309
  if (registration.activation === "region") {
313
- for (const supportId of supportIds) {
314
- const decision = coordinator.decideFeaturePolicy?.(supportId);
315
- if (decision?.granted !== true)
316
- continue;
317
- featureId = supportId;
318
- parameters = decision.parameters;
319
- break;
320
- }
321
- if (!featureId)
310
+ const decision = coordinator.decideFeaturePolicy?.(registration.toolId);
311
+ if (decision?.granted !== true)
322
312
  return null;
313
+ granted = true;
314
+ parameters = decision.parameters;
323
315
  }
324
316
  else {
325
317
  const scopeId = current.scope.sectionId || "*";
318
+ let placed = false;
326
319
  for (const level of SECTION_POLICY_LEVELS) {
327
320
  const decision = coordinator.decideToolPolicy({
328
321
  level,
@@ -336,11 +329,14 @@ export function createToolSurfaceHost(onSnapshot, options) {
336
329
  const entry = decision.visibleTools.find((candidate) => candidate.toolId === registration.toolId);
337
330
  if (!entry)
338
331
  continue;
339
- featureId = supportIds[0] ?? registration.toolId;
340
- parameters = entry.settings;
332
+ // Placement admits the tool; only a support, requirement or
333
+ // test-administration override grants it.
334
+ placed = true;
335
+ granted = entry.required || entry.alwaysAvailable;
336
+ parameters = entry.parameters;
341
337
  break;
342
338
  }
343
- if (!featureId)
339
+ if (!placed)
344
340
  return null;
345
341
  }
346
342
  }
@@ -350,7 +346,7 @@ export function createToolSurfaceHost(onSnapshot, options) {
350
346
  }
351
347
  const context = {
352
348
  toolId: registration.toolId,
353
- featureId,
349
+ granted,
354
350
  surface: current.surface,
355
351
  parameters,
356
352
  services: current.services,
@@ -463,7 +459,6 @@ export function createToolSurfaceHost(onSnapshot, options) {
463
459
  }
464
460
  }
465
461
  report(toolId, "render", `Tool "${toolId}" failed to render into the "${current.surface}" surface.`, error);
466
- return;
467
462
  }
468
463
  }
469
464
  function reconcile() {
@@ -10,26 +10,16 @@ export type ToolComponentFactory = (args: {
10
10
  export type ToolComponentFactoryMap = Record<string, ToolComponentFactory>;
11
11
  export interface ToolComponentOverrides {
12
12
  toolTagMap?: Partial<ToolTagMap>;
13
- toolComponentFactory?: ToolComponentFactory;
14
13
  toolComponentFactories?: Partial<ToolComponentFactoryMap>;
15
14
  }
16
15
  /**
17
- * Resolve the element tag for a tool from the overrides in play.
18
- *
19
- * There is no built-in map to fall back to. One lived here, naming eleven
20
- * capabilities, and a core module holding that catalogue is why a host could not
21
- * add a twelfth without editing this package — the map was overridable, but the
22
- * default was core-resident. The packaged map is `PACKAGED_TOOL_TAG_MAP` in
23
- * `@pie-players/pie-default-tool-loaders`, installed onto a registry through
16
+ * Resolve the element tag for a tool from the overrides in play. Core holds no
17
+ * tag map; the packaged one is `PACKAGED_TOOL_TAG_MAP` in
18
+ * `@pie-players/pie-default-tool-loaders`, installed through
24
19
  * `ToolRegistry.setComponentOverrides`.
25
20
  *
26
- * An unmapped toolId falls through to itself, which is only a valid tag if the
27
- * host's tool id already looks like one. Every packaged id is a single camelCase
28
- * word, so in practice an unmapped packaged tool throws here rather than
29
- * rendering a bogus element — the failure names the missing mapping, because
30
- * "custom element names must include a hyphen" is a true statement about the
31
- * wrong thing.
21
+ * An unmapped toolId is its own tag when it contains a hyphen. Otherwise this
22
+ * throws an error naming the missing mapping.
32
23
  */
33
24
  export declare const resolveToolTag: (toolId: string, overrides?: ToolComponentOverrides) => string;
34
25
  export declare const createToolElement: (toolId: string, context: ToolContext, toolbarContext: ToolbarContext, overrides?: ToolComponentOverrides) => HTMLElement;
35
- export declare const toToolIdFromTag: (tagName: string, overrides?: ToolComponentOverrides) => string | undefined;
@@ -1,20 +1,12 @@
1
1
  import { validateCustomElementTag } from "@pie-players/pie-players-shared/pie/tag-names";
2
2
  /**
3
- * Resolve the element tag for a tool from the overrides in play.
4
- *
5
- * There is no built-in map to fall back to. One lived here, naming eleven
6
- * capabilities, and a core module holding that catalogue is why a host could not
7
- * add a twelfth without editing this package — the map was overridable, but the
8
- * default was core-resident. The packaged map is `PACKAGED_TOOL_TAG_MAP` in
9
- * `@pie-players/pie-default-tool-loaders`, installed onto a registry through
3
+ * Resolve the element tag for a tool from the overrides in play. Core holds no
4
+ * tag map; the packaged one is `PACKAGED_TOOL_TAG_MAP` in
5
+ * `@pie-players/pie-default-tool-loaders`, installed through
10
6
  * `ToolRegistry.setComponentOverrides`.
11
7
  *
12
- * An unmapped toolId falls through to itself, which is only a valid tag if the
13
- * host's tool id already looks like one. Every packaged id is a single camelCase
14
- * word, so in practice an unmapped packaged tool throws here rather than
15
- * rendering a bogus element — the failure names the missing mapping, because
16
- * "custom element names must include a hyphen" is a true statement about the
17
- * wrong thing.
8
+ * An unmapped toolId is its own tag when it contains a hyphen. Otherwise this
9
+ * throws an error naming the missing mapping.
18
10
  */
19
11
  export const resolveToolTag = (toolId, overrides) => {
20
12
  const mapped = overrides?.toolTagMap?.[toolId];
@@ -26,14 +18,8 @@ export const resolveToolTag = (toolId, overrides) => {
26
18
  const createDefaultToolElement = (tagName) => document.createElement(tagName);
27
19
  export const createToolElement = (toolId, context, toolbarContext, overrides) => {
28
20
  const tagName = resolveToolTag(toolId, overrides);
29
- const factoryForTool = overrides?.toolComponentFactories?.[toolId];
30
- const factory = factoryForTool ?? overrides?.toolComponentFactory;
21
+ const factory = overrides?.toolComponentFactories?.[toolId];
31
22
  return factory
32
23
  ? factory({ toolId, tagName, context, toolbarContext })
33
24
  : createDefaultToolElement(tagName);
34
25
  };
35
- export const toToolIdFromTag = (tagName, overrides) => {
36
- const validTag = validateCustomElementTag(tagName, "tool component tag");
37
- const map = overrides?.toolTagMap ?? {};
38
- return Object.entries(map).find(([, tag]) => tag === validTag)?.[0];
39
- };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Structural equality for plain data: host-supplied policy inputs and session
3
+ * payloads.
4
+ *
5
+ * Plain objects compare by own enumerable keys in any order, a key holding
6
+ * `undefined` matching an absent one, and arrays compare by position. Every
7
+ * other value compares with `Object.is`, so class instances, functions and
8
+ * maps are equal only to themselves. A pair already under comparison counts as
9
+ * equal, which keeps a cyclic value from recursing forever.
10
+ */
11
+ export declare function structurallyEqual(a: unknown, b: unknown): boolean;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Structural equality for plain data: host-supplied policy inputs and session
3
+ * payloads.
4
+ *
5
+ * Plain objects compare by own enumerable keys in any order, a key holding
6
+ * `undefined` matching an absent one, and arrays compare by position. Every
7
+ * other value compares with `Object.is`, so class instances, functions and
8
+ * maps are equal only to themselves. A pair already under comparison counts as
9
+ * equal, which keeps a cyclic value from recursing forever.
10
+ */
11
+ export function structurallyEqual(a, b) {
12
+ return compare(a, b, new WeakMap());
13
+ }
14
+ function compare(a, b, inProgress) {
15
+ if (Object.is(a, b))
16
+ return true;
17
+ const aIsArray = Array.isArray(a);
18
+ if (aIsArray !== Array.isArray(b))
19
+ return false;
20
+ if (!aIsArray && (!isPlainObject(a) || !isPlainObject(b)))
21
+ return false;
22
+ const left = a;
23
+ const right = b;
24
+ if (aIsArray && a.length !== b.length) {
25
+ return false;
26
+ }
27
+ let partners = inProgress.get(left);
28
+ if (partners?.has(right))
29
+ return true;
30
+ if (!partners) {
31
+ partners = new Set();
32
+ inProgress.set(left, partners);
33
+ }
34
+ partners.add(right);
35
+ const keys = new Set([...Object.keys(left), ...Object.keys(right)]);
36
+ for (const key of keys) {
37
+ if (!compare(left[key], right[key], inProgress))
38
+ return false;
39
+ }
40
+ return true;
41
+ }
42
+ function isPlainObject(value) {
43
+ if (value === null || typeof value !== "object")
44
+ return false;
45
+ const proto = Object.getPrototypeOf(value);
46
+ return proto === Object.prototype || proto === null;
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-players/pie-assessment-toolkit",
3
- "version": "0.3.74",
3
+ "version": "1.0.0-beta.0",
4
4
  "type": "module",
5
5
  "description": "PIE assessment toolkit: composable services + reference implementation for assessment players and tool coordination",
6
6
  "license": "MIT",
@@ -21,13 +21,13 @@
21
21
  "types": "./dist/index.d.ts",
22
22
  "import": "./dist/index.js"
23
23
  },
24
- "./tools/client": {
25
- "types": "./dist/tools/client.d.ts",
26
- "import": "./dist/tools/client.js"
24
+ "./tools/registration": {
25
+ "types": "./dist/tools/registration.d.ts",
26
+ "import": "./dist/tools/registration.js"
27
27
  },
28
- "./tools/internal": {
29
- "types": "./dist/tools/internal.d.ts",
30
- "import": "./dist/tools/internal.js"
28
+ "./components/item-scope-element": {
29
+ "types": "./dist/components/item-scope-element.d.ts",
30
+ "import": "./dist/components/item-scope-element.js"
31
31
  },
32
32
  "./components/item-toolbar-element": {
33
33
  "types": "./dist/components/item-toolbar-element.d.ts",
@@ -45,54 +45,40 @@
45
45
  "types": "./dist/services/AccessibilityCatalogResolver.d.ts",
46
46
  "import": "./dist/services/AccessibilityCatalogResolver.js"
47
47
  },
48
- "./services/pnp-standard-features": {
49
- "types": "./dist/services/pnp-standard-features.d.ts",
50
- "import": "./dist/services/pnp-standard-features.js"
51
- },
52
- "./services/I18nService": {
53
- "types": "./dist/services/I18nService.d.ts",
54
- "import": "./dist/services/I18nService.js"
55
- },
56
48
  "./runtime/engine": {
57
49
  "types": "./dist/runtime/engine.d.ts",
58
50
  "import": "./dist/runtime/engine.js"
59
51
  },
60
- "./runtime/internal": {
61
- "types": "./dist/runtime/internal.d.ts",
62
- "import": "./dist/runtime/internal.js"
63
- },
64
52
  "./policy/engine": {
65
53
  "types": "./dist/policy/engine.d.ts",
66
54
  "import": "./dist/policy/engine.js"
67
- },
68
- "./policy/internal": {
69
- "types": "./dist/policy/internal.d.ts",
70
- "import": "./dist/policy/internal.js"
71
55
  }
72
56
  },
57
+ "customElements": "custom-elements.json",
73
58
  "files": [
74
59
  "dist",
60
+ "custom-elements.json",
75
61
  "README.md"
76
62
  ],
77
63
  "scripts": {
78
64
  "build": "rm -rf dist tsconfig.tsbuildinfo && tsc -p tsconfig.json && bun ./scripts/build-ce-components.mjs",
79
65
  "dev": "tsc -p tsconfig.json --watch",
80
- "typecheck": "tsc -p tsconfig.json --noEmit",
66
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.tests.json",
81
67
  "lint": "biome lint .",
82
68
  "check": "svelte-check --tsconfig ./tsconfig.json",
83
69
  "test": "bun test"
84
70
  },
85
71
  "dependencies": {
86
- "@pie-players/pie-calculator": "0.3.74",
87
- "@pie-players/pie-context": "0.3.74",
88
- "@pie-players/pie-players-shared": "0.3.74",
89
- "@pie-players/pie-tts": "0.3.74",
72
+ "@pie-players/pie-calculator": "1.0.0-beta.0",
73
+ "@pie-players/pie-context": "1.0.0-beta.0",
74
+ "@pie-players/pie-players-shared": "1.0.0-beta.0",
75
+ "@pie-players/pie-tts": "1.0.0-beta.0",
90
76
  "speech-rule-engine": "5.0.0-rc.4"
91
77
  },
92
78
  "devDependencies": {
93
79
  "@biomejs/biome": "^2.5.15",
94
80
  "@happy-dom/global-registrator": "^20.14.5",
95
- "@pie-players/tts-client-server": "0.3.74",
81
+ "@pie-players/tts-client-server": "1.0.0-beta.0",
96
82
  "svelte": "^5.57.1",
97
83
  "svelte-check": "^4.7.6",
98
84
  "typescript": "^5.9.3"
@@ -1,49 +0,0 @@
1
- import type { TestAttemptSession } from "../TestSession.js";
2
- export interface PieBackendActivityItemRef {
3
- identifier?: string;
4
- item?: {
5
- id?: string;
6
- identifier?: string;
7
- };
8
- }
9
- export interface PieBackendActivityDefinition {
10
- id?: string;
11
- identifier?: string;
12
- assessmentId?: string;
13
- assessmentItemRefs?: PieBackendActivityItemRef[];
14
- }
15
- export interface PieBackendActivitySession {
16
- id?: string;
17
- activitySessionId?: string;
18
- startedAt?: string;
19
- updatedAt?: string;
20
- completedAt?: string;
21
- currentItemIndex?: number;
22
- currentSectionIdentifier?: string;
23
- visitedItemIdentifiers?: string[];
24
- itemSessions?: Record<string, unknown>;
25
- }
26
- export interface MapActivityToTestAttemptSessionArgs {
27
- activityDefinition?: PieBackendActivityDefinition | null;
28
- activitySession?: PieBackendActivitySession | null;
29
- itemRefs?: PieBackendActivityItemRef[];
30
- itemSessionsByItemIdentifier?: Record<string, unknown>;
31
- assessmentId?: string;
32
- testAttemptSessionIdentifier?: string;
33
- }
34
- export interface ActivitySessionPatchPayload {
35
- activitySession: {
36
- id: string;
37
- startedAt?: string;
38
- updatedAt?: string;
39
- completedAt?: string;
40
- currentItemIndex: number;
41
- currentSectionIdentifier?: string;
42
- visitedItemIdentifiers: string[];
43
- itemSessions: Record<string, unknown>;
44
- };
45
- }
46
- export declare function mapActivityToTestAttemptSession(args: MapActivityToTestAttemptSessionArgs): TestAttemptSession;
47
- export declare function toItemSessionsRecord(testAttemptSession: TestAttemptSession): Record<string, unknown>;
48
- export declare function buildActivitySessionPatchFromTestAttemptSession(testAttemptSession: TestAttemptSession): ActivitySessionPatchPayload;
49
- export declare function buildActivitySessionItemUpdate(testAttemptSession: TestAttemptSession, itemIdentifier: string): ActivitySessionPatchPayload;
@@ -1,138 +0,0 @@
1
- function nowIso() {
2
- return new Date().toISOString();
3
- }
4
- function getItemIdentifier(itemRef) {
5
- return (itemRef.identifier || itemRef.item?.identifier || itemRef.item?.id || null);
6
- }
7
- function resolveItemIdentifiers(args) {
8
- const refs = args.itemRefs || args.activityDefinition?.assessmentItemRefs || [];
9
- const identifiers = refs
10
- .map((itemRef) => getItemIdentifier(itemRef))
11
- .filter((itemIdentifier) => !!itemIdentifier);
12
- return Array.from(new Set(identifiers));
13
- }
14
- function resolveAssessmentId(args) {
15
- return (args.assessmentId ||
16
- args.activityDefinition?.assessmentId ||
17
- args.activityDefinition?.identifier ||
18
- args.activityDefinition?.id ||
19
- "unknown-assessment");
20
- }
21
- function resolveTestAttemptSessionIdentifier(args, assessmentId) {
22
- return (args.testAttemptSessionIdentifier ||
23
- args.activitySession?.activitySessionId ||
24
- args.activitySession?.id ||
25
- `tas_${assessmentId}`);
26
- }
27
- function resolveBackendItemSessions(args) {
28
- return {
29
- ...(args.activitySession?.itemSessions || {}),
30
- ...(args.itemSessionsByItemIdentifier || {}),
31
- };
32
- }
33
- function mapItemSessions(itemIdentifiers, backendItemSessions) {
34
- return itemIdentifiers.reduce((acc, itemIdentifier) => {
35
- const rawSession = backendItemSessions[itemIdentifier];
36
- if (!rawSession)
37
- return acc;
38
- const pieSessionId = typeof rawSession.id === "string" ? rawSession.id : undefined;
39
- const attemptCount = typeof rawSession.attemptCount === "number" &&
40
- rawSession.attemptCount > 0
41
- ? rawSession.attemptCount
42
- : pieSessionId
43
- ? 1
44
- : 0;
45
- const isCompleted = typeof rawSession.isCompleted === "boolean"
46
- ? rawSession.isCompleted
47
- : Boolean(rawSession.complete);
48
- const startedAt = typeof rawSession.startedAt === "string"
49
- ? rawSession.startedAt
50
- : undefined;
51
- const updatedAt = typeof rawSession.updatedAt === "string"
52
- ? rawSession.updatedAt
53
- : undefined;
54
- const completedAt = typeof rawSession.completedAt === "string"
55
- ? rawSession.completedAt
56
- : undefined;
57
- acc[itemIdentifier] = {
58
- itemIdentifier,
59
- pieSessionId,
60
- attemptCount,
61
- isCompleted,
62
- startedAt,
63
- updatedAt,
64
- completedAt,
65
- session: rawSession,
66
- };
67
- return acc;
68
- }, {});
69
- }
70
- export function mapActivityToTestAttemptSession(args) {
71
- const assessmentId = resolveAssessmentId(args);
72
- const itemIdentifiers = resolveItemIdentifiers(args);
73
- const testAttemptSessionIdentifier = resolveTestAttemptSessionIdentifier(args, assessmentId);
74
- const backendItemSessions = resolveBackendItemSessions(args);
75
- const now = nowIso();
76
- const startedAt = args.activitySession?.startedAt || now;
77
- const updatedAt = args.activitySession?.updatedAt || startedAt;
78
- return {
79
- version: 1,
80
- testAttemptSessionIdentifier,
81
- assessmentId,
82
- startedAt,
83
- updatedAt,
84
- completedAt: args.activitySession?.completedAt,
85
- navigationState: {
86
- currentItemIndex: args.activitySession?.currentItemIndex ?? -1,
87
- visitedItemIdentifiers: [
88
- ...(args.activitySession?.visitedItemIdentifiers || []),
89
- ],
90
- currentSectionIdentifier: args.activitySession?.currentSectionIdentifier,
91
- },
92
- realization: {
93
- seed: testAttemptSessionIdentifier,
94
- itemIdentifiers,
95
- },
96
- itemSessions: mapItemSessions(itemIdentifiers, backendItemSessions),
97
- };
98
- }
99
- export function toItemSessionsRecord(testAttemptSession) {
100
- return Object.entries(testAttemptSession.itemSessions).reduce((acc, [itemIdentifier, itemSession]) => {
101
- if (itemSession.session) {
102
- acc[itemIdentifier] = itemSession.session;
103
- }
104
- return acc;
105
- }, {});
106
- }
107
- export function buildActivitySessionPatchFromTestAttemptSession(testAttemptSession) {
108
- return {
109
- activitySession: {
110
- id: testAttemptSession.testAttemptSessionIdentifier,
111
- startedAt: testAttemptSession.startedAt,
112
- updatedAt: testAttemptSession.updatedAt,
113
- completedAt: testAttemptSession.completedAt,
114
- currentItemIndex: testAttemptSession.navigationState.currentItemIndex,
115
- currentSectionIdentifier: testAttemptSession.navigationState.currentSectionIdentifier,
116
- visitedItemIdentifiers: [
117
- ...testAttemptSession.navigationState.visitedItemIdentifiers,
118
- ],
119
- itemSessions: toItemSessionsRecord(testAttemptSession),
120
- },
121
- };
122
- }
123
- export function buildActivitySessionItemUpdate(testAttemptSession, itemIdentifier) {
124
- const itemSession = testAttemptSession.itemSessions[itemIdentifier];
125
- return {
126
- activitySession: {
127
- id: testAttemptSession.testAttemptSessionIdentifier,
128
- currentItemIndex: testAttemptSession.navigationState.currentItemIndex,
129
- currentSectionIdentifier: testAttemptSession.navigationState.currentSectionIdentifier,
130
- visitedItemIdentifiers: [
131
- ...testAttemptSession.navigationState.visitedItemIdentifiers,
132
- ],
133
- itemSessions: itemSession?.session
134
- ? { [itemIdentifier]: itemSession.session }
135
- : {},
136
- },
137
- };
138
- }