@inferencesh/sdk 0.4.4 → 0.4.8
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/dist/client.d.ts +14 -6
- package/dist/client.js +40 -15
- package/dist/client.test.js +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/proxy/express.d.ts +37 -0
- package/dist/proxy/express.js +84 -0
- package/dist/proxy/express.mjs +1 -0
- package/dist/proxy/hono.d.ts +59 -0
- package/dist/proxy/hono.js +84 -0
- package/dist/proxy/hono.mjs +1 -0
- package/dist/proxy/index.d.ts +55 -0
- package/dist/proxy/index.js +136 -0
- package/dist/proxy/index.mjs +1 -0
- package/dist/proxy/index.test.d.ts +1 -0
- package/dist/proxy/index.test.js +220 -0
- package/dist/proxy/index.test.mjs +1 -0
- package/dist/proxy/nextjs.d.ts +61 -0
- package/dist/proxy/nextjs.js +95 -0
- package/dist/proxy/nextjs.mjs +1 -0
- package/dist/proxy/remix.d.ts +47 -0
- package/dist/proxy/remix.js +61 -0
- package/dist/proxy/remix.mjs +1 -0
- package/dist/proxy/svelte.d.ts +46 -0
- package/dist/proxy/svelte.js +62 -0
- package/dist/proxy/svelte.mjs +1 -0
- package/dist/types.d.ts +171 -94
- package/dist/types.js +30 -5
- package/package.json +60 -3
- package/dist/agent.d.ts +0 -78
- package/dist/agent.js +0 -188
package/dist/client.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ApiAppRunRequest, TaskDTO as Task, File, ChatDTO, ChatMessageDTO,
|
|
1
|
+
import { ApiAppRunRequest, TaskDTO as Task, File, ChatDTO, ChatMessageDTO, AgentConfig } from './types';
|
|
2
2
|
import { EventSource } from 'eventsource';
|
|
3
3
|
/**
|
|
4
|
-
* Ad-hoc agent configuration - extends
|
|
5
|
-
* Uses Partial to make
|
|
4
|
+
* Ad-hoc agent configuration - extends AgentConfig with core_app_ref required
|
|
5
|
+
* Uses Partial to make fields optional for ad-hoc usage
|
|
6
6
|
*/
|
|
7
|
-
export type AdHocAgentConfig = Partial<
|
|
7
|
+
export type AdHocAgentConfig = Partial<AgentConfig> & {
|
|
8
8
|
/** Core LLM app ref: namespace/name@shortid (required for ad-hoc agents) */
|
|
9
9
|
core_app_ref: string;
|
|
10
10
|
};
|
|
@@ -29,10 +29,17 @@ export interface UploadFileOptions {
|
|
|
29
29
|
public?: boolean;
|
|
30
30
|
}
|
|
31
31
|
export interface InferenceConfig {
|
|
32
|
-
/** Your inference.sh API key */
|
|
33
|
-
apiKey
|
|
32
|
+
/** Your inference.sh API key (required unless using proxyUrl) */
|
|
33
|
+
apiKey?: string;
|
|
34
34
|
/** Custom API base URL (defaults to https://api.inference.sh) */
|
|
35
35
|
baseUrl?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Proxy URL for frontend apps.
|
|
38
|
+
* When set, requests are routed through your proxy server to protect API keys.
|
|
39
|
+
* @example "/api/inference/proxy"
|
|
40
|
+
* @example "https://myapp.com/api/inference/proxy"
|
|
41
|
+
*/
|
|
42
|
+
proxyUrl?: string;
|
|
36
43
|
}
|
|
37
44
|
export interface RunOptions {
|
|
38
45
|
/** Callback for real-time status updates */
|
|
@@ -60,6 +67,7 @@ export interface RunOptions {
|
|
|
60
67
|
export declare class Inference {
|
|
61
68
|
private readonly apiKey;
|
|
62
69
|
private readonly baseUrl;
|
|
70
|
+
private readonly proxyUrl;
|
|
63
71
|
constructor(config: InferenceConfig);
|
|
64
72
|
/** @internal */
|
|
65
73
|
_request<T>(method: "get" | "post" | "put" | "delete", endpoint: string, options?: {
|
package/dist/client.js
CHANGED
|
@@ -17,26 +17,39 @@ const errors_1 = require("./errors");
|
|
|
17
17
|
*/
|
|
18
18
|
class Inference {
|
|
19
19
|
constructor(config) {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
// Either apiKey or proxyUrl must be provided
|
|
21
|
+
if (!config.apiKey && !config.proxyUrl) {
|
|
22
|
+
throw new Error('Either apiKey or proxyUrl is required');
|
|
22
23
|
}
|
|
23
24
|
this.apiKey = config.apiKey;
|
|
24
25
|
this.baseUrl = config.baseUrl || "https://api.inference.sh";
|
|
26
|
+
this.proxyUrl = config.proxyUrl;
|
|
25
27
|
}
|
|
26
28
|
/** @internal */
|
|
27
29
|
async _request(method, endpoint, options = {}) {
|
|
28
|
-
|
|
30
|
+
// Build the target URL (always points to the API)
|
|
31
|
+
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
29
32
|
if (options.params) {
|
|
30
33
|
Object.entries(options.params).forEach(([key, value]) => {
|
|
31
34
|
if (value !== undefined && value !== null) {
|
|
32
|
-
|
|
35
|
+
targetUrl.searchParams.append(key, String(value));
|
|
33
36
|
}
|
|
34
37
|
});
|
|
35
38
|
}
|
|
39
|
+
// In proxy mode, requests go to the proxy with target URL in a header
|
|
40
|
+
const isProxyMode = !!this.proxyUrl;
|
|
41
|
+
const fetchUrl = isProxyMode ? this.proxyUrl : targetUrl.toString();
|
|
36
42
|
const headers = {
|
|
37
43
|
"Content-Type": "application/json",
|
|
38
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
39
44
|
};
|
|
45
|
+
if (isProxyMode) {
|
|
46
|
+
// Proxy mode: send target URL as header, no auth (proxy handles it)
|
|
47
|
+
headers["x-inf-target-url"] = targetUrl.toString();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Direct mode: include authorization header
|
|
51
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
52
|
+
}
|
|
40
53
|
const fetchOptions = {
|
|
41
54
|
method: method.toUpperCase(),
|
|
42
55
|
headers,
|
|
@@ -45,7 +58,7 @@ class Inference {
|
|
|
45
58
|
if (options.data) {
|
|
46
59
|
fetchOptions.body = JSON.stringify(options.data);
|
|
47
60
|
}
|
|
48
|
-
const response = await fetch(
|
|
61
|
+
const response = await fetch(fetchUrl, fetchOptions);
|
|
49
62
|
const responseText = await response.text();
|
|
50
63
|
// Try to parse as JSON
|
|
51
64
|
let data = null;
|
|
@@ -94,15 +107,27 @@ class Inference {
|
|
|
94
107
|
}
|
|
95
108
|
/** @internal */
|
|
96
109
|
_createEventSource(endpoint) {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
110
|
+
const targetUrl = new URL(`${this.baseUrl}${endpoint}`);
|
|
111
|
+
const isProxyMode = !!this.proxyUrl;
|
|
112
|
+
const fetchUrl = isProxyMode ? this.proxyUrl : targetUrl.toString();
|
|
113
|
+
return new eventsource_1.EventSource(fetchUrl, {
|
|
114
|
+
fetch: (input, init) => {
|
|
115
|
+
const headers = {
|
|
116
|
+
...init?.headers,
|
|
117
|
+
};
|
|
118
|
+
if (isProxyMode) {
|
|
119
|
+
// Proxy mode: send target URL as header
|
|
120
|
+
headers["x-inf-target-url"] = targetUrl.toString();
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Direct mode: include authorization header
|
|
124
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
125
|
+
}
|
|
126
|
+
return fetch(input, {
|
|
127
|
+
...init,
|
|
128
|
+
headers,
|
|
129
|
+
});
|
|
130
|
+
},
|
|
106
131
|
});
|
|
107
132
|
}
|
|
108
133
|
_stripTask(task) {
|
package/dist/client.test.js
CHANGED
|
@@ -14,9 +14,9 @@ describe('Inference', () => {
|
|
|
14
14
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
15
15
|
expect(client).toBeInstanceOf(client_1.Inference);
|
|
16
16
|
});
|
|
17
|
-
it('should throw error when apiKey is
|
|
18
|
-
expect(() => new client_1.Inference({ apiKey: '' })).toThrow('
|
|
19
|
-
expect(() => new client_1.Inference({})).toThrow('
|
|
17
|
+
it('should throw error when neither apiKey nor proxyUrl is provided', () => {
|
|
18
|
+
expect(() => new client_1.Inference({ apiKey: '' })).toThrow('Either apiKey or proxyUrl is required');
|
|
19
|
+
expect(() => new client_1.Inference({})).toThrow('Either apiKey or proxyUrl is required');
|
|
20
20
|
});
|
|
21
21
|
it('should use default baseUrl when not provided', () => {
|
|
22
22
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { Inference, inference, InferenceConfig, RunOptions, UploadFileOptions, Agent, AdHocAgentConfig, SendMessageOptions, } from './client';
|
|
2
|
-
export { AgentConfig, AdHocAgentOptions, TemplateAgentOptions, AgentOptions, } from './agent';
|
|
3
2
|
export { tool, appTool, agentTool, webhookTool, internalTools, string, number, integer, boolean, enumOf, object, array, optional } from './tool-builder';
|
|
4
3
|
export { StreamManager, PartialDataWrapper } from './stream';
|
|
5
4
|
export { InferenceError, RequirementsNotMetException } from './errors';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express.js proxy handler for Inference.sh API
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import express from "express";
|
|
7
|
+
* import * as inferenceProxy from "@inferencesh/sdk/proxy/express";
|
|
8
|
+
*
|
|
9
|
+
* const app = express();
|
|
10
|
+
* app.use(express.json());
|
|
11
|
+
* app.all(inferenceProxy.route, inferenceProxy.handler);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
import type { RequestHandler } from "express";
|
|
15
|
+
/**
|
|
16
|
+
* The default proxy route path.
|
|
17
|
+
*/
|
|
18
|
+
export declare const route = "/api/inference/proxy";
|
|
19
|
+
/**
|
|
20
|
+
* Express middleware handler for the Inference.sh proxy.
|
|
21
|
+
*
|
|
22
|
+
* Requires `express.json()` middleware to be applied before this handler.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import express from "express";
|
|
27
|
+
* import cors from "cors";
|
|
28
|
+
* import * as inferenceProxy from "@inferencesh/sdk/proxy/express";
|
|
29
|
+
*
|
|
30
|
+
* const app = express();
|
|
31
|
+
* app.use(express.json());
|
|
32
|
+
*
|
|
33
|
+
* // If clients are external, enable CORS
|
|
34
|
+
* app.all(inferenceProxy.route, cors(), inferenceProxy.handler);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare const handler: RequestHandler;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Express.js proxy handler for Inference.sh API
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import express from "express";
|
|
8
|
+
* import * as inferenceProxy from "@inferencesh/sdk/proxy/express";
|
|
9
|
+
*
|
|
10
|
+
* const app = express();
|
|
11
|
+
* app.use(express.json());
|
|
12
|
+
* app.all(inferenceProxy.route, inferenceProxy.handler);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.handler = exports.route = void 0;
|
|
17
|
+
const index_1 = require("./index");
|
|
18
|
+
/**
|
|
19
|
+
* The default proxy route path.
|
|
20
|
+
*/
|
|
21
|
+
exports.route = index_1.DEFAULT_PROXY_ROUTE;
|
|
22
|
+
/**
|
|
23
|
+
* Express middleware handler for the Inference.sh proxy.
|
|
24
|
+
*
|
|
25
|
+
* Requires `express.json()` middleware to be applied before this handler.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* import express from "express";
|
|
30
|
+
* import cors from "cors";
|
|
31
|
+
* import * as inferenceProxy from "@inferencesh/sdk/proxy/express";
|
|
32
|
+
*
|
|
33
|
+
* const app = express();
|
|
34
|
+
* app.use(express.json());
|
|
35
|
+
*
|
|
36
|
+
* // If clients are external, enable CORS
|
|
37
|
+
* app.all(inferenceProxy.route, cors(), inferenceProxy.handler);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
const handler = async (req, res, _next) => {
|
|
41
|
+
const responseHeaders = {};
|
|
42
|
+
return (0, index_1.handleRequest)({
|
|
43
|
+
id: "express",
|
|
44
|
+
method: req.method,
|
|
45
|
+
getRequestBody: async () => JSON.stringify(req.body),
|
|
46
|
+
getHeaders: () => req.headers,
|
|
47
|
+
getHeader: (name) => req.headers[name],
|
|
48
|
+
sendHeader: (name, value) => {
|
|
49
|
+
responseHeaders[name] = value;
|
|
50
|
+
res.setHeader(name, value);
|
|
51
|
+
},
|
|
52
|
+
respondWith: (status, data) => {
|
|
53
|
+
return res.status(status).json(data);
|
|
54
|
+
},
|
|
55
|
+
sendResponse: async (response) => {
|
|
56
|
+
// Copy status
|
|
57
|
+
res.status(response.status);
|
|
58
|
+
// Handle streaming responses
|
|
59
|
+
const contentType = response.headers.get("content-type");
|
|
60
|
+
if (contentType?.includes("text/event-stream") ||
|
|
61
|
+
contentType?.includes("application/octet-stream")) {
|
|
62
|
+
// Stream the response
|
|
63
|
+
if (response.body) {
|
|
64
|
+
const reader = response.body.getReader();
|
|
65
|
+
while (true) {
|
|
66
|
+
const { done, value } = await reader.read();
|
|
67
|
+
if (done)
|
|
68
|
+
break;
|
|
69
|
+
res.write(value);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
res.end();
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
// Handle JSON responses
|
|
76
|
+
if (contentType?.includes("application/json")) {
|
|
77
|
+
return res.json(await response.json());
|
|
78
|
+
}
|
|
79
|
+
// Handle text responses
|
|
80
|
+
return res.send(await response.text());
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
exports.handler = handler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./express.js";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono proxy handler for Inference.sh API
|
|
3
|
+
*
|
|
4
|
+
* Lightweight handler for Hono framework, ideal for edge/serverless deployments.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Hono } from "hono";
|
|
9
|
+
* import { createRouteHandler } from "@inferencesh/sdk/proxy/hono";
|
|
10
|
+
*
|
|
11
|
+
* const app = new Hono();
|
|
12
|
+
* const proxyHandler = createRouteHandler();
|
|
13
|
+
*
|
|
14
|
+
* app.all("/api/inference/proxy", proxyHandler);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
import type { Context } from "hono";
|
|
18
|
+
export interface HonoProxyOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Custom function to resolve the API key.
|
|
21
|
+
* Defaults to reading from INFERENCE_API_KEY environment variable.
|
|
22
|
+
*/
|
|
23
|
+
resolveApiKey?: () => Promise<string | undefined>;
|
|
24
|
+
}
|
|
25
|
+
type RouteHandler = (context: Context) => Promise<Response>;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a Hono route handler that proxies requests to the Inference.sh API.
|
|
28
|
+
*
|
|
29
|
+
* This is a drop-in handler for Hono applications that keeps API keys safe
|
|
30
|
+
* by running on your server.
|
|
31
|
+
*
|
|
32
|
+
* @param options - Proxy options
|
|
33
|
+
* @returns A Hono route handler function
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { Hono } from "hono";
|
|
38
|
+
* import { createRouteHandler } from "@inferencesh/sdk/proxy/hono";
|
|
39
|
+
*
|
|
40
|
+
* const app = new Hono();
|
|
41
|
+
* const proxyHandler = createRouteHandler();
|
|
42
|
+
*
|
|
43
|
+
* app.all("/api/inference/proxy", proxyHandler);
|
|
44
|
+
*
|
|
45
|
+
* export default app;
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example Custom API key resolver
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const proxyHandler = createRouteHandler({
|
|
51
|
+
* resolveApiKey: async () => {
|
|
52
|
+
* // Load from a secrets manager
|
|
53
|
+
* return await getSecretFromVault("INFERENCE_API_KEY");
|
|
54
|
+
* },
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function createRouteHandler({ resolveApiKey, }?: HonoProxyOptions): RouteHandler;
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hono proxy handler for Inference.sh API
|
|
4
|
+
*
|
|
5
|
+
* Lightweight handler for Hono framework, ideal for edge/serverless deployments.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Hono } from "hono";
|
|
10
|
+
* import { createRouteHandler } from "@inferencesh/sdk/proxy/hono";
|
|
11
|
+
*
|
|
12
|
+
* const app = new Hono();
|
|
13
|
+
* const proxyHandler = createRouteHandler();
|
|
14
|
+
*
|
|
15
|
+
* app.all("/api/inference/proxy", proxyHandler);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.createRouteHandler = createRouteHandler;
|
|
20
|
+
const index_1 = require("./index");
|
|
21
|
+
/**
|
|
22
|
+
* Creates a Hono route handler that proxies requests to the Inference.sh API.
|
|
23
|
+
*
|
|
24
|
+
* This is a drop-in handler for Hono applications that keeps API keys safe
|
|
25
|
+
* by running on your server.
|
|
26
|
+
*
|
|
27
|
+
* @param options - Proxy options
|
|
28
|
+
* @returns A Hono route handler function
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { Hono } from "hono";
|
|
33
|
+
* import { createRouteHandler } from "@inferencesh/sdk/proxy/hono";
|
|
34
|
+
*
|
|
35
|
+
* const app = new Hono();
|
|
36
|
+
* const proxyHandler = createRouteHandler();
|
|
37
|
+
*
|
|
38
|
+
* app.all("/api/inference/proxy", proxyHandler);
|
|
39
|
+
*
|
|
40
|
+
* export default app;
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example Custom API key resolver
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const proxyHandler = createRouteHandler({
|
|
46
|
+
* resolveApiKey: async () => {
|
|
47
|
+
* // Load from a secrets manager
|
|
48
|
+
* return await getSecretFromVault("INFERENCE_API_KEY");
|
|
49
|
+
* },
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function createRouteHandler({ resolveApiKey = index_1.resolveApiKeyFromEnv, } = {}) {
|
|
54
|
+
const routeHandler = async (context) => {
|
|
55
|
+
const responseHeaders = new Headers();
|
|
56
|
+
return (0, index_1.handleRequest)({
|
|
57
|
+
id: "hono",
|
|
58
|
+
method: context.req.method,
|
|
59
|
+
respondWith: (status, data) => {
|
|
60
|
+
return new Response(JSON.stringify(data), {
|
|
61
|
+
status,
|
|
62
|
+
headers: {
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
...Object.fromEntries(responseHeaders.entries()),
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
getHeaders: () => (0, index_1.fromHeaders)(context.req.raw.headers),
|
|
69
|
+
getHeader: (name) => context.req.header(name),
|
|
70
|
+
sendHeader: (name, value) => responseHeaders.set(name, value),
|
|
71
|
+
getRequestBody: async () => {
|
|
72
|
+
try {
|
|
73
|
+
return await context.req.text();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
sendResponse: index_1.responsePassthrough,
|
|
80
|
+
resolveApiKey,
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
return routeHandler;
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./hono.js";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @inferencesh/sdk/proxy - Server-side proxy for Inference.sh API
|
|
3
|
+
*
|
|
4
|
+
* Protects API keys by proxying requests from frontend apps through your server.
|
|
5
|
+
* Supports Next.js (App & Page Router), Express, Hono, Remix, and SvelteKit.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TARGET_URL_HEADER = "x-inf-target-url";
|
|
8
|
+
export declare const DEFAULT_PROXY_ROUTE = "/api/inference/proxy";
|
|
9
|
+
export type HeaderValue = string | string[] | undefined | null;
|
|
10
|
+
/**
|
|
11
|
+
* The proxy behavior interface - a subset of request/response objects
|
|
12
|
+
* that abstracts framework-specific APIs.
|
|
13
|
+
*/
|
|
14
|
+
export interface ProxyBehavior<ResponseType> {
|
|
15
|
+
/** Framework identifier for logging/debugging */
|
|
16
|
+
id: string;
|
|
17
|
+
/** HTTP method */
|
|
18
|
+
method: string;
|
|
19
|
+
/** Return an error response */
|
|
20
|
+
respondWith(status: number, data: string | object): ResponseType;
|
|
21
|
+
/** Pass through a fetch Response */
|
|
22
|
+
sendResponse(response: Response): Promise<ResponseType>;
|
|
23
|
+
/** Get all headers as a record */
|
|
24
|
+
getHeaders(): Record<string, HeaderValue>;
|
|
25
|
+
/** Get a single header value */
|
|
26
|
+
getHeader(name: string): HeaderValue;
|
|
27
|
+
/** Set a response header */
|
|
28
|
+
sendHeader(name: string, value: string): void;
|
|
29
|
+
/** Get the request body as a string */
|
|
30
|
+
getRequestBody(): Promise<string | undefined>;
|
|
31
|
+
/** Optional custom API key resolver */
|
|
32
|
+
resolveApiKey?: () => Promise<string | undefined>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Core proxy request handler.
|
|
36
|
+
*
|
|
37
|
+
* Proxies requests to the Inference.sh API with server-side credential injection.
|
|
38
|
+
* This handler is framework-agnostic and works via the ProxyBehavior interface.
|
|
39
|
+
*
|
|
40
|
+
* @param behavior - Framework-specific request/response handling
|
|
41
|
+
* @returns Promise that resolves when the request is handled
|
|
42
|
+
*/
|
|
43
|
+
export declare function handleRequest<ResponseType>(behavior: ProxyBehavior<ResponseType>): Promise<ResponseType>;
|
|
44
|
+
/**
|
|
45
|
+
* Convert a Headers object to a plain record.
|
|
46
|
+
*/
|
|
47
|
+
export declare function fromHeaders(headers: Headers): Record<string, string | string[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Simple passthrough for Response objects (used in app router style handlers).
|
|
50
|
+
*/
|
|
51
|
+
export declare const responsePassthrough: (res: Response) => Promise<Response>;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve API key from environment (exposed for custom handlers).
|
|
54
|
+
*/
|
|
55
|
+
export declare const resolveApiKeyFromEnv: () => Promise<string | undefined>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @inferencesh/sdk/proxy - Server-side proxy for Inference.sh API
|
|
4
|
+
*
|
|
5
|
+
* Protects API keys by proxying requests from frontend apps through your server.
|
|
6
|
+
* Supports Next.js (App & Page Router), Express, Hono, Remix, and SvelteKit.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.resolveApiKeyFromEnv = exports.responsePassthrough = exports.DEFAULT_PROXY_ROUTE = exports.TARGET_URL_HEADER = void 0;
|
|
10
|
+
exports.handleRequest = handleRequest;
|
|
11
|
+
exports.fromHeaders = fromHeaders;
|
|
12
|
+
exports.TARGET_URL_HEADER = "x-inf-target-url";
|
|
13
|
+
exports.DEFAULT_PROXY_ROUTE = "/api/inference/proxy";
|
|
14
|
+
const INFERENCE_API_KEY = process.env.INFERENCE_API_KEY;
|
|
15
|
+
// Only allow requests to inference.sh domains
|
|
16
|
+
const INFERENCE_URL_REGEX = /(\.|^)inference\.sh$/;
|
|
17
|
+
/**
|
|
18
|
+
* Utility to get a header value as string from potentially array value.
|
|
19
|
+
*/
|
|
20
|
+
function singleHeaderValue(value) {
|
|
21
|
+
if (!value)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (Array.isArray(value))
|
|
24
|
+
return value[0];
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Get the API key from environment variables.
|
|
29
|
+
*/
|
|
30
|
+
function getApiKey() {
|
|
31
|
+
return INFERENCE_API_KEY;
|
|
32
|
+
}
|
|
33
|
+
// Headers to exclude from response passthrough
|
|
34
|
+
const EXCLUDED_HEADERS = ["content-length", "content-encoding"];
|
|
35
|
+
/**
|
|
36
|
+
* Core proxy request handler.
|
|
37
|
+
*
|
|
38
|
+
* Proxies requests to the Inference.sh API with server-side credential injection.
|
|
39
|
+
* This handler is framework-agnostic and works via the ProxyBehavior interface.
|
|
40
|
+
*
|
|
41
|
+
* @param behavior - Framework-specific request/response handling
|
|
42
|
+
* @returns Promise that resolves when the request is handled
|
|
43
|
+
*/
|
|
44
|
+
async function handleRequest(behavior) {
|
|
45
|
+
// 1. Get and validate target URL
|
|
46
|
+
const targetUrl = singleHeaderValue(behavior.getHeader(exports.TARGET_URL_HEADER));
|
|
47
|
+
if (!targetUrl) {
|
|
48
|
+
return behavior.respondWith(400, {
|
|
49
|
+
error: `Missing the ${exports.TARGET_URL_HEADER} header`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// 2. Validate target is an inference.sh domain
|
|
53
|
+
let urlHost;
|
|
54
|
+
try {
|
|
55
|
+
urlHost = new URL(targetUrl).host;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return behavior.respondWith(400, {
|
|
59
|
+
error: `Invalid ${exports.TARGET_URL_HEADER} header: not a valid URL`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (!INFERENCE_URL_REGEX.test(urlHost)) {
|
|
63
|
+
return behavior.respondWith(412, {
|
|
64
|
+
error: `Invalid ${exports.TARGET_URL_HEADER} header: must be an inference.sh domain`,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// 3. Get API key
|
|
68
|
+
const apiKey = behavior.resolveApiKey
|
|
69
|
+
? await behavior.resolveApiKey()
|
|
70
|
+
: getApiKey();
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
return behavior.respondWith(401, {
|
|
73
|
+
error: "Missing INFERENCE_API_KEY environment variable",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// 4. Build forwarded headers (x-inf-* prefixed)
|
|
77
|
+
const forwardedHeaders = {};
|
|
78
|
+
const allHeaders = behavior.getHeaders();
|
|
79
|
+
for (const key of Object.keys(allHeaders)) {
|
|
80
|
+
if (key.toLowerCase().startsWith("x-inf-")) {
|
|
81
|
+
const value = singleHeaderValue(allHeaders[key]);
|
|
82
|
+
if (value) {
|
|
83
|
+
forwardedHeaders[key.toLowerCase()] = value;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// 5. Forward content-type if present
|
|
88
|
+
const contentType = singleHeaderValue(behavior.getHeader("content-type"));
|
|
89
|
+
// 6. Build proxy user agent
|
|
90
|
+
const proxyUserAgent = `@inferencesh/sdk-proxy/${behavior.id}`;
|
|
91
|
+
const userAgent = singleHeaderValue(behavior.getHeader("user-agent"));
|
|
92
|
+
// 7. Make the proxied request
|
|
93
|
+
const res = await fetch(targetUrl, {
|
|
94
|
+
method: behavior.method,
|
|
95
|
+
headers: {
|
|
96
|
+
...forwardedHeaders,
|
|
97
|
+
authorization: singleHeaderValue(behavior.getHeader("authorization")) ??
|
|
98
|
+
`Bearer ${apiKey}`,
|
|
99
|
+
accept: "application/json",
|
|
100
|
+
"content-type": contentType || "application/json",
|
|
101
|
+
"user-agent": userAgent || proxyUserAgent,
|
|
102
|
+
"x-inf-client-proxy": proxyUserAgent,
|
|
103
|
+
},
|
|
104
|
+
body: behavior.method?.toUpperCase() === "GET"
|
|
105
|
+
? undefined
|
|
106
|
+
: await behavior.getRequestBody(),
|
|
107
|
+
});
|
|
108
|
+
// 8. Copy response headers (excluding certain ones)
|
|
109
|
+
res.headers.forEach((value, key) => {
|
|
110
|
+
if (!EXCLUDED_HEADERS.includes(key.toLowerCase())) {
|
|
111
|
+
behavior.sendHeader(key, value);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// 9. Return the response
|
|
115
|
+
return behavior.sendResponse(res);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Convert a Headers object to a plain record.
|
|
119
|
+
*/
|
|
120
|
+
function fromHeaders(headers) {
|
|
121
|
+
const result = {};
|
|
122
|
+
headers.forEach((value, key) => {
|
|
123
|
+
result[key] = value;
|
|
124
|
+
});
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Simple passthrough for Response objects (used in app router style handlers).
|
|
129
|
+
*/
|
|
130
|
+
const responsePassthrough = (res) => Promise.resolve(res);
|
|
131
|
+
exports.responsePassthrough = responsePassthrough;
|
|
132
|
+
/**
|
|
133
|
+
* Resolve API key from environment (exposed for custom handlers).
|
|
134
|
+
*/
|
|
135
|
+
const resolveApiKeyFromEnv = () => Promise.resolve(getApiKey());
|
|
136
|
+
exports.resolveApiKeyFromEnv = resolveApiKeyFromEnv;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|