@pie-players/pie-assessment-toolkit 0.3.55 → 0.3.56

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.
@@ -7046,6 +7046,9 @@ var resolveTTSHostToolbarLayout = (config) => {
7046
7046
  controlsRow: {
7047
7047
  reserveSpace: true,
7048
7048
  expandWhenToolActive: false
7049
+ },
7050
+ headerOverlay: {
7051
+ expandWhenToolActive: false
7049
7052
  }
7050
7053
  };
7051
7054
  case "expanding-row":
@@ -7054,9 +7057,22 @@ var resolveTTSHostToolbarLayout = (config) => {
7054
7057
  controlsRow: {
7055
7058
  reserveSpace: false,
7056
7059
  expandWhenToolActive: true
7060
+ },
7061
+ headerOverlay: {
7062
+ expandWhenToolActive: false
7057
7063
  }
7058
7064
  };
7059
7065
  case "floating-overlay":
7066
+ return {
7067
+ mount: "before-buttons",
7068
+ controlsRow: {
7069
+ reserveSpace: false,
7070
+ expandWhenToolActive: false
7071
+ },
7072
+ headerOverlay: {
7073
+ expandWhenToolActive: false
7074
+ }
7075
+ };
7060
7076
  case "left-aligned":
7061
7077
  default:
7062
7078
  return {
@@ -7064,6 +7080,9 @@ var resolveTTSHostToolbarLayout = (config) => {
7064
7080
  controlsRow: {
7065
7081
  reserveSpace: false,
7066
7082
  expandWhenToolActive: false
7083
+ },
7084
+ headerOverlay: {
7085
+ expandWhenToolActive: true
7067
7086
  }
7068
7087
  };
7069
7088
  }
@@ -7183,6 +7202,9 @@ var ttsToolRegistration = {
7183
7202
  controlsRow: {
7184
7203
  reserveSpace: hostLayout.controlsRow.reserveSpace,
7185
7204
  showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive
7205
+ },
7206
+ headerOverlay: {
7207
+ showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive
7186
7208
  }
7187
7209
  }
7188
7210
  }
@@ -9179,10 +9201,37 @@ function ItemToolBar($$anchor, $$props) {
9179
9201
  toolId: renderedTool.toolId,
9180
9202
  hint: entry.layoutHints?.controlsRow
9181
9203
  })).filter((entry) => Boolean(entry.hint))));
9204
+ const headerOverlayHints = user_derived(() => get2(renderedTools).flatMap((renderedTool) => (renderedTool.elements || []).map((entry) => ({
9205
+ toolId: renderedTool.toolId,
9206
+ hint: entry.layoutHints?.headerOverlay
9207
+ })).filter((entry) => Boolean(entry.hint))));
9182
9208
  const controlsRowShouldReserveSpace = user_derived(() => get2(controlsRowHints).some((entry) => entry.hint?.reserveSpace === true));
9183
9209
  const controlsRowShouldExpandForActiveTool = user_derived(() => get2(controlsRowHints).some((entry) => entry.hint?.showWhenToolActive === true && (get2(renderedToolActiveById)[entry.toolId] ?? false)));
9184
9210
  const controlsRowAlignStart = user_derived(() => position() === "left" || position() === "right");
9211
+ const headerOverlayShouldExpandForActiveTool = user_derived(() => get2(headerOverlayHints).some((entry) => entry.hint?.showWhenToolActive === true && (get2(renderedToolActiveById)[entry.toolId] ?? false)));
9185
9212
  const shouldRenderControlsRow = user_derived(() => get2(mountedElementsControlsRow).length > 0 || get2(controlsRowShouldReserveSpace) || get2(controlsRowShouldExpandForActiveTool));
9213
+ function resolveToolbarHostElement() {
9214
+ if (!get2(toolbarRootElement))
9215
+ return null;
9216
+ const root = get2(toolbarRootElement).getRootNode();
9217
+ if (root instanceof ShadowRoot) {
9218
+ return root.host;
9219
+ }
9220
+ return null;
9221
+ }
9222
+ user_effect(() => {
9223
+ const host = resolveToolbarHostElement();
9224
+ if (!host)
9225
+ return;
9226
+ const hasHeaderOverlay = get2(headerOverlayHints).length > 0;
9227
+ const active = get2(headerOverlayShouldExpandForActiveTool);
9228
+ host.setAttribute("data-pie-header-overlay", hasHeaderOverlay ? "true" : "false");
9229
+ host.setAttribute("data-pie-header-overlay-active", active ? "true" : "false");
9230
+ return () => {
9231
+ host.removeAttribute("data-pie-header-overlay");
9232
+ host.removeAttribute("data-pie-header-overlay-active");
9233
+ };
9234
+ });
9186
9235
  user_effect(() => {
9187
9236
  if (!isBrowser)
9188
9237
  return;
@@ -10637,7 +10686,8 @@ function ItemToolBar($$anchor, $$props) {
10637
10686
  "item-toolbar--top": position() === "top",
10638
10687
  "item-toolbar--right": position() === "right",
10639
10688
  "item-toolbar--bottom": position() === "bottom",
10640
- "item-toolbar--left": position() === "left"
10689
+ "item-toolbar--left": position() === "left",
10690
+ "item-toolbar--header-overlay-active": get2(headerOverlayShouldExpandForActiveTool)
10641
10691
  });
10642
10692
  set_attribute2(div, "data-content-kind", get2(effectiveContentKind));
10643
10693
  set_attribute2(div, "data-level", get2(effectiveLevel));
@@ -19146,6 +19146,9 @@ var resolveTTSHostToolbarLayout = (config) => {
19146
19146
  controlsRow: {
19147
19147
  reserveSpace: true,
19148
19148
  expandWhenToolActive: false
19149
+ },
19150
+ headerOverlay: {
19151
+ expandWhenToolActive: false
19149
19152
  }
19150
19153
  };
19151
19154
  case "expanding-row":
@@ -19154,9 +19157,22 @@ var resolveTTSHostToolbarLayout = (config) => {
19154
19157
  controlsRow: {
19155
19158
  reserveSpace: false,
19156
19159
  expandWhenToolActive: true
19160
+ },
19161
+ headerOverlay: {
19162
+ expandWhenToolActive: false
19157
19163
  }
19158
19164
  };
19159
19165
  case "floating-overlay":
19166
+ return {
19167
+ mount: "before-buttons",
19168
+ controlsRow: {
19169
+ reserveSpace: false,
19170
+ expandWhenToolActive: false
19171
+ },
19172
+ headerOverlay: {
19173
+ expandWhenToolActive: false
19174
+ }
19175
+ };
19160
19176
  case "left-aligned":
19161
19177
  default:
19162
19178
  return {
@@ -19164,6 +19180,9 @@ var resolveTTSHostToolbarLayout = (config) => {
19164
19180
  controlsRow: {
19165
19181
  reserveSpace: false,
19166
19182
  expandWhenToolActive: false
19183
+ },
19184
+ headerOverlay: {
19185
+ expandWhenToolActive: true
19167
19186
  }
19168
19187
  };
19169
19188
  }
@@ -19283,6 +19302,9 @@ var ttsToolRegistration = {
19283
19302
  controlsRow: {
19284
19303
  reserveSpace: hostLayout.controlsRow.reserveSpace,
19285
19304
  showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive
19305
+ },
19306
+ headerOverlay: {
19307
+ showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive
19286
19308
  }
19287
19309
  }
19288
19310
  }
@@ -11229,6 +11229,9 @@ var resolveTTSHostToolbarLayout = (config) => {
11229
11229
  controlsRow: {
11230
11230
  reserveSpace: true,
11231
11231
  expandWhenToolActive: false
11232
+ },
11233
+ headerOverlay: {
11234
+ expandWhenToolActive: false
11232
11235
  }
11233
11236
  };
11234
11237
  case "expanding-row":
@@ -11237,9 +11240,22 @@ var resolveTTSHostToolbarLayout = (config) => {
11237
11240
  controlsRow: {
11238
11241
  reserveSpace: false,
11239
11242
  expandWhenToolActive: true
11243
+ },
11244
+ headerOverlay: {
11245
+ expandWhenToolActive: false
11240
11246
  }
11241
11247
  };
11242
11248
  case "floating-overlay":
11249
+ return {
11250
+ mount: "before-buttons",
11251
+ controlsRow: {
11252
+ reserveSpace: false,
11253
+ expandWhenToolActive: false
11254
+ },
11255
+ headerOverlay: {
11256
+ expandWhenToolActive: false
11257
+ }
11258
+ };
11243
11259
  case "left-aligned":
11244
11260
  default:
11245
11261
  return {
@@ -11247,6 +11263,9 @@ var resolveTTSHostToolbarLayout = (config) => {
11247
11263
  controlsRow: {
11248
11264
  reserveSpace: false,
11249
11265
  expandWhenToolActive: false
11266
+ },
11267
+ headerOverlay: {
11268
+ expandWhenToolActive: true
11250
11269
  }
11251
11270
  };
11252
11271
  }
@@ -11364,6 +11383,9 @@ var ttsToolRegistration = {
11364
11383
  controlsRow: {
11365
11384
  reserveSpace: hostLayout.controlsRow.reserveSpace,
11366
11385
  showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive
11386
+ },
11387
+ headerOverlay: {
11388
+ showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive
11367
11389
  }
11368
11390
  }
11369
11391
  }
@@ -13344,10 +13366,37 @@ function ItemToolBar($$anchor, $$props) {
13344
13366
  toolId: renderedTool.toolId,
13345
13367
  hint: entry.layoutHints?.controlsRow
13346
13368
  })).filter((entry) => Boolean(entry.hint))));
13369
+ const headerOverlayHints = user_derived2(() => get22(renderedTools).flatMap((renderedTool) => (renderedTool.elements || []).map((entry) => ({
13370
+ toolId: renderedTool.toolId,
13371
+ hint: entry.layoutHints?.headerOverlay
13372
+ })).filter((entry) => Boolean(entry.hint))));
13347
13373
  const controlsRowShouldReserveSpace = user_derived2(() => get22(controlsRowHints).some((entry) => entry.hint?.reserveSpace === true));
13348
13374
  const controlsRowShouldExpandForActiveTool = user_derived2(() => get22(controlsRowHints).some((entry) => entry.hint?.showWhenToolActive === true && (get22(renderedToolActiveById)[entry.toolId] ?? false)));
13349
13375
  const controlsRowAlignStart = user_derived2(() => position() === "left" || position() === "right");
