npm package: @mchen-lab/service-clients
Description: Unified TypeScript client library for mchen-lab services
Author: mchen-lab
Latest version: 0.1.0

# @mchen-lab/service-clients

Unified TypeScript client library for mchen-lab services.

## Installation

```bash
npm install @mchen-lab/service-clients
```

Or install locally:
```bash
cd service-clients && npm install && npm run build
npm link  # Makes it available globally
cd ../your-project && npm link @mchen-lab/service-clients
```

## Quick Start

```typescript
import { 
  UploadServiceClient,
  LLMServiceClient,
  CrawlerServiceClient,
  ProxyServiceClient,
  ImageSearchClient
} from "@mchen-lab/service-clients";
```

---

## UploadServiceClient

File upload and bucket management.

### Constructor

```typescript
const upload = new UploadServiceClient({
  baseUrl: string;      // Required. e.g. "http://localhost:31150"
  apiKey: string;       // Required. Bucket API key from .settings.json
  bucket?: string;      // Optional default bucket name
});
```

### Methods

| Method | Description |
|--------|-------------|
| `upload(files, options?)` | Upload files to a bucket |
| `listFiles(bucket?, options?)` | List files with pagination |
| `deleteFile(path, bucket?)` | Delete a file |
| `getFileUrl(path, bucket?, variant?)` | Get file URL |
| `listBuckets()` | List all buckets |

### upload()

```typescript
const result = await upload.upload(
  files: string[] | Buffer[],  // File paths or buffers
  options?: {
    bucket?: string;           // Override default bucket
    filenames?: string[];      // Names for Buffer uploads
  }
): Promise<UploadResult>;

// Response
interface UploadResult {
  success: boolean;
  count: number;
  files: Array<{
    originalName: string;
    filename: string;      // e.g. "20260204_123456_abc123def.jpg"
    path: string;          // e.g. "2026/02/04/filename.jpg"
    size: number;
    mimetype: string;
    urls: {
      original: string;    // Full URL to original
      thumb?: string;      // Full URL to thumbnail
      medium?: string;     // Full URL to medium size
    };
  }>;
}
```

### listFiles()

```typescript
const files = await upload.listFiles(
  bucket?: string,
  options?: {
    search?: string;   // Filter by filename
    page?: number;     // Page number (default: 1)
    limit?: number;    // Items per page (default: 50)
  }
);
```

---

## LLMServiceClient

Text and structured generation.

### Constructor

```typescript
const llm = new LLMServiceClient({
  baseUrl: string;  // e.g. "http://localhost:31160"
});
```

### Methods

| Method | Description |
|--------|-------------|
| `gen_text(prompt, options?)` | Generate plain text |
| `gen_dict<T>(prompt, schema, options?)` | Generate structured output |
| `getSettings()` | Get current settings |
| `updateSettings(settings)` | Update settings |

### gen_text()

```typescript
const text = await llm.gen_text(
  prompt: string,
  options?: {
    model?: string;   // e.g. "openrouter:google/gemini-2.5-flash-lite"
    tag?: string;     // Tag for logging/filtering
    mode?: "auto" | "json" | "tools";  // Instructor mode
  }
): Promise<string>;
```

### gen_dict()

```typescript
const result = await llm.gen_dict<{ name: string; age: number }>(
  prompt: string,
  schema: string,     // String-schema format: "name:str, age:int"
  options?: GenerateOptions
): Promise<StructuredResult<T>>;

// Response
interface StructuredResult<T> {
  data: T;
  response_meta?: {
    model: string;
    finish_reason: string;
    usage?: { prompt_tokens, completion_tokens, total_tokens };
  };
}
```

**String-schema examples:**
- `"name:str, age:int"` → `{ name: string, age: number }`
- `"tags:[str]"` → `{ tags: string[] }`
- `"user:{name:str, email:str}"` → nested object

---

## CrawlerServiceClient

Web page fetching with browser rendering support.

### Constructor

```typescript
const crawler = new CrawlerServiceClient({
  baseUrl: string;  // e.g. "http://localhost:31170"
});
```

### Methods

| Method | Description |
|--------|-------------|
| `fetch(url, options?)` | Fetch a URL |
| `getStatus()` | Get crawler status |
| `updateConfig(config)` | Update crawler config |

### fetch()

