The rejected PR #1110 had a genuinely careful PII-free event design, but shipped three things a local-first app can't: exception autocapture ON (raw tracebacks — home paths, and in this codebase HF tokens out of exception messages — bypassing core.failure.sanitize() entirely), no user consent or disclosure, and 3,069 lines of PostHog wizard scaffolding. This is the same capability with those fixed. core/analytics.py, three rules, each enforced and tested rather than promised: 1. OFF unless the user says yes. TWO gates must both be true: a build-provided POSTHOG_PROJECT_TOKEN *and* the user's analytics_enabled pref, default False. A default install transmits nothing, so "nothing leaves your machine" stays literally true for everyone who doesn't opt in. A broken prefs file fails CLOSED. OMNIVOICE_ANALYTICS_DISABLED=1 is a hard kill switch above both. Withdrawing consent tears the client down immediately — no restart. 2. NO exception autocapture. Explicitly disabled; a test asserts the constructor arg, because the SDK's default is the leak. 3. Metadata ONLY, by allowlist. Every property passes sanitize_properties(), which DROPS any key not on _ALLOWED_PROPS and refuses long strings — so no future caller can leak a take's text, a path, or a voice name by adding a field. text_length is the LENGTH; the text itself has no way through. The person id is a random per-install UUID — not hardware, hostname, or username. UI: Settings → Privacy → "Help improve OmniVoice" states in the panel exactly what is sent, exactly what never is, and that it can be turned off — rather than burying it in a policy. No destination in the build (any source build) → the toggle isn't shown, because an inert switch would be a lie. Docs: README FAQ answers "does OmniVoice collect any data about me?" honestly. Also fixed a bug I'd introduced in my own wiring: the generation event referenced variables not in scope, and the call site's bare `except: pass` swallowed the NameError — so the event would have silently never fired. The call site now logs. 12 tests (default-off / opt-in without token still can't transmit / both gates / kill switch / consent withdrawal / prefs failure fails closed / allowlist drops text+paths+names / long strings refused / autocapture OFF / never raises / random install id). Backend 2936 passed; frontend 1211 passed. Refs #1110 Co-authored-by: mergetest <nizam4103@gmail.com>
React + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Oxc
- @vitejs/plugin-react-swc uses SWC
React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
Expanding the ESLint configuration
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the TS template for information on how to integrate TypeScript and typescript-eslint in your project.