npm package: @shinrag/sdk
Description: Official SDK for ShinRAG - Enterprise RAG Platform
Latest version: 0.6.0

# @shinrag/sdk

Official TypeScript/JavaScript SDK for the ShinRAG Enterprise RAG Platform. Provides full API coverage for agents, pipelines, indexes, integrations, widgets, usage/billing, cost tracking, and more.

## Installation

```bash
npm install @shinrag/sdk
# or
pnpm add @shinrag/sdk
# or
yarn add @shinrag/sdk
```

**Requirements:** Node.js 18+ (uses native `fetch`). No runtime dependencies.

## Quick Start

```typescript
import { ShinRAGClient } from '@shinrag/sdk';

const client = new ShinRAGClient({
  apiKey: 'sk_your_api_key_here',
  organizationId: 'org_123', // Optional: for org-scoped resources
});

// Query a pipeline
const result = await client.executePipeline('pipeline-id', {
  input: 'What are the key features mentioned in the documentation?',
});
console.log(result.output);
console.log('Tokens used:', result.totalTokensUsed);

// Query an agent
const agentResult = await client.queryAgent('agent-id', {
  question: 'What are the key features?',
  maxResults: 5,
});
console.log(agentResult.answer);
console.log('Sources:', agentResult.sources);

// Search an index
const indexResult = await client.queryIndex({
  indexId: 'index-id',
  queryText: 'What are the key features?',
  limit: 10,
});
console.log(indexResult.results);
```

## API Reference

### `ShinRAGClient`

The main client class for interacting with the ShinRAG API.

#### Constructor

```typescript
new ShinRAGClient(config: ShinRAGClientConfig)
```

**Parameters:**

- `config.apiKey` (string, required): Your API key (must start with `sk_`)
- `config.baseUrl` (string, optional): Base URL for the API (defaults to `https://api.shinrag.com/v1`)
- `config.organizationId` (string, optional): Organization ID for accessing org-scoped resources

### Agents

```typescript
// List all agents
const agents = await client.listAgents();

// Get a specific agent
const agent = await client.getAgent('agent-id');

// Create an agent
const newAgent = await client.createAgent({
  name: 'My Agent',
  description: 'A helpful assistant',
  provider: 'openai',
  model: 'gpt-4o',
  indexIds: ['index-id'],
});

// Update an agent
const updated = await client.updateAgent('agent-id', { name: 'Updated Name' });

// Delete an agent
await client.deleteAgent('agent-id');

// Query an agent (RAG)
const answer = await client.queryAgent('agent-id', {
  question: 'How do I reset my password?',
  maxResults: 5,       // optional
  temperature: 0.7,    // optional
  maxTokens: 1000,     // optional
});
```

**`QueryAgentResponse`:**

```typescript
{
  answer: string | null;
  sources: Array<{ dataset?: string; index?: string; score: number; text: string }>;
  tokensUsed: number;
  model: string;
  warning?: string;
  diagnostic?: { totalResultsFound: number; threshold: number | null; topScores: number[] };
}
```

### Pipelines

```typescript
// List all pipelines
const pipelines = await client.listPipelines();

// Get a specific pipeline
const pipeline = await client.getPipeline('pipeline-id');

// Execute a pipeline
const result = await client.executePipeline('pipeline-id', {
  input: 'What is the return policy?',
});
// Or use the convenience alias:
const result2 = await client.queryPipeline('pipeline-id', {
  input: 'What is the return policy?',
});

// Get execution status
const status = await client.getPipelineExecutionStatus('pipeline-id', 'execution-id');

// Get execution details
const execution = await client.getPipelineExecution('pipeline-id', 'execution-id');

// List executions with pagination
const executions = await client.getPipelineExecutions('pipeline-id', {
  cursor: undefined,
  limit: 20,
});
```

**`ExecutePipelineResponse`:**

```typescript
{
  executionId: string;
  status: string;
  output?: string;
  outputs?: Array<{ nodeId: string; label?: string; output: string }>;
  error?: string;
  nodeResults: Array<{ nodeId: string; status: string; output?: string; tokensUsed: number; warning?: string }>;
  totalTokensUsed: number;
}
```

### Indexes

