@pie-players/pie-assessment-toolkit 0.3.73 → 0.3.74

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 (108) hide show
  1. package/README.md +171 -56
  2. package/dist/attempt/AssessmentSession.d.ts +1 -5
  3. package/dist/attempt/AssessmentSession.js +0 -29
  4. package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
  5. package/dist/components/ItemToolBar.custom-element.js +1 -1
  6. package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
  7. package/dist/components/PieAssessmentToolkit.custom-element.js +14 -14
  8. package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
  9. package/dist/components/SectionToolBar.custom-element.js +1 -1
  10. package/dist/components/chunks/ItemToolBar-b9dz5jvd.js +40 -0
  11. package/dist/components/chunks/ItemToolBar-gmrryv2v.js +2 -0
  12. package/dist/components/chunks/ItemToolBar-h4xap0t0.js +4 -0
  13. package/dist/components/chunks/ItemToolBar-wr2myaah.js +2 -0
  14. package/dist/components/chunks/sre-engine-wf9s43gg.js +1 -0
  15. package/dist/context/assessment-toolkit-context.d.ts +5 -0
  16. package/dist/context/runtime-context-consumer.js +5 -38
  17. package/dist/index.d.ts +6 -6
  18. package/dist/index.js +8 -9
  19. package/dist/policy/core/ToolPolicyEngine.d.ts +8 -2
  20. package/dist/policy/core/ToolPolicyEngine.js +12 -0
  21. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +3 -3
  22. package/dist/runtime/adapter/SectionEngineAdapter.js +3 -3
  23. package/dist/runtime/registration-events.d.ts +3 -0
  24. package/dist/runtime/section-runtime-engine-host-context.d.ts +3 -9
  25. package/dist/runtime/section-runtime-engine-host-context.js +5 -43
  26. package/dist/runtime/tool-host-contract.d.ts +20 -0
  27. package/dist/runtime/tool-host-contract.js +21 -0
  28. package/dist/services/HighlightCoordinator.d.ts +1 -7
  29. package/dist/services/HighlightCoordinator.js +1 -3
  30. package/dist/services/TTSService.d.ts +15 -1
  31. package/dist/services/TTSService.js +88 -35
  32. package/dist/services/ToolCoordinator.d.ts +1 -7
  33. package/dist/services/ToolCoordinator.js +1 -3
  34. package/dist/services/ToolRegistry.d.ts +13 -6
  35. package/dist/services/ToolRegistry.js +19 -7
  36. package/dist/services/ToolkitCoordinator.d.ts +110 -18
  37. package/dist/services/ToolkitCoordinator.js +273 -85
  38. package/dist/services/catalog-owner.d.ts +11 -0
  39. package/dist/services/catalog-owner.js +25 -0
  40. package/dist/services/create-tools-config.d.ts +2 -2
  41. package/dist/services/framework-error.d.ts +8 -1
  42. package/dist/services/interfaces.d.ts +9 -9
  43. package/dist/services/pnp-standard-features.d.ts +1 -1
  44. package/dist/services/section-controller-types.d.ts +15 -0
  45. package/dist/services/spoken-audio-cards.js +1 -1
  46. package/dist/services/tool-config-validation.d.ts +13 -2
  47. package/dist/services/tool-config-validation.js +33 -16
  48. package/dist/services/tool-context.js +29 -13
  49. package/dist/services/tool-providers/TTSToolProvider.d.ts +27 -65
  50. package/dist/services/tool-providers/TTSToolProvider.js +47 -9
  51. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +4 -4
  52. package/dist/services/tool-providers/ToolProviderRegistry.js +4 -16
  53. package/dist/services/tool-providers/index.d.ts +0 -9
  54. package/dist/services/tool-providers/index.js +2 -4
  55. package/dist/services/tools-config-normalizer.d.ts +20 -1
  56. package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
  57. package/dist/services/tts/catalog-span-alignment.js +17 -142
  58. package/dist/services/tts/generated-speech/types.d.ts +0 -12
  59. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
  60. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +26 -1
  61. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
  62. package/dist/services/tts/math-alignment/index.d.ts +0 -5
  63. package/dist/services/tts/math-alignment/index.js +5 -25
  64. package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
  65. package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
  66. package/dist/services/tts/math-alignment/types.d.ts +4 -2
  67. package/dist/services/tts/math-aware-text-processing.js +44 -2
  68. package/dist/services/tts/math-speech.d.ts +5 -1
  69. package/dist/services/tts/math-speech.js +9 -6
  70. package/dist/services/tts/sre-engine.d.ts +7 -0
  71. package/dist/services/tts/sre-engine.js +11 -0
  72. package/dist/services/tts/sre-locales.d.ts +14 -0
  73. package/dist/services/tts/sre-locales.js +57 -0
  74. package/dist/services/tts/text-processing.d.ts +0 -1
  75. package/dist/services/tts/text-processing.js +0 -1
  76. package/dist/services/tts-runtime-config.d.ts +21 -3
  77. package/dist/services/tts-runtime-config.js +11 -3
  78. package/dist/tools/client.d.ts +1 -3
  79. package/dist/tools/client.js +1 -5
  80. package/dist/tools/internal.d.ts +6 -5
  81. package/dist/tools/internal.js +6 -8
  82. package/package.json +17 -36
  83. package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
  84. package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
  85. package/dist/services/ToolConfigResolver.d.ts +0 -161
  86. package/dist/services/ToolConfigResolver.js +0 -229
  87. package/dist/services/catalog-media.d.ts +0 -56
  88. package/dist/services/catalog-media.js +0 -190
  89. package/dist/services/createDefaultToolRegistry.d.ts +0 -53
  90. package/dist/services/createDefaultToolRegistry.js +0 -45
  91. package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
  92. package/dist/services/tool-providers/CortexToolProvider.js +0 -32
  93. package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
  94. package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
  95. package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
  96. package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
  97. package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
  98. package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
  99. package/dist/services/tts/visual-line-ranges.d.ts +0 -18
  100. package/dist/services/tts/visual-line-ranges.js +0 -226
  101. package/dist/tools/index.d.ts +0 -8
  102. package/dist/tools/index.js +0 -10
  103. package/dist/tools/response-discovery.d.ts +0 -61
  104. package/dist/tools/response-discovery.js +0 -113
  105. package/dist/tools/types.d.ts +0 -337
  106. package/dist/tools/types.js +0 -12
  107. package/dist/tools/variant-resolver.d.ts +0 -41
  108. package/dist/tools/variant-resolver.js +0 -207
