@easyrag/sdk
v0.1.1
Published
Official JavaScript SDK for EasyRAG.com API
Maintainers
Readme
@easyrag/sdk
Official JavaScript/TypeScript SDK for EasyRAG - RAG as a Service.
Installation
npm install @easyrag/sdkGetting an API Key
To obtain an API key, Sign Up to EasyRAG and generate a new API via the Dashboard
Quick Start
import { EasyRAG } from '@easyrag/sdk';
// Initialize with API key
const client = new EasyRAG('YOUR_API_KEY');
// Upload files
const upload = await client.upload('my-dataset', [file1, file2]);
console.log(`Uploaded ${upload.files.length} files`);
// Search
const results = await client.search('my-dataset', 'What is the refund policy?');
console.log(results.data);
// Query
const answer = await client.query('my-dataset', 'Summarize the key points');
console.log(answer.data.result);Method Overview
| Method | Purpose | Returns |
|--------|---------|---------|
| upload(dataset, files, options?) | Upload and index files | UploadResponse |
| listFiles(dataset) | List all files in dataset | ListFilesResponse |
| getFile(dataset, fileId) | Get file details + download URL | GetFileResponse |
| deleteFile(dataset, fileId) | Delete a specific file | DeleteResponse |
| deleteDataset(dataset) | Delete all files in dataset | DeleteResponse |
| deleteAll() | Delete all customer files | DeleteResponse |
| search(dataset, question, options?) | Semantic search | SearchResponse |
| query(dataset, question, options?) | AI-generated answer | QueryResponse |
| queryStream(dataset, question, options?) | Streaming AI answer | AsyncGenerator<StreamEvent> |
| createToken(dataset, options?) | Create frontend token | CreateTokenResponse |
Quick Reference
const client = new EasyRAG('YOUR_API_KEY');
// Files
await client.upload(datasetId, files, options?)
await client.listFiles(datasetId)
await client.getFile(datasetId, fileId)
await client.deleteFile(datasetId, fileId)
await client.deleteDataset(datasetId)
await client.deleteAll()
// Search & Query
await client.search(datasetId, question, options?)
await client.query(datasetId, question, options?)
for await (const chunk of client.queryStream(datasetId, question, options?)) { }
// Tokens
await client.createToken(datasetId, options?)API Reference
Constructor
// Simple
const client = new EasyRAG('YOUR_API_KEY');
// With options
const client = new EasyRAG({
apiKey: 'YOUR_API_KEY',
baseUrl: 'https://api.easyrag.com', // optional
timeout: 30000 // optional, default 30s
});Upload Files
// Single file
await client.upload('my-dataset', file);
// Multiple files
await client.upload('my-dataset', [file1, file2, file3]);
// With metadata
await client.upload('my-dataset', [file], {
metadata: {
'document.pdf': {
userId: 'user_123',
department: 'legal'
}
}
});
// With custom chunking
await client.upload('my-dataset', [file], {
chunkSize: 500,
chunkOverlap: 50
});Response:
{
success: true,
message: "Files processed and indexed successfully!",
files: [
{
fileId: "f7a3b2c1-4d5e-6f7g",
originalName: "document.pdf",
datasetId: "my-dataset",
created: "2024-12-13T10:30:00.000Z",
// ...
}
],
billed: {
fileCount: 1,
uploadUnits: 10
}
}List Files
Get all files in a dataset.
const response = await client.listFiles('my-dataset');
// Response type: ListFilesResponse
console.log(response.files); // FileMetadata[]Response:
{
success: true,
files: [
{
fileId: "f7a3b2c1-4d5e-6f7g",
originalName: "document.pdf",
datasetId: "my-dataset",
size: 245678,
mimeType: "application/pdf",
created: "2024-12-13T10:30:00.000Z",
extension: ".pdf",
extraMeta: { userId: "user_123" },
// ... other fields
}
]
}Get File Details
Get detailed information about a specific file, including a signed download URL.
const response = await client.getFile('my-dataset', 'fileId');
// Response type: GetFileResponse
console.log(response.file.permanentUrl); // Signed download URL
console.log(response.file.originalName);
console.log(response.file.size);Response:
{
success: true,
file: {
fileId: "f7a3b2c1-4d5e-6f7g",
originalName: "document.pdf",
datasetId: "my-dataset",
permanentUrl: "https://storage.googleapis.com/...",
// ... all file metadata
}
}The permanentUrl is a signed URL valid until year 2491 for direct file download.
Delete File
Delete a specific file from a dataset.
const response = await client.deleteFile('my-dataset', 'fileId');
// Response type: DeleteResponse
console.log(response.success); // trueThis removes:
- File from cloud storage
- All vector embeddings
- File metadata
Note: Deletion is permanent and cannot be undone. Credits are not refunded.
Delete All Files in Dataset
Delete all files in a specific dataset.
const response = await client.deleteDataset('my-dataset');
// Response type: DeleteResponse
console.log(response.deleted); // Number of files deletedResponse:
{
success: true,
deleted: 15 // Number of files removed
}⚠️ Warning: This is irreversible and deletes ALL files in the dataset.
Delete All Customer Files
Delete all files across all datasets for the authenticated customer.
const response = await client.deleteAll();
// Response type: DeleteResponse
console.log(response.deleted); // Total files deletedResponse:
{
success: true,
deleted: 127 // Total files across all datasets
}⚠️ Warning: This is a complete wipe and cannot be undone. Only works with API keys (not frontend tokens).
Search
Perform semantic search across your documents.
// Basic search
const results = await client.search(
'my-dataset',
'What is the refund policy?'
);
// Response type: SearchResponse
console.log(results.data); // SearchResult[]With filters:
const results = await client.search(
'my-dataset',
'contract terms',
{
filters: [
{ key: 'department', match: { value: 'legal' } },
{ key: 'year', match: { value: 2024 } },
{ key: 'status', match: { value: 'active' } }
]
}
);Response:
{
success: true,
data: [
{
score: 0.89, // Relevance score (0-1, higher is better)
pageContent: "...", // Text chunk from document
metadata: {
fileId: "f7a3b2c1",
originalName: "policy.pdf",
datasetId: "my-dataset",
// ... custom metadata from upload
}
}
]
}Filter syntax:
interface SearchFilter {
key: string; // Metadata field name
match: {
value: string | number | boolean; // Exact value to match
};
}Multiple filters use AND logic (all must match).
Score interpretation:
- 0.9+ - Highly relevant
- 0.8-0.9 - Very relevant
- 0.7-0.8 - Relevant
- < 0.7 - Possibly relevant
Query (Non-Streaming)
Get an AI-generated answer to a question about your documents.
const answer = await client.query(
'my-dataset',
'Summarize the key points'
);
// Response type: QueryResponse
console.log(answer.data.result); // AI-generated answer
console.log(answer.data.sources); // Source chunks usedWith filters:
const answer = await client.query(
'my-dataset',
'What is the vacation policy?',
{
filters: [
{ key: 'department', match: { value: 'HR' } },
{ key: 'year', match: { value: 2024 } }
]
}
);Response:
{
success: true,
data: {
result: "Based on the documents, the key points are:\n1. ...",
sources: [
{
pageContent: "...",
metadata: { fileId: "...", originalName: "..." }
}
]
}
}The AI answers only based on your documents - no hallucinations.
Query (Streaming)
Stream the AI response in real-time for better UX.
// Stream the response word-by-word
for await (const chunk of client.queryStream('my-dataset', 'Explain the features')) {
if (chunk.delta) {
process.stdout.write(chunk.delta); // New text chunk
} else if (chunk.done) {
console.log('\nComplete!'); // Stream finished
} else if (chunk.error) {
console.error('Error:', chunk.error); // Stream error
}
}With filters:
for await (const chunk of client.queryStream(
'my-dataset',
'Explain the policy',
{
filters: [{ key: 'department', match: { value: 'HR' } }]
}
)) {
if (chunk.delta) {
console.log(chunk.delta);
}
}Stream event types:
// Text chunk
{ delta: "Based on" }
// Completion
{ done: true }
// Error
{ error: "Error message" }Use streaming when:
- Building chat interfaces
- User experience matters
- Long responses expected
Benefits:
- Response starts immediately
- Users see progress in real-time
- Same cost as non-streaming (0.1 credit)
Create Frontend Token
Create a scoped token for use in browsers or mobile apps.
// Create a token for frontend use
const result = await client.createToken('my-dataset', {
ttlSeconds: 3600 // 1 hour (default: 3600, max: 86400)
});
// Response type: CreateTokenResponse
console.log(result.token); // JWT token for frontend
console.log(result.expiresIn); // 3600 (seconds)Response:
{
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
expiresIn: 3600
}Token scoping:
- Token is scoped to a single dataset
- Can only access the specified dataset
- Expires after
ttlSeconds - Cannot create other tokens
Recommended TTL values:
// Quick upload
await client.createToken('dataset', { ttlSeconds: 300 }); // 5 min
// Chat session
await client.createToken('dataset', { ttlSeconds: 3600 }); // 1 hour
// Long session
await client.createToken('dataset', { ttlSeconds: 14400 }); // 4 hours
// Maximum
await client.createToken('dataset', { ttlSeconds: 86400 }); // 24 hoursFrontend usage:
// Backend generates token
const { token } = await client.createToken('user-dataset', { ttlSeconds: 3600 });
// Send to frontend
res.json({ token });
// Frontend uses token
const frontendClient = new EasyRAG(token);
await frontendClient.search('user-dataset', 'query');Security notes:
- Only call this endpoint from your backend
- Never expose API keys in the frontend
- Tokens automatically scope to the specified dataset
- No way to revoke tokens before expiry
Error Handling
import { EasyRAGError } from '@easyrag/sdk';
try {
await client.upload('my-dataset', file);
} catch (error) {
if (error instanceof EasyRAGError) {
console.error('Status:', error.status);
console.error('Code:', error.code);
console.error('Message:', error.message);
console.error('Details:', error.details);
}
}TypeScript Support
Full TypeScript support with autocomplete:
import type { SearchResult, UploadResponse } from '@easyrag/sdk';
const results: SearchResult[] = await client.search(...);
const upload: UploadResponse = await client.upload(...);Costs
| Operation | Cost | Notes |
|-----------|------|-------|
| upload() | 1 credit per file | Includes processing and indexing |
| listFiles() | Free | No charge |
| getFile() | Free | No charge |
| deleteFile() | Free | Credits not refunded |
| deleteDataset() | Free | Credits not refunded |
| deleteAll() | Free | Credits not refunded |
| search() | 0.1 credit | Per search request |
| query() | 0.1 credit | Same for streaming/non-streaming |
| queryStream() | 0.1 credit | Same cost as non-streaming |
| createToken() | Free | No charge |
Complete API Reference
Constructor
new EasyRAG(apiKey: string): EasyRAG
new EasyRAG(config: EasyRAGConfig): EasyRAG
interface EasyRAGConfig {
apiKey: string;
baseUrl?: string; // Default: 'https://api.easyrag.com'
timeout?: number; // Default: 30000 (30 seconds)
}Methods
upload()
upload(
datasetId: string,
files: File | File[],
options?: UploadOptions
): Promise<UploadResponse>
interface UploadOptions {
metadata?: Record<string, Record<string, any>>;
chunkSize?: number; // Default: 300
chunkOverlap?: number; // Default: 20
}listFiles()
listFiles(datasetId: string): Promise<ListFilesResponse>getFile()
getFile(
datasetId: string,
fileId: string
): Promise<GetFileResponse>deleteFile()
deleteFile(
datasetId: string,
fileId: string
): Promise<DeleteResponse>deleteDataset()
deleteDataset(datasetId: string): Promise<DeleteResponse>deleteAll()
deleteAll(): Promise<DeleteResponse>search()
search(
datasetId: string,
question: string,
options?: SearchOptions
): Promise<SearchResponse>
interface SearchOptions {
filters?: SearchFilter[];
}
interface SearchFilter {
key: string;
match: { value: string | number | boolean };
}query()
query(
datasetId: string,
question: string,
options?: QueryOptions
): Promise<QueryResponse>
interface QueryOptions {
filters?: SearchFilter[];
}queryStream()
queryStream(
datasetId: string,
question: string,
options?: QueryOptions
): AsyncGenerator<StreamEvent>
type StreamEvent = StreamDelta | StreamDone | StreamError;
interface StreamDelta {
delta: string;
}
interface StreamDone {
done: true;
}
interface StreamError {
error: string;
}createToken()
createToken(
datasetId: string,
options?: CreateTokenOptions
): Promise<CreateTokenResponse>
interface CreateTokenOptions {
ttlSeconds?: number; // Default: 3600, Max: 86400
}Response Types
interface UploadResponse {
success: true;
message: string;
files: FileMetadata[];
billed: {
fileCount: number;
uploadUnits: number;
};
}
interface FileMetadata {
customerId: string;
datasetId: string;
fileId: string;
filePath: string;
originalName: string;
mimeType: string | null;
size: number | null;
loaderId: string;
created: string;
extension: string;
transcriptionText: string | null;
transcriptionSrt: SrtEntry[] | null;
extraMeta: Record<string, any> | null;
permanentUrl?: string; // Only in getFile() response
}
interface SearchResponse {
success: true;
data: SearchResult[];
}
interface SearchResult {
score: number;
pageContent: string;
metadata: {
fileId: string;
originalName: string;
customerId: string;
datasetId: string;
[key: string]: any;
};
}
interface QueryResponse {
success: true;
data: {
result: string;
sources?: Array<{
pageContent: string;
metadata: Record<string, any>;
}>;
};
}
interface ListFilesResponse {
success: true;
files: FileMetadata[];
}
interface GetFileResponse {
success: true;
file: FileMetadata;
}
interface DeleteResponse {
success: true;
deleted?: number;
}
interface CreateTokenResponse {
token: string;
expiresIn: number;
}Error Handling
class EasyRAGError extends Error {
status?: number; // HTTP status code
code?: string; // Error code from API
details?: any; // Additional error details
}Example:
import { EasyRAGError } from '@easyrag/sdk';
try {
await client.upload('dataset', file);
} catch (error) {
if (error instanceof EasyRAGError) {
console.log('Status:', error.status); // 402
console.log('Code:', error.code); // "INSUFFICIENT_CREDITS"
console.log('Message:', error.message); // "You are out of credits..."
console.log('Details:', error.details); // { required: 1, available: 0 }
}
}Costs
| Operation | Cost | |-----------|------| | Upload 1 file | 1 credit | | Search | 0.1 credit | | Query (streaming or not) | 0.1 credit | | List files | Free | | Get file | Free | | Delete file | Free |
Rate Limits
- Search/Query: 1000 requests/minute
- Upload: 100 requests/minute
- File operations: 1000 requests/minute
Requests automatically timeout after 30 seconds (configurable via constructor).
Examples
Basic Usage
import { EasyRAG } from '@easyrag/sdk';
const client = new EasyRAG(process.env.EASYRAG_API_KEY);
// Upload
const upload = await client.upload('docs', [file]);
console.log('Uploaded:', upload.files[0].fileId);
// Search
const results = await client.search('docs', 'pricing information');
results.data.forEach(r => {
console.log(`Score: ${r.score}`);
console.log(`Content: ${r.pageContent}`);
});
// Query
const answer = await client.query('docs', 'What are the pricing tiers?');
console.log(answer.data.result);Streaming Chat
const question = 'Explain the main features';
process.stdout.write('Answer: ');
for await (const chunk of client.queryStream('docs', question)) {
if (chunk.delta) {
process.stdout.write(chunk.delta);
}
}
console.log('\n');Multi-Tenant with Filters
// Upload with user metadata
await client.upload('shared-dataset', [file], {
metadata: {
'document.pdf': { userId: 'user_123' }
}
});
// Search only user's documents
const results = await client.search(
'shared-dataset',
'my documents',
{
filters: [
{ key: 'userId', match: { value: 'user_123' } }
]
}
);Error Handling
import { EasyRAGError } from '@easyrag/sdk';
try {
await client.upload('my-dataset', file);
} catch (error) {
if (error instanceof EasyRAGError) {
if (error.status === 402) {
console.log('Out of credits!');
} else if (error.status === 400) {
console.log('Bad request:', error.message);
}
}
}File Management
// List all files
const { files } = await client.listFiles('my-dataset');
console.log(`Total files: ${files.length}`);
// Get file details
const { file } = await client.getFile('my-dataset', fileId);
console.log('Download URL:', file.permanentUrl);
// Delete file
await client.deleteFile('my-dataset', fileId);
console.log('File deleted');Browser Usage
The SDK works in browsers with the Fetch API:
// Frontend (with token from backend)
const token = await fetch('/api/token').then(r => r.json());
const client = new EasyRAG(token);
// Upload from file input
const fileInput = document.querySelector('input[type="file"]');
const files = Array.from(fileInput.files);
await client.upload('dataset', files);⚠️ Security Note: Never use API keys in the browser. Use frontend tokens from your backend.
Node.js Usage
import { EasyRAG } from '@easyrag/sdk';
import fs from 'fs';
const client = new EasyRAG(process.env.EASYRAG_API_KEY);
// Upload from filesystem
const file = new File(
[fs.readFileSync('document.pdf')],
'document.pdf',
{ type: 'application/pdf' }
);
await client.upload('my-dataset', file);Rate Limits
The SDK respects API rate limits:
- 1000 requests/minute for search/query
- 100 requests/minute for uploads
- Requests timeout after 30 seconds (configurable)
Support
- 📧 Email: [email protected]
- 📚 Docs: https://easyrag.com/docs
- 🐛 Issues: https://github.com/easyrag/sdk/issues
License
MIT
