@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.
Files changed (75) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/actions.js +3 -3
  3. package/dist/agent/actions.test.js +231 -1
  4. package/dist/agent/api.test.js +18 -1
  5. package/dist/api/agents.d.ts +10 -0
  6. package/dist/api/agents.js +17 -3
  7. package/dist/api/agents.test.js +500 -0
  8. package/dist/api/api-keys.d.ts +24 -0
  9. package/dist/api/api-keys.js +26 -0
  10. package/dist/api/api-keys.test.d.ts +1 -0
  11. package/dist/api/api-keys.test.js +44 -0
  12. package/dist/api/apps.js +1 -1
  13. package/dist/api/apps.test.js +71 -3
  14. package/dist/api/chats.d.ts +14 -0
  15. package/dist/api/chats.js +18 -0
  16. package/dist/api/chats.test.js +52 -0
  17. package/dist/api/engines.d.ts +12 -0
  18. package/dist/api/engines.js +18 -0
  19. package/dist/api/engines.test.js +78 -0
  20. package/dist/api/files.test.js +183 -0
  21. package/dist/api/flow-runs.test.js +42 -0
  22. package/dist/api/flows.d.ts +4 -0
  23. package/dist/api/flows.js +6 -0
  24. package/dist/api/flows.test.js +75 -0
  25. package/dist/api/integrations.d.ts +41 -0
  26. package/dist/api/integrations.js +56 -0
  27. package/dist/api/integrations.test.d.ts +1 -0
  28. package/dist/api/integrations.test.js +109 -0
  29. package/dist/api/knowledge.d.ts +112 -0
  30. package/dist/api/knowledge.js +163 -0
  31. package/dist/api/knowledge.test.d.ts +1 -0
  32. package/dist/api/knowledge.test.js +238 -0
  33. package/dist/api/mcp-servers.d.ts +45 -0
  34. package/dist/api/mcp-servers.js +62 -0
  35. package/dist/api/mcp-servers.test.d.ts +1 -0
  36. package/dist/api/mcp-servers.test.js +98 -0
  37. package/dist/api/projects.d.ts +29 -0
  38. package/dist/api/projects.js +38 -0
  39. package/dist/api/projects.test.d.ts +1 -0
  40. package/dist/api/projects.test.js +61 -0
  41. package/dist/api/search.d.ts +21 -0
  42. package/dist/api/search.js +20 -0
  43. package/dist/api/search.test.d.ts +1 -0
  44. package/dist/api/search.test.js +39 -0
  45. package/dist/api/secrets.d.ts +29 -0
  46. package/dist/api/secrets.js +38 -0
  47. package/dist/api/secrets.test.d.ts +1 -0
  48. package/dist/api/secrets.test.js +61 -0
  49. package/dist/api/sessions.test.js +12 -0
  50. package/dist/api/tasks.d.ts +13 -1
  51. package/dist/api/tasks.js +18 -0
  52. package/dist/api/tasks.test.js +171 -0
  53. package/dist/api/teams.d.ts +71 -0
  54. package/dist/api/teams.js +92 -0
  55. package/dist/api/teams.test.d.ts +1 -0
  56. package/dist/api/teams.test.js +139 -0
  57. package/dist/client.test.js +112 -1
  58. package/dist/http/client.d.ts +5 -0
  59. package/dist/http/client.js +42 -23
  60. package/dist/http/client.test.js +245 -0
  61. package/dist/http/errors.test.js +13 -0
  62. package/dist/index.d.ts +25 -0
  63. package/dist/index.js +25 -0
  64. package/dist/proxy/hono.test.d.ts +1 -0
  65. package/dist/proxy/hono.test.js +90 -0
  66. package/dist/proxy/nextjs.test.d.ts +1 -0
  67. package/dist/proxy/nextjs.test.js +125 -0
  68. package/dist/proxy/remix.test.d.ts +1 -0
  69. package/dist/proxy/remix.test.js +66 -0
  70. package/dist/proxy/svelte.test.d.ts +1 -0
  71. package/dist/proxy/svelte.test.js +69 -0
  72. package/dist/tool-builder.test.js +11 -1
  73. package/dist/types.d.ts +110 -5
  74. package/dist/types.js +58 -2
  75. package/package.json +6 -6
