/** * OS-native TTS (text-to-speech) adapter battery — shells out to the platform's own speech binary. * * @module @nhtio/adk/batteries/tts/native/adapter * * @remarks * **Node-only.** This adapter synthesizes by shelling out to the operating system's own speech * binary — macOS `say`, Linux `espeak-ng`, or Windows PowerShell `System.Speech` — and reading back * the WAV file it writes. It is model-less: it extends the shared {@link BaseTtsAdapterOptions} * (`voice`/`rate`) but adds NO `model` field. Every `node:*` import is a LAZY dynamic import inside a * method, so constructing and validating the adapter never touches node builtins and unit tests stay * hermetic (zero `child_process`, zero `fs`, zero real files). * * The shell-out and filesystem access are fully injectable: {@link NativeTtsAdapterOptions.executor} * (default: a lazy `node:child_process` `execFile` wrapper with an `AbortController` enforcing the * timeout), {@link NativeTtsAdapterOptions.fs} (default: `node:fs/promises`), plus * {@link NativeTtsAdapterOptions.tmpdir} / {@link NativeTtsAdapterOptions.randomName} seams for the * scratch output path. The flow mirrors the media domain's `soffice` engine — build args, exec, * read the output file, finally clean up — but this engine controls its own output path directly * (it does NOT depend on the media domain's `ScratchWorkspace`). * * Result classification is from the executor's FLAGS, never inferred from exit code or stderr (a * timeout, a signal kill, and a non-zero CLI exit are indistinguishable from those signals alone): * `result.timedOut` → `E_NATIVE_TTS_TIMEOUT` (504); else `result.failed` → * `E_NATIVE_TTS_ENGINE_ERROR` (502). The read-back WAV is hard-validated against the RIFF/WAVE * magic — a payload missing that magic throws `E_NATIVE_TTS_ENGINE_ERROR`. */ import type { GeneratedMediaOutput } from "../_shared/index"; import type { NativeSynthesizeOptions } from "./types"; /** * TTS adapter that shells out to the OS's own speech binary. Reusable: construct once, call * {@link NativeTtsAdapter.synthesize} as many times as needed. * * @remarks * A zero-config `new NativeTtsAdapter()` is valid — it auto-detects the platform from * `process.platform` at `synthesize` time and resolves the default executor / fs / scratch-path * seams lazily. */ export declare class NativeTtsAdapter { #private; /** * Whether this battery is available. `true` whenever a Node `process` is present on a supported * {@link NativeTtsPlatform} — the engine itself is the platform's own binary, so there is no peer * dependency to probe. */ static isAvailable(): boolean; /** * @param options - Constructor options. **All optional**; validated eagerly against * {@link @nhtio/adk/batteries/tts/native!nativeTtsOptionsSchema}. Pass `undefined` for zero-config. * @throws {@link @nhtio/adk/batteries/tts/native!E_INVALID_NATIVE_TTS_OPTIONS} when invalid. */ constructor(options?: unknown); /** Instance availability probe (honours an injected `isAvailable`). */ isAvailable(): boolean; /** No-op. The native engine has nothing to preload — the binary is invoked fresh per call. */ preload(): Promise; /** No-op. The native engine holds no state between calls to reset. */ reset(): void; /** * Synthesizes text into a WAV audio clip. * * @remarks * Resolves the platform (constructor `platform` or `process.platform`), the effective * voice/rate/pitch (per-call overrides ctor), the words-per-minute (for `say`/`espeak-ng`) and * the `-10..10` PowerShell rate (for win32), then shells out via the executor, reads the scratch * WAV back, hard-validates the RIFF/WAVE magic, and unlinks the scratch file in a `finally`. * * @param text - The text to speak. Passed verbatim as the final positional arg / PowerShell literal. * @param opts - Per-call options; each field overrides the constructor default of the same name. * @returns A {@link GeneratedMediaOutput} descriptor with `kind: 'audio'`, `mimeType: 'audio/wav'`, * the WAV bytes, and `filename: 'speech.wav'`. * @throws {@link @nhtio/adk/batteries/tts/native!E_NATIVE_TTS_UNSUPPORTED_PLATFORM} when the * resolved platform is not `darwin`/`linux`/`win32`. * @throws {@link @nhtio/adk/batteries/tts/native!E_NATIVE_TTS_TIMEOUT} when the binary is aborted * for exceeding `timeoutMs` (default 60_000 ms). * @throws {@link @nhtio/adk/batteries/tts/native!E_NATIVE_TTS_ENGINE_ERROR} when the binary fails, * produces no output, or yields bytes that are not a RIFF/WAVE file. */ synthesize(text: string, opts?: NativeSynthesizeOptions): Promise; }