JSPM

  • Created
  • Published
  • Downloads 11
  • Score
    100M100P100Q82323F
  • License MIT

SDK for API integration with Streaming API Improvements

Package Exports

  • solver-sdk

Readme

Code Solver SDK v7.3.0

AI-powered code analysis SDK. 100% typed, production ready.

Install

npm install solver-sdk@7.3.0

Quick Start

import { CodeSolverSDK } from 'solver-sdk';

const sdk = await CodeSolverSDK.create({
  baseURL: 'https://api.example.com',
  getAuthToken: async () => getToken()
});

// Projects
const projects = await sdk.projects.getAllProjects();
await sdk.projects.createProject('MyProject');

// Chat with Thinking
const response = await sdk.chat.chat([
  { role: 'user', content: 'explain this code' }
], { thinking: { type: 'enabled', budget_tokens: 10000 } });

// Search
const results = await sdk.search.searchCode({
  projectId,
  query: 'authentication function'
});

// User & Updates
const profile = await sdk.user.getProfile();
const update = await sdk.updates.checkForUpdates({...});

API Overview

Feature Methods Status
Projects 19 ✅ Full CRUD + state
Delta Chunking 7 ✅ Encrypted sync
Chat 12 ✅ Streaming + Extended Thinking
Search 4 ✅ Vector-based
Tools 5 ✅ AI tool schemas
Models 5 ✅ Provider info
Updates 5 ✅ Auto-check + changelog
User 3 ✅ Profile + Limits
Auth 2 ✅ Token revocation + logout

Auth

// Local dev
const sdk = await CodeSolverSDK.create({
  baseURL: 'http://localhost:3000',
  getAuthToken: async () => 'your-token'
});

// Production with token refresh
const sdk = await CodeSolverSDK.create({
  baseURL: 'https://api.example.com',
  getAuthToken: async () => {
    if (isTokenExpired()) {
      await refreshToken();
    }
    return getToken();
  }
});

WebSocket (Real-time)

// Connect
await sdk.connectWebSocket();

// Subscribe to project
sdk.projectSync.subscribeToProject(projectId);

// Listen for updates
sdk.projectSync.on('sync-progress', (data) => {
  console.log(`Progress: ${data.processedFiles}/${data.totalFiles}`);
});

sdk.projectSync.on('sync-completed', (data) => {
  console.log(`Done: ${data.statistics.totalFiles} files`);
});

Error Handling

Auth Errors

By default, 401/403 auth errors return null instead of throwing:

const projects = await sdk.projects.getAllProjects();
if (!projects) {
  // Token expired - refresh and retry
  await refreshToken();
}

// To throw errors instead:
const sdk = await CodeSolverSDK.create({
  suppressAuthErrors: false
});

Usage Limits & Rate Limiting

SDK automatically handles usage limit and rate limit errors with specialized error classes:

Checking Limit Status

import { CodeSolverSDK } from 'solver-sdk';

const sdk = await CodeSolverSDK.create({ /* ... */ });

// Get detailed limit status
const status = await sdk.user.getLimitStatus();

console.log(`Status: ${status.status}`); // 'ok' | 'warning' | 'critical' | 'blocked' | 'on_demand'
console.log(`Can make requests: ${status.canMakeRequest}`);

if (status.status === 'warning' || status.status === 'critical') {
  console.warn(`Warning: ${status.message}`);
}

if (status.action) {
  console.log(`Recommendation: ${status.action.suggestion}`);
}

Handling Limit Exceeded (403)

import { CodeSolverSDK, LimitExceededError } from 'solver-sdk';

try {
  await sdk.chat.streamChat([
    { role: 'user', content: 'Hello' }
  ]);
} catch (error) {
  if (error instanceof LimitExceededError) {
    console.log('Usage limit exceeded!');
    console.log(`Type: ${error.statusType}`); // e.g. 'debt_limit_exceeded'
    console.log(`Blocked: ${error.isBlocked()}`); // true/false
    
    if (error.action) {
      console.log(`Action: ${error.action.suggestion}`);
      console.log(`URL: ${error.getActionUrl()}`);
    }
    
    if (error.balance) {
      console.log(`Balance: ${error.balance.currentRub}`);
      console.log(`Required topup: ${error.balance.requiredTopup}`);
    }
  }
}

Handling Rate Limit (429)

import { CodeSolverSDK, RateLimitError } from 'solver-sdk';

try {
  // Making multiple requests rapidly
  for (let i = 0; i < 100; i++) {
    await sdk.user.getProfile();
  }
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log('Rate limit exceeded!');
    console.log(`Wait ${error.retryAfter} seconds`);
    console.log(`Retry at: ${error.retryAt}`);
    console.log(`Time remaining: ${error.getRetryDelayMs()}ms`);
    
    // Wait and retry
    await new Promise(resolve => setTimeout(resolve, error.getRetryDelayMs()));
    // ... retry request
  }
}