13376
+ const headerOverlayShouldExpandForActiveTool = user_derived2(() => get22(headerOverlayHints).some((entry) => entry.hint?.showWhenToolActive === true && (get22(renderedToolActiveById)[entry.toolId] ?? false)));
13350
13377
  const shouldRenderControlsRow = user_derived2(() => get22(mountedElementsControlsRow).length > 0 || get22(controlsRowShouldReserveSpace) || get22(controlsRowShouldExpandForActiveTool));
13378
+ function resolveToolbarHostElement() {
13379
+ if (!get22(toolbarRootElement))
13380
+ return null;
13381
+ const root = get22(toolbarRootElement).getRootNode();
13382
+ if (root instanceof ShadowRoot) {
13383
+ return root.host;
13384
+ }
13385
+ return null;
13386
+ }
13387
+ user_effect2(() => {
13388
+ const host = resolveToolbarHostElement();
13389
+ if (!host)
13390
+ return;
13391
+ const hasHeaderOverlay = get22(headerOverlayHints).length > 0;
13392
+ const active = get22(headerOverlayShouldExpandForActiveTool);
13393
+ host.setAttribute("data-pie-header-overlay", hasHeaderOverlay ? "true" : "false");
13394
+ host.setAttribute("data-pie-header-overlay-active", active ? "true" : "false");
13395
+ return () => {
13396
+ host.removeAttribute("data-pie-header-overlay");
13397
+ host.removeAttribute("data-pie-header-overlay-active");
13398
+ };
13399
+ });
13351
13400
  user_effect2(() => {
13352
13401
  if (!isBrowser)
13353
13402
  return;
@@ -14802,7 +14851,8 @@ function ItemToolBar($$anchor, $$props) {
14802
14851
  "item-toolbar--top": position() === "top",
14803
14852
  "item-toolbar--right": position() === "right",
14804
14853
  "item-toolbar--bottom": position() === "bottom",
14805
- "item-toolbar--left": position() === "left"
14854
+ "item-toolbar--left": position() === "left",
14855
+ "item-toolbar--header-overlay-active": get22(headerOverlayShouldExpandForActiveTool)
14806
14856
  });
14807
14857
  set_attribute22(div, "data-content-kind", get22(effectiveContentKind));
14808
14858
  set_attribute22(div, "data-level", get22(effectiveLevel));
@@ -77,6 +77,9 @@ export interface ToolRenderElement {
77
77
  reserveSpace?: boolean;
78
78
  showWhenToolActive?: boolean;
79
79
  };
80
+ headerOverlay?: {
81
+ showWhenToolActive?: boolean;
82
+ };
80
83
  };
81
84
  shell?: ToolWindowShellConfig;
