Whistle API
    Preparing search index...

    Run the installed CLI during your build/deployment, then deny outbound networking:

    pnpm exec whistle download --out vendor/whistle
    pnpm exec whistle download --offline --out vendor/whistle

    --offline verifies and reuses files; it cannot acquire a missing model. Load the result with the /node entry point:

    import { createWhistle } from '@tiny-stt/whistle/node';

    /** Call with decoded 16 kHz mono PCM and assets prepared before networking is disabled. */
    export async function transcribeLocally(pcm: Float32Array, assetsPath: string | URL) {
    const whistle = await createWhistle({ assetsPath });
    try {
    return await whistle.transcribe(pcm, { wordTimestamps: true });
    } finally {
    await whistle.dispose();
    }
    }

    assetsPath accepts a local filesystem directory or file: URL, including paths with spaces. Relative paths resolve at factory invocation. HTTP(S) locations are rejected and missing/corrupt files fail explicitly. Initialization, inference and cancellation recovery never fall back to a remote download.

    Each instance owns one worker and retains its model. Calls are FIFO; an active abort terminates blocking WASM and reloads from local assets before surviving requests run. dispose() settles pending work and awaits worker termination, allowing the process to exit. Use try/finally even when inference fails.

    The SDK accepts decoded PCM, not Node Buffer or encoded WAV/MP3 bytes. The repository's Node example in packages/documentation/examples/node includes a small reader for mono 16 kHz PCM16 WAV. General audio format conversion is the host application's responsibility; no native compiler or Python runtime is required by the SDK.

    From the repository root:

    pnpm build
    pnpm assets:prepare
    pnpm example:node

    This transcribes the licensed fixture with timestamps. To supply your own prepared assets and compatible WAV file:

    node packages/documentation/examples/node/transcribe.mjs ./vendor/whistle ./clip.wav
    

    The example imports the public /node entry and disposes its worker in finally:

    import { createWhistle } from '@tiny-stt/whistle/node';
    import { readWav } from './wav.mjs';

    const [assetsPath, file] = process.argv.slice(2);
    if (!assetsPath || !file) {
    console.error('Usage: node transcribe.mjs <assets-directory> <mono-16k-pcm16.wav>');
    process.exitCode = 2;
    } else {
    const whistle = await createWhistle({ assetsPath });
    try {
    console.log(
    JSON.stringify(await whistle.transcribe(readWav(file), { wordTimestamps: true }), null, 2),
    );
    } finally {
    await whistle.dispose();
    }
    }

    Copy both transcribe.mjs and wav.mjs into an application with the SDK installed to run outside this workspace. The WAV reader is deliberately limited to mono, 16 kHz, signed PCM16 audio; it is not a general-purpose audio decoder.