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

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 (74) hide show
  1. package/README.md +81 -33
  2. package/dist/components/ItemToolBar.custom-element.js +1 -1
  3. package/dist/components/PieAssessmentToolkit.custom-element.js +9 -8
  4. package/dist/components/SectionToolBar.custom-element.js +1 -1
  5. package/dist/components/chunks/ItemToolBar-8jgdz50p.js +51 -0
  6. package/dist/components/chunks/ItemToolBar-cvs646j3.js +36 -0
  7. package/dist/index.d.ts +7 -8
  8. package/dist/index.js +10 -5
  9. package/dist/policy/core/PolicySource.d.ts +2 -2
  10. package/dist/policy/core/PolicySource.js +2 -2
  11. package/dist/policy/core/ToolPolicyEngine.d.ts +7 -3
  12. package/dist/policy/core/ToolPolicyEngine.js +11 -3
  13. package/dist/policy/core/compose-decision.d.ts +3 -2
  14. package/dist/policy/core/compose-decision.js +3 -2
  15. package/dist/policy/core/decision-types.d.ts +2 -2
  16. package/dist/policy/core/decision-types.js +2 -2
  17. package/dist/policy/core/feature-decision.d.ts +28 -1
  18. package/dist/policy/core/feature-decision.js +25 -3
  19. package/dist/policy/core/pnp-policy-inputs.d.ts +2 -2
  20. package/dist/policy/core/pnp-policy-inputs.js +2 -2
  21. package/dist/policy/core/provenance.d.ts +4 -1
  22. package/dist/policy/core/provenance.js +4 -1
  23. package/dist/policy/sources/PnpPolicySource.d.ts +2 -1
  24. package/dist/policy/sources/PnpPolicySource.js +2 -1
  25. package/dist/runtime/composition-emit-scheduler.d.ts +78 -0
  26. package/dist/runtime/composition-emit-scheduler.js +154 -0
  27. package/dist/runtime/core/engine-resolver.d.ts +1 -1
  28. package/dist/runtime/core/engine-transition.js +3 -1
  29. package/dist/services/AccessibilityCatalogResolver.d.ts +49 -10
  30. package/dist/services/AccessibilityCatalogResolver.js +180 -11
  31. package/dist/services/TTSService.d.ts +11 -0
  32. package/dist/services/TTSService.js +220 -32
  33. package/dist/services/ToolRegistry.d.ts +259 -8
  34. package/dist/services/ToolRegistry.js +181 -11
  35. package/dist/services/ToolkitCoordinator.d.ts +20 -2
  36. package/dist/services/ToolkitCoordinator.js +47 -8
  37. package/dist/services/catalog-owner.d.ts +71 -0
  38. package/dist/services/catalog-owner.js +64 -0
  39. package/dist/services/createDefaultToolRegistry.d.ts +25 -58
  40. package/dist/services/createDefaultToolRegistry.js +24 -104
  41. package/dist/services/defaultPersonalNeedsProfile.d.ts +16 -14
  42. package/dist/services/defaultPersonalNeedsProfile.js +17 -38
  43. package/dist/services/framework-error.d.ts +1 -1
  44. package/dist/services/interfaces.d.ts +15 -3
  45. package/dist/services/pnp-standard-features.d.ts +1 -1
  46. package/dist/services/tool-config-defaults.d.ts +7 -23
  47. package/dist/services/tool-config-defaults.js +7 -46
  48. package/dist/services/tool-config-validation.d.ts +1 -1
  49. package/dist/services/tool-config-validation.js +44 -4
  50. package/dist/services/tts/browser-provider.js +191 -24
  51. package/dist/services/tts-runtime-config.js +7 -2
  52. package/dist/tools/internal.d.ts +35 -0
  53. package/dist/tools/internal.js +33 -0
  54. package/dist/tools/tool-tag-map.d.ts +15 -3
  55. package/dist/tools/tool-tag-map.js +21 -18
  56. package/package.json +14 -10
  57. package/dist/components/chunks/ItemToolBar-3cppre9r.js +0 -51
  58. package/dist/components/chunks/ItemToolBar-7rq2gj8b.js +0 -22
  59. package/dist/runtime/catalog-registration.d.ts +0 -67
  60. package/dist/runtime/catalog-registration.js +0 -86
  61. package/dist/services/sign-language-cards.d.ts +0 -82
  62. package/dist/services/sign-language-cards.js +0 -133
  63. package/dist/tools/registrations/accessibility-tools.d.ts +0 -34
  64. package/dist/tools/registrations/accessibility-tools.js +0 -217
  65. package/dist/tools/registrations/calculator.d.ts +0 -20
  66. package/dist/tools/registrations/calculator.js +0 -228
  67. package/dist/tools/registrations/interaction-tools.d.ts +0 -27
  68. package/dist/tools/registrations/interaction-tools.js +0 -143
  69. package/dist/tools/registrations/measurement-tools.d.ts +0 -24
  70. package/dist/tools/registrations/measurement-tools.js +0 -130
  71. package/dist/tools/registrations/subject-specific-tools.d.ts +0 -27
  72. package/dist/tools/registrations/subject-specific-tools.js +0 -158
  73. package/dist/tools/registrations/tts.d.ts +0 -21
  74. package/dist/tools/registrations/tts.js +0 -184