82
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ToolRegistry.js","sourceRoot":"","sources":["../../src/services/ToolRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool Registry\n *\n * Central registry for all assessment tools. Manages tool metadata, visibility logic,\n * and button/instance creation. Supports dynamic registration and override by integrators.\n */\n\nimport type { ToolContext, ToolLevel } from \"./tool-context.js\";\nimport type { ToolComponentOverrides } from \"../tools/tool-tag-map.js\";\nimport type {\n\tElementToolStateStoreApi,\n\tToolCoordinatorApi,\n\tToolkitCoordinatorApi,\n\tTtsServiceApi,\n} from \"./interfaces.js\";\nimport type { ToolProviderApi } from \"./tool-providers/ToolProviderApi.js\";\nimport type { ToolProviderConfig as ToolRuntimeConfig } from \"./tools-config-normalizer.js\";\nimport type { ToolConfigDiagnostic } from \"./tool-config-validation.js\";\nimport { normalizeToolAlias } from \"./tools-config-normalizer.js\";\n\nexport type ToolModuleLoader = () => Promise<unknown>;\n\nexport interface ToolToolbarButtonDefinition {\n\ttoolId: string;\n\tlabel: string;\n\ticon: string;\n\tariaLabel: string;\n\ttooltip?: string;\n\tonClick: () => void;\n\tclassName?: string;\n\tdisabled?: boolean;\n\tactive?: boolean;\n}\n\nexport interface ToolbarContext {\n\tscope: {\n\t\tlevel: ToolLevel;\n\t\tscopeId: string;\n\t\tassessmentId?: string;\n\t\tsectionId?: string;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t};\n\titemId: string;\n\tcatalogId: string;\n\tlanguage: string;\n\tui?: {\n\t\tsize?: string;\n\t};\n\tgetScopeElement?: () => HTMLElement | null;\n\tgetGlobalElementId?: () => string | null;\n\ttoolCoordinator: ToolCoordinatorApi | null;\n\ttoolkitCoordinator: ToolkitCoordinatorApi | null;\n\tttsService: TtsServiceApi | null;\n\telementToolStateStore: ElementToolStateStoreApi | null;\n\ttoggleTool: (toolId: string) => void;\n\tisToolVisible: (toolId: string) => boolean;\n\tsubscribeVisibility: ((listener: () => void) => () => void) | null;\n\tcomponentOverrides?: ToolComponentOverrides;\n\tgetResolvedToolContext?: (toolId: string) => ResolvedToolContext | null;\n\tgetToolRenderParams?: (toolId: string) => Record<string, unknown> | null;\n}\n\nexport interface ToolContextResolverContext {\n\ttoolId: string;\n\tcontext: ToolContext;\n\ttoolbarContext: ToolbarContext;\n}\n\nexport interface ToolContextResolverResult {\n\tvisible?: boolean;\n\tparams?: Record<string, unknown>;\n\treason?: string;\n}\n\nexport type ToolContextResolver = (\n\tcontext: ToolContextResolverContext,\n) => ToolContextResolverResult | null | undefined;\n\nexport type ToolContextResolverMap = Record<\n\tstring,\n\tToolContextResolver | null | undefined\n>;\n\nexport interface ResolvedToolContext {\n\ttoolId: string;\n\tvisible: boolean;\n\tparams: Record<string, unknown>;\n\treason?: string;\n}\n\nexport interface ToolRenderElement {\n\telement: HTMLElement | null;\n\tmount: \"before-buttons\" | \"after-buttons\" | \"controls-row\";\n\tlayoutHints?: {\n\t\tcontrolsRow?: {\n\t\t\treserveSpace?: boolean;\n\t\t\tshowWhenToolActive?: boolean;\n\t\t};\n\t};\n\tshell?: ToolWindowShellConfig;\n}\n\nexport interface ToolWindowShellAction {\n\tid: string;\n\tlabel: string;\n\tariaLabel?: string;\n\ticonSvg?: string;\n\tonClick: () => void;\n}\n\n/**\n * Alignment corner for the initial shell position.\n * The shell is offset by `initialMargin` (default 16 px) from the chosen corner.\n */\nexport type ToolWindowShellAlign =\n\t| \"center\"\n\t| \"top-left\"\n\t| \"top-right\"\n\t| \"bottom-left\"\n\t| \"bottom-right\";\n\nexport interface ToolWindowShellContentConfig {\n\t/** Vertical overflow behavior for the hosted content pane. Defaults to \"hidden\". */\n\toverflowY?: \"hidden\" | \"auto\";\n\t/**\n\t * Preserve the content area's configured minimum height when the shell shrinks\n\t * below `minHeight`, letting the content pane scroll instead of compressing\n\t * the hosted element.\n\t */\n\tpreserveMinHeight?: boolean;\n}\n\nexport interface ToolWindowShellConfig {\n\ttitle?: string;\n\tdraggable?: boolean;\n\tresizable?: boolean;\n\tcloseable?: boolean;\n\tinitialWidth?: number;\n\tinitialHeight?: number;\n\tminWidth?: number;\n\tminHeight?: number;\n\tmaxWidth?: number;\n\tmaxHeight?: number;\n\t/** Initial placement of the shell. Defaults to `'center'`. */\n\tinitialAlign?: ToolWindowShellAlign;\n\t/** Distance (px) from the viewport edge when using a corner align. Defaults to 16. */\n\tinitialMargin?: number;\n\tcontent?: ToolWindowShellContentConfig;\n\tactions?: ToolWindowShellAction[];\n}\n\nexport interface HostedToolContext {\n\ttoolId: string;\n\ttoolbarContext: ToolbarContext;\n\tshellConfig: ToolWindowShellConfig;\n}\n\nexport interface HostedToolSize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface ToolProviderDescriptor {\n\tgetProviderId?: (config: ToolRuntimeConfig | undefined) => string;\n\tcreateProvider: (config: ToolRuntimeConfig | undefined) => ToolProviderApi;\n\tgetInitConfig?: (\n\t\tconfig: ToolRuntimeConfig | undefined,\n\t) => Record<string, unknown>;\n\tsanitizeConfig?: (config: ToolRuntimeConfig) => ToolRuntimeConfig;\n\tvalidateConfig?: (config: ToolRuntimeConfig) => ToolConfigDiagnostic[];\n\tgetAuthFetcher?: (\n\t\tconfig: ToolRuntimeConfig | undefined,\n\t) => (() => Promise<Record<string, unknown>>) | undefined;\n\tlazy?: boolean;\n}\n\nexport interface ToolToolbarRenderResult {\n\ttoolId: string;\n\telements?: ToolRenderElement[];\n\tbutton?: ToolToolbarButtonDefinition | null;\n\tsync?: () => void;\n\tsubscribeActive?: (callback: (active: boolean) => void) => () => void;\n}\n\nexport type ToolActivation = \"toolbar-toggle\" | \"selection-gateway\";\nexport type ToolSingletonScope = \"section\";\n\n/**\n * Tool registration interface\n */\nexport interface ToolRegistration {\n\t/** Unique tool identifier (e.g., 'calculator', 'textToSpeech') */\n\ttoolId: string;\n\n\t/** Human-readable name */\n\tname: string;\n\n\t/** Description of what the tool does */\n\tdescription: string;\n\n\t/** Icon identifier or SVG string */\n\ticon: string | ((context: ToolContext) => string);\n\n\t/** Which levels this tool supports */\n\tsupportedLevels: ToolLevel[];\n\n\t/**\n\t * Activation model for this tool.\n\t * - toolbar-toggle: rendered as a toolbar button (default)\n\t * - selection-gateway: rendered as a singleton selection-driven gateway\n\t */\n\tactivation?: ToolActivation;\n\n\t/**\n\t * Optional singleton scope for activation models that mount exactly one instance.\n\t */\n\tsingletonScope?: ToolSingletonScope;\n\n\t/**\n\t * PNP support IDs that enable this tool (optional)\n\t * Used by the tool policy engine to determine if a PNP support enables this tool.\n\t * Example: ['calculator', 'basic-calculator', 'scientific-calculator']\n\t */\n\tpnpSupportIds?: string[];\n\t/**\n\t * Optional provider registration metadata.\n\t * When present, ToolkitCoordinator can register provider(s) generically\n\t * without hardcoded tool-specific branches.\n\t */\n\tprovider?: ToolProviderDescriptor;\n\t/**\n\t * Optional shell-host lifecycle hooks for hosted (floating) tools.\n\t */\n\tonHostedMount?: (\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\tonHostedResize?: (\n\t\tsize: HostedToolSize,\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\tonHostedUnmount?: (\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Pass 2: Tool decides if it's relevant in this context\n\t * Called ONLY if orchestrator has already allowed the tool (Pass 1)\n\t *\n\t * @param context - Rich context about where tool is being evaluated\n\t * @returns true if tool should be visible, false to hide\n\t */\n\tisVisibleInContext(context: ToolContext): boolean;\n\n\t/** Required toolbar-first render contract. */\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult | null;\n}\n\nconst VALID_TOOL_LEVELS: ToolLevel[] = [\n\t\"assessment\",\n\t\"section\",\n\t\"item\",\n\t\"passage\",\n\t\"rubric\",\n\t\"element\",\n];\n\nfunction assertNonEmptyString(\n\tvalue: unknown,\n\tfieldName: string,\n): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration: \"${fieldName}\" must be a non-empty string.`,\n\t\t);\n\t}\n}\n\n// Defence-in-depth: reject obvious XSS payloads in tool-registered icon\n// markup at registration time. Runtime rendering still runs each icon\n// through DOMPurify (see `ToolIcon.svelte`), but surfacing the problem\n// early produces a clearer error for tool authors than \"the icon silently\n// disappeared after sanitization\".\nconst SCRIPTABLE_ICON_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [\n\t{ pattern: /<script\\b/i, reason: \"contains a <script> tag\" },\n\t{\n\t\tpattern: /\\son[a-z]+\\s*=/i,\n\t\treason: \"contains an inline event handler (on*=) attribute\",\n\t},\n\t{ pattern: /javascript:/i, reason: \"contains a javascript: URL\" },\n\t{\n\t\tpattern: /<foreignObject\\b/i,\n\t\treason: \"contains a <foreignObject> element\",\n\t},\n];\n\nfunction assertIconStringIsSafe(\n\ttoolId: string,\n\ticon: string,\n\tfieldName: string,\n): void {\n\tconst trimmed = icon.trimStart();\n\tconst looksLikeSvg = trimmed.toLowerCase().startsWith(\"<svg\");\n\tconst looksLikeUrl = /^https?:/i.test(trimmed);\n\tconst looksLikeDataUrl = /^data:/i.test(trimmed);\n\tif (looksLikeDataUrl) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${toolId}\": \"${fieldName}\" may not be a data: URL.`,\n\t\t);\n\t}\n\tif (!looksLikeSvg && !looksLikeUrl) return;\n\tfor (const { pattern, reason } of SCRIPTABLE_ICON_PATTERNS) {\n\t\tif (pattern.test(icon)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid tool registration \"${toolId}\": \"${fieldName}\" ${reason}. Inline SVG icons must not include scriptable content.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction assertToolRegistrationShape(registration: ToolRegistration): void {\n\tassertNonEmptyString(registration.toolId, \"toolId\");\n\tassertNonEmptyString(registration.name, \"name\");\n\tassertNonEmptyString(registration.description, \"description\");\n\n\tif (\n\t\ttypeof registration.icon !== \"string\" &&\n\t\ttypeof registration.icon !== \"function\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"icon\" must be a string or function.`,\n\t\t);\n\t}\n\tif (typeof registration.icon === \"string\") {\n\t\tassertIconStringIsSafe(registration.toolId, registration.icon, \"icon\");\n\t}\n\tif (\n\t\t!Array.isArray(registration.supportedLevels) ||\n\t\tregistration.supportedLevels.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"supportedLevels\" must be a non-empty array.`,\n\t\t);\n\t}\n\tconst invalidLevel = registration.supportedLevels.find(\n\t\t(level) => !VALID_TOOL_LEVELS.includes(level),\n\t);\n\tif (invalidLevel) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported level \"${invalidLevel}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.activation !== undefined &&\n\t\tregistration.activation !== \"toolbar-toggle\" &&\n\t\tregistration.activation !== \"selection-gateway\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported activation \"${String(registration.activation)}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.singletonScope !== undefined &&\n\t\tregistration.singletonScope !== \"section\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported singletonScope \"${String(registration.singletonScope)}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.activation === \"selection-gateway\" &&\n\t\tregistration.singletonScope !== \"section\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": selection-gateway tools must declare singletonScope \"section\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.pnpSupportIds !== undefined &&\n\t\t(!Array.isArray(registration.pnpSupportIds) ||\n\t\t\tregistration.pnpSupportIds.some(\n\t\t\t\t(pnpId) => typeof pnpId !== \"string\" || pnpId.trim().length === 0,\n\t\t\t))\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"pnpSupportIds\" must be an array of non-empty strings.`,\n\t\t);\n\t}\n\tif (typeof registration.isVisibleInContext !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"isVisibleInContext\" must be a function.`,\n\t\t);\n\t}\n\tif (typeof registration.renderToolbar !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"renderToolbar\" must be a function.`,\n\t\t);\n\t}\n}\n\n/**\n * Tool Registry\n *\n * Manages tool registrations and provides query/lookup functionality\n */\nexport class ToolRegistry {\n\tprivate tools = new Map<string, ToolRegistration>();\n\tprivate pnpIndex = new Map<string, Set<string>>(); // pnpSupportId → Set<toolId>\n\tprivate componentOverrides: ToolComponentOverrides = {};\n\tprivate moduleLoaders = new Map<string, ToolModuleLoader>();\n\tprivate loadedToolModules = new Set<string>();\n\tprivate moduleLoadPromises = new Map<string, Promise<void>>();\n\n\t/**\n\t * Normalize a single tool alias to canonical toolId.\n\t */\n\tnormalizeToolId(toolId: string): string {\n\t\treturn normalizeToolAlias(toolId);\n\t}\n\n\t/**\n\t * Normalize a list of tool aliases to canonical toolIds.\n\t */\n\tnormalizeToolIds(toolIds: string[]): string[] {\n\t\treturn toolIds.map((toolId) => this.normalizeToolId(toolId));\n\t}\n\n\t/**\n\t * Register a tool\n\t *\n\t * @param registration - Tool registration\n\t * @throws Error if toolId is already registered\n\t */\n\tregister(registration: ToolRegistration): void {\n\t\tassertToolRegistrationShape(registration);\n\t\tif (this.tools.has(registration.toolId)) {\n\t\t\tthrow new Error(`Tool '${registration.toolId}' is already registered`);\n\t\t}\n\n\t\tthis.tools.set(registration.toolId, registration);\n\n\t\t// Index PNP support IDs\n\t\tif (registration.pnpSupportIds) {\n\t\t\tfor (const pnpId of registration.pnpSupportIds) {\n\t\t\t\tif (!this.pnpIndex.has(pnpId)) {\n\t\t\t\t\tthis.pnpIndex.set(pnpId, new Set());\n\t\t\t\t}\n\t\t\t\tthis.pnpIndex.get(pnpId)!.add(registration.toolId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Override an existing tool registration\n\t *\n\t * @param registration - New tool registration (must have existing toolId)\n\t */\n\toverride(registration: ToolRegistration): void {\n\t\tassertToolRegistrationShape(registration);\n\t\tif (!this.tools.has(registration.toolId)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot override non-existent tool '${registration.toolId}'`,\n\t\t\t);\n\t\t}\n\n\t\t// Remove old PNP index entries\n\t\tconst oldReg = this.tools.get(registration.toolId)!;\n\t\tif (oldReg.pnpSupportIds) {\n\t\t\tfor (const pnpId of oldReg.pnpSupportIds) {\n\t\t\t\tthis.pnpIndex.get(pnpId)?.delete(registration.toolId);\n\t\t\t}\n\t\t}\n\n\t\t// Add new registration\n\t\tthis.tools.set(registration.toolId, registration);\n\n\t\t// Re-index PNP support IDs\n\t\tif (registration.pnpSupportIds) {\n\t\t\tfor (const pnpId of registration.pnpSupportIds) {\n\t\t\t\tif (!this.pnpIndex.has(pnpId)) {\n\t\t\t\t\tthis.pnpIndex.set(pnpId, new Set());\n\t\t\t\t}\n\t\t\t\tthis.pnpIndex.get(pnpId)!.add(registration.toolId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Unregister a tool\n\t *\n\t * @param toolId - Tool ID to remove\n\t */\n\tunregister(toolId: string): void {\n\t\tconst reg = this.tools.get(toolId);\n\t\tif (!reg) return;\n\n\t\t// Remove PNP index entries\n\t\tif (reg.pnpSupportIds) {\n\t\t\tfor (const pnpId of reg.pnpSupportIds) {\n\t\t\t\tthis.pnpIndex.get(pnpId)?.delete(toolId);\n\t\t\t}\n\t\t}\n\n\t\tthis.tools.delete(toolId);\n\t}\n\n\t/**\n\t * Get a tool registration by ID\n\t *\n\t * @param toolId - Tool ID\n\t * @returns Tool registration or undefined\n\t */\n\tget(toolId: string): ToolRegistration | undefined {\n\t\treturn this.tools.get(toolId);\n\t}\n\n\t/**\n\t * Check if a tool is registered\n\t *\n\t * @param toolId - Tool ID\n\t * @returns true if registered\n\t */\n\thas(toolId: string): boolean {\n\t\treturn this.tools.has(toolId);\n\t}\n\n\t/**\n\t * Get all registered tool IDs\n\t *\n\t * @returns Array of tool IDs\n\t */\n\tgetAllToolIds(): string[] {\n\t\treturn Array.from(this.tools.keys());\n\t}\n\n\t/**\n\t * Get all tool registrations\n\t *\n\t * @returns Array of tool registrations\n\t */\n\tgetAllTools(): ToolRegistration[] {\n\t\treturn Array.from(this.tools.values());\n\t}\n\n\t/**\n\t * Find tool IDs that support a given PNP support ID\n\t *\n\t * @param pnpSupportId - PNP support ID (e.g., 'calculator')\n\t * @returns Set of tool IDs that support this PNP ID\n\t */\n\tgetToolsByPNPSupport(pnpSupportId: string): Set<string> {\n\t\treturn this.pnpIndex.get(pnpSupportId) || new Set();\n\t}\n\n\t/**\n\t * Get tools that support a specific level\n\t *\n\t * @param level - Tool level (assessment, section, item, passage, element)\n\t * @returns Array of tool registrations that support this level\n\t */\n\tgetToolsByLevel(level: ToolLevel): ToolRegistration[] {\n\t\treturn this.getAllTools().filter((tool) =>\n\t\t\ttool.supportedLevels.includes(level),\n\t\t);\n\t}\n\n\t/**\n\t * Resolve tool activation, defaulting to toolbar-toggle.\n\t */\n\tgetToolActivation(toolId: string): ToolActivation {\n\t\treturn this.get(toolId)?.activation || \"toolbar-toggle\";\n\t}\n\n\t/**\n\t * Resolve singleton scope for a tool when present.\n\t */\n\tgetToolSingletonScope(toolId: string): ToolSingletonScope | null {\n\t\treturn this.get(toolId)?.singletonScope || null;\n\t}\n\n\t/**\n\t * Filter tool IDs by activation type.\n\t */\n\tfilterToolIdsByActivation(\n\t\ttoolIds: string[],\n\t\tactivation: ToolActivation,\n\t): string[] {\n\t\treturn toolIds.filter(\n\t\t\t(toolId) => this.getToolActivation(toolId) === activation,\n\t\t);\n\t}\n\n\t/**\n\t * Filter tools by visibility in a given context\n\t *\n\t * Pass 2 of the two-pass model: Given a list of allowed tool IDs (from Pass 1),\n\t * ask each tool if it's relevant in this context.\n\t *\n\t * @param allowedToolIds - Tool IDs that passed Pass 1 (orchestrator approval)\n\t * @param context - Context to evaluate\n\t * @returns Array of visible tool registrations\n\t */\n\tfilterVisibleInContext(\n\t\tallowedToolIds: string[],\n\t\tcontext: ToolContext,\n\t): ToolRegistration[] {\n\t\tconst visible: ToolRegistration[] = [];\n\n\t\tfor (const toolId of allowedToolIds) {\n\t\t\tconst tool = this.get(toolId);\n\t\t\tif (!tool) {\n\t\t\t\tconsole.warn(`Tool '${toolId}' is allowed but not registered`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Check if tool supports this level\n\t\t\tif (!tool.supportedLevels.includes(context.level)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Pass 2: Ask tool if it's relevant\n\t\t\ttry {\n\t\t\t\tif (tool.isVisibleInContext(context)) {\n\t\t\t\t\tvisible.push(tool);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error evaluating visibility for tool '${toolId}':`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn visible;\n\t}\n\n\t/**\n\t * Get tool metadata for building UIs\n\t * Useful for building PNP configuration interfaces\n\t *\n\t * @returns Array of tool metadata (id, name, description, pnpSupportIds)\n\t */\n\tgetToolMetadata(): Array<{\n\t\ttoolId: string;\n\t\tname: string;\n\t\tdescription: string;\n\t\tpnpSupportIds: string[];\n\t\tsupportedLevels: ToolLevel[];\n\t\tactivation: ToolActivation;\n\t\tsingletonScope: ToolSingletonScope | null;\n\t}> {\n\t\treturn this.getAllTools().map((tool) => ({\n\t\t\ttoolId: tool.toolId,\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tpnpSupportIds: tool.pnpSupportIds || [],\n\t\t\tsupportedLevels: tool.supportedLevels,\n\t\t\tactivation: tool.activation || \"toolbar-toggle\",\n\t\t\tsingletonScope: tool.singletonScope || null,\n\t\t}));\n\t}\n\n\t/**\n\t * Generate PNP support IDs from enabled tools\n\t * Useful for creating PNP profiles\n\t *\n\t * @param enabledToolIds - Tool IDs to enable\n\t * @returns Array of unique PNP support IDs\n\t */\n\tgeneratePNPSupportsFromTools(enabledToolIds: string[]): string[] {\n\t\tconst pnpSupports = new Set<string>();\n\n\t\tfor (const toolId of enabledToolIds) {\n\t\t\tconst tool = this.get(toolId);\n\t\t\tif (tool?.pnpSupportIds) {\n\t\t\t\tfor (const pnpId of tool.pnpSupportIds) {\n\t\t\t\t\tpnpSupports.add(pnpId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(pnpSupports);\n\t}\n\n\t/**\n\t * Clear all registrations (useful for testing)\n\t */\n\tclear(): void {\n\t\tthis.tools.clear();\n\t\tthis.pnpIndex.clear();\n\t}\n\n\t/**\n\t * Configure global component overrides used by tool instance creation.\n\t */\n\tsetComponentOverrides(overrides: ToolComponentOverrides): void {\n\t\tthis.componentOverrides = overrides;\n\t}\n\n\t/**\n\t * Register lazy module loaders by toolId.\n\t * Toolbars call ensureToolModuleLoaded(toolId) before instance creation.\n\t */\n\tsetToolModuleLoaders(\n\t\tloaders: Partial<Record<string, ToolModuleLoader>>,\n\t): void {\n\t\tfor (const [toolId, loader] of Object.entries(loaders)) {\n\t\t\tif (!loader) continue;\n\t\t\tassertNonEmptyString(toolId, \"tool module loader id\");\n\t\t\tif (typeof loader !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid tool module loader for \"${toolId}\": expected a function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.moduleLoaders.set(toolId, loader);\n\t\t}\n\t}\n\n\t/**\n\t * Ensure tool module side-effects are loaded exactly once.\n\t * Safe to call repeatedly; concurrent callers share the same promise.\n\t */\n\tasync ensureToolModuleLoaded(toolId: string): Promise<void> {\n\t\tif (this.loadedToolModules.has(toolId)) return;\n\n\t\tconst existingPromise = this.moduleLoadPromises.get(toolId);\n\t\tif (existingPromise) {\n\t\t\tawait existingPromise;\n\t\t\treturn;\n\t\t}\n\n\t\tconst loader = this.moduleLoaders.get(toolId);\n\t\tif (!loader) return;\n\n\t\tconst loadPromise = (async () => {\n\t\t\tawait loader();\n\t\t\tthis.loadedToolModules.add(toolId);\n\t\t})();\n\n\t\tthis.moduleLoadPromises.set(toolId, loadPromise);\n\t\ttry {\n\t\t\tawait loadPromise;\n\t\t} finally {\n\t\t\tthis.moduleLoadPromises.delete(toolId);\n\t\t}\n\t}\n\n\t/**\n\t * Ensure a set of tool modules are loaded.\n\t */\n\tasync ensureToolModulesLoaded(toolIds: string[]): Promise<void> {\n\t\tawait Promise.all(\n\t\t\ttoolIds.map((toolId) => this.ensureToolModuleLoaded(toolId)),\n\t\t);\n\t}\n\n\t/**\n\t * Whether a tool module has already been loaded.\n\t */\n\tisToolModuleLoaded(toolId: string): boolean {\n\t\treturn this.loadedToolModules.has(toolId);\n\t}\n\n\t/**\n\t * Render a tool for toolbar use with component overrides attached.\n\t */\n\trenderForToolbar(\n\t\ttoolId: string,\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult | null {\n\t\tconst tool = this.get(toolId);\n\t\tif (!tool) {\n\t\t\tthrow new Error(`Tool '${toolId}' is not registered`);\n\t\t}\n\n\t\tconst mergedContext: ToolbarContext = {\n\t\t\t...toolbarContext,\n\t\t\tcomponentOverrides: {\n\t\t\t\t...(this.componentOverrides || {}),\n\t\t\t\t...(toolbarContext.componentOverrides || {}),\n\t\t\t},\n\t\t};\n\n\t\treturn tool.renderToolbar(context, mergedContext);\n\t}\n}\n"]}
1
+ {"version":3,"file":"ToolRegistry.js","sourceRoot":"","sources":["../../src/services/ToolRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tool Registry\n *\n * Central registry for all assessment tools. Manages tool metadata, visibility logic,\n * and button/instance creation. Supports dynamic registration and override by integrators.\n */\n\nimport type { ToolContext, ToolLevel } from \"./tool-context.js\";\nimport type { ToolComponentOverrides } from \"../tools/tool-tag-map.js\";\nimport type {\n\tElementToolStateStoreApi,\n\tToolCoordinatorApi,\n\tToolkitCoordinatorApi,\n\tTtsServiceApi,\n} from \"./interfaces.js\";\nimport type { ToolProviderApi } from \"./tool-providers/ToolProviderApi.js\";\nimport type { ToolProviderConfig as ToolRuntimeConfig } from \"./tools-config-normalizer.js\";\nimport type { ToolConfigDiagnostic } from \"./tool-config-validation.js\";\nimport { normalizeToolAlias } from \"./tools-config-normalizer.js\";\n\nexport type ToolModuleLoader = () => Promise<unknown>;\n\nexport interface ToolToolbarButtonDefinition {\n\ttoolId: string;\n\tlabel: string;\n\ticon: string;\n\tariaLabel: string;\n\ttooltip?: string;\n\tonClick: () => void;\n\tclassName?: string;\n\tdisabled?: boolean;\n\tactive?: boolean;\n}\n\nexport interface ToolbarContext {\n\tscope: {\n\t\tlevel: ToolLevel;\n\t\tscopeId: string;\n\t\tassessmentId?: string;\n\t\tsectionId?: string;\n\t\titemId?: string;\n\t\tcanonicalItemId?: string;\n\t\tcontentKind?: string;\n\t};\n\titemId: string;\n\tcatalogId: string;\n\tlanguage: string;\n\tui?: {\n\t\tsize?: string;\n\t};\n\tgetScopeElement?: () => HTMLElement | null;\n\tgetGlobalElementId?: () => string | null;\n\ttoolCoordinator: ToolCoordinatorApi | null;\n\ttoolkitCoordinator: ToolkitCoordinatorApi | null;\n\tttsService: TtsServiceApi | null;\n\telementToolStateStore: ElementToolStateStoreApi | null;\n\ttoggleTool: (toolId: string) => void;\n\tisToolVisible: (toolId: string) => boolean;\n\tsubscribeVisibility: ((listener: () => void) => () => void) | null;\n\tcomponentOverrides?: ToolComponentOverrides;\n\tgetResolvedToolContext?: (toolId: string) => ResolvedToolContext | null;\n\tgetToolRenderParams?: (toolId: string) => Record<string, unknown> | null;\n}\n\nexport interface ToolContextResolverContext {\n\ttoolId: string;\n\tcontext: ToolContext;\n\ttoolbarContext: ToolbarContext;\n}\n\nexport interface ToolContextResolverResult {\n\tvisible?: boolean;\n\tparams?: Record<string, unknown>;\n\treason?: string;\n}\n\nexport type ToolContextResolver = (\n\tcontext: ToolContextResolverContext,\n) => ToolContextResolverResult | null | undefined;\n\nexport type ToolContextResolverMap = Record<\n\tstring,\n\tToolContextResolver | null | undefined\n>;\n\nexport interface ResolvedToolContext {\n\ttoolId: string;\n\tvisible: boolean;\n\tparams: Record<string, unknown>;\n\treason?: string;\n}\n\nexport interface ToolRenderElement {\n\telement: HTMLElement | null;\n\tmount: \"before-buttons\" | \"after-buttons\" | \"controls-row\";\n\tlayoutHints?: {\n\t\tcontrolsRow?: {\n\t\t\treserveSpace?: boolean;\n\t\t\tshowWhenToolActive?: boolean;\n\t\t};\n\t\theaderOverlay?: {\n\t\t\tshowWhenToolActive?: boolean;\n\t\t};\n\t};\n\tshell?: ToolWindowShellConfig;\n}\n\nexport interface ToolWindowShellAction {\n\tid: string;\n\tlabel: string;\n\tariaLabel?: string;\n\ticonSvg?: string;\n\tonClick: () => void;\n}\n\n/**\n * Alignment corner for the initial shell position.\n * The shell is offset by `initialMargin` (default 16 px) from the chosen corner.\n */\nexport type ToolWindowShellAlign =\n\t| \"center\"\n\t| \"top-left\"\n\t| \"top-right\"\n\t| \"bottom-left\"\n\t| \"bottom-right\";\n\nexport interface ToolWindowShellContentConfig {\n\t/** Vertical overflow behavior for the hosted content pane. Defaults to \"hidden\". */\n\toverflowY?: \"hidden\" | \"auto\";\n\t/**\n\t * Preserve the content area's configured minimum height when the shell shrinks\n\t * below `minHeight`, letting the content pane scroll instead of compressing\n\t * the hosted element.\n\t */\n\tpreserveMinHeight?: boolean;\n}\n\nexport interface ToolWindowShellConfig {\n\ttitle?: string;\n\tdraggable?: boolean;\n\tresizable?: boolean;\n\tcloseable?: boolean;\n\tinitialWidth?: number;\n\tinitialHeight?: number;\n\tminWidth?: number;\n\tminHeight?: number;\n\tmaxWidth?: number;\n\tmaxHeight?: number;\n\t/** Initial placement of the shell. Defaults to `'center'`. */\n\tinitialAlign?: ToolWindowShellAlign;\n\t/** Distance (px) from the viewport edge when using a corner align. Defaults to 16. */\n\tinitialMargin?: number;\n\tcontent?: ToolWindowShellContentConfig;\n\tactions?: ToolWindowShellAction[];\n}\n\nexport interface HostedToolContext {\n\ttoolId: string;\n\ttoolbarContext: ToolbarContext;\n\tshellConfig: ToolWindowShellConfig;\n}\n\nexport interface HostedToolSize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface ToolProviderDescriptor {\n\tgetProviderId?: (config: ToolRuntimeConfig | undefined) => string;\n\tcreateProvider: (config: ToolRuntimeConfig | undefined) => ToolProviderApi;\n\tgetInitConfig?: (\n\t\tconfig: ToolRuntimeConfig | undefined,\n\t) => Record<string, unknown>;\n\tsanitizeConfig?: (config: ToolRuntimeConfig) => ToolRuntimeConfig;\n\tvalidateConfig?: (config: ToolRuntimeConfig) => ToolConfigDiagnostic[];\n\tgetAuthFetcher?: (\n\t\tconfig: ToolRuntimeConfig | undefined,\n\t) => (() => Promise<Record<string, unknown>>) | undefined;\n\tlazy?: boolean;\n}\n\nexport interface ToolToolbarRenderResult {\n\ttoolId: string;\n\telements?: ToolRenderElement[];\n\tbutton?: ToolToolbarButtonDefinition | null;\n\tsync?: () => void;\n\tsubscribeActive?: (callback: (active: boolean) => void) => () => void;\n}\n\nexport type ToolActivation = \"toolbar-toggle\" | \"selection-gateway\";\nexport type ToolSingletonScope = \"section\";\n\n/**\n * Tool registration interface\n */\nexport interface ToolRegistration {\n\t/** Unique tool identifier (e.g., 'calculator', 'textToSpeech') */\n\ttoolId: string;\n\n\t/** Human-readable name */\n\tname: string;\n\n\t/** Description of what the tool does */\n\tdescription: string;\n\n\t/** Icon identifier or SVG string */\n\ticon: string | ((context: ToolContext) => string);\n\n\t/** Which levels this tool supports */\n\tsupportedLevels: ToolLevel[];\n\n\t/**\n\t * Activation model for this tool.\n\t * - toolbar-toggle: rendered as a toolbar button (default)\n\t * - selection-gateway: rendered as a singleton selection-driven gateway\n\t */\n\tactivation?: ToolActivation;\n\n\t/**\n\t * Optional singleton scope for activation models that mount exactly one instance.\n\t */\n\tsingletonScope?: ToolSingletonScope;\n\n\t/**\n\t * PNP support IDs that enable this tool (optional)\n\t * Used by the tool policy engine to determine if a PNP support enables this tool.\n\t * Example: ['calculator', 'basic-calculator', 'scientific-calculator']\n\t */\n\tpnpSupportIds?: string[];\n\t/**\n\t * Optional provider registration metadata.\n\t * When present, ToolkitCoordinator can register provider(s) generically\n\t * without hardcoded tool-specific branches.\n\t */\n\tprovider?: ToolProviderDescriptor;\n\t/**\n\t * Optional shell-host lifecycle hooks for hosted (floating) tools.\n\t */\n\tonHostedMount?: (\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\tonHostedResize?: (\n\t\tsize: HostedToolSize,\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\tonHostedUnmount?: (\n\t\telement: HTMLElement,\n\t\tcontext: HostedToolContext,\n\t) => void | Promise<void>;\n\n\t/**\n\t * Pass 2: Tool decides if it's relevant in this context\n\t * Called ONLY if orchestrator has already allowed the tool (Pass 1)\n\t *\n\t * @param context - Rich context about where tool is being evaluated\n\t * @returns true if tool should be visible, false to hide\n\t */\n\tisVisibleInContext(context: ToolContext): boolean;\n\n\t/** Required toolbar-first render contract. */\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult | null;\n}\n\nconst VALID_TOOL_LEVELS: ToolLevel[] = [\n\t\"assessment\",\n\t\"section\",\n\t\"item\",\n\t\"passage\",\n\t\"rubric\",\n\t\"element\",\n];\n\nfunction assertNonEmptyString(\n\tvalue: unknown,\n\tfieldName: string,\n): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration: \"${fieldName}\" must be a non-empty string.`,\n\t\t);\n\t}\n}\n\n// Defence-in-depth: reject obvious XSS payloads in tool-registered icon\n// markup at registration time. Runtime rendering still runs each icon\n// through DOMPurify (see `ToolIcon.svelte`), but surfacing the problem\n// early produces a clearer error for tool authors than \"the icon silently\n// disappeared after sanitization\".\nconst SCRIPTABLE_ICON_PATTERNS: Array<{ pattern: RegExp; reason: string }> = [\n\t{ pattern: /<script\\b/i, reason: \"contains a <script> tag\" },\n\t{\n\t\tpattern: /\\son[a-z]+\\s*=/i,\n\t\treason: \"contains an inline event handler (on*=) attribute\",\n\t},\n\t{ pattern: /javascript:/i, reason: \"contains a javascript: URL\" },\n\t{\n\t\tpattern: /<foreignObject\\b/i,\n\t\treason: \"contains a <foreignObject> element\",\n\t},\n];\n\nfunction assertIconStringIsSafe(\n\ttoolId: string,\n\ticon: string,\n\tfieldName: string,\n): void {\n\tconst trimmed = icon.trimStart();\n\tconst looksLikeSvg = trimmed.toLowerCase().startsWith(\"<svg\");\n\tconst looksLikeUrl = /^https?:/i.test(trimmed);\n\tconst looksLikeDataUrl = /^data:/i.test(trimmed);\n\tif (looksLikeDataUrl) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${toolId}\": \"${fieldName}\" may not be a data: URL.`,\n\t\t);\n\t}\n\tif (!looksLikeSvg && !looksLikeUrl) return;\n\tfor (const { pattern, reason } of SCRIPTABLE_ICON_PATTERNS) {\n\t\tif (pattern.test(icon)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid tool registration \"${toolId}\": \"${fieldName}\" ${reason}. Inline SVG icons must not include scriptable content.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nfunction assertToolRegistrationShape(registration: ToolRegistration): void {\n\tassertNonEmptyString(registration.toolId, \"toolId\");\n\tassertNonEmptyString(registration.name, \"name\");\n\tassertNonEmptyString(registration.description, \"description\");\n\n\tif (\n\t\ttypeof registration.icon !== \"string\" &&\n\t\ttypeof registration.icon !== \"function\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"icon\" must be a string or function.`,\n\t\t);\n\t}\n\tif (typeof registration.icon === \"string\") {\n\t\tassertIconStringIsSafe(registration.toolId, registration.icon, \"icon\");\n\t}\n\tif (\n\t\t!Array.isArray(registration.supportedLevels) ||\n\t\tregistration.supportedLevels.length === 0\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"supportedLevels\" must be a non-empty array.`,\n\t\t);\n\t}\n\tconst invalidLevel = registration.supportedLevels.find(\n\t\t(level) => !VALID_TOOL_LEVELS.includes(level),\n\t);\n\tif (invalidLevel) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported level \"${invalidLevel}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.activation !== undefined &&\n\t\tregistration.activation !== \"toolbar-toggle\" &&\n\t\tregistration.activation !== \"selection-gateway\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported activation \"${String(registration.activation)}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.singletonScope !== undefined &&\n\t\tregistration.singletonScope !== \"section\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": unsupported singletonScope \"${String(registration.singletonScope)}\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.activation === \"selection-gateway\" &&\n\t\tregistration.singletonScope !== \"section\"\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": selection-gateway tools must declare singletonScope \"section\".`,\n\t\t);\n\t}\n\tif (\n\t\tregistration.pnpSupportIds !== undefined &&\n\t\t(!Array.isArray(registration.pnpSupportIds) ||\n\t\t\tregistration.pnpSupportIds.some(\n\t\t\t\t(pnpId) => typeof pnpId !== \"string\" || pnpId.trim().length === 0,\n\t\t\t))\n\t) {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"pnpSupportIds\" must be an array of non-empty strings.`,\n\t\t);\n\t}\n\tif (typeof registration.isVisibleInContext !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"isVisibleInContext\" must be a function.`,\n\t\t);\n\t}\n\tif (typeof registration.renderToolbar !== \"function\") {\n\t\tthrow new Error(\n\t\t\t`Invalid tool registration \"${registration.toolId}\": \"renderToolbar\" must be a function.`,\n\t\t);\n\t}\n}\n\n/**\n * Tool Registry\n *\n * Manages tool registrations and provides query/lookup functionality\n */\nexport class ToolRegistry {\n\tprivate tools = new Map<string, ToolRegistration>();\n\tprivate pnpIndex = new Map<string, Set<string>>(); // pnpSupportId → Set<toolId>\n\tprivate componentOverrides: ToolComponentOverrides = {};\n\tprivate moduleLoaders = new Map<string, ToolModuleLoader>();\n\tprivate loadedToolModules = new Set<string>();\n\tprivate moduleLoadPromises = new Map<string, Promise<void>>();\n\n\t/**\n\t * Normalize a single tool alias to canonical toolId.\n\t */\n\tnormalizeToolId(toolId: string): string {\n\t\treturn normalizeToolAlias(toolId);\n\t}\n\n\t/**\n\t * Normalize a list of tool aliases to canonical toolIds.\n\t */\n\tnormalizeToolIds(toolIds: string[]): string[] {\n\t\treturn toolIds.map((toolId) => this.normalizeToolId(toolId));\n\t}\n\n\t/**\n\t * Register a tool\n\t *\n\t * @param registration - Tool registration\n\t * @throws Error if toolId is already registered\n\t */\n\tregister(registration: ToolRegistration): void {\n\t\tassertToolRegistrationShape(registration);\n\t\tif (this.tools.has(registration.toolId)) {\n\t\t\tthrow new Error(`Tool '${registration.toolId}' is already registered`);\n\t\t}\n\n\t\tthis.tools.set(registration.toolId, registration);\n\n\t\t// Index PNP support IDs\n\t\tif (registration.pnpSupportIds) {\n\t\t\tfor (const pnpId of registration.pnpSupportIds) {\n\t\t\t\tif (!this.pnpIndex.has(pnpId)) {\n\t\t\t\t\tthis.pnpIndex.set(pnpId, new Set());\n\t\t\t\t}\n\t\t\t\tthis.pnpIndex.get(pnpId)!.add(registration.toolId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Override an existing tool registration\n\t *\n\t * @param registration - New tool registration (must have existing toolId)\n\t */\n\toverride(registration: ToolRegistration): void {\n\t\tassertToolRegistrationShape(registration);\n\t\tif (!this.tools.has(registration.toolId)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot override non-existent tool '${registration.toolId}'`,\n\t\t\t);\n\t\t}\n\n\t\t// Remove old PNP index entries\n\t\tconst oldReg = this.tools.get(registration.toolId)!;\n\t\tif (oldReg.pnpSupportIds) {\n\t\t\tfor (const pnpId of oldReg.pnpSupportIds) {\n\t\t\t\tthis.pnpIndex.get(pnpId)?.delete(registration.toolId);\n\t\t\t}\n\t\t}\n\n\t\t// Add new registration\n\t\tthis.tools.set(registration.toolId, registration);\n\n\t\t// Re-index PNP support IDs\n\t\tif (registration.pnpSupportIds) {\n\t\t\tfor (const pnpId of registration.pnpSupportIds) {\n\t\t\t\tif (!this.pnpIndex.has(pnpId)) {\n\t\t\t\t\tthis.pnpIndex.set(pnpId, new Set());\n\t\t\t\t}\n\t\t\t\tthis.pnpIndex.get(pnpId)!.add(registration.toolId);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Unregister a tool\n\t *\n\t * @param toolId - Tool ID to remove\n\t */\n\tunregister(toolId: string): void {\n\t\tconst reg = this.tools.get(toolId);\n\t\tif (!reg) return;\n\n\t\t// Remove PNP index entries\n\t\tif (reg.pnpSupportIds) {\n\t\t\tfor (const pnpId of reg.pnpSupportIds) {\n\t\t\t\tthis.pnpIndex.get(pnpId)?.delete(toolId);\n\t\t\t}\n\t\t}\n\n\t\tthis.tools.delete(toolId);\n\t}\n\n\t/**\n\t * Get a tool registration by ID\n\t *\n\t * @param toolId - Tool ID\n\t * @returns Tool registration or undefined\n\t */\n\tget(toolId: string): ToolRegistration | undefined {\n\t\treturn this.tools.get(toolId);\n\t}\n\n\t/**\n\t * Check if a tool is registered\n\t *\n\t * @param toolId - Tool ID\n\t * @returns true if registered\n\t */\n\thas(toolId: string): boolean {\n\t\treturn this.tools.has(toolId);\n\t}\n\n\t/**\n\t * Get all registered tool IDs\n\t *\n\t * @returns Array of tool IDs\n\t */\n\tgetAllToolIds(): string[] {\n\t\treturn Array.from(this.tools.keys());\n\t}\n\n\t/**\n\t * Get all tool registrations\n\t *\n\t * @returns Array of tool registrations\n\t */\n\tgetAllTools(): ToolRegistration[] {\n\t\treturn Array.from(this.tools.values());\n\t}\n\n\t/**\n\t * Find tool IDs that support a given PNP support ID\n\t *\n\t * @param pnpSupportId - PNP support ID (e.g., 'calculator')\n\t * @returns Set of tool IDs that support this PNP ID\n\t */\n\tgetToolsByPNPSupport(pnpSupportId: string): Set<string> {\n\t\treturn this.pnpIndex.get(pnpSupportId) || new Set();\n\t}\n\n\t/**\n\t * Get tools that support a specific level\n\t *\n\t * @param level - Tool level (assessment, section, item, passage, element)\n\t * @returns Array of tool registrations that support this level\n\t */\n\tgetToolsByLevel(level: ToolLevel): ToolRegistration[] {\n\t\treturn this.getAllTools().filter((tool) =>\n\t\t\ttool.supportedLevels.includes(level),\n\t\t);\n\t}\n\n\t/**\n\t * Resolve tool activation, defaulting to toolbar-toggle.\n\t */\n\tgetToolActivation(toolId: string): ToolActivation {\n\t\treturn this.get(toolId)?.activation || \"toolbar-toggle\";\n\t}\n\n\t/**\n\t * Resolve singleton scope for a tool when present.\n\t */\n\tgetToolSingletonScope(toolId: string): ToolSingletonScope | null {\n\t\treturn this.get(toolId)?.singletonScope || null;\n\t}\n\n\t/**\n\t * Filter tool IDs by activation type.\n\t */\n\tfilterToolIdsByActivation(\n\t\ttoolIds: string[],\n\t\tactivation: ToolActivation,\n\t): string[] {\n\t\treturn toolIds.filter(\n\t\t\t(toolId) => this.getToolActivation(toolId) === activation,\n\t\t);\n\t}\n\n\t/**\n\t * Filter tools by visibility in a given context\n\t *\n\t * Pass 2 of the two-pass model: Given a list of allowed tool IDs (from Pass 1),\n\t * ask each tool if it's relevant in this context.\n\t *\n\t * @param allowedToolIds - Tool IDs that passed Pass 1 (orchestrator approval)\n\t * @param context - Context to evaluate\n\t * @returns Array of visible tool registrations\n\t */\n\tfilterVisibleInContext(\n\t\tallowedToolIds: string[],\n\t\tcontext: ToolContext,\n\t): ToolRegistration[] {\n\t\tconst visible: ToolRegistration[] = [];\n\n\t\tfor (const toolId of allowedToolIds) {\n\t\t\tconst tool = this.get(toolId);\n\t\t\tif (!tool) {\n\t\t\t\tconsole.warn(`Tool '${toolId}' is allowed but not registered`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Check if tool supports this level\n\t\t\tif (!tool.supportedLevels.includes(context.level)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Pass 2: Ask tool if it's relevant\n\t\t\ttry {\n\t\t\t\tif (tool.isVisibleInContext(context)) {\n\t\t\t\t\tvisible.push(tool);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`Error evaluating visibility for tool '${toolId}':`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn visible;\n\t}\n\n\t/**\n\t * Get tool metadata for building UIs\n\t * Useful for building PNP configuration interfaces\n\t *\n\t * @returns Array of tool metadata (id, name, description, pnpSupportIds)\n\t */\n\tgetToolMetadata(): Array<{\n\t\ttoolId: string;\n\t\tname: string;\n\t\tdescription: string;\n\t\tpnpSupportIds: string[];\n\t\tsupportedLevels: ToolLevel[];\n\t\tactivation: ToolActivation;\n\t\tsingletonScope: ToolSingletonScope | null;\n\t}> {\n\t\treturn this.getAllTools().map((tool) => ({\n\t\t\ttoolId: tool.toolId,\n\t\t\tname: tool.name,\n\t\t\tdescription: tool.description,\n\t\t\tpnpSupportIds: tool.pnpSupportIds || [],\n\t\t\tsupportedLevels: tool.supportedLevels,\n\t\t\tactivation: tool.activation || \"toolbar-toggle\",\n\t\t\tsingletonScope: tool.singletonScope || null,\n\t\t}));\n\t}\n\n\t/**\n\t * Generate PNP support IDs from enabled tools\n\t * Useful for creating PNP profiles\n\t *\n\t * @param enabledToolIds - Tool IDs to enable\n\t * @returns Array of unique PNP support IDs\n\t */\n\tgeneratePNPSupportsFromTools(enabledToolIds: string[]): string[] {\n\t\tconst pnpSupports = new Set<string>();\n\n\t\tfor (const toolId of enabledToolIds) {\n\t\t\tconst tool = this.get(toolId);\n\t\t\tif (tool?.pnpSupportIds) {\n\t\t\t\tfor (const pnpId of tool.pnpSupportIds) {\n\t\t\t\t\tpnpSupports.add(pnpId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(pnpSupports);\n\t}\n\n\t/**\n\t * Clear all registrations (useful for testing)\n\t */\n\tclear(): void {\n\t\tthis.tools.clear();\n\t\tthis.pnpIndex.clear();\n\t}\n\n\t/**\n\t * Configure global component overrides used by tool instance creation.\n\t */\n\tsetComponentOverrides(overrides: ToolComponentOverrides): void {\n\t\tthis.componentOverrides = overrides;\n\t}\n\n\t/**\n\t * Register lazy module loaders by toolId.\n\t * Toolbars call ensureToolModuleLoaded(toolId) before instance creation.\n\t */\n\tsetToolModuleLoaders(\n\t\tloaders: Partial<Record<string, ToolModuleLoader>>,\n\t): void {\n\t\tfor (const [toolId, loader] of Object.entries(loaders)) {\n\t\t\tif (!loader) continue;\n\t\t\tassertNonEmptyString(toolId, \"tool module loader id\");\n\t\t\tif (typeof loader !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Invalid tool module loader for \"${toolId}\": expected a function.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.moduleLoaders.set(toolId, loader);\n\t\t}\n\t}\n\n\t/**\n\t * Ensure tool module side-effects are loaded exactly once.\n\t * Safe to call repeatedly; concurrent callers share the same promise.\n\t */\n\tasync ensureToolModuleLoaded(toolId: string): Promise<void> {\n\t\tif (this.loadedToolModules.has(toolId)) return;\n\n\t\tconst existingPromise = this.moduleLoadPromises.get(toolId);\n\t\tif (existingPromise) {\n\t\t\tawait existingPromise;\n\t\t\treturn;\n\t\t}\n\n\t\tconst loader = this.moduleLoaders.get(toolId);\n\t\tif (!loader) return;\n\n\t\tconst loadPromise = (async () => {\n\t\t\tawait loader();\n\t\t\tthis.loadedToolModules.add(toolId);\n\t\t})();\n\n\t\tthis.moduleLoadPromises.set(toolId, loadPromise);\n\t\ttry {\n\t\t\tawait loadPromise;\n\t\t} finally {\n\t\t\tthis.moduleLoadPromises.delete(toolId);\n\t\t}\n\t}\n\n\t/**\n\t * Ensure a set of tool modules are loaded.\n\t */\n\tasync ensureToolModulesLoaded(toolIds: string[]): Promise<void> {\n\t\tawait Promise.all(\n\t\t\ttoolIds.map((toolId) => this.ensureToolModuleLoaded(toolId)),\n\t\t);\n\t}\n\n\t/**\n\t * Whether a tool module has already been loaded.\n\t */\n\tisToolModuleLoaded(toolId: string): boolean {\n\t\treturn this.loadedToolModules.has(toolId);\n\t}\n\n\t/**\n\t * Render a tool for toolbar use with component overrides attached.\n\t */\n\trenderForToolbar(\n\t\ttoolId: string,\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult | null {\n\t\tconst tool = this.get(toolId);\n\t\tif (!tool) {\n\t\t\tthrow new Error(`Tool '${toolId}' is not registered`);\n\t\t}\n\n\t\tconst mergedContext: ToolbarContext = {\n\t\t\t...toolbarContext,\n\t\t\tcomponentOverrides: {\n\t\t\t\t...(this.componentOverrides || {}),\n\t\t\t\t...(toolbarContext.componentOverrides || {}),\n\t\t\t},\n\t\t};\n\n\t\treturn tool.renderToolbar(context, mergedContext);\n\t}\n}\n"]}
@@ -8,6 +8,9 @@ export interface TTSHostToolbarLayout {
8
8
  reserveSpace: boolean;
9
9
  expandWhenToolActive: boolean;
10
10
  };
