@pie-players/pie-assessment-toolkit 0.3.64 → 0.3.65

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 (47) hide show
  1. package/README.md +45 -17
  2. package/dist/components/ItemToolBar.custom-element.js +1 -1
  3. package/dist/components/PieAssessmentToolkit.custom-element.js +6 -6
  4. package/dist/components/SectionToolBar.custom-element.js +1 -1
  5. package/dist/components/chunks/ItemToolBar-cckwpz6c.js +51 -0
  6. package/dist/components/chunks/ItemToolBar-pryf0rtz.js +22 -0
  7. package/dist/index.d.ts +5 -6
  8. package/dist/index.js +9 -4
  9. package/dist/runtime/composition-emit-scheduler.d.ts +78 -0
  10. package/dist/runtime/composition-emit-scheduler.js +154 -0
  11. package/dist/runtime/core/engine-resolver.d.ts +1 -1
  12. package/dist/services/ToolRegistry.d.ts +218 -8
  13. package/dist/services/ToolRegistry.js +124 -8
  14. package/dist/services/ToolkitCoordinator.d.ts +2 -1
  15. package/dist/services/ToolkitCoordinator.js +23 -6
  16. package/dist/services/createDefaultToolRegistry.d.ts +25 -58
  17. package/dist/services/createDefaultToolRegistry.js +24 -104
  18. package/dist/services/defaultPersonalNeedsProfile.d.ts +16 -14
  19. package/dist/services/defaultPersonalNeedsProfile.js +17 -38
  20. package/dist/services/pnp-standard-features.d.ts +1 -1
  21. package/dist/services/tool-config-defaults.d.ts +7 -23
  22. package/dist/services/tool-config-defaults.js +7 -46
  23. package/dist/services/tool-config-validation.d.ts +1 -1
  24. package/dist/services/tool-config-validation.js +44 -4
  25. package/dist/services/tts/browser-provider.js +2 -1
  26. package/dist/services/tts-runtime-config.js +7 -2
  27. package/dist/tools/internal.d.ts +34 -0
  28. package/dist/tools/internal.js +33 -0
  29. package/dist/tools/tool-tag-map.d.ts +15 -3
  30. package/dist/tools/tool-tag-map.js +21 -18
  31. package/package.json +14 -10
  32. package/dist/components/chunks/ItemToolBar-3cppre9r.js +0 -51
  33. package/dist/components/chunks/ItemToolBar-7rq2gj8b.js +0 -22
  34. package/dist/services/sign-language-cards.d.ts +0 -82
  35. package/dist/services/sign-language-cards.js +0 -133
  36. package/dist/tools/registrations/accessibility-tools.d.ts +0 -34
  37. package/dist/tools/registrations/accessibility-tools.js +0 -217
  38. package/dist/tools/registrations/calculator.d.ts +0 -20
  39. package/dist/tools/registrations/calculator.js +0 -228
  40. package/dist/tools/registrations/interaction-tools.d.ts +0 -27
  41. package/dist/tools/registrations/interaction-tools.js +0 -143
  42. package/dist/tools/registrations/measurement-tools.d.ts +0 -24
  43. package/dist/tools/registrations/measurement-tools.js +0 -130
  44. package/dist/tools/registrations/subject-specific-tools.d.ts +0 -27
  45. package/dist/tools/registrations/subject-specific-tools.js +0 -158
  46. package/dist/tools/registrations/tts.d.ts +0 -21
  47. package/dist/tools/registrations/tts.js +0 -184
@@ -25,7 +25,7 @@ import { TTSService } from "./TTSService.js";
25
25
  import { BrowserTTSProvider } from "./tts/browser-provider.js";
26
26
  import { buildRuntimeTTSConfig, resolveTTSBackend, resolveTTSRuntimeSettings, } from "./tts-runtime-config.js";
27
27
  import { ToolProviderRegistry } from "./tool-providers/index.js";
28
- import { createPackagedToolRegistry } from "./createDefaultToolRegistry.js";
28
+ import { ToolRegistry } from "./ToolRegistry.js";
29
29
  import { ToolPolicyEngine, } from "../policy/engine.js";
30
30
  import { resolveDefaultPnpEnforcement } from "../policy/internal.js";
31
31
  const isPlainRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
