Whistle API
    Preparing search index...

    Use the CLI from the installed, lockfile-pinned SDK during build/deployment:

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

    The browser typically serves public/whistle; Node reads a private local directory such as vendor/whistle. A production build should prepare assets before bundling the application. No npm postinstall download is performed.

    Valid files are hash-checked and reused without network access. Corrupt managed files are repaired, unrelated files are preserved, and temporary downloads are verified before atomic rename. manifest.json is published last. --offline never fetches and fails if required model bytes are missing or corrupt. Transient failures have at most three attempts, a 60-second request timeout, and cancellable backoff. Progress goes to stderr. Exit codes: 0 success, 1 operational failure, 2 usage error, 130 SIGINT, 143 SIGTERM where supported.

    Run the installed whistle download --out <directory> during build/deployment. The flat directory includes whistle.cact, needle.js, needle.wasm, both worker bundles, a package.json marking ESM, asset-lock.json, manifest.json, LICENSE, NOTICE, NEEDLE-LICENSE, and WHISTLE-LICENSE. No manual worker/WASM path surgery is needed: use this directory as assetsPath or assetsUrl.

    asset-lock.json schema 1 records the immutable upstream pair, original and adapted loader hashes, header, licenses and model metadata. The build verifies vendored inputs against that lock. The generated manifest.json schema 1 records the SDK version, compatibility ID, and size/SHA-256 of every deployment file except itself. Both adapters compare the supplied manifest with their compiled inventory. Ship a package and assets from the same build; different generated worker hashes are intentionally incompatible even if the upstream pair stayed the same.

    These digests establish consistency with the trusted checked-in lock; they are not a separate publisher signature. Treat the application and static executable code as trusted deployment material. Browser ESM loading does not offer subresource integrity for dynamic imports: the SDK checks loader bytes before importing the static URL, but a server that changes JS between requests is outside this integrity model. Never serve executable assets from an untrusted writable origin. No fetched source is evaluated with eval, Function, or a blob loader.

    CLI renames are atomic per file; the whole directory is not a multi-file transaction. On first-install failure, no completion manifest is created. On interrupted repair, an older manifest may remain; adapters still verify against the installed package, so mismatched files cannot silently load. SIGINT/SIGTERM remove this process's temporary writes. SIGKILL/power loss may leave uniquely named .tmp files; they are never accepted as assets and a later run ignores them. Unrelated files are not deleted. Avoid concurrent deployments to the same output directory; deploy a new directory and switch your application's pointer if zero-downtime upgrades are needed.

    The root entry has no Node imports. Vite production builds are tested from an installed tarball, including a /demo/ base. Default workers use the recognizable new Worker(new URL(..., import.meta.url), { type: 'module' }) pattern. Loader/WASM URLs use module-relative static assets. Other bundlers are not claimed tested. If your build rewrites assets differently, prepare a static directory and pass assetsUrl; workerUrl and wasmUrl are explicit escape hatches. A worker override must run the package's matching protocol/code, not an arbitrary implementation.

    Serve .js as JavaScript and .wasm as application/wasm. Use HTTPS or localhost for Web Crypto, IndexedDB and microphone APIs. The runtime requires WebAssembly SIMD and BigInt integration; it does not use WebGPU or WASM threads. Our browser checks ran with crossOriginIsolated === false: SharedArrayBuffer and COOP/COEP are not required for this pinned engine.

    For a same-origin static application and CLI assets, this tested CSP is sufficient:

    default-src 'self';
    script-src 'self' 'wasm-unsafe-eval';
    worker-src 'self';
    connect-src 'self';
    style-src 'self';
    media-src 'self' blob:;
    

    Apply suitable policy to worker script responses as well as the page. There is no JavaScript unsafe-eval requirement. A policy that prohibits WebAssembly compilation will not work. Default official-model acquisition additionally needs connect-src permission for the pinned Hugging Face URL and its CDN/storage redirect hosts; those third-party hosts can change. Self-host assets when you require a fixed same-origin CSP. Cross-origin mirrors also need CORS. Module workers are normally same-origin, so serve the packaged worker on your application origin.

    IndexedDB stores verified complete bytes by immutable SHA-256. Transactions complete before assets are reported loaded. It is optional: denial, private-mode restrictions, quota exhaustion and eviction cause uncached loading. Cache is per browser origin; there is no global audio/model service. To clear SDK persistence, delete the tiny-stt-whistle-v1 database after disposing active instances. The SDK never persists recordings or transcripts. Cache hits are rehashed before use.

    cache: 'none' disables SDK-managed persistence, not the browser's HTTP cache.

    Offline websites also need their HTML, application bundle, module worker, loader, and self-hosted manifest to remain available. Use your application's service worker or a local static server as appropriate. An HTTP/self-hosted success with external hosts blocked is not proof that an uncached browser can open your site offline.

    Use /node and an explicit local asset directory. The worker reads files directly, verifies all inventory entries, then supplies WASM bytes to the adapted static ESM loader. No file: URL is passed to browser-style fetch. The adapted loader disables its original Node filesystem/process-exit hooks; it still uses the unchanged engine binary. Model bytes are kept alive for the lifetime of the worker.

    Node 22 and 24 are the initial targets. Linux arm64 and macOS arm64 have executed packed-package evidence; Windows is configured in CI but not executed locally. No CommonJS entry, native addon, compiler or Python is required. The npm package has no production dependencies and no postinstall script.

    Release preparation must check publishing access and the whistle executable's potential command-name conflicts. The package identity is already settled as @tiny-stt/whistle. The release workflow publishes the SDK using npm trusted publishing and deploys the documentation and demo to Cloudflare Pages after a matching release tag is pushed and all CI checks pass. Local build and preview commands do not publish or deploy.