Provider setup
The entire SDK lives behind one component. Mount <ConsoleProvider> once, above
every part of your app that uses an SDK hook, and you are done — there is no
step two.
// App.tsx — the COMPLETE SDK bootstrap.import { ConsoleProvider } from '@rogue/console-sdk';
export default function App() { return ( <ConsoleProvider> <AppNavigator /> </ConsoleProvider> );}Zero config is the config
Section titled “Zero config is the config”The SDK makes no backend calls and needs no keys, no auth, and no environment
setup. A bare <ConsoleProvider> scans, connects, drives consoles, and reads
results with sensible production defaults already applied — BLE transport,
saved-device persistence (auto-detected async-storage, memory fallback), a
four-device fleet cap, one machine per modality, and auto-reconnect on.
Children render immediately. Readiness is data, not a gate: while storage hydrates, every hook already returns its documented zero state, so it is safe to call hooks from your first render. Read the lifecycle when you need it:
import { useConsoleSdk } from '@rogue/console-sdk';
function StartupGate({ children }: { children: React.ReactNode }) { const { status, error, restart } = useConsoleSdk(); if (status === 'error') { return <ErrorCard error={error} onRetry={restart} />; } return <>{children}</>;}status moves 'starting' → 'ready', or 'starting' → 'error' if saved-device
hydration fails; restart() is the recovery action, legal only at 'error'.
createConsoleConfig() — the inert factory
Section titled “createConsoleConfig() — the inert factory”When you do need options, build a config with createConsoleConfig() and pass
it to the provider. The factory is inert: it validates and freezes its input
and performs zero I/O — no radios spin up, no storage is read, nothing connects.
All of that happens inside the provider, once it mounts.
import { ConsoleProvider, createConsoleConfig } from '@rogue/console-sdk';
const config = createConsoleConfig({ fleet: { maxDevices: 2, onePerModality: true, autoReconnect: { enabled: true }, }, athlete: { weightKg: 84, units: { distance: 'meters', pace: 'per500m' } },});
export default function App() { return ( <ConsoleProvider config={config}> <AppNavigator /> </ConsoleProvider> );}The options that exist are all optional:
transport— the device I/O boundary. Defaults to the BLE transport; swap in the simulated transport for tests and demos (see Testing & mocking).storage— the saved-device persistence adapter. Auto-detects async-storage; falls back to in-memory with a one-time dev warning.fleet— the declarative fleet policy (max devices, one-per-modality, connect timeout, auto-reconnect, and auto-scan cooldowns). See Fleet & auto-reconnect.athlete— weight, height, sex, and default units the firmware uses for calorie computation and its own display. Pushed to consoles on connect.firmware— the OTA channel and manifest URL (the SDK’s only network touch), landing with the firmware surface.telemetryandonError— host-owned sinks the SDK calls out to; see the host-integration guide (landing with that surface).
Define the config module-level (as above) or memoize it — a new config object is a meaningful signal, covered next.
Config identity is the truth
Section titled “Config identity is the truth”There are no setters. The provider treats the identity of the config object
as its key: passing a new ConsoleConfig tears the current runtime down in
order — every device gracefully detaches, any session is abandoned, and the
transport disposes — then a fresh runtime is built from the new config.
// A new config object ⇒ orderly teardown + reconstruction.// Keep the identity stable across renders unless you INTEND to reconfigure.const config = useMemo(() => createConsoleConfig({ fleet: { maxDevices } }), [maxDevices]);Recreating the same config on every render would thrash the whole runtime, so build it once (module scope) or memoize it against the inputs that should actually trigger a reconfiguration.
Provider unmount is disposal
Section titled “Provider unmount is disposal”Connection lifetime is provider lifetime. There is no reset(),
destroyAll(), or disconnect-everything API — none exist. When the provider
unmounts, the runtime runs its ordered teardown: connected devices detach,
sessions abandon, the transport releases the radio. Mount the provider at the
root of the subtree whose lifetime should own the connections, and let React’s
tree do the cleanup.
Reference
Section titled “Reference”ConsoleProvider·ConsoleProviderPropscreateConsoleConfig·ConsoleConfigOptions·ConsoleConfiguseConsoleSdk·ConsoleSdkResult- Why it works this way: Architecture.