@curvet/sdk 0.1.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/errors.ts","../src/core/retry.ts","../src/core/http.ts","../src/resources/chat.ts","../src/resources/image.ts","../src/core/normalize.ts","../src/core/poll.ts","../src/resources/jobs.ts","../src/resources/video.ts","../src/resources/models.ts","../src/resources/balance.ts","../src/client.ts"],"sourcesContent":["export { Curvet, DEFAULT_BASE_URL } from \"./client\";\nexport type { CurvetOptions } from \"./client\";\n\n// Errors\nexport {\n CurvetError,\n AuthError,\n PermissionError,\n BadRequestError,\n NotFoundError,\n APIError,\n ConnectionError,\n InsufficientBalanceError,\n RateLimitError,\n JobFailedError,\n JobTimeoutError,\n} from \"./core/errors\";\nexport type { CurvetErrorOptions } from \"./core/errors\";\n\n// Resources\nexport { Chat } from \"./resources/chat\";\nexport { Images } from \"./resources/image\";\nexport { Video } from \"./resources/video\";\nexport { Jobs, Job } from \"./resources/jobs\";\nexport type { JobDefaults } from \"./resources/jobs\";\nexport { Models } from \"./resources/models\";\nexport type { ModelsListOptions } from \"./resources/models\";\nexport { Balance } from \"./resources/balance\";\nexport type { BalanceInfo } from \"./resources/balance\";\n\n// Types\nexport type { Usage, RequestOptions, FetchLike } from \"./types/common\";\nexport type { ChatRole, ChatMessage, ChatCreateParams, ChatResponse } from \"./types/chat\";\nexport type { ImageGenerateParams, ImageResponse } from \"./types/image\";\nexport type {\n JobStatus,\n MediaKind,\n MediaJob,\n VideoGenerateParams,\n PollOptions,\n} from \"./types/job\";\nexport type { ModelType, ModelInfo, RateLimits, KnownModelId, ModelId } from \"./types/models\";\n","export interface CurvetErrorOptions {\n status?: number;\n requestId?: string;\n raw?: unknown;\n}\n\n/** Base class for every error thrown by the SDK. */\nexport class CurvetError extends Error {\n readonly status?: number;\n readonly requestId?: string;\n readonly raw?: unknown;\n\n constructor(message: string, opts: CurvetErrorOptions = {}) {\n super(message);\n this.name = new.target.name;\n this.status = opts.status;\n this.requestId = opts.requestId;\n this.raw = opts.raw;\n // Restore prototype chain so `instanceof` works after transpilation.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — missing or invalid `x-app-key`. */\nexport class AuthError extends CurvetError {}\n/** 403 — app not active, playground not enabled, or model/category not allowed. */\nexport class PermissionError extends CurvetError {}\n/** 400 — invalid/unknown model or malformed payload. */\nexport class BadRequestError extends CurvetError {}\n/** 404 — job or workflow not found. */\nexport class NotFoundError extends CurvetError {}\n/** 5xx — upstream/server error (retried automatically). */\nexport class APIError extends CurvetError {}\n/** Network failure or timeout before a response was received. */\nexport class ConnectionError extends CurvetError {}\n\n/** 402 — not enough credits to complete the request. */\nexport class InsufficientBalanceError extends CurvetError {\n required?: number;\n available?: number;\n}\n\n/** 429 — hourly request limit or daily cost cap exceeded. */\nexport class RateLimitError extends CurvetError {\n kind?: \"rate\" | \"cost\";\n limit?: number;\n used?: number;\n resetsAt?: Date;\n retryAfterMs?: number;\n}\n\n/** An async media job finished with status \"failed\". */\nexport class JobFailedError extends CurvetError {\n readonly jobId: string;\n constructor(message: string, jobId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.jobId = jobId;\n }\n}\n\n/** An async media job did not finish within the poll timeout. */\nexport class JobTimeoutError extends CurvetError {\n readonly jobId: string;\n constructor(message: string, jobId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.jobId = jobId;\n }\n}\n\ninterface HeaderBag {\n get(name: string): string | null;\n}\n\n/** Map an HTTP status + JSON error body to the right typed error. */\nexport function errorFromResponse(\n status: number,\n body: unknown,\n requestId?: string,\n headers?: HeaderBag,\n): CurvetError {\n const b = (body ?? {}) as Record<string, any>;\n const message =\n typeof b.error === \"string\" ? b.error : `HTTP ${status}`;\n const base: CurvetErrorOptions = { status, requestId, raw: body };\n\n switch (status) {\n case 400:\n return new BadRequestError(message, base);\n case 401:\n return new AuthError(message, base);\n case 402: {\n const e = new InsufficientBalanceError(message, base);\n e.required = b.required;\n e.available = b.available;\n return e;\n }\n case 403:\n return new PermissionError(message, base);\n case 404:\n return new NotFoundError(message, base);\n case 429: {\n const e = new RateLimitError(message, base);\n const info = b.rateLimitInfo ?? b.costCapInfo;\n e.kind = b.costCapInfo ? \"cost\" : \"rate\";\n if (info) {\n e.limit = info.limit;\n e.used = info.used;\n if (info.resetsAt) e.resetsAt = new Date(info.resetsAt);\n }\n const retryAfter = headers?.get?.(\"retry-after\");\n if (info?.resetsIn != null) e.retryAfterMs = Number(info.resetsIn) * 1000;\n else if (retryAfter) e.retryAfterMs = Number(retryAfter) * 1000;\n else if (e.resetsAt) e.retryAfterMs = Math.max(0, e.resetsAt.getTime() - Date.now());\n return e;\n }\n default:\n return new APIError(message, base);\n }\n}\n","/** Exponential backoff with full jitter. */\nexport function fullJitterBackoff(attempt: number, baseMs = 500, capMs = 8000): number {\n const exp = Math.min(capMs, baseMs * 2 ** attempt);\n return Math.random() * exp;\n}\n\n/** Sleep that rejects with an AbortError if the signal fires. */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(abortError());\n const onAbort = () => {\n cleanup();\n reject(abortError());\n };\n const cleanup = () => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport function abortError(): Error {\n const e = new Error(\"The operation was aborted.\");\n e.name = \"AbortError\";\n return e;\n}\n\n/** Only 429 and 5xx are safe to retry. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n","import type { FetchLike, RequestOptions } from \"../types/common\";\nimport {\n CurvetError,\n ConnectionError,\n RateLimitError,\n errorFromResponse,\n} from \"./errors\";\nimport { fullJitterBackoff, isRetryableStatus, sleep } from \"./retry\";\n\nexport interface HttpClientOptions {\n appKey: string;\n baseURL: string;\n timeout: number;\n maxRetries: number;\n fetch: FetchLike;\n}\n\nexport interface RequestArgs {\n method: string;\n path: string;\n body?: unknown;\n query?: Record<string, string | number | undefined>;\n options?: RequestOptions;\n}\n\n/**\n * The single place that knows about fetch, headers, base URL, error mapping,\n * and retries. Resources call `request()`; everything else stays mockable.\n */\nexport class HttpClient {\n constructor(private opts: HttpClientOptions) {}\n\n async request<T = any>(args: RequestArgs): Promise<T> {\n const { method, path, body, query, options } = args;\n const url = this.buildUrl(path, query);\n const maxRetries = options?.maxRetries ?? this.opts.maxRetries;\n const timeout = options?.timeout ?? this.opts.timeout;\n\n const headers: Record<string, string> = {\n \"x-app-key\": this.opts.appKey,\n accept: \"application/json\",\n ...(options?.headers ?? {}),\n };\n let payload: string | undefined;\n if (body !== undefined) {\n headers[\"content-type\"] = \"application/json\";\n payload = JSON.stringify(body);\n }\n\n let attempt = 0;\n for (;;) {\n const { signal, done } = this.makeSignal(timeout, options?.signal);\n try {\n const res = await this.opts.fetch(url, { method, headers, body: payload, signal });\n const text = await res.text();\n const parsed = text ? safeJson(text) : undefined;\n\n if (res.ok) return parsed as T;\n\n const requestId =\n res.headers.get(\"x-request-id\") ??\n (parsed as any)?.metadata?.requestId ??\n undefined;\n const err = errorFromResponse(res.status, parsed, requestId, res.headers);\n\n if (isRetryableStatus(res.status) && attempt < maxRetries) {\n await this.backoff(err, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw err;\n } catch (e: any) {\n if (e instanceof CurvetError) throw e;\n // AbortError: distinguish user-abort (rethrow) from our timeout (retry/ConnectionError).\n if (e?.name === \"AbortError\") {\n if (options?.signal?.aborted) throw e;\n if (attempt < maxRetries) {\n await this.backoff(undefined, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw new ConnectionError(\"Request timed out\", { raw: e });\n }\n // Network error before any response — safe to retry.\n if (attempt < maxRetries) {\n await this.backoff(undefined, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw new ConnectionError(e?.message ?? \"Network request failed\", { raw: e });\n } finally {\n done();\n }\n }\n }\n\n private async backoff(err: CurvetError | undefined, attempt: number, signal?: AbortSignal) {\n let delay = fullJitterBackoff(attempt);\n if (err instanceof RateLimitError && err.retryAfterMs != null) {\n delay = Math.min(err.retryAfterMs, 30000);\n }\n await sleep(delay, signal);\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const base = this.opts.baseURL.replace(/\\/$/, \"\");\n let url = base + (path.startsWith(\"/\") ? path : \"/\" + path);\n if (query) {\n const qs = Object.entries(query)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)\n .join(\"&\");\n if (qs) url += \"?\" + qs;\n }\n return url;\n }\n\n /** Combine a per-request timeout with an optional user AbortSignal. */\n private makeSignal(timeout: number, userSignal?: AbortSignal) {\n const controller = new AbortController();\n const onUserAbort = () => controller.abort();\n if (userSignal) {\n if (userSignal.aborted) controller.abort();\n else userSignal.addEventListener(\"abort\", onUserAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(), timeout);\n return {\n signal: controller.signal,\n done: () => {\n clearTimeout(timer);\n userSignal?.removeEventListener(\"abort\", onUserAbort);\n },\n };\n }\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ChatCreateParams, ChatResponse } from \"../types/chat\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport class Chat {\n constructor(private client: HttpClient) {}\n\n /** Create a chat completion. Synchronous — resolves with the model's reply. */\n create(params: ChatCreateParams, options?: RequestOptions): Promise<ChatResponse> {\n return this.client.request<ChatResponse>({\n method: \"POST\",\n path: \"/chat\",\n body: params,\n options,\n });\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ImageGenerateParams, ImageResponse } from \"../types/image\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport class Images {\n constructor(private client: HttpClient) {}\n\n /** Generate an image from a prompt. Synchronous — resolves with `imageUrl`. */\n generate(params: ImageGenerateParams, options?: RequestOptions): Promise<ImageResponse> {\n return this.client.request<ImageResponse>({\n method: \"POST\",\n path: \"/image\",\n body: params,\n options,\n });\n }\n}\n","import type { MediaJob, JobStatus } from \"../types/job\";\n\n/**\n * The API returns the output URL under three different keys depending on the\n * endpoint: `videoUrl` (/video), `audioUrl` (/audio), `modelUrl` (/3d), and\n * `output.mediaUrl` (GET /jobs/:id). Unify them.\n */\nfunction pickMediaUrl(body: Record<string, any>): string | undefined {\n return (\n body?.videoUrl ??\n body?.audioUrl ??\n body?.modelUrl ??\n body?.output?.mediaUrl ??\n body?.mediaUrl ??\n undefined\n );\n}\n\n/**\n * Normalize a POST /video|/audio|/3d response, which is EITHER a 200 with the\n * final media URL (job already done) OR a 202 with just a `jobId` to poll.\n */\nexport function normalizeMediaPost(body: unknown): MediaJob {\n const b = (body ?? {}) as Record<string, any>;\n const mediaUrl = pickMediaUrl(b);\n const jobId = b.jobId ?? b.metadata?.jobId;\n const status: JobStatus = mediaUrl\n ? \"completed\"\n : b.status === \"failed\"\n ? \"failed\"\n : \"processing\";\n return {\n jobId,\n status,\n mediaUrl,\n usage: b.usage,\n metadata: b.metadata,\n error: b.error ?? null,\n raw: body,\n };\n}\n\n/** Normalize a GET /jobs/:id response. */\nexport function normalizeJob(body: unknown): MediaJob {\n const b = (body ?? {}) as Record<string, any>;\n const mediaUrl = pickMediaUrl(b);\n const status: JobStatus = (b.status as JobStatus) ?? (mediaUrl ? \"completed\" : \"processing\");\n return {\n jobId: b.jobId,\n status,\n progress: b.progress,\n mediaUrl,\n metadata: b.output?.metadata ?? b.metadata,\n error: b.error ?? null,\n cost: b.cost,\n eta: b.eta,\n raw: body,\n };\n}\n","import { sleep } from \"./retry\";\n\n/** Thrown internally when a poll loop exceeds its timeout. */\nexport class PollTimeoutError extends Error {\n constructor(message = \"Polling timed out\") {\n super(message);\n this.name = \"PollTimeoutError\";\n }\n}\n\nexport interface PollConfig<T> {\n isTerminal: (result: T) => boolean;\n intervalMs: number;\n timeoutMs: number;\n signal?: AbortSignal;\n onTick?: (result: T) => void;\n}\n\n/**\n * Repeatedly call `fn` until `isTerminal` is true (resolves the result) or the\n * timeout elapses (throws PollTimeoutError). Polls immediately, then every\n * `intervalMs`. Honors an AbortSignal between ticks.\n */\nexport async function pollUntil<T>(fn: () => Promise<T>, cfg: PollConfig<T>): Promise<T> {\n const start = Date.now();\n for (;;) {\n const result = await fn();\n cfg.onTick?.(result);\n if (cfg.isTerminal(result)) return result;\n const elapsed = Date.now() - start;\n if (elapsed >= cfg.timeoutMs) throw new PollTimeoutError();\n const remaining = cfg.timeoutMs - elapsed;\n await sleep(Math.min(cfg.intervalMs, Math.max(0, remaining)), cfg.signal);\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { MediaJob, PollOptions } from \"../types/job\";\nimport type { RequestOptions } from \"../types/common\";\nimport { normalizeJob } from \"../core/normalize\";\nimport { pollUntil, PollTimeoutError } from \"../core/poll\";\nimport { JobFailedError, JobTimeoutError } from \"../core/errors\";\n\nexport interface JobDefaults {\n pollIntervalMs: number;\n pollTimeoutMs: number;\n}\n\nexport class Jobs {\n constructor(\n private client: HttpClient,\n private defaults: JobDefaults,\n ) {}\n\n /** Fetch the current status of an async job once (no polling). */\n async retrieve(jobId: string, options?: RequestOptions): Promise<MediaJob> {\n const body = await this.client.request({\n method: \"GET\",\n path: `/jobs/${encodeURIComponent(jobId)}`,\n options,\n });\n return normalizeJob(body);\n }\n\n /** Get a {@link Job} handle to poll/await an existing job by id. */\n handle(jobId: string): Job {\n return new Job(jobId, this.client, this.defaults);\n }\n}\n\n/** A handle to a single async media job. */\nexport class Job {\n constructor(\n readonly id: string,\n private client: HttpClient,\n private defaults: JobDefaults,\n ) {}\n\n /** One status fetch (no polling). */\n retrieve(options?: RequestOptions): Promise<MediaJob> {\n return new Jobs(this.client, this.defaults).retrieve(this.id, options);\n }\n\n /**\n * Poll until the job reaches a terminal state.\n * Resolves with the completed job, or throws JobFailedError / JobTimeoutError.\n */\n async wait(opts: PollOptions = {}): Promise<MediaJob> {\n const intervalMs = opts.pollIntervalMs ?? this.defaults.pollIntervalMs;\n const timeoutMs = opts.pollTimeoutMs ?? this.defaults.pollTimeoutMs;\n\n let result: MediaJob;\n try {\n result = await pollUntil(() => this.retrieve({ signal: opts.signal }), {\n intervalMs,\n timeoutMs,\n signal: opts.signal,\n isTerminal: (r) => r.status === \"completed\" || r.status === \"failed\",\n onTick: (r) => opts.onProgress?.(r.progress ?? 0, r.eta),\n });\n } catch (e) {\n if (e instanceof PollTimeoutError) {\n throw new JobTimeoutError(\n `Job ${this.id} did not complete within ${timeoutMs}ms`,\n this.id,\n );\n }\n throw e;\n }\n\n if (result.status === \"failed\") {\n throw new JobFailedError(result.error || `Job ${this.id} failed`, this.id, {\n raw: result.raw,\n });\n }\n return result;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { MediaJob, VideoGenerateParams, PollOptions } from \"../types/job\";\nimport type { RequestOptions } from \"../types/common\";\nimport { normalizeMediaPost } from \"../core/normalize\";\nimport { Job, type JobDefaults } from \"./jobs\";\nimport { CurvetError } from \"../core/errors\";\n\n/**\n * Video generation. Backed by an async job queue: `generate()` submits and\n * polls to completion (the common case); `submit()` fires and returns the job\n * handle for manual polling.\n *\n * The same implementation backs audio and 3D (v1.1) via the `path` arg.\n */\nexport class Video {\n constructor(\n private client: HttpClient,\n private defaults: JobDefaults,\n private path: string = \"/video\",\n ) {}\n\n /**\n * Submit a job WITHOUT polling. Returns once the server responds — either the\n * 200 fast-path (already done) or a 202 with a jobId.\n *\n * The media POST long-polls server-side and can block well past a normal\n * request timeout, so we default its timeout to the poll budget and disable\n * auto-retry (a retried POST would enqueue a duplicate, double-charged job).\n */\n async submit(params: VideoGenerateParams, options?: RequestOptions): Promise<MediaJob> {\n const reqOptions: RequestOptions = {\n ...options,\n timeout: options?.timeout ?? this.defaults.pollTimeoutMs,\n maxRetries: options?.maxRetries ?? 0,\n };\n const body = await this.client.request({\n method: \"POST\",\n path: this.path,\n body: params,\n options: reqOptions,\n });\n return normalizeMediaPost(body);\n }\n\n /**\n * Submit and resolve to the finished media. Handles the 200-vs-202 split and\n * polls `/jobs/:id` internally. Throws JobFailedError / JobTimeoutError.\n */\n async generate(\n params: VideoGenerateParams,\n options?: RequestOptions & PollOptions,\n ): Promise<MediaJob> {\n const submitted = await this.submit(params, options);\n if (submitted.status === \"completed\" || submitted.status === \"failed\") {\n return submitted;\n }\n if (!submitted.jobId) {\n throw new CurvetError(\"Async job did not return a jobId to poll\", {\n raw: submitted.raw,\n });\n }\n const job = new Job(submitted.jobId, this.client, this.defaults);\n return job.wait({\n pollIntervalMs: options?.pollIntervalMs,\n pollTimeoutMs: options?.pollTimeoutMs,\n signal: options?.signal,\n onProgress: options?.onProgress,\n });\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ModelInfo, RateLimits } from \"../types/models\";\nimport type { RequestOptions } from \"../types/common\";\n\ninterface ModelsListResponse {\n success: boolean;\n models: ModelInfo[];\n rateLimits: RateLimits;\n}\n\nexport interface ModelsListOptions extends RequestOptions {\n /** Filter to a single model type (e.g. \"chat\", \"image\", \"video\"). */\n type?: string;\n /** Bypass the in-memory cache and fetch fresh. */\n refresh?: boolean;\n}\n\n/**\n * Live model catalog. The list is dynamic and per-app filtered server-side, so\n * it is always fetched (with a short in-memory cache), never hardcoded.\n */\nexport class Models {\n private cache?: { at: number; data: ModelsListResponse };\n\n constructor(\n private client: HttpClient,\n private cacheTtlMs = 60_000,\n ) {}\n\n private async load(options?: RequestOptions): Promise<ModelsListResponse> {\n return this.client.request<ModelsListResponse>({\n method: \"GET\",\n path: \"/models\",\n options,\n });\n }\n\n private async ensure(options?: ModelsListOptions): Promise<ModelsListResponse> {\n const stale = !this.cache || Date.now() - this.cache.at > this.cacheTtlMs;\n if (options?.refresh || stale) {\n this.cache = { at: Date.now(), data: await this.load(options) };\n }\n return this.cache!.data;\n }\n\n /** List available models, optionally filtered by `type`. */\n async list(options?: ModelsListOptions): Promise<ModelInfo[]> {\n const data = await this.ensure(options);\n const models = data.models ?? [];\n return options?.type ? models.filter((m) => m.type === options.type) : models;\n }\n\n /** Find a single model by id (or undefined). */\n async get(id: string, options?: ModelsListOptions): Promise<ModelInfo | undefined> {\n return (await this.list(options)).find((m) => m.id === id);\n }\n\n /** The app's rate limits as reported by GET /models. */\n async rateLimits(options?: ModelsListOptions): Promise<RateLimits | undefined> {\n return (await this.ensure(options)).rateLimits;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport interface BalanceInfo {\n walletBalance?: number;\n totalAvailableUSD: number;\n totalPoints?: number;\n breakdown?: {\n walletCredits?: number;\n totalCredits?: number;\n organizationLimit?: number;\n monthlyUsed?: number;\n isEnterprise?: boolean;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nexport class Balance {\n constructor(private client: HttpClient) {}\n\n /** Get the current credit balance for the app owner. */\n async get(options?: RequestOptions): Promise<BalanceInfo> {\n const body = await this.client.request<{ success: boolean; balance: BalanceInfo }>({\n method: \"GET\",\n path: \"/balance\",\n options,\n });\n return body.balance;\n }\n}\n","import { HttpClient } from \"./core/http\";\nimport { CurvetError } from \"./core/errors\";\nimport type { FetchLike } from \"./types/common\";\nimport { Chat } from \"./resources/chat\";\nimport { Images } from \"./resources/image\";\nimport { Video } from \"./resources/video\";\nimport { Jobs } from \"./resources/jobs\";\nimport { Models } from \"./resources/models\";\nimport { Balance } from \"./resources/balance\";\n\nexport const DEFAULT_BASE_URL = \"https://curvet.ai/api/v1/playground\";\n\nexport interface CurvetOptions {\n /** Your app key. Falls back to the CURVET_APP_KEY env var. */\n appKey?: string;\n /** Override the gateway base URL (defaults to production). */\n baseURL?: string;\n /** Per-request timeout in ms (default 60000). */\n timeout?: number;\n /** Max automatic retries for 429/5xx and network errors (default 2). */\n maxRetries?: number;\n /** Inject a fetch implementation (defaults to global fetch on Node 18+). */\n fetch?: FetchLike;\n /** Default poll interval for async media jobs, in ms (default 2500). */\n defaultPollIntervalMs?: number;\n /** Default poll timeout for async media jobs, in ms (default 180000). */\n defaultPollTimeoutMs?: number;\n}\n\n/**\n * The Curvet client. One instance per app key.\n *\n * ```ts\n * const curvet = new Curvet({ appKey: process.env.CURVET_APP_KEY });\n * const { response } = await curvet.chat.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hi\" }],\n * });\n * ```\n */\nexport class Curvet {\n readonly chat: Chat;\n readonly image: Images;\n readonly video: Video;\n readonly jobs: Jobs;\n readonly models: Models;\n readonly balance: Balance;\n\n constructor(options: CurvetOptions = {}) {\n const appKey = options.appKey ?? envKey();\n if (!appKey) {\n throw new CurvetError(\n \"Missing Curvet app key. Pass { appKey } or set the CURVET_APP_KEY environment variable.\",\n );\n }\n const fetchImpl = options.fetch ?? defaultFetch();\n if (!fetchImpl) {\n throw new CurvetError(\n \"No fetch implementation available. Use Node 18+ or pass { fetch }.\",\n );\n }\n\n const client = new HttpClient({\n appKey,\n baseURL: options.baseURL ?? DEFAULT_BASE_URL,\n timeout: options.timeout ?? 60_000,\n maxRetries: options.maxRetries ?? 2,\n fetch: fetchImpl,\n });\n\n const jobDefaults = {\n pollIntervalMs: options.defaultPollIntervalMs ?? 2500,\n pollTimeoutMs: options.defaultPollTimeoutMs ?? 180_000,\n };\n\n this.chat = new Chat(client);\n this.image = new Images(client);\n this.jobs = new Jobs(client, jobDefaults);\n this.video = new Video(client, jobDefaults);\n this.models = new Models(client);\n this.balance = new Balance(client);\n }\n}\n\nfunction envKey(): string | undefined {\n return typeof process !== \"undefined\" ? process.env?.CURVET_APP_KEY : undefined;\n}\n\nfunction defaultFetch(): FetchLike | undefined {\n const f = (globalThis as { fetch?: unknown }).fetch;\n return typeof f === \"function\" ? (f.bind(globalThis) as FetchLike) : undefined;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/errors.ts","../src/core/retry.ts","../src/core/http.ts","../src/resources/chat.ts","../src/resources/image.ts","../src/core/normalize.ts","../src/core/poll.ts","../src/resources/jobs.ts","../src/resources/media.ts","../src/resources/video.ts","../src/resources/audio.ts","../src/resources/threeD.ts","../src/resources/models.ts","../src/resources/balance.ts","../src/resources/analytics.ts","../src/resources/workflows.ts","../src/resources/food.ts","../src/resources/voice.ts","../src/client.ts"],"sourcesContent":["export { Curvet, DEFAULT_BASE_URL } from \"./client\";\nexport type { CurvetOptions } from \"./client\";\n\n// Errors\nexport {\n CurvetError,\n AuthError,\n PermissionError,\n BadRequestError,\n NotFoundError,\n APIError,\n ConnectionError,\n InsufficientBalanceError,\n RateLimitError,\n JobFailedError,\n JobTimeoutError,\n WorkflowRunFailedError,\n WorkflowRunTimeoutError,\n} from \"./core/errors\";\nexport type { CurvetErrorOptions } from \"./core/errors\";\n\n// Resources\nexport { Chat } from \"./resources/chat\";\nexport { Images } from \"./resources/image\";\nexport { MediaResource } from \"./resources/media\";\nexport type { MediaParamsBase } from \"./resources/media\";\nexport { Video } from \"./resources/video\";\nexport { Audio } from \"./resources/audio\";\nexport { ThreeD } from \"./resources/threeD\";\nexport { Jobs, Job } from \"./resources/jobs\";\nexport type { JobDefaults } from \"./resources/jobs\";\nexport { Models } from \"./resources/models\";\nexport type { ModelsListOptions } from \"./resources/models\";\nexport { Balance } from \"./resources/balance\";\nexport type { BalanceInfo } from \"./resources/balance\";\nexport { Analytics } from \"./resources/analytics\";\nexport type { AnalyticsParams, AnalyticsResult } from \"./resources/analytics\";\nexport { Workflows, WorkflowRuns } from \"./resources/workflows\";\nexport type {\n WorkflowRunParams,\n WorkflowRunResult,\n WorkflowRunStatus,\n WorkflowRunNode,\n WorkflowRun,\n WorkflowSubmitResult,\n WorkflowPollOptions,\n} from \"./resources/workflows\";\nexport { Food } from \"./resources/food\";\nexport type { FoodItem } from \"./resources/food\";\nexport { Voice } from \"./resources/voice\";\nexport type { SttParams, SttResult } from \"./resources/voice\";\n\n// Types\nexport type { Usage, RequestOptions, FetchLike } from \"./types/common\";\nexport type { ChatRole, ChatMessage, ChatCreateParams, ChatResponse } from \"./types/chat\";\nexport type { ImageGenerateParams, ImageResponse } from \"./types/image\";\nexport type {\n JobStatus,\n MediaKind,\n MediaJob,\n VideoGenerateParams,\n AudioGenerateParams,\n ThreeDGenerateParams,\n PollOptions,\n} from \"./types/job\";\nexport type { ModelType, ModelInfo, RateLimits, KnownModelId, ModelId } from \"./types/models\";\n","export interface CurvetErrorOptions {\n status?: number;\n requestId?: string;\n raw?: unknown;\n}\n\n/** Base class for every error thrown by the SDK. */\nexport class CurvetError extends Error {\n readonly status?: number;\n readonly requestId?: string;\n readonly raw?: unknown;\n\n constructor(message: string, opts: CurvetErrorOptions = {}) {\n super(message);\n this.name = new.target.name;\n this.status = opts.status;\n this.requestId = opts.requestId;\n this.raw = opts.raw;\n // Restore prototype chain so `instanceof` works after transpilation.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 401 — missing or invalid `x-app-key`. */\nexport class AuthError extends CurvetError {}\n/** 403 — app not active, playground not enabled, or model/category not allowed. */\nexport class PermissionError extends CurvetError {}\n/** 400 — invalid/unknown model or malformed payload. */\nexport class BadRequestError extends CurvetError {}\n/** 404 — job or workflow not found. */\nexport class NotFoundError extends CurvetError {}\n/** 5xx — upstream/server error (retried automatically). */\nexport class APIError extends CurvetError {}\n/** Network failure or timeout before a response was received. */\nexport class ConnectionError extends CurvetError {}\n\n/** 402 — not enough credits to complete the request. */\nexport class InsufficientBalanceError extends CurvetError {\n required?: number;\n available?: number;\n}\n\n/** 429 — hourly request limit or daily cost cap exceeded. */\nexport class RateLimitError extends CurvetError {\n kind?: \"rate\" | \"cost\";\n limit?: number;\n used?: number;\n resetsAt?: Date;\n retryAfterMs?: number;\n}\n\n/** An async media job finished with status \"failed\". */\nexport class JobFailedError extends CurvetError {\n readonly jobId: string;\n constructor(message: string, jobId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.jobId = jobId;\n }\n}\n\n/** An async media job did not finish within the poll timeout. */\nexport class JobTimeoutError extends CurvetError {\n readonly jobId: string;\n constructor(message: string, jobId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.jobId = jobId;\n }\n}\n\n/** An async workflow run finished with status \"failed\" (or \"stopped\"). */\nexport class WorkflowRunFailedError extends CurvetError {\n readonly runId: string;\n constructor(message: string, runId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.runId = runId;\n }\n}\n\n/** An async workflow run did not finish within the poll timeout. */\nexport class WorkflowRunTimeoutError extends CurvetError {\n readonly runId: string;\n constructor(message: string, runId: string, opts: CurvetErrorOptions = {}) {\n super(message, opts);\n this.runId = runId;\n }\n}\n\ninterface HeaderBag {\n get(name: string): string | null;\n}\n\n/** Map an HTTP status + JSON error body to the right typed error. */\nexport function errorFromResponse(\n status: number,\n body: unknown,\n requestId?: string,\n headers?: HeaderBag,\n): CurvetError {\n const b = (body ?? {}) as Record<string, any>;\n const message =\n typeof b.error === \"string\" ? b.error : `HTTP ${status}`;\n const base: CurvetErrorOptions = { status, requestId, raw: body };\n\n switch (status) {\n case 400:\n return new BadRequestError(message, base);\n case 401:\n return new AuthError(message, base);\n case 402: {\n const e = new InsufficientBalanceError(message, base);\n e.required = b.required;\n e.available = b.available;\n return e;\n }\n case 403:\n return new PermissionError(message, base);\n case 404:\n return new NotFoundError(message, base);\n case 429: {\n const e = new RateLimitError(message, base);\n const info = b.rateLimitInfo ?? b.costCapInfo;\n e.kind = b.costCapInfo ? \"cost\" : \"rate\";\n if (info) {\n e.limit = info.limit;\n e.used = info.used;\n if (info.resetsAt) e.resetsAt = new Date(info.resetsAt);\n }\n const retryAfter = headers?.get?.(\"retry-after\");\n if (info?.resetsIn != null) e.retryAfterMs = Number(info.resetsIn) * 1000;\n else if (retryAfter) e.retryAfterMs = Number(retryAfter) * 1000;\n else if (e.resetsAt) e.retryAfterMs = Math.max(0, e.resetsAt.getTime() - Date.now());\n return e;\n }\n default:\n return new APIError(message, base);\n }\n}\n","/** Exponential backoff with full jitter. */\nexport function fullJitterBackoff(attempt: number, baseMs = 500, capMs = 8000): number {\n const exp = Math.min(capMs, baseMs * 2 ** attempt);\n return Math.random() * exp;\n}\n\n/** Sleep that rejects with an AbortError if the signal fires. */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(abortError());\n const onAbort = () => {\n cleanup();\n reject(abortError());\n };\n const cleanup = () => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", onAbort);\n };\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nexport function abortError(): Error {\n const e = new Error(\"The operation was aborted.\");\n e.name = \"AbortError\";\n return e;\n}\n\n/** Only 429 and 5xx are safe to retry. */\nexport function isRetryableStatus(status: number): boolean {\n return status === 429 || status >= 500;\n}\n","import type { FetchLike, RequestOptions } from \"../types/common\";\nimport {\n CurvetError,\n ConnectionError,\n RateLimitError,\n errorFromResponse,\n} from \"./errors\";\nimport { fullJitterBackoff, isRetryableStatus, sleep } from \"./retry\";\n\nexport interface HttpClientOptions {\n appKey: string;\n baseURL: string;\n timeout: number;\n maxRetries: number;\n fetch: FetchLike;\n}\n\nexport interface RequestArgs {\n method: string;\n path: string;\n body?: unknown;\n query?: Record<string, string | number | undefined>;\n options?: RequestOptions;\n}\n\n/**\n * The single place that knows about fetch, headers, base URL, error mapping,\n * and retries. Resources call `request()`; everything else stays mockable.\n */\nexport class HttpClient {\n constructor(private opts: HttpClientOptions) {}\n\n async request<T = any>(args: RequestArgs): Promise<T> {\n const { method, path, body, query, options } = args;\n const url = this.buildUrl(path, query);\n const maxRetries = options?.maxRetries ?? this.opts.maxRetries;\n const timeout = options?.timeout ?? this.opts.timeout;\n\n const headers: Record<string, string> = {\n \"x-app-key\": this.opts.appKey,\n accept: \"application/json\",\n ...(options?.headers ?? {}),\n };\n let payload: string | FormData | undefined;\n if (body !== undefined) {\n if (typeof FormData !== \"undefined\" && body instanceof FormData) {\n // Multipart — let fetch set the content-type (with boundary).\n payload = body;\n } else {\n headers[\"content-type\"] = \"application/json\";\n payload = JSON.stringify(body);\n }\n }\n\n let attempt = 0;\n for (;;) {\n const { signal, done } = this.makeSignal(timeout, options?.signal);\n try {\n const res = await this.opts.fetch(url, { method, headers, body: payload, signal });\n const text = await res.text();\n const parsed = text ? safeJson(text) : undefined;\n\n if (res.ok) return parsed as T;\n\n const requestId =\n res.headers.get(\"x-request-id\") ??\n (parsed as any)?.metadata?.requestId ??\n undefined;\n const err = errorFromResponse(res.status, parsed, requestId, res.headers);\n\n if (isRetryableStatus(res.status) && attempt < maxRetries) {\n await this.backoff(err, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw err;\n } catch (e: any) {\n if (e instanceof CurvetError) throw e;\n // AbortError: distinguish user-abort (rethrow) from our timeout (retry/ConnectionError).\n if (e?.name === \"AbortError\") {\n if (options?.signal?.aborted) throw e;\n if (attempt < maxRetries) {\n await this.backoff(undefined, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw new ConnectionError(\"Request timed out\", { raw: e });\n }\n // Network error before any response — safe to retry.\n if (attempt < maxRetries) {\n await this.backoff(undefined, attempt, options?.signal);\n attempt++;\n continue;\n }\n throw new ConnectionError(e?.message ?? \"Network request failed\", { raw: e });\n } finally {\n done();\n }\n }\n }\n\n private async backoff(err: CurvetError | undefined, attempt: number, signal?: AbortSignal) {\n let delay = fullJitterBackoff(attempt);\n if (err instanceof RateLimitError && err.retryAfterMs != null) {\n delay = Math.min(err.retryAfterMs, 30000);\n }\n await sleep(delay, signal);\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | undefined>) {\n const base = this.opts.baseURL.replace(/\\/$/, \"\");\n let url = base + (path.startsWith(\"/\") ? path : \"/\" + path);\n if (query) {\n const qs = Object.entries(query)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)\n .join(\"&\");\n if (qs) url += \"?\" + qs;\n }\n return url;\n }\n\n /** Combine a per-request timeout with an optional user AbortSignal. */\n private makeSignal(timeout: number, userSignal?: AbortSignal) {\n const controller = new AbortController();\n const onUserAbort = () => controller.abort();\n if (userSignal) {\n if (userSignal.aborted) controller.abort();\n else userSignal.addEventListener(\"abort\", onUserAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(), timeout);\n return {\n signal: controller.signal,\n done: () => {\n clearTimeout(timer);\n userSignal?.removeEventListener(\"abort\", onUserAbort);\n },\n };\n }\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ChatCreateParams, ChatResponse } from \"../types/chat\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport class Chat {\n constructor(private client: HttpClient) {}\n\n /** Create a chat completion. Synchronous — resolves with the model's reply. */\n create(params: ChatCreateParams, options?: RequestOptions): Promise<ChatResponse> {\n return this.client.request<ChatResponse>({\n method: \"POST\",\n path: \"/chat\",\n body: params,\n options,\n });\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ImageGenerateParams, ImageResponse } from \"../types/image\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport class Images {\n constructor(private client: HttpClient) {}\n\n /** Generate an image from a prompt. Synchronous — resolves with `imageUrl`. */\n generate(params: ImageGenerateParams, options?: RequestOptions): Promise<ImageResponse> {\n return this.client.request<ImageResponse>({\n method: \"POST\",\n path: \"/image\",\n body: params,\n options,\n });\n }\n}\n","import type { MediaJob, JobStatus } from \"../types/job\";\n\n/**\n * The API returns the output URL under three different keys depending on the\n * endpoint: `videoUrl` (/video), `audioUrl` (/audio), `modelUrl` (/3d), and\n * `output.mediaUrl` (GET /jobs/:id). Unify them.\n */\nfunction pickMediaUrl(body: Record<string, any>): string | undefined {\n return (\n body?.videoUrl ??\n body?.audioUrl ??\n body?.modelUrl ??\n body?.output?.mediaUrl ??\n body?.mediaUrl ??\n undefined\n );\n}\n\n/**\n * Normalize a POST /video|/audio|/3d response, which is EITHER a 200 with the\n * final media URL (job already done) OR a 202 with just a `jobId` to poll.\n */\nexport function normalizeMediaPost(body: unknown): MediaJob {\n const b = (body ?? {}) as Record<string, any>;\n const mediaUrl = pickMediaUrl(b);\n const jobId = b.jobId ?? b.metadata?.jobId;\n const status: JobStatus = mediaUrl\n ? \"completed\"\n : b.status === \"failed\"\n ? \"failed\"\n : \"processing\";\n return {\n jobId,\n status,\n mediaUrl,\n usage: b.usage,\n metadata: b.metadata,\n error: b.error ?? null,\n raw: body,\n };\n}\n\n/** Normalize a GET /jobs/:id response. */\nexport function normalizeJob(body: unknown): MediaJob {\n const b = (body ?? {}) as Record<string, any>;\n const mediaUrl = pickMediaUrl(b);\n const status: JobStatus = (b.status as JobStatus) ?? (mediaUrl ? \"completed\" : \"processing\");\n return {\n jobId: b.jobId,\n status,\n progress: b.progress,\n mediaUrl,\n metadata: b.output?.metadata ?? b.metadata,\n error: b.error ?? null,\n cost: b.cost,\n eta: b.eta,\n raw: body,\n };\n}\n","import { sleep } from \"./retry\";\n\n/** Thrown internally when a poll loop exceeds its timeout. */\nexport class PollTimeoutError extends Error {\n constructor(message = \"Polling timed out\") {\n super(message);\n this.name = \"PollTimeoutError\";\n }\n}\n\nexport interface PollConfig<T> {\n isTerminal: (result: T) => boolean;\n intervalMs: number;\n timeoutMs: number;\n signal?: AbortSignal;\n onTick?: (result: T) => void;\n}\n\n/**\n * Repeatedly call `fn` until `isTerminal` is true (resolves the result) or the\n * timeout elapses (throws PollTimeoutError). Polls immediately, then every\n * `intervalMs`. Honors an AbortSignal between ticks.\n */\nexport async function pollUntil<T>(fn: () => Promise<T>, cfg: PollConfig<T>): Promise<T> {\n const start = Date.now();\n for (;;) {\n const result = await fn();\n cfg.onTick?.(result);\n if (cfg.isTerminal(result)) return result;\n const elapsed = Date.now() - start;\n if (elapsed >= cfg.timeoutMs) throw new PollTimeoutError();\n const remaining = cfg.timeoutMs - elapsed;\n await sleep(Math.min(cfg.intervalMs, Math.max(0, remaining)), cfg.signal);\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { MediaJob, PollOptions } from \"../types/job\";\nimport type { RequestOptions } from \"../types/common\";\nimport { normalizeJob } from \"../core/normalize\";\nimport { pollUntil, PollTimeoutError } from \"../core/poll\";\nimport { JobFailedError, JobTimeoutError } from \"../core/errors\";\n\nexport interface JobDefaults {\n pollIntervalMs: number;\n pollTimeoutMs: number;\n}\n\nexport class Jobs {\n constructor(\n private client: HttpClient,\n private defaults: JobDefaults,\n ) {}\n\n /** Fetch the current status of an async job once (no polling). */\n async retrieve(jobId: string, options?: RequestOptions): Promise<MediaJob> {\n const body = await this.client.request({\n method: \"GET\",\n path: `/jobs/${encodeURIComponent(jobId)}`,\n options,\n });\n return normalizeJob(body);\n }\n\n /** Get a {@link Job} handle to poll/await an existing job by id. */\n handle(jobId: string): Job {\n return new Job(jobId, this.client, this.defaults);\n }\n}\n\n/** A handle to a single async media job. */\nexport class Job {\n constructor(\n readonly id: string,\n private client: HttpClient,\n private defaults: JobDefaults,\n ) {}\n\n /** One status fetch (no polling). */\n retrieve(options?: RequestOptions): Promise<MediaJob> {\n return new Jobs(this.client, this.defaults).retrieve(this.id, options);\n }\n\n /**\n * Poll until the job reaches a terminal state.\n * Resolves with the completed job, or throws JobFailedError / JobTimeoutError.\n */\n async wait(opts: PollOptions = {}): Promise<MediaJob> {\n const intervalMs = opts.pollIntervalMs ?? this.defaults.pollIntervalMs;\n const timeoutMs = opts.pollTimeoutMs ?? this.defaults.pollTimeoutMs;\n\n let result: MediaJob;\n try {\n result = await pollUntil(() => this.retrieve({ signal: opts.signal }), {\n intervalMs,\n timeoutMs,\n signal: opts.signal,\n isTerminal: (r) => r.status === \"completed\" || r.status === \"failed\",\n onTick: (r) => opts.onProgress?.(r.progress ?? 0, r.eta),\n });\n } catch (e) {\n if (e instanceof PollTimeoutError) {\n throw new JobTimeoutError(\n `Job ${this.id} did not complete within ${timeoutMs}ms`,\n this.id,\n );\n }\n throw e;\n }\n\n if (result.status === \"failed\") {\n throw new JobFailedError(result.error || `Job ${this.id} failed`, this.id, {\n raw: result.raw,\n });\n }\n return result;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { MediaJob, PollOptions } from \"../types/job\";\nimport type { RequestOptions } from \"../types/common\";\nimport { normalizeMediaPost } from \"../core/normalize\";\nimport { Job, type JobDefaults } from \"./jobs\";\nimport { CurvetError } from \"../core/errors\";\n\nexport interface MediaParamsBase {\n model: string;\n prompt: string;\n [key: string]: unknown;\n}\n\n/**\n * Generic engine for the async media endpoints (video / audio / 3d). They all\n * enqueue the same server-side job queue, so they share one implementation\n * parameterized by `path` and request param type.\n *\n * `generate()` submits and polls to completion; `submit()` fires without polling.\n */\nexport class MediaResource<P extends MediaParamsBase> {\n constructor(\n protected client: HttpClient,\n protected defaults: JobDefaults,\n protected path: string,\n ) {}\n\n /**\n * Submit WITHOUT polling. The media POST long-polls server-side and can block\n * well past a normal request timeout, so we default its timeout to the poll\n * budget and disable auto-retry (a retried POST would enqueue a duplicate job).\n */\n async submit(params: P, options?: RequestOptions): Promise<MediaJob> {\n const reqOptions: RequestOptions = {\n ...options,\n timeout: options?.timeout ?? this.defaults.pollTimeoutMs,\n maxRetries: options?.maxRetries ?? 0,\n };\n const body = await this.client.request({\n method: \"POST\",\n path: this.path,\n body: params,\n options: reqOptions,\n });\n return normalizeMediaPost(body);\n }\n\n /** Submit and resolve to the finished media (auto-polls /jobs/:id). */\n async generate(params: P, options?: RequestOptions & PollOptions): Promise<MediaJob> {\n const submitted = await this.submit(params, options);\n if (submitted.status === \"completed\" || submitted.status === \"failed\") {\n return submitted;\n }\n if (!submitted.jobId) {\n throw new CurvetError(\"Async job did not return a jobId to poll\", {\n raw: submitted.raw,\n });\n }\n const job = new Job(submitted.jobId, this.client, this.defaults);\n return job.wait({\n pollIntervalMs: options?.pollIntervalMs,\n pollTimeoutMs: options?.pollTimeoutMs,\n signal: options?.signal,\n onProgress: options?.onProgress,\n });\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { JobDefaults } from \"./jobs\";\nimport type { VideoGenerateParams } from \"../types/job\";\nimport { MediaResource } from \"./media\";\n\n/** Video generation (async). `curvet.video.generate(...)` auto-polls to completion. */\nexport class Video extends MediaResource<VideoGenerateParams> {\n constructor(client: HttpClient, defaults: JobDefaults) {\n super(client, defaults, \"/video\");\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { JobDefaults } from \"./jobs\";\nimport type { AudioGenerateParams } from \"../types/job\";\nimport { MediaResource } from \"./media\";\n\n/** Audio generation (async). `curvet.audio.generate(...)` auto-polls to completion. */\nexport class Audio extends MediaResource<AudioGenerateParams> {\n constructor(client: HttpClient, defaults: JobDefaults) {\n super(client, defaults, \"/audio\");\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { JobDefaults } from \"./jobs\";\nimport type { ThreeDGenerateParams } from \"../types/job\";\nimport { MediaResource } from \"./media\";\n\n/** 3D model generation (async). `curvet.threeD.generate(...)` auto-polls to completion. */\nexport class ThreeD extends MediaResource<ThreeDGenerateParams> {\n constructor(client: HttpClient, defaults: JobDefaults) {\n super(client, defaults, \"/3d\");\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { ModelInfo, RateLimits } from \"../types/models\";\nimport type { RequestOptions } from \"../types/common\";\n\ninterface ModelsListResponse {\n success: boolean;\n models: ModelInfo[];\n rateLimits: RateLimits;\n}\n\nexport interface ModelsListOptions extends RequestOptions {\n /** Filter to a single model type (e.g. \"chat\", \"image\", \"video\"). */\n type?: string;\n /** Bypass the in-memory cache and fetch fresh. */\n refresh?: boolean;\n}\n\n/**\n * Live model catalog. The list is dynamic and per-app filtered server-side, so\n * it is always fetched (with a short in-memory cache), never hardcoded.\n */\nexport class Models {\n private cache?: { at: number; data: ModelsListResponse };\n\n constructor(\n private client: HttpClient,\n private cacheTtlMs = 60_000,\n ) {}\n\n private async load(options?: RequestOptions): Promise<ModelsListResponse> {\n return this.client.request<ModelsListResponse>({\n method: \"GET\",\n path: \"/models\",\n options,\n });\n }\n\n private async ensure(options?: ModelsListOptions): Promise<ModelsListResponse> {\n const stale = !this.cache || Date.now() - this.cache.at > this.cacheTtlMs;\n if (options?.refresh || stale) {\n this.cache = { at: Date.now(), data: await this.load(options) };\n }\n return this.cache!.data;\n }\n\n /** List available models, optionally filtered by `type`. */\n async list(options?: ModelsListOptions): Promise<ModelInfo[]> {\n const data = await this.ensure(options);\n const models = data.models ?? [];\n return options?.type ? models.filter((m) => m.type === options.type) : models;\n }\n\n /** Find a single model by id (or undefined). */\n async get(id: string, options?: ModelsListOptions): Promise<ModelInfo | undefined> {\n return (await this.list(options)).find((m) => m.id === id);\n }\n\n /** The app's rate limits as reported by GET /models. */\n async rateLimits(options?: ModelsListOptions): Promise<RateLimits | undefined> {\n return (await this.ensure(options)).rateLimits;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport interface BalanceInfo {\n walletBalance?: number;\n totalAvailableUSD: number;\n totalPoints?: number;\n breakdown?: {\n walletCredits?: number;\n totalCredits?: number;\n organizationLimit?: number;\n monthlyUsed?: number;\n isEnterprise?: boolean;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nexport class Balance {\n constructor(private client: HttpClient) {}\n\n /** Get the current credit balance for the app owner. */\n async get(options?: RequestOptions): Promise<BalanceInfo> {\n const body = await this.client.request<{ success: boolean; balance: BalanceInfo }>({\n method: \"GET\",\n path: \"/balance\",\n options,\n });\n return body.balance;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport interface AnalyticsParams extends RequestOptions {\n /** ISO 8601 start date. */\n startDate?: string;\n /** ISO 8601 end date. */\n endDate?: string;\n}\n\nexport interface AnalyticsResult {\n totalRequests?: number;\n totalCost?: number;\n requestsByModel?: Record<string, number>;\n requestsByCategory?: Record<string, number>;\n [key: string]: unknown;\n}\n\nexport class Analytics {\n constructor(private client: HttpClient) {}\n\n /** Usage analytics for the app, optionally bounded by a date range. */\n async get(params: AnalyticsParams = {}): Promise<AnalyticsResult> {\n const { startDate, endDate, ...options } = params;\n const body = await this.client.request<{ success: boolean; analytics: AnalyticsResult }>({\n method: \"GET\",\n path: \"/analytics\",\n query: { startDate, endDate },\n options,\n });\n return body.analytics;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\nimport { pollUntil, PollTimeoutError } from \"../core/poll\";\nimport {\n CurvetError,\n WorkflowRunFailedError,\n WorkflowRunTimeoutError,\n} from \"../core/errors\";\n\nexport interface WorkflowRunParams {\n /** Input values for the workflow. */\n inputs?: Record<string, unknown>;\n /** Optional file inputs, keyed by the workflow's file field name. */\n files?: Record<string, Blob>;\n /** Include the full execution state in the response (default true server-side). */\n includeFullState?: boolean;\n}\n\n/** Result of a synchronous `run()` call. */\nexport interface WorkflowRunResult {\n success: boolean;\n [key: string]: unknown;\n}\n\nexport type WorkflowRunStatus =\n | \"queued\"\n | \"running\"\n | \"completed\"\n | \"failed\"\n | \"stopped\";\n\nexport interface WorkflowRunNode {\n nodeId: string;\n nodeLabel?: string;\n nodeType?: string;\n status?: string;\n executionTime?: number;\n}\n\n/** Normalized status of an async (pollable) workflow run. */\nexport interface WorkflowRun {\n runId: string;\n status: WorkflowRunStatus;\n progress?: number;\n totalNodes?: number;\n completedNodeCount?: number;\n /** The node currently executing (null when finished/queued). */\n currentNode?: { id: string; label?: string; type?: string } | null;\n nodesExecuted?: WorkflowRunNode[];\n /** Final outputs (present once completed). */\n result?: unknown;\n error?: string | null;\n startTime?: string;\n endTime?: string;\n /** Raw, unnormalized response body. */\n raw: unknown;\n}\n\nexport interface WorkflowSubmitResult {\n runId: string;\n status: WorkflowRunStatus;\n raw: unknown;\n}\n\nexport interface WorkflowPollOptions {\n /** Poll interval in ms (default 2500). */\n pollIntervalMs?: number;\n /** Total poll timeout in ms before throwing WorkflowRunTimeoutError (default 300000). */\n pollTimeoutMs?: number;\n signal?: AbortSignal;\n /** Called on each poll tick with the latest run status (current node, progress). */\n onProgress?: (run: WorkflowRun) => void;\n}\n\nfunction normalizeRun(body: unknown): WorkflowRun {\n const b = (body ?? {}) as Record<string, any>;\n return {\n runId: b.runId,\n status: b.status,\n progress: b.progress,\n totalNodes: b.totalNodes,\n completedNodeCount: b.completedNodeCount,\n currentNode: b.currentNode ?? null,\n nodesExecuted: b.nodesExecuted,\n result: b.result,\n error: b.error ?? null,\n startTime: b.startTime,\n endTime: b.endTime,\n raw: body,\n };\n}\n\nfunction buildBody(params: WorkflowRunParams, extra: Record<string, unknown> = {}) {\n const hasFiles = params.files && Object.keys(params.files).length > 0;\n if (hasFiles) {\n const form = new FormData();\n form.append(\"inputs\", JSON.stringify(params.inputs ?? {}));\n if (params.includeFullState !== undefined) {\n form.append(\"includeFullState\", String(params.includeFullState));\n }\n for (const [k, v] of Object.entries(extra)) form.append(k, String(v));\n for (const [field, file] of Object.entries(params.files!)) {\n form.append(field, file);\n }\n return form;\n }\n return {\n inputs: params.inputs ?? {},\n includeFullState: params.includeFullState,\n ...extra,\n };\n}\n\n/** Retrieve async workflow-run status. */\nexport class WorkflowRuns {\n constructor(private client: HttpClient) {}\n\n /** Fetch the current status of an async run once (no polling). */\n async retrieve(runId: string, options?: RequestOptions): Promise<WorkflowRun> {\n const body = await this.client.request({\n method: \"GET\",\n path: `/workflows/runs/${encodeURIComponent(runId)}`,\n options,\n });\n return normalizeRun(body);\n }\n}\n\nexport class Workflows {\n readonly runs: WorkflowRuns;\n\n constructor(private client: HttpClient) {\n this.runs = new WorkflowRuns(client);\n }\n\n /**\n * Execute a workflow synchronously (blocks until it finishes). Best for short\n * workflows; for long ones (video/audio/3D nodes) prefer `runAndPoll`.\n * Sends JSON, or multipart/form-data when file inputs are provided.\n */\n async run(\n id: string,\n params: WorkflowRunParams = {},\n options?: RequestOptions,\n ): Promise<WorkflowRunResult> {\n const reqOptions: RequestOptions = { ...options, maxRetries: options?.maxRetries ?? 0 };\n return this.client.request<WorkflowRunResult>({\n method: \"POST\",\n path: `/workflows/${encodeURIComponent(id)}/run`,\n body: buildBody(params),\n options: reqOptions,\n });\n }\n\n /**\n * Submit a workflow in async (pollable) mode — returns immediately with a\n * runId. Poll `runs.retrieve(runId)` for status, or use `runAndPoll`.\n */\n async submit(\n id: string,\n params: WorkflowRunParams = {},\n options?: RequestOptions,\n ): Promise<WorkflowSubmitResult> {\n const reqOptions: RequestOptions = { ...options, maxRetries: options?.maxRetries ?? 0 };\n const res = await this.client.request<Record<string, any>>({\n method: \"POST\",\n path: `/workflows/${encodeURIComponent(id)}/run`,\n body: buildBody(params, { async: true }),\n options: reqOptions,\n });\n return { runId: res?.runId, status: res?.status ?? \"running\", raw: res };\n }\n\n /**\n * Submit and poll to completion. Resolves with the completed run (including\n * `result`), reporting progress via `onProgress`. Throws WorkflowRunFailedError\n * on failure, WorkflowRunTimeoutError on timeout.\n */\n async runAndPoll(\n id: string,\n params: WorkflowRunParams = {},\n opts: RequestOptions & WorkflowPollOptions = {},\n ): Promise<WorkflowRun> {\n const submitted = await this.submit(id, params, opts);\n if (!submitted.runId) {\n throw new CurvetError(\"Workflow submit did not return a runId\", {\n raw: submitted.raw,\n });\n }\n\n const intervalMs = opts.pollIntervalMs ?? 2500;\n const timeoutMs = opts.pollTimeoutMs ?? 300_000;\n\n let run: WorkflowRun;\n try {\n run = await pollUntil(\n () => this.runs.retrieve(submitted.runId, { signal: opts.signal }),\n {\n intervalMs,\n timeoutMs,\n signal: opts.signal,\n isTerminal: (r) =>\n r.status === \"completed\" || r.status === \"failed\" || r.status === \"stopped\",\n onTick: (r) => opts.onProgress?.(r),\n },\n );\n } catch (e) {\n if (e instanceof PollTimeoutError) {\n throw new WorkflowRunTimeoutError(\n `Workflow run ${submitted.runId} did not finish within ${timeoutMs}ms`,\n submitted.runId,\n );\n }\n throw e;\n }\n\n if (run.status === \"failed\" || run.status === \"stopped\") {\n throw new WorkflowRunFailedError(\n run.error || `Workflow run ${submitted.runId} ${run.status}`,\n submitted.runId,\n { raw: run.raw },\n );\n }\n return run;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport interface FoodItem {\n [key: string]: unknown;\n}\n\n/**\n * Indian Food Dataset API. Mounted as a sibling of the playground under\n * `/api/v1/food`, so it uses the v1-root HTTP client. Requires the app to have\n * Food API access enabled.\n */\nexport class Food {\n constructor(private client: HttpClient) {}\n\n /** List dishes (default limit 20). */\n async list(opts?: { limit?: number } & RequestOptions): Promise<FoodItem[]> {\n const { limit, ...options } = opts ?? {};\n const body = await this.client.request<{ success: boolean; data: FoodItem[]; count: number }>({\n method: \"GET\",\n path: \"/food\",\n query: { limit },\n options,\n });\n return body.data;\n }\n\n /** Full-text search for dishes. */\n async search(query: string, opts?: { limit?: number } & RequestOptions): Promise<FoodItem[]> {\n const { limit, ...options } = opts ?? {};\n const body = await this.client.request<{ success: boolean; data: FoodItem[] }>({\n method: \"GET\",\n path: \"/food/search\",\n query: { q: query, limit },\n options,\n });\n return body.data;\n }\n\n /** Natural-language dish recommendations. */\n async recommendations(prompt: string, options?: RequestOptions): Promise<FoodItem[]> {\n const body = await this.client.request<{ success: boolean; data: FoodItem[] }>({\n method: \"POST\",\n path: \"/food/recommendations\",\n body: { prompt },\n options,\n });\n return body.data;\n }\n}\n","import type { HttpClient } from \"../core/http\";\nimport type { RequestOptions } from \"../types/common\";\n\nexport interface SttParams {\n /** The audio to transcribe. */\n audio: Blob | Uint8Array | ArrayBuffer;\n /** File name for the upload (default \"audio\"). */\n filename?: string;\n provider?: \"elevenlabs\" | \"deepinfra\" | (string & {});\n /** ASR model id (provider-specific; optional). */\n model?: string;\n prompt?: string;\n /** ISO 639-1 language hint. */\n languageCode?: string;\n allowFallback?: boolean;\n}\n\nexport interface SttResult {\n success: boolean;\n text: string;\n languageCode?: string;\n segments?: Array<{ start: number; end: number; text: string }>;\n provider?: string;\n creditsCharged?: number;\n creditsRemaining?: number;\n [key: string]: unknown;\n}\n\n/**\n * Public speech-to-text. Mounted as a sibling of the playground under\n * `/api/v1/voice`, so it uses the v1-root HTTP client. Multipart upload; not\n * auto-retried (it consumes credits).\n */\nexport class Voice {\n constructor(private client: HttpClient) {}\n\n async stt(params: SttParams, options?: RequestOptions): Promise<SttResult> {\n const form = new FormData();\n form.append(\"audio\", toBlob(params.audio), params.filename ?? \"audio\");\n if (params.provider) form.append(\"provider\", params.provider);\n if (params.model) form.append(\"model\", params.model);\n if (params.prompt) form.append(\"prompt\", params.prompt);\n if (params.languageCode) form.append(\"languageCode\", params.languageCode);\n if (params.allowFallback !== undefined) {\n form.append(\"allowFallback\", String(params.allowFallback));\n }\n\n const reqOptions: RequestOptions = {\n ...options,\n timeout: options?.timeout ?? 120_000,\n maxRetries: options?.maxRetries ?? 0,\n };\n return this.client.request<SttResult>({\n method: \"POST\",\n path: \"/voice/stt/public\",\n body: form,\n options: reqOptions,\n });\n }\n}\n\nfunction toBlob(audio: Blob | Uint8Array | ArrayBuffer): Blob {\n if (typeof Blob !== \"undefined\" && audio instanceof Blob) return audio;\n return new Blob([audio] as ConstructorParameters<typeof Blob>[0]);\n}\n","import { HttpClient } from \"./core/http\";\nimport { CurvetError } from \"./core/errors\";\nimport type { FetchLike } from \"./types/common\";\nimport { Chat } from \"./resources/chat\";\nimport { Images } from \"./resources/image\";\nimport { Video } from \"./resources/video\";\nimport { Audio } from \"./resources/audio\";\nimport { ThreeD } from \"./resources/threeD\";\nimport { Jobs } from \"./resources/jobs\";\nimport { Models } from \"./resources/models\";\nimport { Balance } from \"./resources/balance\";\nimport { Analytics } from \"./resources/analytics\";\nimport { Workflows } from \"./resources/workflows\";\nimport { Food } from \"./resources/food\";\nimport { Voice } from \"./resources/voice\";\n\nexport const DEFAULT_BASE_URL = \"https://curvet.ai/api/v1/playground\";\n\nexport interface CurvetOptions {\n /** Your app key. Falls back to the CURVET_APP_KEY env var. */\n appKey?: string;\n /** Override the playground base URL (defaults to production). */\n baseURL?: string;\n /** Per-request timeout in ms (default 60000). */\n timeout?: number;\n /** Max automatic retries for 429/5xx and network errors (default 2). */\n maxRetries?: number;\n /** Inject a fetch implementation (defaults to global fetch on Node 18+). */\n fetch?: FetchLike;\n /** Default poll interval for async media jobs, in ms (default 2500). */\n defaultPollIntervalMs?: number;\n /** Default poll timeout for async media jobs, in ms (default 180000). */\n defaultPollTimeoutMs?: number;\n}\n\n/**\n * The Curvet client. One instance per app key.\n *\n * ```ts\n * const curvet = new Curvet({ appKey: process.env.CURVET_APP_KEY });\n * const { response } = await curvet.chat.create({\n * model: \"gpt-4o-mini\",\n * messages: [{ role: \"user\", content: \"hi\" }],\n * });\n * ```\n */\nexport class Curvet {\n readonly chat: Chat;\n readonly image: Images;\n readonly video: Video;\n readonly audio: Audio;\n readonly threeD: ThreeD;\n readonly jobs: Jobs;\n readonly models: Models;\n readonly balance: Balance;\n readonly analytics: Analytics;\n readonly workflows: Workflows;\n readonly food: Food;\n readonly voice: Voice;\n\n constructor(options: CurvetOptions = {}) {\n const appKey = options.appKey ?? envKey();\n if (!appKey) {\n throw new CurvetError(\n \"Missing Curvet app key. Pass { appKey } or set the CURVET_APP_KEY environment variable.\",\n );\n }\n const fetchImpl = options.fetch ?? defaultFetch();\n if (!fetchImpl) {\n throw new CurvetError(\n \"No fetch implementation available. Use Node 18+ or pass { fetch }.\",\n );\n }\n\n const playgroundBase = options.baseURL ?? DEFAULT_BASE_URL;\n // Sibling routes (food, voice) live one level up at /api/v1/*.\n const v1Base = playgroundBase.replace(/\\/playground\\/?$/, \"\");\n\n const shared = {\n appKey,\n timeout: options.timeout ?? 60_000,\n maxRetries: options.maxRetries ?? 2,\n fetch: fetchImpl,\n };\n const client = new HttpClient({ ...shared, baseURL: playgroundBase });\n const v1Client = new HttpClient({ ...shared, baseURL: v1Base });\n\n const jobDefaults = {\n pollIntervalMs: options.defaultPollIntervalMs ?? 2500,\n pollTimeoutMs: options.defaultPollTimeoutMs ?? 180_000,\n };\n\n this.chat = new Chat(client);\n this.image = new Images(client);\n this.jobs = new Jobs(client, jobDefaults);\n this.video = new Video(client, jobDefaults);\n this.audio = new Audio(client, jobDefaults);\n this.threeD = new ThreeD(client, jobDefaults);\n this.models = new Models(client);\n this.balance = new Balance(client);\n this.analytics = new Analytics(client);\n this.workflows = new Workflows(client);\n this.food = new Food(v1Client);\n this.voice = new Voice(v1Client);\n }\n}\n\nfunction envKey(): string | undefined {\n return typeof process !== \"undefined\" ? process.env?.CURVET_APP_KEY : undefined;\n}\n\nfunction defaultFetch(): FetchLike | undefined {\n const f = (globalThis as { fetch?: unknown }).fetch;\n return typeof f === \"function\" ? (f.bind(globalThis) as FetchLike) : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,IAAM,cAAN,cAA0B,MAAM;AAAA,EAKrC,YAAY,SAAiB,OAA2B,CAAC,GAAG;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AACvB,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,KAAK;AACtB,SAAK,MAAM,KAAK;AAEhB,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,IAAM,YAAN,cAAwB,YAAY;AAAC;AAErC,IAAM,kBAAN,cAA8B,YAAY;AAAC;AAE3C,IAAM,kBAAN,cAA8B,YAAY;AAAC;AAE3C,IAAM,gBAAN,cAA4B,YAAY;AAAC;AAEzC,IAAM,WAAN,cAAuB,YAAY;AAAC;AAEpC,IAAM,kBAAN,cAA8B,YAAY;AAAC;AAG3C,IAAM,2BAAN,cAAuC,YAAY;AAG1D;AAGO,IAAM,iBAAN,cAA6B,YAAY;AAMhD;AAGO,IAAM,iBAAN,cAA6B,YAAY;AAAA,EAE9C,YAAY,SAAiB,OAAe,OAA2B,CAAC,GAAG;AACzE,UAAM,SAAS,IAAI;AACnB,SAAK,QAAQ;AAAA,EACf;AACF;AAGO,IAAM,kBAAN,cAA8B,YAAY;AAAA,EAE/C,YAAY,SAAiB,OAAe,OAA2B,CAAC,GAAG;AACzE,UAAM,SAAS,IAAI;AACnB,SAAK,QAAQ;AAAA,EACf;AACF;AAGO,IAAM,yBAAN,cAAqC,YAAY;AAAA,EAEtD,YAAY,SAAiB,OAAe,OAA2B,CAAC,GAAG;AACzE,UAAM,SAAS,IAAI;AACnB,SAAK,QAAQ;AAAA,EACf;AACF;AAGO,IAAM,0BAAN,cAAsC,YAAY;AAAA,EAEvD,YAAY,SAAiB,OAAe,OAA2B,CAAC,GAAG;AACzE,UAAM,SAAS,IAAI;AACnB,SAAK,QAAQ;AAAA,EACf;AACF;AAOO,SAAS,kBACd,QACA,MACA,WACA,SACa;AACb,QAAM,IAAK,QAAQ,CAAC;AACpB,QAAM,UACJ,OAAO,EAAE,UAAU,WAAW,EAAE,QAAQ,QAAQ,MAAM;AACxD,QAAM,OAA2B,EAAE,QAAQ,WAAW,KAAK,KAAK;AAEhE,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,IAAI,gBAAgB,SAAS,IAAI;AAAA,IAC1C,KAAK;AACH,aAAO,IAAI,UAAU,SAAS,IAAI;AAAA,IACpC,KAAK,KAAK;AACR,YAAM,IAAI,IAAI,yBAAyB,SAAS,IAAI;AACpD,QAAE,WAAW,EAAE;AACf,QAAE,YAAY,EAAE;AAChB,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,IAAI,gBAAgB,SAAS,IAAI;AAAA,IAC1C,KAAK;AACH,aAAO,IAAI,cAAc,SAAS,IAAI;AAAA,IACxC,KAAK,KAAK;AACR,YAAM,IAAI,IAAI,eAAe,SAAS,IAAI;AAC1C,YAAM,OAAO,EAAE,iBAAiB,EAAE;AAClC,QAAE,OAAO,EAAE,cAAc,SAAS;AAClC,UAAI,MAAM;AACR,UAAE,QAAQ,KAAK;AACf,UAAE,OAAO,KAAK;AACd,YAAI,KAAK,SAAU,GAAE,WAAW,IAAI,KAAK,KAAK,QAAQ;AAAA,MACxD;AACA,YAAM,aAAa,SAAS,MAAM,aAAa;AAC/C,UAAI,MAAM,YAAY,KAAM,GAAE,eAAe,OAAO,KAAK,QAAQ,IAAI;AAAA,eAC5D,WAAY,GAAE,eAAe,OAAO,UAAU,IAAI;AAAA,eAClD,EAAE,SAAU,GAAE,eAAe,KAAK,IAAI,GAAG,EAAE,SAAS,QAAQ,IAAI,KAAK,IAAI,CAAC;AACnF,aAAO;AAAA,IACT;AAAA,IACA;AACE,aAAO,IAAI,SAAS,SAAS,IAAI;AAAA,EACrC;AACF;;;ACvIO,SAAS,kBAAkB,SAAiB,SAAS,KAAK,QAAQ,KAAc;AACrF,QAAM,MAAM,KAAK,IAAI,OAAO,SAAS,KAAK,OAAO;AACjD,SAAO,KAAK,OAAO,IAAI;AACzB;AAGO,SAAS,MAAM,IAAY,QAAqC;AACrE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,QAAQ,QAAS,QAAO,OAAO,WAAW,CAAC;AAC/C,UAAM,UAAU,MAAM;AACpB,cAAQ;AACR,aAAO,WAAW,CAAC;AAAA,IACrB;AACA,UAAM,UAAU,MAAM;AACpB,mBAAa,KAAK;AAClB,cAAQ,oBAAoB,SAAS,OAAO;AAAA,IAC9C;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ;AACR,cAAQ;AAAA,IACV,GAAG,EAAE;AACL,YAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,EAC3D,CAAC;AACH;AAEO,SAAS,aAAoB;AAClC,QAAM,IAAI,IAAI,MAAM,4BAA4B;AAChD,IAAE,OAAO;AACT,SAAO;AACT;AAGO,SAAS,kBAAkB,QAAyB;AACzD,SAAO,WAAW,OAAO,UAAU;AACrC;;;ACNO,IAAM,aAAN,MAAiB;AAAA,EACtB,YAAoB,MAAyB;AAAzB;AAAA,EAA0B;AAAA,EAE9C,MAAM,QAAiB,MAA+B;AACpD,UAAM,EAAE,QAAQ,MAAM,MAAM,OAAO,QAAQ,IAAI;AAC/C,UAAM,MAAM,KAAK,SAAS,MAAM,KAAK;AACrC,UAAM,aAAa,SAAS,cAAc,KAAK,KAAK;AACpD,UAAM,UAAU,SAAS,WAAW,KAAK,KAAK;AAE9C,UAAM,UAAkC;AAAA,MACtC,aAAa,KAAK,KAAK;AAAA,MACvB,QAAQ;AAAA,MACR,GAAI,SAAS,WAAW,CAAC;AAAA,IAC3B;AACA,QAAI;AACJ,QAAI,SAAS,QAAW;AACtB,UAAI,OAAO,aAAa,eAAe,gBAAgB,UAAU;AAE/D,kBAAU;AAAA,MACZ,OAAO;AACL,gBAAQ,cAAc,IAAI;AAC1B,kBAAU,KAAK,UAAU,IAAI;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI,UAAU;AACd,eAAS;AACP,YAAM,EAAE,QAAQ,KAAK,IAAI,KAAK,WAAW,SAAS,SAAS,MAAM;AACjE,UAAI;AACF,cAAM,MAAM,MAAM,KAAK,KAAK,MAAM,KAAK,EAAE,QAAQ,SAAS,MAAM,SAAS,OAAO,CAAC;AACjF,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,cAAM,SAAS,OAAO,SAAS,IAAI,IAAI;AAEvC,YAAI,IAAI,GAAI,QAAO;AAEnB,cAAM,YACJ,IAAI,QAAQ,IAAI,cAAc,KAC7B,QAAgB,UAAU,aAC3B;AACF,cAAM,MAAM,kBAAkB,IAAI,QAAQ,QAAQ,WAAW,IAAI,OAAO;AAExE,YAAI,kBAAkB,IAAI,MAAM,KAAK,UAAU,YAAY;AACzD,gBAAM,KAAK,QAAQ,KAAK,SAAS,SAAS,MAAM;AAChD;AACA;AAAA,QACF;AACA,cAAM;AAAA,MACR,SAAS,GAAQ;AACf,YAAI,aAAa,YAAa,OAAM;AAEpC,YAAI,GAAG,SAAS,cAAc;AAC5B,cAAI,SAAS,QAAQ,QAAS,OAAM;AACpC,cAAI,UAAU,YAAY;AACxB,kBAAM,KAAK,QAAQ,QAAW,SAAS,SAAS,MAAM;AACtD;AACA;AAAA,UACF;AACA,gBAAM,IAAI,gBAAgB,qBAAqB,EAAE,KAAK,EAAE,CAAC;AAAA,QAC3D;AAEA,YAAI,UAAU,YAAY;AACxB,gBAAM,KAAK,QAAQ,QAAW,SAAS,SAAS,MAAM;AACtD;AACA;AAAA,QACF;AACA,cAAM,IAAI,gBAAgB,GAAG,WAAW,0BAA0B,EAAE,KAAK,EAAE,CAAC;AAAA,MAC9E,UAAE;AACA,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,QAAQ,KAA8B,SAAiB,QAAsB;AACzF,QAAI,QAAQ,kBAAkB,OAAO;AACrC,QAAI,eAAe,kBAAkB,IAAI,gBAAgB,MAAM;AAC7D,cAAQ,KAAK,IAAI,IAAI,cAAc,GAAK;AAAA,IAC1C;AACA,UAAM,MAAM,OAAO,MAAM;AAAA,EAC3B;AAAA,EAEQ,SAAS,MAAc,OAAqD;AAClF,UAAM,OAAO,KAAK,KAAK,QAAQ,QAAQ,OAAO,EAAE;AAChD,QAAI,MAAM,QAAQ,KAAK,WAAW,GAAG,IAAI,OAAO,MAAM;AACtD,QAAI,OAAO;AACT,YAAM,KAAK,OAAO,QAAQ,KAAK,EAC5B,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAS,EACjC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,mBAAmB,CAAC,CAAC,IAAI,mBAAmB,OAAO,CAAC,CAAC,CAAC,EAAE,EAC3E,KAAK,GAAG;AACX,UAAI,GAAI,QAAO,MAAM;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,WAAW,SAAiB,YAA0B;AAC5D,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,cAAc,MAAM,WAAW,MAAM;AAC3C,QAAI,YAAY;AACd,UAAI,WAAW,QAAS,YAAW,MAAM;AAAA,UACpC,YAAW,iBAAiB,SAAS,aAAa,EAAE,MAAM,KAAK,CAAC;AAAA,IACvE;AACA,UAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO;AAC1D,WAAO;AAAA,MACL,QAAQ,WAAW;AAAA,MACnB,MAAM,MAAM;AACV,qBAAa,KAAK;AAClB,oBAAY,oBAAoB,SAAS,WAAW;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,SAAS,MAAuB;AACvC,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC/IO,IAAM,OAAN,MAAW;AAAA,EAChB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,OAAO,QAA0B,SAAiD;AAChF,WAAO,KAAK,OAAO,QAAsB;AAAA,MACvC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACZO,IAAM,SAAN,MAAa;AAAA,EAClB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,SAAS,QAA6B,SAAkD;AACtF,WAAO,KAAK,OAAO,QAAuB;AAAA,MACxC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACTA,SAAS,aAAa,MAA+C;AACnE,SACE,MAAM,YACN,MAAM,YACN,MAAM,YACN,MAAM,QAAQ,YACd,MAAM,YACN;AAEJ;AAMO,SAAS,mBAAmB,MAAyB;AAC1D,QAAM,IAAK,QAAQ,CAAC;AACpB,QAAM,WAAW,aAAa,CAAC;AAC/B,QAAM,QAAQ,EAAE,SAAS,EAAE,UAAU;AACrC,QAAM,SAAoB,WACtB,cACA,EAAE,WAAW,WACX,WACA;AACN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,EAAE;AAAA,IACT,UAAU,EAAE;AAAA,IACZ,OAAO,EAAE,SAAS;AAAA,IAClB,KAAK;AAAA,EACP;AACF;AAGO,SAAS,aAAa,MAAyB;AACpD,QAAM,IAAK,QAAQ,CAAC;AACpB,QAAM,WAAW,aAAa,CAAC;AAC/B,QAAM,SAAqB,EAAE,WAAyB,WAAW,cAAc;AAC/E,SAAO;AAAA,IACL,OAAO,EAAE;AAAA,IACT;AAAA,IACA,UAAU,EAAE;AAAA,IACZ;AAAA,IACA,UAAU,EAAE,QAAQ,YAAY,EAAE;AAAA,IAClC,OAAO,EAAE,SAAS;AAAA,IAClB,MAAM,EAAE;AAAA,IACR,KAAK,EAAE;AAAA,IACP,KAAK;AAAA,EACP;AACF;;;ACvDO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,UAAU,qBAAqB;AACzC,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAeA,eAAsB,UAAa,IAAsB,KAAgC;AACvF,QAAM,QAAQ,KAAK,IAAI;AACvB,aAAS;AACP,UAAM,SAAS,MAAM,GAAG;AACxB,QAAI,SAAS,MAAM;AACnB,QAAI,IAAI,WAAW,MAAM,EAAG,QAAO;AACnC,UAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,QAAI,WAAW,IAAI,UAAW,OAAM,IAAI,iBAAiB;AACzD,UAAM,YAAY,IAAI,YAAY;AAClC,UAAM,MAAM,KAAK,IAAI,IAAI,YAAY,KAAK,IAAI,GAAG,SAAS,CAAC,GAAG,IAAI,MAAM;AAAA,EAC1E;AACF;;;ACtBO,IAAM,OAAN,MAAW;AAAA,EAChB,YACU,QACA,UACR;AAFQ;AACA;AAAA,EACP;AAAA;AAAA,EAGH,MAAM,SAAS,OAAe,SAA6C;AACzE,UAAM,OAAO,MAAM,KAAK,OAAO,QAAQ;AAAA,MACrC,QAAQ;AAAA,MACR,MAAM,SAAS,mBAAmB,KAAK,CAAC;AAAA,MACxC;AAAA,IACF,CAAC;AACD,WAAO,aAAa,IAAI;AAAA,EAC1B;AAAA;AAAA,EAGA,OAAO,OAAoB;AACzB,WAAO,IAAI,IAAI,OAAO,KAAK,QAAQ,KAAK,QAAQ;AAAA,EAClD;AACF;AAGO,IAAM,MAAN,MAAU;AAAA,EACf,YACW,IACD,QACA,UACR;AAHS;AACD;AACA;AAAA,EACP;AAAA;AAAA,EAGH,SAAS,SAA6C;AACpD,WAAO,IAAI,KAAK,KAAK,QAAQ,KAAK,QAAQ,EAAE,SAAS,KAAK,IAAI,OAAO;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAK,OAAoB,CAAC,GAAsB;AACpD,UAAM,aAAa,KAAK,kBAAkB,KAAK,SAAS;AACxD,UAAM,YAAY,KAAK,iBAAiB,KAAK,SAAS;AAEtD,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,UAAU,MAAM,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG;AAAA,QACrE;AAAA,QACA;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,YAAY,CAAC,MAAM,EAAE,WAAW,eAAe,EAAE,WAAW;AAAA,QAC5D,QAAQ,CAAC,MAAM,KAAK,aAAa,EAAE,YAAY,GAAG,EAAE,GAAG;AAAA,MACzD,CAAC;AAAA,IACH,SAAS,GAAG;AACV,UAAI,aAAa,kBAAkB;AACjC,cAAM,IAAI;AAAA,UACR,OAAO,KAAK,EAAE,4BAA4B,SAAS;AAAA,UACnD,KAAK;AAAA,QACP;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAEA,QAAI,OAAO,WAAW,UAAU;AAC9B,YAAM,IAAI,eAAe,OAAO,SAAS,OAAO,KAAK,EAAE,WAAW,KAAK,IAAI;AAAA,QACzE,KAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACF;;;AC7DO,IAAM,gBAAN,MAA+C;AAAA,EACpD,YACY,QACA,UACA,MACV;AAHU;AACA;AACA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOH,MAAM,OAAO,QAAW,SAA6C;AACnE,UAAM,aAA6B;AAAA,MACjC,GAAG;AAAA,MACH,SAAS,SAAS,WAAW,KAAK,SAAS;AAAA,MAC3C,YAAY,SAAS,cAAc;AAAA,IACrC;AACA,UAAM,OAAO,MAAM,KAAK,OAAO,QAAQ;AAAA,MACrC,QAAQ;AAAA,MACR,MAAM,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AACD,WAAO,mBAAmB,IAAI;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,SAAS,QAAW,SAA2D;AACnF,UAAM,YAAY,MAAM,KAAK,OAAO,QAAQ,OAAO;AACnD,QAAI,UAAU,WAAW,eAAe,UAAU,WAAW,UAAU;AACrE,aAAO;AAAA,IACT;AACA,QAAI,CAAC,UAAU,OAAO;AACpB,YAAM,IAAI,YAAY,4CAA4C;AAAA,QAChE,KAAK,UAAU;AAAA,MACjB,CAAC;AAAA,IACH;AACA,UAAM,MAAM,IAAI,IAAI,UAAU,OAAO,KAAK,QAAQ,KAAK,QAAQ;AAC/D,WAAO,IAAI,KAAK;AAAA,MACd,gBAAgB,SAAS;AAAA,MACzB,eAAe,SAAS;AAAA,MACxB,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,IACvB,CAAC;AAAA,EACH;AACF;;;AC5DO,IAAM,QAAN,cAAoB,cAAmC;AAAA,EAC5D,YAAY,QAAoB,UAAuB;AACrD,UAAM,QAAQ,UAAU,QAAQ;AAAA,EAClC;AACF;;;ACJO,IAAM,QAAN,cAAoB,cAAmC;AAAA,EAC5D,YAAY,QAAoB,UAAuB;AACrD,UAAM,QAAQ,UAAU,QAAQ;AAAA,EAClC;AACF;;;ACJO,IAAM,SAAN,cAAqB,cAAoC;AAAA,EAC9D,YAAY,QAAoB,UAAuB;AACrD,UAAM,QAAQ,UAAU,KAAK;AAAA,EAC/B;AACF;;;ACWO,IAAM,SAAN,MAAa;AAAA,EAGlB,YACU,QACA,aAAa,KACrB;AAFQ;AACA;AAAA,EACP;AAAA,EAEH,MAAc,KAAK,SAAuD;AACxE,WAAO,KAAK,OAAO,QAA4B;AAAA,MAC7C,QAAQ;AAAA,MACR,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,OAAO,SAA0D;AAC7E,UAAM,QAAQ,CAAC,KAAK,SAAS,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,KAAK;AAC/D,QAAI,SAAS,WAAW,OAAO;AAC7B,WAAK,QAAQ,EAAE,IAAI,KAAK,IAAI,GAAG,MAAM,MAAM,KAAK,KAAK,OAAO,EAAE;AAAA,IAChE;AACA,WAAO,KAAK,MAAO;AAAA,EACrB;AAAA;AAAA,EAGA,MAAM,KAAK,SAAmD;AAC5D,UAAM,OAAO,MAAM,KAAK,OAAO,OAAO;AACtC,UAAM,SAAS,KAAK,UAAU,CAAC;AAC/B,WAAO,SAAS,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,IAAI,IAAI;AAAA,EACzE;AAAA;AAAA,EAGA,MAAM,IAAI,IAAY,SAA6D;AACjF,YAAQ,MAAM,KAAK,KAAK,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,EAC3D;AAAA;AAAA,EAGA,MAAM,WAAW,SAA8D;AAC7E,YAAQ,MAAM,KAAK,OAAO,OAAO,GAAG;AAAA,EACtC;AACF;;;AC3CO,IAAM,UAAN,MAAc;AAAA,EACnB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,MAAM,IAAI,SAAgD;AACxD,UAAM,OAAO,MAAM,KAAK,OAAO,QAAoD;AAAA,MACjF,QAAQ;AAAA,MACR,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AACF;;;ACZO,IAAM,YAAN,MAAgB;AAAA,EACrB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,MAAM,IAAI,SAA0B,CAAC,GAA6B;AAChE,UAAM,EAAE,WAAW,SAAS,GAAG,QAAQ,IAAI;AAC3C,UAAM,OAAO,MAAM,KAAK,OAAO,QAA0D;AAAA,MACvF,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,EAAE,WAAW,QAAQ;AAAA,MAC5B;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AACF;;;AC0CA,SAAS,aAAa,MAA4B;AAChD,QAAM,IAAK,QAAQ,CAAC;AACpB,SAAO;AAAA,IACL,OAAO,EAAE;AAAA,IACT,QAAQ,EAAE;AAAA,IACV,UAAU,EAAE;AAAA,IACZ,YAAY,EAAE;AAAA,IACd,oBAAoB,EAAE;AAAA,IACtB,aAAa,EAAE,eAAe;AAAA,IAC9B,eAAe,EAAE;AAAA,IACjB,QAAQ,EAAE;AAAA,IACV,OAAO,EAAE,SAAS;AAAA,IAClB,WAAW,EAAE;AAAA,IACb,SAAS,EAAE;AAAA,IACX,KAAK;AAAA,EACP;AACF;AAEA,SAAS,UAAU,QAA2B,QAAiC,CAAC,GAAG;AACjF,QAAM,WAAW,OAAO,SAAS,OAAO,KAAK,OAAO,KAAK,EAAE,SAAS;AACpE,MAAI,UAAU;AACZ,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,UAAU,KAAK,UAAU,OAAO,UAAU,CAAC,CAAC,CAAC;AACzD,QAAI,OAAO,qBAAqB,QAAW;AACzC,WAAK,OAAO,oBAAoB,OAAO,OAAO,gBAAgB,CAAC;AAAA,IACjE;AACA,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,EAAG,MAAK,OAAO,GAAG,OAAO,CAAC,CAAC;AACpE,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,OAAO,KAAM,GAAG;AACzD,WAAK,OAAO,OAAO,IAAI;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,QAAQ,OAAO,UAAU,CAAC;AAAA,IAC1B,kBAAkB,OAAO;AAAA,IACzB,GAAG;AAAA,EACL;AACF;AAGO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,MAAM,SAAS,OAAe,SAAgD;AAC5E,UAAM,OAAO,MAAM,KAAK,OAAO,QAAQ;AAAA,MACrC,QAAQ;AAAA,MACR,MAAM,mBAAmB,mBAAmB,KAAK,CAAC;AAAA,MAClD;AAAA,IACF,CAAC;AACD,WAAO,aAAa,IAAI;AAAA,EAC1B;AACF;AAEO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YAAoB,QAAoB;AAApB;AAClB,SAAK,OAAO,IAAI,aAAa,MAAM;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IACJ,IACA,SAA4B,CAAC,GAC7B,SAC4B;AAC5B,UAAM,aAA6B,EAAE,GAAG,SAAS,YAAY,SAAS,cAAc,EAAE;AACtF,WAAO,KAAK,OAAO,QAA2B;AAAA,MAC5C,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,EAAE,CAAC;AAAA,MAC1C,MAAM,UAAU,MAAM;AAAA,MACtB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OACJ,IACA,SAA4B,CAAC,GAC7B,SAC+B;AAC/B,UAAM,aAA6B,EAAE,GAAG,SAAS,YAAY,SAAS,cAAc,EAAE;AACtF,UAAM,MAAM,MAAM,KAAK,OAAO,QAA6B;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM,cAAc,mBAAmB,EAAE,CAAC;AAAA,MAC1C,MAAM,UAAU,QAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,MACvC,SAAS;AAAA,IACX,CAAC;AACD,WAAO,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,UAAU,WAAW,KAAK,IAAI;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WACJ,IACA,SAA4B,CAAC,GAC7B,OAA6C,CAAC,GACxB;AACtB,UAAM,YAAY,MAAM,KAAK,OAAO,IAAI,QAAQ,IAAI;AACpD,QAAI,CAAC,UAAU,OAAO;AACpB,YAAM,IAAI,YAAY,0CAA0C;AAAA,QAC9D,KAAK,UAAU;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,UAAM,aAAa,KAAK,kBAAkB;AAC1C,UAAM,YAAY,KAAK,iBAAiB;AAExC,QAAI;AACJ,QAAI;AACF,YAAM,MAAM;AAAA,QACV,MAAM,KAAK,KAAK,SAAS,UAAU,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC;AAAA,QACjE;AAAA,UACE;AAAA,UACA;AAAA,UACA,QAAQ,KAAK;AAAA,UACb,YAAY,CAAC,MACX,EAAE,WAAW,eAAe,EAAE,WAAW,YAAY,EAAE,WAAW;AAAA,UACpE,QAAQ,CAAC,MAAM,KAAK,aAAa,CAAC;AAAA,QACpC;AAAA,MACF;AAAA,IACF,SAAS,GAAG;AACV,UAAI,aAAa,kBAAkB;AACjC,cAAM,IAAI;AAAA,UACR,gBAAgB,UAAU,KAAK,0BAA0B,SAAS;AAAA,UAClE,UAAU;AAAA,QACZ;AAAA,MACF;AACA,YAAM;AAAA,IACR;AAEA,QAAI,IAAI,WAAW,YAAY,IAAI,WAAW,WAAW;AACvD,YAAM,IAAI;AAAA,QACR,IAAI,SAAS,gBAAgB,UAAU,KAAK,IAAI,IAAI,MAAM;AAAA,QAC1D,UAAU;AAAA,QACV,EAAE,KAAK,IAAI,IAAI;AAAA,MACjB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;;;ACrNO,IAAM,OAAN,MAAW;AAAA,EAChB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA;AAAA,EAGzC,MAAM,KAAK,MAAiE;AAC1E,UAAM,EAAE,OAAO,GAAG,QAAQ,IAAI,QAAQ,CAAC;AACvC,UAAM,OAAO,MAAM,KAAK,OAAO,QAA+D;AAAA,MAC5F,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,EAAE,MAAM;AAAA,MACf;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,OAAO,OAAe,MAAiE;AAC3F,UAAM,EAAE,OAAO,GAAG,QAAQ,IAAI,QAAQ,CAAC;AACvC,UAAM,OAAO,MAAM,KAAK,OAAO,QAAgD;AAAA,MAC7E,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO,EAAE,GAAG,OAAO,MAAM;AAAA,MACzB;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,gBAAgB,QAAgB,SAA+C;AACnF,UAAM,OAAO,MAAM,KAAK,OAAO,QAAgD;AAAA,MAC7E,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM,EAAE,OAAO;AAAA,MACf;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AACF;;;AChBO,IAAM,QAAN,MAAY;AAAA,EACjB,YAAoB,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAEzC,MAAM,IAAI,QAAmB,SAA8C;AACzE,UAAM,OAAO,IAAI,SAAS;AAC1B,SAAK,OAAO,SAAS,OAAO,OAAO,KAAK,GAAG,OAAO,YAAY,OAAO;AACrE,QAAI,OAAO,SAAU,MAAK,OAAO,YAAY,OAAO,QAAQ;AAC5D,QAAI,OAAO,MAAO,MAAK,OAAO,SAAS,OAAO,KAAK;AACnD,QAAI,OAAO,OAAQ,MAAK,OAAO,UAAU,OAAO,MAAM;AACtD,QAAI,OAAO,aAAc,MAAK,OAAO,gBAAgB,OAAO,YAAY;AACxE,QAAI,OAAO,kBAAkB,QAAW;AACtC,WAAK,OAAO,iBAAiB,OAAO,OAAO,aAAa,CAAC;AAAA,IAC3D;AAEA,UAAM,aAA6B;AAAA,MACjC,GAAG;AAAA,MACH,SAAS,SAAS,WAAW;AAAA,MAC7B,YAAY,SAAS,cAAc;AAAA,IACrC;AACA,WAAO,KAAK,OAAO,QAAmB;AAAA,MACpC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAEA,SAAS,OAAO,OAA8C;AAC5D,MAAI,OAAO,SAAS,eAAe,iBAAiB,KAAM,QAAO;AACjE,SAAO,IAAI,KAAK,CAAC,KAAK,CAA0C;AAClE;;;AChDO,IAAM,mBAAmB;AA8BzB,IAAM,SAAN,MAAa;AAAA,EAclB,YAAY,UAAyB,CAAC,GAAG;AACvC,UAAM,SAAS,QAAQ,UAAU,OAAO;AACxC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,QAAQ,SAAS,aAAa;AAChD,QAAI,CAAC,WAAW;AACd,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBAAiB,QAAQ,WAAW;AAE1C,UAAM,SAAS,eAAe,QAAQ,oBAAoB,EAAE;AAE5D,UAAM,SAAS;AAAA,MACb;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,MAC5B,YAAY,QAAQ,cAAc;AAAA,MAClC,OAAO;AAAA,IACT;AACA,UAAM,SAAS,IAAI,WAAW,EAAE,GAAG,QAAQ,SAAS,eAAe,CAAC;AACpE,UAAM,WAAW,IAAI,WAAW,EAAE,GAAG,QAAQ,SAAS,OAAO,CAAC;AAE9D,UAAM,cAAc;AAAA,MAClB,gBAAgB,QAAQ,yBAAyB;AAAA,MACjD,eAAe,QAAQ,wBAAwB;AAAA,IACjD;AAEA,SAAK,OAAO,IAAI,KAAK,MAAM;AAC3B,SAAK,QAAQ,IAAI,OAAO,MAAM;AAC9B,SAAK,OAAO,IAAI,KAAK,QAAQ,WAAW;AACxC,SAAK,QAAQ,IAAI,MAAM,QAAQ,WAAW;AAC1C,SAAK,QAAQ,IAAI,MAAM,QAAQ,WAAW;AAC1C,SAAK,SAAS,IAAI,OAAO,QAAQ,WAAW;AAC5C,SAAK,SAAS,IAAI,OAAO,MAAM;AAC/B,SAAK,UAAU,IAAI,QAAQ,MAAM;AACjC,SAAK,YAAY,IAAI,UAAU,MAAM;AACrC,SAAK,YAAY,IAAI,UAAU,MAAM;AACrC,SAAK,OAAO,IAAI,KAAK,QAAQ;AAC7B,SAAK,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACjC;AACF;AAEA,SAAS,SAA6B;AACpC,SAAO,OAAO,YAAY,cAAc,QAAQ,KAAK,iBAAiB;AACxE;AAEA,SAAS,eAAsC;AAC7C,QAAM,IAAK,WAAmC;AAC9C,SAAO,OAAO,MAAM,aAAc,EAAE,KAAK,UAAU,IAAkB;AACvE;","names":[]}
package/dist/index.d.cts CHANGED
@@ -29,7 +29,7 @@ interface FetchResponse {
29
29
  interface FetchInit {
30
30
  method?: string;
31
31
  headers?: Record<string, string>;
32
- body?: string;
32
+ body?: string | FormData;
33
33
  signal?: AbortSignal;
34
34
  }
35
35
  /** Injectable fetch implementation (defaults to global fetch on Node 18+). */
@@ -173,6 +173,17 @@ interface VideoGenerateParams {
173
173
  resolution?: string;
174
174
  [key: string]: unknown;
175
175
  }
176
+ interface AudioGenerateParams {
177
+ model: ModelId;
178
+ prompt: string;
179
+ voice?: string;
180
+ [key: string]: unknown;
181
+ }
182
+ interface ThreeDGenerateParams {
183
+ model: ModelId;
184
+ prompt: string;
185
+ [key: string]: unknown;
186
+ }
176
187
  interface PollOptions {
177
188
  /** Poll interval in ms (default 2500). */
178
189
  pollIntervalMs?: number;
@@ -211,32 +222,46 @@ declare class Job {
211
222
  wait(opts?: PollOptions): Promise<MediaJob>;
212
223
  }
213
224
 
225
+ interface MediaParamsBase {
226
+ model: string;
227
+ prompt: string;
228
+ [key: string]: unknown;
229
+ }
214
230
  /**
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.
231
+ * Generic engine for the async media endpoints (video / audio / 3d). They all
232
+ * enqueue the same server-side job queue, so they share one implementation
233
+ * parameterized by `path` and request param type.
218
234
  *
219
- * The same implementation backs audio and 3D (v1.1) via the `path` arg.
235
+ * `generate()` submits and polls to completion; `submit()` fires without polling.
220
236
  */
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>;
237
+ declare class MediaResource<P extends MediaParamsBase> {
238
+ protected client: HttpClient;
239
+ protected defaults: JobDefaults;
240
+ protected path: string;
241
+ constructor(client: HttpClient, defaults: JobDefaults, path: string);
235
242
  /**
236
- * Submit and resolve to the finished media. Handles the 200-vs-202 split and
237
- * polls `/jobs/:id` internally. Throws JobFailedError / JobTimeoutError.
243
+ * Submit WITHOUT polling. The media POST long-polls server-side and can block
244
+ * well past a normal request timeout, so we default its timeout to the poll
245
+ * budget and disable auto-retry (a retried POST would enqueue a duplicate job).
238
246
  */
239
- generate(params: VideoGenerateParams, options?: RequestOptions & PollOptions): Promise<MediaJob>;
247
+ submit(params: P, options?: RequestOptions): Promise<MediaJob>;
248
+ /** Submit and resolve to the finished media (auto-polls /jobs/:id). */
249
+ generate(params: P, options?: RequestOptions & PollOptions): Promise<MediaJob>;
250
+ }
251
+
252
+ /** Video generation (async). `curvet.video.generate(...)` auto-polls to completion. */
253
+ declare class Video extends MediaResource<VideoGenerateParams> {
254
+ constructor(client: HttpClient, defaults: JobDefaults);
255
+ }
256
+
257
+ /** Audio generation (async). `curvet.audio.generate(...)` auto-polls to completion. */
258
+ declare class Audio extends MediaResource<AudioGenerateParams> {
259
+ constructor(client: HttpClient, defaults: JobDefaults);
260
+ }
261
+
262
+ /** 3D model generation (async). `curvet.threeD.generate(...)` auto-polls to completion. */
263
+ declare class ThreeD extends MediaResource<ThreeDGenerateParams> {
264
+ constructor(client: HttpClient, defaults: JobDefaults);
240
265
  }
241
266
 
242
267
  interface ModelsListOptions extends RequestOptions {
@@ -285,11 +310,179 @@ declare class Balance {
285
310
  get(options?: RequestOptions): Promise<BalanceInfo>;
286
311
  }
287
312
 
313
+ interface AnalyticsParams extends RequestOptions {
314
+ /** ISO 8601 start date. */
315
+ startDate?: string;
316
+ /** ISO 8601 end date. */
317
+ endDate?: string;
318
+ }
319
+ interface AnalyticsResult {
320
+ totalRequests?: number;
321
+ totalCost?: number;
322
+ requestsByModel?: Record<string, number>;
323
+ requestsByCategory?: Record<string, number>;
324
+ [key: string]: unknown;
325
+ }
326
+ declare class Analytics {
327
+ private client;
328
+ constructor(client: HttpClient);
329
+ /** Usage analytics for the app, optionally bounded by a date range. */
330
+ get(params?: AnalyticsParams): Promise<AnalyticsResult>;
331
+ }
332
+
333
+ interface WorkflowRunParams {
334
+ /** Input values for the workflow. */
335
+ inputs?: Record<string, unknown>;
336
+ /** Optional file inputs, keyed by the workflow's file field name. */
337
+ files?: Record<string, Blob>;
338
+ /** Include the full execution state in the response (default true server-side). */
339
+ includeFullState?: boolean;
340
+ }
341
+ /** Result of a synchronous `run()` call. */
342
+ interface WorkflowRunResult {
343
+ success: boolean;
344
+ [key: string]: unknown;
345
+ }
346
+ type WorkflowRunStatus = "queued" | "running" | "completed" | "failed" | "stopped";
347
+ interface WorkflowRunNode {
348
+ nodeId: string;
349
+ nodeLabel?: string;
350
+ nodeType?: string;
351
+ status?: string;
352
+ executionTime?: number;
353
+ }
354
+ /** Normalized status of an async (pollable) workflow run. */
355
+ interface WorkflowRun {
356
+ runId: string;
357
+ status: WorkflowRunStatus;
358
+ progress?: number;
359
+ totalNodes?: number;
360
+ completedNodeCount?: number;
361
+ /** The node currently executing (null when finished/queued). */
362
+ currentNode?: {
363
+ id: string;
364
+ label?: string;
365
+ type?: string;
366
+ } | null;
367
+ nodesExecuted?: WorkflowRunNode[];
368
+ /** Final outputs (present once completed). */
369
+ result?: unknown;
370
+ error?: string | null;
371
+ startTime?: string;
372
+ endTime?: string;
373
+ /** Raw, unnormalized response body. */
374
+ raw: unknown;
375
+ }
376
+ interface WorkflowSubmitResult {
377
+ runId: string;
378
+ status: WorkflowRunStatus;
379
+ raw: unknown;
380
+ }
381
+ interface WorkflowPollOptions {
382
+ /** Poll interval in ms (default 2500). */
383
+ pollIntervalMs?: number;
384
+ /** Total poll timeout in ms before throwing WorkflowRunTimeoutError (default 300000). */
385
+ pollTimeoutMs?: number;
386
+ signal?: AbortSignal;
387
+ /** Called on each poll tick with the latest run status (current node, progress). */
388
+ onProgress?: (run: WorkflowRun) => void;
389
+ }
390
+ /** Retrieve async workflow-run status. */
391
+ declare class WorkflowRuns {
392
+ private client;
393
+ constructor(client: HttpClient);
394
+ /** Fetch the current status of an async run once (no polling). */
395
+ retrieve(runId: string, options?: RequestOptions): Promise<WorkflowRun>;
396
+ }
397
+ declare class Workflows {
398
+ private client;
399
+ readonly runs: WorkflowRuns;
400
+ constructor(client: HttpClient);
401
+ /**
402
+ * Execute a workflow synchronously (blocks until it finishes). Best for short
403
+ * workflows; for long ones (video/audio/3D nodes) prefer `runAndPoll`.
404
+ * Sends JSON, or multipart/form-data when file inputs are provided.
405
+ */
406
+ run(id: string, params?: WorkflowRunParams, options?: RequestOptions): Promise<WorkflowRunResult>;
407
+ /**
408
+ * Submit a workflow in async (pollable) mode — returns immediately with a
409
+ * runId. Poll `runs.retrieve(runId)` for status, or use `runAndPoll`.
410
+ */
411
+ submit(id: string, params?: WorkflowRunParams, options?: RequestOptions): Promise<WorkflowSubmitResult>;
412
+ /**
413
+ * Submit and poll to completion. Resolves with the completed run (including
414
+ * `result`), reporting progress via `onProgress`. Throws WorkflowRunFailedError
415
+ * on failure, WorkflowRunTimeoutError on timeout.
416
+ */
417
+ runAndPoll(id: string, params?: WorkflowRunParams, opts?: RequestOptions & WorkflowPollOptions): Promise<WorkflowRun>;
418
+ }
419
+
420
+ interface FoodItem {
421
+ [key: string]: unknown;
422
+ }
423
+ /**
424
+ * Indian Food Dataset API. Mounted as a sibling of the playground under
425
+ * `/api/v1/food`, so it uses the v1-root HTTP client. Requires the app to have
426
+ * Food API access enabled.
427
+ */
428
+ declare class Food {
429
+ private client;
430
+ constructor(client: HttpClient);
431
+ /** List dishes (default limit 20). */
432
+ list(opts?: {
433
+ limit?: number;
434
+ } & RequestOptions): Promise<FoodItem[]>;
435
+ /** Full-text search for dishes. */
436
+ search(query: string, opts?: {
437
+ limit?: number;
438
+ } & RequestOptions): Promise<FoodItem[]>;
439
+ /** Natural-language dish recommendations. */
440
+ recommendations(prompt: string, options?: RequestOptions): Promise<FoodItem[]>;
441
+ }
442
+
443
+ interface SttParams {
444
+ /** The audio to transcribe. */
445
+ audio: Blob | Uint8Array | ArrayBuffer;
446
+ /** File name for the upload (default "audio"). */
447
+ filename?: string;
448
+ provider?: "elevenlabs" | "deepinfra" | (string & {});
449
+ /** ASR model id (provider-specific; optional). */
450
+ model?: string;
451
+ prompt?: string;
452
+ /** ISO 639-1 language hint. */
453
+ languageCode?: string;
454
+ allowFallback?: boolean;
455
+ }
456
+ interface SttResult {
457
+ success: boolean;
458
+ text: string;
459
+ languageCode?: string;
460
+ segments?: Array<{
461
+ start: number;
462
+ end: number;
463
+ text: string;
464
+ }>;
465
+ provider?: string;
466
+ creditsCharged?: number;
467
+ creditsRemaining?: number;
468
+ [key: string]: unknown;
469
+ }
470
+ /**
471
+ * Public speech-to-text. Mounted as a sibling of the playground under
472
+ * `/api/v1/voice`, so it uses the v1-root HTTP client. Multipart upload; not
473
+ * auto-retried (it consumes credits).
474
+ */
475
+ declare class Voice {
476
+ private client;
477
+ constructor(client: HttpClient);
478
+ stt(params: SttParams, options?: RequestOptions): Promise<SttResult>;
479
+ }
480
+
288
481
  declare const DEFAULT_BASE_URL = "https://curvet.ai/api/v1/playground";
289
482
  interface CurvetOptions {
290
483
  /** Your app key. Falls back to the CURVET_APP_KEY env var. */
291
484
  appKey?: string;
292
- /** Override the gateway base URL (defaults to production). */
485
+ /** Override the playground base URL (defaults to production). */
293
486
  baseURL?: string;
294
487
  /** Per-request timeout in ms (default 60000). */
295
488
  timeout?: number;
@@ -317,9 +510,15 @@ declare class Curvet {
317
510
  readonly chat: Chat;
318
511
  readonly image: Images;
319
512
  readonly video: Video;
513
+ readonly audio: Audio;
514
+ readonly threeD: ThreeD;
320
515
  readonly jobs: Jobs;
321
516
  readonly models: Models;
322
517
  readonly balance: Balance;
518
+ readonly analytics: Analytics;
519
+ readonly workflows: Workflows;
520
+ readonly food: Food;
521
+ readonly voice: Voice;
323
522
  constructor(options?: CurvetOptions);
324
523
  }
325
524
 
@@ -376,5 +575,15 @@ declare class JobTimeoutError extends CurvetError {
376
575
  readonly jobId: string;
377
576
  constructor(message: string, jobId: string, opts?: CurvetErrorOptions);
378
577
  }
578
+ /** An async workflow run finished with status "failed" (or "stopped"). */
579
+ declare class WorkflowRunFailedError extends CurvetError {
580
+ readonly runId: string;
581
+ constructor(message: string, runId: string, opts?: CurvetErrorOptions);
582
+ }
583
+ /** An async workflow run did not finish within the poll timeout. */
584
+ declare class WorkflowRunTimeoutError extends CurvetError {
585
+ readonly runId: string;
586
+ constructor(message: string, runId: string, opts?: CurvetErrorOptions);
587
+ }
379
588
 
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 };
589
+ export { APIError, Analytics, type AnalyticsParams, type AnalyticsResult, Audio, type AudioGenerateParams, 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, Food, type FoodItem, type ImageGenerateParams, type ImageResponse, Images, InsufficientBalanceError, Job, type JobDefaults, JobFailedError, type JobStatus, JobTimeoutError, Jobs, type KnownModelId, type MediaJob, type MediaKind, type MediaParamsBase, MediaResource, type ModelId, type ModelInfo, type ModelType, Models, type ModelsListOptions, NotFoundError, PermissionError, type PollOptions, RateLimitError, type RateLimits, type RequestOptions, type SttParams, type SttResult, ThreeD, type ThreeDGenerateParams, type Usage, Video, type VideoGenerateParams, Voice, type WorkflowPollOptions, type WorkflowRun, WorkflowRunFailedError, type WorkflowRunNode, type WorkflowRunParams, type WorkflowRunResult, type WorkflowRunStatus, WorkflowRunTimeoutError, WorkflowRuns, type WorkflowSubmitResult, Workflows };