@@ -29,7 +29,8 @@ import type { SREMathSpeechOptions } from "./tts/math-speech.js";
29
29
  import { ToolProviderRegistry } from "./tool-providers/index.js";
30
30
  import type { ToolProviderApi } from "./tool-providers/ToolProviderApi.js";
31
31
  import type { TTSToolProviderConfig } from "./tool-providers/index.js";
32
- import type { ResolvedToolContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap, ToolRegistry } from "./ToolRegistry.js";
32
+ import { ToolRegistry } from "./ToolRegistry.js";
33
+ import type { ResolvedToolContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap } from "./ToolRegistry.js";
33
34
  import { type FeaturePolicyDecision, type PnpEnforcementMode, type PolicySource, type ResolvedEngineInputs, type ToolPolicyChangeListener, type ToolPolicyDecision, type ToolPolicyDecisionRequest } from "../policy/engine.js";
34
35
  import type { SectionControllerContext, SectionControllerEvent, SectionControllerEventType, SectionControllerFactoryDefaults, SectionControllerHandle, SectionControllerKey, SectionSessionPersistenceStrategy, SectionPersistenceFactoryDefaults } from "./section-controller-types.js";
35
36
  export type { SectionControllerContext, SectionControllerEvent, SectionControllerEventType, SectionControllerFactoryDefaults, SectionControllerHandle, SectionControllerKey, SectionControllerLoadedRenderable, SectionSessionPersistenceConfig, SectionSessionPersistenceStrategy, SectionControllerRuntimeState, SectionControllerSessionState, SectionPersistenceFactoryDefaults, } from "./section-controller-types.js";
