@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
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,14 @@ export { ChatsAPI } from './api/chats';
|
|
|
12
12
|
export { FlowsAPI } from './api/flows';
|
|
13
13
|
export { FlowRunsAPI } from './api/flow-runs';
|
|
14
14
|
export { EnginesAPI } from './api/engines';
|
|
15
|
+
export { KnowledgeAPI, SkillsAPI } from './api/knowledge';
|
|
16
|
+
export { TeamsAPI, MeResponse } from './api/teams';
|
|
17
|
+
export { SecretsAPI } from './api/secrets';
|
|
18
|
+
export { ApiKeysAPI } from './api/api-keys';
|
|
19
|
+
export { IntegrationsAPI } from './api/integrations';
|
|
20
|
+
export { SearchAPI } from './api/search';
|
|
21
|
+
export { ProjectsAPI } from './api/projects';
|
|
22
|
+
export { MCPServersAPI } from './api/mcp-servers';
|
|
15
23
|
export { tool, appTool, agentTool, webhookTool, httpTool, callTool, mcpTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional, } from './tool-builder';
|
|
16
24
|
export type { ClientTool, ClientToolHandler } from './tool-builder';
|
|
17
25
|
export { parseStatus, isTerminalStatus } from './utils';
|
|
@@ -27,6 +35,14 @@ import { ChatsAPI } from './api/chats';
|
|
|
27
35
|
import { FlowsAPI } from './api/flows';
|
|
28
36
|
import { FlowRunsAPI } from './api/flow-runs';
|
|
29
37
|
import { EnginesAPI } from './api/engines';
|
|
38
|
+
import { KnowledgeAPI, SkillsAPI } from './api/knowledge';
|
|
39
|
+
import { TeamsAPI } from './api/teams';
|
|
40
|
+
import { SecretsAPI } from './api/secrets';
|
|
41
|
+
import { ApiKeysAPI } from './api/api-keys';
|
|
42
|
+
import { IntegrationsAPI } from './api/integrations';
|
|
43
|
+
import { SearchAPI } from './api/search';
|
|
44
|
+
import { ProjectsAPI } from './api/projects';
|
|
45
|
+
import { MCPServersAPI } from './api/mcp-servers';
|
|
30
46
|
import { ApiAppRunRequest, TaskDTO as Task, AgentConfigInput as AgentConfig, FileDTO as File } from './types';
|
|
31
47
|
export interface InferenceConfig {
|
|
32
48
|
/** Your inference.sh API key (required unless using proxyUrl) */
|
|
@@ -68,6 +84,15 @@ export declare class Inference {
|
|
|
68
84
|
readonly flows: FlowsAPI;
|
|
69
85
|
readonly flowRuns: FlowRunsAPI;
|
|
70
86
|
readonly engines: EnginesAPI;
|
|
87
|
+
readonly knowledge: KnowledgeAPI;
|
|
88
|
+
readonly skills: SkillsAPI;
|
|
89
|
+
readonly teams: TeamsAPI;
|
|
90
|
+
readonly secrets: SecretsAPI;
|
|
91
|
+
readonly apiKeys: ApiKeysAPI;
|
|
92
|
+
readonly integrations: IntegrationsAPI;
|
|
93
|
+
readonly search: SearchAPI;
|
|
94
|
+
readonly projects: ProjectsAPI;
|
|
95
|
+
readonly mcpServers: MCPServersAPI;
|
|
71
96
|
constructor(config: InferenceConfig | HttpClientConfig);
|
|
72
97
|
/** @internal */
|
|
73
98
|
_request<T>(method: 'get' | 'post' | 'put' | 'delete', endpoint: string, options?: {
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,14 @@ export { ChatsAPI } from './api/chats';
|
|
|
16
16
|
export { FlowsAPI } from './api/flows';
|
|
17
17
|
export { FlowRunsAPI } from './api/flow-runs';
|
|
18
18
|
export { EnginesAPI } from './api/engines';
|
|
19
|
+
export { KnowledgeAPI, SkillsAPI } from './api/knowledge';
|
|
20
|
+
export { TeamsAPI } from './api/teams';
|
|
21
|
+
export { SecretsAPI } from './api/secrets';
|
|
22
|
+
export { ApiKeysAPI } from './api/api-keys';
|
|
23
|
+
export { IntegrationsAPI } from './api/integrations';
|
|
24
|
+
export { SearchAPI } from './api/search';
|
|
25
|
+
export { ProjectsAPI } from './api/projects';
|
|
26
|
+
export { MCPServersAPI } from './api/mcp-servers';
|
|
19
27
|
// Tool Builder (fluent API)
|
|
20
28
|
export { tool, appTool, agentTool, webhookTool, httpTool, callTool, mcpTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional, } from './tool-builder';
|
|
21
29
|
// Status utilities (handle both int and string status values)
|
|
@@ -35,6 +43,14 @@ import { ChatsAPI } from './api/chats';
|
|
|
35
43
|
import { FlowsAPI } from './api/flows';
|
|
36
44
|
import { FlowRunsAPI } from './api/flow-runs';
|
|
37
45
|
import { EnginesAPI } from './api/engines';
|
|
46
|
+
import { KnowledgeAPI, SkillsAPI } from './api/knowledge';
|
|
47
|
+
import { TeamsAPI } from './api/teams';
|
|
48
|
+
import { SecretsAPI } from './api/secrets';
|
|
49
|
+
import { ApiKeysAPI } from './api/api-keys';
|
|
50
|
+
import { IntegrationsAPI } from './api/integrations';
|
|
51
|
+
import { SearchAPI } from './api/search';
|
|
52
|
+
import { ProjectsAPI } from './api/projects';
|
|
53
|
+
import { MCPServersAPI } from './api/mcp-servers';
|
|
38
54
|
/**
|
|
39
55
|
* Inference.sh SDK Client
|
|
40
56
|
*
|
|
@@ -67,6 +83,15 @@ export class Inference {
|
|
|
67
83
|
this.flows = new FlowsAPI(this.http);
|
|
68
84
|
this.flowRuns = new FlowRunsAPI(this.http);
|
|
69
85
|
this.engines = new EnginesAPI(this.http);
|
|
86
|
+
this.knowledge = new KnowledgeAPI(this.http);
|
|
87
|
+
this.skills = new SkillsAPI(this.http);
|
|
88
|
+
this.teams = new TeamsAPI(this.http);
|
|
89
|
+
this.secrets = new SecretsAPI(this.http);
|
|
90
|
+
this.apiKeys = new ApiKeysAPI(this.http);
|
|
91
|
+
this.integrations = new IntegrationsAPI(this.http);
|
|
92
|
+
this.search = new SearchAPI(this.http);
|
|
93
|
+
this.projects = new ProjectsAPI(this.http);
|
|
94
|
+
this.mcpServers = new MCPServersAPI(this.http);
|
|
70
95
|
}
|
|
71
96
|
// Legacy methods for backward compatibility
|
|
72
97
|
/** @internal */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { INF_TARGET_HEADER } from './index';
|
|
2
|
+
import { createHandler } from './hono';
|
|
3
|
+
function createMockContext(overrides = {}) {
|
|
4
|
+
const headers = new Headers(overrides.headers ?? {});
|
|
5
|
+
const url = overrides.url ?? 'http://localhost/api/inference/proxy';
|
|
6
|
+
return {
|
|
7
|
+
req: {
|
|
8
|
+
method: overrides.method ?? 'POST',
|
|
9
|
+
url,
|
|
10
|
+
raw: { headers },
|
|
11
|
+
header: (name) => headers.get(name) ?? undefined,
|
|
12
|
+
text: () => Promise.resolve(overrides.body ?? '{"ok":true}'),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
describe('hono createHandler', () => {
|
|
17
|
+
const originalFetch = global.fetch;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.clearAllMocks();
|
|
20
|
+
process.env.INFERENCE_API_KEY = 'hono-test-key';
|
|
21
|
+
});
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
global.fetch = originalFetch;
|
|
24
|
+
});
|
|
25
|
+
it('should return 400 when target URL is missing', async () => {
|
|
26
|
+
const handler = createHandler();
|
|
27
|
+
const response = await handler(createMockContext());
|
|
28
|
+
expect(response.status).toBe(400);
|
|
29
|
+
expect(await response.json()).toEqual({
|
|
30
|
+
error: `Missing ${INF_TARGET_HEADER} header or __inf_target query param`,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
it('should proxy JSON responses', async () => {
|
|
34
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
35
|
+
status: 200,
|
|
36
|
+
headers: { 'content-type': 'application/json' },
|
|
37
|
+
}));
|
|
38
|
+
const handler = createHandler();
|
|
39
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
40
|
+
const response = await handler(createMockContext({
|
|
41
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
42
|
+
}));
|
|
43
|
+
expect(response.status).toBe(200);
|
|
44
|
+
expect(await response.json()).toEqual({ ok: true });
|
|
45
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
46
|
+
headers: expect.objectContaining({
|
|
47
|
+
authorization: 'Bearer hono-test-key',
|
|
48
|
+
}),
|
|
49
|
+
}));
|
|
50
|
+
});
|
|
51
|
+
it('should passthrough SSE streaming responses', async () => {
|
|
52
|
+
const encoder = new TextEncoder();
|
|
53
|
+
const stream = new ReadableStream({
|
|
54
|
+
start(controller) {
|
|
55
|
+
controller.enqueue(encoder.encode('data: {"x":1}\n\n'));
|
|
56
|
+
controller.close();
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(stream, {
|
|
60
|
+
status: 200,
|
|
61
|
+
headers: { 'content-type': 'text/event-stream' },
|
|
62
|
+
}));
|
|
63
|
+
const handler = createHandler();
|
|
64
|
+
const target = 'https://api.inference.sh/v1/stream';
|
|
65
|
+
const response = await handler(createMockContext({
|
|
66
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
67
|
+
}));
|
|
68
|
+
expect(response.status).toBe(200);
|
|
69
|
+
expect(response.headers.get('content-type')).toContain('text/event-stream');
|
|
70
|
+
expect(await response.text()).toContain('data:');
|
|
71
|
+
});
|
|
72
|
+
it('should resolve API key via resolveApiKey option', async () => {
|
|
73
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
74
|
+
status: 200,
|
|
75
|
+
headers: { 'content-type': 'application/json' },
|
|
76
|
+
}));
|
|
77
|
+
const handler = createHandler({
|
|
78
|
+
resolveApiKey: async () => 'custom-hono-key',
|
|
79
|
+
});
|
|
80
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
81
|
+
await handler(createMockContext({
|
|
82
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
83
|
+
}));
|
|
84
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
85
|
+
headers: expect.objectContaining({
|
|
86
|
+
authorization: 'Bearer custom-hono-key',
|
|
87
|
+
}),
|
|
88
|
+
}));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { INF_TARGET_HEADER } from './index';
|
|
2
|
+
import { handlers, pageHandler } from './nextjs';
|
|
3
|
+
function createMockPageResponse() {
|
|
4
|
+
const res = {
|
|
5
|
+
statusCode: 200,
|
|
6
|
+
headers: {},
|
|
7
|
+
body: undefined,
|
|
8
|
+
status(code) {
|
|
9
|
+
this.statusCode = code;
|
|
10
|
+
return this;
|
|
11
|
+
},
|
|
12
|
+
setHeader(name, value) {
|
|
13
|
+
this.headers[name] = value;
|
|
14
|
+
},
|
|
15
|
+
json(data) {
|
|
16
|
+
this.body = data;
|
|
17
|
+
return this;
|
|
18
|
+
},
|
|
19
|
+
send(data) {
|
|
20
|
+
this.body = data;
|
|
21
|
+
return this;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
return res;
|
|
25
|
+
}
|
|
26
|
+
function createMockNextRequest(overrides = {}) {
|
|
27
|
+
const headers = new Headers(overrides.headers ?? {});
|
|
28
|
+
return {
|
|
29
|
+
method: overrides.method ?? 'POST',
|
|
30
|
+
url: overrides.url ?? 'http://localhost/api/inference/proxy',
|
|
31
|
+
headers,
|
|
32
|
+
text: () => Promise.resolve(overrides.body ?? '{"prompt":"hi"}'),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
describe('nextjs pageHandler', () => {
|
|
36
|
+
const originalFetch = global.fetch;
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
jest.clearAllMocks();
|
|
39
|
+
process.env.INFERENCE_API_KEY = 'nextjs-test-key';
|
|
40
|
+
});
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
global.fetch = originalFetch;
|
|
43
|
+
});
|
|
44
|
+
it('should return 400 when target URL is missing', async () => {
|
|
45
|
+
const req = { method: 'POST', body: {}, headers: {}, query: {} };
|
|
46
|
+
const res = createMockPageResponse();
|
|
47
|
+
await pageHandler(req, res);
|
|
48
|
+
expect(res.statusCode).toBe(400);
|
|
49
|
+
expect(res.body).toEqual({
|
|
50
|
+
error: `Missing ${INF_TARGET_HEADER} header or __inf_target query param`,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
it('should proxy JSON responses through res.json()', async () => {
|
|
54
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
55
|
+
status: 200,
|
|
56
|
+
headers: { 'content-type': 'application/json' },
|
|
57
|
+
}));
|
|
58
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
59
|
+
const req = {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
body: { prompt: 'hi' },
|
|
62
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
63
|
+
query: {},
|
|
64
|
+
};
|
|
65
|
+
const res = createMockPageResponse();
|
|
66
|
+
await pageHandler(req, res);
|
|
67
|
+
expect(res.statusCode).toBe(200);
|
|
68
|
+
expect(res.body).toEqual({ ok: true });
|
|
69
|
+
});
|
|
70
|
+
it('should proxy non-JSON responses through res.send()', async () => {
|
|
71
|
+
global.fetch = jest.fn().mockResolvedValue(new Response('plain text', {
|
|
72
|
+
status: 200,
|
|
73
|
+
headers: { 'content-type': 'text/plain' },
|
|
74
|
+
}));
|
|
75
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
76
|
+
const req = {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: {},
|
|
79
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
80
|
+
query: {},
|
|
81
|
+
};
|
|
82
|
+
const res = createMockPageResponse();
|
|
83
|
+
await pageHandler(req, res);
|
|
84
|
+
expect(res.statusCode).toBe(200);
|
|
85
|
+
expect(res.body).toBe('plain text');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('nextjs handlers (App Router)', () => {
|
|
89
|
+
const originalFetch = global.fetch;
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
jest.clearAllMocks();
|
|
92
|
+
process.env.INFERENCE_API_KEY = 'nextjs-test-key';
|
|
93
|
+
});
|
|
94
|
+
afterEach(() => {
|
|
95
|
+
global.fetch = originalFetch;
|
|
96
|
+
});
|
|
97
|
+
it('should return 400 when target URL is missing', async () => {
|
|
98
|
+
const response = await handlers.GET(createMockNextRequest());
|
|
99
|
+
expect(response.status).toBe(400);
|
|
100
|
+
expect(await response.json()).toEqual({
|
|
101
|
+
error: `Missing ${INF_TARGET_HEADER} header or __inf_target query param`,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it('should passthrough streaming responses via Response body', async () => {
|
|
105
|
+
const encoder = new TextEncoder();
|
|
106
|
+
const stream = new ReadableStream({
|
|
107
|
+
start(controller) {
|
|
108
|
+
controller.enqueue(encoder.encode('data: {"x":1}\n\n'));
|
|
109
|
+
controller.close();
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(stream, {
|
|
113
|
+
status: 200,
|
|
114
|
+
headers: { 'content-type': 'text/event-stream' },
|
|
115
|
+
}));
|
|
116
|
+
const target = 'https://api.inference.sh/v1/stream';
|
|
117
|
+
const response = await handlers.GET(createMockNextRequest({
|
|
118
|
+
method: 'GET',
|
|
119
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
120
|
+
}));
|
|
121
|
+
expect(response.status).toBe(200);
|
|
122
|
+
expect(response.body).toBeDefined();
|
|
123
|
+
expect(response.headers.get('content-type')).toContain('text/event-stream');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { INF_TARGET_HEADER } from './index';
|
|
2
|
+
import { createHandler } from './remix';
|
|
3
|
+
describe('remix createHandler', () => {
|
|
4
|
+
const originalFetch = global.fetch;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
jest.clearAllMocks();
|
|
7
|
+
process.env.INFERENCE_API_KEY = 'remix-test-key';
|
|
8
|
+
});
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
global.fetch = originalFetch;
|
|
11
|
+
});
|
|
12
|
+
it('should return 400 when target URL is missing', async () => {
|
|
13
|
+
const handler = createHandler();
|
|
14
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
body: '{}',
|
|
17
|
+
});
|
|
18
|
+
const response = await handler({ request });
|
|
19
|
+
expect(response.status).toBe(400);
|
|
20
|
+
expect(await response.json()).toEqual({
|
|
21
|
+
error: `Missing ${INF_TARGET_HEADER} header or __inf_target query param`,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it('should proxy JSON responses with framework remix', async () => {
|
|
25
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
26
|
+
status: 200,
|
|
27
|
+
headers: { 'content-type': 'application/json' },
|
|
28
|
+
}));
|
|
29
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
30
|
+
const handler = createHandler();
|
|
31
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
34
|
+
body: '{"prompt":"hi"}',
|
|
35
|
+
});
|
|
36
|
+
const response = await handler({ request });
|
|
37
|
+
expect(response.status).toBe(200);
|
|
38
|
+
expect(await response.json()).toEqual({ ok: true });
|
|
39
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
40
|
+
headers: expect.objectContaining({
|
|
41
|
+
authorization: 'Bearer remix-test-key',
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
});
|
|
45
|
+
it('should use custom resolveApiKey when provided', async () => {
|
|
46
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
47
|
+
status: 200,
|
|
48
|
+
headers: { 'content-type': 'application/json' },
|
|
49
|
+
}));
|
|
50
|
+
const handler = createHandler({
|
|
51
|
+
resolveApiKey: async () => 'custom-remix-key',
|
|
52
|
+
});
|
|
53
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
54
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
57
|
+
body: '{}',
|
|
58
|
+
});
|
|
59
|
+
await handler({ request });
|
|
60
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
61
|
+
headers: expect.objectContaining({
|
|
62
|
+
authorization: 'Bearer custom-remix-key',
|
|
63
|
+
}),
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { INF_TARGET_HEADER } from './index';
|
|
2
|
+
import { createHandler } from './svelte';
|
|
3
|
+
function createMockRequestEvent(request) {
|
|
4
|
+
return { request };
|
|
5
|
+
}
|
|
6
|
+
describe('svelte createHandler', () => {
|
|
7
|
+
const originalFetch = global.fetch;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
jest.clearAllMocks();
|
|
10
|
+
process.env.INFERENCE_API_KEY = 'svelte-test-key';
|
|
11
|
+
});
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
global.fetch = originalFetch;
|
|
14
|
+
});
|
|
15
|
+
it('should return 400 when target URL is missing', async () => {
|
|
16
|
+
const handler = createHandler();
|
|
17
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
body: '{}',
|
|
20
|
+
});
|
|
21
|
+
const response = await handler(createMockRequestEvent(request));
|
|
22
|
+
expect(response.status).toBe(400);
|
|
23
|
+
expect(await response.json()).toEqual({
|
|
24
|
+
error: `Missing ${INF_TARGET_HEADER} header or __inf_target query param`,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
it('should proxy JSON responses with framework sveltekit', async () => {
|
|
28
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
29
|
+
status: 200,
|
|
30
|
+
headers: { 'content-type': 'application/json' },
|
|
31
|
+
}));
|
|
32
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
33
|
+
const handler = createHandler();
|
|
34
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
37
|
+
body: '{"prompt":"hi"}',
|
|
38
|
+
});
|
|
39
|
+
const response = await handler(createMockRequestEvent(request));
|
|
40
|
+
expect(response.status).toBe(200);
|
|
41
|
+
expect(await response.json()).toEqual({ ok: true });
|
|
42
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
43
|
+
headers: expect.objectContaining({
|
|
44
|
+
authorization: 'Bearer svelte-test-key',
|
|
45
|
+
}),
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
it('should use custom resolveApiKey when provided', async () => {
|
|
49
|
+
global.fetch = jest.fn().mockResolvedValue(new Response(JSON.stringify({ ok: true }), {
|
|
50
|
+
status: 200,
|
|
51
|
+
headers: { 'content-type': 'application/json' },
|
|
52
|
+
}));
|
|
53
|
+
const handler = createHandler({
|
|
54
|
+
resolveApiKey: async () => 'custom-svelte-key',
|
|
55
|
+
});
|
|
56
|
+
const target = 'https://api.inference.sh/v1/run';
|
|
57
|
+
const request = new Request('http://localhost/api/inference/proxy', {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { [INF_TARGET_HEADER]: target },
|
|
60
|
+
body: '{}',
|
|
61
|
+
});
|
|
62
|
+
await handler(createMockRequestEvent(request));
|
|
63
|
+
expect(global.fetch).toHaveBeenCalledWith(target, expect.objectContaining({
|
|
64
|
+
headers: expect.objectContaining({
|
|
65
|
+
authorization: 'Bearer custom-svelte-key',
|
|
66
|
+
}),
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool, appTool, agentTool, webhookTool, httpTool, callTool, mcpTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional, } from './tool-builder';
|
|
2
|
-
import { ToolTypeClient, ToolTypeApp, ToolTypeAgent, ToolTypeHook, ToolTypeHTTP, ToolTypeMCP, IntegrationProviderGoogle, } from './types';
|
|
2
|
+
import { ToolTypeClient, ToolTypeApp, ToolTypeAgent, ToolTypeHook, ToolTypeHTTP, ToolTypeMCP, IntegrationProviderGoogle, IntegrationProviderGoogleSA, } from './types';
|
|
3
3
|
describe('Schema Helpers', () => {
|
|
4
4
|
describe('string', () => {
|
|
5
5
|
it('creates string schema without description', () => {
|
|
@@ -276,6 +276,16 @@ describe('HTTPToolBuilder (httpTool)', () => {
|
|
|
276
276
|
integration_id: 'int-123',
|
|
277
277
|
});
|
|
278
278
|
});
|
|
279
|
+
it('should attach integration auth for google-sa service account provider', () => {
|
|
280
|
+
const t = httpTool('calendar_read', 'https://api.example.com/calendar')
|
|
281
|
+
.auth({ integration: IntegrationProviderGoogleSA, integrationId: 'sa-int-1' })
|
|
282
|
+
.build();
|
|
283
|
+
expect(t.http?.auth).toEqual({
|
|
284
|
+
type: 'integration',
|
|
285
|
+
provider: IntegrationProviderGoogleSA,
|
|
286
|
+
integration_id: 'sa-int-1',
|
|
287
|
+
});
|
|
288
|
+
});
|
|
279
289
|
it('should attach api key auth with default header', () => {
|
|
280
290
|
const t = httpTool('fetch', 'https://api.example.com').auth({ apiKey: 'KEY' }).build();
|
|
281
291
|
expect(t.http?.auth).toEqual({
|