@@ -190,7 +190,13 @@ export class ToolkitCoordinator {
190
190
  boundCurrentItemRef = null;
191
191
  static resolveConfig(config) {
192
192
  const strictness = normalizeToolConfigStrictness(config.toolConfigStrictness);
193
- const toolRegistry = config.toolRegistry ?? createPackagedToolRegistry();
193
+ // An empty registry when the host supplies none. This package no longer
194
+ // holds the packaged capability set, so there is nothing to fall back to —
195
+ // a host that wants stock tools passes a registry from
196
+ // `@pie-players/pie-default-tool-loaders`. Tool-id validation is skipped
197
+ // against an empty registry (with a diagnostic saying so) rather than
198
+ // rejecting every configured id.
199
+ const toolRegistry = config.toolRegistry ?? new ToolRegistry();
194
200
  const normalized = config.deferToolConfigValidation === true
195
201
  ? normalizeToolsConfig(config.tools)
196
202
  : normalizeAndValidateToolsConfig(config.tools, {
@@ -232,8 +238,7 @@ export class ToolkitCoordinator {
232
238
  const resolvedConfig = ToolkitCoordinator.resolveConfig(config);
233
239
  this.assessmentId = resolvedConfig.assessmentId;
234
240
  this.config = resolvedConfig;
235
- this.toolRegistry =
236
- resolvedConfig.toolRegistry ?? createPackagedToolRegistry();
241
+ this.toolRegistry = resolvedConfig.toolRegistry ?? new ToolRegistry();
237
242
  this.installToolContextResolvers(resolvedConfig.toolContextResolvers);
238
243
  this.hooks = resolvedConfig.hooks ?? {};
239
244
  this.lazyInit = config.lazyInit === true;
@@ -1268,13 +1273,16 @@ export class ToolkitCoordinator {
1268
1273
  if (canUseEventTarget) {
1269
1274
  synth.removeEventListener("voiceschanged", onVoicesChanged);
1270
1275
  }
1271
- else if (assignedHandler && synth.onvoiceschanged === onVoicesChanged) {
1276
+ else if (assignedHandler &&
1277
+ synth.onvoiceschanged === onVoicesChanged) {
1272
1278
  synth.onvoiceschanged = previousHandler;
1273
1279
  }
1274
1280
  resolve();
1275
1281
  };
1276
1282
  const onVoicesChanged = (event) => {
1277
- if (!canUseEventTarget && typeof previousHandler === "function" && event) {
1283
+ if (!canUseEventTarget &&
1284
+ typeof previousHandler === "function" &&
1285
+ event) {
1278
1286
  previousHandler.call(synth, event);
1279
1287
  }
1280
1288
  finish();
@@ -1371,6 +1379,15 @@ export class ToolkitCoordinator {
1371
1379
  if (toolId === "tts") {
1372
1380
  throw new Error(`Tool id "tts" is no longer supported. Use "textToSpeech".`);
1373
1381
  }
1382
+ // An empty registry means the host supplied none, not that every id is
1383
+ // wrong. There is nothing to check an id against, and throwing turns a
1384
+ // host's every tool-config call into an exception — including the calls
1385
+ // this coordinator's own default-provider block provokes, which is how a
1386
+ // host that passes no registry ended up unable to read its own config.
1387
+ // `normalizeAndValidateToolsConfig` already reports the missing registry
1388
+ // once, as `tools.registryUnavailable`; a second report per call is noise.
1389
+ if (this.toolRegistry.getAllToolIds().length === 0)
1390
+ return;
1374
1391
  if (!this.toolRegistry.get(toolId)) {
1375
1392
  throw new Error(`Unknown tool id "${toolId}".`);
1376
1393
  }
@@ -1,86 +1,53 @@
1
1
  /**
2
- * Default Tool Registry Factory
2
+ * Tool Registry Factory
3
3
  *
4
- * Creates a ToolRegistry pre-populated with all PIE framework tools.
5
- * Integrators can use this as a starting point and customize as needed.
4
+ * Creates an empty `ToolRegistry` and installs whatever component overrides and
5
+ * lazy module loaders the caller supplies.
6
+ *
7
+ * It registers nothing by itself, deliberately. Eleven concrete registrations
8
+ * used to live in this package, which made the policy and registry core know
9
+ * every capability by name and left a host unable to contribute one without a PR
10
+ * against this package. The packaged set now lives in the composition layer:
11
+ * `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
6
12
  */
13
+ import type { ToolRegistration, ToolModuleLoader } from "./ToolRegistry.js";
7
14
  import { ToolRegistry } from "./ToolRegistry.js";
8
- import type { ToolRegistration } from "./ToolRegistry.js";
9
- import type { ToolModuleLoader } from "./ToolRegistry.js";
10
- import { type ToolComponentFactory, type ToolComponentFactoryMap, type ToolTagMap } from "../tools/tool-tag-map.js";
11
- import { DEFAULT_TOOL_PLACEMENT, PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT } from "./tool-config-defaults.js";
15
+ import type { ToolComponentFactory, ToolComponentFactoryMap, ToolTagMap } from "../tools/tool-tag-map.js";
16
+ import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
12
17
  export interface DefaultToolRegistryOptions {
13
18
  /**
14
- * Override default tool registrations by toolId.
15
- * This is the highest-precedence extension point.
19
+ * Registrations to register, keyed by toolId. Nothing is registered when this
20
+ * is absent.
16
21
  */
17
- overrides?: Partial<Record<string, ToolRegistration>>;
22
+ registrations?: Partial<Record<string, ToolRegistration>>;
18
23
  /**
19
- * Override default component tag mapping used by built-in registrations.
24
+ * Element tag mapping for the registrations being installed. There is no
25
+ * built-in default: a tag map names capabilities, so it belongs to whoever
26
+ * decides which capabilities exist.
20
27
  */
21
28
  toolTagMap?: Partial<ToolTagMap>;
22
29
  /**
23
- * Override component factory globally (all tools) or per tool.
30
+ * Override component creation globally (all tools) or per tool.
24
31
  */
25
32
  toolComponentFactory?: ToolComponentFactory;
26
33
  toolComponentFactories?: Partial<ToolComponentFactoryMap>;
27
34
  /**
28
35
  * Optional lazy module loaders keyed by toolId.
29
- * Hosts can inject default loaders from an external package.
30
36
  */
31
37
  toolModuleLoaders?: Partial<Record<string, ToolModuleLoader>>;
32
- /**
33
- * Register packaged PIE tools by default.
34
- *
35
- * @default false
36
- */
37
- includePackagedTools?: boolean;
38
- /**
39
- * Restrict registration to specific packaged tool IDs.
40
- * Ignored when includePackagedTools is false.
41
- */
42
- toolIds?: string[];
43
38
  }
44
39
  /**
45
40
  * Create a tool registry.
46
41
  *
47
- * By default, this creates an empty registry so hosts can explicitly opt in.
48
- * For convenience, pass { includePackagedTools: true } to register all packaged tools,
49
- * or use createPackagedToolRegistry().
50
- *
51
- * @returns ToolRegistry with all default tools
42
+ * @returns an empty `ToolRegistry` unless `registrations` is supplied
52
43
  */
53
44
  export declare function createDefaultToolRegistry(options?: DefaultToolRegistryOptions): ToolRegistry;
54
- export interface RegisterPackagedToolsOptions {
55
- toolIds?: string[];
56
- applyOverrides?: (registration: ToolRegistration) => ToolRegistration;
57
- }
58
45
  /**
59
- * Register packaged PIE tools onto an existing registry.
60
- */
61
- export declare function registerPackagedTools(registry: ToolRegistry, options?: RegisterPackagedToolsOptions): void;
62
- /**
63
- * Convenience factory that registers all packaged PIE tools.
64
- */
65
- export declare function createPackagedToolRegistry(options?: Omit<DefaultToolRegistryOptions, "includePackagedTools">): ToolRegistry;
66
- /**
67
- * Default tool placement configuration
46
+ * Placement configuration with every level empty.
68
47
  *
69
- * Defines which tools appear at which levels by default.
70
- * Integrators can override this configuration.
71
- *
72
- * Categories:
73
- * - Global tools: theme (assessment/section level)
74
- * - Context-smart: calculator, graph, periodicTable (item/element, auto-detect)
75
- * - Reading aids: textToSpeech, lineReader, annotationToolbar (where text exists)
76
- * - Interaction-specific: answerEliminator (choice questions), highlighter (text)
77
- * - Measurement: ruler, protractor (element level, diagram/geometry)
48
+ * The only placement default this package can hold: a populated one would name
49
+ * capabilities. `PACKAGED_TOOL_PLACEMENT` and
50
+ * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
51
+ * `@pie-players/pie-default-tool-loaders`.
78
52
  */
79
53
  export { DEFAULT_TOOL_PLACEMENT };
80
- export { PACKAGED_TOOL_PLACEMENT };
81
- export { SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT };
82
- /**
83
- * Tool priority order for rendering
84
- * Tools will be rendered in this order when multiple tools are visible
85
- */
86
- export declare const DEFAULT_TOOL_ORDER: readonly ["theme", "calculator", "textToSpeech", "lineReader", "annotationToolbar", "highlighter", "answerEliminator", "ruler", "protractor", "graph", "periodicTable"];
@@ -1,125 +1,45 @@
1
1
  /**
2
- * Default Tool Registry Factory
2
+ * Tool Registry Factory
3
3
  *
4
- * Creates a ToolRegistry pre-populated with all PIE framework tools.
5
- * Integrators can use this as a starting point and customize as needed.
4
+ * Creates an empty `ToolRegistry` and installs whatever component overrides and
5
+ * lazy module loaders the caller supplies.
6
+ *
7
+ * It registers nothing by itself, deliberately. Eleven concrete registrations
8
+ * used to live in this package, which made the policy and registry core know
9
+ * every capability by name and left a host unable to contribute one without a PR
10
+ * against this package. The packaged set now lives in the composition layer:
11
+ * `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
6
12
  */
7
13
  import { ToolRegistry } from "./ToolRegistry.js";
8
- import { calculatorToolRegistration } from "../tools/registrations/calculator.js";
9
- import { ttsToolRegistration } from "../tools/registrations/tts.js";
10
- import { rulerToolRegistration, protractorToolRegistration, } from "../tools/registrations/measurement-tools.js";
11
- import { answerEliminatorToolRegistration, highlighterToolRegistration, } from "../tools/registrations/interaction-tools.js";
12
- import { lineReaderToolRegistration, themeToolRegistration, annotationToolbarRegistration, } from "../tools/registrations/accessibility-tools.js";
13
- import { graphToolRegistration, periodicTableToolRegistration, } from "../tools/registrations/subject-specific-tools.js";
14
- import { DEFAULT_TOOL_TAG_MAP, } from "../tools/tool-tag-map.js";
15
- import { DEFAULT_TOOL_PLACEMENT, PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT, } from "./tool-config-defaults.js";
16
- const PACKAGED_TOOL_REGISTRATIONS = [
17
- calculatorToolRegistration,
18
- ttsToolRegistration,
19
- rulerToolRegistration,
20
- protractorToolRegistration,
21
- answerEliminatorToolRegistration,
22
- highlighterToolRegistration,
23
- lineReaderToolRegistration,
24
- themeToolRegistration,
25
- annotationToolbarRegistration,
26
- graphToolRegistration,
27
- periodicTableToolRegistration,
28
- ];
14
+ import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
29
15
  /**
30
16
  * Create a tool registry.
31
17
  *
32
- * By default, this creates an empty registry so hosts can explicitly opt in.
33
- * For convenience, pass { includePackagedTools: true } to register all packaged tools,
34
- * or use createPackagedToolRegistry().
35
- *
36
- * @returns ToolRegistry with all default tools
18
+ * @returns an empty `ToolRegistry` unless `registrations` is supplied
37
19
  */
38
20
  export function createDefaultToolRegistry(options = {}) {
39
21
  const registry = new ToolRegistry();
40
- const componentConfig = {
41
- toolTagMap: {
42
- ...DEFAULT_TOOL_TAG_MAP,
43
- ...(options.toolTagMap || {}),
44
- },
45
- toolComponentFactory: options.toolComponentFactory,
46
- toolComponentFactories: options.toolComponentFactories,
47
- };
48
- const applyOverrides = (registration) => options.overrides?.[registration.toolId] || registration;
49
- if (options.includePackagedTools) {
50
- registerPackagedTools(registry, {
51
- toolIds: options.toolIds,
52
- applyOverrides,
53
- });
22
+ for (const registration of Object.values(options.registrations ?? {})) {
23
+ if (registration)
24
+ registry.register(registration);
54
25
  }
55
26
  if (options.toolModuleLoaders &&
56
27
  Object.keys(options.toolModuleLoaders).length > 0) {
57
28
  registry.setToolModuleLoaders(options.toolModuleLoaders);
58
29
  }
59
- registry.setComponentOverrides(componentConfig);
60
- return registry;
61
- }
62
- /**
63
- * Register packaged PIE tools onto an existing registry.
64
- */
65
- export function registerPackagedTools(registry, options = {}) {
66
- const selectedToolIds = options.toolIds && options.toolIds.length > 0
67
- ? new Set(options.toolIds)
68
- : null;
69
- const applyOverrides = options.applyOverrides ||
70
- ((registration) => registration);
71
- for (const registration of PACKAGED_TOOL_REGISTRATIONS) {
72
- if (selectedToolIds && !selectedToolIds.has(registration.toolId)) {
73
- continue;
74
- }
75
- registry.register(applyOverrides(registration));
76
- }
77
- }
78
- /**
79
- * Convenience factory that registers all packaged PIE tools.
80
- */
81
- export function createPackagedToolRegistry(options = {}) {
82
- return createDefaultToolRegistry({
83
- ...options,
84
- includePackagedTools: true,
30
+ registry.setComponentOverrides({
31
+ toolTagMap: options.toolTagMap,
32
+ toolComponentFactory: options.toolComponentFactory,
33
+ toolComponentFactories: options.toolComponentFactories,
85
34
  });
35
+ return registry;
86
36
  }
87
37
  /**
88
- * Default tool placement configuration
89
- *
90
- * Defines which tools appear at which levels by default.
91
- * Integrators can override this configuration.
38
+ * Placement configuration with every level empty.
92
39
  *
93
- * Categories:
94
- * - Global tools: theme (assessment/section level)
95
- * - Context-smart: calculator, graph, periodicTable (item/element, auto-detect)
96
- * - Reading aids: textToSpeech, lineReader, annotationToolbar (where text exists)
97
- * - Interaction-specific: answerEliminator (choice questions), highlighter (text)
98
- * - Measurement: ruler, protractor (element level, diagram/geometry)
40
+ * The only placement default this package can hold: a populated one would name
41
+ * capabilities. `PACKAGED_TOOL_PLACEMENT` and
42
+ * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
43
+ * `@pie-players/pie-default-tool-loaders`.
99
44
  */
100
45
  export { DEFAULT_TOOL_PLACEMENT };
101
- export { PACKAGED_TOOL_PLACEMENT };
102
- export { SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT };
103
- /**
104
- * Tool priority order for rendering
105
- * Tools will be rendered in this order when multiple tools are visible
106
- */
107
- export const DEFAULT_TOOL_ORDER = [
108
- // Global accessibility first
109
- "theme",
110
- // Common tools
111
- "calculator",
112
- "textToSpeech",
113
- // Reading aids
114
- "lineReader",
115
- "annotationToolbar",
116
- "highlighter",
117
- // Interaction tools
118
- "answerEliminator",
119
- // Measurement tools
120
- "ruler",
121
- "protractor",
122
- // Subject-specific
123
- "graph",
124
- "periodicTable",
125
- ];
@@ -1,19 +1,21 @@
1
1
  import type { PersonalNeedsProfile } from "@pie-players/pie-players-shared/types";
2
2
  /**
3
- * PNP support ids that must never enter the computed default profile, however
4
- * they reach the registry.
3
+ * An empty personal-needs profile: nothing granted, nothing prohibited, nothing
4
+ * activated at init.
5
5
  *
6
- * `computeDefaultSupports()` derives the fallback profile from every registered
7
- * tool's `pnpSupportIds`, which is right for universal features — a highlighter
8
- * or a zoom control should be there for every student by default. It is wrong
9
- * for an **accommodation**: signing requires a documented need (IEP / 504), so
10
- * granting it to every host that does not supply its own profile would invert
11
- * the eligibility tier. Registry membership is about being policy-addressable,
12
- * not about who may enable it.
6
+ * The core ships no populated default on purpose. It once derived one from every
7
+ * registered tool's `pnpSupportIds`, which read *registry membership* as
8
+ * *eligibility tier* registration means "policy-addressable", not "universal,
9
+ * on by default" so an accommodation-tier capability was granted to every
10
+ * student of every host that supplied no profile. The remedy at the time was a
11
+ * compile-time list of ids to exclude, which a host could not extend for its own
12
+ * accommodation.
13
13
  *
14
- * Excluded here rather than by declining to register, so the guarantee holds
15
- * even if a signing tool is later registered for some other reason.
14
+ * Which capabilities a deployment grants by default is a property of the
15
+ * program, not of this package: TTS is a universal feature in one program and a
16
+ * documented accommodation in another. That belongs in policy configuration
17
+ * alongside the district and test-administration levels. A named preset of
18
+ * today's universal set ships as data from
19
+ * `@pie-players/pie-default-tool-loaders`, for hosts that want it.
16
20
  */
17
- export declare const ACCOMMODATION_ONLY_SUPPORT_IDS: readonly string[];
18
- export declare const DEFAULT_PERSONAL_NEEDS_PROFILE: PersonalNeedsProfile;
19
- export declare function createDefaultPersonalNeedsProfile(): PersonalNeedsProfile;
21
+ export declare function createEmptyPersonalNeedsProfile(): PersonalNeedsProfile;
@@ -1,46 +1,25 @@
1
- import { createPackagedToolRegistry } from "./createDefaultToolRegistry.js";
2
1
  /**
3
- * PNP support ids that must never enter the computed default profile, however
4
- * they reach the registry.
2
+ * An empty personal-needs profile: nothing granted, nothing prohibited, nothing
3
+ * activated at init.
5
4
  *
6
- * `computeDefaultSupports()` derives the fallback profile from every registered
7
- * tool's `pnpSupportIds`, which is right for universal features — a highlighter
8
- * or a zoom control should be there for every student by default. It is wrong
9
- * for an **accommodation**: signing requires a documented need (IEP / 504), so
10
- * granting it to every host that does not supply its own profile would invert
11
- * the eligibility tier. Registry membership is about being policy-addressable,
12
- * not about who may enable it.
5
+ * The core ships no populated default on purpose. It once derived one from every
6
+ * registered tool's `pnpSupportIds`, which read *registry membership* as
7
+ * *eligibility tier* registration means "policy-addressable", not "universal,
8
+ * on by default" so an accommodation-tier capability was granted to every
9
+ * student of every host that supplied no profile. The remedy at the time was a
10
+ * compile-time list of ids to exclude, which a host could not extend for its own
11
+ * accommodation.
13
12
  *
14
- * Excluded here rather than by declining to register, so the guarantee holds
15
- * even if a signing tool is later registered for some other reason.
13
+ * Which capabilities a deployment grants by default is a property of the
14
+ * program, not of this package: TTS is a universal feature in one program and a
15
+ * documented accommodation in another. That belongs in policy configuration
16
+ * alongside the district and test-administration levels. A named preset of
17
+ * today's universal set ships as data from
18
+ * `@pie-players/pie-default-tool-loaders`, for hosts that want it.
16
19
  */
17
- export const ACCOMMODATION_ONLY_SUPPORT_IDS = [
18
- // QTI 3.0 / AfA `signLanguage`. Signed alternates are rendered by
19
- // section-player's per-item media region, gated on this id.
20
- "signLanguage",
21
- ];
22
- function computeDefaultSupports() {
23
- const registry = createPackagedToolRegistry();
24
- const supports = new Set();
25
- const excluded = new Set(ACCOMMODATION_ONLY_SUPPORT_IDS);
26
- for (const tool of registry.getAllTools()) {
27
- for (const supportId of tool.pnpSupportIds || []) {
28
- if (excluded.has(supportId))
29
- continue;
30
- supports.add(supportId);
31
- }
32
- }
33
- return [...supports].sort();
34
- }
35
- const DEFAULT_SUPPORTS = computeDefaultSupports();
36
- export const DEFAULT_PERSONAL_NEEDS_PROFILE = {
37
- supports: [...DEFAULT_SUPPORTS],
38
- prohibitedSupports: [],
39
- activateAtInit: [],
40
- };
41
- export function createDefaultPersonalNeedsProfile() {
20
+ export function createEmptyPersonalNeedsProfile() {
42
21
  return {
43
- supports: [...DEFAULT_SUPPORTS],
22
+ supports: [],
44
23
  prohibitedSupports: [],
45
24
  activateAtInit: [],
46
25
  };
@@ -167,7 +167,7 @@ export declare const QTI_STANDARD_ACCESS_FEATURES: {
167
167
  /**
168
168
  * Flat list of all standard access features for validation
169
169
  */
170
- export declare const ALL_STANDARD_ACCESS_FEATURES: ("transcript" | "braille" | "textToSpeech" | "graph" | "periodicTable" | "calculator" | "answerEliminator" | "ruler" | "protractor" | "graphingCalculator" | "readAloud" | "strikethrough" | "answerMasking" | "readingMask" | "readingGuide" | "readingRuler" | "highContrastDisplay" | "colorContrast" | "invertColors" | "highlighting" | "annotations" | "signLanguage" | "magnification" | "screenMagnifier" | "zoomable" | "highContrastAudio" | "displayTransformability" | "largePrint" | "fontEnlargement" | "resizeText" | "alternativeText" | "longDescription" | "describedMath" | "tactileGraphic" | "tactileObject" | "audioDescription" | "humanVoice" | "syntheticVoice" | "speechRate" | "speechVolume" | "voicePitch" | "captions" | "closedCaptions" | "openCaptions" | "subtitles" | "audioControl" | "noBackgroundAudio" | "keyboardControl" | "mouseControl" | "touchControl" | "voiceControl" | "switchControl" | "eyeGazeControl" | "singleSwitchAccess" | "stickyKeys" | "keyboardShortcuts" | "timingControl" | "unlimitedTime" | "extendedTime" | "pauseControl" | "simplifiedLanguage" | "reducedComplexity" | "structuralNavigation" | "tableOfContents" | "reducedDistraction" | "noFlashing" | "pauseAnimation" | "bookmarking" | "guidedNavigation" | "thesaurus" | "spellingAssistance" | "grammarAssistance" | "lineSpacing" | "wordSpacing" | "letterSpacing" | "fontFamily" | "wordHighlighting" | "lineHighlighting" | "focusIndicator" | "printableResource" | "nemeth" | "refreshableBraille" | "index" | "pageNavigation" | "skipContent" | "breadcrumbs" | "searchable" | "fullTextSearch" | "multilingualText" | "translatedText" | "glossary" | "signLanguageInterpretation" | "visualLanguage" | "formulaSheet" | "itemGlossary" | "tutorialAvailable")[];
170
+ export declare const ALL_STANDARD_ACCESS_FEATURES: ("transcript" | "braille" | "textToSpeech" | "calculator" | "strikethrough" | "answerEliminator" | "magnification" | "screenMagnifier" | "zoomable" | "highContrastDisplay" | "highContrastAudio" | "colorContrast" | "invertColors" | "displayTransformability" | "largePrint" | "fontEnlargement" | "resizeText" | "alternativeText" | "longDescription" | "describedMath" | "tactileGraphic" | "tactileObject" | "audioDescription" | "readAloud" | "humanVoice" | "syntheticVoice" | "speechRate" | "speechVolume" | "voicePitch" | "captions" | "closedCaptions" | "openCaptions" | "signLanguage" | "subtitles" | "audioControl" | "noBackgroundAudio" | "keyboardControl" | "mouseControl" | "touchControl" | "voiceControl" | "switchControl" | "eyeGazeControl" | "singleSwitchAccess" | "stickyKeys" | "keyboardShortcuts" | "timingControl" | "unlimitedTime" | "extendedTime" | "pauseControl" | "simplifiedLanguage" | "reducedComplexity" | "structuralNavigation" | "tableOfContents" | "reducedDistraction" | "noFlashing" | "pauseAnimation" | "annotations" | "bookmarking" | "highlighting" | "guidedNavigation" | "thesaurus" | "spellingAssistance" | "grammarAssistance" | "lineSpacing" | "wordSpacing" | "letterSpacing" | "fontFamily" | "readingMask" | "readingGuide" | "readingRuler" | "wordHighlighting" | "lineHighlighting" | "focusIndicator" | "printableResource" | "nemeth" | "refreshableBraille" | "index" | "pageNavigation" | "skipContent" | "breadcrumbs" | "searchable" | "fullTextSearch" | "multilingualText" | "translatedText" | "glossary" | "signLanguageInterpretation" | "visualLanguage" | "protractor" | "ruler" | "graph" | "graphingCalculator" | "periodicTable" | "formulaSheet" | "answerMasking" | "itemGlossary" | "tutorialAvailable")[];
171
171
  /**
172
172
  * Example PNP configurations for common accessibility needs
173
173
  * These are NOT official profiles but illustrative examples showing
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Placement defaults this package can hold.
3
+ *
4
+ * Only the empty one. `PACKAGED_TOOL_PLACEMENT` and
5
+ * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` name capabilities, so they moved to
6
+ * the composition layer (`@pie-players/pie-default-tool-loaders`).
7
+ */
1
8
  export declare const DEFAULT_TOOL_PLACEMENT: {
2
9
  readonly assessment: readonly [];
3
10
  readonly section: readonly [];
@@ -6,26 +13,3 @@ export declare const DEFAULT_TOOL_PLACEMENT: {
6
13
  readonly rubric: readonly [];
7
14
  readonly element: readonly [];
8
15
  };
9
- /**
10
- * Complete placement preset for hosts that want to enable all packaged tools.
11
- * Prefer explicit host configuration over implicit defaults.
12
- */
13
- export declare const PACKAGED_TOOL_PLACEMENT: {
14
- readonly assessment: readonly ["theme"];
15
- readonly section: readonly ["theme"];
16
- readonly item: readonly ["textToSpeech", "highlighter", "annotationToolbar", "graph", "periodicTable"];
17
- readonly passage: readonly ["textToSpeech", "highlighter", "annotationToolbar", "lineReader"];
18
- readonly rubric: readonly ["textToSpeech", "highlighter", "annotationToolbar", "lineReader"];
19
- readonly element: readonly ["calculator", "answerEliminator", "textToSpeech", "ruler", "protractor", "highlighter", "annotationToolbar", "graph", "periodicTable"];
20
- };
21
- /**
22
- * Opt-in section-player placement preset for hosts that want to expose every
23
- * packaged tool once at its normal assessment surface. This is not exhaustive:
24
- * `supportedLevels` still defines where tools can run, and hosts can still
25
- * choose different placement for custom UX.
26
- */
27
- export declare const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT: {
28
- section: string[];
29
- item: string[];
30
- passage: string[];
31
- };
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Placement defaults this package can hold.
3
+ *
4
+ * Only the empty one. `PACKAGED_TOOL_PLACEMENT` and
5
+ * `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` name capabilities, so they moved to
6
+ * the composition layer (`@pie-players/pie-default-tool-loaders`).
7
+ */
1
8
  export const DEFAULT_TOOL_PLACEMENT = {
2
9
  assessment: [],
3
10
  section: [],
@@ -6,49 +13,3 @@ export const DEFAULT_TOOL_PLACEMENT = {
6
13
  rubric: [],
7
14
  element: [],
8
15
  };
9
- /**
10
- * Complete placement preset for hosts that want to enable all packaged tools.
11
- * Prefer explicit host configuration over implicit defaults.
12
- */
13
- export const PACKAGED_TOOL_PLACEMENT = {
14
- assessment: ["theme"],
15
- section: ["theme"],
16
- item: [
17
- "textToSpeech",
18
- "highlighter",
19
- "annotationToolbar",
20
- "graph",
21
- "periodicTable",
22
- ],
23
- passage: ["textToSpeech", "highlighter", "annotationToolbar", "lineReader"],
24
- rubric: ["textToSpeech", "highlighter", "annotationToolbar", "lineReader"],
25
- element: [
26
- "calculator",
27
- "answerEliminator",
28
- "textToSpeech",
29
- "ruler",
30
- "protractor",
31
- "highlighter",
32
- "annotationToolbar",
33
- "graph",
34
- "periodicTable",
35
- ],
36
- };
37
- /**
38
- * Opt-in section-player placement preset for hosts that want to expose every
39
- * packaged tool once at its normal assessment surface. This is not exhaustive:
40
- * `supportedLevels` still defines where tools can run, and hosts can still
41
- * choose different placement for custom UX.
42
- */
43
- export const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT = {
44
- section: [
45
- "theme",
46
- "graph",
47
- "periodicTable",
48
- "lineReader",
49
- "ruler",
50
- "protractor",
51
- ],
52
- item: ["calculator", "textToSpeech", "answerEliminator", "annotationToolbar"],
53
- passage: ["textToSpeech", "annotationToolbar"],
54
- };
@@ -4,7 +4,7 @@ import type { ToolRegistry } from "./ToolRegistry.js";
4
4
  export type ToolConfigStrictness = "off" | "warn" | "error";
5
5
  export type ToolConfigDiagnosticSeverity = "warning" | "error";
6
6
  export interface ToolConfigDiagnostic {
7
- code: "tools.unknownToolId" | "tools.unsupportedLevel" | "tools.unknownProviderKey" | "tools.removedProviderKey" | "tools.providerSanitizeFailed" | "tools.providerValidateFailed" | "tools.invalidProviderValidation";
7
+ code: "tools.unknownToolId" | "tools.unsupportedLevel" | "tools.unplaceableActivation" | "tools.registryUnavailable" | "tools.unknownProviderKey" | "tools.removedProviderKey" | "tools.providerSanitizeFailed" | "tools.providerValidateFailed" | "tools.invalidProviderValidation";
8
8
  severity: ToolConfigDiagnosticSeverity;
9
9
  path: string;
10
10
  message: string;
@@ -1,6 +1,5 @@
1
1
  import { normalizeToolsConfig, } from "./tools-config-normalizer.js";
2
2
  import { frameworkErrorFromToolConfigDiagnostics, frameworkErrorFromUnknown, } from "./framework-error.js";
3
- import { createPackagedToolRegistry } from "./createDefaultToolRegistry.js";
4
3
  export function frameworkErrorFromToolConfigValidation(args) {
5
4
  if (Array.isArray(args.diagnostics) && args.diagnostics.length > 0) {
6
5
  return frameworkErrorFromToolConfigDiagnostics({
@@ -120,6 +119,20 @@ function collectPlacementDiagnostics(config, toolMap, diagnostics) {
120
119
  }));
121
120
  continue;
122
121
  }
122
+ if (tool.activation === "region") {
123
+ // A region capability has no toolbar button, so placing it names a
124
+ // surface that will never render it. Reported at the placement rather
125
+ // than at render time, where the symptom is an absent accommodation and
126
+ // no error.
127
+ diagnostics.push(createDiagnostic({
128
+ code: "tools.unplaceableActivation",
129
+ severity: "error",
130
+ path: `placement.${level}`,
131
+ message: `Tool "${toolId}" renders into a host surface (activation "region") and cannot be placed on the ${level} toolbar. Remove it from placement.${level}; its availability comes from policy plus its content dependency.`,
132
+ toolId,
133
+ }));
134
+ continue;
135
+ }
123
136
  const supportsLevel = tool.supportedLevels.includes(level);
124
137
  // Leniency policy: section-capable tools are tolerated in item placement.
125
138
  // This avoids strict failures for common host config patterns while still
@@ -204,9 +217,27 @@ function throwValidationError(diagnostics, source) {
204
217
  export function normalizeAndValidateToolsConfig(input, options = {}) {
205
218
  const strictness = normalizeToolConfigStrictness(options.strictness);
206
219
  const source = options.source ?? "tools";
207
- const registryTools = getRegistryToolMap(options.toolRegistry ?? createPackagedToolRegistry());
220
+ const registryTools = getRegistryToolMap(options.toolRegistry);
208
221
  const normalized = normalizeToolsConfig(input);
209
222
  const diagnostics = [];
223
+ // Tool-id and provider checks need a registry to check against, and every
224
+ // collector below returns early without one. Say so: this package no longer
225
+ // falls back to a packaged registry, so a caller that used to get id
226
+ // validation for free now gets none, and a silent downgrade from "your ids are
227
+ // valid" to "nobody looked" is the kind of change that surfaces as a typo
228
+ // reaching a learner.
229
+ const hasConfiguredTools = Object.values(normalized.placement).some((ids) => ids.length > 0) ||
230
+ Object.keys(normalized.providers).length > 0 ||
231
+ (normalized.policy.allowed?.length ?? 0) > 0 ||
232
+ (normalized.policy.blocked?.length ?? 0) > 0;
233
+ if (registryTools.size === 0 && hasConfiguredTools) {
234
+ diagnostics.push(createDiagnostic({
235
+ code: "tools.registryUnavailable",
236
+ severity: "warning",
237
+ path: "tools",
238
+ message: 'No tool registry was supplied, so tool ids, placement levels and provider config were not validated. Pass `toolRegistry` — for the packaged capability set, `createPackagedToolRegistry()` from "@pie-players/pie-default-tool-loaders".',
239
+ }));
240
+ }
210
241
  const hasRemovedTtsKey = Object.hasOwn(normalized.providers, "tts");
211
242
  const nextProviders = {
212
243
  ...(normalized.providers || {}),
@@ -233,8 +264,17 @@ export function normalizeAndValidateToolsConfig(input, options = {}) {
233
264
  if (strictness === "warn") {
234
265
  emitWarnings(diagnostics, source);
235
266
  }
236
- if (strictness === "error" && diagnostics.length > 0) {
237
- throwValidationError(diagnostics, source);
267
+ // Severity decides what `strictness: "error"` rejects. Every diagnostic this
268
+ // function raised was `"error"` until `tools.registryUnavailable`, which
269
+ // reports that validation could not run rather than that the config is wrong —
270
+ // throwing on it would turn "no registry supplied" from a host's existing,
271
+ // working setup into a construction failure.
272
+ const blocking = diagnostics.filter((entry) => entry.severity === "error");
273
+ if (strictness === "error" && blocking.length > 0) {
274
+ throwValidationError(blocking, source);
275
+ }
276
+ if (strictness === "error" && blocking.length === 0) {
277
+ emitWarnings(diagnostics, source);
238
278
  }
239
279
  return {
240
280
  config: nextConfig,