```typescript
const result = await crawler.fetch(
  url: string,
  options?: {
    engine?: "auto" | "fast" | "browser";  // Default: "auto"
    renderJs?: boolean;   // Force JS rendering (default: false)
    proxy?: string;       // Proxy URL override
  }
): Promise<FetchResult>;

// Response
interface FetchResult {
  success: boolean;
  content?: string;     // HTML content
  url?: string;         // Final URL (after redirects)
  engineUsed?: string;  // "crawlee:http" | "crawlee:browser"
  error?: string;
}
```

**Engine options:**

| Engine | Description | Speed | JS Support |
|--------|-------------|-------|------------|
| `auto` | Auto-select based on page | Varies | Adaptive |
| `fast` | HTTP-only (Crawlee HTTP) | ⚡ Fast | ❌ No |
| `browser` | Full browser (Browserless) | 🐢 Slow | ✅ Yes |

---

## ProxyServiceClient

Proxy pool management (GOST-based).

### Constructor

```typescript
const proxy = new ProxyServiceClient({
  baseUrl: string;  // e.g. "http://localhost:31130"
});
```

### Methods

| Method | Description |
|--------|-------------|
| `getStatus()` | Get proxy service status |
| `getProxies()` | Get configured proxies |
| `setProxies(proxies)` | Set proxy list |
| `testProxy(url)` | Test connectivity through proxy |
| `getTestUrls()` | Get test URLs |
| `setTestUrls(urls)` | Set test URLs |

### setProxies()

```typescript
await proxy.setProxies(
  proxies: string[] | string  // Array or newline-separated string
);

// Supported formats:
// - "socks5://user:pass@host:port"
// - "http://host:port"
// - "https://user:pass@host:port"
```

### testProxy()

```typescript
const result = await proxy.testProxy(url: string): Promise<TestResult>;

interface TestResult {
  success: boolean;
  status?: number;
  data?: any;
  error?: string;
}
```

---

## ImageSearchClient

Multi-engine image search with translation.

### Constructor

```typescript
const imageSearch = new ImageSearchClient({
  baseUrl: string;  // e.g. "http://localhost:31140"
});
```

### Methods

| Method | Description |
|--------|-------------|
| `search(prompt, options?)` | Search for images |
| `getHistory(limit?, offset?)` | Get search history |
| `getHistoryDetail(id)` | Get history record details |
| `deleteHistory(id)` | Delete history record |
| `getStatus()` | Get service status |

### search()

```typescript
const result = await imageSearch.search(
  prompt: string,
  options?: {
    maxResults?: number;   // 1-50, default: 10
    size?: "small" | "medium" | "large";
    type?: "photo" | "clipart" | "line" | "gif" | "transparent";
  }
): Promise<SearchResult>;

// Response
interface SearchResult {
  success: boolean;
  query: string;
  images: Array<{
    url: string;
    thumbnail?: string;
    title?: string;
    source?: string;
    width?: number;
    height?: number;
  }>;
  savedPath?: string;
  error?: string;
}
```

### getHistory()

```typescript
const history = await imageSearch.getHistory(
  limit?: number,   // Max items (default: 50)
  offset?: number   // Skip items (default: 0)
): Promise<HistoryResult>;

interface HistoryResult {
  success: boolean;
  items: Array<{
    id: number;
    query: string;
    createdAt: string;
    imageCount: number;
  }>;
  total: number;
  count: number;
}
```

---

## Service Ports Reference

| Service | Port | Client |
|---------|------|--------|
| Upload Service | 31150 | `UploadServiceClient` |
| Simple LLM | 31160 | `LLMServiceClient` |
| Crawler | 31170 | `CrawlerServiceClient` |
| GOST Proxy | 31130 | `ProxyServiceClient` |
| Image Search | 31140 | `ImageSearchClient` |

## TypeScript

All types are exported:

```typescript
import type { 
  // Upload
  UploadResult, UploadedFile, FileInfo, FileListResult, BucketInfo,
  // LLM
  GenerateOptions, StructuredResult,
  // Crawler
  FetchOptions, FetchResult, CrawlerStatus,
  // Proxy
  ProxyStatus, TestResult,
  // Image Search
  SearchOptions, SearchResult, SearchImage, HistoryResult, HistoryDetail
} from "@mchen-lab/service-clients";
```

## DevOps

### Build & Publish

```bash
./publish.sh           # Build only (dry run)
./publish.sh --publish # Build and publish to npm
```

### Integration Testing

```bash
npm run test:clients
```

## License

MIT