11
+ headerOverlay: {
12
+ expandWhenToolActive: boolean;
13
+ };
11
14
  }
12
15
  export interface TTSSpeedOptionConfig {
13
16
  rate: number;
@@ -312,6 +312,9 @@ export const resolveTTSHostToolbarLayout = (config) => {
312
312
  reserveSpace: true,
313
313
  expandWhenToolActive: false,
314
314
  },
315
+ headerOverlay: {
316
+ expandWhenToolActive: false,
317
+ },
315
318
  };
316
319
  case "expanding-row":
317
320
  return {
@@ -320,8 +323,21 @@ export const resolveTTSHostToolbarLayout = (config) => {
320
323
  reserveSpace: false,
321
324
  expandWhenToolActive: true,
322
325
  },
326
+ headerOverlay: {
327
+ expandWhenToolActive: false,
328
+ },
323
329
  };
324
330
  case "floating-overlay":
331
+ return {
332
+ mount: "before-buttons",
333
+ controlsRow: {
334
+ reserveSpace: false,
335
+ expandWhenToolActive: false,
336
+ },
337
+ headerOverlay: {
338
+ expandWhenToolActive: false,
339
+ },
340
+ };
325
341
  case "left-aligned":
326
342
  default:
327
343
  return {
@@ -330,6 +346,9 @@ export const resolveTTSHostToolbarLayout = (config) => {
330
346
  reserveSpace: false,
331
347
  expandWhenToolActive: false,
332
348
  },
349
+ headerOverlay: {
350
+ expandWhenToolActive: true,
351
+ },
333
352
  };