```typescript
// List all indexes
const indexes = await client.listIndexes();

// Get a specific index
const index = await client.getIndex('index-id');

// Create an index
import { PineconeEmbeddingModel } from '@shinrag/sdk';
const newIndex = await client.createIndex({
  name: 'My Index',
  pineconeIndexName: 'my-pinecone-index',
  embeddingModel: PineconeEmbeddingModel.OPENAI_SMALL,
  metric: 'cosine', // optional: 'cosine' | 'euclidean' | 'dotproduct'
});

// Query an index (semantic search)
const results = await client.queryIndex({
  indexId: 'index-id',
  queryText: 'authentication',
  limit: 10,
  filter: { category: 'docs' }, // optional metadata filter
});
// Or use the convenience alias:
const results2 = await client.searchIndex({
  indexId: 'index-id',
  queryText: 'authentication',
});

// Get records with pagination
const records = await client.getIndexRecords('index-id', {
  limit: 50,
  paginationToken: 'token',
  prefix: 'doc_',
});

// Update records
await client.updateIndexRecords('index-id', {
  records: [
    { id: 'rec_1', metadata: { text: 'Updated content' } },
    { id: 'rec_2', metadata: { text: 'New content' }, isNew: true },
    { id: 'rec_3', metadata: {}, isDeleted: true },
  ],
});

// Check ingestion job status
const job = await client.getIngestionStatus('job-id');
```

### Integrations

```typescript
// List all integrations
const integrations = await client.listIntegrations();

// Get integration types and categories
const types = await client.getIntegrationTypes();
const byCategory = await client.getIntegrationTypesByCategory();

// Create an integration (e.g., PostgreSQL)
const integration = await client.createIntegration({
  type: 'postgres',
  name: 'My Database',
  credentials: { host: 'localhost', port: 5432, database: 'mydb', user: 'user', password: 'pass' },
  validateCredentials: true,
});

// Test an integration
const testResult = await client.testIntegration('integration-id');

// Execute an integration
const execResult = await client.executeIntegration('integration-id', {
  config: { query: 'SELECT * FROM users LIMIT 10' },
  input: 'Fetch user data',
});

// Slack OAuth flow
const { url } = await client.getSlackAuthUrl();
// Redirect user to url, then on callback:
const slackIntegration = await client.completeSlackOAuth(code);
const { channels } = await client.refreshSlackChannels('integration-id');

// GitHub OAuth flow
const { url: ghUrl } = await client.getGitHubAuthUrl();
const ghIntegration = await client.completeGitHubOAuth(code);
const { repositories } = await client.refreshGitHubRepositories('integration-id');
const { issues } = await client.getGitHubIssues('integration-id', 'owner', 'repo', 'open');
const { pullRequests } = await client.getGitHubPullRequests('integration-id', 'owner', 'repo');
```

**Supported integration types:** `slack`, `discord`, `webhook`, `github`, `postgres`, `mysql`, `mongodb`, `snowflake`, `bigquery`, `perplexity`, `tavily`, `http`

### Widgets

```typescript
// Manage widgets (authenticated)
const widgets = await client.listWidgets();
const widget = await client.createWidget({ name: 'Support Chat', agentId: 'agent-id' });
await client.updateWidget('widget-id', { isActive: false });
await client.deleteWidget('widget-id');

// Public widget endpoints (can be used without API key auth)
const widgetInfo = await client.getWidgetByKey('widget-key');
const response = await client.queryWidget('widget-key', {
  question: 'How do I get started?',
  sessionId: 'session_123', // optional: for conversation continuity
});
const history = await client.getWidgetSessionHistory('widget-key', 'session_123');
```

### API Keys

```typescript
const keys = await client.listApiKeys();
const newKey = await client.createApiKey({ name: 'Production Key' });
console.log(newKey.key); // sk_... (only shown once!)
await client.deleteApiKey('key-id');
```

### Usage & Billing

```typescript
const usage = await client.getUsage();
const pricing = await client.getV2Pricing();
const usageSummary = await client.getV2UsageSummary();
const cacheStatus = await client.getV2CacheStatus();

// Checkout for upgrading tier
const { checkoutUrl } = await client.createV2Checkout({
  tier: 'developer',
  successUrl: 'https://myapp.com/success',
  cancelUrl: 'https://myapp.com/cancel',
});

// Downgrade management
const downgradeStatus = await client.getV2DowngradeStatus();
await client.scheduleV2Downgrade('sandbox');
await client.cancelV2PendingDowngrade();

// Cancel subscription
await client.cancelV2Subscription();
```

### Cost Tracking

