@pie-players/pie-assessment-toolkit 0.3.75 → 1.0.0-beta.1
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 +451 -541
- package/custom-elements.json +1315 -0
- package/dist/attempt/TestSession.d.ts +0 -1
- package/dist/attempt/TestSession.js +10 -5
- package/dist/components/ItemScope.custom-element.js +1 -1
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +8 -8
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/{ItemToolBar-7tt7v2xp.js → ItemToolBar-3zrc4p3d.js} +4 -4
- package/dist/components/chunks/{ItemToolBar-jx38w99s.js → ItemToolBar-66hcwmfw.js} +2 -2
- package/dist/components/chunks/ItemToolBar-asenkvx6.js +40 -0
- package/dist/components/chunks/ItemToolBar-hzc5wyjp.js +2 -0
- package/dist/components/chunks/{ItemToolBar-97hx60z4.js → ItemToolBar-kkj69ptr.js} +1 -1
- package/dist/components/chunks/sre-engine-bj997w4b.js +1 -0
- package/dist/context/assessment-toolkit-context.d.ts +6 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -10
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +46 -7
- package/dist/policy/core/ToolPolicyEngine.js +73 -16
- package/dist/policy/core/compose-decision.d.ts +3 -3
- package/dist/policy/core/compose-decision.js +32 -30
- package/dist/policy/core/decision-types.d.ts +51 -34
- package/dist/policy/core/feature-decision.d.ts +17 -15
- package/dist/policy/core/feature-decision.js +11 -13
- package/dist/policy/core/pnp-policy-inputs.d.ts +7 -3
- package/dist/policy/core/pnp-policy-inputs.js +17 -33
- package/dist/policy/core/provenance.d.ts +2 -2
- package/dist/policy/core/tool-parameters.d.ts +12 -0
- package/dist/policy/core/tool-parameters.js +27 -0
- package/dist/policy/engine.d.ts +1 -1
- package/dist/policy/sources/PnpPolicySource.d.ts +18 -24
- package/dist/policy/sources/PnpPolicySource.js +57 -29
- package/dist/runtime/SectionControllerBinding.d.ts +6 -2
- package/dist/runtime/SectionControllerBinding.js +21 -15
- package/dist/runtime/adapter/subscriber-fanout.d.ts +0 -1
- package/dist/runtime/adapter/subscriber-fanout.js +1 -4
- package/dist/runtime/composition-emit-scheduler.d.ts +3 -3
- package/dist/runtime/composition-emit-scheduler.js +1 -1
- package/dist/runtime/content-region.d.ts +0 -4
- package/dist/runtime/content-region.js +2 -2
- package/dist/runtime/core/SectionEngineCore.d.ts +0 -2
- package/dist/runtime/core/SectionEngineCore.js +0 -4
- package/dist/runtime/core/cohort.d.ts +0 -5
- package/dist/runtime/core/cohort.js +0 -9
- package/dist/runtime/core/engine-output.d.ts +3 -2
- package/dist/runtime/core/engine-transition.js +3 -2
- package/dist/runtime/registration-events.d.ts +11 -14
- package/dist/runtime/runtime-id.d.ts +1 -1
- package/dist/runtime/runtime-id.js +1 -1
- package/dist/runtime/shell-scope.d.ts +4 -4
- package/dist/runtime/shell-scope.js +15 -9
- package/dist/runtime/tool-host-contract.d.ts +0 -4
- package/dist/runtime/tool-host-contract.js +1 -1
- package/dist/services/AccessibilityCatalogResolver.d.ts +21 -31
- package/dist/services/AccessibilityCatalogResolver.js +29 -42
- package/dist/services/ElementToolStateStore.d.ts +32 -61
- package/dist/services/ElementToolStateStore.js +37 -67
- package/dist/services/HighlightCoordinator.d.ts +9 -21
- package/dist/services/HighlightCoordinator.js +52 -80
- package/dist/services/RangeSerializer.d.ts +4 -35
- package/dist/services/RangeSerializer.js +4 -48
- package/dist/services/SSMLExtractor.d.ts +8 -31
- package/dist/services/SSMLExtractor.js +18 -40
- package/dist/services/TTSService.d.ts +51 -57
- package/dist/services/TTSService.js +323 -284
- package/dist/services/ToolCoordinator.d.ts +6 -49
- package/dist/services/ToolCoordinator.js +25 -61
- package/dist/services/ToolRegistry.d.ts +83 -80
- package/dist/services/ToolRegistry.js +91 -67
- package/dist/services/ToolkitCoordinator.d.ts +83 -81
- package/dist/services/ToolkitCoordinator.js +186 -174
- package/dist/services/framework-error.d.ts +30 -7
- package/dist/services/framework-error.js +10 -13
- package/dist/services/interfaces.d.ts +51 -71
- package/dist/services/section-controller-types.d.ts +7 -7
- package/dist/services/section-session-assignment.js +6 -8
- package/dist/services/spoken-audio-cards.d.ts +2 -4
- package/dist/services/spoken-audio-cards.js +2 -4
- package/dist/services/tool-config-validation.d.ts +5 -7
- package/dist/services/tool-config-validation.js +11 -26
- package/dist/services/tool-context.d.ts +39 -24
- package/dist/services/tool-context.js +158 -92
- package/dist/services/tool-failure.d.ts +30 -0
- package/dist/services/tool-failure.js +11 -0
- package/dist/services/tool-icons.d.ts +1 -2
- package/dist/services/tool-icons.js +2 -2
- package/dist/services/tool-instance-id.d.ts +8 -6
- package/dist/services/tool-instance-id.js +12 -18
- package/dist/services/tool-providers/TTSToolProvider.d.ts +6 -43
- package/dist/services/tool-providers/TTSToolProvider.js +7 -63
- package/dist/services/tool-providers/ToolProviderApi.d.ts +0 -7
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +7 -42
- package/dist/services/tool-providers/ToolProviderRegistry.js +21 -63
- package/dist/services/tool-request.d.ts +4 -0
- package/dist/services/tool-request.js +7 -2
- package/dist/services/toolbar-decided-tools.d.ts +2 -0
- package/dist/services/toolbar-decided-tools.js +2 -0
- package/dist/services/toolbar-items.js +2 -5
- package/dist/services/tools-config-normalizer.d.ts +18 -9
- package/dist/services/tools-config-normalizer.js +25 -19
- package/dist/services/tts/browser-provider.d.ts +2 -5
- package/dist/services/tts/browser-provider.js +13 -22
- package/dist/services/tts/catalog-span-alignment.js +14 -7
- package/dist/services/tts/flat-tree.d.ts +0 -7
- package/dist/services/tts/flat-tree.js +2 -2
- package/dist/services/tts/generated-speech/dom/to-chunk-inputs.d.ts +2 -2
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/types.d.ts +1 -1
- package/dist/services/tts/generated-speech/types.js +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +10 -12
- package/dist/services/tts/highlight-target-resolver.d.ts +12 -0
- package/dist/services/tts/math-aware-text-processing.js +10 -29
- package/dist/services/tts/math-speech.d.ts +1 -1
- package/dist/services/tts/math-speech.js +3 -0
- package/dist/services/tts/mathml-sanitization.d.ts +7 -0
- package/dist/services/tts/mathml-sanitization.js +9 -1
- package/dist/services/tts/provider-options.d.ts +12 -1
- package/dist/services/tts/ssml/spoken-text.js +1 -1
- package/dist/services/tts/start-failure.d.ts +0 -7
- package/dist/services/tts/start-failure.js +1 -1
- package/dist/services/tts/text-segmentation.d.ts +5 -0
- package/dist/services/tts/text-segmentation.js +13 -10
- package/dist/services/tts-runtime-config.d.ts +32 -12
- package/dist/services/tts-runtime-config.js +14 -20
- package/dist/tools/content-capability-resolution.d.ts +2 -2
- package/dist/tools/registration.d.ts +7 -6
- package/dist/tools/registration.js +10 -9
- package/dist/tools/registrations/toolbar-registration-helpers.d.ts +6 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +6 -0
- package/dist/tools/tool-surface-host.js +1 -8
- package/package.json +8 -6
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +0 -2
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +0 -40
- package/dist/components/chunks/sre-engine-jd8cc08x.js +0 -1
- package/dist/services/ContextVariableStore.d.ts +0 -113
- package/dist/services/ContextVariableStore.js +0 -206
- package/dist/services/tts-control-events.d.ts +0 -13
- package/dist/services/tts-control-events.js +0 -7
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.js +0 -10
|
@@ -7,7 +7,11 @@ import type { BoundarySpacingMode } from "./text-processing.js";
|
|
|
7
7
|
* each value at runtime.
|
|
8
8
|
*/
|
|
9
9
|
export interface ToolkitTTSProviderOptions extends TTSProviderOptions {
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Highlight words or sentences while reading. Defaults by provider
|
|
12
|
+
* capability. A playback that sends no word boundaries highlights its
|
|
13
|
+
* sentence in either mode.
|
|
14
|
+
*/
|
|
11
15
|
highlightMode?: "word" | "sentence";
|
|
12
16
|
/** Locale for text processing; the toolkit sets it per speak. */
|
|
13
17
|
locale?: string;
|
|
@@ -38,4 +42,11 @@ export interface ToolkitTTSProviderOptions extends TTSProviderOptions {
|
|
|
38
42
|
/** A provider configuration as the toolkit reads it. */
|
|
39
43
|
export interface ToolkitTTSConfig extends TTSConfig {
|
|
40
44
|
providerOptions?: ToolkitTTSProviderOptions;
|
|
45
|
+
/**
|
|
46
|
+
* Highlight math token by token; `false` highlights each formula as one
|
|
47
|
+
* block. The highlight pipeline reads it, and providers ignore it.
|
|
48
|
+
*
|
|
49
|
+
* @default true
|
|
50
|
+
*/
|
|
51
|
+
mathTokenHighlighting?: boolean;
|
|
41
52
|
}
|
|
@@ -8,7 +8,7 @@ import { normalizeTextForSpeech } from "../text-processing.js";
|
|
|
8
8
|
* stripping used by:
|
|
9
9
|
* - the catalog span aligner (`catalog-span-alignment.ts`),
|
|
10
10
|
* - the math speech tokenizer (`math-alignment/speech-tokenizer.ts`),
|
|
11
|
-
* - the runtime generated-speech path
|
|
11
|
+
* - the runtime generated-speech path.
|
|
12
12
|
*
|
|
13
13
|
* Keeping one implementation guarantees provider word-boundary offsets (which
|
|
14
14
|
* are into the raw SSML string) map to the same spoken text on every path.
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `code` a speak's rejection carries when speech could not start, as
|
|
3
|
-
* distinct from a failure while speaking. Read by shape: several copies of the
|
|
4
|
-
* toolkit can share a page, so an error class from one fails `instanceof` in
|
|
5
|
-
* another.
|
|
6
|
-
*/
|
|
7
|
-
export declare const TTS_START_FAILED_CODE = "tts-start-failed";
|
|
8
1
|
/** Whether a speak rejected because speech could not start. */
|
|
9
2
|
export declare function isTTSStartFailure(error: unknown): boolean;
|
|
10
3
|
/** Marks `cause` as a start failure, keeping its message and stack. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* toolkit can share a page, so an error class from one fails `instanceof` in
|
|
5
5
|
* another.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
const TTS_START_FAILED_CODE = "tts-start-failed";
|
|
8
8
|
/** Whether a speak rejected because speech could not start. */
|
|
9
9
|
export function isTTSStartFailure(error) {
|
|
10
10
|
return (typeof error === "object" &&
|
|
@@ -6,6 +6,11 @@ export interface SentenceSegmentationOptions {
|
|
|
6
6
|
locale?: string;
|
|
7
7
|
useSentenceSegmenter?: boolean;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* `text` split into sentences at their offsets in it, by Intl.Segmenter unless
|
|
11
|
+
* the policy disables it or it is missing. The segmenter path drops
|
|
12
|
+
* whitespace-only segments; the regex fallback keeps every match.
|
|
13
|
+
*/
|
|
9
14
|
export declare const segmentSentences: (text: string, options?: SentenceSegmentationOptions) => SentenceSegment[];
|
|
10
15
|
/**
|
|
11
16
|
* `text` in pieces of at most `maxLength` characters: whole sentences while they
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `text` split into sentences at their offsets in it, by Intl.Segmenter unless
|
|
3
|
+
* the policy disables it or it is missing. The segmenter path drops
|
|
4
|
+
* whitespace-only segments; the regex fallback keeps every match.
|
|
5
|
+
*/
|
|
1
6
|
export const segmentSentences = (text, options) => {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const Segmenter = globalThis.Intl?.Segmenter;
|
|
8
|
-
if (typeof Segmenter === "function") {
|
|
7
|
+
const Segmenter = options?.useSentenceSegmenter === false
|
|
8
|
+
? undefined
|
|
9
|
+
: globalThis.Intl?.Segmenter;
|
|
10
|
+
if (typeof Segmenter === "function") {
|
|
11
|
+
try {
|
|
9
12
|
const segmenter = new Segmenter(options?.locale, {
|
|
10
13
|
granularity: "sentence",
|
|
11
14
|
});
|
|
@@ -18,9 +21,9 @@ export const segmentSentences = (text, options) => {
|
|
|
18
21
|
if (parsed.length > 0)
|
|
19
22
|
return parsed;
|
|
20
23
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
catch {
|
|
25
|
+
// Fall through to regex segmentation.
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
const sentenceRegex = /[^.!?]+(?:[.!?]+|$)/g;
|
|
26
29
|
const raw = text.match(sentenceRegex) || [text];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SpeedRateBucket } from "@pie-players/pie-tts";
|
|
2
2
|
import type { TextToSpeechToolProviderConfig, ToolProviderConfig } from "./tools-config-normalizer.js";
|
|
3
3
|
import { type SREMathSpeechOptions } from "./tts/math-speech.js";
|
|
4
|
+
import type { ToolkitTTSConfig } from "./tts/provider-options.js";
|
|
4
5
|
export type TTSLayoutMode = "reserved-row" | "expanding-row" | "floating-overlay" | "left-aligned";
|
|
5
6
|
export interface TTSHostToolbarLayout {
|
|
6
|
-
mount: "before-buttons";
|
|
7
7
|
controlsRow: {
|
|
8
8
|
reserveSpace: boolean;
|
|
9
9
|
expandWhenToolActive: boolean;
|
|
@@ -50,6 +50,11 @@ export interface TTSRuntimeSettings {
|
|
|
50
50
|
language?: string;
|
|
51
51
|
transportMode?: "pie" | "custom";
|
|
52
52
|
endpointMode?: "synthesizePath" | "rootPost";
|
|
53
|
+
/**
|
|
54
|
+
* The probe the server provider runs before it reports ready: `voices` reads
|
|
55
|
+
* the voices route, `endpoint` sends OPTIONS to the synthesis route, `none`
|
|
56
|
+
* probes nothing. Defaults to `voices` on a `server` backend.
|
|
57
|
+
*/
|
|
53
58
|
endpointValidationMode?: "voices" | "endpoint" | "none";
|
|
54
59
|
includeAuthOnAssetFetch?: boolean;
|
|
55
60
|
/** Origins trusted with the `Authorization` header on asset fetches. */
|
|
@@ -58,9 +63,13 @@ export interface TTSRuntimeSettings {
|
|
|
58
63
|
credentials?: "omit" | "same-origin" | "include";
|
|
59
64
|
/** Headers sent with every request to the TTS server. */
|
|
60
65
|
headers?: Record<string, string>;
|
|
61
|
-
|
|
66
|
+
/** Server-side caching, sent on the `custom` transport. */
|
|
62
67
|
cache?: boolean;
|
|
63
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Speed bucket sent on the `custom` transport; derived from `rate` when
|
|
70
|
+
* unset.
|
|
71
|
+
*/
|
|
72
|
+
speedRate?: SpeedRateBucket;
|
|
64
73
|
/**
|
|
65
74
|
* The custom transport's locale, sent on every read in place of the content
|
|
66
75
|
* language. Where markup and the tool name no language it is also the read's
|
|
@@ -100,10 +109,16 @@ export interface TTSRuntimeSettings {
|
|
|
100
109
|
/**
|
|
101
110
|
* Options passed through to the provider. The fields derived from the
|
|
102
111
|
* settings above, such as `locale` and the Polly engine, win over these.
|
|
112
|
+
* The `custom` transport reads the three typed keys; the settings of the
|
|
113
|
+
* same names win over them.
|
|
103
114
|
*/
|
|
104
|
-
providerOptions?:
|
|
115
|
+
providerOptions?: {
|
|
116
|
+
speedRate?: SpeedRateBucket;
|
|
117
|
+
lang_id?: string;
|
|
118
|
+
cache?: boolean;
|
|
119
|
+
[option: string]: unknown;
|
|
120
|
+
};
|
|
105
121
|
}
|
|
106
|
-
export declare const normalizeTTSLayoutMode: (value: unknown, fallback?: TTSLayoutMode) => TTSLayoutMode;
|
|
107
122
|
export declare const normalizeTTSSpeedControlOptions: (value: unknown) => NormalizedTTSSpeedOption[];
|
|
108
123
|
export declare const formatTTSSpeedOptionsAsText: (values: number[]) => string;
|
|
109
124
|
/**
|
|
@@ -114,18 +129,23 @@ export declare const formatTTSSpeedOptionsAsText: (values: number[]) => string;
|
|
|
114
129
|
export declare const parseTTSSpeedOptionsFromText: (text: string) => number[];
|
|
115
130
|
/**
|
|
116
131
|
* The runtime settings of a `textToSpeech` provider entry: its top-level keys
|
|
117
|
-
* with defaults applied
|
|
118
|
-
* the
|
|
132
|
+
* with defaults applied, an unknown `layoutMode` resolved to `left-aligned`.
|
|
133
|
+
* `enabled` and the runtime `provider` object belong to the tool registration
|
|
134
|
+
* and are dropped.
|
|
119
135
|
*/
|
|
120
|
-
export declare const resolveTTSRuntimeSettings: (config: TextToSpeechToolProviderConfig | ToolProviderConfig | TTSRuntimeSettings | undefined) => TTSRuntimeSettings
|
|
136
|
+
export declare const resolveTTSRuntimeSettings: (config: TextToSpeechToolProviderConfig | ToolProviderConfig | TTSRuntimeSettings | undefined) => TTSRuntimeSettings & {
|
|
137
|
+
layoutMode: TTSLayoutMode;
|
|
138
|
+
};
|
|
121
139
|
export declare const resolveTTSBackend: (config: TTSRuntimeSettings) => NonNullable<TTSRuntimeSettings["backend"]>;
|
|
122
140
|
/**
|
|
123
141
|
* The provider configuration built from host settings: the contract's portable
|
|
124
142
|
* fields plus the server adapter's, under the adapter's names.
|
|
125
143
|
*/
|
|
126
|
-
export type RuntimeTTSConfig = Pick<
|
|
144
|
+
export type RuntimeTTSConfig = Pick<ToolkitTTSConfig, "voice" | "rate" | "pitch" | "providerOptions" | "mathTokenHighlighting"> & Pick<TTSRuntimeSettings, "apiEndpoint" | "language" | "transportMode" | "endpointMode" | "endpointValidationMode" | "includeAuthOnAssetFetch" | "assetOrigins" | "credentials" | "headers"> & {
|
|
127
145
|
provider?: TTSRuntimeSettings["serverProvider"];
|
|
128
146
|
};
|
|
129
147
|
export declare const buildRuntimeTTSConfig: (config: TTSRuntimeSettings) => RuntimeTTSConfig;
|
|
130
|
-
|
|
131
|
-
export declare const resolveTTSHostToolbarLayout: (config:
|
|
148
|
+
/** The toolbar layout hints for the layout mode of resolved settings. */
|
|
149
|
+
export declare const resolveTTSHostToolbarLayout: (config: {
|
|
150
|
+
layoutMode: TTSLayoutMode;
|
|
151
|
+
}) => TTSHostToolbarLayout;
|
|
@@ -7,10 +7,14 @@ const VALID_TTS_LAYOUT_MODES = new Set([
|
|
|
7
7
|
]);
|
|
8
8
|
const toRecord = (value) => value && typeof value === "object" ? value : {};
|
|
9
9
|
const withDefault = (value, fallback) => value === undefined ? fallback : value;
|
|
10
|
-
|
|
10
|
+
/** A custom server provider speaks the custom transport, as `ServerTTSProvider` does on its own. */
|
|
11
|
+
const defaultTransportMode = (config) => resolveTTSBackend(config) === "server" && config.serverProvider === "custom"
|
|
12
|
+
? "custom"
|
|
13
|
+
: "pie";
|
|
14
|
+
const normalizeTTSLayoutMode = (value) => typeof value === "string" &&
|
|
11
15
|
VALID_TTS_LAYOUT_MODES.has(value)
|
|
12
16
|
? value
|
|
13
|
-
:
|
|
17
|
+
: "left-aligned";
|
|
14
18
|
const DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([
|
|
15
19
|
{ rate: 0.8, label: "Slow", ariaLabel: "Slow speed" },
|
|
16
20
|
{ rate: 1, label: "Normal", ariaLabel: "Normal speed", default: true },
|
|
@@ -57,11 +61,7 @@ export const normalizeTTSSpeedControlOptions = (value) => {
|
|
|
57
61
|
if (rate === undefined || dedupedRates.has(rate))
|
|
58
62
|
continue;
|
|
59
63
|
dedupedRates.add(rate);
|
|
60
|
-
const defaultLabel = rate === 1
|
|
61
|
-
? "Normal"
|
|
62
|
-
: typeof entry === "number"
|
|
63
|
-
? formatSpeedLabel(rate)
|
|
64
|
-
: formatSpeedLabel(rate);
|
|
64
|
+
const defaultLabel = rate === 1 ? "Normal" : formatSpeedLabel(rate);
|
|
65
65
|
const label = typeof entry === "number"
|
|
66
66
|
? defaultLabel
|
|
67
67
|
: trimOptionalText(record.label) || defaultLabel;
|
|
@@ -148,9 +148,8 @@ const applyRuntimeDefaults = (config) => {
|
|
|
148
148
|
const withServerDefaults = {
|
|
149
149
|
...withLayoutDefaults,
|
|
150
150
|
apiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, "/api/tts"),
|
|
151
|
-
transportMode: withDefault(withLayoutDefaults.transportMode,
|
|
151
|
+
transportMode: withDefault(withLayoutDefaults.transportMode, defaultTransportMode(config)),
|
|
152
152
|
endpointValidationMode: withDefault(withLayoutDefaults.endpointValidationMode, "voices"),
|
|
153
|
-
validateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),
|
|
154
153
|
includeAuthOnAssetFetch: withDefault(withLayoutDefaults.includeAuthOnAssetFetch, false),
|
|
155
154
|
rate: withDefault(withLayoutDefaults.rate, 1.0),
|
|
156
155
|
language: withDefault(withLayoutDefaults.language, "en-US"),
|
|
@@ -167,8 +166,9 @@ const applyRuntimeDefaults = (config) => {
|
|
|
167
166
|
};
|
|
168
167
|
/**
|
|
169
168
|
* The runtime settings of a `textToSpeech` provider entry: its top-level keys
|
|
170
|
-
* with defaults applied
|
|
171
|
-
* the
|
|
169
|
+
* with defaults applied, an unknown `layoutMode` resolved to `left-aligned`.
|
|
170
|
+
* `enabled` and the runtime `provider` object belong to the tool registration
|
|
171
|
+
* and are dropped.
|
|
172
172
|
*/
|
|
173
173
|
export const resolveTTSRuntimeSettings = (config) => {
|
|
174
174
|
const { enabled: _enabled, provider: _provider, ...settings } = toRecord(config);
|
|
@@ -178,7 +178,7 @@ export const resolveTTSBackend = (config) => config.backend || "browser";
|
|
|
178
178
|
export const buildRuntimeTTSConfig = (config) => {
|
|
179
179
|
const runtimeProvider = resolveTTSBackend(config) === "server" ? config.serverProvider : undefined;
|
|
180
180
|
const polly = runtimeProvider === "polly";
|
|
181
|
-
const transportMode = config.transportMode || (
|
|
181
|
+
const transportMode = config.transportMode || defaultTransportMode(config);
|
|
182
182
|
const mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);
|
|
183
183
|
const runtimeConfig = {
|
|
184
184
|
voice: config.defaultVoice,
|
|
@@ -224,7 +224,6 @@ export const buildRuntimeTTSConfig = (config) => {
|
|
|
224
224
|
assetOrigins: config.assetOrigins,
|
|
225
225
|
credentials: config.credentials,
|
|
226
226
|
headers: config.headers,
|
|
227
|
-
validateEndpoint: config.validateEndpoint,
|
|
228
227
|
// Toolkit-level highlight setting carried through the config channel
|
|
229
228
|
// (like apiEndpoint/transportMode); consumed by the highlight pipeline,
|
|
230
229
|
// ignored by providers. Only forwarded when set so the pipeline default
|
|
@@ -235,13 +234,11 @@ export const buildRuntimeTTSConfig = (config) => {
|
|
|
235
234
|
};
|
|
236
235
|
return runtimeConfig;
|
|
237
236
|
};
|
|
238
|
-
|
|
237
|
+
/** The toolbar layout hints for the layout mode of resolved settings. */
|
|
239
238
|
export const resolveTTSHostToolbarLayout = (config) => {
|
|
240
|
-
|
|
241
|
-
switch (layoutMode) {
|
|
239
|
+
switch (config.layoutMode) {
|
|
242
240
|
case "reserved-row":
|
|
243
241
|
return {
|
|
244
|
-
mount: "before-buttons",
|
|
245
242
|
controlsRow: {
|
|
246
243
|
reserveSpace: true,
|
|
247
244
|
expandWhenToolActive: false,
|
|
@@ -252,7 +249,6 @@ export const resolveTTSHostToolbarLayout = (config) => {
|
|
|
252
249
|
};
|
|
253
250
|
case "expanding-row":
|
|
254
251
|
return {
|
|
255
|
-
mount: "before-buttons",
|
|
256
252
|
controlsRow: {
|
|
257
253
|
reserveSpace: false,
|
|
258
254
|
expandWhenToolActive: true,
|
|
@@ -263,7 +259,6 @@ export const resolveTTSHostToolbarLayout = (config) => {
|
|
|
263
259
|
};
|
|
264
260
|
case "floating-overlay":
|
|
265
261
|
return {
|
|
266
|
-
mount: "before-buttons",
|
|
267
262
|
controlsRow: {
|
|
268
263
|
reserveSpace: false,
|
|
269
264
|
expandWhenToolActive: false,
|
|
@@ -275,7 +270,6 @@ export const resolveTTSHostToolbarLayout = (config) => {
|
|
|
275
270
|
case "left-aligned":
|
|
276
271
|
default:
|
|
277
272
|
return {
|
|
278
|
-
mount: "before-buttons",
|
|
279
273
|
controlsRow: {
|
|
280
274
|
reserveSpace: false,
|
|
281
275
|
expandWhenToolActive: false,
|
|
@@ -34,7 +34,7 @@ import type { CatalogOwnerSnapshot } from "../services/AccessibilityCatalogResol
|
|
|
34
34
|
export type ContentCapabilityPolicy = {
|
|
35
35
|
outcome: "granted";
|
|
36
36
|
/** Feature parameters carried by the decision, if any. */
|
|
37
|
-
parameters?: unknown
|
|
37
|
+
parameters?: Record<string, unknown>;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* No source granted it and none denied it. A capability declaring
|
|
@@ -65,7 +65,7 @@ export interface ResolvedContentCapability {
|
|
|
65
65
|
* tell them apart at render time.
|
|
66
66
|
*/
|
|
67
67
|
granted: boolean;
|
|
68
|
-
parameters?: unknown
|
|
68
|
+
parameters?: Record<string, unknown>;
|
|
69
69
|
/** Whatever the capability's own `resolve` returned; never inspected here. */
|
|
70
70
|
content: unknown;
|
|
71
71
|
}
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
export type { HostedToolContext, HostedToolSize, ToolContentDependencyContext, ToolModuleLoader, ToolProviderDescriptor, ToolRegistration, ToolRenderElement, ToolSurfaceRenderContext, ToolSurfaceRenderResult, ToolSurfaceServices, ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolbarContext, } from "../services/ToolRegistry.js";
|
|
24
24
|
export { ToolRegistry } from "../services/ToolRegistry.js";
|
|
25
25
|
export { resolveToolRegistrationName } from "../services/ToolRegistry.js";
|
|
26
|
+
export type { ToolFailurePhase } from "../services/tool-failure.js";
|
|
27
|
+
export { reportToolFailure } from "../services/tool-failure.js";
|
|
26
28
|
export type { CatalogOwnerSnapshot } from "../services/AccessibilityCatalogResolver.js";
|
|
27
29
|
export type { ToolSelectionAction, ToolSelectionContext, } from "../services/selection-action.js";
|
|
28
30
|
export { resolveFallbackToolIcon } from "../services/tool-icons.js";
|
|
@@ -30,13 +32,13 @@ export type { ContentCapabilityPhase, ContentCapabilityPolicy, ResolveContentCap
|
|
|
30
32
|
export { resolveContentCapabilities } from "./content-capability-resolution.js";
|
|
31
33
|
export type { ToolSurfaceHost, ToolSurfaceHostInput, ToolSurfaceHostOptions, ToolSurfaceHostSnapshot, ToolSurfaceScope, } from "./tool-surface-host.js";
|
|
32
34
|
export { createToolSurfaceHost } from "./tool-surface-host.js";
|
|
33
|
-
export type { ToolContext } from "../services/tool-context.js";
|
|
34
|
-
export {
|
|
35
|
+
export type { ElementSupports, ToolContext, } from "../services/tool-context.js";
|
|
36
|
+
export { elementSupports, hasMathContent, hasReadableText, hasSpokenContent, hasScienceContent, } from "../services/tool-context.js";
|
|
35
37
|
export type { ParsedToolInstanceId } from "../services/tool-instance-id.js";
|
|
36
38
|
export { createScopedToolId, parseScopedToolId, } from "../services/tool-instance-id.js";
|
|
37
39
|
export type { ToolComponentFactory, ToolComponentFactoryMap, ToolComponentOverrides, ToolTagMap, } from "./tool-tag-map.js";
|
|
38
40
|
export { createToolElement, resolveToolTag } from "./tool-tag-map.js";
|
|
39
|
-
export { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "./registrations/toolbar-registration-helpers.js";
|
|
41
|
+
export { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, TOOL_ACTIVE_CHANGE_EVENT, } from "./registrations/toolbar-registration-helpers.js";
|
|
40
42
|
export type { HighlightCoordinatorApi, ToolCoordinatorApi, ToolkitCoordinatorApi, TtsServiceApi, } from "../services/interfaces.js";
|
|
41
43
|
export type { AssessmentToolkitRegionScopeContext, AssessmentToolkitRuntimeContext, AssessmentToolkitShellContext, } from "../context/assessment-toolkit-context.js";
|
|
42
44
|
export { connectToolRegionScopeContext, connectToolRuntimeContext, connectToolShellContext, createToolCoordinatorRegistration, type ToolCoordinatorRegistration, } from "../runtime/tool-host-contract.js";
|
|
@@ -48,11 +50,10 @@ export { findShellScopeHost, resolveContentRegion, } from "../runtime/content-re
|
|
|
48
50
|
export { composedClosest, composedContains, flatTextContent, isShadowRootNode, retargetToTree, } from "../services/tts/flat-tree.js";
|
|
49
51
|
export type { ToolPlacementLevel } from "../services/tools-config-normalizer.js";
|
|
50
52
|
export type { CalculatorToolProviderConfig, TextToSpeechToolProviderConfig, ToolProviderConfig, } from "../services/tools-config-normalizer.js";
|
|
51
|
-
export type { ToolProviderApi
|
|
53
|
+
export type { ToolProviderApi } from "../services/tool-providers/ToolProviderApi.js";
|
|
52
54
|
export { TTSToolProvider } from "../services/tool-providers/index.js";
|
|
53
55
|
export type { NormalizedTTSSpeedOption, TTSLayoutMode, TTSSpeedOption, } from "../services/tts-runtime-config.js";
|
|
54
|
-
export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText,
|
|
55
|
-
export { PIE_TTS_CONTROL_HANDOFF_EVENT } from "../services/tts-control-events.js";
|
|
56
|
+
export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText, normalizeTTSSpeedControlOptions, parseTTSSpeedOptionsFromText, resolveTTSHostToolbarLayout, resolveTTSRuntimeSettings, } from "../services/tts-runtime-config.js";
|
|
56
57
|
export { bindTtsAudioHandoff, pauseTtsForMediaAudio, } from "../services/audio-handoff.js";
|
|
57
58
|
export { isTTSStartFailure } from "../services/tts/start-failure.js";
|
|
58
59
|
export { browserVoiceMatchesLanguage, findBrowserVoice, waitForBrowserVoices, } from "../services/tts/browser-provider.js";
|
|
@@ -25,15 +25,17 @@ export { ToolRegistry } from "../services/ToolRegistry.js";
|
|
|
25
25
|
// title is the registration's name, so the shell needs the same `nameKey`-then-
|
|
26
26
|
// `name` precedence the toolbar uses rather than the raw English field.
|
|
27
27
|
export { resolveToolRegistrationName } from "../services/ToolRegistry.js";
|
|
28
|
+
export { reportToolFailure } from "../services/tool-failure.js";
|
|
28
29
|
// So a gateway button and the toolbar button for the same tool draw one icon.
|
|
29
30
|
export { resolveFallbackToolIcon } from "../services/tool-icons.js";
|
|
30
31
|
export { resolveContentCapabilities } from "./content-capability-resolution.js";
|
|
31
32
|
export { createToolSurfaceHost } from "./tool-surface-host.js";
|
|
32
|
-
export {
|
|
33
|
+
export { elementSupports, hasMathContent, hasReadableText, hasSpokenContent, hasScienceContent, } from "../services/tool-context.js";
|
|
33
34
|
export { createScopedToolId, parseScopedToolId, } from "../services/tool-instance-id.js";
|
|
34
35
|
export { createToolElement, resolveToolTag } from "./tool-tag-map.js";
|
|
35
|
-
// Toolbar button/overlay wiring shared by every toolbar-toggle registration
|
|
36
|
-
|
|
36
|
+
// Toolbar button/overlay wiring shared by every toolbar-toggle registration,
|
|
37
|
+
// and the event a tool element announces its own active state with.
|
|
38
|
+
export { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, TOOL_ACTIVE_CHANGE_EVENT, } from "./registrations/toolbar-registration-helpers.js";
|
|
37
39
|
export { connectToolRegionScopeContext, connectToolRuntimeContext, connectToolShellContext, createToolCoordinatorRegistration, } from "../runtime/tool-host-contract.js";
|
|
38
40
|
export { ZIndexLayer } from "../services/ToolCoordinator.js";
|
|
39
41
|
export { HighlightColor, HighlightCoordinator, } from "../services/HighlightCoordinator.js";
|
|
@@ -43,12 +45,11 @@ export { composedClosest, composedContains, flatTextContent, isShadowRootNode, r
|
|
|
43
45
|
// The TTS provider stays here because it is written against the `pie-tts`
|
|
44
46
|
// contract package, which the toolkit's own `TTSService` also depends on.
|
|
45
47
|
export { TTSToolProvider } from "../services/tool-providers/index.js";
|
|
46
|
-
export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText,
|
|
47
|
-
// Read-aloud coordination for a tool that plays or controls speech:
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
export { PIE_TTS_CONTROL_HANDOFF_EVENT } from "../services/tts-control-events.js";
|
|
48
|
+
export { buildRuntimeTTSConfig, formatTTSSpeedOptionsAsText, normalizeTTSSpeedControlOptions, parseTTSSpeedOptionsFromText, resolveTTSHostToolbarLayout, resolveTTSRuntimeSettings, } from "../services/tts-runtime-config.js";
|
|
49
|
+
// Read-aloud coordination for a tool that plays or controls speech: pausing
|
|
50
|
+
// speech while a media element plays, recognising a start failure the TTS
|
|
51
|
+
// service reports, and choosing a browser voice for a language once the browser
|
|
52
|
+
// has published its voices.
|
|
52
53
|
export { bindTtsAudioHandoff, pauseTtsForMediaAudio, } from "../services/audio-handoff.js";
|
|
53
54
|
export { isTTSStartFailure } from "../services/tts/start-failure.js";
|
|
54
55
|
export { browserVoiceMatchesLanguage, findBrowserVoice, waitForBrowserVoices, } from "../services/tts/browser-provider.js";
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { ToolToolbarButtonDefinition, ToolToolbarRenderResult, ToolbarContext } from "../../services/ToolRegistry.js";
|
|
2
2
|
export type ToolOverlaySurface = "default" | "frameless";
|
|
3
|
+
/**
|
|
4
|
+
* The event a tool element dispatches, bubbling and composed, with
|
|
5
|
+
* `{ active: boolean }` as its detail when it opens or closes its own panel.
|
|
6
|
+
* A registration relays it as the toolbar button's active state.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TOOL_ACTIVE_CHANGE_EVENT = "pie-tool-active-change";
|
|
3
9
|
export declare function createScopedVisibilityBinding(toolId: string, toolbarContext: ToolbarContext): {
|
|
4
10
|
fullToolId: string;
|
|
5
11
|
isActive: () => boolean;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { createScopedToolId } from "../../services/tool-instance-id.js";
|
|
2
|
+
/**
|
|
3
|
+
* The event a tool element dispatches, bubbling and composed, with
|
|
4
|
+
* `{ active: boolean }` as its detail when it opens or closes its own panel.
|
|
5
|
+
* A registration relays it as the toolbar button's active state.
|
|
6
|
+
*/
|
|
7
|
+
export const TOOL_ACTIVE_CHANGE_EVENT = "pie-tool-active-change";
|
|
2
8
|
export function createScopedVisibilityBinding(toolId, toolbarContext) {
|
|
3
9
|
const fullToolId = createScopedToolId(toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
|
|
4
10
|
return {
|
|
@@ -43,12 +43,6 @@ function stableSerializableJson(value) {
|
|
|
43
43
|
if (typeof current === "undefined") {
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
|
-
if (typeof current === "function" || typeof current === "symbol") {
|
|
47
|
-
throw new TypeError(`${path} is not JSON-serializable`);
|
|
48
|
-
}
|
|
49
|
-
if (typeof current === "bigint") {
|
|
50
|
-
throw new TypeError(`${path} is not JSON-serializable`);
|
|
51
|
-
}
|
|
52
46
|
if (typeof current !== "object") {
|
|
53
47
|
throw new TypeError(`${path} is not JSON-serializable`);
|
|
54
48
|
}
|
|
@@ -339,7 +333,7 @@ export function createToolSurfaceHost(onSnapshot, options) {
|
|
|
339
333
|
// test-administration override grants it.
|
|
340
334
|
placed = true;
|
|
341
335
|
granted = entry.required || entry.alwaysAvailable;
|
|
342
|
-
parameters = entry.
|
|
336
|
+
parameters = entry.parameters;
|
|
343
337
|
break;
|
|
344
338
|
}
|
|
345
339
|
if (!placed)
|
|
@@ -465,7 +459,6 @@ export function createToolSurfaceHost(onSnapshot, options) {
|
|
|
465
459
|
}
|
|
466
460
|
}
|
|
467
461
|
report(toolId, "render", `Tool "${toolId}" failed to render into the "${current.surface}" surface.`, error);
|
|
468
|
-
return;
|
|
469
462
|
}
|
|
470
463
|
}
|
|
471
464
|
function reconcile() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-players/pie-assessment-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PIE assessment toolkit: composable services + reference implementation for assessment players and tool coordination",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,8 +54,10 @@
|
|
|
54
54
|
"import": "./dist/policy/engine.js"
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
|
+
"customElements": "custom-elements.json",
|
|
57
58
|
"files": [
|
|
58
59
|
"dist",
|
|
60
|
+
"custom-elements.json",
|
|
59
61
|
"README.md"
|
|
60
62
|
],
|
|
61
63
|
"scripts": {
|
|
@@ -67,16 +69,16 @@
|
|
|
67
69
|
"test": "bun test"
|
|
68
70
|
},
|
|
69
71
|
"dependencies": {
|
|
70
|
-
"@pie-players/pie-calculator": "0.
|
|
71
|
-
"@pie-players/pie-context": "0.
|
|
72
|
-
"@pie-players/pie-players-shared": "0.
|
|
73
|
-
"@pie-players/pie-tts": "0.
|
|
72
|
+
"@pie-players/pie-calculator": "1.0.0-beta.1",
|
|
73
|
+
"@pie-players/pie-context": "1.0.0-beta.1",
|
|
74
|
+
"@pie-players/pie-players-shared": "1.0.0-beta.1",
|
|
75
|
+
"@pie-players/pie-tts": "1.0.0-beta.1",
|
|
74
76
|
"speech-rule-engine": "5.0.0-rc.4"
|
|
75
77
|
},
|
|
76
78
|
"devDependencies": {
|
|
77
79
|
"@biomejs/biome": "^2.5.15",
|
|
78
80
|
"@happy-dom/global-registrator": "^20.14.5",
|
|
79
|
-
"@pie-players/tts-client-server": "0.
|
|
81
|
+
"@pie-players/tts-client-server": "1.0.0-beta.1",
|
|
80
82
|
"svelte": "^5.57.1",
|
|
81
83
|
"svelte-check": "^4.7.6",
|
|
82
84
|
"typescript": "^5.9.3"
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{ia as h,ja as F}from"./ItemToolBar-7tt7v2xp.js";var Y=["assessment","section","item","passage","rubric"],H=new Set(Y);function U(f){return H.has(f)}function N(f,p,c){let w=f.trim(),E=c.trim();if(!w||!E)throw Error("Tool instance ids require non-empty tool and scope ids");if(!U(p))throw Error(`Unknown tool scope level '${p}'. Register custom levels with registerToolScopeLevel().`);return`${w}:${p}:${E}`}function q(f){let p=f.split(":");if(p.length!==3)return null;let[c,w,E]=p;if(!c||!E)return null;if(!U(w))return null;return{baseToolId:c,scopeLevel:w,scopeId:E}}function B(f){return(...p)=>{console.debug(`[${f}]`,...p)}}var z=B("ToolCoordinator"),T;(function(f){f[f.BASE=0]="BASE",f[f.TOOL=1000]="TOOL",f[f.MODAL=2000]="MODAL",f[f.CONTROL=3000]="CONTROL",f[f.HIGHLIGHT=4000]="HIGHLIGHT"})(T||(T={}));function J(f,p){if(!p?.baseId)return!0;return(q(f)?.baseToolId??f)===p.baseId}function M(f){return{id:f.id,name:f.name,isVisible:f.isVisible,element:f.element,layer:f.layer}}class V{tools=new Map;listeners=new Set;subscribe(f){return this.listeners.add(f),()=>{this.listeners.delete(f)}}notifyListeners(){for(let f of this.listeners)try{f()}catch(p){console.warn("[ToolCoordinator] listener failed:",p)}}registerTool(f,p,c,w){z("registerTool called:",{id:f,name:p,hasElement:!!c,layer:w});let E=this.tools.get(f);if(E){E.name=p;let u=E.registered;if(E.registered=!0,w!==void 0&&!E.layerDeclared)E.layer=w,E.layerDeclared=!0,this.stackOnTop(E);else if(!u)this.stackOnTop(E)}else E={id:f,name:p,registered:!0,element:null,layer:w??T.TOOL,layerDeclared:w!==void 0,isVisible:!1,baseZIndex:0},this.tools.set(f,E),this.stackOnTop(E);if(c)this.updateToolElement(f,c)}unregisterTool(f){let p=this.tools.get(f);if(!p?.registered)return;this.detachElement(p),p.registered=!1}releaseTool(f){let p=this.tools.get(f);if(!p)return;if(this.detachElement(p),this.tools.delete(f),p.isVisible)this.notifyListeners()}showTool(f){let p=this.tools.get(f);if(!p){z(`Tool ${f} not found`);return}if(p.element)this.bringToFront(p.element);this.setVisible(p,!0)}hideTool(f){let p=this.tools.get(f);if(!p){z(`Tool ${f} not found`);return}this.setVisible(p,!1)}toggleTool(f){let p=this.tools.get(f);if(!p){z(`Tool ${f} not found`);return}if(p.isVisible)this.hideTool(f);else this.showTool(f)}isToolVisible(f){return this.tools.get(f)?.isVisible??!1}bringToFront(f){let p=Array.from(this.tools.values()).find((c)=>c.element===f);if(!p)return;this.stackOnTop(p)}getRegisteredTools(){return Array.from(this.tools.values()).filter((f)=>f.registered).map((f)=>f.id)}getToolElement(f){return this.tools.get(f)?.element??null}setVisible(f,p){if(f.isVisible===p)return;f.isVisible=p,this.notifyListeners()}detachElement(f){if(f.element&&f.mouseDownHandler)f.element.removeEventListener("mousedown",f.mouseDownHandler);f.element=null,f.mouseDownHandler=void 0}stackOnTop(f){let p=Array.from(this.tools.values()).filter((w)=>w.registered&&w.layer===f.layer&&w!==f).sort((w,E)=>w.baseZIndex-E.baseZIndex),c=f.layer+p.length+1;if(f.baseZIndex===c&&p.every((w)=>w.baseZIndex<c))return;[...p,f].forEach((w,E)=>{if(w.baseZIndex=f.layer+1+E,w.element)w.element.style.zIndex=String(w.baseZIndex)})}updateToolElement(f,p){let c=this.tools.get(f);if(!c?.registered){z(`Tool ${f} not found`);return}if(c.element===p)return;if(c.element?.isConnected&&c.element.contains(p))return;this.detachElement(c);let w=()=>this.bringToFront(p);if(p.addEventListener("mousedown",w),c.element=p,c.mouseDownHandler=w,p.style.zIndex=String(c.baseZIndex),c.isVisible)this.bringToFront(p)}hideAllTools(f){let p=!1;for(let c of this.tools.values()){if(!c.isVisible||!J(c.id,f))continue;c.isVisible=!1,p=!0}if(p)this.notifyListeners()}getToolState(f){let p=this.tools.get(f);return p?.registered?M(p):void 0}getVisibleTools(f){return Array.from(this.tools.values()).filter((p)=>p.isVisible&&J(p.id,f)).map(M)}}import{dynamicMessageKey as a}from"@pie-players/pie-players-shared/i18n/provider";import{validateCustomElementTag as W}from"@pie-players/pie-players-shared/pie/tag-names";var P=(f,p)=>{let c=p?.toolTagMap?.[f];if(c===void 0&&!f.includes("-"))throw Error(`No element tag is mapped for tool "${f}". Install a tag map on the registry via setComponentOverrides({ toolTagMap }) — for the packaged capabilities, PACKAGED_TOOL_TAG_MAP from "@pie-players/pie-default-tool-loaders".`);return W(c??f,`tool component tag for "${f}"`)};var R=["assessment","section","item","passage","rubric","element"];function j(f,p){if(typeof f!=="string"||f.trim().length===0)throw Error(`Invalid tool registration: "${p}" must be a non-empty string.`)}var S=[{pattern:/<script\b/i,reason:"contains a <script> tag"},{pattern:/\son[a-z]+\s*=/i,reason:"contains an inline event handler (on*=) attribute"},{pattern:/javascript:/i,reason:"contains a javascript: URL"},{pattern:/<foreignObject\b/i,reason:"contains a <foreignObject> element"}];function G(f,p,c){let w=p.trimStart(),E=w.toLowerCase().startsWith("<svg"),u=/^https?:/i.test(w);if(/^data:/i.test(w))throw Error(`Invalid tool registration "${f}": "${c}" may not be a data: URL.`);if(!E&&!u)return;for(let{pattern:X,reason:_}of S)if(X.test(p))throw Error(`Invalid tool registration "${f}": "${c}" ${_}. Inline SVG icons must not include scriptable content.`)}function Q(f){j(f.toolId,"toolId"),j(f.name,"name"),j(f.description,"description");let p=f.activation==="region";if(!p||f.icon!==void 0){if(typeof f.icon!=="string"&&typeof f.icon!=="function")throw Error(`Invalid tool registration "${f.toolId}": "icon" must be a string or function.`)}if(typeof f.icon==="string")G(f.toolId,f.icon,"icon");if(!Array.isArray(f.supportedLevels)||f.supportedLevels.length===0)throw Error(`Invalid tool registration "${f.toolId}": "supportedLevels" must be a non-empty array.`);let c=f.supportedLevels.find((w)=>!R.includes(w));if(c)throw Error(`Invalid tool registration "${f.toolId}": unsupported level "${c}".`);if(f.activation!==void 0&&f.activation!=="toolbar-toggle"&&f.activation!=="selection-gateway"&&f.activation!=="region")throw Error(`Invalid tool registration "${f.toolId}": unsupported activation "${String(f.activation)}".`);if(f.surfaces!==void 0&&(!Array.isArray(f.surfaces)||f.surfaces.some((w)=>typeof w!=="string"||w.trim().length===0)))throw Error(`Invalid tool registration "${f.toolId}": "surfaces" must be an array of non-empty strings.`);if(p&&!f.surfaces?.length)throw Error(`Invalid tool registration "${f.toolId}": region tools must declare at least one host surface in "surfaces".`);if(p&&typeof f.renderSurface!=="function")throw Error(`Invalid tool registration "${f.toolId}": region tools must implement "renderSurface".`);if(f.resolvesWithoutGrant!==void 0&&typeof f.resolvesWithoutGrant!=="boolean")throw Error(`Invalid tool registration "${f.toolId}": "resolvesWithoutGrant" must be a boolean.`);if(f.resolvesWithoutGrant&&!f.requiresAuthoredContent)throw Error(`Invalid tool registration "${f.toolId}": "resolvesWithoutGrant" requires "requiresAuthoredContent".`);if(f.renderSurface!==void 0&&typeof f.renderSurface!=="function")throw Error(`Invalid tool registration "${f.toolId}": "renderSurface" must be a function.`);if(f.renderSurface&&!f.surfaces?.length)throw Error(`Invalid tool registration "${f.toolId}": "renderSurface" requires at least one entry in "surfaces".`);if(f.singletonScope!==void 0&&f.singletonScope!=="section")throw Error(`Invalid tool registration "${f.toolId}": unsupported singletonScope "${String(f.singletonScope)}".`);if(f.activation==="selection-gateway"&&f.singletonScope!=="section")throw Error(`Invalid tool registration "${f.toolId}": selection-gateway tools must declare singletonScope "section".`);if(f.activation!=="region"&&typeof f.isVisibleInContext!=="function")throw Error(`Invalid tool registration "${f.toolId}": "isVisibleInContext" must be a function.`);if(f.isVisibleInContext!==void 0&&typeof f.isVisibleInContext!=="function")throw Error(`Invalid tool registration "${f.toolId}": "isVisibleInContext" must be a function when present.`);if(f.isApplicableToContent!==void 0&&typeof f.isApplicableToContent!=="function")throw Error(`Invalid tool registration "${f.toolId}": "isApplicableToContent" must be a function when present.`);if(f.requiresAuthoredContent!==void 0){if(typeof f.requiresAuthoredContent!=="object"||f.requiresAuthoredContent===null||typeof f.requiresAuthoredContent.resolve!=="function")throw Error(`Invalid tool registration "${f.toolId}": "requiresAuthoredContent" must be an object with a "resolve" function.`)}if(f.renderToolbar!==void 0){if(typeof f.renderToolbar!=="function")throw Error(`Invalid tool registration "${f.toolId}": "renderToolbar" must be a function.`)}else if(!p)throw Error(`Invalid tool registration "${f.toolId}": "renderToolbar" must be a function.`)}class D{tools=new Map;componentOverrides={};watchedUndefinedToolElements=new Set;moduleLoaders=new Map;loadedToolModules=new Set;warnedLoaderReplacements=new Set;warnedUnregisteredAllowedTools=new Set;moduleLoadPromises=new Map;changeListeners=new Set;emitChange(f){for(let p of this.changeListeners)try{p(f)}catch(c){console.warn("[ToolRegistry] change listener failed:",c)}}onRegistryChange(f){this.changeListeners.add(f);let p=!0;return()=>{if(!p)return;p=!1,this.changeListeners.delete(f)}}normalizeToolId(f){return f.trim()}normalizeToolIds(f){return f.map((p)=>this.normalizeToolId(p))}register(f){if(Q(f),this.tools.has(f.toolId))throw Error(`Tool '${f.toolId}' is already registered`);this.tools.set(f.toolId,f),this.emitChange({kind:"register",toolIds:[f.toolId]})}override(f){if(Q(f),!this.tools.has(f.toolId))throw Error(`Cannot override non-existent tool '${f.toolId}'`);this.tools.set(f.toolId,f),this.emitChange({kind:"override",toolIds:[f.toolId]})}unregister(f){if(!this.tools.has(f))return;this.tools.delete(f),this.emitChange({kind:"unregister",toolIds:[f]})}get(f){return this.tools.get(f)}has(f){return this.tools.has(f)}getAllToolIds(){return Array.from(this.tools.keys())}getAllTools(){return Array.from(this.tools.values())}getToolsByLevel(f){return this.getAllTools().filter((p)=>p.supportedLevels.includes(f))}getToolActivation(f){return this.get(f)?.activation||"toolbar-toggle"}getToolSingletonScope(f){return this.get(f)?.singletonScope||null}getToolsBySurface(f){if(!f)return[];return this.getAllTools().filter((p)=>typeof p.renderSurface==="function"&&p.surfaces?.includes(f))}getContentDependentSupportIds(){return this.getAllTools().filter((f)=>f.requiresAuthoredContent).map((f)=>f.toolId).sort()}filterToolIdsByActivation(f,p){return f.filter((c)=>this.getToolActivation(c)===p)}filterVisibleInContext(f,p){let c=[];for(let w of f){let E=this.get(w);if(!E){if(!this.warnedUnregisteredAllowedTools.has(w))this.warnedUnregisteredAllowedTools.add(w),console.warn(`Tool '${w}' is allowed but not registered`);continue}if(!E.supportedLevels.includes(p.level))continue;try{if(E.isVisibleInContext?.(p))c.push(E)}catch(u){console.error(`Error evaluating visibility for tool '${w}':`,u)}}return c}isApplicableToAnyContext(f,p){let c=this.get(f);if(!c?.isApplicableToContent)return!0;if(p.length===0)return!0;return p.some((w)=>{try{return c.isApplicableToContent?.(w)??!0}catch(E){return console.error(`Error evaluating applicability for tool '${f}':`,E),!0}})}getToolMetadata(){return this.getAllTools().map((f)=>({toolId:f.toolId,name:f.name,description:f.description,supportedLevels:f.supportedLevels,activation:f.activation||"toolbar-toggle",singletonScope:f.singletonScope||null,surfaces:f.surfaces||[],requiresAuthoredContent:Boolean(f.requiresAuthoredContent),contentDependencyDescription:f.requiresAuthoredContent?.description??null}))}clear(){let f=this.getAllToolIds();if(f.length===0)return;this.tools.clear(),this.emitChange({kind:"clear",toolIds:f})}setComponentOverrides(f){if(this.componentOverrides===f)return;this.componentOverrides=f,this.emitChange({kind:"component-overrides",toolIds:[]})}setToolModuleLoaders(f){let p=Object.entries(f).filter((w)=>w[1]!==void 0);for(let[w,E]of p)if(j(w,"tool module loader id"),typeof E!=="function")throw Error(`Invalid tool module loader for "${w}": expected a function.`);let c=[];for(let[w,E]of p){if(this.moduleLoaders.get(w)===E)continue;if(this.loadedToolModules.has(w)||this.moduleLoadPromises.has(w)){this.warnLoaderReplacedAfterLoad(w);continue}this.moduleLoaders.set(w,E),c.push(w)}if(c.length>0)this.emitChange({kind:"module-loaders",toolIds:c})}warnLoaderReplacedAfterLoad(f){if(this.warnedLoaderReplacements.has(f))return;this.warnedLoaderReplacements.add(f),console.warn(`[ToolRegistry] Ignored a new module loader for "${f}": its module already loaded, so the elements it defines stay in place. Register loaders before the tool first renders.`)}async ensureToolModuleLoaded(f){if(this.loadedToolModules.has(f))return;let p=this.moduleLoadPromises.get(f);if(p){await p;return}let c=this.moduleLoaders.get(f);if(!c){this.watchUndefinedToolElement(f);return}let w=(async()=>{await c(),this.loadedToolModules.add(f),this.warnIfLoadedToolElementUndefined(f)})();this.moduleLoadPromises.set(f,w);try{await w}finally{this.moduleLoadPromises.delete(f)}}undefinedToolElementTag(f){if(typeof customElements>"u"||typeof document>"u")return null;let p=this.componentOverrides;if(p.toolComponentFactories?.[f])return null;let c;try{c=P(f,p)}catch{return null}return customElements.get(c)?null:c}warnIfLoadedToolElementUndefined(f){let p=this.undefinedToolElementTag(f);if(!p)return;F(document,`loadedToolElementUndefined.${f}.${p}`,`[ToolRegistry] Tool "${f}" renders <${p}>, but its module loader finished without defining it, so the tool renders blank. The tag map and the loader disagree: map "${f}" to the tag its loader defines, or register a loader that defines <${p}>. Reported once per page.`)}watchUndefinedToolElement(f){if(this.watchedUndefinedToolElements.has(f))return;let p=this.undefinedToolElementTag(f);if(!p)return;this.watchedUndefinedToolElements.add(f);let c=document,w=setTimeout(()=>{if(customElements.get(p))return;F(c,`undefinedToolElement.${f}`,`[ToolRegistry] Tool "${f}" renders <${p}>, which is still undefined after ${h/1000} s, and its registry has no module loader for it. Pass toolModuleLoaders to createPackagedToolRegistry (DEFAULT_TOOL_MODULE_LOADERS from @pie-players/pie-default-tool-loaders loads the stock tools), register one with setToolModuleLoaders, or import the tool's package before it renders. Reported once per page.`)},h);customElements.whenDefined(p).then(()=>clearTimeout(w))}async ensureToolModulesLoaded(f){let p=await Promise.allSettled(f.map((w)=>this.ensureToolModuleLoaded(w))),c=new Map;return p.forEach((w,E)=>{if(w.status==="rejected")c.set(f[E],w.reason)}),c}isToolModuleLoaded(f){return this.loadedToolModules.has(f)}renderForToolbar(f,p,c){let w=this.get(f);if(!w)throw Error(`Tool '${f}' is not registered`);if(typeof w.renderToolbar!=="function")throw Error(`Tool '${f}' has activation "${w.activation||"toolbar-toggle"}" and renders into a host surface, not a toolbar. Remove it from toolbar placement.`);let E={...c,componentOverrides:{...this.componentOverrides||{},...c.componentOverrides||{}}};return w.renderToolbar(p,E)}renderForSurface(f,p){let c=this.get(f);if(!c)throw Error(`Tool '${f}' is not registered`);if(typeof c.renderSurface!=="function")throw Error(`Tool '${f}' does not render into a host surface. Surface capabilities declare "surfaces" and implement "renderSurface".`);return c.renderSurface({...p,componentOverrides:{...this.componentOverrides||{},...p.componentOverrides||{}}})}}var b={assessment:[],section:[],item:[],passage:[],rubric:[],element:[]};var C={section:[...b.section],item:[...b.item],passage:[...b.passage]};function A(f){return typeof f==="object"&&f!==null&&!Array.isArray(f)}function O(f,p){if(f==null)return[];if(!Array.isArray(f))throw Error(`Invalid tools config at "${p}": expected an array of tool ids.`);if(f.find((w)=>typeof w!=="string")!==void 0)throw Error(`Invalid tools config at "${p}": all entries must be strings.`);return f}function K(f){if(f==null)return;if(!A(f))throw Error('Invalid tools config at "placement": expected an object with section/item/passage arrays.');return f}function k(f){if(f==null)return;if(!A(f))throw Error('Invalid tools config at "policy": expected an object with allowed/blocked arrays.');return f}function L(f,p){if(p==null)return;if(!A(p))throw Error(`Invalid tools config at "providers.${f}": expected an object.`);let c=p;if("enabled"in c&&c.enabled!==void 0&&typeof c.enabled!=="boolean")throw Error(`Invalid tools config at "providers.${f}.enabled": expected a boolean.`);if("settings"in c&&c.settings!==void 0&&!A(c.settings))throw Error(`Invalid tools config at "providers.${f}.settings": expected an object.`);if("provider"in c&&c.provider!==void 0&&!A(c.provider))throw Error(`Invalid tools config at "providers.${f}.provider": expected an object.`);return c}function Z(f){if(f==null)return{};if(!A(f))throw Error('Invalid tools config at "providers": expected an object keyed by tool id.');let p={};for(let[c,w]of Object.entries(f))p[c]=L(c,w);return p}function $(f){if(!f||f.length===0)return[];let p=new Set;for(let c of f){if(typeof c!=="string")throw Error("Invalid tools config: tool list entries must be strings.");let w=c.trim();if(!w)continue;p.add(w)}return Array.from(p)}function ff(f){if(!f)return[];return $(f.split(",").map((p)=>p.trim()).filter(Boolean))}function v(f,p){if(f==null)return;if(f==="on"||f==="off")return f;throw Error(`Invalid tools config at "${p}": expected "on" or "off", got ${JSON.stringify(f)}.`)}function pf(f){if(f!=null&&!A(f))throw Error('Invalid tools config: expected an object with "policy", "placement", and "providers".');let p=k(f?.policy),c=K(f?.placement),w=Z(f?.providers),E=v(f?.pnpEnforcement,"pnpEnforcement"),u={policy:{allowed:$(O(p?.allowed,"policy.allowed")),blocked:$(O(p?.blocked,"policy.blocked"))},placement:{section:$(O(c?.section,"placement.section")).length?$(O(c?.section,"placement.section")):[...C.section],item:$(O(c?.item,"placement.item")).length?$(O(c?.item,"placement.item")):[...C.item],passage:$(O(c?.passage,"placement.passage")).length?$(O(c?.passage,"placement.passage")):[...C.passage]},providers:w};if(E)u.pnpEnforcement=E;return u}
|
|
2
|
-
export{N as m,T as n,V as o,D as p,$ as q,ff as r,pf as s};
|