@pie-players/pie-assessment-toolkit 0.3.52 → 0.3.54
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.
- package/README.md +12 -5
- package/dist/components/ItemToolBar.custom-element.js +97 -55
- package/dist/components/PieAssessmentToolkit.custom-element.js +103 -57
- package/dist/components/SectionToolBar.custom-element.js +97 -55
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/TTSService.d.ts +2 -0
- package/dist/services/TTSService.js +54 -6
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ToolRegistry.d.ts +11 -0
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/tts-runtime-config.d.ts +8 -1
- package/dist/services/tts-runtime-config.js +87 -18
- package/dist/services/tts-runtime-config.js.map +1 -1
- package/dist/tools/registrations/calculator.js +4 -0
- package/dist/tools/registrations/calculator.js.map +1 -1
- package/dist/tools/registrations/tts.js +7 -3
- package/dist/tools/registrations/tts.js.map +1 -1
- package/package.json +7 -7
|
@@ -92,6 +92,16 @@ export interface ToolWindowShellAction {
|
|
|
92
92
|
* The shell is offset by `initialMargin` (default 16 px) from the chosen corner.
|
|
93
93
|
*/
|
|
94
94
|
export type ToolWindowShellAlign = "center" | "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
95
|
+
export interface ToolWindowShellContentConfig {
|
|
96
|
+
/** Vertical overflow behavior for the hosted content pane. Defaults to "hidden". */
|
|
97
|
+
overflowY?: "hidden" | "auto";
|
|
98
|
+
/**
|
|
99
|
+
* Preserve the content area's configured minimum height when the shell shrinks
|
|
100
|
+
* below `minHeight`, letting the content pane scroll instead of compressing
|
|
101
|
+
* the hosted element.
|
|
102
|
+
*/
|
|
103
|
+
preserveMinHeight?: boolean;
|
|
104
|
+
}
|
|
95
105
|
export interface ToolWindowShellConfig {
|
|
96
106
|
title?: string;
|
|
97
107
|
draggable?: boolean;
|
|
@@ -107,6 +117,7 @@ export interface ToolWindowShellConfig {
|
|
|
107
117
|
initialAlign?: ToolWindowShellAlign;
|
|
108
118
|
/** Distance (px) from the viewport edge when using a corner align. Defaults to 16. */
|
|
109
119
|
initialMargin?: number;
|
|
120
|
+
content?: ToolWindowShellContentConfig;
|
|
110
121
|
actions?: ToolWindowShellAction[];
|
|
111
122
|
}
|
|
112
123
|
export interface HostedToolContext {
|
|
@@ -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 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\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};\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"]}
|
|
@@ -13,12 +13,14 @@ export interface TTSSpeedOptionConfig {
|
|
|
13
13
|
rate: number;
|
|
14
14
|
label?: string;
|
|
15
15
|
ariaLabel?: string;
|
|
16
|
+
default?: boolean;
|
|
16
17
|
}
|
|
17
18
|
export type TTSSpeedOption = number | TTSSpeedOptionConfig;
|
|
18
19
|
export interface NormalizedTTSSpeedOption {
|
|
19
20
|
rate: number;
|
|
20
21
|
label: string;
|
|
21
22
|
ariaLabel: string;
|
|
23
|
+
isDefault: boolean;
|
|
22
24
|
}
|
|
23
25
|
export interface TTSRuntimeSettings {
|
|
24
26
|
backend?: "browser" | "polly" | "google" | "server";
|
|
@@ -49,6 +51,11 @@ export interface TTSRuntimeSettings {
|
|
|
49
51
|
* - Object entries can customize button text while preserving numeric rates.
|
|
50
52
|
*/
|
|
51
53
|
speedOptions?: TTSSpeedOption[];
|
|
54
|
+
/**
|
|
55
|
+
* Show a rendered speed group even when there is only one visible option.
|
|
56
|
+
* Defaults to false because a one-option radio group has no meaningful choice.
|
|
57
|
+
*/
|
|
58
|
+
showSingleSpeedOption?: boolean;
|
|
52
59
|
layoutMode?: TTSLayoutMode;
|
|
53
60
|
/**
|
|
54
61
|
* Per-token highlighting of math expressions.
|
|
@@ -67,7 +74,7 @@ export interface TTSRuntimeSettings {
|
|
|
67
74
|
mathSpeech?: SREMathSpeechOptions;
|
|
68
75
|
}
|
|
69
76
|
export declare const normalizeTTSLayoutMode: (value: unknown, fallback?: TTSLayoutMode) => TTSLayoutMode;
|
|
70
|
-
/**
|
|
77
|
+
/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */
|
|
71
78
|
export declare const DEFAULT_TTS_SPEED_OPTIONS: readonly number[];
|
|
72
79
|
export declare const normalizeTTSSpeedOptionConfigs: (value: unknown) => TTSSpeedOption[];
|
|
73
80
|
/**
|
|
@@ -12,8 +12,13 @@ export const normalizeTTSLayoutMode = (value, fallback = "left-aligned") => type
|
|
|
12
12
|
VALID_TTS_LAYOUT_MODES.has(value)
|
|
13
13
|
? value
|
|
14
14
|
: fallback;
|
|
15
|
-
/**
|
|
15
|
+
/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */
|
|
16
16
|
export const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);
|
|
17
|
+
const DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([
|
|
18
|
+
{ rate: 0.8, label: "Slow", ariaLabel: "Slow speed" },
|
|
19
|
+
{ rate: 1, label: "Normal", ariaLabel: "Normal speed", default: true },
|
|
20
|
+
{ rate: 1.25, label: "Fast", ariaLabel: "Fast speed" },
|
|
21
|
+
]);
|
|
17
22
|
const normalizeSpeedRate = (entry) => {
|
|
18
23
|
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
19
24
|
return undefined;
|
|
@@ -21,6 +26,12 @@ const normalizeSpeedRate = (entry) => {
|
|
|
21
26
|
const rounded = Math.round(entry * 100) / 100;
|
|
22
27
|
return rounded === 1 ? undefined : rounded;
|
|
23
28
|
};
|
|
29
|
+
const normalizeControlSpeedRate = (entry) => {
|
|
30
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return Math.round(entry * 100) / 100;
|
|
34
|
+
};
|
|
24
35
|
const trimOptionalText = (value) => {
|
|
25
36
|
if (typeof value !== "string")
|
|
26
37
|
return undefined;
|
|
@@ -28,7 +39,11 @@ const trimOptionalText = (value) => {
|
|
|
28
39
|
return trimmed.length ? trimmed : undefined;
|
|
29
40
|
};
|
|
30
41
|
const formatSpeedLabel = (rate) => `${rate}x`;
|
|
31
|
-
const formatSpeedAriaLabel = (label, usedDefaultLabel) =>
|
|
42
|
+
const formatSpeedAriaLabel = (label, usedDefaultLabel) => label.toLowerCase() === "normal"
|
|
43
|
+
? "Normal speed"
|
|
44
|
+
: usedDefaultLabel
|
|
45
|
+
? `Speed ${label}`
|
|
46
|
+
: `${label} speed`;
|
|
32
47
|
const normalizeSpeedAriaLabel = (label, ariaLabel, usedDefaultLabel) => {
|
|
33
48
|
if (!ariaLabel)
|
|
34
49
|
return formatSpeedAriaLabel(label, usedDefaultLabel);
|
|
@@ -86,24 +101,69 @@ export const normalizeTTSSpeedOptions = (value) => {
|
|
|
86
101
|
return [];
|
|
87
102
|
return normalizeTTSSpeedOptionConfigs(value).map((option) => typeof option === "number" ? option : option.rate);
|
|
88
103
|
};
|
|
89
|
-
export const normalizeTTSSpeedControlOptions = (value) =>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
export const normalizeTTSSpeedControlOptions = (value) => {
|
|
105
|
+
const input = Array.isArray(value)
|
|
106
|
+
? value
|
|
107
|
+
: [...DEFAULT_TTS_SPEED_CONTROL_OPTIONS];
|
|
108
|
+
if (input.length === 0)
|
|
109
|
+
return [];
|
|
110
|
+
const dedupedRates = new Set();
|
|
111
|
+
const normalized = [];
|
|
112
|
+
for (const entry of input) {
|
|
113
|
+
const record = toRecord(entry);
|
|
114
|
+
const rate = typeof entry === "number"
|
|
115
|
+
? normalizeControlSpeedRate(entry)
|
|
116
|
+
: normalizeControlSpeedRate(record.rate);
|
|
117
|
+
if (rate === undefined || dedupedRates.has(rate))
|
|
118
|
+
continue;
|
|
119
|
+
dedupedRates.add(rate);
|
|
120
|
+
const defaultLabel = rate === 1 ? "Normal" : typeof entry === "number" ? formatSpeedLabel(rate) : formatSpeedLabel(rate);
|
|
121
|
+
const label = typeof entry === "number"
|
|
122
|
+
? defaultLabel
|
|
123
|
+
: trimOptionalText(record.label) || defaultLabel;
|
|
124
|
+
const ariaLabel = typeof entry === "number"
|
|
125
|
+
? rate === 1
|
|
126
|
+
? "Normal speed"
|
|
127
|
+
: formatSpeedAriaLabel(label, true)
|
|
128
|
+
: normalizeSpeedAriaLabel(label, trimOptionalText(record.ariaLabel), label === defaultLabel);
|
|
129
|
+
normalized.push({
|
|
130
|
+
rate,
|
|
94
131
|
label,
|
|
95
|
-
ariaLabel
|
|
132
|
+
ariaLabel,
|
|
133
|
+
isDefault: false,
|
|
134
|
+
requestedDefault: record.default === true || record.isDefault === true,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (!normalized.length) {
|
|
138
|
+
return normalizeTTSSpeedControlOptions(DEFAULT_TTS_SPEED_CONTROL_OPTIONS);
|
|
139
|
+
}
|
|
140
|
+
if (!dedupedRates.has(1)) {
|
|
141
|
+
const normalOption = {
|
|
142
|
+
rate: 1,
|
|
143
|
+
label: "Normal",
|
|
144
|
+
ariaLabel: "Normal speed",
|
|
145
|
+
isDefault: false,
|
|
146
|
+
requestedDefault: false,
|
|
96
147
|
};
|
|
148
|
+
const firstFasterIndex = normalized.findIndex((option) => option.rate > 1);
|
|
149
|
+
if (firstFasterIndex >= 0) {
|
|
150
|
+
normalized.splice(firstFasterIndex, 0, normalOption);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
normalized.push(normalOption);
|
|
154
|
+
}
|
|
97
155
|
}
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
156
|
+
const requestedDefaultIndex = normalized.findIndex((option) => option.requestedDefault);
|
|
157
|
+
const defaultIndex = requestedDefaultIndex >= 0
|
|
158
|
+
? requestedDefaultIndex
|
|
159
|
+
: normalized.findIndex((option) => option.rate === 1);
|
|
160
|
+
return normalized.map(({ requestedDefault: _requestedDefault, ...option }, index) => ({
|
|
161
|
+
...option,
|
|
162
|
+
isDefault: index === defaultIndex,
|
|
163
|
+
}));
|
|
164
|
+
};
|
|
106
165
|
export const formatTTSSpeedOptionsAsText = (values) => values.join(", ");
|
|
166
|
+
const DEFAULT_TTS_SPEED_CONTROL_RATES = Object.freeze([0.8, 1, 1.25]);
|
|
107
167
|
/**
|
|
108
168
|
* Parse comma/semicolon-separated multipliers from settings UI text.
|
|
109
169
|
* - Empty or whitespace-only string → hide speed buttons (`[]`).
|
|
@@ -121,8 +181,17 @@ export const parseTTSSpeedOptionsFromText = (text) => {
|
|
|
121
181
|
.map((p) => Number.parseFloat(p))
|
|
122
182
|
.filter((n) => Number.isFinite(n));
|
|
123
183
|
if (!candidates.length)
|
|
124
|
-
return [...
|
|
125
|
-
|
|
184
|
+
return [...DEFAULT_TTS_SPEED_CONTROL_RATES];
|
|
185
|
+
const dedupedRates = new Set();
|
|
186
|
+
const normalized = [];
|
|
187
|
+
for (const candidate of candidates) {
|
|
188
|
+
const rate = normalizeControlSpeedRate(candidate);
|
|
189
|
+
if (rate === undefined || dedupedRates.has(rate))
|
|
190
|
+
continue;
|
|
191
|
+
dedupedRates.add(rate);
|
|
192
|
+
normalized.push(rate);
|
|
193
|
+
}
|
|
194
|
+
return normalized.length ? normalized : [...DEFAULT_TTS_SPEED_CONTROL_RATES];
|
|
126
195
|
};
|
|
127
196
|
const applyRuntimeDefaults = (config) => {
|
|
128
197
|
const withLayoutDefaults = {
|
|
@@ -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}\n\nexport type TTSSpeedOption = number | TTSSpeedOptionConfig;\n\nexport interface NormalizedTTSSpeedOption {\n\trate: number;\n\tlabel: string;\n\tariaLabel: string;\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\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/** Default inline TTS speed button multipliers (excluding 1.0×). */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\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 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\tusedDefaultLabel ? `Speed ${label}` : `${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\tnormalizeTTSSpeedOptionConfigs(value).map((option) => {\n\t\tif (typeof option === \"number\") {\n\t\t\tconst label = formatSpeedLabel(option);\n\t\t\treturn {\n\t\t\t\trate: option,\n\t\t\t\tlabel,\n\t\t\t\tariaLabel: formatSpeedAriaLabel(label, true),\n\t\t\t};\n\t\t}\n\t\tconst defaultLabel = formatSpeedLabel(option.rate);\n\t\tconst label = option.label || defaultLabel;\n\t\treturn {\n\t\t\trate: option.rate,\n\t\t\tlabel,\n\t\t\tariaLabel: normalizeSpeedAriaLabel(\n\t\t\t\tlabel,\n\t\t\t\toption.ariaLabel,\n\t\t\t\tlabel === defaultLabel,\n\t\t\t),\n\t\t};\n\t});\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\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_OPTIONS];\n\treturn normalizeTTSSpeedOptions(candidates);\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}\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAIvD,4EAA4E;AAC5E,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,2EAA2E;AAC3E,8DAA8D;AAC9D,MAAM,mBAAmB,GAAG,IAAI,OAAO,EAGpC,CAAC;AAEJ,SAAS,gBAAgB,CACxB,WAAsC,EACtC,UAAkB;IAElB,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC1B,oEAAoE;IACpE,uEAAuE;IACvE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CACxB,WAAsC,EACtC,UAAkB,EAClB,OAAoB;IAEpB,IAAI,CAAC,WAAW;QAAE,OAAO;IACzB,IAAI,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACnB,mBAAmB,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC9C,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC;AAED,SAAS,yBAAyB,CAAC,cAA8B;IAKhE,MAAM,MAAM,GAAG,cAAc,CAAC,mBAAmB,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;IACxE,MAAM,cAAc,GAAG,uBAAuB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,CAAC;IAChD,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,iBAAiB,CAAC;QACtD,CAAC,CAAC,iBAAiB;aAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC;aAC9C,MAAM,CAAC,CAAC,KAAK,EAA2B,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC;QAC7D,CAAC,CAAC,cAAc;YACf,CAAC,CAAC,CAAC,cAAc,CAAC;YAClB,CAAC,CAAC,IAAI,CAAC;IAET,OAAO;QACN,cAAc;QACd,cAAc;QACd,WAAW,EACV,cAAc,KAAK,YAAY;YAC9B,CAAC,CAAC,uBAAuB;YACzB,CAAC,CAAC,cAAc,KAAK,OAAO;gBAC3B,CAAC,CAAC,kBAAkB;gBACpB,CAAC,CAAC,YAAY;KACjB,CAAC;AACH,CAAC;AAED,SAAS,8BAA8B,CACtC,OAAoB,EACpB,cAAqC,EACrC,cAAuC;IAEvC,MAAM,iBAAiB,GAAG,OAGzB,CAAC;IAEF,IAAI,cAAc,EAAE,CAAC;QACpB,iBAAiB,CAAC,cAAc,GAAG,cAAc,CAAC;QAClD,OAAO,CAAC,YAAY,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACP,OAAO,iBAAiB,CAAC,cAAc,CAAC;QACxC,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,iBAAiB,CAAC,cAAc,GAAG,cAAc,CAAC;IACnD,CAAC;SAAM,CAAC;QACP,OAAO,iBAAiB,CAAC,cAAc,CAAC;IACzC,CAAC;AACF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAqB;IAC3D,MAAM,EAAE,YAAY;IACpB,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,qDAAqD;IAClE,IAAI,EAAE,YAAY;IAClB,QAAQ,EAAE;QACT,aAAa,EAAE,CAAC,MAAsC,EAAE,EAAE,CACzD,OAAO,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;YACxE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;YACpB,CAAC,CAAC,mBAAmB;QACvB,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,kBAAkB,EAAE;QAC9C,aAAa,EAAE,CAAC,MAAsC,EAAE,EAAE,CACzD,MAAM,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE;QAC7B,cAAc,EAAE,CAAC,MAAsC,EAAE,EAAE;YAC1D,MAAM,kBAAkB,GAAG,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC;YAClE,IAAI,OAAO,kBAAkB,KAAK,UAAU;gBAAE,OAAO,kBAAkB,CAAC;YACxE,OAAO,KAAK,IAAI,EAAE;gBACjB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,wBAAwB,EAAE;oBACtD,MAAM,EAAE,KAAK;oBACb,WAAW,EAAE,aAAa;iBAC1B,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;oBAClB,MAAM,IAAI,KAAK,CACd,uCAAuC,QAAQ,CAAC,MAAM,GAAG,CACzD,CAAC;gBACH,CAAC;gBACD,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC3D,CAAC,CAAC;QACH,CAAC;QACD,IAAI,EAAE,IAAI;KACV;IAED,wDAAwD;IACxD,eAAe,EAAE,CAAC,MAAM,CAAC;IAEzB,wCAAwC;IACxC,oEAAoE;IACpE,aAAa,EAAE;QACd,YAAY,EAAE,0CAA0C;QACxD,oBAAoB,EAAE,mDAAmD;QACzE,iBAAiB,EAAE,iBAAiB;QACpC,sBAAsB,EAAE,iBAAiB;KACzC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,OAAoB;QACtC,kDAAkD;QAClD,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,aAAa,CACZ,OAAoB,EACpB,cAA8B;QAE9B,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,GACpD,yBAAyB,CAAC,cAAc,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,kBAAkB,CACpC,IAAI,CAAC,MAAM,EACX,cAAc,CAAC,KAAK,CAAC,KAAK,EAC1B,cAAc,CAAC,KAAK,CAAC,OAAO,CAC5B,CAAC;QACF,MAAM,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;QAC7D,MAAM,aAAa,GAAG,gBAAgB,CACrC,cAAc,CAAC,eAAe,EAC9B,UAAU,CACV,CAAC;QACF,MAAM,OAAO,GAAG,CAAC,aAAa;YAC7B,iBAAiB,CAChB,IAAI,CAAC,MAAM,EACX,OAAO,EACP,cAAc,EACd,kBAAkB,CAClB,CAID,CAAC;QACF,IAAI,CAAC,aAAa,EAAE,CAAC;YACpB,gBAAgB,CAAC,cAAc,CAAC,eAAe,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAC5C,OAAO,CAAC,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;QAC/D,8BAA8B,CAAC,OAAO,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;QACxE,MAAM,SAAS,GACd,cAAc,KAAK,IAAI;YACtB,CAAC,CAAC,4BAA4B;YAC9B,CAAC,CAAC,QAAQ,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC;QACxC,MAAM,UAAU,GACf,cAAc,KAAK,IAAI;YACtB,CAAC,CAAC,6BAA6B;YAC/B,CAAC,CAAC,SAAS,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC;QACzC,MAAM,MAAM,GAAgC;YAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACtE,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,SAAS;YACpB,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YACrD,MAAM,EAAE,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC;SAChD,CAAC;QACF,IAAI,gBAAgB,GAAwB,MAAM,CAAC,MAAM,CAAC;QAC1D,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;YACvC,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,CAAC;QAED,OAAO;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE;gBACT;oBACC,OAAO,EAAE,OAAO;oBAChB,KAAK,EAAE,eAAe;oBACtB,KAAK,EAAE;wBACN,KAAK,EAAE,IAAI,CAAC,IAAI;wBAChB,SAAS,EAAE,IAAI;wBACf,SAAS,EAAE,IAAI;wBACf,SAAS,EAAE,IAAI;wBACf,YAAY,EAAE,GAAG;wBACjB,aAAa,EAAE,GAAG;wBAClB,QAAQ,EAAE,GAAG;wBACb,SAAS,EAAE,GAAG;wBACd,YAAY,EAAE,cAAc;wBAC5B,aAAa,EAAE,EAAE;qBACjB;iBACD;aACD;YACD,MAAM;YACN,IAAI,EAAE,GAAG,EAAE;gBACV,MAAM,MAAM,GAAG,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;gBACxD,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;gBACvB,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;gBAC3B,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;gBACnD,MAAM,CAAC,OAAO,GAAG,MAAM;oBACtB,CAAC,CAAC,SAAS,WAAW,CAAC,WAAW,EAAE,EAAE;oBACtC,CAAC,CAAC,WAAW,CAAC;gBACf,IAAI,gBAAgB,KAAK,MAAM,EAAE,CAAC;oBACjC,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC;oBACzB,gBAAgB,GAAG,MAAM,CAAC;gBAC3B,CAAC;gBACD,IAAI,OAAO,CAAC,kBAAkB,KAAK,cAAc,CAAC,kBAAkB,EAAE,CAAC;oBACtE,OAAO,CAAC,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;gBAChE,CAAC;gBACD,8BAA8B,CAAC,OAAO,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;YACzE,CAAC;YACD,eAAe,EAAE,CAAC,QAAmC,EAAE,EAAE;gBACxD,IAAI,CAAC,cAAc,CAAC,mBAAmB;oBAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;gBACzD,OAAO,cAAc,CAAC,mBAAmB,CAAC,GAAG,EAAE;oBAC9C,QAAQ,CAAC,cAAc,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;gBACpD,CAAC,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\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 componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: \"bottom-right\",\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\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 componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: \"bottom-right\",\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\toverflowY: \"auto\",\n\t\t\t\t\t\t\tpreserveMinHeight: true,\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\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|