@uluops/ops-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1647 -0
- package/dist/client.d.ts +191 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +168 -0
- package/dist/client.js.map +1 -0
- package/dist/config/constants.d.ts +27 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +35 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loaders.d.ts +41 -0
- package/dist/config/loaders.d.ts.map +1 -0
- package/dist/config/loaders.js +43 -0
- package/dist/config/loaders.js.map +1 -0
- package/dist/config/validators.d.ts +163 -0
- package/dist/config/validators.d.ts.map +1 -0
- package/dist/config/validators.js +126 -0
- package/dist/config/validators.js.map +1 -0
- package/dist/errors/errors.d.ts +7 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +7 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/http/auth-strategy.d.ts +5 -0
- package/dist/http/auth-strategy.d.ts.map +1 -0
- package/dist/http/auth-strategy.js +5 -0
- package/dist/http/auth-strategy.js.map +1 -0
- package/dist/http/fetch-adapter.d.ts +5 -0
- package/dist/http/fetch-adapter.d.ts.map +1 -0
- package/dist/http/fetch-adapter.js +2 -0
- package/dist/http/fetch-adapter.js.map +1 -0
- package/dist/http/http-client.d.ts +29 -0
- package/dist/http/http-client.d.ts.map +1 -0
- package/dist/http/http-client.js +25 -0
- package/dist/http/http-client.js.map +1 -0
- package/dist/http/index.d.ts +6 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/http/index.js +3 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/admin.d.ts +89 -0
- package/dist/operations/admin.d.ts.map +1 -0
- package/dist/operations/admin.js +134 -0
- package/dist/operations/admin.js.map +1 -0
- package/dist/operations/analytics.d.ts +81 -0
- package/dist/operations/analytics.d.ts.map +1 -0
- package/dist/operations/analytics.js +111 -0
- package/dist/operations/analytics.js.map +1 -0
- package/dist/operations/auth.d.ts +81 -0
- package/dist/operations/auth.d.ts.map +1 -0
- package/dist/operations/auth.js +115 -0
- package/dist/operations/auth.js.map +1 -0
- package/dist/operations/index.d.ts +8 -0
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +8 -0
- package/dist/operations/index.js.map +1 -0
- package/dist/operations/issues.d.ts +59 -0
- package/dist/operations/issues.d.ts.map +1 -0
- package/dist/operations/issues.js +141 -0
- package/dist/operations/issues.js.map +1 -0
- package/dist/operations/projects.d.ts +56 -0
- package/dist/operations/projects.d.ts.map +1 -0
- package/dist/operations/projects.js +99 -0
- package/dist/operations/projects.js.map +1 -0
- package/dist/operations/query-utils.d.ts +20 -0
- package/dist/operations/query-utils.d.ts.map +1 -0
- package/dist/operations/query-utils.js +22 -0
- package/dist/operations/query-utils.js.map +1 -0
- package/dist/operations/runs.d.ts +53 -0
- package/dist/operations/runs.d.ts.map +1 -0
- package/dist/operations/runs.js +118 -0
- package/dist/operations/runs.js.map +1 -0
- package/dist/operations/taxonomy.d.ts +7 -0
- package/dist/operations/taxonomy.d.ts.map +1 -0
- package/dist/operations/taxonomy.js +7 -0
- package/dist/operations/taxonomy.js.map +1 -0
- package/dist/types/analytics.d.ts +338 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/analytics.js +2 -0
- package/dist/types/analytics.js.map +1 -0
- package/dist/types/auth.d.ts +303 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/enums.d.ts +200 -0
- package/dist/types/enums.d.ts.map +1 -0
- package/dist/types/enums.js +222 -0
- package/dist/types/enums.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/issues.d.ts +182 -0
- package/dist/types/issues.d.ts.map +1 -0
- package/dist/types/issues.js +2 -0
- package/dist/types/issues.js.map +1 -0
- package/dist/types/projects.d.ts +123 -0
- package/dist/types/projects.d.ts.map +1 -0
- package/dist/types/projects.js +2 -0
- package/dist/types/projects.js.map +1 -0
- package/dist/types/response-schemas.d.ts +3441 -0
- package/dist/types/response-schemas.d.ts.map +1 -0
- package/dist/types/response-schemas.js +388 -0
- package/dist/types/response-schemas.js.map +1 -0
- package/dist/types/responses.d.ts +84 -0
- package/dist/types/responses.d.ts.map +1 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/responses.js.map +1 -0
- package/dist/types/runs.d.ts +232 -0
- package/dist/types/runs.d.ts.map +1 -0
- package/dist/types/runs.js +2 -0
- package/dist/types/runs.js.map +1 -0
- package/dist/types/schemas.d.ts +914 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +280 -0
- package/dist/types/schemas.js.map +1 -0
- package/dist/utils/helpers.d.ts +64 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +127 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +5 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +103 -0
package/README.md
ADDED
|
@@ -0,0 +1,1647 @@
|
|
|
1
|
+
# @uluops/ops-sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@uluops/ops-sdk)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
|
|
8
|
+
Official TypeScript SDK with Zod runtime validation for the UluOps validation tracker API. Track validation runs, manage issues, analyze trends, and integrate AI validation pipelines into your workflow.
|
|
9
|
+
|
|
10
|
+
**Current version: 0.1.0** | [Changelog](./CHANGELOG.md)
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
### Programmatic Usage
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { OpsClient } from '@uluops/ops-sdk';
|
|
18
|
+
|
|
19
|
+
// Defaults to http://localhost:3100/api/v1 for local dev.
|
|
20
|
+
// For production, set ULUOPS_BASE_URL env var or pass baseUrl below.
|
|
21
|
+
const client = new OpsClient({
|
|
22
|
+
apiKey: 'ulr_your-api-key-here', // Create via client.auth.createApiKey() or admin dashboard
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Save a validation run
|
|
26
|
+
const result = await client.runs.save({
|
|
27
|
+
project: 'my-project',
|
|
28
|
+
workflowType: 'post-implementation',
|
|
29
|
+
validators: [
|
|
30
|
+
{ name: 'code-validator', score: 85, status: 'PASS' },
|
|
31
|
+
{ name: 'test-architect', score: 72, status: 'APPROVED' },
|
|
32
|
+
],
|
|
33
|
+
recommendations: [
|
|
34
|
+
{
|
|
35
|
+
validator: 'code-validator',
|
|
36
|
+
title: 'Missing error handling',
|
|
37
|
+
priority: 'suggested',
|
|
38
|
+
filePath: 'src/api/client.ts',
|
|
39
|
+
lineNumber: 42,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log(`Run #${result.run.runNumber} saved: ${result.correlation.newIssues} new issues`);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Search Issues
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const issues = await client.issues.search({
|
|
51
|
+
query: 'authentication',
|
|
52
|
+
status: 'open',
|
|
53
|
+
priority: 'critical',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
for (const issue of issues) {
|
|
57
|
+
console.log(`[${issue.severity}] ${issue.title} — ${issue.filePath}:${issue.lineNumber}`);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Project Analytics
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const burndown = await client.analytics.getBurndown({
|
|
65
|
+
project: 'my-project',
|
|
66
|
+
days: 30,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
for (const [domain, trend] of Object.entries(burndown.trends)) {
|
|
70
|
+
console.log(`${domain}: ${trend.direction} (rate: ${trend.rate})`);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Table of Contents
|
|
75
|
+
|
|
76
|
+
- [Overview](#overview)
|
|
77
|
+
- [Features](#features)
|
|
78
|
+
- [Installation](#installation)
|
|
79
|
+
- [Authentication](#authentication)
|
|
80
|
+
- [TypeScript Support](#typescript-support)
|
|
81
|
+
- [API Reference](#api-reference)
|
|
82
|
+
- [Auth Operations](#auth-operations)
|
|
83
|
+
- [Project Operations](#project-operations)
|
|
84
|
+
- [Run Operations](#run-operations)
|
|
85
|
+
- [Issue Operations](#issue-operations)
|
|
86
|
+
- [Analytics Operations](#analytics-operations)
|
|
87
|
+
- [Taxonomy Operations](#taxonomy-operations)
|
|
88
|
+
- [Health Check](#health-check)
|
|
89
|
+
- [Admin Operations](#admin-operations)
|
|
90
|
+
- [Environment Variables](#environment-variables)
|
|
91
|
+
- [Error Handling](#error-handling)
|
|
92
|
+
- [Advanced Usage](#advanced-usage)
|
|
93
|
+
- [Troubleshooting](#troubleshooting)
|
|
94
|
+
- [License](#license)
|
|
95
|
+
|
|
96
|
+
## Overview
|
|
97
|
+
|
|
98
|
+
The UluOps SDK provides programmatic access to the UluOps validation tracker API, enabling you to:
|
|
99
|
+
|
|
100
|
+
- **Track Validation Runs**: Save validation pipeline results with validator scores and recommendations
|
|
101
|
+
- **Manage Issues**: Create, search, update, and track issues across projects
|
|
102
|
+
- **Analyze Trends**: Get burndown charts, velocity metrics, and taxonomy distribution analytics
|
|
103
|
+
- **Automate Workflows**: Integrate validation tracking into CI/CD pipelines
|
|
104
|
+
|
|
105
|
+
The SDK covers **74 API endpoints** across 7 operation domains with full TypeScript support.
|
|
106
|
+
|
|
107
|
+
## Features
|
|
108
|
+
|
|
109
|
+
- **Full API Coverage**: Access all 74 endpoints across auth, projects, runs, issues, analytics, taxonomy, and admin domains
|
|
110
|
+
- **Type-Safe**: Complete TypeScript definitions with Zod runtime validation
|
|
111
|
+
- **Dual Authentication**: API key (preferred) and JWT session support
|
|
112
|
+
- **Automatic Retries**: Exponential backoff for transient errors (502, 503, 504, 429)
|
|
113
|
+
- **Error Hierarchy**: Typed errors for precise error handling
|
|
114
|
+
- **Subpath Exports**: Import only what you need (`@uluops/ops-sdk/types`, `@uluops/ops-sdk/errors`)
|
|
115
|
+
|
|
116
|
+
## Installation
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# npm
|
|
120
|
+
npm install @uluops/ops-sdk
|
|
121
|
+
|
|
122
|
+
# yarn
|
|
123
|
+
yarn add @uluops/ops-sdk
|
|
124
|
+
|
|
125
|
+
# pnpm
|
|
126
|
+
pnpm add @uluops/ops-sdk
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Requirements:**
|
|
130
|
+
- Node.js 18.0.0 or higher
|
|
131
|
+
- TypeScript 5.0+ (for TypeScript users)
|
|
132
|
+
|
|
133
|
+
## Authentication
|
|
134
|
+
|
|
135
|
+
The SDK supports two authentication methods:
|
|
136
|
+
|
|
137
|
+
### API Key Authentication (Recommended)
|
|
138
|
+
|
|
139
|
+
API keys provide persistent authentication without session management. Keys must start with the `ulr_` prefix.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { OpsClient } from '@uluops/ops-sdk';
|
|
143
|
+
|
|
144
|
+
const client = new OpsClient({
|
|
145
|
+
apiKey: 'ulr_your-api-key-here',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Check authentication status
|
|
149
|
+
console.log(client.isAuthenticated()); // true
|
|
150
|
+
console.log(client.getAuthType()); // 'api_key'
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Session-Based Authentication
|
|
154
|
+
|
|
155
|
+
For interactive applications, you can authenticate with email/password:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { OpsClient } from '@uluops/ops-sdk';
|
|
159
|
+
|
|
160
|
+
const client = new OpsClient({
|
|
161
|
+
baseUrl: 'https://api.uluops.com/api/v1',
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Login to get a session
|
|
165
|
+
const { token, user } = await client.auth.login({
|
|
166
|
+
email: 'user@example.com',
|
|
167
|
+
password: 'your-password',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Create a new client with the session token
|
|
171
|
+
const authenticatedClient = new OpsClient({
|
|
172
|
+
sessionToken: token,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Logout when done
|
|
176
|
+
await authenticatedClient.logout();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Credential Priority Chain
|
|
180
|
+
|
|
181
|
+
The SDK loads credentials in the following order:
|
|
182
|
+
|
|
183
|
+
1. **Constructor arguments**: `apiKey`, `sessionToken`, `email`/`password`
|
|
184
|
+
2. **Environment variables**: `ULUOPS_API_KEY`, `ULUOPS_EMAIL`, `ULUOPS_PASSWORD`
|
|
185
|
+
3. **Local `.env` file**: In the current working directory
|
|
186
|
+
4. **Global credentials**: `~/.uluops/credentials.json`
|
|
187
|
+
|
|
188
|
+
## TypeScript Support
|
|
189
|
+
|
|
190
|
+
The SDK is written in TypeScript with full type definitions. Import types directly:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Main client
|
|
194
|
+
import { OpsClient, type OpsClientConfig } from '@uluops/ops-sdk';
|
|
195
|
+
|
|
196
|
+
// Types only
|
|
197
|
+
import type {
|
|
198
|
+
Project,
|
|
199
|
+
Issue,
|
|
200
|
+
Run,
|
|
201
|
+
ValidatorPerformance,
|
|
202
|
+
Priority,
|
|
203
|
+
Status,
|
|
204
|
+
Severity,
|
|
205
|
+
} from '@uluops/ops-sdk/types';
|
|
206
|
+
|
|
207
|
+
// Errors only
|
|
208
|
+
import {
|
|
209
|
+
OpsApiError,
|
|
210
|
+
ValidationError,
|
|
211
|
+
NotFoundError,
|
|
212
|
+
RateLimitError,
|
|
213
|
+
} from '@uluops/ops-sdk/errors';
|
|
214
|
+
|
|
215
|
+
// Config utilities
|
|
216
|
+
import { loadCredentials, DEFAULT_BASE_URL } from '@uluops/ops-sdk/config';
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Package Exports
|
|
220
|
+
|
|
221
|
+
| Export Path | Contents |
|
|
222
|
+
|------------|----------|
|
|
223
|
+
| `@uluops/ops-sdk` | Main `OpsClient`, `OpsHttpClient`, auth strategies |
|
|
224
|
+
| `@uluops/ops-sdk/types` | All TypeScript types and Zod schemas |
|
|
225
|
+
| `@uluops/ops-sdk/errors` | Error classes and utilities |
|
|
226
|
+
| `@uluops/ops-sdk/config` | Configuration loaders and constants |
|
|
227
|
+
|
|
228
|
+
#### Granular Type Imports
|
|
229
|
+
|
|
230
|
+
For minimal bundle size, import only the type modules you need:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import type { Project } from '@uluops/ops-sdk/types/projects';
|
|
234
|
+
import type { Issue } from '@uluops/ops-sdk/types/issues';
|
|
235
|
+
import type { Run } from '@uluops/ops-sdk/types/runs';
|
|
236
|
+
import type { BurndownResult } from '@uluops/ops-sdk/types/analytics';
|
|
237
|
+
import type { Priority, Status, Severity } from '@uluops/ops-sdk/types/enums';
|
|
238
|
+
import type { ApiResponse } from '@uluops/ops-sdk/types/responses';
|
|
239
|
+
import type { SaveFeaturesListInput } from '@uluops/ops-sdk/types/schemas';
|
|
240
|
+
import type { Credentials } from '@uluops/ops-sdk/types/auth';
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## API Reference
|
|
244
|
+
|
|
245
|
+
### Client Configuration
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const client = new OpsClient({
|
|
249
|
+
// Authentication (choose one)
|
|
250
|
+
apiKey: 'ulr_...', // API key (preferred)
|
|
251
|
+
sessionToken: 'jwt-token', // Existing session token
|
|
252
|
+
email: 'user@example.com', // Email for login
|
|
253
|
+
password: 'password', // Password for login
|
|
254
|
+
|
|
255
|
+
// Connection settings
|
|
256
|
+
baseUrl: 'http://localhost:3100/api/v1', // API base URL
|
|
257
|
+
timeout: 30000, // Request timeout in ms (default: 30000)
|
|
258
|
+
retries: 3, // Retry count for transient errors (default: 3)
|
|
259
|
+
debug: false, // Enable debug logging
|
|
260
|
+
|
|
261
|
+
// Callbacks
|
|
262
|
+
onTokenRefresh: (token) => { /* handle token refresh */ },
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### Auth Operations
|
|
269
|
+
|
|
270
|
+
Manage user authentication, API keys, and sessions.
|
|
271
|
+
|
|
272
|
+
#### `client.auth.register(input)`
|
|
273
|
+
|
|
274
|
+
Register a new user account.
|
|
275
|
+
|
|
276
|
+
| Parameter | Type | Required | Description |
|
|
277
|
+
|-----------|------|----------|-------------|
|
|
278
|
+
| `email` | `string` | Yes | User email address |
|
|
279
|
+
| `password` | `string` | Yes | User password |
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
const { user, token } = await client.auth.register({
|
|
283
|
+
email: 'newuser@example.com',
|
|
284
|
+
password: 'securePassword123',
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### `client.auth.login(input)`
|
|
289
|
+
|
|
290
|
+
Login with email and password.
|
|
291
|
+
|
|
292
|
+
| Parameter | Type | Required | Description |
|
|
293
|
+
|-----------|------|----------|-------------|
|
|
294
|
+
| `email` | `string` | Yes | User email address |
|
|
295
|
+
| `password` | `string` | Yes | User password |
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
const { user, token } = await client.auth.login({
|
|
299
|
+
email: 'user@example.com',
|
|
300
|
+
password: 'password123',
|
|
301
|
+
});
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### `client.auth.logoutAll()`
|
|
305
|
+
|
|
306
|
+
Revoke all active sessions for the current user.
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
const { sessionsRevoked } = await client.auth.logoutAll();
|
|
310
|
+
console.log(`Revoked ${sessionsRevoked} sessions`);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### `client.auth.getMe()`
|
|
314
|
+
|
|
315
|
+
Get the current authenticated user.
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
const user = await client.auth.getMe();
|
|
319
|
+
console.log(user.email, user.role);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### `client.auth.getProfile()`
|
|
323
|
+
|
|
324
|
+
Get detailed user profile.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
const { user } = await client.auth.getProfile();
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### `client.auth.updateProfile(input)`
|
|
331
|
+
|
|
332
|
+
Update user profile information.
|
|
333
|
+
|
|
334
|
+
| Parameter | Type | Required | Description |
|
|
335
|
+
|-----------|------|----------|-------------|
|
|
336
|
+
| `displayName` | `string` | No | Display name |
|
|
337
|
+
| `bio` | `string` | No | User bio |
|
|
338
|
+
| `avatarUrl` | `string` | No | Avatar URL |
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
const { user } = await client.auth.updateProfile({
|
|
342
|
+
displayName: 'John Doe',
|
|
343
|
+
bio: 'Software Engineer',
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### `client.auth.changePassword(input)`
|
|
348
|
+
|
|
349
|
+
Change the current user's password.
|
|
350
|
+
|
|
351
|
+
| Parameter | Type | Required | Description |
|
|
352
|
+
|-----------|------|----------|-------------|
|
|
353
|
+
| `currentPassword` | `string` | Yes | Current password |
|
|
354
|
+
| `newPassword` | `string` | Yes | New password |
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
await client.auth.changePassword({
|
|
358
|
+
currentPassword: 'oldPassword',
|
|
359
|
+
newPassword: 'newSecurePassword',
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
#### `client.auth.forgotPassword(email)`
|
|
364
|
+
|
|
365
|
+
Request a password reset email.
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
await client.auth.forgotPassword('user@example.com');
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### `client.auth.resetPassword(input)`
|
|
372
|
+
|
|
373
|
+
Reset password using a reset token.
|
|
374
|
+
|
|
375
|
+
| Parameter | Type | Required | Description |
|
|
376
|
+
|-----------|------|----------|-------------|
|
|
377
|
+
| `token` | `string` | Yes | Reset token from email |
|
|
378
|
+
| `newPassword` | `string` | Yes | New password |
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
await client.auth.resetPassword({
|
|
382
|
+
token: 'reset-token-from-email',
|
|
383
|
+
newPassword: 'newSecurePassword',
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### `client.auth.listApiKeys()`
|
|
388
|
+
|
|
389
|
+
List all API keys for the current user.
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const keys = await client.auth.listApiKeys();
|
|
393
|
+
for (const key of keys) {
|
|
394
|
+
console.log(key.name, key.prefix, key.createdAt);
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
#### `client.auth.createApiKey(input)`
|
|
399
|
+
|
|
400
|
+
Create a new API key.
|
|
401
|
+
|
|
402
|
+
| Parameter | Type | Required | Description |
|
|
403
|
+
|-----------|------|----------|-------------|
|
|
404
|
+
| `name` | `string` | No | Key name/description |
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
const { id, name, key } = await client.auth.createApiKey({ name: 'CI Pipeline' });
|
|
408
|
+
console.log('Save this key:', key); // Only shown once!
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### `client.auth.revokeApiKey(keyId)`
|
|
412
|
+
|
|
413
|
+
Revoke an API key.
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
await client.auth.revokeApiKey('key-id-123');
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
#### `client.auth.listSessions()`
|
|
420
|
+
|
|
421
|
+
List all active sessions.
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const sessions = await client.auth.listSessions();
|
|
425
|
+
for (const session of sessions) {
|
|
426
|
+
console.log(session.userAgent, session.createdAt);
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
#### `client.auth.revokeSession(sessionId)`
|
|
431
|
+
|
|
432
|
+
Revoke a specific session.
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
await client.auth.revokeSession('session-id-123');
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### Project Operations
|
|
441
|
+
|
|
442
|
+
Manage validation projects.
|
|
443
|
+
|
|
444
|
+
#### `client.projects.list()`
|
|
445
|
+
|
|
446
|
+
List all projects.
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
const projects = await client.projects.list();
|
|
450
|
+
for (const project of projects) {
|
|
451
|
+
console.log(project.id, project.name, project.createdAt);
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
#### `client.projects.get(idOrName)`
|
|
456
|
+
|
|
457
|
+
Get a project by ID or name.
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
const project = await client.projects.get('my-project');
|
|
461
|
+
console.log(project.name, project.runCount, project.issueCount);
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
#### `client.projects.create(input)`
|
|
465
|
+
|
|
466
|
+
Create a new project.
|
|
467
|
+
|
|
468
|
+
| Parameter | Type | Required | Description |
|
|
469
|
+
|-----------|------|----------|-------------|
|
|
470
|
+
| `name` | `string` | Yes | Project name (unique) |
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
const project = await client.projects.create({ name: 'new-project' });
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
#### `client.projects.update(idOrName, input)`
|
|
477
|
+
|
|
478
|
+
Update a project.
|
|
479
|
+
|
|
480
|
+
| Parameter | Type | Required | Description |
|
|
481
|
+
|-----------|------|----------|-------------|
|
|
482
|
+
| `name` | `string` | No | New project name |
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
const project = await client.projects.update('my-project', {
|
|
486
|
+
name: 'renamed-project',
|
|
487
|
+
});
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
#### `client.projects.rename(input)`
|
|
491
|
+
|
|
492
|
+
Rename a project.
|
|
493
|
+
|
|
494
|
+
| Parameter | Type | Required | Description |
|
|
495
|
+
|-----------|------|----------|-------------|
|
|
496
|
+
| `project` | `string` | Yes | Current project name or ID |
|
|
497
|
+
| `name` | `string` | Yes | New project name |
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
const project = await client.projects.rename({
|
|
501
|
+
project: 'old-name',
|
|
502
|
+
name: 'new-name',
|
|
503
|
+
});
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
#### `client.projects.delete(idOrName, input)`
|
|
507
|
+
|
|
508
|
+
Permanently delete a project.
|
|
509
|
+
|
|
510
|
+
| Parameter | Type | Required | Description |
|
|
511
|
+
|-----------|------|----------|-------------|
|
|
512
|
+
| `confirm` | `boolean` | Yes | Must be `true` |
|
|
513
|
+
| `confirmationPhrase` | `string` | Yes | Must match project name |
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
await client.projects.delete('my-project', {
|
|
517
|
+
confirm: true,
|
|
518
|
+
confirmationPhrase: 'my-project',
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### `client.projects.softDelete(idOrName, input)`
|
|
523
|
+
|
|
524
|
+
Soft delete a project (can be restored).
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
await client.projects.softDelete('my-project', {
|
|
528
|
+
confirm: true,
|
|
529
|
+
confirmationPhrase: 'my-project',
|
|
530
|
+
});
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
#### `client.projects.restore(idOrName)`
|
|
534
|
+
|
|
535
|
+
Restore a soft-deleted project.
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
const project = await client.projects.restore('my-project');
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
#### `client.projects.getSummary(idOrName)`
|
|
542
|
+
|
|
543
|
+
Get project summary with statistics.
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
const summary = await client.projects.getSummary('my-project');
|
|
547
|
+
console.log(`Total runs: ${summary.totalRuns}`);
|
|
548
|
+
console.log(`Total issues: ${summary.totalIssues}`);
|
|
549
|
+
console.log(`Open issues: ${summary.openIssues}`);
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
#### `client.projects.getTrends(idOrName, query)`
|
|
553
|
+
|
|
554
|
+
Get issue trend data over time.
|
|
555
|
+
|
|
556
|
+
| Parameter | Type | Required | Description |
|
|
557
|
+
|-----------|------|----------|-------------|
|
|
558
|
+
| `days` | `number` | No | Number of days (default: 30) |
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
const trends = await client.projects.getTrends('my-project', { days: 30 });
|
|
562
|
+
for (const point of trends) {
|
|
563
|
+
console.log(point.date, point.openIssues, point.closedIssues);
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
#### `client.projects.listIssues(idOrName, query)`
|
|
568
|
+
|
|
569
|
+
List issues for a project with filters.
|
|
570
|
+
|
|
571
|
+
| Parameter | Type | Required | Description |
|
|
572
|
+
|-----------|------|----------|-------------|
|
|
573
|
+
| `status` | `Status` | No | Filter by status |
|
|
574
|
+
| `priority` | `Priority` | No | Filter by priority |
|
|
575
|
+
| `severity` | `Severity` | No | Filter by severity |
|
|
576
|
+
| `validator` | `string` | No | Filter by validator |
|
|
577
|
+
| `limit` | `number` | No | Max results (default: 50) |
|
|
578
|
+
| `offset` | `number` | No | Pagination offset |
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
const issues = await client.projects.listIssues('my-project', {
|
|
582
|
+
status: 'open',
|
|
583
|
+
priority: 'critical',
|
|
584
|
+
limit: 10,
|
|
585
|
+
});
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
#### `client.projects.bulkUpdateIssueStatus(idOrName, updates)`
|
|
589
|
+
|
|
590
|
+
Bulk update issue statuses.
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
const results = await client.projects.bulkUpdateIssueStatus('my-project', [
|
|
594
|
+
{ issueId: 'issue-1', status: 'completed', reason: 'Fixed' },
|
|
595
|
+
{ issueId: 'issue-2', status: 'deferred', reason: 'Not a priority' },
|
|
596
|
+
]);
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
#### `client.projects.mergeIssues(idOrName, input)`
|
|
600
|
+
|
|
601
|
+
Merge duplicate issues.
|
|
602
|
+
|
|
603
|
+
| Parameter | Type | Required | Description |
|
|
604
|
+
|-----------|------|----------|-------------|
|
|
605
|
+
| `targetIssueId` | `string` | Yes | Issue to merge into |
|
|
606
|
+
| `sourceIssueIds` | `string[]` | Yes | Issues to merge from |
|
|
607
|
+
| `strategy` | `string` | No | `'keep_target'` or `'keep_highest_priority'` |
|
|
608
|
+
|
|
609
|
+
```typescript
|
|
610
|
+
const result = await client.projects.mergeIssues('my-project', {
|
|
611
|
+
targetIssueId: 'issue-1',
|
|
612
|
+
sourceIssueIds: ['issue-2', 'issue-3'],
|
|
613
|
+
strategy: 'keep_target',
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
### Run Operations
|
|
620
|
+
|
|
621
|
+
Save and manage validation runs.
|
|
622
|
+
|
|
623
|
+
#### `client.runs.save(input)`
|
|
624
|
+
|
|
625
|
+
Save a new validation run.
|
|
626
|
+
|
|
627
|
+
| Parameter | Type | Required | Description |
|
|
628
|
+
|-----------|------|----------|-------------|
|
|
629
|
+
| `project` | `string` | Yes | Project name or ID |
|
|
630
|
+
| `workflowType` | `string` | Yes | Workflow type (e.g., `'post-implementation'`) |
|
|
631
|
+
| `validators` | `Validator[]` | Yes | Array of validator results |
|
|
632
|
+
| `recommendations` | `Recommendation[]` | No | Array of issues/recommendations |
|
|
633
|
+
| `summary` | `object` | No | Summary statistics |
|
|
634
|
+
| `rawMarkdown` | `string` | No | Raw markdown report |
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
const result = await client.runs.save({
|
|
638
|
+
project: 'my-project',
|
|
639
|
+
workflowType: 'post-implementation',
|
|
640
|
+
validators: [
|
|
641
|
+
{
|
|
642
|
+
name: 'code-validator',
|
|
643
|
+
score: 85,
|
|
644
|
+
status: 'PASS',
|
|
645
|
+
model: 'sonnet',
|
|
646
|
+
tokens: { input_tokens: 1000, output_tokens: 500 },
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
name: 'test-architect',
|
|
650
|
+
score: 72,
|
|
651
|
+
status: 'APPROVED',
|
|
652
|
+
},
|
|
653
|
+
],
|
|
654
|
+
recommendations: [
|
|
655
|
+
{
|
|
656
|
+
validator: 'code-validator',
|
|
657
|
+
title: 'Missing error handling in API client',
|
|
658
|
+
priority: 'suggested',
|
|
659
|
+
severity: 'medium',
|
|
660
|
+
filePath: 'src/api/client.ts',
|
|
661
|
+
lineNumber: 42,
|
|
662
|
+
description: 'Add try-catch for network errors',
|
|
663
|
+
failureCode: 'SEM-VAL/M',
|
|
664
|
+
},
|
|
665
|
+
],
|
|
666
|
+
summary: {
|
|
667
|
+
averageScore: 78.5,
|
|
668
|
+
allGatesPassed: true,
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
console.log(`Run #${result.run.runNumber} saved`);
|
|
673
|
+
console.log(`Issues: ${result.correlation.newIssues} new, ${result.correlation.recurringIssues} recurring`);
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
#### `client.runs.validate(input)`
|
|
677
|
+
|
|
678
|
+
Preview what a save would do without persisting.
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
const preview = await client.runs.validate({
|
|
682
|
+
project: 'my-project',
|
|
683
|
+
workflowType: 'post-implementation',
|
|
684
|
+
validators: [...],
|
|
685
|
+
recommendations: [...],
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
console.log('Would create:', preview.wouldCreate);
|
|
689
|
+
console.log('Would update:', preview.wouldUpdate);
|
|
690
|
+
console.log('Would regress:', preview.wouldRegress);
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
#### `client.runs.listByProject(projectId, query)`
|
|
694
|
+
|
|
695
|
+
List runs for a project.
|
|
696
|
+
|
|
697
|
+
| Parameter | Type | Required | Description |
|
|
698
|
+
|-----------|------|----------|-------------|
|
|
699
|
+
| `workflowType` | `string` | No | Filter by workflow type |
|
|
700
|
+
| `limit` | `number` | No | Max results |
|
|
701
|
+
| `offset` | `number` | No | Pagination offset |
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
const runs = await client.runs.listByProject('my-project', {
|
|
705
|
+
workflowType: 'ship',
|
|
706
|
+
limit: 10,
|
|
707
|
+
});
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
#### `client.runs.getLatest(projectId, workflowType)`
|
|
711
|
+
|
|
712
|
+
Get the latest run for a project.
|
|
713
|
+
|
|
714
|
+
```typescript
|
|
715
|
+
const latestRun = await client.runs.getLatest('my-project', 'post-implementation');
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
#### `client.runs.get(runId)`
|
|
719
|
+
|
|
720
|
+
Get a run by ID.
|
|
721
|
+
|
|
722
|
+
```typescript
|
|
723
|
+
const run = await client.runs.get('run-uuid-here');
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
#### `client.runs.getDetails(projectId, runNumber)`
|
|
727
|
+
|
|
728
|
+
Get detailed run information with recommendations.
|
|
729
|
+
|
|
730
|
+
```typescript
|
|
731
|
+
const details = await client.runs.getDetails('my-project', 5);
|
|
732
|
+
console.log(details.validators);
|
|
733
|
+
console.log(details.recommendations);
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
#### `client.runs.diff(query)`
|
|
737
|
+
|
|
738
|
+
Compare two runs to see fixed/new issues.
|
|
739
|
+
|
|
740
|
+
| Parameter | Type | Required | Description |
|
|
741
|
+
|-----------|------|----------|-------------|
|
|
742
|
+
| `project` | `string` | Yes | Project name or ID |
|
|
743
|
+
| `baseRun` | `number` | Yes | Base run number |
|
|
744
|
+
| `compareRun` | `number` | Yes | Compare run number |
|
|
745
|
+
| `workflowType` | `string` | No | Filter by workflow type |
|
|
746
|
+
|
|
747
|
+
```typescript
|
|
748
|
+
const diff = await client.runs.diff({
|
|
749
|
+
project: 'my-project',
|
|
750
|
+
baseRun: 1,
|
|
751
|
+
compareRun: 5,
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
console.log('Fixed issues:', diff.fixed.length);
|
|
755
|
+
console.log('New issues:', diff.new.length);
|
|
756
|
+
console.log('Unchanged:', diff.unchanged.length);
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
#### `client.runs.archive(input)`
|
|
760
|
+
|
|
761
|
+
Archive old runs.
|
|
762
|
+
|
|
763
|
+
| Parameter | Type | Required | Description |
|
|
764
|
+
|-----------|------|----------|-------------|
|
|
765
|
+
| `project` | `string` | Yes | Project name or ID |
|
|
766
|
+
| `beforeRunNumber` | `number` | No | Archive runs before this number |
|
|
767
|
+
| `beforeDate` | `string` | No | Archive runs before this date |
|
|
768
|
+
| `keepLast` | `number` | No | Keep last N runs |
|
|
769
|
+
| `reason` | `string` | No | Archive reason |
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
const result = await client.runs.archive({
|
|
773
|
+
project: 'my-project',
|
|
774
|
+
keepLast: 10,
|
|
775
|
+
reason: 'Quarterly cleanup',
|
|
776
|
+
});
|
|
777
|
+
console.log(`Archived ${result.archivedCount} runs`);
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
#### `client.runs.update(input)`
|
|
781
|
+
|
|
782
|
+
Update run metadata (tokens, scores).
|
|
783
|
+
|
|
784
|
+
```typescript
|
|
785
|
+
const run = await client.runs.update({
|
|
786
|
+
project: 'my-project',
|
|
787
|
+
runNumber: 5,
|
|
788
|
+
validators: [
|
|
789
|
+
{ name: 'code-validator', score: 90, input_tokens: 1500 },
|
|
790
|
+
],
|
|
791
|
+
});
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
#### `client.runs.delete(runId)`
|
|
795
|
+
|
|
796
|
+
Delete a run.
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
await client.runs.delete('run-uuid-here');
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
---
|
|
803
|
+
|
|
804
|
+
### Issue Operations
|
|
805
|
+
|
|
806
|
+
Track and manage validation issues.
|
|
807
|
+
|
|
808
|
+
#### `client.issues.create(input)`
|
|
809
|
+
|
|
810
|
+
Create a user-submitted issue.
|
|
811
|
+
|
|
812
|
+
| Parameter | Type | Required | Description |
|
|
813
|
+
|-----------|------|----------|-------------|
|
|
814
|
+
| `project` | `string` | Yes | Project name or ID |
|
|
815
|
+
| `title` | `string` | Yes | Issue title |
|
|
816
|
+
| `priority` | `Priority` | Yes | `'critical'`, `'suggested'`, `'backlog'` |
|
|
817
|
+
| `severity` | `Severity` | No | `'critical'`, `'high'`, `'medium'`, `'low'`, `'info'` |
|
|
818
|
+
| `type` | `IssueType` | No | `'bug'`, `'feature'`, `'refactor'`, etc. |
|
|
819
|
+
| `filePath` | `string` | No | File path where issue exists |
|
|
820
|
+
| `lineNumber` | `number` | No | Line number |
|
|
821
|
+
| `description` | `string` | No | Detailed description |
|
|
822
|
+
| `failureCode` | `string` | No | Taxonomy code (e.g., `'SEM-VAL/H'`) |
|
|
823
|
+
| `validator` | `string` | No | Validator name (defaults to `'user-submitted'`) |
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
const issue = await client.issues.create({
|
|
827
|
+
project: 'my-project',
|
|
828
|
+
title: 'Security vulnerability in auth module',
|
|
829
|
+
priority: 'critical',
|
|
830
|
+
severity: 'critical',
|
|
831
|
+
type: 'security',
|
|
832
|
+
filePath: 'src/auth/login.ts',
|
|
833
|
+
lineNumber: 45,
|
|
834
|
+
description: 'SQL injection vulnerability in login query',
|
|
835
|
+
failureCode: 'PRA-SEC/C',
|
|
836
|
+
});
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
#### `client.issues.search(query)`
|
|
840
|
+
|
|
841
|
+
Search issues across projects.
|
|
842
|
+
|
|
843
|
+
| Parameter | Type | Required | Description |
|
|
844
|
+
|-----------|------|----------|-------------|
|
|
845
|
+
| `query` | `string` | Yes | Search query |
|
|
846
|
+
| `projects` | `string[]` | No | Filter by projects |
|
|
847
|
+
| `validators` | `string[]` | No | Filter by validators |
|
|
848
|
+
| `status` | `Status` | No | Filter by status |
|
|
849
|
+
| `priority` | `Priority` | No | Filter by priority |
|
|
850
|
+
| `severities` | `Severity[]` | No | Filter by severities |
|
|
851
|
+
| `failureDomains` | `string[]` | No | Filter by domains (`'STR'`, `'SEM'`, `'PRA'`, `'EPI'`) |
|
|
852
|
+
| `limit` | `number` | No | Max results |
|
|
853
|
+
|
|
854
|
+
```typescript
|
|
855
|
+
const issues = await client.issues.search({
|
|
856
|
+
query: 'authentication',
|
|
857
|
+
status: 'open',
|
|
858
|
+
priority: 'critical',
|
|
859
|
+
});
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
#### `client.issues.get(issueId)`
|
|
863
|
+
|
|
864
|
+
Get an issue by ID.
|
|
865
|
+
|
|
866
|
+
```typescript
|
|
867
|
+
const issue = await client.issues.get('issue-uuid-here');
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
#### `client.issues.getDetails(issueId)`
|
|
871
|
+
|
|
872
|
+
Get detailed issue information with occurrences and notes.
|
|
873
|
+
|
|
874
|
+
```typescript
|
|
875
|
+
const details = await client.issues.getDetails('issue-uuid-here');
|
|
876
|
+
console.log('Occurrences:', details.occurrences);
|
|
877
|
+
console.log('Notes:', details.notes);
|
|
878
|
+
console.log('Related issues:', details.relatedIssues);
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
#### `client.issues.getByFingerprint(fingerprint, project)`
|
|
882
|
+
|
|
883
|
+
Get an issue by its SHA-256 fingerprint.
|
|
884
|
+
|
|
885
|
+
```typescript
|
|
886
|
+
const issue = await client.issues.getByFingerprint('abc123...', 'my-project');
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
#### `client.issues.getHistory(issueId)`
|
|
890
|
+
|
|
891
|
+
Get status change history for an issue.
|
|
892
|
+
|
|
893
|
+
```typescript
|
|
894
|
+
const history = await client.issues.getHistory('issue-uuid');
|
|
895
|
+
for (const entry of history) {
|
|
896
|
+
console.log(`${entry.fromStatus} -> ${entry.toStatus} at ${entry.changedAt}`);
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### `client.issues.updateStatus(issueId, input)`
|
|
901
|
+
|
|
902
|
+
Update an issue's status.
|
|
903
|
+
|
|
904
|
+
| Parameter | Type | Required | Description |
|
|
905
|
+
|-----------|------|----------|-------------|
|
|
906
|
+
| `status` | `Status` | Yes | New status |
|
|
907
|
+
| `reason` | `string` | No | Reason for change |
|
|
908
|
+
|
|
909
|
+
```typescript
|
|
910
|
+
const issue = await client.issues.updateStatus('issue-uuid', {
|
|
911
|
+
status: 'completed',
|
|
912
|
+
reason: 'Fixed in PR #123',
|
|
913
|
+
});
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
#### `client.issues.edit(issueId, input)`
|
|
917
|
+
|
|
918
|
+
Edit issue metadata.
|
|
919
|
+
|
|
920
|
+
| Parameter | Type | Required | Description |
|
|
921
|
+
|-----------|------|----------|-------------|
|
|
922
|
+
| `title` | `string` | No | New title |
|
|
923
|
+
| `filePath` | `string` | No | New file path |
|
|
924
|
+
| `lineNumber` | `number` | No | New line number |
|
|
925
|
+
| `severity` | `Severity` | No | New severity |
|
|
926
|
+
| `category` | `string` | No | New category |
|
|
927
|
+
| `failureCode` | `string` | No | New failure code |
|
|
928
|
+
|
|
929
|
+
```typescript
|
|
930
|
+
const issue = await client.issues.edit('issue-uuid', {
|
|
931
|
+
title: 'Updated title',
|
|
932
|
+
severity: 'high',
|
|
933
|
+
});
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
#### `client.issues.addNote(issueId, input)`
|
|
937
|
+
|
|
938
|
+
Add a note to an issue.
|
|
939
|
+
|
|
940
|
+
| Parameter | Type | Required | Description |
|
|
941
|
+
|-----------|------|----------|-------------|
|
|
942
|
+
| `content` | `string` | Yes | Note content |
|
|
943
|
+
| `noteType` | `NoteType` | No | `'context'`, `'resolution'`, `'blocker'` |
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
const note = await client.issues.addNote('issue-uuid', {
|
|
947
|
+
content: 'Root cause identified: race condition in async handler',
|
|
948
|
+
noteType: 'context',
|
|
949
|
+
});
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
#### `client.issues.restore(issueId)`
|
|
953
|
+
|
|
954
|
+
Restore a soft-deleted issue.
|
|
955
|
+
|
|
956
|
+
```typescript
|
|
957
|
+
const issue = await client.issues.restore('issue-uuid');
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
#### `client.issues.undoLastChange(issueId)`
|
|
961
|
+
|
|
962
|
+
Undo the last status change on an issue.
|
|
963
|
+
|
|
964
|
+
```typescript
|
|
965
|
+
const issue = await client.issues.undoLastChange('issue-uuid');
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
#### `client.issues.bulkUpdateStatus(updates)`
|
|
969
|
+
|
|
970
|
+
Bulk update issue statuses.
|
|
971
|
+
|
|
972
|
+
```typescript
|
|
973
|
+
const results = await client.issues.bulkUpdateStatus([
|
|
974
|
+
{ issueId: 'issue-1', status: 'completed' },
|
|
975
|
+
{ issueId: 'issue-2', status: 'deferred', reason: 'Not a priority' },
|
|
976
|
+
]);
|
|
977
|
+
|
|
978
|
+
// Each result includes per-item success/failure — some items may fail
|
|
979
|
+
// while others succeed (e.g., issue not found, invalid status transition)
|
|
980
|
+
for (const result of results) {
|
|
981
|
+
if (!result.success) {
|
|
982
|
+
console.warn(`Failed to update ${result.issueId}: ${result.error}`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
Maximum 100 items per bulk request. The SDK validates this limit client-side via Zod before sending.
|
|
988
|
+
|
|
989
|
+
#### `client.issues.listByProject(projectId, query)`
|
|
990
|
+
|
|
991
|
+
List issues for a specific project.
|
|
992
|
+
|
|
993
|
+
```typescript
|
|
994
|
+
const issues = await client.issues.listByProject('my-project', {
|
|
995
|
+
status: 'open',
|
|
996
|
+
limit: 20,
|
|
997
|
+
});
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
### Analytics Operations
|
|
1003
|
+
|
|
1004
|
+
Get insights and metrics about validation trends.
|
|
1005
|
+
|
|
1006
|
+
#### `client.analytics.getValidatorPerformance(query)`
|
|
1007
|
+
|
|
1008
|
+
Get performance metrics by validator.
|
|
1009
|
+
|
|
1010
|
+
| Parameter | Type | Required | Description |
|
|
1011
|
+
|-----------|------|----------|-------------|
|
|
1012
|
+
| `project` | `string` | No | Filter by project |
|
|
1013
|
+
| `days` | `number` | No | Time window (default: 30) |
|
|
1014
|
+
|
|
1015
|
+
```typescript
|
|
1016
|
+
const performance = await client.analytics.getValidatorPerformance({ days: 30 });
|
|
1017
|
+
for (const validator of performance) {
|
|
1018
|
+
console.log(`${validator.validator}: avg=${validator.avgScore}, pass=${validator.passRate}`);
|
|
1019
|
+
}
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
#### `client.analytics.getValidatorReliability(query)`
|
|
1023
|
+
|
|
1024
|
+
Get validator reliability statistics (false positive rates, resolution rates).
|
|
1025
|
+
|
|
1026
|
+
| Parameter | Type | Required | Description |
|
|
1027
|
+
|-----------|------|----------|-------------|
|
|
1028
|
+
| `validator` | `string` | No | Filter by validator |
|
|
1029
|
+
| `days` | `number` | No | Time window (default: 90) |
|
|
1030
|
+
|
|
1031
|
+
```typescript
|
|
1032
|
+
const { validators } = await client.analytics.getValidatorReliability({ days: 90 });
|
|
1033
|
+
for (const v of validators) {
|
|
1034
|
+
console.log(`${v.validator}: reliability=${v.reliabilityScore}`);
|
|
1035
|
+
}
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
#### `client.analytics.getResolutionRates(query)`
|
|
1039
|
+
|
|
1040
|
+
Get issue resolution rates by project.
|
|
1041
|
+
|
|
1042
|
+
```typescript
|
|
1043
|
+
const rates = await client.analytics.getResolutionRates();
|
|
1044
|
+
for (const rate of rates) {
|
|
1045
|
+
console.log(`${rate.project}: ${rate.rate * 100}% resolved`);
|
|
1046
|
+
}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
#### `client.analytics.getFileHotspots(query)`
|
|
1050
|
+
|
|
1051
|
+
Get files with the most issues.
|
|
1052
|
+
|
|
1053
|
+
| Parameter | Type | Required | Description |
|
|
1054
|
+
|-----------|------|----------|-------------|
|
|
1055
|
+
| `project` | `string` | No | Filter by project |
|
|
1056
|
+
| `days` | `number` | No | Time window |
|
|
1057
|
+
| `limit` | `number` | No | Max results |
|
|
1058
|
+
|
|
1059
|
+
```typescript
|
|
1060
|
+
const hotspots = await client.analytics.getFileHotspots({ limit: 10 });
|
|
1061
|
+
for (const hotspot of hotspots) {
|
|
1062
|
+
console.log(`${hotspot.filePath}: ${hotspot.issueCount} issues`);
|
|
1063
|
+
}
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
#### `client.analytics.getTaxonomyDistribution(query)`
|
|
1067
|
+
|
|
1068
|
+
Get issue distribution by failure domain.
|
|
1069
|
+
|
|
1070
|
+
```typescript
|
|
1071
|
+
const distribution = await client.analytics.getTaxonomyDistribution();
|
|
1072
|
+
for (const d of distribution) {
|
|
1073
|
+
console.log(`${d.domain}: ${d.count} issues`);
|
|
1074
|
+
}
|
|
1075
|
+
// Output: STR: 50, SEM: 80, PRA: 30, EPI: 20
|
|
1076
|
+
```
|
|
1077
|
+
|
|
1078
|
+
#### `client.analytics.getFullTaxonomy(query)`
|
|
1079
|
+
|
|
1080
|
+
Get comprehensive taxonomy analytics.
|
|
1081
|
+
|
|
1082
|
+
```typescript
|
|
1083
|
+
const { data, computedAt } = await client.analytics.getFullTaxonomy();
|
|
1084
|
+
console.log('By domain:', data.byDomain);
|
|
1085
|
+
console.log('By mode:', data.byMode);
|
|
1086
|
+
console.log('By severity:', data.bySeverity);
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
#### `client.analytics.getBurndown(query)`
|
|
1090
|
+
|
|
1091
|
+
Get burndown time series by failure domain.
|
|
1092
|
+
|
|
1093
|
+
| Parameter | Type | Required | Description |
|
|
1094
|
+
|-----------|------|----------|-------------|
|
|
1095
|
+
| `project` | `string` | No | Filter by project |
|
|
1096
|
+
| `days` | `number` | No | Time window (default: 30) |
|
|
1097
|
+
| `granularity` | `string` | No | `'daily'` or `'weekly'` |
|
|
1098
|
+
|
|
1099
|
+
```typescript
|
|
1100
|
+
const burndown = await client.analytics.getBurndown({ days: 30 });
|
|
1101
|
+
console.log('Time series:', burndown.timeSeries);
|
|
1102
|
+
console.log('Trends:', burndown.trends);
|
|
1103
|
+
// { STR: { direction: 'declining', rate: -0.05 }, ... }
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
#### `client.analytics.getVelocity(query)`
|
|
1107
|
+
|
|
1108
|
+
Get velocity metrics per failure mode.
|
|
1109
|
+
|
|
1110
|
+
| Parameter | Type | Required | Description |
|
|
1111
|
+
|-----------|------|----------|-------------|
|
|
1112
|
+
| `project` | `string` | No | Filter by project |
|
|
1113
|
+
| `days` | `number` | No | Time window |
|
|
1114
|
+
| `alertThreshold` | `number` | No | Velocity threshold for alerts |
|
|
1115
|
+
|
|
1116
|
+
```typescript
|
|
1117
|
+
const velocity = await client.analytics.getVelocity({ alertThreshold: 10 });
|
|
1118
|
+
for (const mode of velocity.modes) {
|
|
1119
|
+
console.log(`${mode.mode}: velocity=${mode.velocity}, trend=${mode.trend}`);
|
|
1120
|
+
}
|
|
1121
|
+
console.log('Alerts:', velocity.alerts);
|
|
1122
|
+
```
|
|
1123
|
+
|
|
1124
|
+
#### `client.analytics.getDiscovery(query)`
|
|
1125
|
+
|
|
1126
|
+
Get discovery timeline (new vs recurring issues).
|
|
1127
|
+
|
|
1128
|
+
| Parameter | Type | Required | Description |
|
|
1129
|
+
|-----------|------|----------|-------------|
|
|
1130
|
+
| `project` | `string` | No | Filter by project |
|
|
1131
|
+
| `days` | `number` | No | Time window |
|
|
1132
|
+
| `groupBy` | `string` | No | `'day'`, `'week'`, `'month'` |
|
|
1133
|
+
|
|
1134
|
+
```typescript
|
|
1135
|
+
const discovery = await client.analytics.getDiscovery({ groupBy: 'week' });
|
|
1136
|
+
console.log('Timeline:', discovery.timeline);
|
|
1137
|
+
console.log('Summary:', discovery.summary);
|
|
1138
|
+
// { totalNew: 8, totalRecurring: 22, newRate: 0.27 }
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
#### `client.analytics.getValidatorMatrix(query)`
|
|
1142
|
+
|
|
1143
|
+
Get validator-taxonomy coverage matrix.
|
|
1144
|
+
|
|
1145
|
+
| Parameter | Type | Required | Description |
|
|
1146
|
+
|-----------|------|----------|-------------|
|
|
1147
|
+
| `project` | `string` | No | Filter by project |
|
|
1148
|
+
| `days` | `number` | No | Time window (default: 90) |
|
|
1149
|
+
| `minIssues` | `number` | No | Min issues for inclusion |
|
|
1150
|
+
|
|
1151
|
+
```typescript
|
|
1152
|
+
const matrix = await client.analytics.getValidatorMatrix();
|
|
1153
|
+
console.log('Coverage matrix:', matrix.matrix);
|
|
1154
|
+
console.log('Blind spots:', matrix.blindSpots); // Domains not detected
|
|
1155
|
+
console.log('Single points:', matrix.singlePoints); // Only one validator detects
|
|
1156
|
+
console.log('High overlap:', matrix.highOverlap); // 3+ validators detect
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
#### `client.analytics.getTrendSummary(query)`
|
|
1160
|
+
|
|
1161
|
+
Get general trend summary.
|
|
1162
|
+
|
|
1163
|
+
```typescript
|
|
1164
|
+
const trends = await client.analytics.getTrendSummary();
|
|
1165
|
+
for (const trend of trends) {
|
|
1166
|
+
console.log(`${trend.metric}: ${trend.value} (${trend.change > 0 ? '+' : ''}${trend.change})`);
|
|
1167
|
+
}
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
#### `client.analytics.getByMetric(metric, query)`
|
|
1171
|
+
|
|
1172
|
+
Get analytics by specific metric name.
|
|
1173
|
+
|
|
1174
|
+
```typescript
|
|
1175
|
+
const costData = await client.analytics.getByMetric('cost_analysis', { days: 30 });
|
|
1176
|
+
const regressions = await client.analytics.getByMetric('regression_analysis', { project: 'my-project' });
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
---
|
|
1180
|
+
|
|
1181
|
+
### Taxonomy Operations
|
|
1182
|
+
|
|
1183
|
+
Get the failure taxonomy schema.
|
|
1184
|
+
|
|
1185
|
+
#### `client.taxonomy.get()`
|
|
1186
|
+
|
|
1187
|
+
Get the full taxonomy schema with domains, modes, and severities.
|
|
1188
|
+
|
|
1189
|
+
```typescript
|
|
1190
|
+
const taxonomy = await client.taxonomy.get();
|
|
1191
|
+
|
|
1192
|
+
console.log('Domains:', taxonomy.domains);
|
|
1193
|
+
// [
|
|
1194
|
+
// { code: 'STR', name: 'Structural', modes: ['OMI', 'RED', 'MIS'] },
|
|
1195
|
+
// { code: 'SEM', name: 'Semantic', modes: ['VAL', 'TYP', 'LOG'] },
|
|
1196
|
+
// { code: 'PRA', name: 'Pragmatic', modes: ['PER', 'SEC', 'MAI'] },
|
|
1197
|
+
// { code: 'EPI', name: 'Epistemic', modes: ['DOC', 'NAM', 'CLR'] },
|
|
1198
|
+
// ]
|
|
1199
|
+
|
|
1200
|
+
console.log('Severities:', taxonomy.severities);
|
|
1201
|
+
// ['critical', 'high', 'medium', 'low', 'info']
|
|
1202
|
+
|
|
1203
|
+
console.log('Priorities:', taxonomy.priorities);
|
|
1204
|
+
// ['critical', 'suggested', 'backlog']
|
|
1205
|
+
```
|
|
1206
|
+
|
|
1207
|
+
---
|
|
1208
|
+
|
|
1209
|
+
### Health Check
|
|
1210
|
+
|
|
1211
|
+
Check API server status. This endpoint does not require authentication.
|
|
1212
|
+
|
|
1213
|
+
```typescript
|
|
1214
|
+
import { OpsHttpClient } from '@uluops/ops-sdk';
|
|
1215
|
+
import type { HealthResponse } from '@uluops/ops-sdk/types';
|
|
1216
|
+
|
|
1217
|
+
const http = new OpsHttpClient({ baseUrl: 'http://localhost:3100/api/v1' });
|
|
1218
|
+
const health = await http.get<HealthResponse>('/health');
|
|
1219
|
+
console.log(health.status); // 'ok' | 'degraded' | 'unhealthy'
|
|
1220
|
+
console.log(health.version); // API version
|
|
1221
|
+
console.log(health.database); // { connected: boolean, latencyMs: number }
|
|
1222
|
+
```
|
|
1223
|
+
|
|
1224
|
+
---
|
|
1225
|
+
|
|
1226
|
+
### Admin Operations
|
|
1227
|
+
|
|
1228
|
+
Administrative operations (requires admin role).
|
|
1229
|
+
|
|
1230
|
+
#### `client.admin.getStats()`
|
|
1231
|
+
|
|
1232
|
+
Get dashboard statistics.
|
|
1233
|
+
|
|
1234
|
+
```typescript
|
|
1235
|
+
const stats = await client.admin.getStats();
|
|
1236
|
+
console.log(`Users: ${stats.totalUsers} (${stats.activeUsers} active)`);
|
|
1237
|
+
console.log(`Projects: ${stats.totalProjects}`);
|
|
1238
|
+
console.log(`Runs: ${stats.totalRuns}`);
|
|
1239
|
+
console.log(`Issues: ${stats.totalIssues}`);
|
|
1240
|
+
```
|
|
1241
|
+
|
|
1242
|
+
#### `client.admin.listUsers(query)`
|
|
1243
|
+
|
|
1244
|
+
List all users with pagination.
|
|
1245
|
+
|
|
1246
|
+
| Parameter | Type | Required | Description |
|
|
1247
|
+
|-----------|------|----------|-------------|
|
|
1248
|
+
| `role` | `string` | No | Filter by role |
|
|
1249
|
+
| `search` | `string` | No | Search by email |
|
|
1250
|
+
| `page` | `number` | No | Page number |
|
|
1251
|
+
| `limit` | `number` | No | Results per page |
|
|
1252
|
+
|
|
1253
|
+
```typescript
|
|
1254
|
+
const { users, pagination } = await client.admin.listUsers({
|
|
1255
|
+
role: 'admin',
|
|
1256
|
+
limit: 20,
|
|
1257
|
+
});
|
|
1258
|
+
```
|
|
1259
|
+
|
|
1260
|
+
#### `client.admin.getUser(userId)`
|
|
1261
|
+
|
|
1262
|
+
Get user details with stats.
|
|
1263
|
+
|
|
1264
|
+
```typescript
|
|
1265
|
+
const { user, stats } = await client.admin.getUser('user-id');
|
|
1266
|
+
console.log(`${user.email}: ${stats.projectCount} projects, ${stats.runCount} runs`);
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
#### `client.admin.createUser(input)`
|
|
1270
|
+
|
|
1271
|
+
Create a new user.
|
|
1272
|
+
|
|
1273
|
+
| Parameter | Type | Required | Description |
|
|
1274
|
+
|-----------|------|----------|-------------|
|
|
1275
|
+
| `email` | `string` | Yes | User email |
|
|
1276
|
+
| `password` | `string` | No | User password |
|
|
1277
|
+
| `role` | `string` | No | User role |
|
|
1278
|
+
| `sendWelcomeEmail` | `boolean` | No | Send welcome email |
|
|
1279
|
+
|
|
1280
|
+
```typescript
|
|
1281
|
+
const { user, temporaryPassword } = await client.admin.createUser({
|
|
1282
|
+
email: 'newuser@example.com',
|
|
1283
|
+
role: 'developer',
|
|
1284
|
+
sendWelcomeEmail: true,
|
|
1285
|
+
});
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
#### `client.admin.updateUser(userId, input)`
|
|
1289
|
+
|
|
1290
|
+
Update user attributes.
|
|
1291
|
+
|
|
1292
|
+
| Parameter | Type | Required | Description |
|
|
1293
|
+
|-----------|------|----------|-------------|
|
|
1294
|
+
| `role` | `string` | No | New role |
|
|
1295
|
+
| `subscriptionTier` | `string` | No | New subscription tier |
|
|
1296
|
+
|
|
1297
|
+
```typescript
|
|
1298
|
+
const { user } = await client.admin.updateUser('user-id', {
|
|
1299
|
+
role: 'admin',
|
|
1300
|
+
subscriptionTier: 'enterprise',
|
|
1301
|
+
});
|
|
1302
|
+
```
|
|
1303
|
+
|
|
1304
|
+
#### `client.admin.deactivateUser(userId)`
|
|
1305
|
+
|
|
1306
|
+
Deactivate a user account.
|
|
1307
|
+
|
|
1308
|
+
```typescript
|
|
1309
|
+
const { user } = await client.admin.deactivateUser('user-id');
|
|
1310
|
+
console.log(`User deactivated: ${user.isActive === false}`);
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
#### `client.admin.reactivateUser(userId)`
|
|
1314
|
+
|
|
1315
|
+
Reactivate a deactivated user.
|
|
1316
|
+
|
|
1317
|
+
```typescript
|
|
1318
|
+
const { user } = await client.admin.reactivateUser('user-id');
|
|
1319
|
+
```
|
|
1320
|
+
|
|
1321
|
+
#### `client.admin.resetUserPassword(userId)`
|
|
1322
|
+
|
|
1323
|
+
Trigger a password reset email for a user.
|
|
1324
|
+
|
|
1325
|
+
```typescript
|
|
1326
|
+
const { message } = await client.admin.resetUserPassword('user-id');
|
|
1327
|
+
```
|
|
1328
|
+
|
|
1329
|
+
#### `client.admin.bulkDeactivate(userIds)`
|
|
1330
|
+
|
|
1331
|
+
Bulk deactivate multiple users.
|
|
1332
|
+
|
|
1333
|
+
```typescript
|
|
1334
|
+
const result = await client.admin.bulkDeactivate(['user-1', 'user-2', 'user-3']);
|
|
1335
|
+
console.log(`Deactivated: ${result.success}, Failed: ${result.failed}`);
|
|
1336
|
+
```
|
|
1337
|
+
|
|
1338
|
+
#### `client.admin.listSessions(query)`
|
|
1339
|
+
|
|
1340
|
+
List all active sessions.
|
|
1341
|
+
|
|
1342
|
+
| Parameter | Type | Required | Description |
|
|
1343
|
+
|-----------|------|----------|-------------|
|
|
1344
|
+
| `userId` | `string` | No | Filter by user |
|
|
1345
|
+
| `page` | `number` | No | Page number |
|
|
1346
|
+
| `limit` | `number` | No | Results per page |
|
|
1347
|
+
|
|
1348
|
+
```typescript
|
|
1349
|
+
const { sessions, pagination } = await client.admin.listSessions({ userId: 'user-1' });
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
#### `client.admin.terminateSession(sessionId)`
|
|
1353
|
+
|
|
1354
|
+
Terminate a specific session.
|
|
1355
|
+
|
|
1356
|
+
```typescript
|
|
1357
|
+
const { message } = await client.admin.terminateSession('session-id');
|
|
1358
|
+
```
|
|
1359
|
+
|
|
1360
|
+
#### `client.admin.terminateUserSessions(userId)`
|
|
1361
|
+
|
|
1362
|
+
Terminate all sessions for a user.
|
|
1363
|
+
|
|
1364
|
+
```typescript
|
|
1365
|
+
const { message } = await client.admin.terminateUserSessions('user-id');
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
#### `client.admin.listKeys(query)`
|
|
1369
|
+
|
|
1370
|
+
List all API keys.
|
|
1371
|
+
|
|
1372
|
+
| Parameter | Type | Required | Description |
|
|
1373
|
+
|-----------|------|----------|-------------|
|
|
1374
|
+
| `userId` | `string` | No | Filter by user |
|
|
1375
|
+
| `search` | `string` | No | Search by name |
|
|
1376
|
+
| `page` | `number` | No | Page number |
|
|
1377
|
+
| `limit` | `number` | No | Results per page |
|
|
1378
|
+
|
|
1379
|
+
```typescript
|
|
1380
|
+
const { keys, pagination } = await client.admin.listKeys({ search: 'production' });
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
#### `client.admin.revokeKey(keyId)`
|
|
1384
|
+
|
|
1385
|
+
Revoke an API key.
|
|
1386
|
+
|
|
1387
|
+
```typescript
|
|
1388
|
+
const { message } = await client.admin.revokeKey('key-id');
|
|
1389
|
+
```
|
|
1390
|
+
|
|
1391
|
+
---
|
|
1392
|
+
|
|
1393
|
+
## CLI
|
|
1394
|
+
|
|
1395
|
+
For command-line usage, see the dedicated CLI package: [`@uluops/cli`](https://www.npmjs.com/package/@uluops/cli).
|
|
1396
|
+
|
|
1397
|
+
## Environment Variables
|
|
1398
|
+
|
|
1399
|
+
| Variable | Description | Default |
|
|
1400
|
+
|----------|-------------|---------|
|
|
1401
|
+
| `ULUOPS_API_KEY` | API key for authentication | - |
|
|
1402
|
+
| `ULUOPS_EMAIL` | Email for session auth | - |
|
|
1403
|
+
| `ULUOPS_PASSWORD` | Password for session auth | - |
|
|
1404
|
+
| `ULUOPS_BASE_URL` | API base URL | `http://localhost:3100/api/v1` |
|
|
1405
|
+
| `ULUOPS_DEBUG` | Enable debug logging | `false` |
|
|
1406
|
+
|
|
1407
|
+
Create a `.env` file in your project:
|
|
1408
|
+
|
|
1409
|
+
```env
|
|
1410
|
+
ULUOPS_API_KEY=ulr_your-api-key-here
|
|
1411
|
+
ULUOPS_BASE_URL=https://api.uluops.com/api/v1
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
Or configure globally in `~/.uluops/.env`.
|
|
1415
|
+
|
|
1416
|
+
> **Note:** The SDK defaults to `http://localhost:3100/api/v1` for local development. For production use, always set `ULUOPS_BASE_URL` or pass `baseUrl` to the constructor.
|
|
1417
|
+
|
|
1418
|
+
## Error Handling
|
|
1419
|
+
|
|
1420
|
+
The SDK provides typed error classes for precise error handling:
|
|
1421
|
+
|
|
1422
|
+
```typescript
|
|
1423
|
+
import {
|
|
1424
|
+
OpsApiError,
|
|
1425
|
+
ValidationError,
|
|
1426
|
+
UnauthorizedError,
|
|
1427
|
+
ForbiddenError,
|
|
1428
|
+
NotFoundError,
|
|
1429
|
+
ConflictError,
|
|
1430
|
+
RateLimitError,
|
|
1431
|
+
ServiceUnavailableError,
|
|
1432
|
+
NetworkError,
|
|
1433
|
+
TimeoutError,
|
|
1434
|
+
isOpsApiError,
|
|
1435
|
+
} from '@uluops/ops-sdk/errors';
|
|
1436
|
+
|
|
1437
|
+
try {
|
|
1438
|
+
await client.projects.get('non-existent');
|
|
1439
|
+
} catch (error) {
|
|
1440
|
+
if (error instanceof NotFoundError) {
|
|
1441
|
+
console.log(error.message); // "Project 'non-existent' not found"
|
|
1442
|
+
console.log(error.details); // { id: 'non-existent' }
|
|
1443
|
+
} else if (error instanceof UnauthorizedError) {
|
|
1444
|
+
console.log('Please authenticate');
|
|
1445
|
+
} else if (error instanceof RateLimitError) {
|
|
1446
|
+
console.log(`Rate limited. Retry after ${error.details?.retryAfter}s`);
|
|
1447
|
+
} else if (error instanceof ValidationError) {
|
|
1448
|
+
console.log('Invalid input:', error.details);
|
|
1449
|
+
} else if (isOpsApiError(error)) {
|
|
1450
|
+
console.log(`API error: ${error.code} - ${error.message}`);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
```
|
|
1454
|
+
|
|
1455
|
+
### Error Classes
|
|
1456
|
+
|
|
1457
|
+
| Error | Status | Description |
|
|
1458
|
+
|-------|--------|-------------|
|
|
1459
|
+
| `ValidationError` | 400 | Invalid request data |
|
|
1460
|
+
| `UnauthorizedError` | 401 | Authentication required |
|
|
1461
|
+
| `ForbiddenError` | 403 | Access denied |
|
|
1462
|
+
| `NotFoundError` | 404 | Resource not found |
|
|
1463
|
+
| `ConflictError` | 409 | Resource conflict |
|
|
1464
|
+
| `RateLimitError` | 429 | Rate limit exceeded |
|
|
1465
|
+
| `ServiceUnavailableError` | 503 | Server unavailable |
|
|
1466
|
+
| `NetworkError` | - | Connection error |
|
|
1467
|
+
| `TimeoutError` | - | Request timeout |
|
|
1468
|
+
|
|
1469
|
+
### Automatic Retries
|
|
1470
|
+
|
|
1471
|
+
The SDK automatically retries on transient errors (502, 503, 504, 429) with exponential backoff:
|
|
1472
|
+
|
|
1473
|
+
```typescript
|
|
1474
|
+
const client = new OpsClient({
|
|
1475
|
+
apiKey: 'ulr_...',
|
|
1476
|
+
retries: 3, // Number of retry attempts (default: 3)
|
|
1477
|
+
timeout: 30000, // Request timeout in ms (default: 30000)
|
|
1478
|
+
});
|
|
1479
|
+
```
|
|
1480
|
+
|
|
1481
|
+
### Request Size Limits
|
|
1482
|
+
|
|
1483
|
+
The API enforces the following payload limits:
|
|
1484
|
+
|
|
1485
|
+
- **Request body**: 1 MB maximum for most endpoints
|
|
1486
|
+
- **`raw_markdown`** field in `runs.save()`: up to 100,000 characters
|
|
1487
|
+
- **Recommendations array**: no hard limit, but very large arrays (1000+) may cause timeouts
|
|
1488
|
+
- **Bulk operations**: capped at 100 items per request (e.g., `bulkUpdateStatus`)
|
|
1489
|
+
|
|
1490
|
+
Requests exceeding these limits will receive a `413 Payload Too Large` or `422 Unprocessable Entity` response.
|
|
1491
|
+
|
|
1492
|
+
## Input Validation
|
|
1493
|
+
|
|
1494
|
+
The SDK includes Zod-based runtime validators for all mutating operations. Import them from `@uluops/ops-sdk/config`:
|
|
1495
|
+
|
|
1496
|
+
```typescript
|
|
1497
|
+
import { validateCreateProjectInput, InputValidationError } from '@uluops/ops-sdk/config';
|
|
1498
|
+
|
|
1499
|
+
try {
|
|
1500
|
+
const validated = validateCreateProjectInput({ name: '' }); // throws
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
if (error instanceof InputValidationError) {
|
|
1503
|
+
console.log('Validation errors:', error.errors);
|
|
1504
|
+
// => [{ code: 'too_small', minimum: 1, path: ['name'], message: 'String must contain at least 1 character(s)' }]
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
```
|
|
1508
|
+
|
|
1509
|
+
Available validators: `validateRegisterInput`, `validateLoginInput`, `validateCreateProjectInput`, `validateSaveFeaturesListInput`, `validateCreateUserIssueInput`, `validateUpdateIssueStatusInput`, `validateBulkStatusUpdateInput`, and more. See [`src/config/validators.ts`](./src/config/validators.ts) for the full list.
|
|
1510
|
+
|
|
1511
|
+
## Advanced Usage
|
|
1512
|
+
|
|
1513
|
+
### Using the Low-Level HTTP Client
|
|
1514
|
+
|
|
1515
|
+
For advanced use cases, you can use `OpsHttpClient` directly:
|
|
1516
|
+
|
|
1517
|
+
```typescript
|
|
1518
|
+
import { OpsHttpClient } from '@uluops/ops-sdk';
|
|
1519
|
+
|
|
1520
|
+
const http = new OpsHttpClient({
|
|
1521
|
+
baseUrl: 'http://localhost:3100/api/v1',
|
|
1522
|
+
apiKey: 'ulr_...',
|
|
1523
|
+
});
|
|
1524
|
+
|
|
1525
|
+
// Make raw requests
|
|
1526
|
+
const data = await http.get<MyType>('/custom/endpoint', { param: 'value' });
|
|
1527
|
+
const result = await http.post<MyType>('/custom/endpoint', { body: 'data' });
|
|
1528
|
+
const raw = await http.requestRaw('GET', '/endpoint'); // Without data unwrapping
|
|
1529
|
+
```
|
|
1530
|
+
|
|
1531
|
+
### Custom Authentication Strategy
|
|
1532
|
+
|
|
1533
|
+
```typescript
|
|
1534
|
+
import { OpsHttpClient, createAuthStrategy } from '@uluops/ops-sdk';
|
|
1535
|
+
|
|
1536
|
+
// Create auth strategy manually
|
|
1537
|
+
const authStrategy = createAuthStrategy({
|
|
1538
|
+
apiKey: 'ulr_...',
|
|
1539
|
+
// or
|
|
1540
|
+
sessionToken: 'jwt-token',
|
|
1541
|
+
});
|
|
1542
|
+
|
|
1543
|
+
const http = new OpsHttpClient({
|
|
1544
|
+
baseUrl: 'http://localhost:3100/api/v1',
|
|
1545
|
+
// Auth strategy will be created from config
|
|
1546
|
+
});
|
|
1547
|
+
```
|
|
1548
|
+
|
|
1549
|
+
### Loading Credentials Programmatically
|
|
1550
|
+
|
|
1551
|
+
```typescript
|
|
1552
|
+
import { loadCredentials, loadConfig } from '@uluops/ops-sdk/config';
|
|
1553
|
+
|
|
1554
|
+
// Load from environment and config files
|
|
1555
|
+
const credentials = loadCredentials();
|
|
1556
|
+
console.log(credentials.apiKey);
|
|
1557
|
+
console.log(credentials.email);
|
|
1558
|
+
|
|
1559
|
+
// Load full config
|
|
1560
|
+
const config = loadConfig();
|
|
1561
|
+
console.log(config.baseUrl);
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
## Troubleshooting
|
|
1565
|
+
|
|
1566
|
+
### Invalid API Key Format
|
|
1567
|
+
|
|
1568
|
+
```
|
|
1569
|
+
Error: Invalid API key format. Keys must start with 'ulr_'
|
|
1570
|
+
```
|
|
1571
|
+
|
|
1572
|
+
Ensure your API key starts with the `ulr_` prefix. Generate a new key if needed:
|
|
1573
|
+
|
|
1574
|
+
```typescript
|
|
1575
|
+
const { key } = await client.auth.createApiKey({ name: 'My Key' });
|
|
1576
|
+
console.log(key); // ulr_abc123...
|
|
1577
|
+
```
|
|
1578
|
+
|
|
1579
|
+
### Authentication Errors
|
|
1580
|
+
|
|
1581
|
+
```
|
|
1582
|
+
UnauthorizedError: Authentication required
|
|
1583
|
+
```
|
|
1584
|
+
|
|
1585
|
+
Check that:
|
|
1586
|
+
1. Your API key is valid and not revoked
|
|
1587
|
+
2. Environment variables are set correctly
|
|
1588
|
+
3. The `.env` file is in the correct location
|
|
1589
|
+
|
|
1590
|
+
```bash
|
|
1591
|
+
# Verify environment
|
|
1592
|
+
echo $ULUOPS_API_KEY
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
### Connection Errors
|
|
1596
|
+
|
|
1597
|
+
```
|
|
1598
|
+
NetworkError: connect ECONNREFUSED 127.0.0.1:3100
|
|
1599
|
+
```
|
|
1600
|
+
|
|
1601
|
+
Verify the API server is running and accessible:
|
|
1602
|
+
|
|
1603
|
+
```bash
|
|
1604
|
+
curl http://localhost:3100/api/v1/health
|
|
1605
|
+
```
|
|
1606
|
+
|
|
1607
|
+
Or configure the correct base URL:
|
|
1608
|
+
|
|
1609
|
+
```typescript
|
|
1610
|
+
const client = new OpsClient({
|
|
1611
|
+
baseUrl: 'https://api.uluops.com/api/v1',
|
|
1612
|
+
apiKey: 'ulr_...',
|
|
1613
|
+
});
|
|
1614
|
+
```
|
|
1615
|
+
|
|
1616
|
+
### Rate Limiting
|
|
1617
|
+
|
|
1618
|
+
```
|
|
1619
|
+
RateLimitError: Rate limit exceeded. Retry after 60 seconds
|
|
1620
|
+
```
|
|
1621
|
+
|
|
1622
|
+
The SDK automatically retries rate-limited requests. For high-volume operations:
|
|
1623
|
+
|
|
1624
|
+
1. Batch operations where possible
|
|
1625
|
+
2. Increase retry count: `retries: 5`
|
|
1626
|
+
3. Add delays between requests
|
|
1627
|
+
|
|
1628
|
+
### Debug Mode
|
|
1629
|
+
|
|
1630
|
+
Enable debug logging to see request/response details:
|
|
1631
|
+
|
|
1632
|
+
```typescript
|
|
1633
|
+
const client = new OpsClient({
|
|
1634
|
+
apiKey: 'ulr_...',
|
|
1635
|
+
debug: true,
|
|
1636
|
+
});
|
|
1637
|
+
```
|
|
1638
|
+
|
|
1639
|
+
Or via environment:
|
|
1640
|
+
|
|
1641
|
+
```bash
|
|
1642
|
+
ULUOPS_DEBUG=true node app.js
|
|
1643
|
+
```
|
|
1644
|
+
|
|
1645
|
+
## License
|
|
1646
|
+
|
|
1647
|
+
MIT License - see [LICENSE](./LICENSE) for details.
|