Proactive Limit Checking

// Check before making expensive operations
async function sendChatMessage(message: string) {
  // 1. Check limit status first
  const status = await sdk.user.getLimitStatus();
  
  if (!status.canMakeRequest) {
    console.error('Cannot make request:', status.message);
    return;
  }
  
  if (status.status === 'warning') {
    console.warn('Low on tokens:', status.message);
  }
  
  // 2. Make the request
  try {
    await sdk.chat.streamChat([
      { role: 'user', content: message }
    ]);
  } catch (error) {
    if (error instanceof LimitExceededError) {
      // Handle limit error
    } else if (error instanceof RateLimitError) {
      // Handle rate limit
    }
  }
}

Types

import {
  ChatMessage,
  ChatOptions,
  Project,
  ProjectState,
  SearchResult,
  UserProfile,
  LimitStatus,
  LimitExceededError,
  RateLimitError
} from 'solver-sdk';

Debug

const sdk = await CodeSolverSDK.create({
  debug: 'verbose',  // silent | error | warn | info | debug | verbose
  webSocket: { debug: true }
});

Delta Chunking (Indexing)

// ✅ Main indexing method
await sdk.deltaManager.syncEncryptedChunks(projectId, chunks, rootHash, {
  batchSize: 50,
  onProgress: (current, total) => console.log(`${current}/${total}`)
});

// Check sync status
const state = await sdk.projects.getProjectState(projectId, clientRootHash);
if (state.syncRequired) {
  // Needs sync
}

// Cancel ongoing sync
await sdk.deltaManager.cancelSync(projectId);

Session Recovery

// Always check on project open
const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
  const { processedFiles, totalFiles, percentage } = recovery.progress;
  
  // Show dialog: "Continue (67%) — 480/642 files" or "Start Fresh"
  await sdk.projects.resumeSync(projectId);  // Continue
  // OR
  await sdk.projects.cancelRecovery(projectId);  // Start over
}

Key Types

ProjectState

interface ProjectState {
  projectId: string;
  merkleRootHash: string | null;
  totalFiles: number;              // For UI display
  indexingStatus: 'pending' | 'in-progress' | 'complete' | 'failed';
  syncRequired?: boolean;          // Compare with client hash
}

SyncProgressEvent

interface SyncProgressEvent {
  projectId: string;
  progress: number;                // 0-100
  processedFiles: number;          // 450
  totalFiles: number;              // 722
  stage: 'receiving_chunks' | 'processing_chunks' | 'creating_embeddings' | 'finalizing';
}

RecoveryInfo

interface RecoveryInfo {
  needsRecovery: boolean;
  progress: {
    processedFiles: number;
    totalFiles: number;
    percentage: number;            // 0-100
  };
  canResume: boolean;
}

LimitStatus

interface LimitStatus {
  status: 'ok' | 'warning' | 'critical' | 'blocked' | 'on_demand';
  statusType: string;              // e.g. 'using_bonus_tokens', 'debt_limit_exceeded'
  message: string;                 // Human-readable message
  canMakeRequest: boolean;         // Can user make API requests?
  
  currentSource?: 'bonus' | 'subscription' | 'on_demand';
  
  remaining?: {
    bonusTokens?: number;          // Remaining bonus tokens
    bonusPercent?: number;         // % remaining
    subscriptionTokens?: number;   // Remaining subscription tokens
    subscriptionPercent?: number;
  };
  
  balance?: {
    currentRub?: number;           // Current balance in rubles
    maxDebtRub?: number;           // Max allowed debt
    requiredTopup?: number;        // Required topup amount
  };
  
  action?: {
    type: 'info' | 'urgent' | 'required';
    suggestion: string;            // "Top up balance" / "Upgrade plan"
    ctaUrl?: string;               // Dashboard URL
  };
}

Troubleshooting

"0 files" after indexing

const state = await sdk.projects.getProjectState(projectId);
console.log(state.totalFiles); // Should be > 0
// If 0: update backend to latest version

No WebSocket updates

// 1. Check connection
console.log(sdk.isWebSocketConnected); // should be true

// 2. Verify subscription
sdk.projectSync.subscribeToProject(projectId);

// 3. Ensure OAuth token (production)
const sdk = await CodeSolverSDK.create({
  getAuthToken: () => authManager.getAccessToken()
});

// 4. Fallback to HTTP polling
const status = await sdk.projects.getIndexingStatus(projectId);

Interrupted sync

const recovery = await sdk.projects.getRecoveryStatus(projectId);
if (recovery.needsRecovery) {
  // Option 1: Resume
  await sdk.projects.resumeSync(projectId);
  
  // Option 2: Cancel and restart
  await sdk.projects.cancelRecovery(projectId);
}

API Reference

Projects (sdk.projects)

