@inferencesh/sdk 0.6.10 → 0.6.12

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.
Files changed (64) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/actions.js +3 -3
  3. package/dist/agent/actions.test.js +6 -0
  4. package/dist/api/agents.d.ts +10 -0
  5. package/dist/api/agents.js +17 -3
  6. package/dist/api/agents.test.js +215 -0
  7. package/dist/api/api-keys.d.ts +24 -0
  8. package/dist/api/api-keys.js +26 -0
  9. package/dist/api/api-keys.test.d.ts +1 -0
  10. package/dist/api/api-keys.test.js +44 -0
  11. package/dist/api/apps.js +1 -1
  12. package/dist/api/apps.test.js +71 -3
  13. package/dist/api/chats.d.ts +14 -0
  14. package/dist/api/chats.js +18 -0
  15. package/dist/api/chats.test.js +52 -0
  16. package/dist/api/engines.d.ts +12 -0
  17. package/dist/api/engines.js +18 -0
  18. package/dist/api/engines.test.js +78 -0
  19. package/dist/api/files.test.js +183 -0
  20. package/dist/api/flow-runs.test.js +42 -0
  21. package/dist/api/flows.d.ts +4 -0
  22. package/dist/api/flows.js +6 -0
  23. package/dist/api/flows.test.js +75 -0
  24. package/dist/api/integrations.d.ts +41 -0
  25. package/dist/api/integrations.js +56 -0
  26. package/dist/api/integrations.test.d.ts +1 -0
  27. package/dist/api/integrations.test.js +109 -0
  28. package/dist/api/knowledge.d.ts +112 -0
  29. package/dist/api/knowledge.js +163 -0
  30. package/dist/api/knowledge.test.d.ts +1 -0
  31. package/dist/api/knowledge.test.js +94 -0
  32. package/dist/api/mcp-servers.d.ts +45 -0
  33. package/dist/api/mcp-servers.js +62 -0
  34. package/dist/api/mcp-servers.test.d.ts +1 -0
  35. package/dist/api/mcp-servers.test.js +64 -0
  36. package/dist/api/projects.d.ts +29 -0
  37. package/dist/api/projects.js +38 -0
  38. package/dist/api/projects.test.d.ts +1 -0
  39. package/dist/api/projects.test.js +52 -0
  40. package/dist/api/search.d.ts +21 -0
  41. package/dist/api/search.js +20 -0
  42. package/dist/api/search.test.d.ts +1 -0
  43. package/dist/api/search.test.js +39 -0
  44. package/dist/api/secrets.d.ts +29 -0
  45. package/dist/api/secrets.js +38 -0
  46. package/dist/api/secrets.test.d.ts +1 -0
  47. package/dist/api/secrets.test.js +61 -0
  48. package/dist/api/tasks.d.ts +13 -1
  49. package/dist/api/tasks.js +18 -0
  50. package/dist/api/tasks.test.js +134 -0
  51. package/dist/api/teams.d.ts +71 -0
  52. package/dist/api/teams.js +92 -0
  53. package/dist/api/teams.test.d.ts +1 -0
  54. package/dist/api/teams.test.js +79 -0
  55. package/dist/http/client.d.ts +5 -0
  56. package/dist/http/client.js +42 -23
  57. package/dist/http/client.test.js +245 -0
  58. package/dist/http/errors.test.js +13 -0
  59. package/dist/index.d.ts +25 -0
  60. package/dist/index.js +25 -0
  61. package/dist/tool-builder.test.js +11 -1
  62. package/dist/types.d.ts +110 -5
  63. package/dist/types.js +58 -2
  64. package/package.json +4 -4
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Projects API
3
+ */
4
+ export class ProjectsAPI {
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ /**
9
+ * List projects with cursor-based pagination
10
+ */
11
+ async list(params) {
12
+ return this.http.request('post', '/projects/list', { data: params });
13
+ }
14
+ /**
15
+ * Get a project by ID
16
+ */
17
+ async get(id) {
18
+ return this.http.request('get', `/projects/${id}`);
19
+ }
20
+ /**
21
+ * Create a project
22
+ */
23
+ async create(data) {
24
+ return this.http.request('post', '/projects', { data });
25
+ }
26
+ /**
27
+ * Update a project
28
+ */
29
+ async update(id, data) {
30
+ return this.http.request('post', `/projects/${id}`, { data });
31
+ }
32
+ /**
33
+ * Delete a project
34
+ */
35
+ async delete(id) {
36
+ return this.http.request('delete', `/projects/${id}`);
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { ProjectsAPI } from './projects';
3
+ const mockFetch = jest.fn();
4
+ global.fetch = mockFetch;
5
+ function mockJsonResponse(body) {
6
+ mockFetch.mockResolvedValueOnce({
7
+ ok: true,
8
+ status: 200,
9
+ text: () => Promise.resolve(JSON.stringify(body)),
10
+ });
11
+ }
12
+ describe('ProjectsAPI', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+ const api = () => new ProjectsAPI(new HttpClient({ apiKey: 'test-key' }));
17
+ it('should POST /projects/list for list()', async () => {
18
+ const page = { items: [{ id: 'proj-1' }], next_cursor: null };
19
+ mockJsonResponse(page);
20
+ const result = await api().list({ limit: 20 });
21
+ expect(result).toEqual(page);
22
+ const [url, init] = mockFetch.mock.calls[0];
23
+ expect(url).toContain('/projects/list');
24
+ expect(init.method).toBe('POST');
25
+ });
26
+ it('should GET /projects/{id} for get()', async () => {
27
+ const project = { id: 'proj-1', name: 'Demo' };
28
+ mockJsonResponse(project);
29
+ const result = await api().get('proj-1');
30
+ expect(result).toEqual(project);
31
+ const [url, init] = mockFetch.mock.calls[0];
32
+ expect(url).toContain('/projects/proj-1');
33
+ expect(init.method).toBe('GET');
34
+ });
35
+ it('should POST /projects for create()', async () => {
36
+ const payload = { name: 'New Project' };
37
+ const project = { id: 'proj-new', ...payload };
38
+ mockJsonResponse(project);
39
+ const result = await api().create(payload);
40
+ expect(result).toEqual(project);
41
+ const [url, init] = mockFetch.mock.calls[0];
42
+ expect(url).toContain('/projects');
43
+ expect(init.method).toBe('POST');
44
+ });
45
+ it('should DELETE /projects/{id} for delete()', async () => {
46
+ mockJsonResponse(null);
47
+ await api().delete('proj-1');
48
+ const [url, init] = mockFetch.mock.calls[0];
49
+ expect(url).toContain('/projects/proj-1');
50
+ expect(init.method).toBe('DELETE');
51
+ });
52
+ });
@@ -0,0 +1,21 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { SuggestRequest, SuggestResponse } from '../types';
3
+ /**
4
+ * Search API
5
+ */
6
+ export declare class SearchAPI {
7
+ private readonly http;
8
+ constructor(http: HttpClient);
9
+ /**
10
+ * Unified search across skills, knowledge, and apps
11
+ */
12
+ suggest(params: Partial<SuggestRequest>): Promise<SuggestResponse>;
13
+ /**
14
+ * Full-text search via Meilisearch
15
+ */
16
+ search(params: {
17
+ q: string;
18
+ type?: string;
19
+ limit?: number;
20
+ }): Promise<unknown>;
21
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Search API
3
+ */
4
+ export class SearchAPI {
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ /**
9
+ * Unified search across skills, knowledge, and apps
10
+ */
11
+ async suggest(params) {
12
+ return this.http.request('post', '/suggest', { data: params });
13
+ }
14
+ /**
15
+ * Full-text search via Meilisearch
16
+ */
17
+ async search(params) {
18
+ return this.http.request('post', '/search', { data: params });
19
+ }
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { SearchAPI } from './search';
3
+ const mockFetch = jest.fn();
4
+ global.fetch = mockFetch;
5
+ function mockJsonResponse(body) {
6
+ mockFetch.mockResolvedValueOnce({
7
+ ok: true,
8
+ status: 200,
9
+ text: () => Promise.resolve(JSON.stringify(body)),
10
+ });
11
+ }
12
+ describe('SearchAPI', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+ const api = () => new SearchAPI(new HttpClient({ apiKey: 'test-key' }));
17
+ it('should POST /suggest for suggest()', async () => {
18
+ const payload = { query: 'image gen', types: ['apps', 'skills'] };
19
+ const response = { results: [{ type: 'app', id: 'app-1' }] };
20
+ mockJsonResponse(response);
21
+ const result = await api().suggest(payload);
22
+ expect(result).toEqual(response);
23
+ const [url, init] = mockFetch.mock.calls[0];
24
+ expect(url).toContain('/suggest');
25
+ expect(init.method).toBe('POST');
26
+ expect(JSON.parse(init.body)).toEqual(payload);
27
+ });
28
+ it('should POST /search for search()', async () => {
29
+ const payload = { q: 'claude', type: 'apps', limit: 5 };
30
+ const response = { hits: [{ id: 'app-1' }] };
31
+ mockJsonResponse(response);
32
+ const result = await api().search(payload);
33
+ expect(result).toEqual(response);
34
+ const [url, init] = mockFetch.mock.calls[0];
35
+ expect(url).toContain('/search');
36
+ expect(init.method).toBe('POST');
37
+ expect(JSON.parse(init.body)).toEqual(payload);
38
+ });
39
+ });
@@ -0,0 +1,29 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { SecretDTO, SecretCreateRequest, CursorListRequest, CursorListResponse } from '../types';
3
+ /**
4
+ * Secrets API
5
+ */
6
+ export declare class SecretsAPI {
7
+ private readonly http;
8
+ constructor(http: HttpClient);
9
+ /**
10
+ * List secrets with cursor-based pagination
11
+ */
12
+ list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<SecretDTO>>;
13
+ /**
14
+ * Create a secret
15
+ */
16
+ create(data: SecretCreateRequest): Promise<SecretDTO>;
17
+ /**
18
+ * Update a secret
19
+ */
20
+ update(key: string, data: Partial<SecretCreateRequest>): Promise<SecretDTO>;
21
+ /**
22
+ * Delete a secret
23
+ */
24
+ delete(key: string): Promise<void>;
25
+ /**
26
+ * Reveal a secret value
27
+ */
28
+ reveal(key: string): Promise<SecretDTO>;
29
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Secrets API
3
+ */
4
+ export class SecretsAPI {
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ /**
9
+ * List secrets with cursor-based pagination
10
+ */
11
+ async list(params) {
12
+ return this.http.request('post', '/secrets/list', { data: params });
13
+ }
14
+ /**
15
+ * Create a secret
16
+ */
17
+ async create(data) {
18
+ return this.http.request('post', '/secrets', { data });
19
+ }
20
+ /**
21
+ * Update a secret
22
+ */
23
+ async update(key, data) {
24
+ return this.http.request('put', `/secrets/${key}`, { data });
25
+ }
26
+ /**
27
+ * Delete a secret
28
+ */
29
+ async delete(key) {
30
+ return this.http.request('delete', `/secrets/${key}`);
31
+ }
32
+ /**
33
+ * Reveal a secret value
34
+ */
35
+ async reveal(key) {
36
+ return this.http.request('get', `/secrets/reveal/${key}`);
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { SecretsAPI } from './secrets';
3
+ const mockFetch = jest.fn();
4
+ global.fetch = mockFetch;
5
+ function mockJsonResponse(body) {
6
+ mockFetch.mockResolvedValueOnce({
7
+ ok: true,
8
+ status: 200,
9
+ text: () => Promise.resolve(JSON.stringify(body)),
10
+ });
11
+ }
12
+ describe('SecretsAPI', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+ const api = () => new SecretsAPI(new HttpClient({ apiKey: 'test-key' }));
17
+ it('should POST /secrets/list for list()', async () => {
18
+ const page = { items: [{ key: 'API_KEY' }], next_cursor: null };
19
+ mockJsonResponse(page);
20
+ const result = await api().list({ limit: 10 });
21
+ expect(result).toEqual(page);
22
+ const [url, init] = mockFetch.mock.calls[0];
23
+ expect(url).toContain('/secrets/list');
24
+ expect(init.method).toBe('POST');
25
+ });
26
+ it('should POST /secrets for create()', async () => {
27
+ const payload = { key: 'DB_PASSWORD', value: 'secret' };
28
+ const secret = { key: 'DB_PASSWORD' };
29
+ mockJsonResponse(secret);
30
+ const result = await api().create(payload);
31
+ expect(result).toEqual(secret);
32
+ const [url, init] = mockFetch.mock.calls[0];
33
+ expect(url).toContain('/secrets');
34
+ expect(init.method).toBe('POST');
35
+ expect(JSON.parse(init.body)).toEqual(payload);
36
+ });
37
+ it('should PUT /secrets/{key} for update()', async () => {
38
+ const secret = { key: 'DB_PASSWORD' };
39
+ mockJsonResponse(secret);
40
+ await api().update('DB_PASSWORD', { value: 'new-secret' });
41
+ const [url, init] = mockFetch.mock.calls[0];
42
+ expect(url).toContain('/secrets/DB_PASSWORD');
43
+ expect(init.method).toBe('PUT');
44
+ });
45
+ it('should GET /secrets/reveal/{key} for reveal()', async () => {
46
+ const secret = { key: 'API_KEY', value: 'sk-live-abc' };
47
+ mockJsonResponse(secret);
48
+ const result = await api().reveal('API_KEY');
49
+ expect(result).toEqual(secret);
50
+ const [url, init] = mockFetch.mock.calls[0];
51
+ expect(url).toContain('/secrets/reveal/API_KEY');
52
+ expect(init.method).toBe('GET');
53
+ });
54
+ it('should DELETE /secrets/{key} for delete()', async () => {
55
+ mockJsonResponse(null);
56
+ await api().delete('OLD_KEY');
57
+ const [url, init] = mockFetch.mock.calls[0];
58
+ expect(url).toContain('/secrets/OLD_KEY');
59
+ expect(init.method).toBe('DELETE');
60
+ });
61
+ });
@@ -1,5 +1,5 @@
1
1
  import { HttpClient } from '../http/client';
2
- import { TaskDTO as Task, ApiAppRunRequest, CursorListRequest, CursorListResponse } from '../types';
2
+ import { TaskDTO as Task, TaskLogsDTO, TaskTimingsDTO, ApiAppRunRequest, CursorListRequest, CursorListResponse } from '../types';
3
3
  export interface RunOptions {
4
4
  /** Callback for real-time status updates */
5
5
  onUpdate?: (update: Task) => void;
@@ -62,5 +62,17 @@ export declare class TasksAPI {
62
62
  * Feature/unfeature a task
63
63
  */
64
64
  feature(taskId: string, featured: boolean): Promise<Task>;
65
+ /**
66
+ * Get task logs
67
+ */
68
+ getLogs(taskId: string): Promise<TaskLogsDTO>;
69
+ /**
70
+ * Get task timings
71
+ */
72
+ getTimings(taskId: string): Promise<TaskTimingsDTO>;
73
+ /**
74
+ * Get task telemetry
75
+ */
76
+ getTelemetry(taskId: string): Promise<Record<string, unknown>[]>;
65
77
  }
66
78
  export declare function createTasksAPI(http: HttpClient): TasksAPI;
package/dist/api/tasks.js CHANGED
@@ -193,6 +193,24 @@ export class TasksAPI {
193
193
  async feature(taskId, featured) {
194
194
  return this.http.request('post', `/tasks/${taskId}/featured`, { data: { is_featured: featured } });
195
195
  }
196
+ /**
197
+ * Get task logs
198
+ */
199
+ async getLogs(taskId) {
200
+ return this.http.request('get', `/tasks/${taskId}/logs`);
201
+ }
202
+ /**
203
+ * Get task timings
204
+ */
205
+ async getTimings(taskId) {
206
+ return this.http.request('get', `/tasks/${taskId}/timings`);
207
+ }
208
+ /**
209
+ * Get task telemetry
210
+ */
211
+ async getTelemetry(taskId) {
212
+ return this.http.request('get', `/tasks/${taskId}/telemetry`);
213
+ }
196
214
  }
197
215
  export function createTasksAPI(http) {
198
216
  return new TasksAPI(http);
@@ -76,6 +76,20 @@ describe('TasksAPI.run (polling mode)', () => {
76
76
  mockFetch.mockRejectedValueOnce(new Error('status endpoint down'));
77
77
  await expect(api().run({ app: 'test-app', input: {} }, {}, { wait: true, stream: false })).rejects.toThrow('status endpoint down');
78
78
  });
79
+ it('should not refetch full task when poll status is unchanged', async () => {
80
+ const runningTask = makeTask();
81
+ const completedTask = makeTask({ status: TaskStatusCompleted, output: { ok: true } });
82
+ mockJsonResponse(runningTask);
83
+ mockJsonResponse({ status: TaskStatusRunning });
84
+ mockJsonResponse({ status: TaskStatusRunning });
85
+ mockJsonResponse({ status: TaskStatusCompleted });
86
+ mockJsonResponse(completedTask);
87
+ await api().run({ app: 'test-app', input: {} }, {}, { wait: true, stream: false });
88
+ const fullTaskGets = mockFetch.mock.calls.filter(([url, init]) => String(url).includes('/tasks/task-1') &&
89
+ !String(url).includes('/status') &&
90
+ init.method === 'GET');
91
+ expect(fullTaskGets).toHaveLength(1);
92
+ });
79
93
  it('should parse string terminal statuses from the status endpoint', async () => {
80
94
  const runningTask = makeTask();
81
95
  const completedTask = makeTask({ status: TaskStatusCompleted });
@@ -187,3 +201,123 @@ describe('TasksAPI.run (streaming mode)', () => {
187
201
  expect(onPartialUpdate).toHaveBeenCalledWith(expect.objectContaining({ id: 'task-1', status: TaskStatusCompleted }), ['status']);
188
202
  });
189
203
  });
204
+ describe('TasksAPI.create', () => {
205
+ beforeEach(() => {
206
+ jest.clearAllMocks();
207
+ });
208
+ const api = () => new TasksAPI(new HttpClient({ apiKey: 'test-key' }));
209
+ it('should POST /apps/run for create()', async () => {
210
+ const task = makeTask();
211
+ mockJsonResponse(task);
212
+ const result = await api().create({ app: 'test-app', input: { prompt: 'hi' } });
213
+ expect(result).toEqual(task);
214
+ const [url, init] = mockFetch.mock.calls[0];
215
+ expect(url).toContain('/apps/run');
216
+ expect(init.method).toBe('POST');
217
+ expect(JSON.parse(init.body)).toEqual({
218
+ app: 'test-app',
219
+ input: { prompt: 'hi' },
220
+ });
221
+ });
222
+ });
223
+ describe('TasksAPI (CRUD and admin)', () => {
224
+ beforeEach(() => {
225
+ jest.clearAllMocks();
226
+ });
227
+ const api = () => new TasksAPI(new HttpClient({ apiKey: 'test-key' }));
228
+ it('should POST /tasks/list for list()', async () => {
229
+ const page = { items: [{ id: 'task-1' }], next_cursor: null };
230
+ mockJsonResponse(page);
231
+ const result = await api().list({ limit: 5 });
232
+ expect(result).toEqual(page);
233
+ const [url, init] = mockFetch.mock.calls[0];
234
+ expect(url).toContain('/tasks/list');
235
+ expect(init.method).toBe('POST');
236
+ expect(JSON.parse(init.body)).toEqual({ limit: 5 });
237
+ });
238
+ it('should GET /tasks/featured for listFeatured()', async () => {
239
+ const page = { items: [{ id: 'task-f' }], next_cursor: null };
240
+ mockJsonResponse(page);
241
+ const result = await api().listFeatured({ cursor: 'abc' });
242
+ expect(result).toEqual(page);
243
+ const [url, init] = mockFetch.mock.calls[0];
244
+ expect(url).toContain('/tasks/featured');
245
+ expect(init.method).toBe('GET');
246
+ });
247
+ it('should GET /tasks/{id} for get()', async () => {
248
+ const task = makeTask();
249
+ mockJsonResponse(task);
250
+ const result = await api().get('task-1');
251
+ expect(result).toEqual(task);
252
+ const [url, init] = mockFetch.mock.calls[0];
253
+ expect(url).toContain('/tasks/task-1');
254
+ expect(init.method).toBe('GET');
255
+ });
256
+ it('should DELETE /tasks/{id} for delete()', async () => {
257
+ mockJsonResponse(null);
258
+ await api().delete('task-1');
259
+ const [url, init] = mockFetch.mock.calls[0];
260
+ expect(url).toContain('/tasks/task-1');
261
+ expect(init.method).toBe('DELETE');
262
+ });
263
+ it('should POST /tasks/{id}/cancel for cancel()', async () => {
264
+ mockJsonResponse(null);
265
+ await api().cancel('task-1');
266
+ const [url, init] = mockFetch.mock.calls[0];
267
+ expect(url).toContain('/tasks/task-1/cancel');
268
+ expect(init.method).toBe('POST');
269
+ });
270
+ it('should POST visibility for updateVisibility()', async () => {
271
+ const task = makeTask({ visibility: 'public' });
272
+ mockJsonResponse(task);
273
+ const result = await api().updateVisibility('task-1', 'public');
274
+ expect(result).toEqual(task);
275
+ const [, init] = mockFetch.mock.calls[0];
276
+ expect(JSON.parse(init.body)).toEqual({ visibility: 'public' });
277
+ });
278
+ it('should POST is_featured for feature()', async () => {
279
+ const task = makeTask({ is_featured: true });
280
+ mockJsonResponse(task);
281
+ await api().feature('task-1', true);
282
+ const [url, init] = mockFetch.mock.calls[0];
283
+ expect(url).toContain('/tasks/task-1/featured');
284
+ expect(JSON.parse(init.body)).toEqual({ is_featured: true });
285
+ });
286
+ it('should open SSE on /tasks/{id}/stream for stream()', async () => {
287
+ const http = new HttpClient({ apiKey: 'test-key' });
288
+ const createEventSource = jest
289
+ .spyOn(http, 'createEventSource')
290
+ .mockResolvedValue(null);
291
+ const tasks = new TasksAPI(http);
292
+ await tasks.stream('task-42');
293
+ expect(createEventSource).toHaveBeenCalledWith('/tasks/task-42/stream');
294
+ createEventSource.mockRestore();
295
+ });
296
+ it('should GET /tasks/{id}/logs for getLogs()', async () => {
297
+ const logs = { logs: [{ message: 'started', timestamp: '2026-01-01T00:00:00Z' }] };
298
+ mockJsonResponse(logs);
299
+ const result = await api().getLogs('task-1');
300
+ expect(result).toEqual(logs);
301
+ const [url, init] = mockFetch.mock.calls[0];
302
+ expect(url).toContain('/tasks/task-1/logs');
303
+ expect(init.method).toBe('GET');
304
+ });
305
+ it('should GET /tasks/{id}/timings for getTimings()', async () => {
306
+ const timings = { total_ms: 1200, stages: [{ name: 'inference', ms: 900 }] };
307
+ mockJsonResponse(timings);
308
+ const result = await api().getTimings('task-1');
309
+ expect(result).toEqual(timings);
310
+ const [url, init] = mockFetch.mock.calls[0];
311
+ expect(url).toContain('/tasks/task-1/timings');
312
+ expect(init.method).toBe('GET');
313
+ });
314
+ it('should GET /tasks/{id}/telemetry for getTelemetry()', async () => {
315
+ const telemetry = [{ metric: 'gpu_util', value: 0.82 }];
316
+ mockJsonResponse(telemetry);
317
+ const result = await api().getTelemetry('task-1');
318
+ expect(result).toEqual(telemetry);
319
+ const [url, init] = mockFetch.mock.calls[0];
320
+ expect(url).toContain('/tasks/task-1/telemetry');
321
+ expect(init.method).toBe('GET');
322
+ });
323
+ });
@@ -0,0 +1,71 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { UserDTO, TeamRelationDTO, TeamMemberDTO, TeamInviteDTO, TeamCreateRequest, TeamMemberAddRequest, TeamInviteCreateRequest } from '../types';
3
+ export interface MeResponse {
4
+ user: UserDTO;
5
+ team?: TeamRelationDTO;
6
+ }
7
+ /**
8
+ * Teams API
9
+ */
10
+ export declare class TeamsAPI {
11
+ private readonly http;
12
+ constructor(http: HttpClient);
13
+ /**
14
+ * Get current user and team context
15
+ */
16
+ me(): Promise<MeResponse>;
17
+ /**
18
+ * List user's teams
19
+ */
20
+ list(): Promise<TeamRelationDTO[]>;
21
+ /**
22
+ * Get a team by ID
23
+ */
24
+ get(teamId: string): Promise<TeamRelationDTO>;
25
+ /**
26
+ * Create a new team
27
+ */
28
+ create(data: TeamCreateRequest): Promise<TeamRelationDTO>;
29
+ /**
30
+ * Update a team
31
+ */
32
+ update(teamId: string, data: Partial<TeamCreateRequest>): Promise<TeamRelationDTO>;
33
+ /**
34
+ * Delete a team
35
+ */
36
+ delete(teamId: string): Promise<void>;
37
+ /**
38
+ * Check username availability
39
+ */
40
+ checkUsername(username: string): Promise<{
41
+ available: boolean;
42
+ }>;
43
+ /**
44
+ * Get team members
45
+ */
46
+ getMembers(teamId: string): Promise<TeamMemberDTO[]>;
47
+ /**
48
+ * Add a team member
49
+ */
50
+ addMember(teamId: string, data: TeamMemberAddRequest): Promise<TeamMemberDTO>;
51
+ /**
52
+ * Remove a team member
53
+ */
54
+ removeMember(teamId: string, userId: string): Promise<void>;
55
+ /**
56
+ * Update a member's role
57
+ */
58
+ updateMemberRole(teamId: string, userId: string, role: string): Promise<TeamMemberDTO>;
59
+ /**
60
+ * List team invites
61
+ */
62
+ listInvites(teamId: string): Promise<TeamInviteDTO[]>;
63
+ /**
64
+ * Create an invite
65
+ */
66
+ createInvite(teamId: string, data: TeamInviteCreateRequest): Promise<TeamInviteDTO>;
67
+ /**
68
+ * Revoke an invite
69
+ */
70
+ revokeInvite(teamId: string, inviteId: string): Promise<void>;
71
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Teams API
3
+ */
4
+ export class TeamsAPI {
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ /**
9
+ * Get current user and team context
10
+ */
11
+ async me() {
12
+ return this.http.request('get', '/me');
13
+ }
14
+ /**
15
+ * List user's teams
16
+ */
17
+ async list() {
18
+ return this.http.request('get', '/teams');
19
+ }
20
+ /**
21
+ * Get a team by ID
22
+ */
23
+ async get(teamId) {
24
+ return this.http.request('get', `/teams/${teamId}`);
25
+ }
26
+ /**
27
+ * Create a new team
28
+ */
29
+ async create(data) {
30
+ return this.http.request('post', '/teams', { data });
31
+ }
32
+ /**
33
+ * Update a team
34
+ */
35
+ async update(teamId, data) {
36
+ return this.http.request('post', `/teams/${teamId}`, { data });
37
+ }
38
+ /**
39
+ * Delete a team
40
+ */
41
+ async delete(teamId) {
42
+ return this.http.request('delete', `/teams/${teamId}`);
43
+ }
44
+ /**
45
+ * Check username availability
46
+ */
47
+ async checkUsername(username) {
48
+ return this.http.request('get', '/teams/check-username', { params: { username } });
49
+ }
50
+ /**
51
+ * Get team members
52
+ */
53
+ async getMembers(teamId) {
54
+ return this.http.request('get', `/teams/${teamId}/members`);
55
+ }
56
+ /**
57
+ * Add a team member
58
+ */
59
+ async addMember(teamId, data) {
60
+ return this.http.request('post', `/teams/${teamId}/members`, { data });
61
+ }
62
+ /**
63
+ * Remove a team member
64
+ */
65
+ async removeMember(teamId, userId) {
66
+ return this.http.request('delete', `/teams/${teamId}/members/${userId}`);
67
+ }
68
+ /**
69
+ * Update a member's role
70
+ */
71
+ async updateMemberRole(teamId, userId, role) {
72
+ return this.http.request('post', `/teams/${teamId}/members/${userId}/role`, { data: { role } });
73
+ }
74
+ /**
75
+ * List team invites
76
+ */
77
+ async listInvites(teamId) {
78
+ return this.http.request('get', `/teams/${teamId}/invites`);
79
+ }
80
+ /**
81
+ * Create an invite
82
+ */
83
+ async createInvite(teamId, data) {
84
+ return this.http.request('post', `/teams/${teamId}/invites`, { data });
85
+ }
86
+ /**
87
+ * Revoke an invite
88
+ */
89
+ async revokeInvite(teamId, inviteId) {
90
+ return this.http.request('delete', `/teams/${teamId}/invites/${inviteId}`);
91
+ }
92
+ }
@@ -0,0 +1 @@
1
+ export {};