Three-file config module under src/config/:
- schema.ts: RuntimeConfigSchema (directusUrl, liveWsUrl, businessWsUrl,
optional googleMapsKey, env enum). Custom UrlOrAbsolutePath validator
accepts http(s)/ws(s) URLs plus paths starting with /.
- load.ts: loadConfig() fetches /config.json with cache: 'no-store',
safeParse, throws ConfigValidationError on schema failure.
- context.ts: RuntimeConfigContext + useRuntimeConfig() hook (no JSX).
- provider.tsx: RuntimeConfigProvider — loading / ready / error states.
Single retry after 500ms on network failure; renders zod issues on
validation failure for debuggability.
public/config.json: committed dev defaults (relative paths matching the
Vite proxy from 1.3).
src/main.tsx wraps App in <RuntimeConfigProvider>.
README gains a Runtime config section with the schema table.
Deviation: spec sketched provider+hook in one context.tsx. Split into
context.ts (hook only) and provider.tsx (component only) to satisfy
react-refresh/only-export-components without adding an eslint override.