@curvet/sdk 0.1.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.
@@ -0,0 +1,380 @@
1
+ /** Credit/cost usage block returned by synchronous endpoints. */
2
+ interface Usage {
3
+ cost: number;
4
+ credits: number;
5
+ remainingBalance?: number;
6
+ remainingPoints?: number;
7
+ }
8
+ /** Per-request overrides accepted by every SDK method. */
9
+ interface RequestOptions {
10
+ /** Abort the request (and any polling) via an AbortSignal. */
11
+ signal?: AbortSignal;
12
+ /** Per-request timeout in ms (overrides the client default). */
13
+ timeout?: number;
14
+ /** Per-request max retries (overrides the client default). */
15
+ maxRetries?: number;
16
+ /** Extra headers merged into the request. */
17
+ headers?: Record<string, string>;
18
+ }
19
+ /** Minimal structural type for a fetch Response (keeps the SDK runtime-agnostic). */
20
+ interface FetchResponse {
21
+ ok: boolean;
22
+ status: number;
23
+ headers: {
24
+ get(name: string): string | null;
25
+ };
26
+ text(): Promise<string>;
27
+ }
28
+ /** Minimal structural type for fetch init options. */
29
+ interface FetchInit {
30
+ method?: string;
31
+ headers?: Record<string, string>;
32
+ body?: string;
33
+ signal?: AbortSignal;
34
+ }
35
+ /** Injectable fetch implementation (defaults to global fetch on Node 18+). */
36
+ type FetchLike = (url: string, init?: FetchInit) => Promise<FetchResponse>;
37
+
38
+ interface HttpClientOptions {
39
+ appKey: string;
40
+ baseURL: string;
41
+ timeout: number;
42
+ maxRetries: number;
43
+ fetch: FetchLike;
44
+ }
45
+ interface RequestArgs {
46
+ method: string;
47
+ path: string;
48
+ body?: unknown;
49
+ query?: Record<string, string | number | undefined>;
50
+ options?: RequestOptions;
51
+ }
52
+ /**
53
+ * The single place that knows about fetch, headers, base URL, error mapping,
54
+ * and retries. Resources call `request()`; everything else stays mockable.
55
+ */
56
+ declare class HttpClient {
57
+ private opts;
58
+ constructor(opts: HttpClientOptions);
59
+ request<T = any>(args: RequestArgs): Promise<T>;
60
+ private backoff;
61
+ private buildUrl;
62
+ /** Combine a per-request timeout with an optional user AbortSignal. */
63
+ private makeSignal;
64
+ }
65
+
66
+ type ModelType = "chat" | "image" | "video" | "audio" | "3d" | "web-browse" | "design" | "ui-builder" | "presentation" | (string & {});
67
+ interface ModelInfo {
68
+ id: string;
69
+ name: string;
70
+ cost: number;
71
+ type: ModelType;
72
+ provider: string;
73
+ credits: number;
74
+ supportsVision?: boolean;
75
+ }
76
+ interface RateLimits {
77
+ requestsPerHour: number;
78
+ costCapPerDay: number;
79
+ }
80
+ /**
81
+ * Known model IDs — provided purely for editor autocomplete.
82
+ * The model catalog is dynamic and per-app filtered, so any string is accepted
83
+ * (see {@link ModelId}); always call `models.list()` for the live catalog.
84
+ */
85
+ type KnownModelId = "gpt-4o" | "gpt-4o-mini" | "qwen-235b" | "gemma-4-26b" | "perplexity-sonar" | "claude-haiku-4-5-20251001" | "claude-sonnet-4-6" | "claude-opus-4-7" | "flux-2-klein-4b" | "wan-2.2" | "auto" | "smart";
86
+ /** A model ID. Accepts any string; {@link KnownModelId} drives autocomplete only. */
87
+ type ModelId = KnownModelId | (string & {});
88
+
89
+ type ChatRole = "system" | "user" | "assistant";
90
+ interface ChatMessage {
91
+ role: ChatRole;
92
+ content: string;
93
+ }
94
+ interface ChatCreateParams {
95
+ model: ModelId;
96
+ messages: ChatMessage[];
97
+ /** Creativity control (default 0.7). */
98
+ temperature?: number;
99
+ /** Maximum response tokens (default 1000). */
100
+ maxTokens?: number;
101
+ }
102
+ interface ChatResponse {
103
+ success: boolean;
104
+ response: string;
105
+ usage: Usage;
106
+ metadata: {
107
+ model: string;
108
+ latencyMs: number;
109
+ requestId: string;
110
+ };
111
+ }
112
+
113
+ declare class Chat {
114
+ private client;
115
+ constructor(client: HttpClient);
116
+ /** Create a chat completion. Synchronous — resolves with the model's reply. */
117
+ create(params: ChatCreateParams, options?: RequestOptions): Promise<ChatResponse>;
118
+ }
119
+
120
+ interface ImageGenerateParams {
121
+ model: ModelId;
122
+ prompt: string;
123
+ /**
124
+ * Output dimensions as "<width>x<height>" (default "1024x1024").
125
+ * Note: the API uses a single `size` field, NOT separate width/height.
126
+ */
127
+ size?: string;
128
+ }
129
+ interface ImageResponse {
130
+ success: boolean;
131
+ imageUrl: string;
132
+ usage: Usage;
133
+ metadata: {
134
+ model: string;
135
+ latencyMs: number;
136
+ requestId: string;
137
+ };
138
+ }
139
+
140
+ declare class Images {
141
+ private client;
142
+ constructor(client: HttpClient);
143
+ /** Generate an image from a prompt. Synchronous — resolves with `imageUrl`. */
144
+ generate(params: ImageGenerateParams, options?: RequestOptions): Promise<ImageResponse>;
145
+ }
146
+
147
+ type JobStatus = "processing" | "completed" | "failed";
148
+ type MediaKind = "video" | "audio" | "3d";
149
+ /**
150
+ * Unified media-job result. The raw API uses three different URL keys
151
+ * (`videoUrl`/`audioUrl`/`modelUrl`) and a 200-vs-202 split; this normalizes
152
+ * all of them to a single shape with `mediaUrl`.
153
+ */
154
+ interface MediaJob {
155
+ jobId?: string;
156
+ status: JobStatus;
157
+ progress?: number;
158
+ /** Final media URL once completed (image/video/audio/3d output). */
159
+ mediaUrl?: string;
160
+ usage?: Usage;
161
+ metadata?: Record<string, unknown>;
162
+ error?: string | null;
163
+ cost?: unknown;
164
+ eta?: string;
165
+ /** The raw, unnormalized response body. */
166
+ raw: unknown;
167
+ }
168
+ interface VideoGenerateParams {
169
+ model: ModelId;
170
+ prompt: string;
171
+ mode?: "text_to_video" | "image_to_video";
172
+ duration?: number;
173
+ resolution?: string;
174
+ [key: string]: unknown;
175
+ }
176
+ interface PollOptions {
177
+ /** Poll interval in ms (default 2500). */
178
+ pollIntervalMs?: number;
179
+ /** Total poll timeout in ms before throwing JobTimeoutError (default 180000). */
180
+ pollTimeoutMs?: number;
181
+ signal?: AbortSignal;
182
+ /** Called on each poll tick with progress (0-100) and ETA if available. */
183
+ onProgress?: (progress: number, eta?: string) => void;
184
+ }
185
+
186
+ interface JobDefaults {
187
+ pollIntervalMs: number;
188
+ pollTimeoutMs: number;
189
+ }
190
+ declare class Jobs {
191
+ private client;
192
+ private defaults;
193
+ constructor(client: HttpClient, defaults: JobDefaults);
194
+ /** Fetch the current status of an async job once (no polling). */
195
+ retrieve(jobId: string, options?: RequestOptions): Promise<MediaJob>;
196
+ /** Get a {@link Job} handle to poll/await an existing job by id. */
197
+ handle(jobId: string): Job;
198
+ }
199
+ /** A handle to a single async media job. */
200
+ declare class Job {
201
+ readonly id: string;
202
+ private client;
203
+ private defaults;
204
+ constructor(id: string, client: HttpClient, defaults: JobDefaults);
205
+ /** One status fetch (no polling). */
206
+ retrieve(options?: RequestOptions): Promise<MediaJob>;
207
+ /**
208
+ * Poll until the job reaches a terminal state.
209
+ * Resolves with the completed job, or throws JobFailedError / JobTimeoutError.
210
+ */
211
+ wait(opts?: PollOptions): Promise<MediaJob>;
212
+ }
213
+
214
+ /**
215
+ * Video generation. Backed by an async job queue: `generate()` submits and
216
+ * polls to completion (the common case); `submit()` fires and returns the job
217
+ * handle for manual polling.
218
+ *
219
+ * The same implementation backs audio and 3D (v1.1) via the `path` arg.
220
+ */
221
+ declare class Video {
222
+ private client;
223
+ private defaults;
224
+ private path;
225
+ constructor(client: HttpClient, defaults: JobDefaults, path?: string);
226
+ /**
227
+ * Submit a job WITHOUT polling. Returns once the server responds — either the
228
+ * 200 fast-path (already done) or a 202 with a jobId.
229
+ *
230
+ * The media POST long-polls server-side and can block well past a normal
231
+ * request timeout, so we default its timeout to the poll budget and disable
232
+ * auto-retry (a retried POST would enqueue a duplicate, double-charged job).
233
+ */
234
+ submit(params: VideoGenerateParams, options?: RequestOptions): Promise<MediaJob>;
235
+ /**
236
+ * Submit and resolve to the finished media. Handles the 200-vs-202 split and
237
+ * polls `/jobs/:id` internally. Throws JobFailedError / JobTimeoutError.
238
+ */
239
+ generate(params: VideoGenerateParams, options?: RequestOptions & PollOptions): Promise<MediaJob>;
240
+ }
241
+
242
+ interface ModelsListOptions extends RequestOptions {
243
+ /** Filter to a single model type (e.g. "chat", "image", "video"). */
244
+ type?: string;
245
+ /** Bypass the in-memory cache and fetch fresh. */
246
+ refresh?: boolean;
247
+ }
248
+ /**
249
+ * Live model catalog. The list is dynamic and per-app filtered server-side, so
250
+ * it is always fetched (with a short in-memory cache), never hardcoded.
251
+ */
252
+ declare class Models {
253
+ private client;
254
+ private cacheTtlMs;
255
+ private cache?;
256
+ constructor(client: HttpClient, cacheTtlMs?: number);
257
+ private load;
258
+ private ensure;
259
+ /** List available models, optionally filtered by `type`. */
260
+ list(options?: ModelsListOptions): Promise<ModelInfo[]>;
261
+ /** Find a single model by id (or undefined). */
262
+ get(id: string, options?: ModelsListOptions): Promise<ModelInfo | undefined>;
263
+ /** The app's rate limits as reported by GET /models. */
264
+ rateLimits(options?: ModelsListOptions): Promise<RateLimits | undefined>;
265
+ }
266
+
267
+ interface BalanceInfo {
268
+ walletBalance?: number;
269
+ totalAvailableUSD: number;
270
+ totalPoints?: number;
271
+ breakdown?: {
272
+ walletCredits?: number;
273
+ totalCredits?: number;
274
+ organizationLimit?: number;
275
+ monthlyUsed?: number;
276
+ isEnterprise?: boolean;
277
+ [key: string]: unknown;
278
+ };
279
+ [key: string]: unknown;
280
+ }
281
+ declare class Balance {
282
+ private client;
283
+ constructor(client: HttpClient);
284
+ /** Get the current credit balance for the app owner. */
285
+ get(options?: RequestOptions): Promise<BalanceInfo>;
286
+ }
287
+
288
+ declare const DEFAULT_BASE_URL = "https://curvet.ai/api/v1/playground";
289
+ interface CurvetOptions {
290
+ /** Your app key. Falls back to the CURVET_APP_KEY env var. */
291
+ appKey?: string;
292
+ /** Override the gateway base URL (defaults to production). */
293
+ baseURL?: string;
294
+ /** Per-request timeout in ms (default 60000). */
295
+ timeout?: number;
296
+ /** Max automatic retries for 429/5xx and network errors (default 2). */
297
+ maxRetries?: number;
298
+ /** Inject a fetch implementation (defaults to global fetch on Node 18+). */
299
+ fetch?: FetchLike;
300
+ /** Default poll interval for async media jobs, in ms (default 2500). */
301
+ defaultPollIntervalMs?: number;
302
+ /** Default poll timeout for async media jobs, in ms (default 180000). */
303
+ defaultPollTimeoutMs?: number;
304
+ }
305
+ /**
306
+ * The Curvet client. One instance per app key.
307
+ *
308
+ * ```ts
309
+ * const curvet = new Curvet({ appKey: process.env.CURVET_APP_KEY });
310
+ * const { response } = await curvet.chat.create({
311
+ * model: "gpt-4o-mini",
312
+ * messages: [{ role: "user", content: "hi" }],
313
+ * });
314
+ * ```
315
+ */
316
+ declare class Curvet {
317
+ readonly chat: Chat;
318
+ readonly image: Images;
319
+ readonly video: Video;
320
+ readonly jobs: Jobs;
321
+ readonly models: Models;
322
+ readonly balance: Balance;
323
+ constructor(options?: CurvetOptions);
324
+ }
325
+
326
+ interface CurvetErrorOptions {
327
+ status?: number;
328
+ requestId?: string;
329
+ raw?: unknown;
330
+ }
331
+ /** Base class for every error thrown by the SDK. */
332
+ declare class CurvetError extends Error {
333
+ readonly status?: number;
334
+ readonly requestId?: string;
335
+ readonly raw?: unknown;
336
+ constructor(message: string, opts?: CurvetErrorOptions);
337
+ }
338
+ /** 401 — missing or invalid `x-app-key`. */
339
+ declare class AuthError extends CurvetError {
340
+ }
341
+ /** 403 — app not active, playground not enabled, or model/category not allowed. */
342
+ declare class PermissionError extends CurvetError {
343
+ }
344
+ /** 400 — invalid/unknown model or malformed payload. */
345
+ declare class BadRequestError extends CurvetError {
346
+ }
347
+ /** 404 — job or workflow not found. */
348
+ declare class NotFoundError extends CurvetError {
349
+ }
350
+ /** 5xx — upstream/server error (retried automatically). */
351
+ declare class APIError extends CurvetError {
352
+ }
353
+ /** Network failure or timeout before a response was received. */
354
+ declare class ConnectionError extends CurvetError {
355
+ }
356
+ /** 402 — not enough credits to complete the request. */
357
+ declare class InsufficientBalanceError extends CurvetError {
358
+ required?: number;
359
+ available?: number;
360
+ }
361
+ /** 429 — hourly request limit or daily cost cap exceeded. */
362
+ declare class RateLimitError extends CurvetError {
363
+ kind?: "rate" | "cost";
364
+ limit?: number;
365
+ used?: number;
366
+ resetsAt?: Date;
367
+ retryAfterMs?: number;
368
+ }
369
+ /** An async media job finished with status "failed". */
370
+ declare class JobFailedError extends CurvetError {
371
+ readonly jobId: string;
372
+ constructor(message: string, jobId: string, opts?: CurvetErrorOptions);
373
+ }
374
+ /** An async media job did not finish within the poll timeout. */
375
+ declare class JobTimeoutError extends CurvetError {
376
+ readonly jobId: string;
377
+ constructor(message: string, jobId: string, opts?: CurvetErrorOptions);
378
+ }
379
+
380
+ export { APIError, AuthError, BadRequestError, Balance, type BalanceInfo, Chat, type ChatCreateParams, type ChatMessage, type ChatResponse, type ChatRole, ConnectionError, Curvet, CurvetError, type CurvetErrorOptions, type CurvetOptions, DEFAULT_BASE_URL, type FetchLike, type ImageGenerateParams, type ImageResponse, Images, InsufficientBalanceError, Job, type JobDefaults, JobFailedError, type JobStatus, JobTimeoutError, Jobs, type KnownModelId, type MediaJob, type MediaKind, type ModelId, type ModelInfo, type ModelType, Models, type ModelsListOptions, NotFoundError, PermissionError, type PollOptions, RateLimitError, type RateLimits, type RequestOptions, type Usage, Video, type VideoGenerateParams };