@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
@@ -3,7 +3,7 @@
3
3
  * profile.
4
4
  *
5
5
  * Two independent halves, and a capability is in play only when both answer yes:
6
- * policy granted one of its support ids, and its own `requiresAuthoredContent`
6
+ * policy granted its support id, and its own `requiresAuthoredContent`
7
7
  * found the resource in this entity's catalogs. Neither implies the other — a
8
8
  * learner with an accommodation still sees nothing on an item carrying no
9
9
  * resource, and an item carrying one shows nothing to a learner without the
@@ -30,11 +30,9 @@
30
30
  */
31
31
  import type { ToolRegistration } from "../services/ToolRegistry.js";
32
32
  import type { CatalogOwnerSnapshot } from "../services/AccessibilityCatalogResolver.js";
33
- /** What policy answered about one feature id. */
33
+ /** What policy answered about one capability's support id. */
34
34
  export type ContentCapabilityPolicy = {
35
35
  outcome: "granted";
36
- /** The support id that was granted — a capability may declare several. */
37
- featureId: string;
38
36
  /** Feature parameters carried by the decision, if any. */
39
37
  parameters?: unknown;
40
38
  }
@@ -61,12 +59,12 @@ export type ContentCapabilityPhase = "policy" | "content";
61
59
  export interface ResolvedContentCapability {
62
60
  registration: ToolRegistration;
63
61
  /**
64
- * The granted support id, or `""` when the capability resolved without a
65
- * grant. Passed through to the render context unchanged, so a capability that
62
+ * Whether policy granted the capability; `false` when it resolved from content
63
+ * alone. Passed through to the render context unchanged, so a capability that
66
64
  * serves both an authored-presentation case and an accommodation can still
67
65
  * tell them apart at render time.
68
66
  */
69
- featureId: string;
67
+ granted: boolean;
70
68
  parameters?: unknown;
71
69
  /** Whatever the capability's own `resolve` returned; never inspected here. */
72
70
  content: unknown;
@@ -81,7 +79,7 @@ export interface ResolveContentCapabilitiesArgs {
81
79
  /** The entity's cards, or `null` when no resolver is available. */
82
80
  catalogs: CatalogOwnerSnapshot | null;
83
81
  /**
84
- * Policy's answer about one feature id, in three states.
82
+ * Policy's answer about one support id, which is a tool id, in three states.
85
83
  *
86
84
  * Granting requires a documented need, so an unconfigured feature is
87
85
  * `"silent"`, never granted. What the third state buys is the distinction
@@ -89,7 +87,7 @@ export interface ResolveContentCapabilitiesArgs {
89
87
  * something, and a capability allowed to answer from content alone must not
90
88
  * treat that as nobody having spoken.
91
89
  */
92
- policyFor: (featureId: string) => ContentCapabilityPolicy;
90
+ policyFor: (supportId: string) => ContentCapabilityPolicy;
93
91
  /**
94
92
  * Report a capability that threw. It is dropped either way; this is how a
95
93
  * caller surfaces it as its own recoverable warning rather than letting one
@@ -3,7 +3,7 @@
3
3
  * profile.
4
4
  *
5
5
  * Two independent halves, and a capability is in play only when both answer yes:
6
- * policy granted one of its support ids, and its own `requiresAuthoredContent`
6
+ * policy granted its support id, and its own `requiresAuthoredContent`
7
7
  * found the resource in this entity's catalogs. Neither implies the other — a
8
8
  * learner with an accommodation still sees nothing on an item carrying no
9
9
  * resource, and an item carrying one shows nothing to a learner without the
@@ -28,51 +28,15 @@
28
28
  * a capability interprets its own cards, and the resolution owns only the
29
29
  * two-halves rule and its one documented exception.
30
30
  */
31
- /** The support ids a capability answers to, defaulting to its own id. */
32
- const supportIdsOf = (registration) => registration.pnpSupportIds?.length
33
- ? registration.pnpSupportIds
34
- : [registration.toolId];
35
- /**
36
- * Everything policy has to say about one capability: a grant, an off switch, or
37
- * nothing.
38
- *
39
- * Denial is checked ahead of a grant on each id rather than after the scan,
40
- * because the two can only disagree when a host blocked one of a capability's ids
41
- * while a profile granted another, and there the off switch is the later, more
42
- * specific statement about this delivery.
43
- *
44
- * A host gate names *capabilities*, so the tool id is probed too when it is not
45
- * already a declared support id — otherwise a capability whose id differs from
46
- * its support ids would slip a host block. That probe is gate-only: a grant on
47
- * the tool id is ignored, or blocking would double as a second way to switch a
48
- * capability on.
49
- */
50
- function policyForCapability(registration, args) {
51
- const supportIds = supportIdsOf(registration);
52
- for (const supportId of supportIds) {
53
- const answer = args.policyFor(supportId);
54
- if (answer.outcome === "denied")
55
- return { grant: null, denied: true };
56
- if (answer.outcome === "granted")
57
- return { grant: answer, denied: false };
58
- }
59
- if (supportIds.includes(registration.toolId)) {
60
- return { grant: null, denied: false };
61
- }
62
- return {
63
- grant: null,
64
- denied: args.policyFor(registration.toolId).outcome === "denied",
65
- };
66
- }
67
31
  function resolveOne(registration, args) {
68
32
  let grant = null;
69
33
  try {
70
- const answer = policyForCapability(registration, args);
71
- // Nothing reopens a host denial — not a grant it outranked, and not the
72
- // content exception below.
73
- if (answer.denied)
34
+ const answer = args.policyFor(registration.toolId);
35
+ // Nothing reopens a host denial, not even the content exception below.
36
+ if (answer.outcome === "denied")
74
37
  return null;
75
- grant = answer.grant;
38
+ if (answer.outcome === "granted")
39
+ grant = answer;
76
40
  }
77
41
  catch (error) {
78
42
  args.onError?.(registration, "policy", error);
@@ -92,13 +56,12 @@ function resolveOne(registration, args) {
92
56
  return null;
93
57
  return {
94
58
  registration,
95
- featureId: grant.featureId,
59
+ granted: true,
96
60
  parameters: grant.parameters,
97
61
  content: null,
98
62
  };
99
63
  }
100
64
  const context = {
101
- featureId: grant?.featureId ?? "",
102
65
  parameters: grant?.parameters,
103
66
  catalogs: args.catalogs,
104
67
  granted: Boolean(grant),
@@ -117,7 +80,7 @@ function resolveOne(registration, args) {
117
80
  return null;
118
81
  return {
119
82
  registration,
120
- featureId: context.featureId,
83
+ granted: context.granted,
121
84
  parameters: context.parameters,
122
85
  content,
123
86
  };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Tool registration — the stable entry for tool authors: writing and rendering a
3
+ * `ToolRegistration`, and the runtime contract a tool element is written against.
4
+ *
5
+ * A capability package writes a registration with it: the registration contract,
6
+ * the context predicates a tool answers `isVisibleInContext` with, scoped ids,
7
+ * element creation, the toolbar button and overlay helpers, the provider contract
8
+ * a descriptor creates, and the TTS provider with its config resolution. A
9
+ * renderer puts registrations on screen with it: `createToolSurfaceHost` mounts
10
+ * and reconciles surfaces, and `resolveContentCapabilities` asks the
11
+ * grant-and-content question without a coordinator. A tool element connects to
12
+ * the runtime with it: the runtime, shell and region-scope contexts, the services
13
+ * they carry, coordinator registration, the reading scope of the content it reads
14
+ * or annotates, and read-aloud coordination.
15
+ *
16
+ * The composition layer (`@pie-players/pie-default-tool-loaders`), the packaged
17
+ * tools and the section player's tool panels are written against it, so a host's
18
+ * own tool uses the mechanism ours use. Its values are complete, so a tool
19
+ * package never imports the root entry, which carries what hosts and players
20
+ * import. A name the root also carries appears here only where a package imports
21
+ * it from here.
22
+ */
23
+ export type { HostedToolContext, HostedToolSize, ToolContentDependencyContext, ToolModuleLoader, ToolProviderDescriptor, ToolRegistration, ToolRenderElement, ToolSurfaceRenderContext, ToolSurfaceRenderResult, ToolSurfaceServices, ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolbarContext, } from "../services/ToolRegistry.js";
24
+ export { ToolRegistry } from "../services/ToolRegistry.js";
25
+ export { resolveToolRegistrationName } from "../services/ToolRegistry.js";
26
+ export type { CatalogOwnerSnapshot } from "../services/AccessibilityCatalogResolver.js";
27
+ export type { ToolSelectionAction, ToolSelectionContext, } from "../services/selection-action.js";
28
+ export { resolveFallbackToolIcon } from "../services/tool-icons.js";
29
+ export type { ContentCapabilityPhase, ContentCapabilityPolicy, ResolveContentCapabilitiesArgs, ResolvedContentCapability, } from "./content-capability-resolution.js";
30
+ export { resolveContentCapabilities } from "./content-capability-resolution.js";
31
+ export type { ToolSurfaceHost, ToolSurfaceHostInput, ToolSurfaceHostOptions, ToolSurfaceHostSnapshot, ToolSurfaceScope, } from "./tool-surface-host.js";
32
+ export { createToolSurfaceHost } from "./tool-surface-host.js";
33
+ export type { ToolContext } from "../services/tool-context.js";
34
+ export { hasChoiceInteraction, hasMathContent, hasReadableText, hasScienceContent, } from "../services/tool-context.js";
35
+ export type { ParsedToolInstanceId } from "../services/tool-instance-id.js";
36
+ export { createScopedToolId, parseScopedToolId, } from "../services/tool-instance-id.js";
37
+ export type { ToolComponentFactory, ToolComponentFactoryMap, ToolComponentOverrides, ToolTagMap, } from "./tool-tag-map.js";
38
+ export { createToolElement, resolveToolTag } from "./tool-tag-map.js";
39
+ export { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "./registrations/toolbar-registration-helpers.js";
40
+ export type { HighlightCoordinatorApi, ToolCoordinatorApi, ToolkitCoordinatorApi, TtsServiceApi, } from "../services/interfaces.js";
41
+ export type { AssessmentToolkitRegionScopeContext, AssessmentToolkitRuntimeContext, AssessmentToolkitShellContext, } from "../context/assessment-toolkit-context.js";
42
+ export { connectToolRegionScopeContext, connectToolRuntimeContext, connectToolShellContext, createToolCoordinatorRegistration, type ToolCoordinatorRegistration, } from "../runtime/tool-host-contract.js";
43
+ export { ZIndexLayer } from "../services/ToolCoordinator.js";
44
+ export { HighlightColor, HighlightCoordinator, } from "../services/HighlightCoordinator.js";
45
+ export type { CatalogLookupContext } from "../services/AccessibilityCatalogResolver.js";
46
+ export { catalogContextForShell, catalogContextHolding, type CatalogRuntimeScope, } from "../runtime/catalog-context.js";
47
+ export { findShellScopeHost, resolveContentRegion, } from "../runtime/content-region.js";
48
+ export { composedClosest, composedContains, flatTextContent, isShadowRootNode, retargetToTree, } from "../services/tts/flat-tree.js";
49
+ export type { ToolPlacementLevel } from "../services/tools-config-normalizer.js";
50
+ export type { CalculatorToolProviderConfig, TextToSpeechToolProviderConfig, ToolProviderConfig, } from "../services/tools-config-normalizer.js";
51
+ export type { ToolProviderApi, ToolProviderCapabilities, } from "../services/tool-providers/ToolProviderApi.js";
52
+ export { TTSToolProvider } from "../services/tool-providers/index.js";
53
+ export type { NormalizedTTSSpeedOption, TTSLayoutMode, TTSSpeedOption, } from "../services/tts-runtime-config.js";
54
+ export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText, normalizeTTSLayoutMode, normalizeTTSSpeedControlOptions, parseTTSSpeedOptionsFromText, resolveTTSHostToolbarLayout, resolveTTSLayoutMode, resolveTTSRuntimeSettings, } from "../services/tts-runtime-config.js";
55
+ export { PIE_TTS_CONTROL_HANDOFF_EVENT } from "../services/tts-control-events.js";
56
+ export { bindTtsAudioHandoff, pauseTtsForMediaAudio, } from "../services/audio-handoff.js";
57
+ export { isTTSStartFailure } from "../services/tts/start-failure.js";
58
+ export { browserVoiceMatchesLanguage, findBrowserVoice, waitForBrowserVoices, } from "../services/tts/browser-provider.js";
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Tool registration — the stable entry for tool authors: writing and rendering a
3
+ * `ToolRegistration`, and the runtime contract a tool element is written against.
4
+ *
5
+ * A capability package writes a registration with it: the registration contract,
6
+ * the context predicates a tool answers `isVisibleInContext` with, scoped ids,
7
+ * element creation, the toolbar button and overlay helpers, the provider contract
8
+ * a descriptor creates, and the TTS provider with its config resolution. A
9
+ * renderer puts registrations on screen with it: `createToolSurfaceHost` mounts
10
+ * and reconciles surfaces, and `resolveContentCapabilities` asks the
11
+ * grant-and-content question without a coordinator. A tool element connects to
12
+ * the runtime with it: the runtime, shell and region-scope contexts, the services
13
+ * they carry, coordinator registration, the reading scope of the content it reads
14
+ * or annotates, and read-aloud coordination.
15
+ *
16
+ * The composition layer (`@pie-players/pie-default-tool-loaders`), the packaged
17
+ * tools and the section player's tool panels are written against it, so a host's
18
+ * own tool uses the mechanism ours use. Its values are complete, so a tool
19
+ * package never imports the root entry, which carries what hosts and players
20
+ * import. A name the root also carries appears here only where a package imports
21
+ * it from here.
22
+ */
23
+ export { ToolRegistry } from "../services/ToolRegistry.js";
24
+ // A registration's own display name in the interface locale. A tool window's
25
+ // title is the registration's name, so the shell needs the same `nameKey`-then-
26
+ // `name` precedence the toolbar uses rather than the raw English field.
27
+ export { resolveToolRegistrationName } from "../services/ToolRegistry.js";
28
+ // So a gateway button and the toolbar button for the same tool draw one icon.
29
+ export { resolveFallbackToolIcon } from "../services/tool-icons.js";
30
+ export { resolveContentCapabilities } from "./content-capability-resolution.js";
31
+ export { createToolSurfaceHost } from "./tool-surface-host.js";
32
+ export { hasChoiceInteraction, hasMathContent, hasReadableText, hasScienceContent, } from "../services/tool-context.js";
33
+ export { createScopedToolId, parseScopedToolId, } from "../services/tool-instance-id.js";
34
+ export { createToolElement, resolveToolTag } from "./tool-tag-map.js";
35
+ // Toolbar button/overlay wiring shared by every toolbar-toggle registration.
36
+ export { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "./registrations/toolbar-registration-helpers.js";
37
+ export { connectToolRegionScopeContext, connectToolRuntimeContext, connectToolShellContext, createToolCoordinatorRegistration, } from "../runtime/tool-host-contract.js";
38
+ export { ZIndexLayer } from "../services/ToolCoordinator.js";
39
+ export { HighlightColor, HighlightCoordinator, } from "../services/HighlightCoordinator.js";
40
+ export { catalogContextForShell, catalogContextHolding, } from "../runtime/catalog-context.js";
41
+ export { findShellScopeHost, resolveContentRegion, } from "../runtime/content-region.js";
42
+ export { composedClosest, composedContains, flatTextContent, isShadowRootNode, retargetToTree, } from "../services/tts/flat-tree.js";
43
+ // The TTS provider stays here because it is written against the `pie-tts`
44
+ // contract package, which the toolkit's own `TTSService` also depends on.
45
+ export { TTSToolProvider } from "../services/tool-providers/index.js";
46
+ export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText, normalizeTTSLayoutMode, normalizeTTSSpeedControlOptions, parseTTSSpeedOptionsFromText, resolveTTSHostToolbarLayout, resolveTTSLayoutMode, resolveTTSRuntimeSettings, } from "../services/tts-runtime-config.js";
47
+ // Read-aloud coordination for a tool that plays or controls speech: the control
48
+ // handoff event between TTS surfaces, pausing speech while a media element plays,
49
+ // recognising a start failure the TTS service reports, and choosing a browser
50
+ // voice for a language once the browser has published its voices.
51
+ export { PIE_TTS_CONTROL_HANDOFF_EVENT } from "../services/tts-control-events.js";
52
+ export { bindTtsAudioHandoff, pauseTtsForMediaAudio, } from "../services/audio-handoff.js";
53
+ export { isTTSStartFailure } from "../services/tts/start-failure.js";
54
+ export { browserVoiceMatchesLanguage, findBrowserVoice, waitForBrowserVoices, } from "../services/tts/browser-provider.js";
@@ -3,12 +3,12 @@ export function createScopedVisibilityBinding(toolId, toolbarContext) {
3
3
  const fullToolId = createScopedToolId(toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
4
4
  return {
5
5
  fullToolId,
6
- isActive: () => toolbarContext.isToolVisible(fullToolId),
6
+ isActive: () => toolbarContext.isToolVisible(toolId),
7
7
  subscribeActive: (callback) => {
8
8
  if (!toolbarContext.subscribeVisibility)
9
9
  return () => { };
10
10
  return toolbarContext.subscribeVisibility(() => {
11
- callback(toolbarContext.isToolVisible(fullToolId));
11
+ callback(toolbarContext.isToolVisible(toolId));
12
12
  });
13
13
  },
14
14
  };
@@ -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();
@@ -112,7 +122,7 @@ function contextSignature(context) {
112
122
  try {
113
123
  return stableSerializableJson({
114
124
  toolId: context.toolId,
115
- featureId: context.featureId,
125
+ granted: context.granted,
116
126
  surface: context.surface,
117
127
  parameters: context.parameters ?? null,
118
128
  content: context.content ?? null,
@@ -235,26 +245,22 @@ export function createToolSurfaceHost(onSnapshot, options) {
235
245
  if (current.scope.kind !== "content")
236
246
  return null;
237
247
  const coordinator = current.services.toolkitCoordinator;
248
+ const featureScope = itemFeatureScope(current.scope.ownerContext);
238
249
  const [resolved] = resolveContentCapabilities({
239
250
  registrations: [registration],
240
251
  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);
252
+ // One decision per support id, in the rule's three states. Denial's
253
+ // precedence over both a grant and `resolvesWithoutGrant` lives in the
254
+ // rule, so this host and print cannot answer differently. All this adapter
255
+ // owns is reading a `FeaturePolicyDecision`: `granted` is not enough on its
256
+ // own, because a host gate and an unconfigured feature are both
257
+ // `granted: false` and only one of them may be reopened by content.
258
+ policyFor: (supportId) => {
259
+ const decision = coordinator?.decideFeaturePolicy?.(supportId, featureScope);
250
260
  if (isHostDeniedFeature(decision))
251
261
  return { outcome: "denied" };
252
262
  if (decision?.granted === true) {
253
- return {
254
- outcome: "granted",
255
- featureId,
256
- parameters: decision.parameters,
257
- };
263
+ return { outcome: "granted", parameters: decision.parameters };
258
264
  }
259
265
  return { outcome: "silent" };
260
266
  },
@@ -281,7 +287,7 @@ export function createToolSurfaceHost(onSnapshot, options) {
281
287
  }
282
288
  const context = {
283
289
  toolId: registration.toolId,
284
- featureId: resolved.featureId,
290
+ granted: resolved.granted,
285
291
  surface: current.surface,
286
292
  parameters: resolved.parameters,
287
293
  content: resolved.content,
@@ -303,26 +309,19 @@ export function createToolSurfaceHost(onSnapshot, options) {
303
309
  const coordinator = current.services.toolkitCoordinator;
304
310
  if (!coordinator)
305
311
  return null;
306
- const supportIds = registration.pnpSupportIds?.length
307
- ? registration.pnpSupportIds
308
- : [registration.toolId];
309
- let featureId = "";
312
+ let granted = false;
310
313
  let parameters;
311
314
  try {
312
315
  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)
316
+ const decision = coordinator.decideFeaturePolicy?.(registration.toolId);
317
+ if (decision?.granted !== true)
322
318
  return null;
319
+ granted = true;
320
+ parameters = decision.parameters;
323
321
  }
324
322
  else {
325
323
  const scopeId = current.scope.sectionId || "*";
324
+ let placed = false;
326
325
  for (const level of SECTION_POLICY_LEVELS) {
327
326
  const decision = coordinator.decideToolPolicy({
328
327
  level,
@@ -336,11 +335,14 @@ export function createToolSurfaceHost(onSnapshot, options) {
336
335
  const entry = decision.visibleTools.find((candidate) => candidate.toolId === registration.toolId);
337
336
  if (!entry)
338
337
  continue;
339
- featureId = supportIds[0] ?? registration.toolId;
338
+ // Placement admits the tool; only a support, requirement or
339
+ // test-administration override grants it.
340
+ placed = true;
341
+ granted = entry.required || entry.alwaysAvailable;
340
342
  parameters = entry.settings;
341
343
  break;
342
344
  }
343
- if (!featureId)
345
+ if (!placed)
344
346
  return null;
345
347
  }
346
348
  }
@@ -350,7 +352,7 @@ export function createToolSurfaceHost(onSnapshot, options) {
350
352
  }
351
353
  const context = {
352
354
  toolId: registration.toolId,
353
- featureId,
355
+ granted,
354
356
  surface: current.surface,
355
357
  parameters,
356
358
  services: current.services,
@@ -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
+ }