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.