skytells 1.0.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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/client.cjs +59 -0
- package/dist/client.d.ts +45 -0
- package/dist/client.js +59 -0
- package/dist/endpoints.cjs +9 -0
- package/dist/endpoints.d.ts +9 -0
- package/dist/endpoints.js +9 -0
- package/dist/http.cjs +118 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.js +118 -0
- package/dist/index.cjs +14 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/model.types.d.ts +13 -0
- package/dist/types/model.types.js +1 -0
- package/dist/types/predict.types.d.ts +80 -0
- package/dist/types/predict.types.js +10 -0
- package/dist/types/shared.types.d.ts +20 -0
- package/dist/types/shared.types.js +11 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Skytells, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Skytells JavaScript/TypeScript SDK
|
|
2
|
+
|
|
3
|
+
The official JavaScript/TypeScript SDK for interacting with the [Skytells](https://skytells.ai) API. Edge-compatible with Cloudflare Pages, Vercel Edge Functions, and more.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install skytells
|
|
9
|
+
# or
|
|
10
|
+
yarn add skytells
|
|
11
|
+
# or
|
|
12
|
+
pnpm add skytells
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { createClient } from 'skytells';
|
|
19
|
+
|
|
20
|
+
// Initialize the client with your API key
|
|
21
|
+
const skytells = createClient('your-api-key-here');
|
|
22
|
+
|
|
23
|
+
// Make a prediction
|
|
24
|
+
async function makePrediction() {
|
|
25
|
+
try {
|
|
26
|
+
const prediction = await skytells.predict({
|
|
27
|
+
model: 'model-name',
|
|
28
|
+
input: {
|
|
29
|
+
prompt: 'Your prompt here'
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log('Prediction ID:', prediction.id);
|
|
34
|
+
console.log('Status:', prediction.status);
|
|
35
|
+
console.log('Output:', prediction.output);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Error making prediction:', error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// List available models
|
|
42
|
+
async function listModels() {
|
|
43
|
+
try {
|
|
44
|
+
const models = await skytells.listModels();
|
|
45
|
+
console.log('Available models:', models);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('Error listing models:', error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get a prediction by ID
|
|
52
|
+
async function getPrediction(id) {
|
|
53
|
+
try {
|
|
54
|
+
const prediction = await skytells.getPrediction(id);
|
|
55
|
+
console.log('Prediction:', prediction);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error getting prediction:', error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Edge Compatibility
|
|
63
|
+
|
|
64
|
+
This SDK is fully compatible with edge environments including:
|
|
65
|
+
|
|
66
|
+
- Cloudflare Workers and Pages
|
|
67
|
+
- Vercel Edge Functions
|
|
68
|
+
- Netlify Edge Functions
|
|
69
|
+
- Deno Deploy
|
|
70
|
+
- Any environment with Fetch API support
|
|
71
|
+
|
|
72
|
+
To use a custom API endpoint or proxy:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { createClient } from 'skytells';
|
|
76
|
+
|
|
77
|
+
// Use a custom API endpoint or proxy
|
|
78
|
+
const client = createClient('your-api-key', {
|
|
79
|
+
baseUrl: 'https://your-proxy.example.com/v1'
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## API Reference
|
|
84
|
+
|
|
85
|
+
### Creating a Client
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { createClient } from 'skytells';
|
|
89
|
+
|
|
90
|
+
// With API key (authenticated)
|
|
91
|
+
const client = createClient('your-api-key');
|
|
92
|
+
|
|
93
|
+
// Without API key (unauthenticated, limited functionality)
|
|
94
|
+
const unauthenticatedClient = createClient();
|
|
95
|
+
|
|
96
|
+
// With options
|
|
97
|
+
const clientWithOptions = createClient('your-api-key', {
|
|
98
|
+
baseUrl: 'https://api.skytells.ai/v1', // Custom API URL
|
|
99
|
+
timeout: 30000 // Custom timeout in ms
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Predictions
|
|
104
|
+
|
|
105
|
+
#### Make a Prediction
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const prediction = await client.predict({
|
|
109
|
+
model: 'model-name',
|
|
110
|
+
input: {
|
|
111
|
+
// Model-specific inputs
|
|
112
|
+
prompt: 'Your prompt here',
|
|
113
|
+
// Other parameters...
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Get a Prediction by ID
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const prediction = await client.getPrediction('prediction-id');
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Stream a Prediction
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const prediction = await client.streamPrediction('prediction-id');
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Cancel a Prediction
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const prediction = await client.cancelPrediction('prediction-id');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Delete a Prediction
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const prediction = await client.deletePrediction('prediction-id');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Models
|
|
143
|
+
|
|
144
|
+
#### List All Models
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const models = await client.listModels();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## TypeScript Support
|
|
151
|
+
|
|
152
|
+
This SDK is built with TypeScript and provides full type definitions for all methods and responses.
|
|
153
|
+
|
|
154
|
+
## Error Handling
|
|
155
|
+
|
|
156
|
+
All API methods return promises that may reject with a `SkytellsError`. The SDK parses API error responses into this structured format:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { createClient, SkytellsError } from 'skytells';
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
const prediction = await client.predict({
|
|
163
|
+
model: 'model-name',
|
|
164
|
+
input: { prompt: 'Your prompt' }
|
|
165
|
+
});
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (error instanceof SkytellsError) {
|
|
168
|
+
console.error('Error message:', error.message);
|
|
169
|
+
console.error('Error ID:', error.errorId); // Example: "VALIDATION_ERROR"
|
|
170
|
+
console.error('Error details:', error.details); // Detailed error information
|
|
171
|
+
console.error('HTTP status:', error.httpStatus); // HTTP status code (e.g., 422)
|
|
172
|
+
} else {
|
|
173
|
+
console.error('Unknown error:', error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Common Error IDs
|
|
179
|
+
|
|
180
|
+
- `VALIDATION_ERROR` - Request parameters failed validation
|
|
181
|
+
- `AUTHENTICATION_ERROR` - Invalid or missing API key
|
|
182
|
+
- `RATE_LIMIT_EXCEEDED` - Too many requests
|
|
183
|
+
- `RESOURCE_NOT_FOUND` - The requested resource doesn't exist
|
|
184
|
+
- `NETWORK_ERROR` - Connection issue with the API
|
|
185
|
+
- `REQUEST_TIMEOUT` - Request took too long to complete
|
|
186
|
+
- `SERVER_ERROR` - The server responded with a non-JSON response (e.g., HTML error page)
|
|
187
|
+
- `INVALID_JSON` - The server returned invalid JSON content
|
|
188
|
+
|
|
189
|
+
### Non-JSON Response Handling
|
|
190
|
+
|
|
191
|
+
The SDK automatically handles cases when the server doesn't respond with valid JSON:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
try {
|
|
195
|
+
const models = await client.listModels();
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (error instanceof SkytellsError) {
|
|
198
|
+
if (error.errorId === 'SERVER_ERROR') {
|
|
199
|
+
console.error('The server returned a non-JSON response:', error.message);
|
|
200
|
+
console.error('Response content excerpt:', error.details);
|
|
201
|
+
// This could indicate a server outage or maintenance
|
|
202
|
+
} else if (error.errorId === 'INVALID_JSON') {
|
|
203
|
+
console.error('The server returned malformed JSON:', error.message);
|
|
204
|
+
console.error('Response content excerpt:', error.details);
|
|
205
|
+
// This could indicate an API bug or server issue
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Install dependencies
|
|
215
|
+
npm install
|
|
216
|
+
|
|
217
|
+
# Build the SDK
|
|
218
|
+
npm run build
|
|
219
|
+
|
|
220
|
+
# Run tests
|
|
221
|
+
npm test
|
|
222
|
+
|
|
223
|
+
# Run linting
|
|
224
|
+
npm run lint
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT
|
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const { HTTP } = require("./http.js");
|
|
2
|
+
const { ENDPOINTS } = require("./endpoints.js");
|
|
3
|
+
export class SkytellsClient {
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new Skytells client
|
|
6
|
+
* @param apiKey Your Skytells API key
|
|
7
|
+
* @param options Configuration options
|
|
8
|
+
*/
|
|
9
|
+
constructor(apiKey, options = {}) {
|
|
10
|
+
this.http = new HTTP(apiKey, options.baseUrl, options.timeout);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Send a prediction request to the Skytells API
|
|
14
|
+
* @param payload The prediction request parameters
|
|
15
|
+
* @returns A promise that resolves to the prediction response
|
|
16
|
+
*/
|
|
17
|
+
async predict(payload) {
|
|
18
|
+
return this.http.request('POST', ENDPOINTS.PREDICT, payload);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get a prediction by ID
|
|
22
|
+
* @param id The prediction ID
|
|
23
|
+
* @returns A promise that resolves to the prediction response
|
|
24
|
+
*/
|
|
25
|
+
async getPrediction(id) {
|
|
26
|
+
return this.http.request('GET', ENDPOINTS.PREDICTION_BY_ID(id));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all available models
|
|
30
|
+
* @returns A promise that resolves to an array of models
|
|
31
|
+
*/
|
|
32
|
+
async listModels() {
|
|
33
|
+
return this.http.request('GET', ENDPOINTS.MODELS);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Stream a prediction by ID
|
|
37
|
+
* @param id The prediction ID
|
|
38
|
+
* @returns A promise that resolves to the prediction response
|
|
39
|
+
*/
|
|
40
|
+
async streamPrediction(id) {
|
|
41
|
+
return this.http.request('GET', ENDPOINTS.STREAM_PREDICTION_BY_ID(id));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Cancel a prediction by ID
|
|
45
|
+
* @param id The prediction ID
|
|
46
|
+
* @returns A promise that resolves to the prediction response
|
|
47
|
+
*/
|
|
48
|
+
async cancelPrediction(id) {
|
|
49
|
+
return this.http.request('POST', ENDPOINTS.CANCEL_PREDICTION_BY_ID(id));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Delete a prediction by ID
|
|
53
|
+
* @param id The prediction ID
|
|
54
|
+
* @returns A promise that resolves to the prediction response
|
|
55
|
+
*/
|
|
56
|
+
async deletePrediction(id) {
|
|
57
|
+
return this.http.request('DELETE', ENDPOINTS.DELETE_PREDICTION_BY_ID(id));
|
|
58
|
+
}
|
|
59
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PredictionRequest, PredictionResponse, Model, ClientOptions } from './types/index.js';
|
|
2
|
+
export declare class SkytellsClient {
|
|
3
|
+
private http;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new Skytells client
|
|
6
|
+
* @param apiKey Your Skytells API key
|
|
7
|
+
* @param options Configuration options
|
|
8
|
+
*/
|
|
9
|
+
constructor(apiKey?: string, options?: ClientOptions);
|
|
10
|
+
/**
|
|
11
|
+
* Send a prediction request to the Skytells API
|
|
12
|
+
* @param payload The prediction request parameters
|
|
13
|
+
* @returns A promise that resolves to the prediction response
|
|
14
|
+
*/
|
|
15
|
+
predict(payload: PredictionRequest): Promise<PredictionResponse>;
|
|
16
|
+
/**
|
|
17
|
+
* Get a prediction by ID
|
|
18
|
+
* @param id The prediction ID
|
|
19
|
+
* @returns A promise that resolves to the prediction response
|
|
20
|
+
*/
|
|
21
|
+
getPrediction(id: string): Promise<PredictionResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* List all available models
|
|
24
|
+
* @returns A promise that resolves to an array of models
|
|
25
|
+
*/
|
|
26
|
+
listModels(): Promise<Model[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Stream a prediction by ID
|
|
29
|
+
* @param id The prediction ID
|
|
30
|
+
* @returns A promise that resolves to the prediction response
|
|
31
|
+
*/
|
|
32
|
+
streamPrediction(id: string): Promise<PredictionResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Cancel a prediction by ID
|
|
35
|
+
* @param id The prediction ID
|
|
36
|
+
* @returns A promise that resolves to the prediction response
|
|
37
|
+
*/
|
|
38
|
+
cancelPrediction(id: string): Promise<PredictionResponse>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete a prediction by ID
|
|
41
|
+
* @param id The prediction ID
|
|
42
|
+
* @returns A promise that resolves to the prediction response
|
|
43
|
+
*/
|
|
44
|
+
deletePrediction(id: string): Promise<PredictionResponse>;
|
|
45
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { HTTP } from './http.js';
|
|
2
|
+
import { ENDPOINTS } from './endpoints.js';
|
|
3
|
+
export class SkytellsClient {
|
|
4
|
+
/**
|
|
5
|
+
* Creates a new Skytells client
|
|
6
|
+
* @param apiKey Your Skytells API key
|
|
7
|
+
* @param options Configuration options
|
|
8
|
+
*/
|
|
9
|
+
constructor(apiKey, options = {}) {
|
|
10
|
+
this.http = new HTTP(apiKey, options.baseUrl, options.timeout);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Send a prediction request to the Skytells API
|
|
14
|
+
* @param payload The prediction request parameters
|
|
15
|
+
* @returns A promise that resolves to the prediction response
|
|
16
|
+
*/
|
|
17
|
+
async predict(payload) {
|
|
18
|
+
return this.http.request('POST', ENDPOINTS.PREDICT, payload);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get a prediction by ID
|
|
22
|
+
* @param id The prediction ID
|
|
23
|
+
* @returns A promise that resolves to the prediction response
|
|
24
|
+
*/
|
|
25
|
+
async getPrediction(id) {
|
|
26
|
+
return this.http.request('GET', ENDPOINTS.PREDICTION_BY_ID(id));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all available models
|
|
30
|
+
* @returns A promise that resolves to an array of models
|
|
31
|
+
*/
|
|
32
|
+
async listModels() {
|
|
33
|
+
return this.http.request('GET', ENDPOINTS.MODELS);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Stream a prediction by ID
|
|
37
|
+
* @param id The prediction ID
|
|
38
|
+
* @returns A promise that resolves to the prediction response
|
|
39
|
+
*/
|
|
40
|
+
async streamPrediction(id) {
|
|
41
|
+
return this.http.request('GET', ENDPOINTS.STREAM_PREDICTION_BY_ID(id));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Cancel a prediction by ID
|
|
45
|
+
* @param id The prediction ID
|
|
46
|
+
* @returns A promise that resolves to the prediction response
|
|
47
|
+
*/
|
|
48
|
+
async cancelPrediction(id) {
|
|
49
|
+
return this.http.request('POST', ENDPOINTS.CANCEL_PREDICTION_BY_ID(id));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Delete a prediction by ID
|
|
53
|
+
* @param id The prediction ID
|
|
54
|
+
* @returns A promise that resolves to the prediction response
|
|
55
|
+
*/
|
|
56
|
+
async deletePrediction(id) {
|
|
57
|
+
return this.http.request('DELETE', ENDPOINTS.DELETE_PREDICTION_BY_ID(id));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const API_BASE_URL = module.exports.API_BASE_URL = "https://api.skytells.ai/v1";
|
|
2
|
+
const ENDPOINTS = module.exports.ENDPOINTS = {
|
|
3
|
+
PREDICT: "/predict",
|
|
4
|
+
MODELS: "/models",
|
|
5
|
+
PREDICTION_BY_ID: (id) => `/predictions/${id}`,
|
|
6
|
+
STREAM_PREDICTION_BY_ID: (id) => `/predictions/${id}/stream`,
|
|
7
|
+
CANCEL_PREDICTION_BY_ID: (id) => `/predictions/${id}/cancel`,
|
|
8
|
+
DELETE_PREDICTION_BY_ID: (id) => `/predictions/${id}/delete`,
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const API_BASE_URL = "https://api.skytells.ai/v1";
|
|
2
|
+
export declare const ENDPOINTS: {
|
|
3
|
+
PREDICT: string;
|
|
4
|
+
MODELS: string;
|
|
5
|
+
PREDICTION_BY_ID: (id: string) => string;
|
|
6
|
+
STREAM_PREDICTION_BY_ID: (id: string) => string;
|
|
7
|
+
CANCEL_PREDICTION_BY_ID: (id: string) => string;
|
|
8
|
+
DELETE_PREDICTION_BY_ID: (id: string) => string;
|
|
9
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const API_BASE_URL = "https://api.skytells.ai/v1";
|
|
2
|
+
export const ENDPOINTS = {
|
|
3
|
+
PREDICT: "/predict",
|
|
4
|
+
MODELS: "/models",
|
|
5
|
+
PREDICTION_BY_ID: (id) => `/predictions/${id}`,
|
|
6
|
+
STREAM_PREDICTION_BY_ID: (id) => `/predictions/${id}/stream`,
|
|
7
|
+
CANCEL_PREDICTION_BY_ID: (id) => `/predictions/${id}/cancel`,
|
|
8
|
+
DELETE_PREDICTION_BY_ID: (id) => `/predictions/${id}/delete`,
|
|
9
|
+
};
|
package/dist/http.cjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const { API_BASE_URL } = require("./endpoints.js");
|
|
2
|
+
const { SkytellsError } = require("./types/shared.types.js");
|
|
3
|
+
// Default timeout in milliseconds
|
|
4
|
+
// 60 seconds
|
|
5
|
+
const DEFAULT_TIMEOUT = 60000;
|
|
6
|
+
export class HTTP {
|
|
7
|
+
constructor(apiKey, baseUrl = API_BASE_URL, timeout = DEFAULT_TIMEOUT) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
this.baseUrl = baseUrl;
|
|
10
|
+
this.timeout = timeout;
|
|
11
|
+
}
|
|
12
|
+
async request(method, path, data) {
|
|
13
|
+
const headers = {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
};
|
|
16
|
+
if (this.apiKey) {
|
|
17
|
+
headers['x-api-key'] = this.apiKey;
|
|
18
|
+
}
|
|
19
|
+
const options = {
|
|
20
|
+
method,
|
|
21
|
+
headers,
|
|
22
|
+
};
|
|
23
|
+
if (method === 'POST' && data) {
|
|
24
|
+
options.body = JSON.stringify(data);
|
|
25
|
+
}
|
|
26
|
+
// Add AbortController for timeout handling
|
|
27
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
28
|
+
if (controller) {
|
|
29
|
+
options.signal = controller.signal;
|
|
30
|
+
}
|
|
31
|
+
// Set up timeout if AbortController is available
|
|
32
|
+
let timeoutId = null;
|
|
33
|
+
if (controller) {
|
|
34
|
+
timeoutId = setTimeout(() => {
|
|
35
|
+
controller.abort();
|
|
36
|
+
}, this.timeout);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
// Use native fetch which is available in modern browsers and edge environments
|
|
40
|
+
const response = await fetch(`${this.baseUrl}${path}`, options);
|
|
41
|
+
// Get the response content type to check if it's JSON
|
|
42
|
+
const contentType = response.headers.get('content-type') || '';
|
|
43
|
+
const isJsonResponse = contentType.includes('application/json');
|
|
44
|
+
// Handle non-JSON responses properly
|
|
45
|
+
if (!isJsonResponse) {
|
|
46
|
+
// If not JSON, get the text for error details
|
|
47
|
+
let responseText = '';
|
|
48
|
+
try {
|
|
49
|
+
responseText = await response.text();
|
|
50
|
+
// Truncate if too long to avoid huge error messages
|
|
51
|
+
if (responseText.length > 500) {
|
|
52
|
+
responseText = responseText.substring(0, 500) + '... [truncated]';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (textError) {
|
|
56
|
+
responseText = 'Could not read response body';
|
|
57
|
+
}
|
|
58
|
+
throw new SkytellsError(`Server responded with non-JSON content (${contentType})`, 'SERVER_ERROR', `Status: ${response.status}, Content: ${responseText}`, response.status);
|
|
59
|
+
}
|
|
60
|
+
// Try to parse as JSON
|
|
61
|
+
let responseData;
|
|
62
|
+
try {
|
|
63
|
+
responseData = await response.json();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Get response text for better error details
|
|
67
|
+
let responseText = '';
|
|
68
|
+
try {
|
|
69
|
+
// Need to clone response since we already tried to read it as JSON
|
|
70
|
+
responseText = await response.clone().text();
|
|
71
|
+
if (responseText.length > 500) {
|
|
72
|
+
responseText = responseText.substring(0, 500) + '... [truncated]';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (textError) {
|
|
76
|
+
responseText = 'Could not read response body';
|
|
77
|
+
}
|
|
78
|
+
throw new SkytellsError('Invalid JSON response', 'INVALID_JSON', `The server returned invalid JSON. Status: ${response.status}, Content: ${responseText}`, response.status);
|
|
79
|
+
}
|
|
80
|
+
// Check if the response indicates an error
|
|
81
|
+
if (!response.ok || (responseData && responseData.status === false)) {
|
|
82
|
+
if (responseData && responseData.error) {
|
|
83
|
+
// API returned a structured error
|
|
84
|
+
throw new SkytellsError(responseData.error.message || responseData.response || 'API error occurred', responseData.error.error_id || 'UNKNOWN_ERROR', responseData.error.details || responseData.response || 'No additional details', responseData.error.http_status || response.status);
|
|
85
|
+
}
|
|
86
|
+
else if (responseData && responseData.response) {
|
|
87
|
+
// Simple error with just a response message
|
|
88
|
+
throw new SkytellsError(responseData.response, 'API_ERROR', responseData.response, response.status);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Generic HTTP error
|
|
92
|
+
throw new SkytellsError(`HTTP error ${response.status}`, 'HTTP_ERROR', `The server returned status code ${response.status}`, response.status);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return responseData;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// Check if it's an abort error (timeout)
|
|
99
|
+
if (error && typeof error === 'object' && 'name' in error && error.name === 'AbortError') {
|
|
100
|
+
throw new SkytellsError(`Request timed out after ${this.timeout}ms`, 'REQUEST_TIMEOUT', `The request took longer than ${this.timeout}ms to complete`, 408 // Request Timeout status code
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
// Re-throw original error
|
|
104
|
+
if (error instanceof SkytellsError) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
// Network or other errors
|
|
108
|
+
throw new SkytellsError(error instanceof Error ? error.message : 'Network error occurred', 'NETWORK_ERROR', 'A network error occurred while communicating with the API', 0 // No HTTP status for network errors
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
// Clear timeout if it was set
|
|
113
|
+
if (timeoutId !== null) {
|
|
114
|
+
clearTimeout(timeoutId);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
package/dist/http.d.ts
ADDED
package/dist/http.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { API_BASE_URL } from './endpoints.js';
|
|
2
|
+
import { SkytellsError } from './types/shared.types.js';
|
|
3
|
+
// Default timeout in milliseconds
|
|
4
|
+
// 60 seconds
|
|
5
|
+
const DEFAULT_TIMEOUT = 60000;
|
|
6
|
+
export class HTTP {
|
|
7
|
+
constructor(apiKey, baseUrl = API_BASE_URL, timeout = DEFAULT_TIMEOUT) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
this.baseUrl = baseUrl;
|
|
10
|
+
this.timeout = timeout;
|
|
11
|
+
}
|
|
12
|
+
async request(method, path, data) {
|
|
13
|
+
const headers = {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
};
|
|
16
|
+
if (this.apiKey) {
|
|
17
|
+
headers['x-api-key'] = this.apiKey;
|
|
18
|
+
}
|
|
19
|
+
const options = {
|
|
20
|
+
method,
|
|
21
|
+
headers,
|
|
22
|
+
};
|
|
23
|
+
if (method === 'POST' && data) {
|
|
24
|
+
options.body = JSON.stringify(data);
|
|
25
|
+
}
|
|
26
|
+
// Add AbortController for timeout handling
|
|
27
|
+
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
|
|
28
|
+
if (controller) {
|
|
29
|
+
options.signal = controller.signal;
|
|
30
|
+
}
|
|
31
|
+
// Set up timeout if AbortController is available
|
|
32
|
+
let timeoutId = null;
|
|
33
|
+
if (controller) {
|
|
34
|
+
timeoutId = setTimeout(() => {
|
|
35
|
+
controller.abort();
|
|
36
|
+
}, this.timeout);
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
// Use native fetch which is available in modern browsers and edge environments
|
|
40
|
+
const response = await fetch(`${this.baseUrl}${path}`, options);
|
|
41
|
+
// Get the response content type to check if it's JSON
|
|
42
|
+
const contentType = response.headers.get('content-type') || '';
|
|
43
|
+
const isJsonResponse = contentType.includes('application/json');
|
|
44
|
+
// Handle non-JSON responses properly
|
|
45
|
+
if (!isJsonResponse) {
|
|
46
|
+
// If not JSON, get the text for error details
|
|
47
|
+
let responseText = '';
|
|
48
|
+
try {
|
|
49
|
+
responseText = await response.text();
|
|
50
|
+
// Truncate if too long to avoid huge error messages
|
|
51
|
+
if (responseText.length > 500) {
|
|
52
|
+
responseText = responseText.substring(0, 500) + '... [truncated]';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (textError) {
|
|
56
|
+
responseText = 'Could not read response body';
|
|
57
|
+
}
|
|
58
|
+
throw new SkytellsError(`Server responded with non-JSON content (${contentType})`, 'SERVER_ERROR', `Status: ${response.status}, Content: ${responseText}`, response.status);
|
|
59
|
+
}
|
|
60
|
+
// Try to parse as JSON
|
|
61
|
+
let responseData;
|
|
62
|
+
try {
|
|
63
|
+
responseData = await response.json();
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Get response text for better error details
|
|
67
|
+
let responseText = '';
|
|
68
|
+
try {
|
|
69
|
+
// Need to clone response since we already tried to read it as JSON
|
|
70
|
+
responseText = await response.clone().text();
|
|
71
|
+
if (responseText.length > 500) {
|
|
72
|
+
responseText = responseText.substring(0, 500) + '... [truncated]';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (textError) {
|
|
76
|
+
responseText = 'Could not read response body';
|
|
77
|
+
}
|
|
78
|
+
throw new SkytellsError('Invalid JSON response', 'INVALID_JSON', `The server returned invalid JSON. Status: ${response.status}, Content: ${responseText}`, response.status);
|
|
79
|
+
}
|
|
80
|
+
// Check if the response indicates an error
|
|
81
|
+
if (!response.ok || (responseData && responseData.status === false)) {
|
|
82
|
+
if (responseData && responseData.error) {
|
|
83
|
+
// API returned a structured error
|
|
84
|
+
throw new SkytellsError(responseData.error.message || responseData.response || 'API error occurred', responseData.error.error_id || 'UNKNOWN_ERROR', responseData.error.details || responseData.response || 'No additional details', responseData.error.http_status || response.status);
|
|
85
|
+
}
|
|
86
|
+
else if (responseData && responseData.response) {
|
|
87
|
+
// Simple error with just a response message
|
|
88
|
+
throw new SkytellsError(responseData.response, 'API_ERROR', responseData.response, response.status);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Generic HTTP error
|
|
92
|
+
throw new SkytellsError(`HTTP error ${response.status}`, 'HTTP_ERROR', `The server returned status code ${response.status}`, response.status);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return responseData;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
// Check if it's an abort error (timeout)
|
|
99
|
+
if (error && typeof error === 'object' && 'name' in error && error.name === 'AbortError') {
|
|
100
|
+
throw new SkytellsError(`Request timed out after ${this.timeout}ms`, 'REQUEST_TIMEOUT', `The request took longer than ${this.timeout}ms to complete`, 408 // Request Timeout status code
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
// Re-throw original error
|
|
104
|
+
if (error instanceof SkytellsError) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
// Network or other errors
|
|
108
|
+
throw new SkytellsError(error instanceof Error ? error.message : 'Network error occurred', 'NETWORK_ERROR', 'A network error occurred while communicating with the API', 0 // No HTTP status for network errors
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
// Clear timeout if it was set
|
|
113
|
+
if (timeoutId !== null) {
|
|
114
|
+
clearTimeout(timeoutId);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { SkytellsClient } = require("./client.js");
|
|
2
|
+
/**
|
|
3
|
+
* Create a new Skytells API client
|
|
4
|
+
* @param apiKey Optional API key for authenticated requests
|
|
5
|
+
* @param options Optional client configuration
|
|
6
|
+
* @returns A new Skytells client instance
|
|
7
|
+
*/
|
|
8
|
+
function createClient(apiKey, options = {}) {
|
|
9
|
+
return new SkytellsClient(apiKey, options);
|
|
10
|
+
}
|
|
11
|
+
export * from './types/index.js';
|
|
12
|
+
module.exports = { SkytellsClient } from './client.js';
|
|
13
|
+
module.exports = { API_BASE_URL } from './endpoints.js';
|
|
14
|
+
module.exports = { SkytellsError } from './types/shared.types.js';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SkytellsClient } from './client.js';
|
|
2
|
+
import { ClientOptions } from './types/shared.types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create a new Skytells API client
|
|
5
|
+
* @param apiKey Optional API key for authenticated requests
|
|
6
|
+
* @param options Optional client configuration
|
|
7
|
+
* @returns A new Skytells client instance
|
|
8
|
+
*/
|
|
9
|
+
export declare function createClient(apiKey?: string, options?: ClientOptions): SkytellsClient;
|
|
10
|
+
export * from './types/index.js';
|
|
11
|
+
export { SkytellsClient } from './client.js';
|
|
12
|
+
export { API_BASE_URL } from './endpoints.js';
|
|
13
|
+
export { SkytellsError } from './types/shared.types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SkytellsClient } from './client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a new Skytells API client
|
|
4
|
+
* @param apiKey Optional API key for authenticated requests
|
|
5
|
+
* @param options Optional client configuration
|
|
6
|
+
* @returns A new Skytells client instance
|
|
7
|
+
*/
|
|
8
|
+
export function createClient(apiKey, options = {}) {
|
|
9
|
+
return new SkytellsClient(apiKey, options);
|
|
10
|
+
}
|
|
11
|
+
export * from './types/index.js';
|
|
12
|
+
export { SkytellsClient } from './client.js';
|
|
13
|
+
export { API_BASE_URL } from './endpoints.js';
|
|
14
|
+
export { SkytellsError } from './types/shared.types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export interface PredictionRequest {
|
|
2
|
+
/**
|
|
3
|
+
* Model to use for the prediction
|
|
4
|
+
*/
|
|
5
|
+
model: string;
|
|
6
|
+
/**
|
|
7
|
+
* Input to the prediction
|
|
8
|
+
*/
|
|
9
|
+
input: Record<string, any>;
|
|
10
|
+
/**
|
|
11
|
+
* Webhook to receive prediction events
|
|
12
|
+
*/
|
|
13
|
+
webhook?: {
|
|
14
|
+
url: string;
|
|
15
|
+
events: string[];
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Whether to wait for the prediction to complete
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
await?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to stream the prediction events
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
stream?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare enum PredictionStatus {
|
|
29
|
+
PENDING = "pending",
|
|
30
|
+
PROCESSING = "processing",
|
|
31
|
+
SUCCEEDED = "succeeded",
|
|
32
|
+
FAILED = "failed",
|
|
33
|
+
CANCELLED = "cancelled",
|
|
34
|
+
STARTING = "starting",
|
|
35
|
+
STARTED = "started"
|
|
36
|
+
}
|
|
37
|
+
export interface PredictionResponse {
|
|
38
|
+
status: PredictionStatus;
|
|
39
|
+
id: string;
|
|
40
|
+
response: string;
|
|
41
|
+
stream: boolean;
|
|
42
|
+
input: Record<string, any>;
|
|
43
|
+
output?: string[];
|
|
44
|
+
created_at: string;
|
|
45
|
+
started_at: string;
|
|
46
|
+
completed_at: string;
|
|
47
|
+
updated_at: string;
|
|
48
|
+
privacy: string;
|
|
49
|
+
model?: {
|
|
50
|
+
name: string;
|
|
51
|
+
type: string;
|
|
52
|
+
};
|
|
53
|
+
webhook?: {
|
|
54
|
+
url: string;
|
|
55
|
+
events: string[];
|
|
56
|
+
};
|
|
57
|
+
metrics?: {
|
|
58
|
+
image_count: number;
|
|
59
|
+
predict_time: number;
|
|
60
|
+
};
|
|
61
|
+
metadata?: {
|
|
62
|
+
billing?: {
|
|
63
|
+
credits_used: number;
|
|
64
|
+
};
|
|
65
|
+
storage?: {
|
|
66
|
+
files: {
|
|
67
|
+
name: string;
|
|
68
|
+
type: string;
|
|
69
|
+
size: number;
|
|
70
|
+
url: string;
|
|
71
|
+
}[];
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
urls?: {
|
|
75
|
+
get?: string;
|
|
76
|
+
cancel?: string;
|
|
77
|
+
stream?: string;
|
|
78
|
+
delete?: string;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export var PredictionStatus;
|
|
2
|
+
(function (PredictionStatus) {
|
|
3
|
+
PredictionStatus["PENDING"] = "pending";
|
|
4
|
+
PredictionStatus["PROCESSING"] = "processing";
|
|
5
|
+
PredictionStatus["SUCCEEDED"] = "succeeded";
|
|
6
|
+
PredictionStatus["FAILED"] = "failed";
|
|
7
|
+
PredictionStatus["CANCELLED"] = "cancelled";
|
|
8
|
+
PredictionStatus["STARTING"] = "starting";
|
|
9
|
+
PredictionStatus["STARTED"] = "started";
|
|
10
|
+
})(PredictionStatus || (PredictionStatus = {}));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ApiError {
|
|
2
|
+
status: boolean;
|
|
3
|
+
response: string;
|
|
4
|
+
error: {
|
|
5
|
+
http_status: number;
|
|
6
|
+
message: string;
|
|
7
|
+
details: string;
|
|
8
|
+
error_id: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface ClientOptions {
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class SkytellsError extends Error {
|
|
16
|
+
errorId: string;
|
|
17
|
+
details: string;
|
|
18
|
+
httpStatus: number;
|
|
19
|
+
constructor(message: string, errorId: string, details: string, httpStatus?: number);
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class SkytellsError extends Error {
|
|
2
|
+
constructor(message, errorId, details, httpStatus) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'SkytellsError';
|
|
5
|
+
this.errorId = errorId;
|
|
6
|
+
this.details = details;
|
|
7
|
+
this.httpStatus = httpStatus || 0;
|
|
8
|
+
// This is needed for proper instanceof checks in some environments
|
|
9
|
+
Object.setPrototypeOf(this, SkytellsError.prototype);
|
|
10
|
+
}
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skytells",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Skytells JavaScript/TypeScript SDK - Edge compatible",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node build.js",
|
|
12
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"lint": "eslint src --ext .ts",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/skytells/ts-sdk.git"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"skytells",
|
|
24
|
+
"skytells-ai",
|
|
25
|
+
"skytells-sdk",
|
|
26
|
+
"edge",
|
|
27
|
+
"cloudflare",
|
|
28
|
+
"vercel-edge",
|
|
29
|
+
"netlify-edge"
|
|
30
|
+
],
|
|
31
|
+
"author": "Skytells, Inc.",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/skytells/ts-sdk/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/skytells/ts-sdk#readme",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/jest": "^29.5.0",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
40
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
41
|
+
"eslint": "^8.40.0",
|
|
42
|
+
"jest": "^29.5.0",
|
|
43
|
+
"ts-jest": "^29.1.0",
|
|
44
|
+
"typescript": "^5.8.2"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=14"
|
|
48
|
+
},
|
|
49
|
+
"type": "module",
|
|
50
|
+
"exports": {
|
|
51
|
+
".": {
|
|
52
|
+
"types": "./dist/index.d.ts",
|
|
53
|
+
"import": "./dist/index.js",
|
|
54
|
+
"require": "./dist/index.cjs"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|