From c926eeae3ac78ef5fe6bba8fe30f79a55af6b601 Mon Sep 17 00:00:00 2001 From: "Yermie Cohen, MD" Date: Mon, 6 Oct 2025 16:06:49 -0700 Subject: [PATCH 1/2] feat: add react native package --- README.md | 29 ++- docs/react-native/getting-started.md | 120 ++++++++++++ packages/chatkit-react-native/README.md | 122 +++++++++++++ packages/chatkit-react-native/package.json | 73 ++++++++ packages/chatkit-react-native/src/index.ts | 28 +++ .../src/networking/streaming.ts | 132 ++++++++++++++ .../src/polyfills/index.ts | 39 ++++ .../src/realtime/webrtc.ts | 147 +++++++++++++++ .../src/realtime/websocket.ts | 63 +++++++ .../chatkit-react-native/src/types/expo.d.ts | 39 ++++ .../chatkit-react-native/src/types/shims.d.ts | 84 +++++++++ .../src/ui/ChatComposer.tsx | 149 +++++++++++++++ .../chatkit-react-native/src/ui/ChatList.tsx | 171 ++++++++++++++++++ .../src/utils/EventEmitter.ts | 47 +++++ .../src/voice/useVoiceSession.ts | 137 ++++++++++++++ packages/chatkit-react-native/tsconfig.json | 18 ++ 16 files changed, 1395 insertions(+), 3 deletions(-) create mode 100644 docs/react-native/getting-started.md create mode 100644 packages/chatkit-react-native/README.md create mode 100644 packages/chatkit-react-native/package.json create mode 100644 packages/chatkit-react-native/src/index.ts create mode 100644 packages/chatkit-react-native/src/networking/streaming.ts create mode 100644 packages/chatkit-react-native/src/polyfills/index.ts create mode 100644 packages/chatkit-react-native/src/realtime/webrtc.ts create mode 100644 packages/chatkit-react-native/src/realtime/websocket.ts create mode 100644 packages/chatkit-react-native/src/types/expo.d.ts create mode 100644 packages/chatkit-react-native/src/types/shims.d.ts create mode 100644 packages/chatkit-react-native/src/ui/ChatComposer.tsx create mode 100644 packages/chatkit-react-native/src/ui/ChatList.tsx create mode 100644 packages/chatkit-react-native/src/utils/EventEmitter.ts create mode 100644 packages/chatkit-react-native/src/voice/useVoiceSession.ts create mode 100644 packages/chatkit-react-native/tsconfig.json diff --git a/README.md b/README.md index e657665..10c871a 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,32 @@ Just add the ChatKit component, give it a client token, and customize the chat e }, }); - return ; - } - ``` + return ; + } + ``` + +### React Native (Expo) preview + +Experimental support for Expo and bare React Native apps lives in the `@openai/chatkit-react-native` package. The library ships +streaming HTTP helpers, WebRTC wrappers, voice primitives, and opinionated UI building blocks (`ChatList`, `ChatComposer`). + +- Install the package alongside the recommended polyfills: + + ```bash + pnpm add @openai/chatkit-react-native react-native-polyfill-globals react-native-url-polyfill react-native-get-random-values base-64 + ``` + +- Import the polyfills at the top of your app entry point before rendering any ChatKit component: + + ```ts + import 'react-native-polyfill-globals/auto'; + import 'react-native-url-polyfill/auto'; + import 'react-native-get-random-values'; + import 'base-64'; + ``` + +Read the [React Native getting started guide](docs/react-native/getting-started.md) for details on Expo networking, WebRTC +signalling, voice support, and testing recommendations. ## License diff --git a/docs/react-native/getting-started.md b/docs/react-native/getting-started.md new file mode 100644 index 0000000..7e01eca --- /dev/null +++ b/docs/react-native/getting-started.md @@ -0,0 +1,120 @@ +# React Native (Expo) Support + +This guide captures the minimum setup for adopting `@openai/chatkit-react-native` inside a new or existing React Native project. The instructions assume you are using [Expo](https://docs.expo.dev) with the development build workflow, but also call out fallbacks for bare React Native. + +## 1. Install dependencies + +```bash +pnpm add @openai/chatkit-react-native +pnpm add react-native-polyfill-globals react-native-url-polyfill react-native-get-random-values base-64 +pnpm add expo expo-dev-client expo-av expo-speech expo-file-system expo-document-picker +pnpm add react-native-webrtc +# For bare React Native (non-Expo) projects +pnpm add react-native-fetch-api +``` + +## 2. Configure polyfills + +Add the following imports at the top of your app entry (for example `app/index.tsx` when using Expo Router or `index.js` for bare projects): + +```ts +import 'react-native-polyfill-globals/auto'; +import 'react-native-url-polyfill/auto'; +import 'react-native-get-random-values'; +import 'base-64'; +``` + +Polyfills must run before any ChatKit code executes to ensure `TextEncoder`, `TextDecoder`, `ReadableStream`, `URL`, `crypto.getRandomValues`, `atob` and `btoa` are defined. + +## 3. Streaming HTTP helpers + +`createStreamingFetcher` wraps Expo's `fetch` implementation and falls back to `react-native-fetch-api` for apps not running inside the Expo runtime. It exposes lifecycle hooks that map cleanly onto ChatKit's expectations. + +```ts +import { createStreamingFetcher } from '@openai/chatkit-react-native'; + +const streamingFetch = createStreamingFetcher(); + +const { response } = await streamingFetch( + 'https://api.openai.com/v1/responses', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${process.env.EXPO_PUBLIC_OPENAI_API_KEY}`, + }, + body: JSON.stringify({ + model: 'gpt-4.1-mini', + input: [{ role: 'user', content: 'Hello!' }], + }), + }, + { + onResponseStart: () => console.log('stream started'), + onChunk: (chunk) => console.log('chunk', chunk), + onResponseEnd: () => console.log('stream ended'), + }, +); +``` + +## 4. Realtime via WebRTC + +`createWebRTCSession` bridges [`react-native-webrtc`](https://github.com/react-native-webrtc/react-native-webrtc) with ChatKit's realtime API. Provide a signalling adapter that exchanges offers/answers with your backend. The backend should authenticate with OpenAI and create a WebRTC session on behalf of the device. + +```ts +const session = await createWebRTCSession({ + signalling: { + negotiate: async (offer) => { + const response = await fetch('https://your-server.example.com/negotiate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ offer }), + }); + if (!response.ok) throw new Error('Failed to negotiate'); + return response.json(); + }, + }, + onResponseChunk: (chunk) => console.log('Realtime chunk', chunk), +}); + +await session.start(); +``` + +For server-to-server integrations or for environments where WebRTC is not available, `createWebSocketSession` provides a lightweight wrapper over the standard `WebSocket` implementation. + +## 5. Voice mode + +The `useVoiceSession` hook layers [`expo-av`](https://docs.expo.dev/versions/latest/sdk/av/) for microphone capture with [`expo-speech`](https://docs.expo.dev/versions/latest/sdk/speech/) for text-to-speech output. + +```tsx +const voice = useVoiceSession(); + +return ( + +