@@ -0,0 +1,238 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { KnowledgeAPI, SkillsAPI } from './knowledge';
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('KnowledgeAPI', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+ const api = () => new KnowledgeAPI(new HttpClient({ apiKey: 'test-key' }));
17
+ it('should POST /knowledge/list for list()', async () => {
18
+ const page = { items: [{ id: 'know-1' }], next_cursor: null };
19
+ mockJsonResponse(page);
20
+ const result = await api().list();
21
+ expect(result).toEqual(page);
22
+ const [url, init] = mockFetch.mock.calls[0];
23
+ expect(url).toContain('/knowledge/list');
24
+ expect(init.method).toBe('POST');
25
+ });
26
+ it('should GET /knowledge/{namespace}/{name} for getByName()', async () => {
27
+ const entry = { id: 'know-1', namespace: 'acme', name: 'docs' };
28
+ mockJsonResponse(entry);
29
+ const result = await api().getByName('acme', 'docs');
30
+ expect(result).toEqual(entry);
31
+ const [url, init] = mockFetch.mock.calls[0];
32
+ expect(url).toContain('/knowledge/acme/docs');
33
+ expect(init.method).toBe('GET');
34
+ });
35
+ it('should POST /knowledge for create()', async () => {
36
+ const payload = { namespace: 'acme', name: 'docs', content: 'hello' };
37
+ const entry = { id: 'know-new', ...payload };
38
+ mockJsonResponse(entry);
39
+ const result = await api().create(payload);
40
+ expect(result).toEqual(entry);
41
+ const [url, init] = mockFetch.mock.calls[0];
42
+ expect(url).toContain('/knowledge');
43
+ expect(init.method).toBe('POST');
44
+ });
45
+ it('should POST team_id for transferOwnership()', async () => {
46
+ const entry = { id: 'know-1' };
47
+ mockJsonResponse(entry);
48
+ await api().transferOwnership('know-1', 'team-5');
49
+ const [url, init] = mockFetch.mock.calls[0];
50
+ expect(url).toContain('/knowledge/know-1/transfer');
51
+ expect(JSON.parse(init.body)).toEqual({ team_id: 'team-5' });
52
+ });
53
+ it('should GET /knowledge/{id} for get()', async () => {
54
+ const entry = { id: 'know-1', name: 'docs' };
55
+ mockJsonResponse(entry);
56
+ const result = await api().get('know-1');
57
+ expect(result).toEqual(entry);
58
+ const [url, init] = mockFetch.mock.calls[0];
59
+ expect(url).toContain('/knowledge/know-1');
60
+ expect(init.method).toBe('GET');
61
+ });
62
+ it('should POST /knowledge/{id} for update()', async () => {
63
+ const entry = { id: 'know-1', name: 'updated' };
64
+ mockJsonResponse(entry);
65
+ const result = await api().update('know-1', { name: 'updated' });
66
+ expect(result).toEqual(entry);
67
+ const [, init] = mockFetch.mock.calls[0];
68
+ expect(JSON.parse(init.body)).toEqual({ name: 'updated' });
69
+ });
70
+ it('should DELETE /knowledge/{id} for delete()', async () => {
71
+ mockJsonResponse(null);
72
+ await api().delete('know-1');
73
+ const [url, init] = mockFetch.mock.calls[0];
74
+ expect(url).toContain('/knowledge/know-1');
75
+ expect(init.method).toBe('DELETE');
76
+ });
77
+ it('should POST /knowledge/{id}/versions/list for listVersions()', async () => {
78
+ const page = { items: [{ id: 'ver-1' }], next_cursor: null };
79
+ mockJsonResponse(page);
80
+ const result = await api().listVersions('know-1', { limit: 10 });
81
+ expect(result).toEqual(page);
82
+ const [url, init] = mockFetch.mock.calls[0];
83
+ expect(url).toContain('/knowledge/know-1/versions/list');
84
+ expect(JSON.parse(init.body)).toEqual({ limit: 10 });
85
+ });
86
+ it('should GET /knowledge/{id}/versions/{versionId} for getVersion()', async () => {
87
+ const version = { id: 'ver-1', knowledge_id: 'know-1' };
88
+ mockJsonResponse(version);
89
+ const result = await api().getVersion('know-1', 'ver-1');
90
+ expect(result).toEqual(version);
91
+ const [url, init] = mockFetch.mock.calls[0];
92
+ expect(url).toContain('/knowledge/know-1/versions/ver-1');
93
+ expect(init.method).toBe('GET');
94
+ });
95
+ it('should POST visibility for updateVisibility()', async () => {
96
+ const entry = { id: 'know-1', visibility: 'team' };
97
+ mockJsonResponse(entry);
98
+ await api().updateVisibility('know-1', 'team');
99
+ const [, init] = mockFetch.mock.calls[0];
100
+ expect(JSON.parse(init.body)).toEqual({ visibility: 'team' });
101
+ });
102
+ });
103
+ describe('SkillsAPI', () => {
104
+ beforeEach(() => {
105
+ jest.clearAllMocks();
106
+ });
107
+ const api = () => new SkillsAPI(new HttpClient({ apiKey: 'test-key' }));
108
+ it('should GET /skills/resolve with ref param for resolve()', async () => {
109
+ const resolved = { ref: 'acme/skill@v1', content: '{}' };
110
+ mockJsonResponse(resolved);
111
+ const result = await api().resolve('acme/skill@v1', 'main');
112
+ expect(result).toEqual(resolved);
113
+ const [url] = mockFetch.mock.calls[0];
114
+ expect(url).toContain('/skills/resolve');
115
+ expect(url).toContain('ref=acme');
116
+ expect(url).toContain('skill=main');
117
+ });
118
+ it('should GET /skills/{namespace}/{name} for getByName()', async () => {
119
+ const skill = { id: 'skill-1', namespace: 'acme', name: 'research' };
120
+ mockJsonResponse(skill);
121
+ const result = await api().getByName('acme', 'research');
122
+ expect(result).toEqual(skill);
123
+ const [url, init] = mockFetch.mock.calls[0];
124
+ expect(url).toContain('/skills/acme/research');
125
+ expect(init.method).toBe('GET');
126
+ });
127
+ it('should GET /skills/{namespace}/{name}/download for download()', async () => {
128
+ mockJsonResponse({ url: 'https://cdn.example.com/skill.zip' });
129
+ await api().download('acme', 'research');
130
+ const [url, init] = mockFetch.mock.calls[0];
131
+ expect(url).toContain('/skills/acme/research/download');
132
+ expect(init.method).toBe('GET');
133
+ });
134
+ it('should POST /store/skills/list for listStore()', async () => {
135
+ const page = { items: [{ namespace: 'public', name: 'starter' }], next_cursor: null };
136
+ mockJsonResponse(page);
137
+ const result = await api().listStore();
138
+ expect(result).toEqual(page);
139
+ const [url, init] = mockFetch.mock.calls[0];
140
+ expect(url).toContain('/store/skills/list');
141
+ expect(init.method).toBe('POST');
142
+ });
143
+ it('should GET /skills/resolve with ref only when skill is omitted', async () => {
144
+ const resolved = { ref: 'acme/skill@v1' };
145
+ mockJsonResponse(resolved);
146
+ const result = await api().resolve('acme/skill@v1');
147
+ expect(result).toEqual(resolved);
148
+ const [url] = mockFetch.mock.calls[0];
149
+ expect(url).toContain('/skills/resolve');
150
+ expect(url).toContain('ref=acme');
151
+ expect(url).not.toContain('skill=');
152
+ });
153
+ it('should GET /skills/{namespace}/{name}/content for getContent()', async () => {
154
+ mockJsonResponse({ body: '# Skill instructions' });
155
+ const result = await api().getContent('acme', 'research');
156
+ expect(result).toEqual({ body: '# Skill instructions' });
157
+ const [url, init] = mockFetch.mock.calls[0];
158
+ expect(url).toContain('/skills/acme/research/content');
159
+ expect(init.method).toBe('GET');
160
+ });
161
+ it('should POST team_id for transferOwnership()', async () => {
162
+ const skill = { id: 'skill-1' };
163
+ mockJsonResponse(skill);
164
+ await api().transferOwnership('skill-1', 'team-8');
165
+ const [url, init] = mockFetch.mock.calls[0];
166
+ expect(url).toContain('/skills/skill-1/transfer');
167
+ expect(JSON.parse(init.body)).toEqual({ team_id: 'team-8' });
168
+ });
169
+ it('should POST /skills/list for list()', async () => {
170
+ const page = { items: [{ id: 'skill-1' }], next_cursor: null };
171
+ mockJsonResponse(page);
172
+ const result = await api().list({ limit: 10 });
173
+ expect(result).toEqual(page);
174
+ const [url, init] = mockFetch.mock.calls[0];
175
+ expect(url).toContain('/skills/list');
176
+ expect(init.method).toBe('POST');
177
+ });
178
+ it('should GET /skills/{id} for get()', async () => {
179
+ const skill = { id: 'skill-1', name: 'research' };
180
+ mockJsonResponse(skill);
181
+ const result = await api().get('skill-1');
182
+ expect(result).toEqual(skill);
183
+ const [url, init] = mockFetch.mock.calls[0];
184
+ expect(url).toContain('/skills/skill-1');
185
+ expect(init.method).toBe('GET');
186
+ });
187
+ it('should POST /skills for create()', async () => {
188
+ const payload = { namespace: 'acme', name: 'research' };
189
+ const skill = { id: 'skill-new', ...payload };
190
+ mockJsonResponse(skill);
191
+ const result = await api().create(payload);
192
+ expect(result).toEqual(skill);
193
+ const [url, init] = mockFetch.mock.calls[0];
194
+ expect(url).toContain('/skills');
195
+ expect(init.method).toBe('POST');
196
+ expect(JSON.parse(init.body)).toEqual(payload);
197
+ });
198
+ it('should POST /skills/{id} for update()', async () => {
199
+ const skill = { id: 'skill-1', name: 'updated' };
200
+ mockJsonResponse(skill);
201
+ const result = await api().update('skill-1', { name: 'updated' });
202
+ expect(result).toEqual(skill);
203
+ const [, init] = mockFetch.mock.calls[0];
204
+ expect(JSON.parse(init.body)).toEqual({ name: 'updated' });
205
+ });
206
+ it('should DELETE /skills/{id} for delete()', async () => {
207
+ mockJsonResponse(null);
208
+ await api().delete('skill-1');
209
+ const [url, init] = mockFetch.mock.calls[0];
210
+ expect(url).toContain('/skills/skill-1');
211
+ expect(init.method).toBe('DELETE');
212
+ });
213
+ it('should POST /skills/{id}/versions/list for listVersions()', async () => {
214
+ const page = { items: [{ id: 'ver-1' }], next_cursor: null };
215
+ mockJsonResponse(page);
216
+ const result = await api().listVersions('skill-1', { limit: 5 });
217
+ expect(result).toEqual(page);
218
+ const [url, init] = mockFetch.mock.calls[0];
219
+ expect(url).toContain('/skills/skill-1/versions/list');
220
+ expect(JSON.parse(init.body)).toEqual({ limit: 5 });
221
+ });
222
+ it('should GET /skills/{id}/versions/{versionId} for getVersion()', async () => {
223
+ const version = { id: 'ver-1', skill_id: 'skill-1' };
224
+ mockJsonResponse(version);
225
+ const result = await api().getVersion('skill-1', 'ver-1');
226
+ expect(result).toEqual(version);
227
+ const [url, init] = mockFetch.mock.calls[0];
228
+ expect(url).toContain('/skills/skill-1/versions/ver-1');
229
+ expect(init.method).toBe('GET');
230
+ });
231
+ it('should POST visibility for updateVisibility()', async () => {
232
+ const skill = { id: 'skill-1', visibility: 'team' };
233
+ mockJsonResponse(skill);
234
+ await api().updateVisibility('skill-1', 'team');
235
+ const [, init] = mockFetch.mock.calls[0];
236
+ expect(JSON.parse(init.body)).toEqual({ visibility: 'team' });
237
+ });
238
+ });
@@ -0,0 +1,45 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { MCPServerDTO, CursorListRequest, CursorListResponse } from '../types';
3
+ /**
4
+ * MCP Servers API
5
+ */
6
+ export declare class MCPServersAPI {
7
+ private readonly http;
8
+ constructor(http: HttpClient);
9
+ /**
10
+ * List public MCP servers
11
+ */
12
+ list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<MCPServerDTO>>;
13
+ /**
14
+ * Get an MCP server by slug
15
+ */
16
+ get(slug: string): Promise<MCPServerDTO>;
17
+ /**
18
+ * List tools for an MCP server
19
+ */
20
+ listTools(slug: string): Promise<unknown[]>;
21
+ /**
22
+ * Call a tool on an MCP server
23
+ */
24
+ callTool(slug: string, tool: string, input: unknown): Promise<unknown>;
25
+ /**
26
+ * List user's own MCP servers
27
+ */
28
+ listOwned(params?: Partial<CursorListRequest>): Promise<CursorListResponse<MCPServerDTO>>;
29
+ /**
30
+ * Get a user's MCP server by ID
31
+ */
32
+ getOwned(id: string): Promise<MCPServerDTO>;
33
+ /**
34
+ * Create an MCP server
35
+ */
36
+ create(data: Partial<MCPServerDTO>): Promise<MCPServerDTO>;
37
+ /**
38
+ * Update an MCP server
39
+ */
40
+ update(id: string, data: Partial<MCPServerDTO>): Promise<MCPServerDTO>;
41
+ /**
42
+ * Delete an MCP server
43
+ */
44
+ delete(id: string): Promise<void>;
45
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * MCP Servers API
3
+ */
4
+ export class MCPServersAPI {
5
+ constructor(http) {
6
+ this.http = http;
7
+ }
8
+ /**
9
+ * List public MCP servers
10
+ */
11
+ async list(params) {
12
+ return this.http.request('post', '/mcps/list', { data: params });
13
+ }
14
+ /**
15
+ * Get an MCP server by slug
16
+ */
17
+ async get(slug) {
18
+ return this.http.request('get', `/mcps/${slug}`);
19
+ }
20
+ /**
21
+ * List tools for an MCP server
22
+ */
23
+ async listTools(slug) {
24
+ return this.http.request('get', `/mcps/${slug}/tools`);
25
+ }
26
+ /**
27
+ * Call a tool on an MCP server
28
+ */
29
+ async callTool(slug, tool, input) {
30
+ return this.http.request('post', `/mcps/${slug}/tools/${tool}`, { data: input });
31
+ }
32
+ /**
33
+ * List user's own MCP servers
34
+ */
35
+ async listOwned(params) {
36
+ return this.http.request('post', '/mcp-servers/list', { data: params });
37
+ }
38
+ /**
39
+ * Get a user's MCP server by ID
40
+ */
41
+ async getOwned(id) {
42
+ return this.http.request('get', `/mcp-servers/${id}`);
43
+ }
44
+ /**
45
+ * Create an MCP server
46
+ */
47
+ async create(data) {
48
+ return this.http.request('post', '/mcp-servers', { data });
49
+ }
50
+ /**
51
+ * Update an MCP server
52
+ */
53
+ async update(id, data) {
54
+ return this.http.request('put', `/mcp-servers/${id}`, { data });
55
+ }
56
+ /**
57
+ * Delete an MCP server
58
+ */
59
+ async delete(id) {
60
+ return this.http.request('delete', `/mcp-servers/${id}`);
61
+ }
62
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,98 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { MCPServersAPI } from './mcp-servers';
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('MCPServersAPI', () => {
13
+ beforeEach(() => {
14
+ jest.clearAllMocks();
15
+ });
16
+ const api = () => new MCPServersAPI(new HttpClient({ apiKey: 'test-key' }));
17
+ it('should POST /mcps/list for list()', async () => {
18
+ const page = { items: [{ slug: 'filesystem' }], next_cursor: null };
19
+ mockJsonResponse(page);
20
+ const result = await api().list();
21
+ expect(result).toEqual(page);
22
+ const [url, init] = mockFetch.mock.calls[0];
23
+ expect(url).toContain('/mcps/list');
24
+ expect(init.method).toBe('POST');
25
+ });
26
+ it('should GET /mcps/{slug}/tools for listTools()', async () => {
27
+ const tools = [{ name: 'read_file' }];
28
+ mockJsonResponse(tools);
29
+ const result = await api().listTools('filesystem');
30
+ expect(result).toEqual(tools);
31
+ const [url, init] = mockFetch.mock.calls[0];
32
+ expect(url).toContain('/mcps/filesystem/tools');
33
+ expect(init.method).toBe('GET');
34
+ });
35
+ it('should POST /mcps/{slug}/tools/{tool} for callTool()', async () => {
36
+ const input = { path: '/tmp/test.txt' };
37
+ const output = { content: 'hello' };
38
+ mockJsonResponse(output);
39
+ const result = await api().callTool('filesystem', 'read_file', input);
40
+ expect(result).toEqual(output);
41
+ const [url, init] = mockFetch.mock.calls[0];
42
+ expect(url).toContain('/mcps/filesystem/tools/read_file');
43
+ expect(init.method).toBe('POST');
44
+ expect(JSON.parse(init.body)).toEqual(input);
45
+ });
46
+ it('should POST /mcp-servers for create()', async () => {
47
+ const payload = { name: 'My MCP', slug: 'my-mcp' };
48
+ const server = { id: 'mcp-1', ...payload };
49
+ mockJsonResponse(server);
50
+ const result = await api().create(payload);
51
+ expect(result).toEqual(server);
52
+ const [url, init] = mockFetch.mock.calls[0];
53
+ expect(url).toContain('/mcp-servers');
54
+ expect(init.method).toBe('POST');
55
+ });
56
+ it('should PUT /mcp-servers/{id} for update()', async () => {
57
+ const server = { id: 'mcp-1', name: 'Updated MCP' };
58
+ mockJsonResponse(server);
59
+ await api().update('mcp-1', { name: 'Updated MCP' });
60
+ const [url, init] = mockFetch.mock.calls[0];
61
+ expect(url).toContain('/mcp-servers/mcp-1');
62
+ expect(init.method).toBe('PUT');
63
+ });
64
+ it('should GET /mcps/{slug} for get()', async () => {
65
+ const server = { slug: 'filesystem', name: 'Filesystem MCP' };
66
+ mockJsonResponse(server);
67
+ const result = await api().get('filesystem');
68
+ expect(result).toEqual(server);
69
+ const [url, init] = mockFetch.mock.calls[0];
70
+ expect(url).toContain('/mcps/filesystem');
71
+ expect(init.method).toBe('GET');
72
+ });
73
+ it('should POST /mcp-servers/list for listOwned()', async () => {
74
+ const page = { items: [{ id: 'mcp-1' }], next_cursor: null };
75
+ mockJsonResponse(page);
76
+ const result = await api().listOwned({ limit: 5 });
77
+ expect(result).toEqual(page);
78
+ const [url, init] = mockFetch.mock.calls[0];
79
+ expect(url).toContain('/mcp-servers/list');
80
+ expect(init.method).toBe('POST');
81
+ });
82
+ it('should GET /mcp-servers/{id} for getOwned()', async () => {
83
+ const server = { id: 'mcp-1', name: 'My MCP' };
84
+ mockJsonResponse(server);
85
+ const result = await api().getOwned('mcp-1');
86
+ expect(result).toEqual(server);
87
+ const [url, init] = mockFetch.mock.calls[0];
88
+ expect(url).toContain('/mcp-servers/mcp-1');
89
+ expect(init.method).toBe('GET');
90
+ });
91
+ it('should DELETE /mcp-servers/{id} for delete()', async () => {
92
+ mockJsonResponse(null);
93
+ await api().delete('mcp-1');
94
+ const [url, init] = mockFetch.mock.calls[0];
95
+ expect(url).toContain('/mcp-servers/mcp-1');
96
+ expect(init.method).toBe('DELETE');
97
+ });
98
+ });
@@ -0,0 +1,29 @@
1
+ import { HttpClient } from '../http/client';
2
+ import { ProjectDTO, CursorListRequest, CursorListResponse } from '../types';
3
+ /**
4
+ * Projects API
5
+ */
6
+ export declare class ProjectsAPI {
7
+ private readonly http;
8
+ constructor(http: HttpClient);
9
+ /**
10
+ * List projects with cursor-based pagination
11
+ */
12
+ list(params?: Partial<CursorListRequest>): Promise<CursorListResponse<ProjectDTO>>;
13
+ /**
14
+ * Get a project by ID
15
+ */
16
+ get(id: string): Promise<ProjectDTO>;
17
+ /**
18
+ * Create a project
19
+ */
20
+ create(data: Partial<ProjectDTO>): Promise<ProjectDTO>;
21
+ /**
22
+ * Update a project
23
+ */
24
+ update(id: string, data: Partial<ProjectDTO>): Promise<ProjectDTO>;
25
+ /**
26
+ * Delete a project
27
+ */
28
+ delete(id: string): Promise<void>;
29
+ }
@@ -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,61 @@
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
+ it('should POST /projects/{id} for update()', async () => {
53
+ const project = { id: 'proj-1', name: 'Renamed' };
54
+ mockJsonResponse(project);
55
+ const result = await api().update('proj-1', { name: 'Renamed' });
56
+ expect(result).toEqual(project);
57
+ const [url, init] = mockFetch.mock.calls[0];
58
+ expect(url).toContain('/projects/proj-1');
59
+ expect(JSON.parse(init.body)).toEqual({ name: 'Renamed' });
60
+ });
61
+ });
@@ -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
+ });