# src/ — Library Source

Core TypeScript source for `@cloudflare/realtimekit-react-native`. Thin React Native bridge over `@cloudflare/realtimekit`.

## FILE MAP

| File | Lines | Role |
|------|-------|------|
| `index.tsx` | 87 | **Entry point**. Side-effect imports: registers WebRTC globals, patches `navigator`, polyfills crypto/URL/encoding. Exports hooks + provider. |
| `ReactHooks.tsx` | 99 | `useRealtimeKitClient`, `useRealtimeKitSelector`, `useRTKSelector` (deprecated), `useRealtimeKitMeeting`. Re-exports from ReactContext. |
| `ReactContext.tsx` | 140 | `RealtimeKitProvider` component + `RealtimeKitUpdates` listener manager. Has `@ts-nocheck` — legacy, do not propagate. |
| `LocalMediaHandler.ts` | 1084 | **Largest file.** Audio/video/screenshare track lifecycle, device switching, permission gating, iOS broadcast + Android foreground service integration. |
| `LocalMediaUtils.ts` | 481 | Static helpers: `getUserMedia` with timeout, device enumeration (audio from native, video from WebRTC), `chooseAudioRoute`, video constraints. |
| `LocalMediaInterfaces.ts` | 101 | Type definitions: `MediaDeviceInfo`, `MediaPermission`, constraint types, quality enums. |
| `LocalMediaError.ts` | 9 | Simple `Error` subclass with `code` field. |
| `NativeAudioManager.ts` | 105 | JS wrapper for `InCallManager` native module. Audio routing, speaker control, device queries. Has `@ts-nocheck`. |
| `PermissionHandler.ts` | 227 | Platform-specific permission flow. Custom `PERMISSIONS`/`RESULTS` constants (mirrors react-native-permissions API without the dependency). Recursive retry with 20s timeout. |
| `BackgroundHandler.ts` | 134 | Native timer bridge (`RTKRNBackgroundTimer`). setTimeout/setInterval that survive background. Exported as singleton instance. |
| `AudioSampleHandler.ts` | 65 | Listens to `audioSamples` events from WebRTCModule. Provides `getFloatTimeDomainData` for audio visualization. |
| `DeviceInfo.ts` | 34 | Reads platform info + SDK version. Exported as singleton. |
| `utils/crypto.ts` | 155 | `crypto.getRandomValues` polyfill. Cascading fallbacks: ExpoCrypto → NativeModules.Core → ExpoRandom (SDK 41-44) → ExpoModules (SDK 45+). Insecure Math.random fallback in debug only. |
| `utils/version.ts` | 2 | `SDK_VERSION` constant, auto-generated by `scripts/generate-version.js`. |
| `__tests__/index.test.tsx` | — | Placeholder: `it.todo('write a test')`. |

## KEY PATTERNS

### Navigator Property Injection
The core `@cloudflare/realtimekit` SDK reads implementations from `navigator` at runtime. This package injects them via `Object.defineProperty` in `index.tsx`:
- `navigator.RNLocalMediaHandlerImpl` → `LocalMediaHandler`
- `navigator.RNAudioSampleHandlerImpl` → `AudioSampleHandler`
- `navigator.RNBackgroundTimerImpl` → `BackgroundTimer`
- `navigator.RNDeviceInfoImpl` → `DeviceInfo`

### Audio Device Flow
```
Native event (onAudioDeviceChanged)
  → LocalMediaUtils.onDeviceChange()
  → LocalMediaHandler.onDeviceChange()
  → setupSpeaker() / setupAudioStream()
  → NativeAudioManager.chooseAudioRoute()
```
Audio devices (earpiece, speaker, bluetooth, wired) are enumerated from native layer, NOT from WebRTC `enumerateDevices`. Video devices use WebRTC enumeration.

### Selector Hook Pattern
`useRealtimeKitSelector(fn)` uses `useRef` + `useReducer` for forced re-renders. Two subscription paths:
1. If selected value has `addListener` → subscribes directly to that object
2. Otherwise → subscribes to `RealtimeKitUpdates` global event bus

### Permission Flow
`setupPermissions(audio, video)` → maps to platform constants → `requestMultiplePermissions` → recursive retry with `setInterval` + 20s rejection timeout. Returns `{camera, microphone, bluetooth, location}` states.

## ANTI-PATTERNS TO AVOID

- Do NOT add more `@ts-nocheck` files (ReactContext.tsx and NativeAudioManager.ts are legacy exceptions)
- Do NOT add `eslint-disable` without a tracked issue
- Do NOT export new singletons (BackgroundHandler/DeviceInfo pattern is tech debt)
- Do NOT use `as any` for type suppression — define proper types in LocalMediaInterfaces.ts
- Empty catch at `ReactHooks.tsx:122` (cleanUpEvents function) — should at minimum log
