@inferencesh/sdk 0.6.10 → 0.6.13
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/README.md +1 -1
- package/dist/agent/actions.js +3 -3
- package/dist/agent/actions.test.js +231 -1
- package/dist/agent/api.test.js +18 -1
- package/dist/api/agents.d.ts +10 -0
- package/dist/api/agents.js +17 -3
- package/dist/api/agents.test.js +500 -0
- package/dist/api/api-keys.d.ts +24 -0
- package/dist/api/api-keys.js +26 -0
- package/dist/api/api-keys.test.d.ts +1 -0
- package/dist/api/api-keys.test.js +44 -0
- package/dist/api/apps.js +1 -1
- package/dist/api/apps.test.js +71 -3
- package/dist/api/chats.d.ts +14 -0
- package/dist/api/chats.js +18 -0
- package/dist/api/chats.test.js +52 -0
- package/dist/api/engines.d.ts +12 -0
- package/dist/api/engines.js +18 -0
- package/dist/api/engines.test.js +78 -0
- package/dist/api/files.test.js +183 -0
- package/dist/api/flow-runs.test.js +42 -0
- package/dist/api/flows.d.ts +4 -0
- package/dist/api/flows.js +6 -0
- package/dist/api/flows.test.js +75 -0
- package/dist/api/integrations.d.ts +41 -0
- package/dist/api/integrations.js +56 -0
- package/dist/api/integrations.test.d.ts +1 -0
- package/dist/api/integrations.test.js +109 -0
- package/dist/api/knowledge.d.ts +112 -0
- package/dist/api/knowledge.js +163 -0
- package/dist/api/knowledge.test.d.ts +1 -0
- package/dist/api/knowledge.test.js +238 -0
- package/dist/api/mcp-servers.d.ts +45 -0
- package/dist/api/mcp-servers.js +62 -0
- package/dist/api/mcp-servers.test.d.ts +1 -0
- package/dist/api/mcp-servers.test.js +98 -0
- package/dist/api/projects.d.ts +29 -0
- package/dist/api/projects.js +38 -0
- package/dist/api/projects.test.d.ts +1 -0
- package/dist/api/projects.test.js +61 -0
- package/dist/api/search.d.ts +21 -0
- package/dist/api/search.js +20 -0
- package/dist/api/search.test.d.ts +1 -0
- package/dist/api/search.test.js +39 -0
- package/dist/api/secrets.d.ts +29 -0
- package/dist/api/secrets.js +38 -0
- package/dist/api/secrets.test.d.ts +1 -0
- package/dist/api/secrets.test.js +61 -0
- package/dist/api/sessions.test.js +12 -0
- package/dist/api/tasks.d.ts +13 -1
- package/dist/api/tasks.js +18 -0
- package/dist/api/tasks.test.js +171 -0
- package/dist/api/teams.d.ts +71 -0
- package/dist/api/teams.js +92 -0
- package/dist/api/teams.test.d.ts +1 -0
- package/dist/api/teams.test.js +139 -0
- package/dist/client.test.js +112 -1
- package/dist/http/client.d.ts +5 -0
- package/dist/http/client.js +42 -23
- package/dist/http/client.test.js +245 -0
- package/dist/http/errors.test.js +13 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +25 -0
- package/dist/proxy/hono.test.d.ts +1 -0
- package/dist/proxy/hono.test.js +90 -0
- package/dist/proxy/nextjs.test.d.ts +1 -0
- package/dist/proxy/nextjs.test.js +125 -0
- package/dist/proxy/remix.test.d.ts +1 -0
- package/dist/proxy/remix.test.js +66 -0
- package/dist/proxy/svelte.test.d.ts +1 -0
- package/dist/proxy/svelte.test.js +69 -0
- package/dist/tool-builder.test.js +11 -1
- package/dist/types.d.ts +110 -5
- package/dist/types.js +58 -2
- package/package.json +6 -6
|
@@ -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
|
+
});
|
|
@@ -23,6 +23,18 @@ describe('SessionsAPI', () => {
|
|
|
23
23
|
expect(url).toContain('/sessions/sess_1');
|
|
24
24
|
expect(init.method).toBe('GET');
|
|
25
25
|
});
|
|
26
|
+
it('should GET /sessions and return session list', async () => {
|
|
27
|
+
const sessions = [
|
|
28
|
+
{ id: 'sess_1', status: 'active' },
|
|
29
|
+
{ id: 'sess_2', status: 'active' },
|
|
30
|
+
];
|
|
31
|
+
mockJsonResponse(sessions);
|
|
32
|
+
const result = await api().list();
|
|
33
|
+
expect(result).toEqual(sessions);
|
|
34
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
35
|
+
expect(url).toContain('/sessions');
|
|
36
|
+
expect(init.method).toBe('GET');
|
|
37
|
+
});
|
|
26
38
|
it('should return an empty array when list() response is null', async () => {
|
|
27
39
|
mockJsonResponse(null);
|
|
28
40
|
const result = await api().list();
|
package/dist/api/tasks.d.ts
CHANGED
|
@@ -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);
|
package/dist/api/tasks.test.js
CHANGED
|
@@ -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 });
|
|
@@ -174,6 +188,23 @@ describe('TasksAPI.run (streaming mode)', () => {
|
|
|
174
188
|
]);
|
|
175
189
|
await expect(api().run({ app: 'test-app', input: {} }, {}, { wait: true })).rejects.toThrow('task cancelled');
|
|
176
190
|
});
|
|
191
|
+
it('should reject when the NDJSON stream connection fails', async () => {
|
|
192
|
+
mockFetch.mockImplementation((url) => {
|
|
193
|
+
if (url.includes('/apps/run')) {
|
|
194
|
+
return Promise.resolve({
|
|
195
|
+
ok: true,
|
|
196
|
+
status: 200,
|
|
197
|
+
text: () => Promise.resolve(JSON.stringify(makeTask())),
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return Promise.resolve({
|
|
201
|
+
ok: false,
|
|
202
|
+
status: 503,
|
|
203
|
+
text: () => Promise.resolve('service unavailable'),
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
await expect(api().run({ app: 'test-app', input: {} }, {}, { wait: true })).rejects.toThrow('HTTP 503');
|
|
207
|
+
});
|
|
177
208
|
it('should handle partial updates via onPartialUpdate', async () => {
|
|
178
209
|
setupStreamMocks([
|
|
179
210
|
`${JSON.stringify({
|
|
@@ -187,3 +218,143 @@ describe('TasksAPI.run (streaming mode)', () => {
|
|
|
187
218
|
expect(onPartialUpdate).toHaveBeenCalledWith(expect.objectContaining({ id: 'task-1', status: TaskStatusCompleted }), ['status']);
|
|
188
219
|
});
|
|
189
220
|
});
|
|
221
|
+
describe('TasksAPI.run (HTTP contract)', () => {
|
|
222
|
+
beforeEach(() => {
|
|
223
|
+
jest.clearAllMocks();
|
|
224
|
+
});
|
|
225
|
+
const api = () => new TasksAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
226
|
+
it('should POST /apps/run with merged params and processedInput', async () => {
|
|
227
|
+
const task = makeTask();
|
|
228
|
+
mockJsonResponse(task);
|
|
229
|
+
const result = await api().run({ app: 'image-gen', version_id: 'ver-2', input: {} }, { prompt: 'sunset', width: 512 }, { wait: false });
|
|
230
|
+
expect(result).toEqual(task);
|
|
231
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
232
|
+
expect(url).toContain('/apps/run');
|
|
233
|
+
expect(init.method).toBe('POST');
|
|
234
|
+
expect(JSON.parse(init.body)).toEqual({
|
|
235
|
+
app: 'image-gen',
|
|
236
|
+
version_id: 'ver-2',
|
|
237
|
+
input: { prompt: 'sunset', width: 512 },
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
describe('TasksAPI.create', () => {
|
|
242
|
+
beforeEach(() => {
|
|
243
|
+
jest.clearAllMocks();
|
|
244
|
+
});
|
|
245
|
+
const api = () => new TasksAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
246
|
+
it('should POST /apps/run for create()', async () => {
|
|
247
|
+
const task = makeTask();
|
|
248
|
+
mockJsonResponse(task);
|
|
249
|
+
const result = await api().create({ app: 'test-app', input: { prompt: 'hi' } });
|
|
250
|
+
expect(result).toEqual(task);
|
|
251
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
252
|
+
expect(url).toContain('/apps/run');
|
|
253
|
+
expect(init.method).toBe('POST');
|
|
254
|
+
expect(JSON.parse(init.body)).toEqual({
|
|
255
|
+
app: 'test-app',
|
|
256
|
+
input: { prompt: 'hi' },
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
describe('TasksAPI (CRUD and admin)', () => {
|
|
261
|
+
beforeEach(() => {
|
|
262
|
+
jest.clearAllMocks();
|
|
263
|
+
});
|
|
264
|
+
const api = () => new TasksAPI(new HttpClient({ apiKey: 'test-key' }));
|
|
265
|
+
it('should POST /tasks/list for list()', async () => {
|
|
266
|
+
const page = { items: [{ id: 'task-1' }], next_cursor: null };
|
|
267
|
+
mockJsonResponse(page);
|
|
268
|
+
const result = await api().list({ limit: 5 });
|
|
269
|
+
expect(result).toEqual(page);
|
|
270
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
271
|
+
expect(url).toContain('/tasks/list');
|
|
272
|
+
expect(init.method).toBe('POST');
|
|
273
|
+
expect(JSON.parse(init.body)).toEqual({ limit: 5 });
|
|
274
|
+
});
|
|
275
|
+
it('should GET /tasks/featured for listFeatured()', async () => {
|
|
276
|
+
const page = { items: [{ id: 'task-f' }], next_cursor: null };
|
|
277
|
+
mockJsonResponse(page);
|
|
278
|
+
const result = await api().listFeatured({ cursor: 'abc' });
|
|
279
|
+
expect(result).toEqual(page);
|
|
280
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
281
|
+
expect(url).toContain('/tasks/featured');
|
|
282
|
+
expect(init.method).toBe('GET');
|
|
283
|
+
});
|
|
284
|
+
it('should GET /tasks/{id} for get()', async () => {
|
|
285
|
+
const task = makeTask();
|
|
286
|
+
mockJsonResponse(task);
|
|
287
|
+
const result = await api().get('task-1');
|
|
288
|
+
expect(result).toEqual(task);
|
|
289
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
290
|
+
expect(url).toContain('/tasks/task-1');
|
|
291
|
+
expect(init.method).toBe('GET');
|
|
292
|
+
});
|
|
293
|
+
it('should DELETE /tasks/{id} for delete()', async () => {
|
|
294
|
+
mockJsonResponse(null);
|
|
295
|
+
await api().delete('task-1');
|
|
296
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
297
|
+
expect(url).toContain('/tasks/task-1');
|
|
298
|
+
expect(init.method).toBe('DELETE');
|
|
299
|
+
});
|
|
300
|
+
it('should POST /tasks/{id}/cancel for cancel()', async () => {
|
|
301
|
+
mockJsonResponse(null);
|
|
302
|
+
await api().cancel('task-1');
|
|
303
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
304
|
+
expect(url).toContain('/tasks/task-1/cancel');
|
|
305
|
+
expect(init.method).toBe('POST');
|
|
306
|
+
});
|
|
307
|
+
it('should POST visibility for updateVisibility()', async () => {
|
|
308
|
+
const task = makeTask({ visibility: 'public' });
|
|
309
|
+
mockJsonResponse(task);
|
|
310
|
+
const result = await api().updateVisibility('task-1', 'public');
|
|
311
|
+
expect(result).toEqual(task);
|
|
312
|
+
const [, init] = mockFetch.mock.calls[0];
|
|
313
|
+
expect(JSON.parse(init.body)).toEqual({ visibility: 'public' });
|
|
314
|
+
});
|
|
315
|
+
it('should POST is_featured for feature()', async () => {
|
|
316
|
+
const task = makeTask({ is_featured: true });
|
|
317
|
+
mockJsonResponse(task);
|
|
318
|
+
await api().feature('task-1', true);
|
|
319
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
320
|
+
expect(url).toContain('/tasks/task-1/featured');
|
|
321
|
+
expect(JSON.parse(init.body)).toEqual({ is_featured: true });
|
|
322
|
+
});
|
|
323
|
+
it('should open SSE on /tasks/{id}/stream for stream()', async () => {
|
|
324
|
+
const http = new HttpClient({ apiKey: 'test-key' });
|
|
325
|
+
const createEventSource = jest
|
|
326
|
+
.spyOn(http, 'createEventSource')
|
|
327
|
+
.mockResolvedValue(null);
|
|
328
|
+
const tasks = new TasksAPI(http);
|
|
329
|
+
await tasks.stream('task-42');
|
|
330
|
+
expect(createEventSource).toHaveBeenCalledWith('/tasks/task-42/stream');
|
|
331
|
+
createEventSource.mockRestore();
|
|
332
|
+
});
|
|
333
|
+
it('should GET /tasks/{id}/logs for getLogs()', async () => {
|
|
334
|
+
const logs = { logs: [{ message: 'started', timestamp: '2026-01-01T00:00:00Z' }] };
|
|
335
|
+
mockJsonResponse(logs);
|
|
336
|
+
const result = await api().getLogs('task-1');
|
|
337
|
+
expect(result).toEqual(logs);
|
|
338
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
339
|
+
expect(url).toContain('/tasks/task-1/logs');
|
|
340
|
+
expect(init.method).toBe('GET');
|
|
341
|
+
});
|
|
342
|
+
it('should GET /tasks/{id}/timings for getTimings()', async () => {
|
|
343
|
+
const timings = { total_ms: 1200, stages: [{ name: 'inference', ms: 900 }] };
|
|
344
|
+
mockJsonResponse(timings);
|
|
345
|
+
const result = await api().getTimings('task-1');
|
|
346
|
+
expect(result).toEqual(timings);
|
|
347
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
348
|
+
expect(url).toContain('/tasks/task-1/timings');
|
|
349
|
+
expect(init.method).toBe('GET');
|
|
350
|
+
});
|
|
351
|
+
it('should GET /tasks/{id}/telemetry for getTelemetry()', async () => {
|
|
352
|
+
const telemetry = [{ metric: 'gpu_util', value: 0.82 }];
|
|
353
|
+
mockJsonResponse(telemetry);
|
|
354
|
+
const result = await api().getTelemetry('task-1');
|
|
355
|
+
expect(result).toEqual(telemetry);
|
|
356
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
357
|
+
expect(url).toContain('/tasks/task-1/telemetry');
|
|
358
|
+
expect(init.method).toBe('GET');
|
|
359
|
+
});
|
|
360
|
+
});
|
|
@@ -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 {};
|