@inferencesh/sdk 0.1.1 → 0.1.3
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.js +39 -4
- package/dist/client.test.js +96 -5
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +61 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/types.d.ts +1364 -436
- package/dist/types.js +167 -23
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.inference = exports.Inference = void 0;
|
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const stream_1 = require("./stream");
|
|
6
6
|
const eventsource_1 = require("eventsource");
|
|
7
|
+
const errors_1 = require("./errors");
|
|
7
8
|
/**
|
|
8
9
|
* Inference.sh SDK Client
|
|
9
10
|
*
|
|
@@ -43,11 +44,45 @@ class Inference {
|
|
|
43
44
|
fetchOptions.body = JSON.stringify(options.data);
|
|
44
45
|
}
|
|
45
46
|
const response = await fetch(url.toString(), fetchOptions);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const responseText = await response.text();
|
|
48
|
+
// Try to parse as JSON
|
|
49
|
+
let data = null;
|
|
50
|
+
try {
|
|
51
|
+
data = JSON.parse(responseText);
|
|
49
52
|
}
|
|
50
|
-
|
|
53
|
+
catch {
|
|
54
|
+
// Not JSON
|
|
55
|
+
}
|
|
56
|
+
// Check for HTTP errors
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
// Check for RequirementsNotMetException (412 with errors array)
|
|
59
|
+
if (response.status === 412 && data && 'errors' in data && Array.isArray(data.errors)) {
|
|
60
|
+
throw errors_1.RequirementsNotMetException.fromResponse(data, response.status);
|
|
61
|
+
}
|
|
62
|
+
// General error handling
|
|
63
|
+
let errorDetail;
|
|
64
|
+
if (data && typeof data === 'object') {
|
|
65
|
+
const apiData = data;
|
|
66
|
+
if (apiData.error) {
|
|
67
|
+
errorDetail = typeof apiData.error === 'object' ? apiData.error.message : String(apiData.error);
|
|
68
|
+
}
|
|
69
|
+
else if ('message' in data) {
|
|
70
|
+
errorDetail = String(data.message);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
errorDetail = JSON.stringify(data);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (responseText) {
|
|
77
|
+
errorDetail = responseText.slice(0, 500);
|
|
78
|
+
}
|
|
79
|
+
throw new errors_1.InferenceError(response.status, errorDetail || 'Request failed', responseText);
|
|
80
|
+
}
|
|
81
|
+
const apiResponse = data;
|
|
82
|
+
if (!apiResponse?.success) {
|
|
83
|
+
throw new errors_1.InferenceError(response.status, apiResponse?.error?.message || 'Request failed', responseText);
|
|
84
|
+
}
|
|
85
|
+
return apiResponse.data;
|
|
51
86
|
}
|
|
52
87
|
createEventSource(endpoint) {
|
|
53
88
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
package/dist/client.test.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const client_1 = require("./client");
|
|
4
|
+
const errors_1 = require("./errors");
|
|
4
5
|
// Mock fetch globally
|
|
5
6
|
const mockFetch = jest.fn();
|
|
6
7
|
global.fetch = mockFetch;
|
|
@@ -39,8 +40,12 @@ describe('Inference', () => {
|
|
|
39
40
|
input: { message: 'hello world' },
|
|
40
41
|
output: { result: 'success' },
|
|
41
42
|
};
|
|
43
|
+
const responseData = { success: true, data: mockTask };
|
|
42
44
|
mockFetch.mockResolvedValueOnce({
|
|
43
|
-
|
|
45
|
+
ok: true,
|
|
46
|
+
status: 200,
|
|
47
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
48
|
+
json: () => Promise.resolve(responseData),
|
|
44
49
|
});
|
|
45
50
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
46
51
|
// Use input that won't trigger base64 detection (contains spaces/special chars)
|
|
@@ -55,17 +60,95 @@ describe('Inference', () => {
|
|
|
55
60
|
}));
|
|
56
61
|
});
|
|
57
62
|
it('should throw error on API failure', async () => {
|
|
63
|
+
const responseData = { success: false, error: { message: 'Invalid app' } };
|
|
58
64
|
mockFetch.mockResolvedValueOnce({
|
|
59
|
-
|
|
65
|
+
ok: false,
|
|
66
|
+
status: 400,
|
|
67
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
68
|
+
json: () => Promise.resolve(responseData),
|
|
60
69
|
});
|
|
61
70
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
62
71
|
await expect(client.run({ app: 'invalid-app', input: { message: 'test!' } }, { wait: false })).rejects.toThrow('Invalid app');
|
|
63
72
|
});
|
|
73
|
+
it('should throw RequirementsNotMetException on 412 with errors', async () => {
|
|
74
|
+
const requirementErrors = [
|
|
75
|
+
{
|
|
76
|
+
type: 'secret',
|
|
77
|
+
key: 'OPENAI_API_KEY',
|
|
78
|
+
message: 'Missing secret: OPENAI_API_KEY',
|
|
79
|
+
action: { type: 'add_secret', secret_key: 'OPENAI_API_KEY' },
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'integration',
|
|
83
|
+
key: 'google',
|
|
84
|
+
message: 'Integration not connected: google',
|
|
85
|
+
action: { type: 'connect', provider: 'google' },
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
const responseData = { errors: requirementErrors };
|
|
89
|
+
mockFetch.mockResolvedValueOnce({
|
|
90
|
+
ok: false,
|
|
91
|
+
status: 412,
|
|
92
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
93
|
+
json: () => Promise.resolve(responseData),
|
|
94
|
+
});
|
|
95
|
+
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
96
|
+
try {
|
|
97
|
+
await client.run({ app: 'test-app', input: { message: 'test!' } }, { wait: false });
|
|
98
|
+
fail('Expected RequirementsNotMetException to be thrown');
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
expect(e).toBeInstanceOf(errors_1.RequirementsNotMetException);
|
|
102
|
+
const exception = e;
|
|
103
|
+
expect(exception.errors).toHaveLength(2);
|
|
104
|
+
expect(exception.errors[0].type).toBe('secret');
|
|
105
|
+
expect(exception.errors[0].key).toBe('OPENAI_API_KEY');
|
|
106
|
+
expect(exception.errors[1].type).toBe('integration');
|
|
107
|
+
expect(exception.statusCode).toBe(412);
|
|
108
|
+
expect(exception.message).toBe('Missing secret: OPENAI_API_KEY');
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
it('should include action details in RequirementsNotMetException', async () => {
|
|
112
|
+
const requirementErrors = [
|
|
113
|
+
{
|
|
114
|
+
type: 'scope',
|
|
115
|
+
key: 'calendar.readonly',
|
|
116
|
+
message: 'Missing scope: calendar.readonly',
|
|
117
|
+
action: {
|
|
118
|
+
type: 'add_scopes',
|
|
119
|
+
provider: 'google',
|
|
120
|
+
scopes: ['calendar.readonly', 'calendar.events'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
const responseData = { errors: requirementErrors };
|
|
125
|
+
mockFetch.mockResolvedValueOnce({
|
|
126
|
+
ok: false,
|
|
127
|
+
status: 412,
|
|
128
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
129
|
+
json: () => Promise.resolve(responseData),
|
|
130
|
+
});
|
|
131
|
+
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
132
|
+
try {
|
|
133
|
+
await client.run({ app: 'test-app', input: {} }, { wait: false });
|
|
134
|
+
fail('Expected RequirementsNotMetException to be thrown');
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
expect(e).toBeInstanceOf(errors_1.RequirementsNotMetException);
|
|
138
|
+
const exception = e;
|
|
139
|
+
expect(exception.errors[0].action?.type).toBe('add_scopes');
|
|
140
|
+
expect(exception.errors[0].action?.scopes).toEqual(['calendar.readonly', 'calendar.events']);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
64
143
|
});
|
|
65
144
|
describe('cancel', () => {
|
|
66
145
|
it('should make a POST request to cancel endpoint', async () => {
|
|
146
|
+
const responseData = { success: true, data: null };
|
|
67
147
|
mockFetch.mockResolvedValueOnce({
|
|
68
|
-
|
|
148
|
+
ok: true,
|
|
149
|
+
status: 200,
|
|
150
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
151
|
+
json: () => Promise.resolve(responseData),
|
|
69
152
|
});
|
|
70
153
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
71
154
|
await client.cancel('task-123');
|
|
@@ -92,9 +175,13 @@ describe('uploadFile', () => {
|
|
|
92
175
|
uri: 'https://example.com/file.png',
|
|
93
176
|
upload_url: 'https://upload.example.com/signed-url',
|
|
94
177
|
};
|
|
178
|
+
const responseData = { success: true, data: [mockFile] };
|
|
95
179
|
mockFetch
|
|
96
180
|
.mockResolvedValueOnce({
|
|
97
|
-
|
|
181
|
+
ok: true,
|
|
182
|
+
status: 200,
|
|
183
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
184
|
+
json: () => Promise.resolve(responseData),
|
|
98
185
|
})
|
|
99
186
|
.mockResolvedValueOnce({ ok: true });
|
|
100
187
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
@@ -112,8 +199,12 @@ describe('uploadFile', () => {
|
|
|
112
199
|
uri: 'https://example.com/file.png',
|
|
113
200
|
// Missing upload_url
|
|
114
201
|
};
|
|
202
|
+
const responseData = { success: true, data: [mockFile] };
|
|
115
203
|
mockFetch.mockResolvedValueOnce({
|
|
116
|
-
|
|
204
|
+
ok: true,
|
|
205
|
+
status: 200,
|
|
206
|
+
text: () => Promise.resolve(JSON.stringify(responseData)),
|
|
207
|
+
json: () => Promise.resolve(responseData),
|
|
117
208
|
});
|
|
118
209
|
const client = new client_1.Inference({ apiKey: 'test-api-key' });
|
|
119
210
|
await expect(client.uploadFile('SGVsbG8gV29ybGQh', { filename: 'test.txt' })).rejects.toThrow('No upload URL provided by the server');
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for the inference.sh SDK.
|
|
3
|
+
*
|
|
4
|
+
* Note: types.ts contains interfaces (APIError, RequirementsNotMetError) that describe
|
|
5
|
+
* the API response data shapes. These classes are throwable Error subclasses for SDK use.
|
|
6
|
+
*/
|
|
7
|
+
import type { RequirementError } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* General HTTP/API error thrown by the SDK.
|
|
10
|
+
*
|
|
11
|
+
* Note: This is distinct from the `APIError` interface in types.ts which describes
|
|
12
|
+
* the error payload shape in API responses.
|
|
13
|
+
*/
|
|
14
|
+
export declare class InferenceError extends Error {
|
|
15
|
+
readonly statusCode: number;
|
|
16
|
+
readonly responseBody?: string;
|
|
17
|
+
constructor(statusCode: number, message: string, responseBody?: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when app requirements (secrets, integrations, scopes) are not met.
|
|
21
|
+
*
|
|
22
|
+
* Thrown for HTTP 412 responses that contain structured requirement errors.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* try {
|
|
27
|
+
* const task = await client.run(params);
|
|
28
|
+
* } catch (e) {
|
|
29
|
+
* if (e instanceof RequirementsNotMetException) {
|
|
30
|
+
* for (const err of e.errors) {
|
|
31
|
+
* console.log(`Missing ${err.type}: ${err.key}`);
|
|
32
|
+
* if (err.action) {
|
|
33
|
+
* console.log(` Fix: ${err.action.type}`);
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class RequirementsNotMetException extends Error {
|
|
41
|
+
readonly errors: RequirementError[];
|
|
42
|
+
readonly statusCode: number;
|
|
43
|
+
constructor(errors: RequirementError[], statusCode?: number);
|
|
44
|
+
/**
|
|
45
|
+
* Create from API response data.
|
|
46
|
+
*/
|
|
47
|
+
static fromResponse(data: {
|
|
48
|
+
errors?: RequirementError[];
|
|
49
|
+
}, statusCode?: number): RequirementsNotMetException;
|
|
50
|
+
}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Error classes for the inference.sh SDK.
|
|
4
|
+
*
|
|
5
|
+
* Note: types.ts contains interfaces (APIError, RequirementsNotMetError) that describe
|
|
6
|
+
* the API response data shapes. These classes are throwable Error subclasses for SDK use.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.RequirementsNotMetException = exports.InferenceError = void 0;
|
|
10
|
+
/**
|
|
11
|
+
* General HTTP/API error thrown by the SDK.
|
|
12
|
+
*
|
|
13
|
+
* Note: This is distinct from the `APIError` interface in types.ts which describes
|
|
14
|
+
* the error payload shape in API responses.
|
|
15
|
+
*/
|
|
16
|
+
class InferenceError extends Error {
|
|
17
|
+
constructor(statusCode, message, responseBody) {
|
|
18
|
+
super(`HTTP ${statusCode}: ${message}`);
|
|
19
|
+
this.name = 'InferenceError';
|
|
20
|
+
this.statusCode = statusCode;
|
|
21
|
+
this.responseBody = responseBody;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.InferenceError = InferenceError;
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when app requirements (secrets, integrations, scopes) are not met.
|
|
27
|
+
*
|
|
28
|
+
* Thrown for HTTP 412 responses that contain structured requirement errors.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* try {
|
|
33
|
+
* const task = await client.run(params);
|
|
34
|
+
* } catch (e) {
|
|
35
|
+
* if (e instanceof RequirementsNotMetException) {
|
|
36
|
+
* for (const err of e.errors) {
|
|
37
|
+
* console.log(`Missing ${err.type}: ${err.key}`);
|
|
38
|
+
* if (err.action) {
|
|
39
|
+
* console.log(` Fix: ${err.action.type}`);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class RequirementsNotMetException extends Error {
|
|
47
|
+
constructor(errors, statusCode = 412) {
|
|
48
|
+
const message = errors.length > 0 ? errors[0].message : 'requirements not met';
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = 'RequirementsNotMetException';
|
|
51
|
+
this.errors = errors;
|
|
52
|
+
this.statusCode = statusCode;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create from API response data.
|
|
56
|
+
*/
|
|
57
|
+
static fromResponse(data, statusCode = 412) {
|
|
58
|
+
return new RequirementsNotMetException(data.errors || [], statusCode);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.RequirementsNotMetException = RequirementsNotMetException;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Inference, inference, InferenceConfig, RunOptions, UploadFileOptions } from './client';
|
|
2
2
|
export { StreamManager, PartialDataWrapper } from './stream';
|
|
3
|
+
export { InferenceError, RequirementsNotMetException } from './errors';
|
|
3
4
|
export * from './types';
|
|
4
5
|
export type { TaskDTO as Task } from './types';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.StreamManager = exports.inference = exports.Inference = void 0;
|
|
17
|
+
exports.RequirementsNotMetException = exports.InferenceError = exports.StreamManager = exports.inference = exports.Inference = void 0;
|
|
18
18
|
// Main client export
|
|
19
19
|
var client_1 = require("./client");
|
|
20
20
|
Object.defineProperty(exports, "Inference", { enumerable: true, get: function () { return client_1.Inference; } });
|
|
@@ -22,5 +22,9 @@ Object.defineProperty(exports, "inference", { enumerable: true, get: function ()
|
|
|
22
22
|
// Stream utilities
|
|
23
23
|
var stream_1 = require("./stream");
|
|
24
24
|
Object.defineProperty(exports, "StreamManager", { enumerable: true, get: function () { return stream_1.StreamManager; } });
|
|
25
|
+
// Error classes (throwable)
|
|
26
|
+
var errors_1 = require("./errors");
|
|
27
|
+
Object.defineProperty(exports, "InferenceError", { enumerable: true, get: function () { return errors_1.InferenceError; } });
|
|
28
|
+
Object.defineProperty(exports, "RequirementsNotMetException", { enumerable: true, get: function () { return errors_1.RequirementsNotMetException; } });
|
|
25
29
|
// Types - includes TaskStatus constants and all DTOs
|
|
26
30
|
__exportStar(require("./types"), exports);
|