```typescript
const summary = await client.getCostSummary(30);       // last 30 days
const pipelineCosts = await client.getPipelineCosts(7); // last 7 days
const trend = await client.getCostTrend(30);            // daily breakdown
const execCost = await client.getExecutionCost('execution-id');
const rates = await client.getCostRates();
```

### Batch Execution

```typescript
const batch = await client.createBatch('pipeline-id', {
  inputs: ['Question 1', 'Question 2', 'Question 3'],
  name: 'Test Batch',
});

// Poll for completion
let status = await client.getBatchStatus(batch.batchId);
while (status.status === 'pending' || status.status === 'processing') {
  await new Promise(r => setTimeout(r, 2000));
  status = await client.getBatchStatus(batch.batchId);
}
console.log('Batch complete:', status.results);
```

### Webhooks

```typescript
const webhooks = await client.listWebhooks('pipeline-id');
const webhook = await client.createWebhook('pipeline-id', {
  name: 'My Webhook',
  description: 'Triggers on incoming data',
  secretToken: 'my-secret',       // optional
  inputMapping: '{{body.query}}',  // optional
});
await client.deleteWebhook('pipeline-id', 'webhook-id');
```

### Schedules

```typescript
const schedules = await client.listSchedules('pipeline-id');
const schedule = await client.createSchedule('pipeline-id', {
  name: 'Daily Report',
  cronExpression: '0 9 * * *',       // Every day at 9 AM
  inputTemplate: 'Generate daily summary',
  timezone: 'America/New_York',      // optional
});
await client.deleteSchedule('pipeline-id', 'schedule-id');
```

### Templates

```typescript
const templates = await client.listTemplates('pipeline-id');
const template = await client.createTemplate('pipeline-id', {
  name: 'FAQ Template',
  inputTemplate: 'Answer the following FAQ: {{question}}',
});
```

### Execution History

```typescript
const history = await client.getExecutionHistory('pipeline-id', {
  limit: 20,
  status: 'completed',                // optional: 'pending' | 'running' | 'completed' | 'failed'
  source: 'api',                       // optional: 'manual' | 'api' | 'schedule' | 'webhook' | 'batch'
  cursor: 'next-page-cursor',         // optional: for pagination
});

const detail = await client.getExecution('execution-id');
```

### Support

```typescript
const issue = await client.createIssue({
  title: 'Bug: Pipeline fails on large input',
  description: 'When input exceeds 10k chars...',
  issueType: 'bug',
});
```

## Advanced: Custom Authentication

The SDK exports `BaseApiClient` for use with custom authentication (e.g., JWT in the frontend):

```typescript
import { BaseApiClient } from '@shinrag/sdk/core';

const client = new BaseApiClient({
  baseUrl: 'http://localhost:1337',
  headers: { 'Authorization': `Bearer ${jwtToken}` },
  organizationId: 'org_123',
});

// All the same API methods are available
const agents = await client.listAgents();
```

## Error Handling

The SDK throws `ShinRAGError` for API errors:

```typescript
import { ShinRAGClient, ShinRAGError } from '@shinrag/sdk';

try {
  const result = await client.executePipeline('pipeline-id', {
    input: 'Your query here',
  });
} catch (error) {
  if (error instanceof ShinRAGError) {
    console.error('API Error:', error.message);
    console.error('Status Code:', error.statusCode);
    console.error('Response:', error.response);
  } else {
    console.error('Unknown error:', error);
  }
}
```

## Type Exports

All types are available as named exports:

```typescript
import type {
  Agent, CreateAgentRequest, QueryAgentRequest, QueryAgentResponse,
  Pipeline, ExecutePipelineRequest, ExecutePipelineResponse,
  IndexMetadata, QueryIndexOptions, QueryIndexResponse,
  Integration, IntegrationType, IntegrationCategory,
  Widget, QueryWidgetRequest, QueryWidgetResponse,
  V2Tier, V2UsageSummary, CostSummary,
  ShinRAGClientConfig, RequestConfig,
  // ... and many more
} from '@shinrag/sdk';

// Enum (value import, not type-only)
import { PineconeEmbeddingModel, ShinRAGError } from '@shinrag/sdk';
```

## Development

For local development, point to your local API:

```typescript
const client = new ShinRAGClient({
  apiKey: 'sk_your_api_key_here',
  baseUrl: 'http://localhost:1337',
});
```

Run the example test suite:

```bash
cd apps/example
cp .env.example .env  # Set your API key
npx tsx index.ts --all
```

## License

MIT