package/README.md CHANGED
@@ -4,6 +4,30 @@
4
4
 
5
5
  This is not an opinionated framework or monolithic "player" - it's a toolkit that solves specific problems through centralized service management.
6
6
 
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @pie-players/pie-assessment-toolkit @pie-players/pie-default-tool-loaders
11
+ ```
12
+
13
+ The examples build their tool registry with `createPackagedToolRegistry()` from
14
+ `@pie-players/pie-default-tool-loaders`, so a host that imports it declares it
15
+ in its own dependencies. The section player depends on it too, but strict
16
+ installers such as pnpm expose only the packages a host declares.
17
+
18
+ Server-backed TTS (`backend: "polly"`, `"google"` or `"server"`) loads
19
+ `@pie-players/tts-client-server`, a dependency of
20
+ `@pie-players/pie-default-tool-loaders` whose TTS registration imports it on
21
+ first use. If it fails to load, TTS initialization reports a `provider-init`
22
+ framework error and falls back to browser speech.
23
+
24
+ A `ToolkitCoordinator` registers tool providers only from its `toolRegistry`.
25
+ Built without one, it adopts the registry of the toolkit it is bound to, such as
26
+ the section player's, which then validates its config and registers its
27
+ providers. A registry passed at construction is never replaced. Bound to a
28
+ toolkit that has none, it registers no providers, skips tool-id and placement
29
+ validation, and warns once (`tools.registryUnavailable`).
30
+
7
31
  ## What's New: ToolkitCoordinator
8
32
 
9
33
  ✨ **Centralized Service Management**: The new `ToolkitCoordinator` provides a single entry point for all toolkit services, simplifying initialization and configuration.
@@ -28,16 +52,21 @@ player.toolCoordinator = toolCoordinator;
28
52
 
29
53
  **After** (coordinator orchestrates):
30
54
  ```typescript
