@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
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Which policy inputs `<pie-assessment-toolkit>` forwards to the coordinator it
3
+ * owns.
4
+ *
5
+ * The toolkit forwards an input when its own value for it changes. A host
6
+ * driving the owned coordinator directly — an embedded toolkit's host binds its
7
+ * assessment from `runtime-ready` or `toolkit-ready` — keeps that binding until
8
+ * the toolkit's own value changes, so an unrelated re-run of the forwarding
9
+ * effect (a `tools` change, a coordinator rebuild trigger) cannot reset it. A
10
+ * coordinator not forwarded to yet is newly built and holds no inputs, so it
11
+ * receives only the inputs that are set.
12
+ */
13
+ import type { AssessmentEntity } from "@pie-players/pie-players-shared/types";
14
+ import type { PnpEnforcementMode } from "../policy/core/ToolPolicyEngine.js";
15
+ export interface ForwardedPolicyInputs {
16
+ pnpEnforcement: PnpEnforcementMode | null;
17
+ assessment: AssessmentEntity | null;
18
+ }
19
+ /**
20
+ * The inputs to forward, in apply order: the enforcement override first, so
21
+ * binding the assessment never resolves auto-mode against a stale override.
22
+ * `previous` is what was last forwarded to the same coordinator, or `null` for
23
+ * a coordinator not forwarded to yet.
24
+ */
25
+ export declare function policyInputsToForward(previous: ForwardedPolicyInputs | null, next: ForwardedPolicyInputs): Array<keyof ForwardedPolicyInputs>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Which policy inputs `<pie-assessment-toolkit>` forwards to the coordinator it
3
+ * owns.
4
+ *
5
+ * The toolkit forwards an input when its own value for it changes. A host
6
+ * driving the owned coordinator directly — an embedded toolkit's host binds its
7
+ * assessment from `runtime-ready` or `toolkit-ready` — keeps that binding until
8
+ * the toolkit's own value changes, so an unrelated re-run of the forwarding
9
+ * effect (a `tools` change, a coordinator rebuild trigger) cannot reset it. A
10
+ * coordinator not forwarded to yet is newly built and holds no inputs, so it
11
+ * receives only the inputs that are set.
12
+ */
13
+ /**
14
+ * The inputs to forward, in apply order: the enforcement override first, so
15
+ * binding the assessment never resolves auto-mode against a stale override.
16
+ * `previous` is what was last forwarded to the same coordinator, or `null` for
17
+ * a coordinator not forwarded to yet.
18
+ */
19
+ export function policyInputsToForward(previous, next) {
20
+ const order = [
21
+ "pnpEnforcement",
22
+ "assessment",
23
+ ];
24
+ return order.filter((key) => previous ? !Object.is(previous[key], next[key]) : next[key] !== null);
25
+ }
@@ -1,3 +1,5 @@
1
+ import type { SessionCommitReason } from "@pie-players/pie-players-shared/pie";
2
+ import type { ItemSettings } from "@pie-players/pie-players-shared/types";
1
3
  import type { MediaTimeSource } from "@pie-players/pie-players-shared/timed-media";
2
4
  export declare const PIE_REGISTER_EVENT = "pie-register";
3
5
  export declare const PIE_UNREGISTER_EVENT = "pie-unregister";
@@ -14,13 +16,25 @@ export interface RuntimeRegistrationDetail {
14
16
  canonicalItemId?: string;
15
17
  contentKind?: string;
16
18
  item?: unknown;
19
+ /**
20
+ * An item's policy settings, which govern decisions scoped to the item; see
21
+ * `ToolkitCoordinatorApi.registerItemSettings`.
22
+ */
23
+ settings?: ItemSettings;
17
24
  element: HTMLElement;
25
+ /**
26
+ * The runtime the shell found through `assessmentToolkitHostRuntimeContext`.
27
+ * A toolkit claims an event carrying it only when the id is its own.
28
+ */
29
+ runtimeId?: string;
18
30
  }
19
31
  export interface ItemSessionChangedDetail {
20
32
  itemId: string;
21
33
  canonicalItemId?: string;
22
34
  session: unknown;
23
35
  sourceRuntimeId?: string;
36
+ /** Set when the change is a commit at a teardown, navigation or page-hidden seam. */
37
+ sessionCommitReason?: SessionCommitReason;
24
38
  }
