@inferencesh/sdk 0.21.0 → 0.22.0
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/CHANGELOG.md +47 -0
- package/dist/agent/api.d.ts +35 -1
- package/dist/agent/api.js +35 -1
- package/dist/agent/reducer.js +23 -7
- package/dist/agent/types.d.ts +29 -4
- package/dist/api/agents.d.ts +9 -3
- package/dist/api/agents.js +87 -63
- package/dist/api/api-keys.d.ts +2 -5
- package/dist/api/apps.d.ts +9 -2
- package/dist/api/apps.js +9 -1
- package/dist/api/chats.d.ts +13 -3
- package/dist/api/chats.js +13 -2
- package/dist/api/engines.d.ts +4 -2
- package/dist/api/engines.js +3 -2
- package/dist/api/flow-runs.d.ts +7 -2
- package/dist/api/flow-runs.js +7 -2
- package/dist/api/flows.d.ts +13 -2
- package/dist/api/flows.js +15 -1
- package/dist/api/knowledge.d.ts +7 -4
- package/dist/api/knowledge.js +6 -4
- package/dist/api/mcp-servers.d.ts +2 -1
- package/dist/api/projects.d.ts +5 -3
- package/dist/api/projects.js +3 -2
- package/dist/api/secrets.d.ts +2 -2
- package/dist/api/tasks.js +38 -56
- package/dist/api/teams.d.ts +4 -2
- package/dist/api/teams.js +3 -2
- package/dist/api/write-bodies.d.ts +110 -0
- package/dist/api/write-bodies.js +1 -0
- package/dist/http/client.d.ts +1 -1
- package/dist/http/client.js +2 -1
- package/dist/http/loopback.d.ts +8 -0
- package/dist/http/loopback.js +18 -0
- package/dist/http/stream-until-terminal.d.ts +55 -0
- package/dist/http/stream-until-terminal.js +88 -0
- package/dist/http/stream.d.ts +1 -0
- package/dist/http/stream.js +7 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/proxy/endpoints.json +156 -0
- package/dist/proxy/express.d.ts +5 -6
- package/dist/proxy/express.js +18 -2
- package/dist/proxy/hono.d.ts +5 -3
- package/dist/proxy/hono.js +4 -3
- package/dist/proxy/index.d.ts +165 -6
- package/dist/proxy/index.js +409 -25
- package/dist/proxy/nextjs.d.ts +29 -17
- package/dist/proxy/nextjs.js +72 -62
- package/dist/proxy/remix.d.ts +5 -3
- package/dist/proxy/remix.js +4 -3
- package/dist/proxy/svelte.d.ts +5 -4
- package/dist/proxy/svelte.js +4 -4
- package/dist/types.d.ts +423 -6
- package/dist/types.js +111 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +7 -0
- package/package.json +2 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loopback hosts, where plain http never leaves the machine (local dev):
|
|
3
|
+
* `localhost`, any `*.localhost`, `[::1]` and 127.0.0.0/8. This is the one
|
|
4
|
+
* copy of the rule; the proxy, the app and common-js all ask it.
|
|
5
|
+
*/
|
|
6
|
+
export function isLoopbackHost(hostname) {
|
|
7
|
+
const h = hostname.toLowerCase();
|
|
8
|
+
return h === 'localhost'
|
|
9
|
+
|| h.endsWith('.localhost')
|
|
10
|
+
|| h === '[::1]'
|
|
11
|
+
|| /^127(\.\d{1,3}){3}$/.test(h);
|
|
12
|
+
}
|
|
13
|
+
/** Whether `url` is https, or plain http to a loopback host. */
|
|
14
|
+
export function isHttpsOrLoopback(url) {
|
|
15
|
+
if (url.protocol === 'https:')
|
|
16
|
+
return true;
|
|
17
|
+
return url.protocol === 'http:' && isLoopbackHost(url.hostname);
|
|
18
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Follow a resource's NDJSON stream until the resource reaches a terminal
|
|
3
|
+
* state.
|
|
4
|
+
*
|
|
5
|
+
* StreamableManager never reconnects, and a stream can close cleanly before
|
|
6
|
+
* the resource is done (load balancer idle timeout, API deploy). A wait built
|
|
7
|
+
* on it must not hang then. This helper owns that contract for every
|
|
8
|
+
* "stream until done" wait: when the stream ends early it fetches the
|
|
9
|
+
* resource once (`reconcile`) and settles with what that shows, or rejects
|
|
10
|
+
* when the resource is still not terminal. sdk-py's `wait_for_completion`
|
|
11
|
+
* does the same final GET.
|
|
12
|
+
*/
|
|
13
|
+
import { type StreamableManagerOptions, type StreamRequest } from './streamable';
|
|
14
|
+
/** Settles a stream-until-terminal wait. Calls after the first are ignored. */
|
|
15
|
+
export interface TerminalSettler<R> {
|
|
16
|
+
resolve(value: R): void;
|
|
17
|
+
reject(error: Error): void;
|
|
18
|
+
}
|
|
19
|
+
/** The stream to follow and how to tell when its resource is done. */
|
|
20
|
+
export type StreamUntilTerminalSpec<T> = Pick<StreamableManagerOptions<T>, 'body' | 'onData' | 'onPartialData' | 'onStart' | 'onDelta'> & {
|
|
21
|
+
/** Sends the stream request, e.g. `(init) => http.fetch(endpoint, init)`. */
|
|
22
|
+
request: StreamRequest;
|
|
23
|
+
/** Typed event listeners ({"event": name, "data": ...} messages). */
|
|
24
|
+
events?: Record<string, (data: any, fields?: string[]) => void>;
|
|
25
|
+
/**
|
|
26
|
+
* Called once when the stream ends cleanly before the wait settled. Fetch
|
|
27
|
+
* the resource and settle if it is terminal; returning without settling
|
|
28
|
+
* rejects the wait with `closedMessage`.
|
|
29
|
+
*/
|
|
30
|
+
reconcile: () => Promise<void>;
|
|
31
|
+
/** Rejection message when the stream closed and the resource is still not terminal. */
|
|
32
|
+
closedMessage: string;
|
|
33
|
+
/**
|
|
34
|
+
* Called when the wait ends because `stop()` was called. Without it `done`
|
|
35
|
+
* stays pending.
|
|
36
|
+
*/
|
|
37
|
+
onStopped?: () => void;
|
|
38
|
+
/**
|
|
39
|
+
* Keep the stream open after the wait settled so its listeners go on
|
|
40
|
+
* seeing updates (default false: settling stops the stream).
|
|
41
|
+
*/
|
|
42
|
+
keepOpen?: boolean;
|
|
43
|
+
};
|
|
44
|
+
export interface StreamUntilTerminal<R> {
|
|
45
|
+
/** Settles when the resource is terminal, the stream fails, or it closed early and the resource is not terminal. */
|
|
46
|
+
done: Promise<R>;
|
|
47
|
+
/** Ends the stream on purpose; see `onStopped`. */
|
|
48
|
+
stop(): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `build` receives the settler and returns the stream spec; its handlers call
|
|
52
|
+
* `settle.resolve`/`settle.reject` once the resource is terminal. Settling
|
|
53
|
+
* stops the stream unless the spec says `keepOpen`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function streamUntilTerminal<T, R>(build: (settle: TerminalSettler<R>) => StreamUntilTerminalSpec<T>): StreamUntilTerminal<R>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Follow a resource's NDJSON stream until the resource reaches a terminal
|
|
3
|
+
* state.
|
|
4
|
+
*
|
|
5
|
+
* StreamableManager never reconnects, and a stream can close cleanly before
|
|
6
|
+
* the resource is done (load balancer idle timeout, API deploy). A wait built
|
|
7
|
+
* on it must not hang then. This helper owns that contract for every
|
|
8
|
+
* "stream until done" wait: when the stream ends early it fetches the
|
|
9
|
+
* resource once (`reconcile`) and settles with what that shows, or rejects
|
|
10
|
+
* when the resource is still not terminal. sdk-py's `wait_for_completion`
|
|
11
|
+
* does the same final GET.
|
|
12
|
+
*/
|
|
13
|
+
import { StreamableManager } from './streamable';
|
|
14
|
+
/**
|
|
15
|
+
* `build` receives the settler and returns the stream spec; its handlers call
|
|
16
|
+
* `settle.resolve`/`settle.reject` once the resource is terminal. Settling
|
|
17
|
+
* stops the stream unless the spec says `keepOpen`.
|
|
18
|
+
*/
|
|
19
|
+
export function streamUntilTerminal(build) {
|
|
20
|
+
let settled = false;
|
|
21
|
+
let stopped = false;
|
|
22
|
+
let manager;
|
|
23
|
+
const done = new Promise((resolve, reject) => {
|
|
24
|
+
const settle = {
|
|
25
|
+
resolve: (value) => {
|
|
26
|
+
if (settled)
|
|
27
|
+
return;
|
|
28
|
+
settled = true;
|
|
29
|
+
if (!keepOpen)
|
|
30
|
+
manager?.stop();
|
|
31
|
+
resolve(value);
|
|
32
|
+
},
|
|
33
|
+
reject: (error) => {
|
|
34
|
+
if (settled)
|
|
35
|
+
return;
|
|
36
|
+
settled = true;
|
|
37
|
+
if (!keepOpen)
|
|
38
|
+
manager?.stop();
|
|
39
|
+
reject(error);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const { events, reconcile, closedMessage, onStopped, keepOpen, ...managerOptions } = build(settle);
|
|
43
|
+
let streamError = null;
|
|
44
|
+
manager = new StreamableManager({
|
|
45
|
+
...managerOptions,
|
|
46
|
+
onError: (error) => {
|
|
47
|
+
streamError = error;
|
|
48
|
+
},
|
|
49
|
+
onEnd: () => {
|
|
50
|
+
if (settled)
|
|
51
|
+
return;
|
|
52
|
+
if (stopped) {
|
|
53
|
+
onStopped?.();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (streamError) {
|
|
57
|
+
settle.reject(streamError);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Closed cleanly before the resource was terminal: ask the API once.
|
|
61
|
+
const closed = (cause) => {
|
|
62
|
+
if (stopped && !settled) {
|
|
63
|
+
onStopped?.();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const error = new Error(closedMessage);
|
|
67
|
+
if (cause !== undefined)
|
|
68
|
+
error.cause = cause;
|
|
69
|
+
settle.reject(error);
|
|
70
|
+
};
|
|
71
|
+
reconcile().then(() => closed(), closed);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
for (const [name, listener] of Object.entries(events ?? {})) {
|
|
75
|
+
manager.addEventListener(name, listener);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
manager.start();
|
|
79
|
+
return {
|
|
80
|
+
done,
|
|
81
|
+
stop: () => {
|
|
82
|
+
if (stopped)
|
|
83
|
+
return;
|
|
84
|
+
stopped = true;
|
|
85
|
+
manager.stop();
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
package/dist/http/stream.d.ts
CHANGED
package/dist/http/stream.js
CHANGED
|
@@ -17,6 +17,7 @@ export class StreamManager {
|
|
|
17
17
|
this.initialConnectionAttempts = 0;
|
|
18
18
|
this.consecutiveErrors = 0;
|
|
19
19
|
this.isConnected = false;
|
|
20
|
+
this.hasEverConnected = false;
|
|
20
21
|
this.isStopped = false;
|
|
21
22
|
this.eventListeners = new Map();
|
|
22
23
|
this.options = {
|
|
@@ -53,6 +54,8 @@ export class StreamManager {
|
|
|
53
54
|
source.addEventListener(eventName, (e) => {
|
|
54
55
|
if (this.isStopped)
|
|
55
56
|
return;
|
|
57
|
+
// A delivered event proves the connection works, same as onmessage.
|
|
58
|
+
this.consecutiveErrors = 0;
|
|
56
59
|
try {
|
|
57
60
|
const parsed = JSON.parse(e.data);
|
|
58
61
|
const listeners = this.eventListeners.get(eventName);
|
|
@@ -114,15 +117,15 @@ export class StreamManager {
|
|
|
114
117
|
if (!this.options.autoReconnect || this.isStopped)
|
|
115
118
|
return false;
|
|
116
119
|
const maxReconnects = this.options.maxReconnects ?? 5;
|
|
117
|
-
if (!this.
|
|
120
|
+
if (!this.hasEverConnected && this.initialConnectionAttempts >= maxReconnects) {
|
|
118
121
|
return false;
|
|
119
122
|
}
|
|
120
|
-
if (this.
|
|
123
|
+
if (this.hasEverConnected && this.consecutiveErrors >= maxReconnects) {
|
|
121
124
|
return false;
|
|
122
125
|
}
|
|
123
126
|
this.reconnectTimeout = setTimeout(() => {
|
|
124
127
|
if (!this.isStopped) {
|
|
125
|
-
if (!this.
|
|
128
|
+
if (!this.hasEverConnected) {
|
|
126
129
|
this.initialConnectionAttempts++;
|
|
127
130
|
}
|
|
128
131
|
this.consecutiveErrors++;
|
|
@@ -142,6 +145,7 @@ export class StreamManager {
|
|
|
142
145
|
return;
|
|
143
146
|
this.eventSource = source;
|
|
144
147
|
this.isConnected = true;
|
|
148
|
+
this.hasEverConnected = true;
|
|
145
149
|
this.options.onStart?.();
|
|
146
150
|
// Set up typed event listeners (for events with `event: eventName` header)
|
|
147
151
|
this.setupAllEventListeners(source);
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Response } from './http/response';
|
|
|
4
4
|
export { StreamManager, type StreamManagerOptions, type PartialDataWrapper } from './http/stream';
|
|
5
5
|
export { StreamableManager, type StreamableManagerOptions, type StreamableSource, type StreamRequest, type StreamRequestInit, type StreamableMessage, streamable, streamableRaw } from './http/streamable';
|
|
6
6
|
export { PollManager, type PollManagerOptions } from './http/poll';
|
|
7
|
+
export { isLoopbackHost, isHttpsOrLoopback } from './http/loopback';
|
|
7
8
|
export { InferenceError, RequirementsNotMetException, SessionError, SessionNotFoundError, SessionExpiredError, SessionEndedError, WorkerLostError, isRequirementsNotMetException, isInferenceError, isSessionError, } from './http/errors';
|
|
8
9
|
export { TasksAPI, type RunOptions, type WatchOptions, type TaskWatch } from './api/tasks';
|
|
9
10
|
export { SocketsAPI, type SocketTarget, type OpenSocketOptions } from './api/sockets';
|
|
@@ -17,6 +18,7 @@ export { FlowRunsAPI } from './api/flow-runs';
|
|
|
17
18
|
export { EnginesAPI } from './api/engines';
|
|
18
19
|
export { KnowledgeAPI, SkillsAPI } from './api/knowledge';
|
|
19
20
|
export { ArtifactsAPI } from './api/artifacts';
|
|
21
|
+
export type { AgentUpdateBody, AppPatchBody, AppUpdateBody, ChatUpdateBody, EngineUpdateBody, FlowUpdateBody, FlowPatchBody, FlowViewportBody, ProjectWriteBody, KnowledgeUpdateBody, TeamUpdateBody, MCPServerUpdateBody, } from './api/write-bodies';
|
|
20
22
|
export { TeamsAPI } from './api/teams';
|
|
21
23
|
export { SecretsAPI } from './api/secrets';
|
|
22
24
|
export { ApiKeysAPI } from './api/api-keys';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { HttpClient, createHttpClient } from './http/client';
|
|
|
3
3
|
export { StreamManager } from './http/stream';
|
|
4
4
|
export { StreamableManager, streamable, streamableRaw } from './http/streamable';
|
|
5
5
|
export { PollManager } from './http/poll';
|
|
6
|
+
export { isLoopbackHost, isHttpsOrLoopback } from './http/loopback';
|
|
6
7
|
export { InferenceError, RequirementsNotMetException, SessionError, SessionNotFoundError, SessionExpiredError, SessionEndedError, WorkerLostError,
|
|
7
8
|
// Type guards (use these instead of instanceof for reliability)
|
|
8
9
|
isRequirementsNotMetException, isInferenceError, isSessionError, } from './http/errors';
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Generated by `make proxy-endpoints` from the route table (internal/api/proxy_endpoints_test.go). Do not edit.",
|
|
3
|
+
"preset": "run-only",
|
|
4
|
+
"endpoints": [
|
|
5
|
+
{
|
|
6
|
+
"method": "POST",
|
|
7
|
+
"path": "/apps/run",
|
|
8
|
+
"purpose": "run an app",
|
|
9
|
+
"scopes": [
|
|
10
|
+
"apps:execute",
|
|
11
|
+
"apps:read",
|
|
12
|
+
"conversations:read"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"method": "POST",
|
|
17
|
+
"path": "/files",
|
|
18
|
+
"purpose": "upload a file input of a run or message",
|
|
19
|
+
"scopes": [
|
|
20
|
+
"files:write"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"method": "GET",
|
|
25
|
+
"path": "/tasks/{id}",
|
|
26
|
+
"purpose": "read a task",
|
|
27
|
+
"scopes": [
|
|
28
|
+
"apps:read"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"method": "GET",
|
|
33
|
+
"path": "/tasks/{id}/status",
|
|
34
|
+
"purpose": "poll a task",
|
|
35
|
+
"scopes": [
|
|
36
|
+
"apps:read"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"method": "GET",
|
|
41
|
+
"path": "/tasks/{id}/stream",
|
|
42
|
+
"purpose": "stream a task",
|
|
43
|
+
"scopes": [
|
|
44
|
+
"apps:read",
|
|
45
|
+
"conversations:read",
|
|
46
|
+
"flows:read"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"method": "POST",
|
|
51
|
+
"path": "/tasks/{id}/cancel",
|
|
52
|
+
"purpose": "cancel a task",
|
|
53
|
+
"scopes": [
|
|
54
|
+
"apps:execute"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"method": "POST",
|
|
59
|
+
"path": "/agents/run",
|
|
60
|
+
"purpose": "send a message to an agent",
|
|
61
|
+
"scopes": [
|
|
62
|
+
"agents:execute",
|
|
63
|
+
"conversations:read"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"method": "POST",
|
|
68
|
+
"path": "/chats",
|
|
69
|
+
"purpose": "start a chat with an agent",
|
|
70
|
+
"scopes": [
|
|
71
|
+
"conversations:write"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"method": "POST",
|
|
76
|
+
"path": "/chats/{id}/messages",
|
|
77
|
+
"purpose": "send a message in a chat",
|
|
78
|
+
"scopes": [
|
|
79
|
+
"agents:execute"
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"method": "POST",
|
|
84
|
+
"path": "/chats/{id}/agent",
|
|
85
|
+
"purpose": "hand a chat to another agent",
|
|
86
|
+
"scopes": [
|
|
87
|
+
"conversations:write"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"method": "GET",
|
|
92
|
+
"path": "/agents/{namespace}/{name}",
|
|
93
|
+
"purpose": "read an agent's info",
|
|
94
|
+
"scopes": [
|
|
95
|
+
"agents:read"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"method": "GET",
|
|
100
|
+
"path": "/chats/{id}",
|
|
101
|
+
"purpose": "read a chat",
|
|
102
|
+
"scopes": [
|
|
103
|
+
"conversations:read"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"method": "GET",
|
|
108
|
+
"path": "/chats/{id}/status",
|
|
109
|
+
"purpose": "poll a chat",
|
|
110
|
+
"scopes": [
|
|
111
|
+
"conversations:read"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"method": "GET",
|
|
116
|
+
"path": "/chats/{id}/messages",
|
|
117
|
+
"purpose": "read a chat's messages",
|
|
118
|
+
"scopes": [
|
|
119
|
+
"conversations:read"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"method": "GET",
|
|
124
|
+
"path": "/chats/{id}/stream",
|
|
125
|
+
"purpose": "stream a chat",
|
|
126
|
+
"scopes": [
|
|
127
|
+
"conversations:read"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"method": "POST",
|
|
132
|
+
"path": "/chats/{id}/stop",
|
|
133
|
+
"purpose": "stop a chat",
|
|
134
|
+
"scopes": [
|
|
135
|
+
"conversations:write"
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"method": "POST",
|
|
140
|
+
"path": "/chats/messages/{messageId}/cancel",
|
|
141
|
+
"purpose": "cancel a message",
|
|
142
|
+
"scopes": [
|
|
143
|
+
"conversations:read",
|
|
144
|
+
"conversations:write"
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"method": "POST",
|
|
149
|
+
"path": "/tools/{toolId}",
|
|
150
|
+
"purpose": "answer a client tool call",
|
|
151
|
+
"scopes": [
|
|
152
|
+
"conversations:write"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
package/dist/proxy/express.d.ts
CHANGED
|
@@ -8,18 +8,17 @@
|
|
|
8
8
|
*
|
|
9
9
|
* const app = express();
|
|
10
10
|
* app.use(express.json());
|
|
11
|
-
* app.all(PROXY_ROUTE, createHandler());
|
|
11
|
+
* app.all(PROXY_ROUTE, createHandler({ allowedEndpoints: ["my-team/*"] }));
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
|
-
import type { RequestHandler } from "express";
|
|
14
|
+
import type { Request, RequestHandler } from "express";
|
|
15
|
+
import { type ProxyOptions } from "./index";
|
|
15
16
|
/** Default proxy route path */
|
|
16
17
|
export declare const PROXY_ROUTE = "/api/inference/proxy";
|
|
17
18
|
/** @deprecated Use PROXY_ROUTE */
|
|
18
19
|
export declare const route = "/api/inference/proxy";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
apiKey?: string;
|
|
22
|
-
}
|
|
20
|
+
/** Proxy options; `isAuthenticated` receives the Express request. */
|
|
21
|
+
export type ExpressProxyOptions = ProxyOptions<Request>;
|
|
23
22
|
/**
|
|
24
23
|
* Creates an Express middleware handler for the Inference.sh proxy.
|
|
25
24
|
*
|
package/dist/proxy/express.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* const app = express();
|
|
10
10
|
* app.use(express.json());
|
|
11
|
-
* app.all(PROXY_ROUTE, createHandler());
|
|
11
|
+
* app.all(PROXY_ROUTE, createHandler({ allowedEndpoints: ["my-team/*"] }));
|
|
12
12
|
* ```
|
|
13
13
|
*/
|
|
14
14
|
import { PROXY_PATH, processProxyRequest, } from "./index";
|
|
@@ -23,8 +23,19 @@ export const route = PROXY_ROUTE;
|
|
|
23
23
|
*/
|
|
24
24
|
export function createHandler(options) {
|
|
25
25
|
return async (req, res, _next) => {
|
|
26
|
+
// The client hung up before the response finished: stop the upstream
|
|
27
|
+
// request too. Chat and task streams never end on their own, so
|
|
28
|
+
// without this the proxy keeps reading them for nobody and the open
|
|
29
|
+
// upstream connection keeps the server process alive.
|
|
30
|
+
const upstream = new AbortController();
|
|
31
|
+
res.on("close", () => {
|
|
32
|
+
if (!res.writableFinished)
|
|
33
|
+
upstream.abort();
|
|
34
|
+
});
|
|
26
35
|
return processProxyRequest({
|
|
27
36
|
framework: "express",
|
|
37
|
+
signal: upstream.signal,
|
|
38
|
+
request: req,
|
|
28
39
|
method: req.method,
|
|
29
40
|
body: async () => JSON.stringify(req.body),
|
|
30
41
|
headers: () => req.headers,
|
|
@@ -61,7 +72,12 @@ export function createHandler(options) {
|
|
|
61
72
|
// Handle text responses
|
|
62
73
|
return res.send(await response.text());
|
|
63
74
|
},
|
|
64
|
-
}, options)
|
|
75
|
+
}, options).catch((error) => {
|
|
76
|
+
// Aborted because the client left; there is nobody to answer.
|
|
77
|
+
if (upstream.signal.aborted)
|
|
78
|
+
return res;
|
|
79
|
+
throw error;
|
|
80
|
+
});
|
|
65
81
|
};
|
|
66
82
|
}
|
|
67
83
|
/** @deprecated Use createHandler() */
|
package/dist/proxy/hono.d.ts
CHANGED
|
@@ -9,11 +9,13 @@
|
|
|
9
9
|
* import { createHandler } from "@inferencesh/sdk/proxy/hono";
|
|
10
10
|
*
|
|
11
11
|
* const app = new Hono();
|
|
12
|
-
* app.all("/api/inference/proxy", createHandler());
|
|
12
|
+
* app.all("/api/inference/proxy", createHandler({ allowedEndpoints: ["my-team/*"] }));
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
import type { Context } from "hono";
|
|
16
|
-
|
|
16
|
+
import { type ProxyOptions } from "./index";
|
|
17
|
+
/** Proxy options; `isAuthenticated` receives the Context. */
|
|
18
|
+
export interface HonoProxyOptions extends ProxyOptions<Context> {
|
|
17
19
|
/** Custom function to resolve the API key */
|
|
18
20
|
resolveApiKey?: () => Promise<string | undefined>;
|
|
19
21
|
}
|
|
@@ -21,7 +23,7 @@ type HonoHandler = (context: Context) => Promise<Response>;
|
|
|
21
23
|
/**
|
|
22
24
|
* Creates a Hono route handler for the Inference.sh proxy.
|
|
23
25
|
*/
|
|
24
|
-
export declare function createHandler({ resolveApiKey, }?: HonoProxyOptions): HonoHandler;
|
|
26
|
+
export declare function createHandler({ resolveApiKey, ...options }?: HonoProxyOptions): HonoHandler;
|
|
25
27
|
/** @deprecated Use createHandler */
|
|
26
28
|
export declare const createRouteHandler: typeof createHandler;
|
|
27
29
|
export {};
|
package/dist/proxy/hono.js
CHANGED
|
@@ -9,19 +9,20 @@
|
|
|
9
9
|
* import { createHandler } from "@inferencesh/sdk/proxy/hono";
|
|
10
10
|
*
|
|
11
11
|
* const app = new Hono();
|
|
12
|
-
* app.all("/api/inference/proxy", createHandler());
|
|
12
|
+
* app.all("/api/inference/proxy", createHandler({ allowedEndpoints: ["my-team/*"] }));
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
import { processProxyRequest, getEnvApiKey, passthrough, headersToRecord, } from "./index";
|
|
16
16
|
/**
|
|
17
17
|
* Creates a Hono route handler for the Inference.sh proxy.
|
|
18
18
|
*/
|
|
19
|
-
export function createHandler({ resolveApiKey = getEnvApiKey, } = {}) {
|
|
19
|
+
export function createHandler({ resolveApiKey = getEnvApiKey, ...options } = {}) {
|
|
20
20
|
return async (context) => {
|
|
21
21
|
const responseHeaders = new Headers();
|
|
22
22
|
const url = new URL(context.req.url);
|
|
23
23
|
return processProxyRequest({
|
|
24
24
|
framework: "hono",
|
|
25
|
+
request: context,
|
|
25
26
|
method: context.req.method,
|
|
26
27
|
body: async () => {
|
|
27
28
|
try {
|
|
@@ -44,7 +45,7 @@ export function createHandler({ resolveApiKey = getEnvApiKey, } = {}) {
|
|
|
44
45
|
}),
|
|
45
46
|
respond: passthrough,
|
|
46
47
|
apiKey: resolveApiKey,
|
|
47
|
-
});
|
|
48
|
+
}, options);
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
51
|
/** @deprecated Use createHandler */
|