diff --git a/.gitignore b/.gitignore index b5028c58..71d825fb 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ skills-lock.json # Swift / SwiftPM build artifacts .build/ +.smoke-expo-moss/ diff --git a/AGENTS.md b/AGENTS.md index c2cbc8e9..895a91bf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,10 +15,13 @@ sdks/ python/sdk/ — Python SDK (PyPI: moss), Python 3.10+ javascript/sdk/ — JS/TS SDK (npm: @moss-dev/moss), ESM-only elixir/sdk/ — Elixir SDK (Hex: moss) + swift/ — Swift SDK for iOS (wraps Moss.xcframework) + react-native/ — Expo / React Native module (@moss-dev/moss-react-native); iOS native, Android stub examples/ python/ — Standalone Python usage examples javascript/ — Standalone TS usage examples javascript-web/ — Browser/Vite examples (no Node runtime) + react-native/ — Expo usage sketch for @moss-dev/moss-react-native c/ — C binding examples go/ — Standalone Go SDK usage examples bun/ — Bun runtime example @@ -223,6 +226,17 @@ mix deps.get mix test ``` +### React Native / Expo module (`sdks/react-native/`) + +```bash +cd sdks/react-native +npm install +npm run build # tsc → build/ +``` + +iOS links `Moss.xcframework` (downloaded at `pod install` via `ios/scripts/download-moss-xcframework.sh`). +Android is a stub until [#411](https://github.com/usemoss/moss/issues/411). Requires Expo prebuild / a dev client — not Expo Go. + ## Architecture: Two-Layer Design Every SDK has the same two-layer structure: diff --git a/README.md b/README.md index 4281a692..55e09b8f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Moss is a sub-10 ms semantic search runtime built for Conversational AI agents. Hybrid retrieval (semantic + Keyword Search), built-in embeddings, metadata filtering, and a WebAssembly build that runs in the browser - all from a single SDK that embeds in your application. -No network hop on the hot path. No clusters to tune. Point the SDK at Moss Cloud, load your index, and query it in **under 10 ms**. Python, TypeScript, Elixir, and C. +No network hop on the hot path. No clusters to tune. Point the SDK at Moss Cloud, load your index, and query it in **under 10 ms**. Python, TypeScript, Elixir, C, Swift, and React Native / Expo. ![Moss Python walkthrough](https://github.com/user-attachments/assets/d826023d-92d6-49ac-8e5e-81cf04d409c5) @@ -116,7 +116,7 @@ Moss isn't a database! It's a **search runtime**. You don't manage clusters, tun - **Runs in the browser too** - separate WebAssembly SDK ([`@moss-dev/moss-web`](https://www.npmjs.com/package/@moss-dev/moss-web)) for client-side semantic search with no server - **Database connectors** - ingest directly from SQLite, MongoDB, MySQL, and Supabase ([`packages/moss-data-connector/`](packages/moss-data-connector/)) - **CLI** - manage indexes and query from the terminal ([`packages/moss-cli/`](packages/moss-cli/)) -- **SDKs** - Python (3.10+), TypeScript / Node.js (20+), Elixir, and C ([`libmoss`](https://github.com/usemoss/moss/releases)) +- **SDKs** - Python (3.10+), TypeScript / Node.js (20+), Elixir, C ([`libmoss`](https://github.com/usemoss/moss/releases)), Swift (iOS), and React Native / Expo (`@moss-dev/moss-react-native`) - **Framework integrations** - LangChain, DSPy, LlamaIndex, Pipecat, LiveKit, Vapi, ElevenLabs, Strands Agents ## Examples @@ -274,7 +274,7 @@ Full Python SDK source code is available at [`sdks/python/`](sdks/python/). Here's where the community can have the most impact: -- **New SDK bindings** — Swift, Go, Elixir,... +- **New SDK bindings** — Kotlin/Android, Rust,… React Native / Expo module shipped under `sdks/react-native/` - **Framework integrations** — CrewAI, Haystack, AutoGen - **Reranking support** — plug in cross-encoder rerankers - **Doc-parsing connectors** — PDF, DOCX, HTML, Markdown ingestion diff --git a/ROADMAP.md b/ROADMAP.md index 3b116e40..21be99b4 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -92,6 +92,7 @@ These are well-scoped and ready for contributors. Each one has (or will have) a - [ ] **Swift bindings** — for iOS/macOS apps with on-device retrieval ([`good first issue`](https://github.com/usemoss/moss/labels/good%20first%20issue)) - [ ] **Rust bindings** — for performance-critical pipelines ([`good first issue`](https://github.com/usemoss/moss/labels/good%20first%20issue)) - [ ] **Kotlin bindings** — for Android apps and Spring Boot backend services ([`good first issue`](https://github.com/usemoss/moss/labels/good%20first%20issue)) +- [x] **React Native / Expo module** — iOS via `Moss.xcframework` + Expo config plugin (`sdks/react-native/`, `@moss-dev/moss-react-native`); Android pending [#411](https://github.com/usemoss/moss/issues/411) ([#432](https://github.com/usemoss/moss/issues/432)) ### Voice AI Ecosystem diff --git a/examples/react-native/README.md b/examples/react-native/README.md new file mode 100644 index 00000000..cdffedda --- /dev/null +++ b/examples/react-native/README.md @@ -0,0 +1,93 @@ +# React Native / Expo example (Moss) + +Minimal usage sketch for [`@moss-dev/moss-react-native`](../../sdks/react-native/). + +This is not a full Expo app (no `node_modules` committed). Scaffold your own with: + +```bash +npx create-expo-app moss-rn-demo +cd moss-rn-demo +npx expo install @moss-dev/moss-react-native +``` + +Add the plugin in `app.json`: + +```json +{ + "expo": { + "plugins": ["@moss-dev/moss-react-native"] + } +} +``` + +Then: + +```bash +npx expo prebuild +npx expo run:ios +``` + +## Example screen + +```tsx +import { useEffect, useState } from 'react'; +import { Button, ScrollView, Text, View } from 'react-native'; +import { MossClient, type SearchResult } from '@moss-dev/moss-react-native'; + +// Development build only. `EXPO_PUBLIC_*` values are inlined into the shipped JS +// bundle, so a project key set this way is readable by anyone with the app and +// grants mutating access (createIndex / addDocs / deleteIndex). Do not ship it +// in a production app — see the package README's "Credentials" section. +const PROJECT_ID = process.env.EXPO_PUBLIC_MOSS_PROJECT_ID!; +const PROJECT_KEY = process.env.EXPO_PUBLIC_MOSS_PROJECT_KEY!; + +export default function App() { + const [result, setResult] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + const client = new MossClient(PROJECT_ID, PROJECT_KEY); + let cancelled = false; + + (async () => { + try { + await client.createIndex('rn-demo', [ + { id: '1', text: 'Refunds are processed within 3-5 business days.' }, + { id: '2', text: 'Shipping usually takes 2 business days.' }, + ]); + await client.loadIndex('rn-demo'); + const search = await client.query('rn-demo', 'how long do refunds take?'); + if (!cancelled) setResult(search); + } catch (e) { + if (!cancelled) setError(e instanceof Error ? e.message : String(e)); + } finally { + client.close(); + } + })(); + + return () => { + cancelled = true; + }; + }, []); + + return ( + + Moss RN demo + {error ? {error} : null} + {result?.docs.map((doc) => ( + + + [{doc.score.toFixed(3)}] {doc.text} + + + ))} +