25
39
  export interface InternalItemSessionChangedDetail {
26
40
  itemId: string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Whether the toolkit running as `runtimeId` claims a shell's event. A shell
3
+ * scope puts the id of the runtime that answered it in `detail.runtimeId`, and
4
+ * only that runtime claims the event. An event without one, from a shell that
5
+ * dispatches on its own, is claimed when `isLocalTarget` resolves its target
6
+ * to this runtime.
7
+ */
8
+ export declare function isRuntimeEventClaimed(event: Event, runtimeId: string, isLocalTarget: (target: EventTarget | null) => boolean): boolean;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Whether the toolkit running as `runtimeId` claims a shell's event. A shell
3
+ * scope puts the id of the runtime that answered it in `detail.runtimeId`, and
4
+ * only that runtime claims the event. An event without one, from a shell that
5
+ * dispatches on its own, is claimed when `isLocalTarget` resolves its target
6
+ * to this runtime.
7
+ */
8
+ export function isRuntimeEventClaimed(event, runtimeId, isLocalTarget) {
9
+ const addressedTo = event
10
+ .detail?.runtimeId;
11
+ if (typeof addressedTo === "string" && addressedTo !== "") {
12
+ return addressedTo === runtimeId;
13
+ }
14
+ return isLocalTarget(event.target);
15
+ }
@@ -0,0 +1,45 @@
1
+ import type { ShellContextKind } from "../context/assessment-toolkit-context.js";
2
+ /**
3
+ * `section`: the shell is its content's only channel to the section. The
4
+ * player's `session-changed`, `load-complete` and `player-error` stop at the
5
+ * shell and travel on as the runtime's internal events, with an item's
6
+ * response changes also announced as `item-session-changed`.
7
+ *
8
+ * `plain`: the host owns the player and listens to it, so the player's events
9
+ * pass through untouched. The runtime still hears that the content loaded or
10
+ * failed, which a section bound later replays; sessions stay with the host.
11
+ */
12
+ export type ShellEventBridgeMode = "section" | "plain";
13
+ export interface ShellEventBridgeIdentity {
14
+ itemId: string;
15
+ canonicalItemId?: string;
16
+ contentKind?: string;
17
+ }
18
+ export interface ShellEventBridgeOptions {
19
+ /** The shell element, where the player's events arrive and leave from. */
20
+ host: HTMLElement;
21
+ kind: ShellContextKind;
22
+ /** Read as each event arrives, so a prop change needs no rebinding. */
23
+ identity: () => ShellEventBridgeIdentity;
24
+ /** Read as each event arrives. */
25
+ mode: () => ShellEventBridgeMode;
26
+ /** Sends an event addressed to the shell's runtime. */
27
+ send: (type: string, detail: object) => void;
28
+ }
29
+ export interface ShellEventBridge {
30
+ /**
31
+ * Gives an item's pending session one last chance to reach the section, then
32
+ * stops listening. The commit runs while the player is still inside the
33
+ * shell, so its `session-changed` arrives at the bridge before it is unbound.
34
+ * The shell has usually left the document by then; `send` delivers the
35
+ * forwarded session on the runtime's element.
36
+ */
37
+ disconnect: () => void;
38
+ }
39
+ /**
40
+ * A shell's translation of its player's events into the runtime's, shared by
41
+ * `<pie-item-scope>` and `<pie-passage-shell>`. The dedupe
42
+ * state lives as long as the bridge, so a prop change does not forget what was
43
+ * forwarded.
44
+ */
45
+ export declare function createShellEventBridge(options: ShellEventBridgeOptions): ShellEventBridge;
@@ -0,0 +1,127 @@
1
+ import { commitPendingSessions, createPieLogger, normalizeItemSessionChange, } from "@pie-players/pie-players-shared";
2
+ import { PIE_INTERNAL_CONTENT_LOADED_EVENT, PIE_INTERNAL_ITEM_PLAYER_ERROR_EVENT, PIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT, PIE_ITEM_SESSION_CHANGED_EVENT, } from "./registration-events.js";
3
+ import { dispatchCrossBoundaryEvent } from "./tool-host-contract.js";
4
+ /**
5
+ * Elements repeat themselves, a `complete` echo most often, so a session event
6
+ * is forwarded only when it differs from the last one, apart from when and
7
+ * through which runtime it was stamped.
8
+ */
9
+ function sessionEventFingerprint(detail) {
10
+ const semanticDetail = detail && typeof detail === "object"
11
+ ? { ...detail }
12
+ : detail;
13
+ if (semanticDetail && typeof semanticDetail === "object") {
14
+ delete semanticDetail.timestamp;
15
+ delete semanticDetail.sourceRuntimeId;
16
+ }
17
+ try {
18
+ return JSON.stringify(semanticDetail);
19
+ }
20
+ catch {
21
+ return String(semanticDetail);
22
+ }
23
+ }
24
+ const isCommit = (detail) => Boolean(detail &&
25
+ typeof detail === "object" &&
26
+ detail.sessionCommitReason);
27
+ /**
28
+ * A shell's translation of its player's events into the runtime's, shared by
29
+ * `<pie-item-scope>` and `<pie-passage-shell>`. The dedupe
30
+ * state lives as long as the bridge, so a prop change does not forget what was
31
+ * forwarded.
32
+ */
33
+ export function createShellEventBridge(options) {
34
+ const { host, kind, identity, mode, send } = options;
35
+ const logger = createPieLogger(host.localName || "pie-shell", () => false);
36
+ let lastForwardedFingerprint = "";
37
+ const forwardSession = (detail) => {
38
+ const { itemId, canonicalItemId } = identity();
39
+ if (!itemId)
40
+ return;
41
+ const internal = {
42
+ itemId,
43
+ session: detail,
44
+ };
45
+ // The runtime keeps item state in step from every change; the public
46
+ // stream carries responses only.
47
+ send(PIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT, internal);
48
+ const normalized = normalizeItemSessionChange({
49
+ itemId,
50
+ sessionDetail: detail,
51
+ });
52
+ if (normalized.intent === "metadata-only" || !normalized.session)
53
+ return;
54
+ const payload = {
55
+ itemId,
56
+ canonicalItemId: canonicalItemId || itemId,
57
+ session: normalized.session,
58
+ ...(normalized.sessionCommitReason
59
+ ? { sessionCommitReason: normalized.sessionCommitReason }
60
+ : {}),
61
+ };
62
+ dispatchCrossBoundaryEvent(host, PIE_ITEM_SESSION_CHANGED_EVENT, payload);
63
+ };
64
+ const onSessionChanged = (event) => {
65
+ if (mode() !== "section")
66
+ return;
67
+ event.stopPropagation();
68
+ // A passage carries no response: a passage id on the section's session
69
+ // stream names no item a host has.
70
+ if (kind !== "item")
71
+ return;
72
+ const detail = event.detail;
73
+ const fingerprint = sessionEventFingerprint(detail);
74
+ // A commit is the response's last chance to reach the section.
75
+ if (!isCommit(detail) && fingerprint === lastForwardedFingerprint)
76
+ return;
77
+ lastForwardedFingerprint = fingerprint;
78
+ forwardSession(detail);
79
+ };
80
+ const onLoadComplete = (event) => {
81
+ if (mode() === "section")
82
+ event.stopPropagation();
83
+ const { itemId, canonicalItemId, contentKind } = identity();
84
+ if (!itemId)
85
+ return;
86
+ const detail = {
87
+ itemId,
88
+ canonicalItemId: canonicalItemId || itemId,
89
+ contentKind,
90
+ detail: event.detail,
91
+ };
92
+ send(PIE_INTERNAL_CONTENT_LOADED_EVENT, detail);
93
+ };
94
+ const onPlayerError = (event) => {
95
+ if (mode() === "section")
96
+ event.stopPropagation();
97
+ const { itemId, canonicalItemId, contentKind } = identity();
98
+ if (!itemId)
99
+ return;
100
+ const detail = {
101
+ itemId,
102
+ canonicalItemId: canonicalItemId || itemId,
103
+ contentKind,
104
+ error: event.detail,
105
+ };
106
+ send(PIE_INTERNAL_ITEM_PLAYER_ERROR_EVENT, detail);
107
+ };
108
+ host.addEventListener("session-changed", onSessionChanged);
109
+ host.addEventListener("load-complete", onLoadComplete);
110
+ host.addEventListener("player-error", onPlayerError);
111
+ return {
112
+ disconnect: () => {
113
+ // An escape from the commit must not strand the listeners it needed, so
114
+ // the unbinding runs either way. A plain player commits its own.
115
+ try {
116
+ if (kind === "item" && mode() === "section") {
117
+ commitPendingSessions(host, { reason: "teardown", logger });
118
+ }
119
+ }
120
+ finally {
121
+ host.removeEventListener("session-changed", onSessionChanged);
122
+ host.removeEventListener("load-complete", onLoadComplete);
123
+ host.removeEventListener("player-error", onPlayerError);
124
+ }
125
+ },
126
+ };
127
+ }
@@ -0,0 +1,73 @@
1
+ import type { ItemSettings } from "@pie-players/pie-players-shared/types";
2
+ /**
3
+ * Registration dispatch for the shells, through their shell scope.
4
+ *
5
+ * Registration is a statement of fact to the runtime, and the runtime takes it
6
+ * literally: a `pie-register` makes the toolkit unregister and re-register the
7
+ * content's accessibility catalogs, re-run `sectionBinding.register`, and
8
+ * re-notify the section controller.
9
+ *
10
+ * A shell's effects re-run whenever its props are re-applied, which happens on
11
+ * every update of its parent card's template. Dispatching from such an effect
12
+ * (with `pie-unregister` in its cleanup) announces a teardown and rebuild of
13
+ * state that has not moved, leaves the content without catalogs between the
14
+ * two, and closes a feedback loop: a reader that re-renders on a catalog change
15
+ * re-applies the shell's props, which re-registers, which changes catalogs
16
+ * again, until Svelte abandons the update at its depth limit with the DOM
17
+ * half-applied — while the elements are all present, so assertions about the
18
+ * rendered output still pass.
19
+ *
20
+ * So the dispatcher keeps the last identity it announced and says nothing when
21
+ * the next one matches.
22
+ */
23
+ export type ShellRegistrationIdentity = {
24
+ kind: "item" | "passage";
25
+ host: HTMLElement;
26
+ itemId: string;
27
+ canonicalItemId: string;
28
+ contentKind: string;
29
+ item: unknown;
30
+ /** The item's policy settings, compared structurally like its catalogs. */
31
+ settings: ItemSettings | null;
32
+ };
33
+ /**
34
+ * The runtime a registration is addressed to: its id, and the element it
35
+ * listens on, which a shell whose host has left the document dispatches on.
36
+ */
37
+ export type ShellRuntimeAddress = {
38
+ runtimeId: string;
39
+ eventTarget: EventTarget;
40
+ };
41
+ /**
42
+ * Where a shell's event to `runtime` goes: from the shell host while it is in
43
+ * the document, so the event bubbles through the tree like any other, and on
44
+ * the runtime's own element once it is not.
45
+ */
46
+ export declare function shellEventTarget(host: HTMLElement, runtime: ShellRuntimeAddress | undefined): EventTarget;
47
+ export type ShellRegistrationDispatcher = {
48
+ /**
49
+ * Announce `identity` if it says anything new, and retire the live
50
+ * registration when there is nothing left to describe — a shell without a host
51
+ * or an id no longer stands for content, and leaving its registration behind
52
+ * would strand it in the runtime.
53
+ *
54
+ * Never dispatches `pie-unregister` before a re-register to the same
55
+ * runtime: both registration paths in the toolkit are keyed by element and
56
+ * replace what is there, so the unregister only ever created the gap. A
57
+ * registration moving to a different runtime is retired first, addressed
58
+ * to the runtime that holds it.
59
+ */
60
+ sync: (identity: ShellRegistrationIdentity | null, runtime?: ShellRuntimeAddress) => void;
61
+ /**
62
+ * Retire the live registration, replaying the identity and runtime it was
63
+ * made under rather than whatever the props say now — by the time a
64
+ * registration is retired the props may already describe its replacement,
65
+ * and unregistering under the new identity would leave the old one live.
66
+ * A host already out of the document retires on the runtime's element.
67
+ *
68
+ * Belongs in a teardown that runs on teardown only. Attaching it to an effect
69
+ * that re-runs on prop changes is what made the churn.
70
+ */
71
+ retire: () => void;
72
+ };
73
+ export declare function createShellRegistrationDispatcher(): ShellRegistrationDispatcher;
@@ -0,0 +1,95 @@
1
+ import { catalogSourceSignature, } from "../services/catalog-owner.js";
2
+ import { structurallyEqual } from "../utils/structural-equality.js";
3
+ import { PIE_REGISTER_EVENT, PIE_UNREGISTER_EVENT, } from "./registration-events.js";
4
+ import { dispatchCrossBoundaryEvent } from "./tool-host-contract.js";
5
+ /**
6
+ * Everything a registration says except the item's catalogs.
7
+ */
8
+ function sameOwner(a, b) {
9
+ return (a.kind === b.kind &&
10
+ a.host === b.host &&
11
+ a.itemId === b.itemId &&
12
+ a.canonicalItemId === b.canonicalItemId &&
13
+ a.contentKind === b.contentKind &&
14
+ structurallyEqual(a.settings, b.settings));
15
+ }
16
+ /**
17
+ * The item's part of a registration is its catalogs, which is all the runtime
18
+ * reads from it. Object identity is no guide: the toolkit and the layout kernel
19
+ * hold the composition in deep reactive state, so every republish, each answer
20
+ * included, hands a shell a new proxy of unchanged content.
21
+ */
22
+ function catalogsOf(identity) {
23
+ return catalogSourceSignature(identity.item, identity.kind);
24
+ }
25
+ /**
26
+ * Where a shell's event to `runtime` goes: from the shell host while it is in
27
+ * the document, so the event bubbles through the tree like any other, and on
28
+ * the runtime's own element once it is not.
29
+ */
30
+ export function shellEventTarget(host, runtime) {
31
+ return host.isConnected || !runtime ? host : runtime.eventTarget;
32
+ }
33
+ function dispatch(eventName, identity, runtime) {
34
+ const detail = {
35
+ kind: identity.kind,
36
+ itemId: identity.itemId,
37
+ canonicalItemId: identity.canonicalItemId,
38
+ contentKind: identity.contentKind,
39
+ item: identity.item,
40
+ ...(identity.settings ? { settings: identity.settings } : {}),
41
+ element: identity.host,
42
+ ...(runtime ? { runtimeId: runtime.runtimeId } : {}),
43
+ };
44
+ dispatchCrossBoundaryEvent(shellEventTarget(identity.host, runtime), eventName, detail);
45
+ }
46
+ export function createShellRegistrationDispatcher() {
47
+ /**
48
+ * What the runtime was last told, and the catalogs it was told about.
49
+ * Deliberately not reactive: it is read to decide whether to dispatch, and
50
+ * making it reactive would put that decision inside the graph it exists to
51
+ * keep quiet.
52
+ */
53
+ let dispatched = null;
54
+ let dispatchedCatalogs = null;
55
+ let dispatchedRuntime;
56
+ function retire() {
57
+ const previous = dispatched;
58
+ if (!previous)
59
+ return;
60
+ const previousRuntime = dispatchedRuntime;
61
+ dispatched = null;
62
+ dispatchedCatalogs = null;
63
+ dispatchedRuntime = undefined;
64
+ dispatch(PIE_UNREGISTER_EVENT, previous, previousRuntime);
65
+ }
66
+ function sync(identity, runtime) {
67
+ if (!identity) {
68
+ retire();
69
+ return;
70
+ }
71
+ if (dispatched && dispatchedRuntime?.runtimeId !== runtime?.runtimeId) {
72
+ retire();
73
+ }
74
+ if (dispatched && sameOwner(dispatched, identity)) {
75
+ // A re-render re-applies the object last seen, so identity settles most
76
+ // runs without serializing anything.
77
+ if (dispatched.item === identity.item)
78
+ return;
79
+ const catalogs = catalogsOf(identity);
80
+ if (catalogs !== null && catalogs === dispatchedCatalogs) {
81
+ dispatched = identity;
82
+ return;
83
+ }
84
+ dispatched = identity;
85
+ dispatchedCatalogs = catalogs;
86
+ dispatch(PIE_REGISTER_EVENT, identity, runtime);
87
+ return;
88
+ }
89
+ dispatched = identity;
90
+ dispatchedCatalogs = catalogsOf(identity);
91
+ dispatchedRuntime = runtime;
92
+ dispatch(PIE_REGISTER_EVENT, identity, runtime);
93
+ }
94
+ return { sync, retire };
95
+ }
@@ -0,0 +1,68 @@
1
+ import { type ShellContextKind } from "../context/assessment-toolkit-context.js";
2
+ import type { ItemSettings } from "@pie-players/pie-players-shared/types";
3
+ import type { TTSHighlightTargetResolver } from "../services/tts/highlight-target-resolver.js";
4
+ /** What a shell says about the content it holds. */
5
+ export interface ShellScopeState {
6
+ /** The shell element: it provides the contexts and dispatches the registration. */
7
+ host: HTMLElement;
8
+ kind: ShellContextKind;
9
+ itemId: string;
10
+ canonicalItemId?: string;
11
+ contentKind: string;
12
+ regionPolicy?: string;
13
+ /** The region the shell's tools act on; the shell itself when unset. */
14
+ scopeElement?: HTMLElement | null;
15
+ ttsHighlightTargetResolver?: TTSHighlightTargetResolver | null;
16
+ item?: unknown;
17
+ /** An item's policy settings, registered with the runtime alongside it. */
18
+ settings?: ItemSettings | null;
19
+ }
20
+ export interface ShellScope {
21
+ /**
22
+ * Publishes `state`, or withdraws the scope when there is none. A state that
23
+ * says nothing new publishes nothing.
24
+ */
25
+ publish: (state: ShellScopeState | null) => void;
26
+ /**
27
+ * Retires the runtime registration under the identity it was made with.
28
+ * Teardown only, after anything that still has to reach the runtime.
29
+ */
30
+ retire: () => void;
31
+ /** Stops providing the contexts, and drops the events `send` holds. */
32
+ disconnect: () => void;
33
+ /**
34
+ * Dispatches `type` from the shell host with the id of the runtime that
35
+ * answered the scope in its detail, so that runtime claims it by id. Once
36
+ * the host has left the document, as in a teardown, the event is dispatched
37
+ * on the runtime's element instead, which the scope captured when the
38
+ * runtime answered. Events
39
+ * sent before a runtime has answered are held, the newest
40
+ * {@link MAX_HELD_SHELL_EVENTS}, and delivered in order once one does.
41
+ * `disconnect` and `publish(null)` drop them.
42
+ */
43
+ send: (type: string, detail: object) => void;
44
+ }
45
+ /**
46
+ * A shell's publication of its content: the identity, as the shell context the
47
+ * tools inside it read, the region they act on, as the region scope, and the
48
+ * content itself, registered with the runtime, which files its accessibility
49
+ * catalogs under it. The section player's item and passage shells and
50
+ * `<pie-item-scope>` all publish through this, so a tool resolves its target
51
+ * and its catalogs the same way inside any of them.
52
+ *
53
+ * Content republished unchanged arrives as a new object, the composition being
54
+ * deep reactive state, so items compare by id and catalogs, the measure the
55
+ * registration applies.
56
+ *
57
+ * The registration waits for the runtime the shell sits in to answer through
58
+ * `assessmentToolkitHostRuntimeContext`, and carries that runtime's id, which
59
+ * the runtime claims it by. A shell mounted before its toolkit, which a host
60
+ * composing the elements itself can do, would otherwise register with no one
61
+ * listening, and nothing replays a registration. The document's context root
62
+ * replays the request instead, once the toolkit's provider connects. A
63
+ * different runtime answering later, a nearer toolkit taking over, moves the
64
+ * registration: the old runtime is told to unregister by its id, and the new
65
+ * one gets the registration and the content's last load, which only the old
66
+ * one heard.
67
+ */
68
+ export declare function createShellScope(): ShellScope;