getAllProjects(): Promise<Project[]>
getProjects(): Promise<Project[]>
getProject(projectId: string): Promise<Project>
createProject(name: string, data?: any, options?: ProjectOptions): Promise<Project>
findOrCreateProject(name: string): Promise<Project>
deleteProject(projectId: string): Promise<void>
getReadyProjects(): Promise<Project[]>
getProjectState(projectId: string, clientRootHash?: string): Promise<ProjectState>
getProjectStatus(projectId: string): Promise<any>
getIndexingStatus(projectId: string): Promise<any>
cancelIndexing(projectId: string): Promise<boolean>
clearIndexingError(projectId: string): Promise<boolean>
getRecoveryStatus(projectId: string): Promise<RecoveryInfo>
resumeSync(projectId: string, options?: any): Promise<any>
cancelRecovery(projectId: string): Promise<void>
initializeDeltaSync(projectId: string, params: any): Promise<any>
resetIndexing(projectId: string): Promise<any>
restartIndexing(projectId: string): Promise<any>
getFilePathMapping(projectId: string): Promise<any>

Delta Manager (sdk.deltaManager)

initSync(projectId: string, request: SyncInitRequest): Promise<any>
uploadChunkBatch(projectId: string, chunks: any[]): Promise<any>
uploadChunksWithRetry(projectId: string, chunks: any[], options?: any): Promise<any>
finalizeSync(projectId: string): Promise<SyncResult>
getSyncStatus(projectId: string): Promise<SyncStatus>
cancelSync(projectId: string): Promise<{ success: boolean; message?: string }>
cleanupFiles(projectId: string, activeFiles: string[]): Promise<any>

Chat (sdk.chat)

chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
chatCompletion(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
chatWithRegionFailover(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>
streamChat(messages: ChatMessage[], options?: ChatStreamOptions): AsyncGenerator<ChatStreamChunk>
streamPrompt(prompt: string, options?: ChatStreamOptions): AsyncGenerator<ChatStreamChunk>
sendContinuation(requestId: string, messages: ChatMessage[]): AsyncGenerator<ChatStreamChunk>
sendPromptWithRegionFailover(prompt: string, options?: ChatOptions): Promise<string>
checkAvailability(): Promise<boolean>
cancelRequest(requestId: string): Promise<void>
getStreamsStats(): Promise<any>
cleanupStaleStreams(timeoutMs?: number): Promise<any>
cancelUserStreams(reason?: string): Promise<number>

Search (sdk.search)

searchCode(projectIdOrParams: string | SearchCodeParams, params?: SearchCodeParams): Promise<SearchResult[]>
searchFunctions(projectIdOrParams: string | SearchFunctionsParams, params?: SearchFunctionsParams): Promise<FunctionSearchResult>
semanticSearch(projectId: string, params: SearchCodeParams): Promise<SearchResult[]>
getFunctionStats(projectId: string): Promise<{ stats: { totalFunctions: number } }>

Tools (sdk.tools)

getSchemas(): Promise<ToolsResponse>
findToolByName(name: string): Promise<ToolSchema | null>
getToolsStats(): Promise<{ total: number; categories: Record<string, number>; mostUsed?: string[] }>
validateToolSchema(tool: ToolSchema): boolean
createToolSchema(name: string, description: string, properties: any, required?: string[]): ToolSchema

User (sdk.user)

getProfile(): Promise<UserProfile>
getLimitStatus(): Promise<LimitStatus>
checkAvailability(): Promise<boolean>

Auth (sdk.auth)

revokeToken(token: string): Promise<{ ok: boolean }>
logout(): Promise<{ ok: boolean }>

Models (sdk.models)

getAllModels(): Promise<any[]>
getModels(): Promise<any[]>
getAvailableModels(): Promise<any[]>
getProviderModels(providerId: string): Promise<ProviderModels>
getModelInfo(modelId: string): Promise<any>

Updates (sdk.updates)

checkForUpdates(options: UpdateCheckOptions): Promise<UpdateResponse>
getChangelog(version: string, locale: string): Promise<string>
sendStats(event: UpdateStatsEvent): Promise<void>
getLatestVersion(channel?: string): Promise<LatestVersionInfo>
checkAvailability(): Promise<boolean>

WebSocket (sdk.projectSync)

connectWebSocket(): Promise<void>
disconnectWebSocket(): void
isWebSocketConnected: boolean
projectSync.subscribeToProject(projectId: string): void
projectSync.unsubscribeFromProject(projectId: string): void
projectSync.on('sync-status-update', callback): void
projectSync.on('sync-progress', callback): void
projectSync.on('sync-completed', callback): void
projectSync.on('sync-error', callback): void
projectSync.off(event: string, callback): void

Utility

checkHealth(): Promise<boolean>
version: string
baseURL: string

Docs

All methods have JSDoc comments - check IDE autocomplete for full reference.


Status: ✅ Production Ready | v7.3.0 | License: MIT