diff --git a/CHANGELOG.md b/CHANGELOG.md index ebff20e..46e00a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi ## [Unreleased] ### Changed +- **Namespace migration surface.** Extracted Rehearser and Audiobook modules now publish parse, stage, voice-picker, + and persistence APIs through `window.TTVC` while retaining legacy globals for the ongoing migration. - **CI frontend gate.** The manifest-driven JavaScript syntax and top-level declaration collision check now runs in the SonarQube quality workflow, alongside Python compilation, regressions, and the production bundle build. - **Structured request correlation.** API and MCP requests now receive a bounded `X-Request-ID` and emit sanitized diff --git a/TODO.md b/TODO.md index 0c145c7..409374e 100644 --- a/TODO.md +++ b/TODO.md @@ -93,6 +93,7 @@ architecture change: the larger Audiobook/Rehearser/style split. duration logs; route-specific logs retain provider/job context without request bodies. - [x] **L — Add linting and duplicate-function checks.** The manifest-driven frontend syntax/declaration gate now runs locally and in the SonarQube quality workflow alongside the existing Python and bundle checks. +- [x] Expose extracted Rehearser and Audiobook parser APIs through the `window.TTVC` namespace bridge. ### P2 — after behavior and safety stabilize diff --git a/VERSION b/VERSION index f3d13e4..4dc8bed 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.24.29 +1.24.30 diff --git a/static/index.html b/static/index.html index 895ab2a..d7bc86e 100644 --- a/static/index.html +++ b/static/index.html @@ -10,7 +10,7 @@ - + @@ -27,7 +27,7 @@ - + @@ -392,7 +392,7 @@ window.toggleNavTree = function(treeId, chevronId) { - + diff --git a/static/js/audiobook-parse.js b/static/js/audiobook-parse.js index db2318a..60bfafe 100644 --- a/static/js/audiobook-parse.js +++ b/static/js/audiobook-parse.js @@ -23,3 +23,7 @@ const AB_PERSON_NOUNS = new Set(['Mann','Frau','Junge','Mädchen','Alte','Alter' 'Bauer','Priester','Priesterin','Nachbar','Nachbarin','Sklave','Sklavin','Verweser','Inquisitor','General','König','Königin', 'Prinz','Prinzessin','Fürst','Fürstin','Baron','Baronin','Bote','Diener','Dienerin','Knabe','Kind','Reiter','Reiterin', 'Bogenschütze','Schmied','Schmiedin','Heiler','Heilerin','Gelehrte','Gelehrter','Kapitän','Anführer','Anführerin']); + +window.TTVC = window.TTVC || {}; +window.TTVC.audiobook = window.TTVC.audiobook || {}; +window.TTVC.audiobook.parse = { audiobookHasDialogue, audiobookDehyphenate }; diff --git a/static/js/rehearser-library.js b/static/js/rehearser-library.js index 2367dd1..ea81249 100644 --- a/static/js/rehearser-library.js +++ b/static/js/rehearser-library.js @@ -57,3 +57,6 @@ function _rehIdbGetAll() { } catch (e) { console.warn('[rehearser] migration skipped:', e); } })(); window.rehDbGetById = rehDbGetById; +window.TTVC = window.TTVC || {}; +window.TTVC.rehearser = window.TTVC.rehearser || {}; +window.TTVC.rehearser.library = { rehDbGetAll, rehDbGetById, rehDbPut, rehDbDelete }; diff --git a/static/js/rehearser-parse.js b/static/js/rehearser-parse.js index 3d2a8bc..0ebb1bf 100644 --- a/static/js/rehearser-parse.js +++ b/static/js/rehearser-parse.js @@ -192,3 +192,6 @@ function detectCharacters(lines) { return cast; } +window.TTVC = window.TTVC || {}; +window.TTVC.rehearser = window.TTVC.rehearser || {}; +window.TTVC.rehearser.parse = { parseScript, detectCharacters }; diff --git a/static/js/rehearser-stage.js b/static/js/rehearser-stage.js index 4884198..a084b31 100644 --- a/static/js/rehearser-stage.js +++ b/static/js/rehearser-stage.js @@ -99,3 +99,7 @@ function renderCastStrip() { $('reh-font-inc')?.addEventListener('click', () => rehStageFontStep(0.1)); $('reh-font-dec')?.addEventListener('click', () => rehStageFontStep(-0.1)); $('reh-cast-toggle')?.addEventListener('click', rehToggleCast); + +window.TTVC = window.TTVC || {}; +window.TTVC.rehearser = window.TTVC.rehearser || {}; +window.TTVC.rehearser.stage = { renderCastStrip, rehApplyStageFont, rehApplyCastCollapsed }; diff --git a/static/js/rehearser-voice-picker.js b/static/js/rehearser-voice-picker.js index 4ae9d8d..b1fc453 100644 --- a/static/js/rehearser-voice-picker.js +++ b/static/js/rehearser-voice-picker.js @@ -71,3 +71,7 @@ function castOnlinePanelHtml(sp, c) { `; } + +window.TTVC = window.TTVC || {}; +window.TTVC.rehearser = window.TTVC.rehearser || {}; +window.TTVC.rehearser.voicePicker = { castOnlinePanelHtml, preview: _rehAudition, stopPreview: _rehStopAudition }; diff --git a/tests/rehearser.spec.js b/tests/rehearser.spec.js index b6d3d7f..8c9d67b 100644 --- a/tests/rehearser.spec.js +++ b/tests/rehearser.spec.js @@ -31,6 +31,11 @@ test('parses a screenplay and builds the cast', async ({ page }) => { await page.waitForSelector('#app-skeleton', { state: 'detached', timeout: 15_000 }); await navTo(page, 's-rehearser'); await page.waitForFunction(() => typeof window.navRehearserPhase === 'function', null, { timeout: 15_000 }); + await expect.poll(() => page.evaluate(() => Boolean( + window.TTVC?.rehearser?.parse?.parseScript && + window.TTVC?.rehearser?.stage?.renderCastStrip && + window.TTVC?.rehearser?.voicePicker?.castOnlinePanelHtml + ))).toBe(true); await page.evaluate(() => window.navRehearserPhase(1)); // Go to the Cast tab area: paste a script and parse