@pie-players/pie-assessment-toolkit 0.3.29 → 0.3.31
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 +313 -5
- package/dist/components/ItemToolBar.custom-element.js +362 -176
- package/dist/components/PieAssessmentToolkit.custom-element.js +604 -107
- package/dist/components/SectionToolBar.custom-element.js +0 -36
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/policy/core/PolicySource.d.ts +64 -0
- package/dist/policy/core/PolicySource.d.ts.map +1 -0
- package/dist/policy/core/PolicySource.js +17 -0
- package/dist/policy/core/PolicySource.js.map +1 -0
- package/dist/policy/core/ToolPolicyEngine.d.ts +123 -0
- package/dist/policy/core/ToolPolicyEngine.d.ts.map +1 -0
- package/dist/policy/core/ToolPolicyEngine.js +217 -0
- package/dist/policy/core/ToolPolicyEngine.js.map +1 -0
- package/dist/policy/core/compose-decision.d.ts +37 -0
- package/dist/policy/core/compose-decision.d.ts.map +1 -0
- package/dist/policy/core/compose-decision.js +332 -0
- package/dist/policy/core/compose-decision.js.map +1 -0
- package/dist/policy/core/decision-types.d.ts +142 -0
- package/dist/policy/core/decision-types.d.ts.map +1 -0
- package/dist/policy/core/decision-types.js +13 -0
- package/dist/policy/core/decision-types.js.map +1 -0
- package/dist/policy/core/engine-context.d.ts +30 -0
- package/dist/policy/core/engine-context.d.ts.map +1 -0
- package/dist/policy/core/engine-context.js +28 -0
- package/dist/policy/core/engine-context.js.map +1 -0
- package/dist/policy/core/policy-source-tag.d.ts +32 -0
- package/dist/policy/core/policy-source-tag.d.ts.map +1 -0
- package/dist/policy/core/policy-source-tag.js +29 -0
- package/dist/policy/core/policy-source-tag.js.map +1 -0
- package/dist/policy/core/provenance.d.ts +163 -0
- package/dist/policy/core/provenance.d.ts.map +1 -0
- package/dist/policy/core/provenance.js +232 -0
- package/dist/policy/core/provenance.js.map +1 -0
- package/dist/policy/core/qti-inputs.d.ts +67 -0
- package/dist/policy/core/qti-inputs.d.ts.map +1 -0
- package/dist/policy/core/qti-inputs.js +139 -0
- package/dist/policy/core/qti-inputs.js.map +1 -0
- package/dist/policy/engine.d.ts +28 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js +24 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/internal.d.ts +26 -0
- package/dist/policy/internal.d.ts.map +1 -0
- package/dist/policy/internal.js +26 -0
- package/dist/policy/internal.js.map +1 -0
- package/dist/policy/sources/QtiPolicySource.d.ts +146 -0
- package/dist/policy/sources/QtiPolicySource.d.ts.map +1 -0
- package/dist/policy/sources/QtiPolicySource.js +270 -0
- package/dist/policy/sources/QtiPolicySource.js.map +1 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +145 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts.map +1 -1
- package/dist/runtime/SectionRuntimeEngine.js +164 -3
- package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +144 -0
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts.map +1 -0
- package/dist/runtime/adapter/SectionEngineAdapter.js +183 -0
- package/dist/runtime/adapter/SectionEngineAdapter.js.map +1 -0
- package/dist/runtime/adapter/coordinator-bridge.d.ts +93 -0
- package/dist/runtime/adapter/coordinator-bridge.d.ts.map +1 -0
- package/dist/runtime/adapter/coordinator-bridge.js +127 -0
- package/dist/runtime/adapter/coordinator-bridge.js.map +1 -0
- package/dist/runtime/adapter/dom-event-bridge.d.ts +63 -0
- package/dist/runtime/adapter/dom-event-bridge.d.ts.map +1 -0
- package/dist/runtime/adapter/dom-event-bridge.js +95 -0
- package/dist/runtime/adapter/dom-event-bridge.js.map +1 -0
- package/dist/runtime/adapter/framework-error-bridge.d.ts +37 -0
- package/dist/runtime/adapter/framework-error-bridge.d.ts.map +1 -0
- package/dist/runtime/adapter/framework-error-bridge.js +47 -0
- package/dist/runtime/adapter/framework-error-bridge.js.map +1 -0
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +32 -0
- package/dist/runtime/adapter/instrumentation-bridge.d.ts.map +1 -0
- package/dist/runtime/adapter/instrumentation-bridge.js +39 -0
- package/dist/runtime/adapter/instrumentation-bridge.js.map +1 -0
- package/dist/runtime/adapter/subscriber-fanout.d.ts +35 -0
- package/dist/runtime/adapter/subscriber-fanout.d.ts.map +1 -0
- package/dist/runtime/adapter/subscriber-fanout.js +60 -0
- package/dist/runtime/adapter/subscriber-fanout.js.map +1 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +52 -0
- package/dist/runtime/core/SectionEngineCore.d.ts.map +1 -0
- package/dist/runtime/core/SectionEngineCore.js +81 -0
- package/dist/runtime/core/SectionEngineCore.js.map +1 -0
- package/dist/runtime/core/cohort.d.ts +40 -0
- package/dist/runtime/core/cohort.d.ts.map +1 -0
- package/dist/runtime/core/cohort.js +49 -0
- package/dist/runtime/core/cohort.js.map +1 -0
- package/dist/runtime/core/engine-input.d.ts +114 -0
- package/dist/runtime/core/engine-input.d.ts.map +1 -0
- package/dist/runtime/core/engine-input.js +19 -0
- package/dist/runtime/core/engine-input.js.map +1 -0
- package/dist/runtime/core/engine-output.d.ts +62 -0
- package/dist/runtime/core/engine-output.d.ts.map +1 -0
- package/dist/runtime/core/engine-output.js +27 -0
- package/dist/runtime/core/engine-output.js.map +1 -0
- package/dist/runtime/core/engine-readiness.d.ts +49 -0
- package/dist/runtime/core/engine-readiness.d.ts.map +1 -0
- package/dist/runtime/core/engine-readiness.js +47 -0
- package/dist/runtime/core/engine-readiness.js.map +1 -0
- package/dist/runtime/core/engine-resolver.d.ts +172 -0
- package/dist/runtime/core/engine-resolver.d.ts.map +1 -0
- package/dist/runtime/core/engine-resolver.js +170 -0
- package/dist/runtime/core/engine-resolver.js.map +1 -0
- package/dist/runtime/core/engine-stage-derivation.d.ts +19 -0
- package/dist/runtime/core/engine-stage-derivation.d.ts.map +1 -0
- package/dist/runtime/core/engine-stage-derivation.js +30 -0
- package/dist/runtime/core/engine-stage-derivation.js.map +1 -0
- package/dist/runtime/core/engine-state.d.ts +83 -0
- package/dist/runtime/core/engine-state.d.ts.map +1 -0
- package/dist/runtime/core/engine-state.js +49 -0
- package/dist/runtime/core/engine-state.js.map +1 -0
- package/dist/runtime/core/engine-transition.d.ts +49 -0
- package/dist/runtime/core/engine-transition.d.ts.map +1 -0
- package/dist/runtime/core/engine-transition.js +261 -0
- package/dist/runtime/core/engine-transition.js.map +1 -0
- package/dist/runtime/engine-context.d.ts +40 -0
- package/dist/runtime/engine-context.d.ts.map +1 -0
- package/dist/runtime/engine-context.js +32 -0
- package/dist/runtime/engine-context.js.map +1 -0
- package/dist/runtime/engine.d.ts +24 -0
- package/dist/runtime/engine.d.ts.map +1 -0
- package/dist/runtime/engine.js +24 -0
- package/dist/runtime/engine.js.map +1 -0
- package/dist/runtime/internal.d.ts +44 -0
- package/dist/runtime/internal.d.ts.map +1 -0
- package/dist/runtime/internal.js +46 -0
- package/dist/runtime/internal.js.map +1 -0
- package/dist/runtime/runtime-id.d.ts +8 -0
- package/dist/runtime/runtime-id.d.ts.map +1 -0
- package/dist/runtime/runtime-id.js +10 -0
- package/dist/runtime/runtime-id.js.map +1 -0
- package/dist/runtime/section-runtime-engine-host-context.d.ts +74 -0
- package/dist/runtime/section-runtime-engine-host-context.d.ts.map +1 -0
- package/dist/runtime/section-runtime-engine-host-context.js +96 -0
- package/dist/runtime/section-runtime-engine-host-context.js.map +1 -0
- package/dist/runtime/stage-emit-gate.d.ts +93 -0
- package/dist/runtime/stage-emit-gate.d.ts.map +1 -0
- package/dist/runtime/stage-emit-gate.js +83 -0
- package/dist/runtime/stage-emit-gate.js.map +1 -0
- package/dist/services/SSMLExtractor.d.ts.map +1 -1
- package/dist/services/SSMLExtractor.js +189 -2
- package/dist/services/SSMLExtractor.js.map +1 -1
- package/dist/services/TTSService.d.ts +7 -0
- package/dist/services/TTSService.d.ts.map +1 -1
- package/dist/services/TTSService.js +15 -0
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ToolRegistry.d.ts.map +1 -1
- package/dist/services/ToolRegistry.js +30 -0
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/ToolkitCoordinator.d.ts +264 -6
- package/dist/services/ToolkitCoordinator.d.ts.map +1 -1
- package/dist/services/ToolkitCoordinator.js +350 -32
- package/dist/services/ToolkitCoordinator.js.map +1 -1
- package/dist/services/framework-error-bus.d.ts +73 -0
- package/dist/services/framework-error-bus.d.ts.map +1 -0
- package/dist/services/framework-error-bus.js +68 -0
- package/dist/services/framework-error-bus.js.map +1 -0
- package/dist/services/framework-error.d.ts +36 -1
- package/dist/services/framework-error.d.ts.map +1 -1
- package/dist/services/framework-error.js +37 -0
- package/dist/services/framework-error.js.map +1 -1
- package/dist/services/interfaces.d.ts +85 -0
- package/dist/services/interfaces.d.ts.map +1 -1
- package/dist/services/interfaces.js.map +1 -1
- package/dist/services/tool-config-validation.js +1 -1
- package/dist/services/tool-config-validation.js.map +1 -1
- package/dist/services/tools-config-normalizer.d.ts +24 -1
- package/dist/services/tools-config-normalizer.d.ts.map +1 -1
- package/dist/services/tools-config-normalizer.js +13 -1
- package/dist/services/tools-config-normalizer.js.map +1 -1
- package/dist/services/tts-control-events.d.ts +14 -0
- package/dist/services/tts-control-events.d.ts.map +1 -0
- package/dist/services/tts-control-events.js +8 -0
- package/dist/services/tts-control-events.js.map +1 -0
- package/dist/tools/calculators/desmos-provider.js +18 -0
- package/dist/tools/calculators/desmos-provider.js.map +1 -1
- package/dist/tools/client.d.ts +0 -1
- package/dist/tools/client.d.ts.map +1 -1
- package/dist/tools/client.js +0 -2
- package/dist/tools/client.js.map +1 -1
- package/dist/tools/default-tool-module-loaders.d.ts.map +1 -1
- package/dist/tools/default-tool-module-loaders.js +2 -0
- package/dist/tools/default-tool-module-loaders.js.map +1 -1
- package/dist/tools/types.d.ts +0 -26
- package/dist/tools/types.d.ts.map +1 -1
- package/package.json +25 -8
- package/dist/runtime/runtime-event-guards.d.ts +0 -2
- package/dist/runtime/runtime-event-guards.d.ts.map +0 -1
- package/dist/runtime/runtime-event-guards.js +0 -4
- package/dist/runtime/runtime-event-guards.js.map +0 -1
- package/dist/tools/tool-coordinator.d.ts +0 -72
- package/dist/tools/tool-coordinator.d.ts.map +0 -1
- package/dist/tools/tool-coordinator.js +0 -194
- package/dist/tools/tool-coordinator.js.map +0 -1
- package/dist/types/events.d.ts +0 -157
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js +0 -11
- package/dist/types/events.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/runtime/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AACzE,YAAY,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAWrF,OAAO,EACN,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,GAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACN,uBAAuB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,4BAA4B,GACjC,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,oBAAoB,EACpB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC1B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACN,0BAA0B,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,GAChC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,2BAA2B,EAC3B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,KAAK,mBAAmB,GACxB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,GAC3B,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,YAAY,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,OAAO,EACN,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,SAAS,GACd,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EACX,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,GACtB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACX,kBAAkB,EAClB,kBAAkB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EACN,qBAAqB,EACrB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,gCAAgC,EAChC,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,kBAAkB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section runtime engine — **internal** entry point (M7 — Variant C).
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the layered core + adapter surface for advanced hosts that
|
|
5
|
+
* want to construct or inspect engines directly, and for the engine's
|
|
6
|
+
* own tests / benchmarks.
|
|
7
|
+
*
|
|
8
|
+
* **Stability posture.** This module is **not** part of the stable
|
|
9
|
+
* public API. Symbols here are subject to change between minor versions
|
|
10
|
+
* with only a changeset note. Hosts that need long-term stability
|
|
11
|
+
* should depend on the facade (`SectionRuntimeEngine` exported from
|
|
12
|
+
* `./runtime/engine`) instead.
|
|
13
|
+
*
|
|
14
|
+
* The split is intentional:
|
|
15
|
+
* - `./runtime/engine` (PR 3) — narrow, stable facade for common
|
|
16
|
+
* host wiring.
|
|
17
|
+
* - `./runtime/internal` — wide, evolving surface for the kernel,
|
|
18
|
+
* adapter tests, and any host that wants to reach past the facade.
|
|
19
|
+
*
|
|
20
|
+
* The `runtime/engine` and `runtime/internal` package `exports` map
|
|
21
|
+
* entries are added in PR 3 alongside the facade refactor.
|
|
22
|
+
*/
|
|
23
|
+
export { SectionEngineAdapter } from "./adapter/SectionEngineAdapter.js";
|
|
24
|
+
// `FrameworkErrorBus` is the package-internal multi-subscriber bus the
|
|
25
|
+
// engine adapter consumes via the `FrameworkErrorReporter` write port.
|
|
26
|
+
// It is re-exported here (alongside the read/write ports) so advanced
|
|
27
|
+
// hosts that construct an engine instance directly — including the M7
|
|
28
|
+
// PR 5 section-player kernel — can wire a bus without reaching into a
|
|
29
|
+
// deep relative path. The class itself remains "package-internal" in
|
|
30
|
+
// posture (the doc comment on the class explains why); this export is
|
|
31
|
+
// a deliberate, advanced-host escape hatch on the evolving
|
|
32
|
+
// `runtime/internal` surface, never on the stable facade.
|
|
33
|
+
export { FrameworkErrorBus, } from "../services/framework-error-bus.js";
|
|
34
|
+
export { createCoordinatorBridge, } from "./adapter/coordinator-bridge.js";
|
|
35
|
+
export { createDomEventBridge, } from "./adapter/dom-event-bridge.js";
|
|
36
|
+
export { createFrameworkErrorBridge, } from "./adapter/framework-error-bridge.js";
|
|
37
|
+
export { createInstrumentationBridge, } from "./adapter/instrumentation-bridge.js";
|
|
38
|
+
export { createSubscriberFanout, } from "./adapter/subscriber-fanout.js";
|
|
39
|
+
export { SectionEngineCore } from "./core/SectionEngineCore.js";
|
|
40
|
+
export { cohortKey, cohortsEqual, makeCohort, } from "./core/cohort.js";
|
|
41
|
+
export { createInitialEngineState } from "./core/engine-state.js";
|
|
42
|
+
export { phaseToStage } from "./core/engine-stage-derivation.js";
|
|
43
|
+
export { DEFAULT_ASSESSMENT_ID, DEFAULT_ENV, DEFAULT_ISOLATION, DEFAULT_LAZY_INIT, DEFAULT_PLAYER_TYPE, resolveOnFrameworkError, resolveRuntime, resolveSectionEngineRuntimeState, resolveToolsConfig, } from "./core/engine-resolver.js";
|
|
44
|
+
export { createReadinessDetail, resolveReadinessPhase, } from "./core/engine-readiness.js";
|
|
45
|
+
export { transition } from "./core/engine-transition.js";
|
|
46
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.js","sourceRoot":"","sources":["../../src/runtime/internal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAGzE,uEAAuE;AACvE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,sEAAsE;AACtE,qEAAqE;AACrE,sEAAsE;AACtE,2DAA2D;AAC3D,0DAA0D;AAC1D,OAAO,EACN,iBAAiB,GAIjB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACN,uBAAuB,GAKvB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACN,oBAAoB,GAGpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACN,0BAA0B,GAG1B,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,2BAA2B,GAI3B,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACN,sBAAsB,GAGtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,EACN,SAAS,EACT,YAAY,EACZ,UAAU,GAEV,MAAM,kBAAkB,CAAC;AAa1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EACN,qBAAqB,EACrB,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,cAAc,EACd,gCAAgC,EAChC,kBAAkB,GAQlB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACN,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable runtime-instance id generator.
|
|
3
|
+
*
|
|
4
|
+
* Produces a per-runtime id used to scope DOM attribute names and
|
|
5
|
+
* telemetry tags. Single export by design — not a "guards" module.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createRuntimeId(prefix?: string): string;
|
|
8
|
+
//# sourceMappingURL=runtime-id.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-id.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime-id.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,SAAY,GAAG,MAAM,CAE1D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable runtime-instance id generator.
|
|
3
|
+
*
|
|
4
|
+
* Produces a per-runtime id used to scope DOM attribute names and
|
|
5
|
+
* telemetry tags. Single export by design — not a "guards" module.
|
|
6
|
+
*/
|
|
7
|
+
export function createRuntimeId(prefix = "runtime") {
|
|
8
|
+
return `${prefix}-${Math.random().toString(16).slice(2)}-${Date.now()}`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=runtime-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-id.js","sourceRoot":"","sources":["../../src/runtime/runtime-id.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAM,GAAG,SAAS;IACjD,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Custom-Element context for the section runtime engine (M7 PR 6).
|
|
3
|
+
*
|
|
4
|
+
* The toolkit CE renders inside its own Shadow DOM, so Svelte's native
|
|
5
|
+
* `setContext`/`getContext` (used by `engine-context.ts`) cannot bridge
|
|
6
|
+
* the kernel-provided engine reference to the toolkit's component tree.
|
|
7
|
+
* This module exposes a `@pie-players/pie-context` based context that
|
|
8
|
+
* does cross the CE boundary via DOM events:
|
|
9
|
+
*
|
|
10
|
+
* - The kernel (`SectionPlayerLayoutKernel.svelte`) installs a
|
|
11
|
+
* `ContextProvider` for `sectionRuntimeEngineHostContext` on its
|
|
12
|
+
* `host` (the layout CE). The provider value carries the engine
|
|
13
|
+
* reference owned by that kernel mount.
|
|
14
|
+
* - The toolkit CE installs a `ContextConsumer` on its own host. When
|
|
15
|
+
* wrapped by a section player layout, the consumer resolves to the
|
|
16
|
+
* kernel's engine and the toolkit treats it as the active engine
|
|
17
|
+
* for legacy controller-side calls (`register`, `handleContent*`,
|
|
18
|
+
* `initialize`, etc.) and for FSM input dispatch (e.g.
|
|
19
|
+
* `framework-error`). When standalone, no upstream provider
|
|
20
|
+
* responds and the toolkit keeps using its locally-constructed
|
|
21
|
+
* engine.
|
|
22
|
+
*
|
|
23
|
+
* The two engine-context surfaces (`SECTION_RUNTIME_ENGINE_KEY` and
|
|
24
|
+
* this one) are deliberately distinct:
|
|
25
|
+
* - `SECTION_RUNTIME_ENGINE_KEY` (Svelte context) stays scoped to a
|
|
26
|
+
* single component tree (kernel + descendants in the same shadow
|
|
27
|
+
* root) and is the right hook for in-tree consumers.
|
|
28
|
+
* - `sectionRuntimeEngineHostContext` (DOM-event context) is the
|
|
29
|
+
* bridge for cross-CE consumers and only carries data that is
|
|
30
|
+
* safe to share across CE boundaries (a stable engine reference).
|
|
31
|
+
*
|
|
32
|
+
* **Stability.** This export is part of the stable runtime/engine
|
|
33
|
+
* surface; the symbol identity and value shape are part of the
|
|
34
|
+
* cross-CE contract. Renaming or replacing the symbol is a major
|
|
35
|
+
* breaking change. Adding optional fields to the value shape is
|
|
36
|
+
* allowed; required fields are not.
|
|
37
|
+
*/
|
|
38
|
+
import type { SectionRuntimeEngine } from "./SectionRuntimeEngine.js";
|
|
39
|
+
/**
|
|
40
|
+
* Value shape published by the kernel and consumed by the wrapped
|
|
41
|
+
* toolkit CE. Carries only the engine reference today; if more
|
|
42
|
+
* cross-CE shared runtime state is needed later, fields can be added
|
|
43
|
+
* here additively.
|
|
44
|
+
*/
|
|
45
|
+
export interface SectionRuntimeEngineHostContextValue {
|
|
46
|
+
engine: SectionRuntimeEngine;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `pie-context` context key for the cross-CE engine bridge. Uses a
|
|
50
|
+
* `Symbol.for(...)` registry key so providers and consumers in
|
|
51
|
+
* separately-bundled CEs see the same identity.
|
|
52
|
+
*/
|
|
53
|
+
export declare const sectionRuntimeEngineHostContext: {
|
|
54
|
+
__context__: SectionRuntimeEngineHostContextValue;
|
|
55
|
+
};
|
|
56
|
+
export type SectionRuntimeEngineHostContextListener = (value: SectionRuntimeEngineHostContextValue) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Connect a DOM host to the cross-CE engine context with the same
|
|
59
|
+
* provider-retry semantics used elsewhere in the toolkit (initial
|
|
60
|
+
* synchronous request + `context-provider` re-request + 50 ms polling
|
|
61
|
+
* fallback up to 200 attempts ≈ 10 s).
|
|
62
|
+
*
|
|
63
|
+
* The retry mirrors the existing
|
|
64
|
+
* `connectAssessmentToolkitHostRuntimeContext` infrastructure so the
|
|
65
|
+
* timing characteristics of cross-CE handshakes stay consistent across
|
|
66
|
+
* the toolkit's contexts.
|
|
67
|
+
*
|
|
68
|
+
* Returns a cleanup function that disconnects the consumer and clears
|
|
69
|
+
* the retry interval. Standalone toolkits naturally exhaust the retry
|
|
70
|
+
* window without ever resolving and continue using their local
|
|
71
|
+
* engine — that is by design and is not an error.
|
|
72
|
+
*/
|
|
73
|
+
export declare function connectSectionRuntimeEngineHostContext(host: HTMLElement, onValue: SectionRuntimeEngineHostContextListener): () => void;
|
|
74
|
+
//# sourceMappingURL=section-runtime-engine-host-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section-runtime-engine-host-context.d.ts","sourceRoot":"","sources":["../../src/runtime/section-runtime-engine-host-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAOH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,WAAW,oCAAoC;IACpD,MAAM,EAAE,oBAAoB,CAAC;CAC7B;AAED;;;;GAIG;AACH,eAAO,MAAM,+BAA+B;;CAG1C,CAAC;AAEH,MAAM,MAAM,uCAAuC,GAAG,CACrD,KAAK,EAAE,oCAAoC,KACvC,IAAI,CAAC;AAMV;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sCAAsC,CACrD,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,uCAAuC,GAC9C,MAAM,IAAI,CAuCZ"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Custom-Element context for the section runtime engine (M7 PR 6).
|
|
3
|
+
*
|
|
4
|
+
* The toolkit CE renders inside its own Shadow DOM, so Svelte's native
|
|
5
|
+
* `setContext`/`getContext` (used by `engine-context.ts`) cannot bridge
|
|
6
|
+
* the kernel-provided engine reference to the toolkit's component tree.
|
|
7
|
+
* This module exposes a `@pie-players/pie-context` based context that
|
|
8
|
+
* does cross the CE boundary via DOM events:
|
|
9
|
+
*
|
|
10
|
+
* - The kernel (`SectionPlayerLayoutKernel.svelte`) installs a
|
|
11
|
+
* `ContextProvider` for `sectionRuntimeEngineHostContext` on its
|
|
12
|
+
* `host` (the layout CE). The provider value carries the engine
|
|
13
|
+
* reference owned by that kernel mount.
|
|
14
|
+
* - The toolkit CE installs a `ContextConsumer` on its own host. When
|
|
15
|
+
* wrapped by a section player layout, the consumer resolves to the
|
|
16
|
+
* kernel's engine and the toolkit treats it as the active engine
|
|
17
|
+
* for legacy controller-side calls (`register`, `handleContent*`,
|
|
18
|
+
* `initialize`, etc.) and for FSM input dispatch (e.g.
|
|
19
|
+
* `framework-error`). When standalone, no upstream provider
|
|
20
|
+
* responds and the toolkit keeps using its locally-constructed
|
|
21
|
+
* engine.
|
|
22
|
+
*
|
|
23
|
+
* The two engine-context surfaces (`SECTION_RUNTIME_ENGINE_KEY` and
|
|
24
|
+
* this one) are deliberately distinct:
|
|
25
|
+
* - `SECTION_RUNTIME_ENGINE_KEY` (Svelte context) stays scoped to a
|
|
26
|
+
* single component tree (kernel + descendants in the same shadow
|
|
27
|
+
* root) and is the right hook for in-tree consumers.
|
|
28
|
+
* - `sectionRuntimeEngineHostContext` (DOM-event context) is the
|
|
29
|
+
* bridge for cross-CE consumers and only carries data that is
|
|
30
|
+
* safe to share across CE boundaries (a stable engine reference).
|
|
31
|
+
*
|
|
32
|
+
* **Stability.** This export is part of the stable runtime/engine
|
|
33
|
+
* surface; the symbol identity and value shape are part of the
|
|
34
|
+
* cross-CE contract. Renaming or replacing the symbol is a major
|
|
35
|
+
* breaking change. Adding optional fields to the value shape is
|
|
36
|
+
* allowed; required fields are not.
|
|
37
|
+
*/
|
|
38
|
+
import { ContextConsumer, createContext, } from "@pie-players/pie-context";
|
|
39
|
+
/**
|
|
40
|
+
* `pie-context` context key for the cross-CE engine bridge. Uses a
|
|
41
|
+
* `Symbol.for(...)` registry key so providers and consumers in
|
|
42
|
+
* separately-bundled CEs see the same identity.
|
|
43
|
+
*/
|
|
44
|
+
export const sectionRuntimeEngineHostContext = createContext(Symbol.for("pie.sectionRuntimeEngineHostContext"));
|
|
45
|
+
/**
|
|
46
|
+
* Connect a DOM host to the cross-CE engine context with the same
|
|
47
|
+
* provider-retry semantics used elsewhere in the toolkit (initial
|
|
48
|
+
* synchronous request + `context-provider` re-request + 50 ms polling
|
|
49
|
+
* fallback up to 200 attempts ≈ 10 s).
|
|
50
|
+
*
|
|
51
|
+
* The retry mirrors the existing
|
|
52
|
+
* `connectAssessmentToolkitHostRuntimeContext` infrastructure so the
|
|
53
|
+
* timing characteristics of cross-CE handshakes stay consistent across
|
|
54
|
+
* the toolkit's contexts.
|
|
55
|
+
*
|
|
56
|
+
* Returns a cleanup function that disconnects the consumer and clears
|
|
57
|
+
* the retry interval. Standalone toolkits naturally exhaust the retry
|
|
58
|
+
* window without ever resolving and continue using their local
|
|
59
|
+
* engine — that is by design and is not an error.
|
|
60
|
+
*/
|
|
61
|
+
export function connectSectionRuntimeEngineHostContext(host, onValue) {
|
|
62
|
+
let hasValue = false;
|
|
63
|
+
const consumer = new ContextConsumer(host, {
|
|
64
|
+
context: sectionRuntimeEngineHostContext,
|
|
65
|
+
subscribe: true,
|
|
66
|
+
onValue: (value) => {
|
|
67
|
+
hasValue = true;
|
|
68
|
+
onValue(value);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
consumer.connect();
|
|
72
|
+
const onContextProvider = (event) => {
|
|
73
|
+
if (event.context !==
|
|
74
|
+
sectionRuntimeEngineHostContext) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
consumer.requestValue();
|
|
78
|
+
};
|
|
79
|
+
host.addEventListener("context-provider", onContextProvider);
|
|
80
|
+
let attempts = 0;
|
|
81
|
+
const maxAttempts = 200;
|
|
82
|
+
const retryTimer = globalThis.setInterval(() => {
|
|
83
|
+
if (hasValue || attempts >= maxAttempts) {
|
|
84
|
+
globalThis.clearInterval(retryTimer);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
attempts += 1;
|
|
88
|
+
consumer.requestValue();
|
|
89
|
+
}, 50);
|
|
90
|
+
return () => {
|
|
91
|
+
globalThis.clearInterval(retryTimer);
|
|
92
|
+
host.removeEventListener("context-provider", onContextProvider);
|
|
93
|
+
consumer.disconnect();
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=section-runtime-engine-host-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section-runtime-engine-host-context.js","sourceRoot":"","sources":["../../src/runtime/section-runtime-engine-host-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EACN,eAAe,EACf,aAAa,GAEb,MAAM,0BAA0B,CAAC;AAalC;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAC3C,aAAa,CACZ,MAAM,CAAC,GAAG,CAAC,qCAAqC,CAAC,CACjD,CAAC;AAUH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sCAAsC,CACrD,IAAiB,EACjB,OAAgD;IAEhD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE;QAC1C,OAAO,EAAE,+BAA+B;QACxC,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAClB,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC;KACD,CAAC,CAAC;IACH,QAAQ,CAAC,OAAO,EAAE,CAAC;IAEnB,MAAM,iBAAiB,GAAG,CAAC,KAA+B,EAAE,EAAE;QAC7D,IACC,KAAK,CAAC,OAAO;YACZ,+BAA6D,EAC7D,CAAC;YACF,OAAO;QACR,CAAC;QACD,QAAQ,CAAC,YAAY,EAAE,CAAC;IACzB,CAAC,CAAC;IACF,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;IAE7D,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,WAAW,GAAG,GAAG,CAAC;IACxB,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,EAAE;QAC9C,IAAI,QAAQ,IAAI,QAAQ,IAAI,WAAW,EAAE,CAAC;YACzC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YACrC,OAAO;QACR,CAAC;QACD,QAAQ,IAAI,CAAC,CAAC;QACd,QAAQ,CAAC,YAAY,EAAE,CAAC;IACzB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,GAAG,EAAE;QACX,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;QAChE,QAAQ,CAAC,UAAU,EAAE,CAAC;IACvB,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage-emit suppression gate (M7 PR 6).
|
|
3
|
+
*
|
|
4
|
+
* `PieAssessmentToolkit.svelte` builds a `createStageTracker(...)` whose
|
|
5
|
+
* `emit` callback dispatches the toolkit CE's `pie-stage-change` DOM
|
|
6
|
+
* event and invokes the runtime-tier `onStageChange` callback. PR 6
|
|
7
|
+
* introduces the wrapped/standalone branch:
|
|
8
|
+
*
|
|
9
|
+
* - **Standalone** (no upstream `SectionRuntimeEngine` provider on
|
|
10
|
+
* the layout CE host): emit + `onStageChange` fire as before.
|
|
11
|
+
* - **Wrapped** (kernel publishes its engine via
|
|
12
|
+
* `sectionRuntimeEngineHostContext` and the toolkit consumer
|
|
13
|
+
* resolves it): emit + `onStageChange` are suppressed on the
|
|
14
|
+
* toolkit CE, because the kernel's engine already emits the
|
|
15
|
+
* canonical `pie-stage-change` chain on the layout CE host and
|
|
16
|
+
* invokes the runtime-tier callback. Without suppression the
|
|
17
|
+
* toolkit CE would also dispatch its own event, which bubbles
|
|
18
|
+
* through `composed: true` to the layout CE host and produces a
|
|
19
|
+
* duplicate emission for outside listeners.
|
|
20
|
+
*
|
|
21
|
+
* The internal `stageTracker` latch state advances **before** this
|
|
22
|
+
* helper is reached (the latch is updated inside
|
|
23
|
+
* `createStageTracker.enter` prior to `opts.emit(...)`), so suppression
|
|
24
|
+
* here only short-circuits the externally-visible side effects. The
|
|
25
|
+
* toolkit's own readiness path (`waitUntilReady` / `engine-ready` /
|
|
26
|
+
* `interactive`) keeps working in standalone mode and degenerates into
|
|
27
|
+
* a series of suppressed emits in wrapped mode without losing any
|
|
28
|
+
* latch transitions.
|
|
29
|
+
*
|
|
30
|
+
* Splitting this helper out of the inline `emit:` closure in
|
|
31
|
+
* `PieAssessmentToolkit.svelte` lets us pin the suppression branch in a
|
|
32
|
+
* unit test without mounting the toolkit CE — see
|
|
33
|
+
* `tests/runtime/stage-emit-gate.test.ts`. The closure in the toolkit
|
|
34
|
+
* passes thunks for `isSuppressed` and `getOnStageChange` so the live
|
|
35
|
+
* Svelte reactive variables (`upstreamEngine`, `onStageChange`) are
|
|
36
|
+
* read at emit time, not captured at construction time. This keeps the
|
|
37
|
+
* pre-PR-6 behavior of always reading the latest `onStageChange` prop
|
|
38
|
+
* value (cohort change, host swap, etc.) intact.
|
|
39
|
+
*
|
|
40
|
+
* NOT a public surface: this helper is internal to the toolkit and is
|
|
41
|
+
* not exported from `runtime/engine.ts`. It only exists to make the
|
|
42
|
+
* gate testable.
|
|
43
|
+
*/
|
|
44
|
+
import type { StageChangeDetail } from "@pie-players/pie-players-shared/pie";
|
|
45
|
+
export type StageOnChangeHandler = (detail: StageChangeDetail) => void;
|
|
46
|
+
export interface StageEmitGateContext {
|
|
47
|
+
/**
|
|
48
|
+
* Reads the current suppression flag. Implemented as a thunk so
|
|
49
|
+
* the reactive Svelte `$state(upstreamEngine)` is read at emit
|
|
50
|
+
* time. Return `true` to suppress; `false` to fire.
|
|
51
|
+
*/
|
|
52
|
+
isSuppressed: () => boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Dispatches the `pie-stage-change` DOM event on the toolkit's
|
|
55
|
+
* CE host. In `PieAssessmentToolkit.svelte` this is the
|
|
56
|
+
* Svelte-generated `emit("pie-stage-change", detail)` helper.
|
|
57
|
+
*/
|
|
58
|
+
dispatchDomEvent: (detail: StageChangeDetail) => void;
|
|
59
|
+
/**
|
|
60
|
+
* Reads the current `onStageChange` runtime-tier callback. Thunk
|
|
61
|
+
* so the latest reassigned handler is invoked, not whichever
|
|
62
|
+
* handler was current at construction time.
|
|
63
|
+
*/
|
|
64
|
+
getOnStageChange: () => StageOnChangeHandler | null | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Optional logger for handler errors. Defaults to `console.error`
|
|
67
|
+
* with the same prefix the toolkit used pre-PR-6 so test output
|
|
68
|
+
* matches production logs.
|
|
69
|
+
*/
|
|
70
|
+
logHandlerError?: (error: unknown) => void;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Run the toolkit's stage emit pipeline with the suppression gate
|
|
74
|
+
* applied.
|
|
75
|
+
*
|
|
76
|
+
* - When `isSuppressed()` returns `true`, the helper returns
|
|
77
|
+
* immediately with neither side effect.
|
|
78
|
+
* - Otherwise it dispatches the `pie-stage-change` DOM event first,
|
|
79
|
+
* then invokes `onStageChange(detail)` (preserving the
|
|
80
|
+
* "DOM-event-then-callback" ordering pre-PR-6 consumers depend
|
|
81
|
+
* on).
|
|
82
|
+
* - A throwing `onStageChange` handler does not interrupt the DOM
|
|
83
|
+
* event (already fired) and does not propagate up to
|
|
84
|
+
* `stageTracker.enter` (latch state already advanced); the error
|
|
85
|
+
* is logged and swallowed, matching pre-PR-6 behavior.
|
|
86
|
+
*
|
|
87
|
+
* Returns `true` if the emit pipeline ran (i.e. it was not
|
|
88
|
+
* suppressed); `false` if it was suppressed. Tests use the return
|
|
89
|
+
* value to assert the gate's decision in isolation from the side
|
|
90
|
+
* effects.
|
|
91
|
+
*/
|
|
92
|
+
export declare function runStageEmitWithSuppression(context: StageEmitGateContext, detail: StageChangeDetail): boolean;
|
|
93
|
+
//# sourceMappingURL=stage-emit-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-emit-gate.d.ts","sourceRoot":"","sources":["../../src/runtime/stage-emit-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACpC;;;;OAIG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC;IAE5B;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAEtD;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,oBAAoB,GAAG,IAAI,GAAG,SAAS,CAAC;IAEhE;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAC1C,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,iBAAiB,GACvB,OAAO,CAcT"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage-emit suppression gate (M7 PR 6).
|
|
3
|
+
*
|
|
4
|
+
* `PieAssessmentToolkit.svelte` builds a `createStageTracker(...)` whose
|
|
5
|
+
* `emit` callback dispatches the toolkit CE's `pie-stage-change` DOM
|
|
6
|
+
* event and invokes the runtime-tier `onStageChange` callback. PR 6
|
|
7
|
+
* introduces the wrapped/standalone branch:
|
|
8
|
+
*
|
|
9
|
+
* - **Standalone** (no upstream `SectionRuntimeEngine` provider on
|
|
10
|
+
* the layout CE host): emit + `onStageChange` fire as before.
|
|
11
|
+
* - **Wrapped** (kernel publishes its engine via
|
|
12
|
+
* `sectionRuntimeEngineHostContext` and the toolkit consumer
|
|
13
|
+
* resolves it): emit + `onStageChange` are suppressed on the
|
|
14
|
+
* toolkit CE, because the kernel's engine already emits the
|
|
15
|
+
* canonical `pie-stage-change` chain on the layout CE host and
|
|
16
|
+
* invokes the runtime-tier callback. Without suppression the
|
|
17
|
+
* toolkit CE would also dispatch its own event, which bubbles
|
|
18
|
+
* through `composed: true` to the layout CE host and produces a
|
|
19
|
+
* duplicate emission for outside listeners.
|
|
20
|
+
*
|
|
21
|
+
* The internal `stageTracker` latch state advances **before** this
|
|
22
|
+
* helper is reached (the latch is updated inside
|
|
23
|
+
* `createStageTracker.enter` prior to `opts.emit(...)`), so suppression
|
|
24
|
+
* here only short-circuits the externally-visible side effects. The
|
|
25
|
+
* toolkit's own readiness path (`waitUntilReady` / `engine-ready` /
|
|
26
|
+
* `interactive`) keeps working in standalone mode and degenerates into
|
|
27
|
+
* a series of suppressed emits in wrapped mode without losing any
|
|
28
|
+
* latch transitions.
|
|
29
|
+
*
|
|
30
|
+
* Splitting this helper out of the inline `emit:` closure in
|
|
31
|
+
* `PieAssessmentToolkit.svelte` lets us pin the suppression branch in a
|
|
32
|
+
* unit test without mounting the toolkit CE — see
|
|
33
|
+
* `tests/runtime/stage-emit-gate.test.ts`. The closure in the toolkit
|
|
34
|
+
* passes thunks for `isSuppressed` and `getOnStageChange` so the live
|
|
35
|
+
* Svelte reactive variables (`upstreamEngine`, `onStageChange`) are
|
|
36
|
+
* read at emit time, not captured at construction time. This keeps the
|
|
37
|
+
* pre-PR-6 behavior of always reading the latest `onStageChange` prop
|
|
38
|
+
* value (cohort change, host swap, etc.) intact.
|
|
39
|
+
*
|
|
40
|
+
* NOT a public surface: this helper is internal to the toolkit and is
|
|
41
|
+
* not exported from `runtime/engine.ts`. It only exists to make the
|
|
42
|
+
* gate testable.
|
|
43
|
+
*/
|
|
44
|
+
const defaultLogHandlerError = (error) => {
|
|
45
|
+
console.error("[pie-assessment-toolkit] onStageChange handler threw", error);
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Run the toolkit's stage emit pipeline with the suppression gate
|
|
49
|
+
* applied.
|
|
50
|
+
*
|
|
51
|
+
* - When `isSuppressed()` returns `true`, the helper returns
|
|
52
|
+
* immediately with neither side effect.
|
|
53
|
+
* - Otherwise it dispatches the `pie-stage-change` DOM event first,
|
|
54
|
+
* then invokes `onStageChange(detail)` (preserving the
|
|
55
|
+
* "DOM-event-then-callback" ordering pre-PR-6 consumers depend
|
|
56
|
+
* on).
|
|
57
|
+
* - A throwing `onStageChange` handler does not interrupt the DOM
|
|
58
|
+
* event (already fired) and does not propagate up to
|
|
59
|
+
* `stageTracker.enter` (latch state already advanced); the error
|
|
60
|
+
* is logged and swallowed, matching pre-PR-6 behavior.
|
|
61
|
+
*
|
|
62
|
+
* Returns `true` if the emit pipeline ran (i.e. it was not
|
|
63
|
+
* suppressed); `false` if it was suppressed. Tests use the return
|
|
64
|
+
* value to assert the gate's decision in isolation from the side
|
|
65
|
+
* effects.
|
|
66
|
+
*/
|
|
67
|
+
export function runStageEmitWithSuppression(context, detail) {
|
|
68
|
+
if (context.isSuppressed()) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
context.dispatchDomEvent(detail);
|
|
72
|
+
const handler = context.getOnStageChange();
|
|
73
|
+
if (handler) {
|
|
74
|
+
try {
|
|
75
|
+
handler(detail);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
(context.logHandlerError ?? defaultLogHandlerError)(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=stage-emit-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-emit-gate.js","sourceRoot":"","sources":["../../src/runtime/stage-emit-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAoCH,MAAM,sBAAsB,GAAG,CAAC,KAAc,EAAQ,EAAE;IACvD,OAAO,CAAC,KAAK,CAAC,sDAAsD,EAAE,KAAK,CAAC,CAAC;AAC9E,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,2BAA2B,CAC1C,OAA6B,EAC7B,MAAyB;IAEzB,IAAI,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAC3C,IAAI,OAAO,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,OAAO,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,CAAC,OAAO,CAAC,eAAe,IAAI,sBAAsB,CAAC,CAAC,KAAK,CAAC,CAAC;QAC5D,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SSMLExtractor.d.ts","sourceRoot":"","sources":["../../src/services/SSMLExtractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACX,oBAAoB,EACpB,YAAY,EAEZ,MAAM,uCAAuC,CAAC;AAU/C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,aAAa,EAAE,YAAY,CAAC;CAC5B;
|
|
1
|
+
{"version":3,"file":"SSMLExtractor.d.ts","sourceRoot":"","sources":["../../src/services/SSMLExtractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACX,oBAAoB,EACpB,YAAY,EAEZ,MAAM,uCAAuC,CAAC;AAU/C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,aAAa,EAAE,YAAY,CAAC;CAC5B;AAgMD;;;;GAIG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,cAAc,CAAK;IAE3B;;;;;OAKG;IACH,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB;IA6D7D;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAuGzB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGb"}
|
|
@@ -16,6 +16,189 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Part of PIE Assessment Toolkit.
|
|
18
18
|
*/
|
|
19
|
+
/**
|
|
20
|
+
* Allow-listed SSML elements (from the SSML 1.1 spec subset we forward to
|
|
21
|
+
* TTS providers). Anything outside this list is unwrapped during
|
|
22
|
+
* sanitization so we never leak author-supplied scripts, iframes, or
|
|
23
|
+
* arbitrary HTML into the TTS pipeline.
|
|
24
|
+
*/
|
|
25
|
+
const SSML_ALLOWED_TAGS = new Set([
|
|
26
|
+
"speak",
|
|
27
|
+
"break",
|
|
28
|
+
"prosody",
|
|
29
|
+
"emphasis",
|
|
30
|
+
"say-as",
|
|
31
|
+
"sub",
|
|
32
|
+
"mark",
|
|
33
|
+
"phoneme",
|
|
34
|
+
"lang",
|
|
35
|
+
"p",
|
|
36
|
+
"s",
|
|
37
|
+
"voice",
|
|
38
|
+
"audio",
|
|
39
|
+
"lexicon",
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* Allow-listed attributes across SSML elements. Attribute allow-listing is
|
|
43
|
+
* global (not per-tag) because the union is small and consistent across
|
|
44
|
+
* providers.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Tags whose content must be dropped entirely (rather than unwrapped to
|
|
48
|
+
* preserve phrasing text). These are dangerous containers whose text
|
|
49
|
+
* payload could be re-interpreted downstream.
|
|
50
|
+
*/
|
|
51
|
+
const SSML_DROP_FULLY_TAGS = new Set([
|
|
52
|
+
"script",
|
|
53
|
+
"style",
|
|
54
|
+
"iframe",
|
|
55
|
+
"object",
|
|
56
|
+
"embed",
|
|
57
|
+
"foreignobject",
|
|
58
|
+
"noscript",
|
|
59
|
+
"template",
|
|
60
|
+
]);
|
|
61
|
+
const SSML_ALLOWED_ATTRS = new Set([
|
|
62
|
+
"alphabet",
|
|
63
|
+
"ph",
|
|
64
|
+
"time",
|
|
65
|
+
"strength",
|
|
66
|
+
"rate",
|
|
67
|
+
"pitch",
|
|
68
|
+
"volume",
|
|
69
|
+
"name",
|
|
70
|
+
"interpret-as",
|
|
71
|
+
"format",
|
|
72
|
+
"detail",
|
|
73
|
+
"language",
|
|
74
|
+
"xml:lang",
|
|
75
|
+
"lang",
|
|
76
|
+
"gender",
|
|
77
|
+
"src",
|
|
78
|
+
]);
|
|
79
|
+
/**
|
|
80
|
+
* Hosts that must never appear inside an SSML `<audio src>` because they
|
|
81
|
+
* would cause the server-side TTS provider to fetch a private / metadata
|
|
82
|
+
* endpoint on behalf of the request. Mirrors the SchoolCity provider's
|
|
83
|
+
* defense-in-depth check; the SSML-side block is cheap and belt-and-braces.
|
|
84
|
+
*/
|
|
85
|
+
const SSML_PRIVATE_AUDIO_HOSTS = [
|
|
86
|
+
/^localhost$/i,
|
|
87
|
+
/^127(?:\.\d{1,3}){3}$/,
|
|
88
|
+
/^0(?:\.\d{1,3}){3}$/,
|
|
89
|
+
/^10(?:\.\d{1,3}){3}$/,
|
|
90
|
+
/^192\.168(?:\.\d{1,3}){2}$/,
|
|
91
|
+
/^172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2}$/,
|
|
92
|
+
/^169\.254(?:\.\d{1,3}){2}$/,
|
|
93
|
+
/^::1$/,
|
|
94
|
+
/^fe80:/i,
|
|
95
|
+
/^fc00:/i,
|
|
96
|
+
/^fd[0-9a-f]{2}:/i,
|
|
97
|
+
/^metadata\.google\.internal$/i,
|
|
98
|
+
/^metadata\.azure\.internal$/i,
|
|
99
|
+
/^metadata\.packet\.net$/i,
|
|
100
|
+
];
|
|
101
|
+
function isSafeSsmlAudioSrc(raw) {
|
|
102
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
103
|
+
return false;
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = new URL(raw);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const hostname = parsed.hostname.replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
115
|
+
return !SSML_PRIVATE_AUDIO_HOSTS.some((pattern) => pattern.test(hostname));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Sanitize an SSML subtree in place: remove disallowed attributes and
|
|
119
|
+
* replace disallowed elements with their text content (so phrasing order
|
|
120
|
+
* is preserved but no scripts / iframes / unknown tags survive).
|
|
121
|
+
*/
|
|
122
|
+
function sanitizeSsmlElement(element) {
|
|
123
|
+
// Walk children snapshot first because we may replace nodes as we go.
|
|
124
|
+
const children = Array.from(element.children);
|
|
125
|
+
for (const child of children) {
|
|
126
|
+
const tagName = child.tagName.toLowerCase();
|
|
127
|
+
if (SSML_DROP_FULLY_TAGS.has(tagName)) {
|
|
128
|
+
child.remove();
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
sanitizeSsmlElement(child);
|
|
132
|
+
if (!SSML_ALLOWED_TAGS.has(tagName)) {
|
|
133
|
+
const textNode = element.ownerDocument.createTextNode(child.textContent ?? "");
|
|
134
|
+
child.replaceWith(textNode);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Strip disallowed attributes on the surviving node.
|
|
138
|
+
const attrNames = Array.from(element.attributes).map((attr) => attr.name);
|
|
139
|
+
for (const attrName of attrNames) {
|
|
140
|
+
if (!SSML_ALLOWED_ATTRS.has(attrName.toLowerCase())) {
|
|
141
|
+
element.removeAttribute(attrName);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Belt-and-braces: even though `src` is allow-listed, SSML `<audio>`
|
|
145
|
+
// sends its URL to a server-side TTS provider that will dereference
|
|
146
|
+
// it. Refuse non-http(s) schemes and private / cloud-metadata hosts
|
|
147
|
+
// at the SSML boundary so we never forward an SSRF primitive.
|
|
148
|
+
if (element.tagName.toLowerCase() === "audio") {
|
|
149
|
+
const src = element.getAttribute("src");
|
|
150
|
+
if (src !== null && !isSafeSsmlAudioSrc(src)) {
|
|
151
|
+
element.removeAttribute("src");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Serialize a sanitized `<speak>` element back to a minimal SSML string.
|
|
157
|
+
* Uses a manual walker instead of `outerHTML` so that any namespace
|
|
158
|
+
* quirks (e.g. `xmlns` attributes added by the HTML parser) are
|
|
159
|
+
* normalised and disallowed descendants cannot reappear through quirks
|
|
160
|
+
* in the serializer.
|
|
161
|
+
*/
|
|
162
|
+
function serializeSsmlElement(element) {
|
|
163
|
+
const tagName = element.tagName.toLowerCase();
|
|
164
|
+
const attrs = Array.from(element.attributes)
|
|
165
|
+
.filter((attr) => SSML_ALLOWED_ATTRS.has(attr.name.toLowerCase()))
|
|
166
|
+
.map((attr) => ` ${attr.name}="${escapeXmlAttr(attr.value)}"`)
|
|
167
|
+
.join("");
|
|
168
|
+
const childPieces = [];
|
|
169
|
+
for (const node of Array.from(element.childNodes)) {
|
|
170
|
+
if (node.nodeType === 3 /* text */) {
|
|
171
|
+
childPieces.push(escapeXmlText(node.nodeValue ?? ""));
|
|
172
|
+
}
|
|
173
|
+
else if (node.nodeType === 1 /* element */) {
|
|
174
|
+
const childElement = node;
|
|
175
|
+
const childTag = childElement.tagName.toLowerCase();
|
|
176
|
+
if (SSML_DROP_FULLY_TAGS.has(childTag)) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (SSML_ALLOWED_TAGS.has(childTag)) {
|
|
180
|
+
childPieces.push(serializeSsmlElement(childElement));
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
childPieces.push(escapeXmlText(childElement.textContent ?? ""));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return `<${tagName}${attrs}>${childPieces.join("")}</${tagName}>`;
|
|
188
|
+
}
|
|
189
|
+
function escapeXmlText(value) {
|
|
190
|
+
return value
|
|
191
|
+
.replace(/&/g, "&")
|
|
192
|
+
.replace(/</g, "<")
|
|
193
|
+
.replace(/>/g, ">");
|
|
194
|
+
}
|
|
195
|
+
function escapeXmlAttr(value) {
|
|
196
|
+
return value
|
|
197
|
+
.replace(/&/g, "&")
|
|
198
|
+
.replace(/</g, "<")
|
|
199
|
+
.replace(/>/g, ">")
|
|
200
|
+
.replace(/"/g, """);
|
|
201
|
+
}
|
|
19
202
|
/**
|
|
20
203
|
* SSMLExtractor Service
|
|
21
204
|
*
|
|
@@ -107,8 +290,12 @@ export class SSMLExtractor {
|
|
|
107
290
|
try {
|
|
108
291
|
// Generate unique catalog ID
|
|
109
292
|
const catalogId = this.generateCatalogId(idPrefix);
|
|
110
|
-
//
|
|
111
|
-
|
|
293
|
+
// Sanitize before serializing so the SSML forwarded to the TTS
|
|
294
|
+
// provider only contains spec-allowed tags/attributes. This
|
|
295
|
+
// closes an author-content -> TTS-server pipeline that would
|
|
296
|
+
// otherwise accept arbitrary HTML.
|
|
297
|
+
sanitizeSsmlElement(speakEl);
|
|
298
|
+
const ssmlContent = serializeSsmlElement(speakEl);
|
|
112
299
|
// Extract language (check both xml:lang and lang attributes)
|
|
113
300
|
const language = speakEl.getAttribute("xml:lang") ||
|
|
114
301
|
speakEl.getAttribute("lang") ||
|