|
1 | 1 | # Supermodel TypeScript SDK |
2 | 2 |
|
3 | | -[](https://www.npmjs.com/package/@supermodeltools/sdk) |
4 | | -[](https://www.typescriptlang.org/) |
5 | | -[](https://github.com/supermodeltools/typescript-sdk/actions/workflows/ci.yml) |
| 3 | +Official TypeScript/JavaScript SDK for the [Supermodel API](https://supermodeltools.com). |
6 | 4 |
|
7 | | -TypeScript client for the [Supermodel API](https://docs.supermodeltools.com) - code graph generation and static analysis. |
| 5 | +Generate code graphs, dependency analysis, and domain models from your source code repositories. |
8 | 6 |
|
9 | | -## Install |
| 7 | +## Installation |
10 | 8 |
|
11 | 9 | ```bash |
12 | 10 | npm install @supermodeltools/sdk |
13 | 11 | ``` |
14 | 12 |
|
15 | 13 | ## Quick Start |
16 | 14 |
|
17 | | -Get your API key from the [Supermodel Dashboard](https://dashboard.supermodeltools.com) and set it as `SUPERMODEL_API_KEY`. |
| 15 | +### Basic Usage (Auto-Polling) |
| 16 | + |
| 17 | +The SDK provides a high-level `SupermodelClient` that automatically handles async job polling: |
18 | 18 |
|
19 | 19 | ```typescript |
20 | | -import { Configuration, DefaultApi } from '@supermodeltools/sdk'; |
| 20 | +import { SupermodelClient, DefaultApi, Configuration } from '@supermodeltools/sdk'; |
21 | 21 | import { readFile } from 'node:fs/promises'; |
22 | 22 |
|
23 | | -const config = new Configuration({ |
| 23 | +// Configure the API client |
| 24 | +const api = new DefaultApi(new Configuration({ |
24 | 25 | basePath: 'https://api.supermodeltools.com', |
25 | | - apiKey: process.env.SUPERMODEL_API_KEY, |
| 26 | + apiKey: () => process.env.SUPERMODEL_API_KEY || '' |
| 27 | +})); |
| 28 | + |
| 29 | +// Create the async client wrapper |
| 30 | +const client = new SupermodelClient(api); |
| 31 | + |
| 32 | +// Generate a code graph (polling handled automatically) |
| 33 | +const zipBuffer = await readFile('./my-repo.zip'); |
| 34 | +const zipBlob = new Blob([zipBuffer]); |
| 35 | + |
| 36 | +const result = await client.generateSupermodelGraph(zipBlob); |
| 37 | +console.log(`Generated graph with ${result.graph.nodes.length} nodes`); |
| 38 | +``` |
| 39 | + |
| 40 | +### Advanced Configuration |
| 41 | + |
| 42 | +Configure polling behavior for long-running operations: |
| 43 | + |
| 44 | +```typescript |
| 45 | +const client = new SupermodelClient(api, { |
| 46 | + // Maximum time to wait for job completion |
| 47 | + timeoutMs: 900000, // 15 minutes (default) |
| 48 | + |
| 49 | + // Polling interval when server doesn't specify |
| 50 | + defaultRetryIntervalMs: 10000, // 10 seconds (default) |
| 51 | + |
| 52 | + // Maximum number of polling attempts |
| 53 | + maxPollingAttempts: 90, // (default) |
| 54 | + |
| 55 | + // Progress callback |
| 56 | + onPollingProgress: (progress) => { |
| 57 | + console.log(`Job ${progress.jobId}: ${progress.status} ` + |
| 58 | + `(${progress.attempt}/${progress.maxAttempts})`); |
| 59 | + }, |
| 60 | + |
| 61 | + // Cancellation support |
| 62 | + signal: abortController.signal, |
| 63 | +}); |
| 64 | +``` |
| 65 | + |
| 66 | +### Per-Request Configuration |
| 67 | + |
| 68 | +Override client defaults for specific requests: |
| 69 | + |
| 70 | +```typescript |
| 71 | +// Use a custom idempotency key |
| 72 | +const result = await client.generateDependencyGraph(zipBlob, { |
| 73 | + idempotencyKey: 'my-repo:dependency:abc123', |
| 74 | +}); |
| 75 | + |
| 76 | +// Add custom headers (e.g., for different auth) |
| 77 | +const result = await client.generateCallGraph(zipBlob, { |
| 78 | + initOverrides: { |
| 79 | + headers: { 'Authorization': 'Bearer custom-token' } |
| 80 | + } |
| 81 | +}); |
| 82 | + |
| 83 | +// Cancel a specific request |
| 84 | +const controller = new AbortController(); |
| 85 | +const promise = client.generateParseGraph(zipBlob, { |
| 86 | + signal: controller.signal |
| 87 | +}); |
| 88 | + |
| 89 | +// Later: controller.abort(); |
| 90 | +``` |
| 91 | + |
| 92 | +## Available Methods |
| 93 | + |
| 94 | +### SupermodelClient (Async Wrapper) |
| 95 | + |
| 96 | +All methods automatically handle polling until job completion: |
| 97 | + |
| 98 | +- `generateSupermodelGraph(file, options?)` - Full Supermodel IR with all analysis |
| 99 | +- `generateDependencyGraph(file, options?)` - Module/package dependencies |
| 100 | +- `generateCallGraph(file, options?)` - Function-level call relationships |
| 101 | +- `generateDomainGraph(file, options?)` - High-level domain model |
| 102 | +- `generateParseGraph(file, options?)` - AST-level parse tree |
| 103 | + |
| 104 | +### Raw API (Manual Polling) |
| 105 | + |
| 106 | +Access the underlying API for manual control: |
| 107 | + |
| 108 | +```typescript |
| 109 | +const rawApi = client.rawApi; |
| 110 | + |
| 111 | +// Make initial request |
| 112 | +let response = await rawApi.generateDependencyGraph({ |
| 113 | + idempotencyKey: 'my-key', |
| 114 | + file: zipBlob |
| 115 | +}); |
| 116 | + |
| 117 | +// Poll manually |
| 118 | +while (response.status === 'pending' || response.status === 'processing') { |
| 119 | + await sleep(response.retryAfter * 1000); |
| 120 | + response = await rawApi.generateDependencyGraph({ |
| 121 | + idempotencyKey: 'my-key', |
| 122 | + file: zipBlob |
| 123 | + }); |
| 124 | +} |
| 125 | + |
| 126 | +if (response.status === 'completed') { |
| 127 | + console.log(response.result); |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +## Configuration Options |
| 132 | + |
| 133 | +### AsyncClientOptions |
| 134 | + |
| 135 | +| Option | Type | Default | Description | |
| 136 | +|--------|------|---------|-------------| |
| 137 | +| `timeoutMs` | `number` | `900000` (15 min) | Maximum time to wait for job completion | |
| 138 | +| `defaultRetryIntervalMs` | `number` | `10000` (10 sec) | Polling interval when server doesn't specify | |
| 139 | +| `maxPollingAttempts` | `number` | `90` | Maximum number of polling attempts | |
| 140 | +| `onPollingProgress` | `function` | `undefined` | Callback for polling progress updates | |
| 141 | +| `generateIdempotencyKey` | `function` | `crypto.randomUUID()` | Custom idempotency key generator | |
| 142 | +| `signal` | `AbortSignal` | `undefined` | AbortSignal for cancelling operations | |
| 143 | + |
| 144 | +### GraphRequestOptions |
| 145 | + |
| 146 | +| Option | Type | Default | Description | |
| 147 | +|--------|------|---------|-------------| |
| 148 | +| `idempotencyKey` | `string` | auto-generated | Idempotency key for request deduplication | |
| 149 | +| `initOverrides` | `RequestInit` | `undefined` | Custom fetch options (headers, etc.) | |
| 150 | +| `signal` | `AbortSignal` | `undefined` | Request-specific abort signal | |
| 151 | + |
| 152 | +## Error Handling |
| 153 | + |
| 154 | +```typescript |
| 155 | +import { JobFailedError, PollingTimeoutError } from '@supermodeltools/sdk'; |
| 156 | + |
| 157 | +try { |
| 158 | + const result = await client.generateDependencyGraph(zipBlob); |
| 159 | +} catch (error) { |
| 160 | + if (error instanceof JobFailedError) { |
| 161 | + console.error(`Job ${error.jobId} failed: ${error.errorMessage}`); |
| 162 | + } else if (error instanceof PollingTimeoutError) { |
| 163 | + console.error(`Job ${error.jobId} timed out after ${error.timeoutMs}ms`); |
| 164 | + } else if (error.name === 'AbortError') { |
| 165 | + console.log('Operation cancelled'); |
| 166 | + } else { |
| 167 | + throw error; |
| 168 | + } |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +## Idempotency |
| 173 | + |
| 174 | +The API uses idempotency keys to prevent duplicate processing. The same key will always return the same result: |
| 175 | + |
| 176 | +```typescript |
| 177 | +// Generate a stable key from your repo state |
| 178 | +import crypto from 'crypto'; |
| 179 | +import { execSync } from 'child_process'; |
| 180 | + |
| 181 | +const gitHash = execSync('git rev-parse --short HEAD').toString().trim(); |
| 182 | +const idempotencyKey = `my-project:supermodel:${gitHash}`; |
| 183 | + |
| 184 | +// This will generate once, then return cached result on subsequent calls |
| 185 | +const result = await client.generateSupermodelGraph(zipBlob, { |
| 186 | + idempotencyKey |
26 | 187 | }); |
| 188 | +``` |
| 189 | + |
| 190 | +## Preparing Repository Archives |
| 191 | + |
| 192 | +### For Git Repositories (Recommended) |
| 193 | + |
| 194 | +```bash |
| 195 | +cd /path/to/your/repo |
| 196 | +git archive -o /tmp/repo.zip HEAD |
| 197 | +``` |
| 198 | + |
| 199 | +This automatically respects `.gitignore` and creates clean, reproducible archives. |
| 200 | + |
| 201 | +### For Any Directory |
| 202 | + |
| 203 | +```bash |
| 204 | +cd /path/to/your/repo |
| 205 | +zip -r /tmp/repo.zip . \ |
| 206 | + -x "node_modules/*" \ |
| 207 | + -x ".git/*" \ |
| 208 | + -x "dist/*" \ |
| 209 | + -x "*.pyc" \ |
| 210 | + -x "__pycache__/*" |
| 211 | +``` |
| 212 | + |
| 213 | +### What to Include |
| 214 | + |
| 215 | +- ✅ Source code files (`.py`, `.js`, `.ts`, `.java`, etc.) |
| 216 | +- ✅ Configuration files (`package.json`, `pyproject.toml`, etc.) |
| 217 | +- ✅ Type definitions (`.d.ts`, `.pyi`) |
| 218 | +- ❌ Dependencies (`node_modules/`, `venv/`, `target/`) |
| 219 | +- ❌ Build outputs (`dist/`, `build/`, `.next/`) |
| 220 | +- ❌ Large binaries, images, datasets |
| 221 | + |
| 222 | +### Size Limits |
27 | 223 |
|
28 | | -const api = new DefaultApi(config); |
| 224 | +Archives should be under 50MB. If larger: |
| 225 | +- Ensure dependencies are excluded |
| 226 | +- Consider analyzing a subdirectory |
| 227 | +- Check for accidentally committed binaries |
29 | 228 |
|
30 | | -// Create a ZIP of your repo: git archive -o /tmp/repo.zip HEAD |
31 | | -const file = new Blob([await readFile('/tmp/repo.zip')], { type: 'application/zip' }); |
| 229 | +## TypeScript Support |
32 | 230 |
|
33 | | -const result = await api.generateSupermodelGraph({ |
34 | | - idempotencyKey: 'my-repo:supermodel:abc123', |
35 | | - file, |
| 231 | +Full TypeScript definitions are included. Types are automatically resolved via `package.json`. |
| 232 | + |
| 233 | +```typescript |
| 234 | +import type { |
| 235 | + SupermodelIR, |
| 236 | + CodeGraphEnvelope, |
| 237 | + DomainClassificationResponse, |
| 238 | +} from '@supermodeltools/sdk'; |
| 239 | + |
| 240 | +// Types are available for all request/response models |
| 241 | +``` |
| 242 | + |
| 243 | +## Environment Support |
| 244 | + |
| 245 | +- ✅ Node.js (18+) |
| 246 | +- ✅ Modern browsers (with Blob support) |
| 247 | +- ✅ Webpack, Vite, Rollup |
| 248 | +- ✅ ES6 modules and CommonJS |
| 249 | + |
| 250 | +## Authentication |
| 251 | + |
| 252 | +Get your API key from the [Supermodel Dashboard](https://dashboard.supermodeltools.com). |
| 253 | + |
| 254 | +```typescript |
| 255 | +const api = new DefaultApi(new Configuration({ |
| 256 | + basePath: 'https://api.supermodeltools.com', |
| 257 | + apiKey: () => process.env.SUPERMODEL_API_KEY || '' |
| 258 | +})); |
| 259 | +``` |
| 260 | + |
| 261 | +## Rate Limiting |
| 262 | + |
| 263 | +The API includes rate limiting headers in responses: |
| 264 | + |
| 265 | +```typescript |
| 266 | +const response = await rawApi.generateDependencyGraphRaw({ |
| 267 | + idempotencyKey: 'key', |
| 268 | + file: blob |
36 | 269 | }); |
37 | 270 |
|
38 | | -console.log(result.graph.nodes.length, 'nodes'); |
| 271 | +console.log(response.raw.headers.get('RateLimit-Limit')); |
| 272 | +console.log(response.raw.headers.get('RateLimit-Remaining')); |
| 273 | +console.log(response.raw.headers.get('RateLimit-Reset')); |
39 | 274 | ``` |
40 | 275 |
|
41 | | -## Methods |
| 276 | +## Examples |
| 277 | + |
| 278 | +### Integration with mcpbr |
42 | 279 |
|
43 | | -| Method | Description | |
44 | | -|--------|-------------| |
45 | | -| `generateDependencyGraph` | File-level dependency graph | |
46 | | -| `generateCallGraph` | Function-level call graph | |
47 | | -| `generateDomainGraph` | Domain model classification | |
48 | | -| `generateParseGraph` | AST parse tree relationships | |
49 | | -| `generateSupermodelGraph` | Full Supermodel IR bundle | |
| 280 | +```typescript |
| 281 | +import { SupermodelClient, DefaultApi, Configuration } from '@supermodeltools/sdk'; |
50 | 282 |
|
51 | | -All methods require `idempotencyKey` (string) and `file` (Blob) parameters. |
| 283 | +const api = new DefaultApi(new Configuration({ |
| 284 | + basePath: process.env.SUPERMODEL_BASE_URL || 'https://api.supermodeltools.com', |
| 285 | + apiKey: () => process.env.SUPERMODEL_API_KEY || '' |
| 286 | +})); |
| 287 | + |
| 288 | +// Configure for long-running benchmark operations |
| 289 | +const client = new SupermodelClient(api, { |
| 290 | + timeoutMs: 900000, // 15 minutes |
| 291 | + maxPollingAttempts: 90, // 90 attempts |
| 292 | + onPollingProgress: (progress) => { |
| 293 | + console.log(`[${progress.jobId}] ${progress.status} - ` + |
| 294 | + `attempt ${progress.attempt}/${progress.maxAttempts}`); |
| 295 | + } |
| 296 | +}); |
| 297 | +``` |
52 | 298 |
|
53 | 299 | ## Links |
54 | 300 |
|
55 | 301 | - [API Documentation](https://docs.supermodeltools.com) |
56 | | -- [OpenAPI Spec](https://www.npmjs.com/package/@supermodeltools/openapi-spec) |
| 302 | +- [GitHub Repository](https://github.com/supermodeltools/supermodel-public-api) |
| 303 | +- [Dashboard](https://dashboard.supermodeltools.com) |
| 304 | +- [Terms of Service](https://supermodeltools.com/legal/api-terms) |
| 305 | + |
| 306 | +## License |
| 307 | + |
| 308 | +This SDK is licensed under the MIT License. See the main repository for details. |
0 commit comments