@@ -295,7 +296,7 @@ export interface ToolkitServiceBundle {
295
296
  * assessmentId: 'demo-three-questions',
296
297
  * tools: {
297
298
  * providers: {
298
- * textToSpeech: { enabled: true, defaultVoice: 'en-US' },
299
+ * textToSpeech: { enabled: true, backend: 'browser' },
299
300
  * answerEliminator: { enabled: true, strategy: 'strikethrough' }
300
301
  * },
301
302
  * placement: {
@@ -413,6 +414,17 @@ export declare class ToolkitCoordinator {
413
414
  * frozen snapshot.
414
415
  */
415
416
  private boundCurrentItemRef;
417
+ /**
418
+ * Whether {@link decideFeaturePolicy} has already reported serving a decision
419
+ * with no assessment bound.
420
+ *
421
+ * One report per coordinator, not per decision: a feature policy is consulted
422
+ * once per capability per card, so a per-decision warning would bury itself.
423
+ * Never reset — {@link updateAssessment} arriving later fixes the deployment,
424
+ * and re-arming would report the same gap again on the next unbound coordinator
425
+ * lifetime for no new information.
426
+ */
427
+ private reportedUnboundFeaturePolicy;
416
428
  private static resolveConfig;
417
429
  constructor(config: ToolkitCoordinatorConfig);
418
430
  /**
@@ -667,6 +679,12 @@ export declare class ToolkitCoordinator {
667
679
  * Thin shim over the owned tool-policy engine; see
668
680
  * {@link ToolPolicyEngine.decideFeature} for the contract, including why
669
681
  * `pnpEnforcement` is not consulted.
682
+ *
683
+ * Reports once per coordinator when it is asked about a feature with no
684
+ * assessment bound. A host in that state gets a correct denial for every
685
+ * capability it asks about, which is indistinguishable from a student who was
686
+ * properly declined — so without this, forgetting {@link updateAssessment}
687
+ * presents as an accommodation that silently never appears.
670
688
  */
671
689
  decideFeaturePolicy(featureId: string): FeaturePolicyDecision;
672
690
  /**
@@ -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);
@@ -70,7 +70,7 @@ const SECTION_SCOPED_EVENT_TYPES = [
70
70
  * assessmentId: 'demo-three-questions',
71
71
  * tools: {
72
72
  * providers: {
73
- * textToSpeech: { enabled: true, defaultVoice: 'en-US' },
73
+ * textToSpeech: { enabled: true, backend: 'browser' },
74
74
  * answerEliminator: { enabled: true, strategy: 'strikethrough' }
75
75
  * },
76
76
  * placement: {
@@ -188,9 +188,26 @@ export class ToolkitCoordinator {
188
188
  * frozen snapshot.
189
189
  */
190
190
  boundCurrentItemRef = null;
191
+ /**
192
+ * Whether {@link decideFeaturePolicy} has already reported serving a decision
193
+ * with no assessment bound.
194
+ *
195
+ * One report per coordinator, not per decision: a feature policy is consulted
196
+ * once per capability per card, so a per-decision warning would bury itself.
197
+ * Never reset — {@link updateAssessment} arriving later fixes the deployment,
198
+ * and re-arming would report the same gap again on the next unbound coordinator
199
+ * lifetime for no new information.
200
+ */
201
+ reportedUnboundFeaturePolicy = false;
191
202
  static resolveConfig(config) {
192
203
  const strictness = normalizeToolConfigStrictness(config.toolConfigStrictness);
193
- const toolRegistry = config.toolRegistry ?? createPackagedToolRegistry();
204
+ // An empty registry when the host supplies none. This package no longer
205
+ // holds the packaged capability set, so there is nothing to fall back to —
206
+ // a host that wants stock tools passes a registry from
207
+ // `@pie-players/pie-default-tool-loaders`. Tool-id validation is skipped
208
+ // against an empty registry (with a diagnostic saying so) rather than
209
+ // rejecting every configured id.
210
+ const toolRegistry = config.toolRegistry ?? new ToolRegistry();
194
211
  const normalized = config.deferToolConfigValidation === true
195
212
  ? normalizeToolsConfig(config.tools)
196
213
  : normalizeAndValidateToolsConfig(config.tools, {
@@ -232,8 +249,7 @@ export class ToolkitCoordinator {
232
249
  const resolvedConfig = ToolkitCoordinator.resolveConfig(config);
233
250
  this.assessmentId = resolvedConfig.assessmentId;
234
251
  this.config = resolvedConfig;
235
- this.toolRegistry =
236
- resolvedConfig.toolRegistry ?? createPackagedToolRegistry();
252
+ this.toolRegistry = resolvedConfig.toolRegistry ?? new ToolRegistry();
237
253
  this.installToolContextResolvers(resolvedConfig.toolContextResolvers);
238
254
  this.hooks = resolvedConfig.hooks ?? {};
239
255
  this.lazyInit = config.lazyInit === true;
@@ -1268,13 +1284,16 @@ export class ToolkitCoordinator {
1268
1284
  if (canUseEventTarget) {
1269
1285
  synth.removeEventListener("voiceschanged", onVoicesChanged);
1270
1286
  }
1271
- else if (assignedHandler && synth.onvoiceschanged === onVoicesChanged) {
1287
+ else if (assignedHandler &&
1288
+ synth.onvoiceschanged === onVoicesChanged) {
1272
1289
  synth.onvoiceschanged = previousHandler;
1273
1290
  }
1274
1291
  resolve();
1275
1292
  };
1276
1293
  const onVoicesChanged = (event) => {
1277
- if (!canUseEventTarget && typeof previousHandler === "function" && event) {
1294
+ if (!canUseEventTarget &&
1295
+ typeof previousHandler === "function" &&
1296
+ event) {
1278
1297
  previousHandler.call(synth, event);
1279
1298
  }
1280
1299
  finish();
@@ -1371,6 +1390,15 @@ export class ToolkitCoordinator {
1371
1390
  if (toolId === "tts") {
1372
1391
  throw new Error(`Tool id "tts" is no longer supported. Use "textToSpeech".`);
1373
1392
  }
1393
+ // An empty registry means the host supplied none, not that every id is
1394
+ // wrong. There is nothing to check an id against, and throwing turns a
1395
+ // host's every tool-config call into an exception — including the calls
1396
+ // this coordinator's own default-provider block provokes, which is how a
1397
+ // host that passes no registry ended up unable to read its own config.
1398
+ // `normalizeAndValidateToolsConfig` already reports the missing registry
1399
+ // once, as `tools.registryUnavailable`; a second report per call is noise.
1400
+ if (this.toolRegistry.getAllToolIds().length === 0)
1401
+ return;
1374
1402
  if (!this.toolRegistry.get(toolId)) {
1375
1403
  throw new Error(`Unknown tool id "${toolId}".`);
1376
1404
  }
@@ -1525,9 +1553,20 @@ export class ToolkitCoordinator {
1525
1553
  * Thin shim over the owned tool-policy engine; see
1526
1554
  * {@link ToolPolicyEngine.decideFeature} for the contract, including why
1527
1555
  * `pnpEnforcement` is not consulted.
1556
+ *
1557
+ * Reports once per coordinator when it is asked about a feature with no
1558
+ * assessment bound. A host in that state gets a correct denial for every
1559
+ * capability it asks about, which is indistinguishable from a student who was
1560
+ * properly declined — so without this, forgetting {@link updateAssessment}
1561
+ * presents as an accommodation that silently never appears.
1528
1562
  */
1529
1563
  decideFeaturePolicy(featureId) {
1530
- return this.policyEngine.decideFeature(featureId);
1564
+ const decision = this.policyEngine.decideFeature(featureId);
1565
+ if (!decision.assessmentBound && !this.reportedUnboundFeaturePolicy) {
1566
+ this.reportedUnboundFeaturePolicy = true;
1567
+ console.warn(`[ToolkitCoordinator] Feature policy was asked about "${featureId}" with no assessment bound, so every capability will be declined for want of a profile to read. Call updateAssessment(...) with the assessment (its personalNeedsProfile, settings.districtPolicy and settings.testAdministration are what policy reads) before relying on any accommodation. Reported once per coordinator.`);
1568
+ }
1569
+ return decision;
1531
1570
  }
1532
1571
  /**
1533
1572
  * Subscribe to policy-engine change events. Fires whenever the
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Identity and traversal rules for one mounted accessibility-catalog owner.
3
+ *
4
+ * The resolver is the public lifecycle boundary. This supporting module keeps
5
+ * its owner identity and direct-lookup helper separate from the runtime event
6
+ * adapter, while keeping the entity walk private to the resolver package.
7
+ */
8
+ import type { AccessibilityCatalog } from "@pie-players/pie-players-shared/types";
9
+ export type CatalogOwnerKind = "global" | "passage" | "itemModel";
10
+ interface CatalogOwnerScopeContext {
11
+ assessmentId?: string;
12
+ sectionId?: string;
13
+ }
14
+ /** A valid resolver scope for a global, passage, or item/model owner. */
15
+ export type CatalogOwnerContext = (CatalogOwnerScopeContext & {
16
+ ownerKind: "global";
17
+ canonicalItemId?: never;
18
+ itemId?: never;
19
+ passageId?: never;
20
+ modelId?: never;
21
+ }) | (CatalogOwnerScopeContext & {
22
+ ownerKind: "passage";
23
+ passageId: string;
24
+ canonicalItemId?: never;
25
+ itemId?: never;
26
+ modelId?: never;
27
+ }) | (CatalogOwnerScopeContext & {
28
+ ownerKind: "itemModel";
29
+ itemId: string;
30
+ canonicalItemId?: string;
31
+ modelId?: string;
32
+ passageId?: never;
33
+ });
34
+ export interface CatalogOwnerRegistrationEntry {
35
+ context: CatalogOwnerContext;
36
+ catalogs: AccessibilityCatalog[];
37
+ }
38
+ /** The entity shape catalogs hang off: an item, or a passage. */
39
+ export interface CatalogSourceEntity {
40
+ accessibilityCatalogs?: AccessibilityCatalog[];
41
+ config?: {
42
+ extractedCatalogs?: AccessibilityCatalog[];
43
+ models?: Array<{
44
+ id?: string;
45
+ accessibilityCatalogs?: AccessibilityCatalog[];
46
+ }>;
47
+ };
48
+ }
49
+ /** Who is rendering the entity — everything owner scoping is derived from. */
50
+ export interface CatalogOwnerIdentity {
51
+ kind: "item" | "passage";
52
+ /** The rendered instance id. */
53
+ itemId: string;
54
+ canonicalItemId?: string;
55
+ assessmentId?: string;
56
+ sectionId?: string;
57
+ }
58
+ /**
59
+ * Build the lookup context for a direct resolver client such as inline TTS.
60
+ *
61
+ * Owner registration uses the same function, so direct readers cannot drift
62
+ * from the context the resolver files the entity under.
63
+ */
64
+ export declare function catalogOwnerContextFor(owner: CatalogOwnerIdentity): CatalogOwnerContext;
65
+ /**
66
+ * Collect every catalog group carried by one owner in registration-precedence
67
+ * order. This is deliberately not exported from the package root: callers
68
+ * register the owner once through `AccessibilityCatalogResolver.registerOwner`.
69
+ */
70
+ export declare function collectOwnerCatalogRegistrations(entity: CatalogSourceEntity | null | undefined, owner: CatalogOwnerIdentity): CatalogOwnerRegistrationEntry[];
71
+ export {};
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Identity and traversal rules for one mounted accessibility-catalog owner.
3
+ *
4
+ * The resolver is the public lifecycle boundary. This supporting module keeps
5
+ * its owner identity and direct-lookup helper separate from the runtime event
6
+ * adapter, while keeping the entity walk private to the resolver package.
7
+ */
8
+ const hasCatalogs = (catalogs) => Array.isArray(catalogs) && catalogs.length > 0;
9
+ /**
10
+ * Build the lookup context for a direct resolver client such as inline TTS.
11
+ *
12
+ * Owner registration uses the same function, so direct readers cannot drift
13
+ * from the context the resolver files the entity under.
14
+ */
15
+ export function catalogOwnerContextFor(owner) {
16
+ if (owner.kind === "passage") {
17
+ return {
18
+ ownerKind: "passage",
19
+ assessmentId: owner.assessmentId,
20
+ sectionId: owner.sectionId,
21
+ passageId: owner.canonicalItemId || owner.itemId,
22
+ };
23
+ }
24
+ return {
25
+ ownerKind: "itemModel",
26
+ assessmentId: owner.assessmentId,
27
+ sectionId: owner.sectionId,
28
+ itemId: owner.itemId,
29
+ canonicalItemId: owner.canonicalItemId || owner.itemId,
30
+ };
31
+ }
32
+ /**
33
+ * Collect every catalog group carried by one owner in registration-precedence
34
+ * order. This is deliberately not exported from the package root: callers
35
+ * register the owner once through `AccessibilityCatalogResolver.registerOwner`.
36
+ */
37
+ export function collectOwnerCatalogRegistrations(entity, owner) {
38
+ if (!entity)
39
+ return [];
40
+ const context = catalogOwnerContextFor(owner);
41
+ const registrations = [];
42
+ if (hasCatalogs(entity.accessibilityCatalogs)) {
43
+ registrations.push({ context, catalogs: entity.accessibilityCatalogs });
44
+ }
45
+ if (hasCatalogs(entity.config?.extractedCatalogs)) {
46
+ registrations.push({
47
+ context,
48
+ catalogs: entity.config.extractedCatalogs,
49
+ });
50
+ }
51
+ if (owner.kind === "passage")
52
+ return registrations;
53
+ if (context.ownerKind !== "itemModel")
54
+ return registrations;
55
+ for (const model of entity.config?.models ?? []) {
56
+ if (!hasCatalogs(model.accessibilityCatalogs))
57
+ continue;
58
+ registrations.push({
59
+ context: { ...context, modelId: model.id },
60
+ catalogs: model.accessibilityCatalogs,
61
+ });
62
+ }
63
+ return registrations;
64
+ }
@@ -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;