55
+ import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
56
+
31
57
  // Create one coordinator with configuration
58
+ const toolRegistry = createPackagedToolRegistry();
32
59
  const toolkitCoordinator = new ToolkitCoordinator({
33
60
  assessmentId: 'my-assessment',
61
+ toolRegistry,
34
62
  tools: {
35
63
  providers: {
36
64
  textToSpeech: { enabled: true, backend: 'browser' },
65
+ // Desmos needs an application key; see "Simple Default" below.
37
66
  calculator: { enabled: true }
38
67
  },
39
68
  placement: {
40
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
69
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
41
70
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
42
71
  passage: ['textToSpeech']
43
72
  }
@@ -84,6 +113,7 @@ provider path is the item-player loader config:
84
113
 
85
114
  ### Toolkit-Owned Canonical Event Stream
86
115
 
116
+ - `pie-toolkit-stage-change`
87
117
  - `pie-toolkit-runtime-owned`
88
118
  - `pie-toolkit-runtime-inherited`
89
119
  - `pie-toolkit-ready`
@@ -141,8 +171,12 @@ tier; the choice is about ergonomics, not capability.
141
171
  object passed by reference. Example:
142
172
 
143
173
  ```ts
174
+ import { createPackagedToolRegistry } from "@pie-players/pie-default-tool-loaders";
175
+
176
+ const toolRegistry = createPackagedToolRegistry();
144
177
  const coordinator = new ToolkitCoordinator({
145
178
  assessmentId: "my-assessment",
179
+ toolRegistry,
146
180
  toolConfigStrictness: "warn",
147
181
  tools: {
148
182
  providers: { calculator: { enabled: true } },
@@ -229,17 +263,21 @@ Otherwise expose it through the configuration object only.
229
263
 
230
264
  ```typescript
231
265
  import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
266
+ import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
232
267
 
233
268
  // Create coordinator with configuration
269
+ const toolRegistry = createPackagedToolRegistry();
234
270
  const coordinator = new ToolkitCoordinator({
235
271
  assessmentId: 'demo-assessment',
272
+ toolRegistry,
236
273
  tools: {
237
274
  providers: {
238
275
  textToSpeech: { enabled: true, backend: 'browser' },
276
+ // Desmos needs an application key; see "Simple Default" below.
239
277
  calculator: { enabled: true }
240
278
  },
241
279
  placement: {
242
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
280
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
243
281
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
244
282
  passage: ['textToSpeech']
245
283
  }
@@ -393,12 +431,78 @@ player.toolCoordinator = toolCoordinator;
393
431
  // ...
394
432
  ```
395
433
 
434
+ ### Without a Section Player
435
+
436
+ `<pie-assessment-toolkit>` needs no section. Bind none and it provides tools,
437
+ policy and services to the item toolbars and item players inside it, which is
438
+ how the toolkit accompanies a plain item player:
439
+
440
+ ```html
441
+ <pie-assessment-toolkit pnp-enforcement="on">
442
+ <pie-item-toolbar item-id="q1"></pie-item-toolbar>
443
+ <pie-item-player></pie-item-player>
444
+ </pie-assessment-toolkit>
445
+ ```
446
+
447
+ ```typescript
448
+ import '@pie-players/pie-assessment-toolkit/components/pie-assessment-toolkit-element';
449
+ import '@pie-players/pie-assessment-toolkit/components/item-toolbar-element';
450
+ import '@pie-players/pie-item-player';
451
+ import {
452
+ createPackagedToolRegistry,
453
+ DEFAULT_TOOL_MODULE_LOADERS,
454
+ } from '@pie-players/pie-default-tool-loaders';
455
+
456
+ // With no section player, the registry's loaders are what define the tool elements.
457
+ const toolRegistry = createPackagedToolRegistry({
458
+ toolModuleLoaders: DEFAULT_TOOL_MODULE_LOADERS,
459
+ });
460
+
461
+ toolkit.tools = { placement: { item: ['calculator'] } };
462
+ toolkit.toolRegistry = toolRegistry;
463
+ toolkit.toolContextResolvers = toolContextResolvers;
464
+ toolkit.assessment = { id: 'a1', personalNeedsProfile: { supports: ['calculator'] } };
465
+
466
+ toolbar.item = item;
467
+ toolbar.toolRegistry = toolRegistry; // the toolbar does not read the toolkit's
468
+ toolbar.scopeElement = player; // the content answerEliminator acts on
469
+ ```
470
+
471
+ A registry built without `toolModuleLoaders` renders toolbar buttons whose tool
472
+ elements never load. `textToSpeech` reads the region an item shell publishes,
473
+ which only the section player's cards provide, so it has no reading target in
474
+ this composition.
475
+
476
+ A profile change is a new `assessment` value; the toolbars re-derive on the
477
+ policy change it emits. Readiness events are section events: `toolkit-ready`,
478
+ `section-ready` and every stage, `composed` included, wait for a bound section,
479
+ and the toolkit builds its own coordinator only after it mounts. A host that needs a
480
+ readiness point constructs the `ToolkitCoordinator`, passes it as
481
+ `coordinator`, awaits `coordinator.waitUntilReady()`, and changes the profile
482
+ with `coordinator.updateAssessment(...)`, since the toolkit applies its
483
+ `assessment` property to a coordinator it owns. The `calculator-pnp` section
484
+ demo composes the owned-coordinator form.
485
+
486
+ The toolkit builds its own coordinator at mount from `tools`, `enabled-tools`,
487
+ `assessment-id`, `accessibility`, `lazy-init`, `tool-config-strictness` and
488
+ `toolRegistry`. A section that arrives after one of those changed initializes
489
+ with a coordinator rebuilt from the current values, and the toolbars move to
490
+ it. After a section has initialized, a change to them is reported once in the
491
+ console and does not reach the coordinator; `pnp-enforcement`, `assessment`,
492
+ `currentItemRef` and `toolContextResolvers` apply to it at any time. That
493
+ coordinator reports feature policy asked with no assessment bound only while
494
+ `pnp-enforcement` is `on`: a toolkit given no `assessment` and no enforcement
495
+ has asked for no accommodation.
496
+
396
497
  ## Tool Configuration Model
397
498
 
398
499
  The toolkit uses one canonical `tools` model with three concerns:
399
500
 
400
501
  - `policy`: allow/block constraints (global gates)
401
- - `placement`: where tools appear (`assessment`, `section`, `item`, `passage`, `rubric`, plus custom registered levels)
502
+ - `placement`: where tools appear (`section`, `item`, `passage`). Each tool
503
+ declares the levels it supports; `calculator` is item-only, and a tool placed
504
+ at a level it does not support fails validation, which throws under the
505
+ default `toolConfigStrictness: "error"`.
402
506
  - `providers`: provider/runtime options (calculator, textToSpeech, etc.)
403
507
 
404
508
  Example:
@@ -410,11 +514,9 @@ tools: {
410
514
  blocked: ['graph']
411
515
  },
412
516
  placement: {
413
- assessment: [],
414
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
517
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
415
518
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
416
- passage: ['textToSpeech'],
417
- rubric: []
519
+ passage: ['textToSpeech']
418
520
  },
419
521
  providers: {
420
522
  calculator: {
@@ -465,7 +567,8 @@ tools: {
465
567
  **Available Item-Level Tools:**
466
568
  - **TTS (Text-to-Speech)**: Reads the specific question/passage text
467
569
  - **Answer Eliminator**: Strikes through answer choices for that question
468
- - **Highlighter**: Highlights text within the item (future)
570
+ - **Calculator**: Basic, scientific or graphing calculator
571
+ - **Highlighter** (`annotationToolbar`): Highlights and annotates selected text; it opens from a text selection, outside the toolbars
469
572
 
470
573
  **Example Use Case:**
471
574
  A student uses answer eliminator on Question 3 to cross out choices B and D. When they navigate to Question 4, they see fresh, uneliminated choices. When they return to Question 3, their eliminations are restored.
@@ -477,38 +580,31 @@ Tools that **float above the entire assessment** and persist across questions:
477
580
  ```typescript
478
581
  tools: {
479
582
  placement: {
480
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler', 'theme']
481
- },
482
- providers: {
483
- calculator: {
484
- enabled: true,
485
- provider: {
486
- runtime: { authFetcher: async () => { /* ... */ } }
487
- }
488
- }
583
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler', 'theme']
489
584
  }
490
585
  }
491
586
  ```
492
587
 
588
+ The section player renders the section toolbar only when its `show-toolbar`
589
+ attribute is `true`; the attribute defaults to `false`.
590
+
493
591
  **Characteristics:**
494
592
  - **Scope**: Section-wide, shared across all questions
495
593
  - **Lifecycle**: Single instance initialized for entire section
496
- - **State**: Persistent (calculator history remains as you navigate)
594
+ - **State**: Persistent (a tool stays open and in place as you navigate)
497
595
  - **UI Pattern**: Draggable floating panels/overlays with z-index management
498
596
  - **State Persistence**: Global state maintained throughout section
499
597
 
500
598
  **Available Floating Tools:**
501
- - **Calculator**: Scientific/graphing calculator with computation history
502
- - **Graph**: Graphing tool for plotting functions
599
+ - **Graph**: Coordinate plane
503
600
  - **Periodic Table**: Interactive periodic table reference
504
601
  - **Protractor**: Angle measurement tool
505
602
  - **Ruler**: Linear measurement tool (metric/imperial)
506
603
  - **Line Reader**: Reading guide/masking overlay
507
- - **Magnifier**: Screen magnification tool
508
- - **Color Scheme**: High-contrast color adjustments
604
+ - **Color Scheme** (`theme`): High-contrast color adjustments
509
605
 
510
606
  **Example Use Case:**
511
- A student opens the calculator on Question 2, computes 45 × 12 = 540. They navigate to Question 7, and the calculator still shows their computation history. They can reference previous calculations across multiple questions without losing context.
607
+ A student opens the periodic table on Question 2 and moves it beside the passage. When they navigate to Question 7, it is still open where they left it.
512
608
 
513
609
  ### When to Use Each
514
610
 
@@ -529,15 +625,19 @@ Use **floating tools** when:
529
625
  Complete example showing both types:
530
626
 
531
627
  ```typescript
628
+ import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
629
+
630
+ const toolRegistry = createPackagedToolRegistry();
532
631
  const coordinator = new ToolkitCoordinator({
533
632
  assessmentId: 'math-exam',
633
+ toolRegistry,
534
634
  tools: {
535
635
  placement: {
536
636
  // Contextual placement
537
637
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
538
638
  passage: ['textToSpeech'],
539
639
  // Section-level utilities
540
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler', 'theme']
640
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler', 'theme']
541
641
  },
542
642
  providers: {
543
643
  calculator: {
@@ -566,11 +666,15 @@ const coordinator = new ToolkitCoordinator({
566
666
  For most use cases, simply enable all available tools:
567
667
 
568
668
  ```typescript
669
+ import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
670
+
671
+ const toolRegistry = createPackagedToolRegistry();
569
672
  const coordinator = new ToolkitCoordinator({
570
673
  assessmentId: 'my-assessment',
674
+ toolRegistry,
571
675
  tools: {
572
676
  placement: {
573
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
677
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
574
678
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
575
679
  passage: ['textToSpeech']
576
680
  },
@@ -588,12 +692,14 @@ const coordinator = new ToolkitCoordinator({
588
692
  ```
589
693
 
590
694
  The ToolkitCoordinator handles service initialization, provider management, and
591
- state coordination. With no calculator provider configuration, the existing
592
- Desmos implementation remains the default and preserves its legacy unkeyed load.
593
- That fallback is for client compatibility; it does not grant a Desmos license.
594
- Licensed deployments can supply `provider.init.apiKey` or
595
- `provider.runtime.authFetcher`. Runtime key delivery avoids committing the key
596
- but does not hide it from the browser's Desmos script request.
695
+ state coordination. With no calculator provider configuration, the Desmos
696
+ implementation remains the default. Desmos's CDN rejects a `calculator.js`
697
+ request without an `apiKey` (HTTP 403), so the Desmos calculator opens only when
698
+ the host supplies `provider.init.apiKey` or `provider.runtime.authFetcher`, or
699
+ has already loaded `window.Desmos`; the adapter's keyless request grants no
700
+ Desmos license either. Runtime key delivery avoids committing the key but does
701
+ not hide it from the browser's Desmos script request. The bundled open-source
702
+ implementation below needs no key.
597
703
 
598
704
  Select the separate GeoGebra implementation explicitly without changing the
599
705
  calculator capability, placement, or item policy:
@@ -747,6 +853,18 @@ tools: {
747
853
  }
748
854
  ```
749
855
 
856
+ The fetch completes before the first TTS request, and its result merges over the
857
+ provider config: a returned `authToken` is sent as `Authorization: Bearer <token>`
858
+ and returned `headers` with every synthesis request, and under
859
+ `includeAuthOnAssetFetch` the `Authorization` header also reaches the custom
860
+ transport's speech-mark and audio fetches. A failed fetch falls back to browser
861
+ speech and reports `pie-tool-init-error`.
862
+
863
+ For a server that authenticates by cookie on another origin, set `credentials:
864
+ "include"` in the `textToSpeech` provider settings, beside
865
+ `includeAuthOnAssetFetch`. The cookie reaches speech-mark and audio fetches only
866
+ for origins in `assetOrigins`; unset, every TTS fetch keeps the browser default.
867
+
750
868
  ### Custom Transport via Server Proxy (SC-style)
751
869
 
752
870
  For custom backends that return URL assets (for example `{ audioContent, word }`),
@@ -838,9 +956,9 @@ The persistence strategy works with the same `SectionControllerSessionState` sha
838
956
  ### ✅ QTI 3.0 Standard Access Features
839
957
 
840
958
  - **95+ Standardized Features**: Complete QTI 3.0 / IMS AfA 3.0 accessibility features
841
- - **9 Feature Categories**: Visual, auditory, motor, cognitive, reading, navigation, linguistic, assessment
959
+ - **8 Feature Categories**: Visual, auditory, motor, cognitive, reading, navigation, linguistic, assessment
842
960
  - **Example Configurations**: Illustrative PNP profile examples (low vision, dyslexia, ADHD, etc.)
843
- - **Tool Mappings**: All 12 default tools map to standard QTI 3.0 features
961
+ - **Tool Mappings**: Every packaged tool registration maps to standard QTI 3.0 features
844
962
 
845
963
  ### ✅ Section Player Integration
846
964
 
@@ -865,11 +983,9 @@ export interface ToolkitCoordinatorConfig {
865
983
  blocked?: string[];
866
984
  };
867
985
  placement?: {
868
- assessment?: string[];
869
986
  section?: string[];
870
987
  item?: string[];
871
988
  passage?: string[];
872
- rubric?: string[];
873
989
  };
874
990
  providers?: {
875
991
  textToSpeech?: {
@@ -1189,8 +1305,8 @@ that could not parse the markup left the video in the visible content, showing t
1189
1305
  accommodation to every learner regardless of eligibility.
1190
1306
 
1191
1307
  This package resolves and registers those cards through
1192
- `AccessibilityCatalogResolver` and the generic media helpers in
1193
- `catalog-media.ts`. Which card types mean what belongs to the capability that
1308
+ `AccessibilityCatalogResolver` and the generic media helpers it re-exports
1309
+ from `@pie-players/pie-players-shared/media`. Which card types mean what belongs to the capability that
1194
1310
  needs them — signing's card validators and its resolution rules live in
1195
1311
  `@pie-players/pie-tool-sign-language`, behind that capability's
1196
1312
  `requiresAuthoredContent`.
@@ -1232,18 +1348,21 @@ mounted surface elements immediately.
1232
1348
  The section player provides automatic ToolkitCoordinator integration:
1233
1349
 
1234
1350
  ```html
1235
- <pie-section-player id="player"></pie-section-player>
1351
+ <pie-section-player-splitpane id="player" section-id="section-1"></pie-section-player-splitpane>
1236
1352
 
1237
1353
  <script type="module">
1238
1354
  import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
1355
+ import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
1239
1356
 
1240
1357
  // Create coordinator
1358
+ const toolRegistry = createPackagedToolRegistry();
1241
1359
  const coordinator = new ToolkitCoordinator({
1242
1360
  assessmentId: 'my-assessment',
1361
+ toolRegistry,
1243
1362
  tools: {
1244
1363
  providers: { textToSpeech: { enabled: true, backend: 'browser' } },
1245
1364
  placement: {
1246
- section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
1365
+ section: ['graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
1247
1366
  item: ['calculator', 'textToSpeech', 'answerEliminator'],
1248
1367
  passage: ['textToSpeech']
1249
1368
  }
@@ -1257,7 +1376,7 @@ The section player provides automatic ToolkitCoordinator integration:
1257
1376
 
1258
1377
  // Player automatically:
1259
1378
  // - Extracts services from coordinator
1260
- // - Generates section ID
1379
+ // - Scopes its runtime engine to `section-id`
1261
1380
  // - Provides runtime context to child components
1262
1381
  // - Manages SSML extraction
1263
1382
  // - Handles catalog lifecycle
@@ -1303,15 +1422,9 @@ player.section = mySection;
1303
1422
 
1304
1423
  // Internally creates:
1305
1424
  // new ToolkitCoordinator({
1306
- // assessmentId: 'anon_...', // auto-generated
1307
- // tools: {
1308
- // providers: { textToSpeech: { enabled: true, backend: 'browser' }, calculator: { enabled: true } },
1309
- // placement: {
1310
- // section: ['calculator', 'graph', 'periodicTable', 'protractor', 'lineReader', 'ruler'],
1311
- // item: ['calculator', 'textToSpeech', 'answerEliminator'],
1312
- // passage: ['textToSpeech']
1313
- // }
1314
- // }
1425
+ // assessmentId: 'section-demo-direct', // or the assessment-id attribute
1426
+ // toolRegistry, // the player's toolRegistry, else the packaged registry
1427
+ // tools: player.runtime?.tools // no tools are placed when this is unset
1315
1428
  // })
1316
1429
  ```
1317
1430
 
@@ -1409,8 +1522,9 @@ pick the stability surface that matches their use case:
1409
1522
  ## Writing a capability package
1410
1523
 
1411
1524
  `@pie-players/pie-assessment-toolkit/tools/internal` is what a capability
1412
- package imports: the `ToolRegistration` contract, the surface and content
1413
- dependency types, `resolveToolTag` and the toolbar registration helpers. Same
1525
+ package imports: the `ToolRegistration` contract, the `ToolProviderApi` its
1526
+ provider descriptor creates, the surface and content dependency types,
1527
+ `resolveToolTag` and the toolbar registration helpers. Same
1414
1528
  stability contract as the other `*/internal` entry points — symbols may change
1415
1529
  between minor versions with a changeset note.
1416
1530
 
@@ -1540,8 +1654,9 @@ section-player kernel intercepts the toolkit's bubbled emit at
1540
1654
  layout host sees only the canonical engine-bridge emit. Direct
1541
1655
  listeners on `<pie-assessment-toolkit>` itself still see the toolkit's
1542
1656
  own emit (the toolkit dispatch reaches them before the kernel listener
1543
- runs). The single-emit contract is pinned by
1544
- `packages/section-player/tests/section-player-framework-error-dual-emit.test.ts`.
1657
+ runs). A coordinator the host passes in reports through the same
1658
+ surfaces. `packages/section-player/tests/section-player-event-delivery.spec.ts`
1659
+ pins these counts.
1545
1660
  The layout host emits one `framework-error` DOM event per framework error.
1546
1661
 
1547
1662
  Hosts should listen to `pie-stage-change` (with the readiness detail also
@@ -1608,8 +1723,8 @@ Full TypeScript definitions included:
1608
1723
 
1609
1724
  ```typescript
1610
1725
  import type {
1611
- IToolkitCoordinator,
1612
- IElementToolStateStore,
1726
+ ToolkitCoordinatorApi,
1727
+ ElementToolStateStoreApi,
1613
1728
  ToolkitCoordinatorConfig,
1614
1729
  ToolkitServiceBundle
1615
1730
  } from '@pie-players/pie-assessment-toolkit';
@@ -1623,7 +1738,7 @@ from tool configuration. Two sanitization layers apply:
1623
1738
 
1624
1739
  - **Item / passage markup** - sanitized by default in
1625
1740
  `pie-item-player`. See
1626
- [pie-item-player README](./README.md#content-trust-boundary)
1741
+ [pie-item-player README](../item-player/README.md#content-trust-boundary)
1627
1742
  for the `trust-markup` opt-out and the `sanitizeMarkup` override.
1628
1743
  As a post-sanitization step, every authored `<img>` outside a `pie-*`
1629
1744
  custom element is wrapped in `<span class="pie-image-scroll">` so
@@ -1,14 +1,10 @@
1
1
  import type { AssessmentSession, AssessmentSectionSessionState, AssessmentSessionNavigationState, AssessmentSessionRealization, SectionControllerSessionState } from "@pie-players/pie-players-shared/types";
2
- import type { StorageLike } from "./TestSession.js";
3
2
  /**
4
3
  * Re-exported so every existing import site keeps its specifier. These shapes are
5
4
  * canonical in `@pie-players/pie-players-shared/types`; this module owns the
6
- * storage helpers over them, not the shapes.
5
+ * helpers over them, not the shapes.
7
6
  */
8
7
  export type { AssessmentSession, AssessmentSectionSessionState, AssessmentSessionNavigationState, AssessmentSessionRealization, };
9
- export declare function getAssessmentSessionStorageKey(assessmentAttemptSessionIdentifier: string): string;
10
- export declare function loadAssessmentSession(storage: StorageLike, assessmentAttemptSessionIdentifier: string): AssessmentSession | null;
11
- export declare function saveAssessmentSession(storage: StorageLike, session: AssessmentSession): void;
12
8
  export declare function createNewAssessmentSession(args: {
13
9
  assessmentAttemptSessionIdentifier: string;
14
10
  assessmentId: string;
@@ -1,36 +1,7 @@
1
1
  const ASSESSMENT_SESSION_VERSION = 1;
2
- const STORAGE_PREFIX = "pie:assessment-session:v1:";
3
2
  function nowIso() {
4
3
  return new Date().toISOString();
5
4
  }
6
- export function getAssessmentSessionStorageKey(assessmentAttemptSessionIdentifier) {
7
- return `${STORAGE_PREFIX}${assessmentAttemptSessionIdentifier}`;
8
- }
9
- export function loadAssessmentSession(storage, assessmentAttemptSessionIdentifier) {
10
- const raw = storage.getItem(getAssessmentSessionStorageKey(assessmentAttemptSessionIdentifier));
11
- if (!raw)
12
- return null;
13
- try {
14
- const parsed = JSON.parse(raw);
15
- if (!parsed || parsed.version !== ASSESSMENT_SESSION_VERSION)
16
- return null;
17
- if (parsed.assessmentAttemptSessionIdentifier !==
18
- assessmentAttemptSessionIdentifier) {
19
- return null;
20
- }
21
- return parsed;
22
- }
23
- catch {
24
- return null;
25
- }
26
- }
27
- export function saveAssessmentSession(storage, session) {
28
- const updated = {
29
- ...session,
30
- updatedAt: nowIso(),
31
- };
32
- storage.setItem(getAssessmentSessionStorageKey(session.assessmentAttemptSessionIdentifier), JSON.stringify(updated));
33
- }
34
5
  export function createNewAssessmentSession(args) {
35
6
  const startedAt = nowIso();
36
7
  const initialSectionIdentifier = args.sectionIdentifiers[0];
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- import{a}from"./chunks/ItemToolBar-byq80z42.js";import"./chunks/ItemToolBar-d36g3aw4.js";export{a as default};
1
+ import{a}from"./chunks/ItemToolBar-b9dz5jvd.js";import"./chunks/ItemToolBar-h4xap0t0.js";import"./chunks/ItemToolBar-gmrryv2v.js";export{a as default};