A TypeScript/JavaScript SDK for integrating with the Rava RAG (Retrieval-Augmented Generation) API. Easily ingest documents and query them with AI-powered retrieval.
- 🚀 Singleton Pattern: Efficient client management - initialize once, use everywhere
- 📄 Document Ingestion: Ingest text, files, GitHub repositories, and URLs
- 🔍 Smart Querying: Query your ingested documents with AI-powered retrieval
- 🔐 Secure Authentication: Bearer token authentication with API keys
- 📦 TypeScript Support: Full type definitions included
- 🎯 Simple API: Intuitive methods for ingest and query operations
npm install @rava-ai/sdk
# or
pnpm add @rava-ai/sdk
# or
yarn add @rava-ai/sdkInitialize the Rava client once at your application startup:
import { RavaClient } from "@rava-ai/sdk"
// At your app startup (e.g., main.ts, server.ts)
RavaClient.initialize({
apiKey: "your-api-key-here",
baseUrl: "https://rava-ydvd.onrender.com", // optional, defaults to https://rava-ydvd.onrender.com
})Use the same client instance throughout your application:
import { RavaClient } from "@rava-ai/sdk"
const client = RavaClient.getInstance()const response = await client.ingest({
name: "my-document",
content: "Your document content here",
metadata: {
type: "text", // 'text', 'github', 'url', or 'file'
},
})
console.log("Ingestion status:", response.status)const response = await client.query({
question: "What is the main topic?",
top_k: 5, // number of relevant results to retrieve
})
console.log("Answer:", response.answer)new RavaClient(config: ClientConfig)Initialize the singleton instance. Call this once at application startup.
Parameters:
config.apiKey(string, required): Your Rava API keyconfig.baseUrl(string, optional): Base URL for the API (defaults tohttps://api.rava.dev)
Returns: The initialized RavaClient instance
RavaClient.initialize({
apiKey: "rag_xxxxxxxxxxxx",
baseUrl: "https://api.rava.dev",
})Get the singleton instance. Must call initialize() first.
Returns: The RavaClient instance
Throws: Error if initialize() was not called
const client = RavaClient.getInstance()Reset the singleton instance. Useful for testing or reinitializing.
RavaClient.reset()
RavaClient.initialize({ apiKey: "new-key" })Ingest a document into your RAG system.
Parameters:
name(string, required): Name/identifier for the documentcontent(string, optional): Document content as stringfilePath(string, optional): Path to file to read (Node.js only)metadata(IngestMetadata, required): Metadata about the document
Metadata Object:
type(string, required): One of'text','github','url', or'file'- Additional metadata fields can be included as needed
Returns: Promise resolving to { status: string }
Examples:
Ingest text content:
const response = await client.ingest({
name: "product-documentation",
content: "This is the product documentation...",
metadata: {
type: "text",
version: "1.0",
category: "docs",
},
})Ingest from file (Node.js):
const response = await client.ingest({
name: "research-paper",
filePath: "./paper.txt",
metadata: {
type: "file",
format: "txt",
},
})Query your ingested documents.
Parameters:
question(string, required): Your question/queryhistory(Array, optional): Conversation history for context- Each item:
{ role: 'user' | 'assistant', content: string }
- Each item:
top_k(number, optional): Number of relevant documents to retrieve (default: 5)
Returns: Promise resolving to { answer: string }
Examples:
Simple query:
const response = await client.query({
question: "What are the main features?",
})
console.log(response.answer)Query with history:
const response = await client.query({
question: "Tell me more about that",
history: [
{ role: "user", content: "What is RAG?" },
{ role: "assistant", content: "RAG stands for Retrieval-Augmented Generation..." },
],
top_k: 3,
})interface ClientConfig {
apiKey: string // Required: Your Rava API key
baseUrl?: string // Optional: API base URL (default: https://api.rava.dev)
}import express from "express"
import { RavaClient } from "@rava-ai/sdk"
const app = express()
// Initialize at startup
RavaClient.initialize({
apiKey: process.env.RAVA_API_KEY!,
})
app.post("/api/ingest", async (req, res) => {
try {
const client = RavaClient.getInstance()
const result = await client.ingest({
name: req.body.name,
content: req.body.content,
metadata: { type: "text" },
})
res.json(result)
} catch (error) {
res.status(500).json({ error: error.message })
}
})
app.post("/api/query", async (req, res) => {
try {
const client = RavaClient.getInstance()
const result = await client.query({
question: req.body.question,
})
res.json(result)
} catch (error) {
res.status(500).json({ error: error.message })
}
})
app.listen(3000)// lib/rava.ts
import { RavaClient } from "@rava-ai/sdk"
// Initialize client at module load time
if (!RavaClient.getInstance()) {
RavaClient.initialize({
apiKey: process.env.NEXT_PUBLIC_RAVA_API_KEY!,
})
}
export const ravaClient = RavaClient.getInstance()// app/api/ingest/route.ts
import { ravaClient } from "@/lib/rava"
export async function POST(req: Request) {
const body = await req.json()
const result = await ravaClient.ingest({
name: body.name,
content: body.content,
metadata: { type: "text" },
})
return Response.json(result)
}import { RavaClient } from "@rava-ai/sdk"
describe("Rava Integration", () => {
beforeEach(() => {
RavaClient.reset()
RavaClient.initialize({ apiKey: "test-key" })
})
afterEach(() => {
RavaClient.reset()
})
it("should ingest documents", async () => {
const client = RavaClient.getInstance()
const result = await client.ingest({
name: "test-doc",
content: "Test content",
metadata: { type: "text" },
})
expect(result.status).toBeDefined()
})
})The SDK throws errors in the following scenarios:
-
Not Initialized: Calling
getInstance()beforeinitialize()try { const client = RavaClient.getInstance() } catch (error) { console.error(error.message) // "RavaClient not initialized. Call RavaClient.initialize(config) first." }
-
Missing Required Fields: When
contentandfilePathare both missingtry { await client.ingest({ name: "doc", metadata: { type: "text" }, }) } catch (error) { console.error(error.message) // "Either content or filePath is required" }
-
Missing Metadata: When metadata is not provided
try { await client.ingest({ name: "doc", content: "content", // metadata missing }) } catch (error) { console.error(error.message) // "metadata is required" }
-
Network Errors: When API calls fail
try { await client.query({ question: "test" }) } catch (error) { console.error(error.message) // Network error details }
Store your API key securely in environment variables:
# .env or .env.local
RAVA_API_KEY=your_api_key_hereThen use in your code:
RavaClient.initialize({
apiKey: process.env.RAVA_API_KEY!,
})Clone the repository and build the SDK:
pnpm install
pnpm run buildThis generates:
dist/index.js- CommonJS bundledist/index.d.ts- TypeScript type definitions
Watch for changes and rebuild automatically:
pnpm run dev- Initialize Once: Call
RavaClient.initialize()exactly once at application startup - Use getInstance(): Never create new RavaClient instances in request handlers
- Error Handling: Always wrap SDK calls in try-catch blocks
- API Keys: Store API keys in environment variables, never hardcode them
- Type Safety: Leverage TypeScript for better IDE support and error detection
- Take a look at the example folder for a nestjs example.