334
353
  }
335
354
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSSpeedOptionConfig {\n\trate: number;\n\tlabel?: string;\n\tariaLabel?: string;\n\tdefault?: boolean;\n}\n\nexport type TTSSpeedOption = number | TTSSpeedOptionConfig;\n\nexport interface NormalizedTTSSpeedOption {\n\trate: number;\n\tlabel: string;\n\tariaLabel: string;\n\tisDefault: boolean;\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t * - Object entries can customize button text while preserving numeric rates.\n\t */\n\tspeedOptions?: TTSSpeedOption[];\n\t/**\n\t * Show a rendered speed group even when there is only one visible option.\n\t * Defaults to false because a one-option radio group has no meaningful choice.\n\t */\n\tshowSingleSpeedOption?: boolean;\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\nconst DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([\n\t{ rate: 0.8, label: \"Slow\", ariaLabel: \"Slow speed\" },\n\t{ rate: 1, label: \"Normal\", ariaLabel: \"Normal speed\", default: true },\n\t{ rate: 1.25, label: \"Fast\", ariaLabel: \"Fast speed\" },\n] satisfies TTSSpeedOptionConfig[]);\n\nconst normalizeSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\tconst rounded = Math.round(entry * 100) / 100;\n\treturn rounded === 1 ? undefined : rounded;\n};\n\nconst normalizeControlSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\treturn Math.round(entry * 100) / 100;\n};\n\nconst trimOptionalText = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst formatSpeedLabel = (rate: number): string => `${rate}x`;\n\nconst formatSpeedAriaLabel = (label: string, usedDefaultLabel: boolean): string =>\n\tlabel.toLowerCase() === \"normal\"\n\t\t? \"Normal speed\"\n\t\t: usedDefaultLabel\n\t\t\t? `Speed ${label}`\n\t\t\t: `${label} speed`;\n\nconst normalizeSpeedAriaLabel = (\n\tlabel: string,\n\tariaLabel: string | undefined,\n\tusedDefaultLabel: boolean,\n): string => {\n\tif (!ariaLabel) return formatSpeedAriaLabel(label, usedDefaultLabel);\n\tif (ariaLabel.toLowerCase().includes(label.toLowerCase())) return ariaLabel;\n\treturn `${label} ${ariaLabel}`;\n};\n\nconst normalizeTTSSpeedOptionConfig = (\n\tentry: unknown,\n): TTSSpeedOption | undefined => {\n\tif (typeof entry === \"number\") return normalizeSpeedRate(entry);\n\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n\tconst record = entry as Record<string, unknown>;\n\tconst rate = normalizeSpeedRate(record.rate);\n\tif (rate === undefined) return undefined;\n\tconst label = trimOptionalText(record.label);\n\tconst ariaLabel = trimOptionalText(record.ariaLabel);\n\treturn {\n\t\trate,\n\t\t...(label ? { label } : {}),\n\t\t...(ariaLabel ? { ariaLabel } : {}),\n\t};\n};\n\nexport const normalizeTTSSpeedOptionConfigs = (\n\tvalue: unknown,\n): TTSSpeedOption[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: TTSSpeedOption[] = [];\n\tfor (const entry of value) {\n\t\tconst option = normalizeTTSSpeedOptionConfig(entry);\n\t\tif (option === undefined) continue;\n\t\tconst rate = typeof option === \"number\" ? option : option.rate;\n\t\tif (dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(option);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\treturn normalizeTTSSpeedOptionConfigs(value).map((option) =>\n\t\ttypeof option === \"number\" ? option : option.rate,\n\t);\n};\n\nexport const normalizeTTSSpeedControlOptions = (\n\tvalue: unknown,\n): NormalizedTTSSpeedOption[] => {\n\tconst input = Array.isArray(value)\n\t\t? value\n\t\t: [...DEFAULT_TTS_SPEED_CONTROL_OPTIONS];\n\tif (input.length === 0) return [];\n\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: Array<NormalizedTTSSpeedOption & { requestedDefault: boolean }> =\n\t\t[];\n\n\tfor (const entry of input) {\n\t\tconst record = toRecord(entry);\n\t\tconst rate =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? normalizeControlSpeedRate(entry)\n\t\t\t\t: normalizeControlSpeedRate(record.rate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\n\t\tconst defaultLabel =\n\t\t\trate === 1 ? \"Normal\" : typeof entry === \"number\" ? formatSpeedLabel(rate) : formatSpeedLabel(rate);\n\t\tconst label =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? defaultLabel\n\t\t\t\t: trimOptionalText(record.label) || defaultLabel;\n\t\tconst ariaLabel =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? rate === 1\n\t\t\t\t\t? \"Normal speed\"\n\t\t\t\t\t: formatSpeedAriaLabel(label, true)\n\t\t\t\t: normalizeSpeedAriaLabel(\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\ttrimOptionalText(record.ariaLabel),\n\t\t\t\t\t\tlabel === defaultLabel,\n\t\t\t\t\t);\n\t\tnormalized.push({\n\t\t\trate,\n\t\t\tlabel,\n\t\t\tariaLabel,\n\t\t\tisDefault: false,\n\t\t\trequestedDefault:\n\t\t\t\trecord.default === true || (record as { isDefault?: unknown }).isDefault === true,\n\t\t});\n\t}\n\n\tif (!normalized.length) {\n\t\treturn normalizeTTSSpeedControlOptions(DEFAULT_TTS_SPEED_CONTROL_OPTIONS);\n\t}\n\n\tif (!dedupedRates.has(1)) {\n\t\tconst normalOption = {\n\t\t\trate: 1,\n\t\t\tlabel: \"Normal\",\n\t\t\tariaLabel: \"Normal speed\",\n\t\t\tisDefault: false,\n\t\t\trequestedDefault: false,\n\t\t};\n\t\tconst firstFasterIndex = normalized.findIndex((option) => option.rate > 1);\n\t\tif (firstFasterIndex >= 0) {\n\t\t\tnormalized.splice(firstFasterIndex, 0, normalOption);\n\t\t} else {\n\t\t\tnormalized.push(normalOption);\n\t\t}\n\t}\n\n\tconst requestedDefaultIndex = normalized.findIndex(\n\t\t(option) => option.requestedDefault,\n\t);\n\tconst defaultIndex =\n\t\trequestedDefaultIndex >= 0\n\t\t\t? requestedDefaultIndex\n\t\t\t: normalized.findIndex((option) => option.rate === 1);\n\n\treturn normalized.map(({ requestedDefault: _requestedDefault, ...option }, index) => ({\n\t\t...option,\n\t\tisDefault: index === defaultIndex,\n\t}));\n};\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\nconst DEFAULT_TTS_SPEED_CONTROL_RATES = Object.freeze([0.8, 1, 1.25]);\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: number[] = [];\n\tfor (const candidate of candidates) {\n\t\tconst rate = normalizeControlSpeedRate(candidate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(rate);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(\n\t\t\t\twithServerDefaults.defaultVoice,\n\t\t\t\t\"en-US-Wavenet-A\",\n\t\t\t),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine\n\t\t\t\t? { engine: config.engine }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format\n\t\t\t\t? { format: config.format }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
1
+ {"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n\theaderOverlay: {\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSSpeedOptionConfig {\n\trate: number;\n\tlabel?: string;\n\tariaLabel?: string;\n\tdefault?: boolean;\n}\n\nexport type TTSSpeedOption = number | TTSSpeedOptionConfig;\n\nexport interface NormalizedTTSSpeedOption {\n\trate: number;\n\tlabel: string;\n\tariaLabel: string;\n\tisDefault: boolean;\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t * - Object entries can customize button text while preserving numeric rates.\n\t */\n\tspeedOptions?: TTSSpeedOption[];\n\t/**\n\t * Show a rendered speed group even when there is only one visible option.\n\t * Defaults to false because a one-option radio group has no meaningful choice.\n\t */\n\tshowSingleSpeedOption?: boolean;\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\nconst DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([\n\t{ rate: 0.8, label: \"Slow\", ariaLabel: \"Slow speed\" },\n\t{ rate: 1, label: \"Normal\", ariaLabel: \"Normal speed\", default: true },\n\t{ rate: 1.25, label: \"Fast\", ariaLabel: \"Fast speed\" },\n] satisfies TTSSpeedOptionConfig[]);\n\nconst normalizeSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\tconst rounded = Math.round(entry * 100) / 100;\n\treturn rounded === 1 ? undefined : rounded;\n};\n\nconst normalizeControlSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\treturn Math.round(entry * 100) / 100;\n};\n\nconst trimOptionalText = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst formatSpeedLabel = (rate: number): string => `${rate}x`;\n\nconst formatSpeedAriaLabel = (label: string, usedDefaultLabel: boolean): string =>\n\tlabel.toLowerCase() === \"normal\"\n\t\t? \"Normal speed\"\n\t\t: usedDefaultLabel\n\t\t\t? `Speed ${label}`\n\t\t\t: `${label} speed`;\n\nconst normalizeSpeedAriaLabel = (\n\tlabel: string,\n\tariaLabel: string | undefined,\n\tusedDefaultLabel: boolean,\n): string => {\n\tif (!ariaLabel) return formatSpeedAriaLabel(label, usedDefaultLabel);\n\tif (ariaLabel.toLowerCase().includes(label.toLowerCase())) return ariaLabel;\n\treturn `${label} ${ariaLabel}`;\n};\n\nconst normalizeTTSSpeedOptionConfig = (\n\tentry: unknown,\n): TTSSpeedOption | undefined => {\n\tif (typeof entry === \"number\") return normalizeSpeedRate(entry);\n\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n\tconst record = entry as Record<string, unknown>;\n\tconst rate = normalizeSpeedRate(record.rate);\n\tif (rate === undefined) return undefined;\n\tconst label = trimOptionalText(record.label);\n\tconst ariaLabel = trimOptionalText(record.ariaLabel);\n\treturn {\n\t\trate,\n\t\t...(label ? { label } : {}),\n\t\t...(ariaLabel ? { ariaLabel } : {}),\n\t};\n};\n\nexport const normalizeTTSSpeedOptionConfigs = (\n\tvalue: unknown,\n): TTSSpeedOption[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: TTSSpeedOption[] = [];\n\tfor (const entry of value) {\n\t\tconst option = normalizeTTSSpeedOptionConfig(entry);\n\t\tif (option === undefined) continue;\n\t\tconst rate = typeof option === \"number\" ? option : option.rate;\n\t\tif (dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(option);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\treturn normalizeTTSSpeedOptionConfigs(value).map((option) =>\n\t\ttypeof option === \"number\" ? option : option.rate,\n\t);\n};\n\nexport const normalizeTTSSpeedControlOptions = (\n\tvalue: unknown,\n): NormalizedTTSSpeedOption[] => {\n\tconst input = Array.isArray(value)\n\t\t? value\n\t\t: [...DEFAULT_TTS_SPEED_CONTROL_OPTIONS];\n\tif (input.length === 0) return [];\n\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: Array<NormalizedTTSSpeedOption & { requestedDefault: boolean }> =\n\t\t[];\n\n\tfor (const entry of input) {\n\t\tconst record = toRecord(entry);\n\t\tconst rate =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? normalizeControlSpeedRate(entry)\n\t\t\t\t: normalizeControlSpeedRate(record.rate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\n\t\tconst defaultLabel =\n\t\t\trate === 1 ? \"Normal\" : typeof entry === \"number\" ? formatSpeedLabel(rate) : formatSpeedLabel(rate);\n\t\tconst label =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? defaultLabel\n\t\t\t\t: trimOptionalText(record.label) || defaultLabel;\n\t\tconst ariaLabel =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? rate === 1\n\t\t\t\t\t? \"Normal speed\"\n\t\t\t\t\t: formatSpeedAriaLabel(label, true)\n\t\t\t\t: normalizeSpeedAriaLabel(\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\ttrimOptionalText(record.ariaLabel),\n\t\t\t\t\t\tlabel === defaultLabel,\n\t\t\t\t\t);\n\t\tnormalized.push({\n\t\t\trate,\n\t\t\tlabel,\n\t\t\tariaLabel,\n\t\t\tisDefault: false,\n\t\t\trequestedDefault:\n\t\t\t\trecord.default === true || (record as { isDefault?: unknown }).isDefault === true,\n\t\t});\n\t}\n\n\tif (!normalized.length) {\n\t\treturn normalizeTTSSpeedControlOptions(DEFAULT_TTS_SPEED_CONTROL_OPTIONS);\n\t}\n\n\tif (!dedupedRates.has(1)) {\n\t\tconst normalOption = {\n\t\t\trate: 1,\n\t\t\tlabel: \"Normal\",\n\t\t\tariaLabel: \"Normal speed\",\n\t\t\tisDefault: false,\n\t\t\trequestedDefault: false,\n\t\t};\n\t\tconst firstFasterIndex = normalized.findIndex((option) => option.rate > 1);\n\t\tif (firstFasterIndex >= 0) {\n\t\t\tnormalized.splice(firstFasterIndex, 0, normalOption);\n\t\t} else {\n\t\t\tnormalized.push(normalOption);\n\t\t}\n\t}\n\n\tconst requestedDefaultIndex = normalized.findIndex(\n\t\t(option) => option.requestedDefault,\n\t);\n\tconst defaultIndex =\n\t\trequestedDefaultIndex >= 0\n\t\t\t? requestedDefaultIndex\n\t\t\t: normalized.findIndex((option) => option.rate === 1);\n\n\treturn normalized.map(({ requestedDefault: _requestedDefault, ...option }, index) => ({\n\t\t...option,\n\t\tisDefault: index === defaultIndex,\n\t}));\n};\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\nconst DEFAULT_TTS_SPEED_CONTROL_RATES = Object.freeze([0.8, 1, 1.25]);\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: number[] = [];\n\tfor (const candidate of candidates) {\n\t\tconst rate = normalizeControlSpeedRate(candidate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(rate);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(\n\t\t\t\twithServerDefaults.defaultVoice,\n\t\t\t\t\"en-US-Wavenet-A\",\n\t\t\t),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine\n\t\t\t\t? { engine: config.engine }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format\n\t\t\t\t? { format: config.format }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t\theaderOverlay: {\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t\theaderOverlay: {\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t\theaderOverlay: {\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t\theaderOverlay: {\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
@@ -151,6 +151,9 @@ export const ttsToolRegistration = {
151
151
  reserveSpace: hostLayout.controlsRow.reserveSpace,
152
152
  showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,
153
153
  },
154
+ headerOverlay: {
155
+ showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive,
156
+ },
154
157
  },
155
158
  },
156
159
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedControlOptions,\n\ttype NormalizedTTSSpeedOption,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tsettings.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||\n\t\t\t\t\tundefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): NormalizedTTSSpeedOption[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () =>\n\t\t\tresolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () =>\n\t\t\tresolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected ===\n\t\t\t\t\t\"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\n\t\t\t\t\"catalog-id\",\n\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(\n\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\n\t\t\t\t\t\"catalog-id\",\n\t\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t\t);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedControlOptions,\n\ttype NormalizedTTSSpeedOption,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tsettings.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||\n\t\t\t\t\tundefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): NormalizedTTSSpeedOption[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () =>\n\t\t\tresolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () =>\n\t\t\tresolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected ===\n\t\t\t\t\t\"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\n\t\t\t\t\"catalog-id\",\n\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(\n\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t\theaderOverlay: {\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\n\t\t\t\t\t\"catalog-id\",\n\t\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t\t);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-players/pie-assessment-toolkit",
3
- "version": "0.3.55",
3
+ "version": "0.3.56",
4
4
  "type": "module",
5
5
  "description": "PIE assessment toolkit: composable services + reference implementation for assessment players and tool coordination",
6
6
  "license": "MIT",
@@ -75,15 +75,15 @@
75
75
  "test": "bun test"
76
76
  },
77
77
  "dependencies": {
78
- "@pie-players/pie-calculator": "0.3.55",
79
- "@pie-players/pie-context": "0.3.55",
80
- "@pie-players/pie-players-shared": "0.3.55",
81
- "@pie-players/pie-tts": "0.3.55",
78
+ "@pie-players/pie-calculator": "0.3.56",
79
+ "@pie-players/pie-context": "0.3.56",
80
+ "@pie-players/pie-players-shared": "0.3.56",
81
+ "@pie-players/pie-tts": "0.3.56",
82
82
  "speech-rule-engine": "^5.0.0-rc.1"
83
83
  },
84
84
  "peerDependencies": {
85
- "@pie-players/pie-calculator-desmos": "0.3.55",
86
- "@pie-players/tts-client-server": "0.3.55"
85
+ "@pie-players/pie-calculator-desmos": "0.3.56",
86
+ "@pie-players/tts-client-server": "0.3.56"
87
87
  },
88
88
  "peerDependenciesMeta": {
89
89
  "@pie-players/pie-calculator-desmos": {