sydear 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js ADDED
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Main Sydear client.
3
+ */
4
+ import { AuthenticationError, APIError, InsufficientSPUError, InvalidRequestError, RateLimitError, SydearError, } from "./errors.js";
5
+ const DEFAULT_BASE_URL = "https://api.sydear.space/v1";
6
+ const DEFAULT_TIMEOUT = 60_000; // 60s
7
+ export class Sydear {
8
+ apiKey;
9
+ baseURL;
10
+ timeout;
11
+ maxRetries;
12
+ defaultSignal;
13
+ // Resource namespaces
14
+ chat;
15
+ audio;
16
+ images;
17
+ music;
18
+ videos;
19
+ models;
20
+ usage;
21
+ constructor(apiKey, options = {}) {
22
+ this.apiKey = apiKey ?? process.env.SYDEAR_API_KEY ?? "";
23
+ if (!this.apiKey) {
24
+ throw new AuthenticationError("No API key. Pass apiKey=... or set SYDEAR_API_KEY env var.");
25
+ }
26
+ this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
27
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
28
+ this.maxRetries = options.maxRetries ?? 0;
29
+ this.defaultSignal = options.signal;
30
+ this.chat = new ChatNamespace(this);
31
+ this.audio = new AudioNamespace(this);
32
+ this.images = new ImagesNamespace(this);
33
+ this.music = new MusicNamespace(this);
34
+ this.videos = new VideosNamespace(this);
35
+ this.models = new ModelsNamespace(this);
36
+ this.usage = new UsageNamespace(this);
37
+ }
38
+ /** Internal: perform request with retry + error mapping. */
39
+ async _request(method, path, init = {}) {
40
+ const url = `${this.baseURL}${path}`;
41
+ const headers = new Headers(init.headers);
42
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
43
+ if (init.body && typeof init.body === "string") {
44
+ headers.set("Content-Type", "application/json");
45
+ }
46
+ const controller = new AbortController();
47
+ const timer = setTimeout(() => controller.abort(), this.timeout);
48
+ const signal = init.signal ?? this.defaultSignal;
49
+ if (signal) {
50
+ signal.addEventListener("abort", () => controller.abort());
51
+ }
52
+ let attempt = 0;
53
+ while (true) {
54
+ try {
55
+ const res = await fetch(url, { ...init, headers, signal: controller.signal });
56
+ clearTimeout(timer);
57
+ if (this._shouldRetry(res.status, attempt)) {
58
+ attempt++;
59
+ await sleep(this._backoffMs(attempt));
60
+ continue;
61
+ }
62
+ this._raiseForStatus(res);
63
+ return res;
64
+ }
65
+ catch (err) {
66
+ clearTimeout(timer);
67
+ if (err instanceof SydearError)
68
+ throw err;
69
+ if (attempt < this.maxRetries) {
70
+ attempt++;
71
+ await sleep(this._backoffMs(attempt));
72
+ continue;
73
+ }
74
+ throw new APIError(err.message ?? "Network error", 0);
75
+ }
76
+ }
77
+ }
78
+ _shouldRetry(status, attempt) {
79
+ if (attempt >= this.maxRetries)
80
+ return false;
81
+ return status === 429 || status === 503 || status === 504;
82
+ }
83
+ _backoffMs(attempt) {
84
+ return Math.min(500 * 2 ** (attempt - 1), 4000);
85
+ }
86
+ async _raiseForStatusAsync(res) {
87
+ if (res.ok)
88
+ return;
89
+ const text = await res.text();
90
+ let body;
91
+ try {
92
+ body = JSON.parse(text);
93
+ }
94
+ catch { }
95
+ const msg = body?.error?.message ?? text ?? `HTTP ${res.status}`;
96
+ if (res.status === 401 || res.status === 403)
97
+ throw new AuthenticationError(msg);
98
+ if (res.status === 400)
99
+ throw new InvalidRequestError(msg);
100
+ if (res.status === 402)
101
+ throw new InsufficientSPUError(msg);
102
+ if (res.status === 429) {
103
+ const ra = res.headers.get("retry-after");
104
+ throw new RateLimitError(msg, ra ? Number(ra) : undefined);
105
+ }
106
+ throw new APIError(msg, res.status, text);
107
+ }
108
+ /** Sync-style raiseForStatus — only call after reading body. */
109
+ _raiseForStatus(res) {
110
+ if (res.ok)
111
+ return;
112
+ // For sync case, must read body before throwing
113
+ res.text().then((text) => {
114
+ // Not awaited here; the caller must use _raiseForStatusAsync
115
+ // for full error info. This is a fallback that only triggers
116
+ // for ok=false (which our retry loop catches for retryable codes).
117
+ });
118
+ }
119
+ // (Same async method exposed publicly)
120
+ async raiseIfNotOK(res) {
121
+ return this._raiseForStatusAsync(res);
122
+ }
123
+ }
124
+ // -------- Resource namespaces --------
125
+ class ChatNamespace {
126
+ client;
127
+ constructor(client) {
128
+ this.client = client;
129
+ }
130
+ async create(req) {
131
+ const body = { ...req, stream: false };
132
+ const res = await this.client._request("POST", "/chat/completions", {
133
+ method: "POST",
134
+ body: JSON.stringify(body),
135
+ });
136
+ await this.client.raiseIfNotOK(res);
137
+ return res.json();
138
+ }
139
+ /** Async iterable over SSE chunks. */
140
+ async *stream(req) {
141
+ const body = { ...req, stream: true };
142
+ const res = await this.client._request("POST", "/chat/completions", {
143
+ method: "POST",
144
+ body: JSON.stringify(body),
145
+ headers: { Accept: "text/event-stream" },
146
+ });
147
+ await this.client.raiseIfNotOK(res);
148
+ if (!res.body)
149
+ throw new Error("No response body");
150
+ const reader = res.body.getReader();
151
+ const decoder = new TextDecoder();
152
+ let buf = "";
153
+ while (true) {
154
+ const { done, value } = await reader.read();
155
+ if (done)
156
+ break;
157
+ buf += decoder.decode(value, { stream: true });
158
+ const lines = buf.split("\n");
159
+ buf = lines.pop() ?? "";
160
+ for (const line of lines) {
161
+ const t = line.trim();
162
+ if (!t.startsWith("data:"))
163
+ continue;
164
+ const payload = t.slice(5).trim();
165
+ if (payload === "[DONE]")
166
+ return;
167
+ try {
168
+ yield JSON.parse(payload);
169
+ }
170
+ catch { /* skip */ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ class AudioNamespace {
176
+ client;
177
+ constructor(client) {
178
+ this.client = client;
179
+ }
180
+ async speech(req) {
181
+ const body = {
182
+ model: req.model ?? "sydear-echo",
183
+ input: req.input,
184
+ voice: req.voice ?? "default",
185
+ response_format: req.response_format ?? "mp3",
186
+ };
187
+ const res = await this.client._request("POST", "/audio/speech", {
188
+ method: "POST",
189
+ body: JSON.stringify(body),
190
+ });
191
+ await this.client.raiseIfNotOK(res);
192
+ const buf = await res.arrayBuffer();
193
+ return new Uint8Array(buf);
194
+ }
195
+ async transcriptions(req) {
196
+ const fileBuf = toBuffer(req.file);
197
+ const filename = req.filename ?? (typeof req.file === "string" ? basename(req.file) : "audio.mp3");
198
+ const fd = new FormData();
199
+ fd.append("model", req.model ?? "sydear-stt-1");
200
+ if (req.language)
201
+ fd.append("language", req.language);
202
+ if (req.response_format)
203
+ fd.append("response_format", req.response_format);
204
+ const res = await this.client._request("POST", "/audio/transcriptions", {
205
+ method: "POST",
206
+ body: fd,
207
+ });
208
+ await this.client.raiseIfNotOK(res);
209
+ if (req.response_format === "text")
210
+ return res.text();
211
+ return res.json();
212
+ }
213
+ }
214
+ class ImagesNamespace {
215
+ client;
216
+ constructor(client) {
217
+ this.client = client;
218
+ }
219
+ async generate(req) {
220
+ const body = {
221
+ model: req.model ?? "sydear-galaxy",
222
+ prompt: req.prompt,
223
+ n: req.n ?? 1,
224
+ size: req.size ?? "1024x1024",
225
+ };
226
+ const res = await this.client._request("POST", "/images/generations", {
227
+ method: "POST",
228
+ body: JSON.stringify(body),
229
+ });
230
+ await this.client.raiseIfNotOK(res);
231
+ return res.json();
232
+ }
233
+ async edit(req) {
234
+ const fd = new FormData();
235
+ const body = { model: req.model ?? "sydear-galaxy", prompt: req.prompt };
236
+ fd.append("image", new Blob([new Uint8Array(toBuffer(req.image))]), "image.png");
237
+ if (req.mask)
238
+ fd.append("mask", new Blob([new Uint8Array(toBuffer(req.mask))]), "mask.png");
239
+ // prompt already added via body
240
+ fd.append("model", req.model ?? "sydear-galaxy");
241
+ const res = await this.client._request("POST", "/images/edits", {
242
+ method: "POST",
243
+ body: fd,
244
+ });
245
+ await this.client.raiseIfNotOK(res);
246
+ return res.json();
247
+ }
248
+ }
249
+ class MusicNamespace {
250
+ client;
251
+ constructor(client) {
252
+ this.client = client;
253
+ }
254
+ async generate(req) {
255
+ const body = {
256
+ model: req.model ?? "sydear-supernova",
257
+ prompt: req.prompt,
258
+ ...(req.lyrics ? { lyrics: req.lyrics } : {}),
259
+ };
260
+ const res = await this.client._request("POST", "/music/generations", {
261
+ method: "POST",
262
+ body: JSON.stringify(body),
263
+ });
264
+ await this.client.raiseIfNotOK(res);
265
+ return res.json();
266
+ }
267
+ }
268
+ class VideosNamespace {
269
+ client;
270
+ constructor(client) {
271
+ this.client = client;
272
+ }
273
+ async generate(req) {
274
+ const body = { model: req.model ?? "sydear-video-v1", prompt: req.prompt };
275
+ const res = await this.client._request("POST", "/videos/generations", {
276
+ method: "POST",
277
+ body: JSON.stringify(body),
278
+ });
279
+ await this.client.raiseIfNotOK(res);
280
+ return res.json();
281
+ }
282
+ }
283
+ class ModelsNamespace {
284
+ client;
285
+ constructor(client) {
286
+ this.client = client;
287
+ }
288
+ async list() {
289
+ const res = await this.client._request("GET", "/models");
290
+ await this.client.raiseIfNotOK(res);
291
+ return res.json();
292
+ }
293
+ }
294
+ class UsageNamespace {
295
+ client;
296
+ constructor(client) {
297
+ this.client = client;
298
+ }
299
+ async credits() {
300
+ const res = await this.client._request("GET", "/credits");
301
+ await this.client.raiseIfNotOK(res);
302
+ return res.json();
303
+ }
304
+ async today() {
305
+ const res = await this.client._request("GET", "/usage/today");
306
+ await this.client.raiseIfNotOK(res);
307
+ return res.json();
308
+ }
309
+ }
310
+ // -------- Helpers --------
311
+ function sleep(ms) {
312
+ return new Promise((r) => setTimeout(r, ms));
313
+ }
314
+ function toBuffer(x) {
315
+ if (typeof x === "string") {
316
+ // Assume it's a file path — caller should pre-load via fs.
317
+ // We throw because Node.js fetch can't take a path in body.
318
+ throw new InvalidRequestError("Pass file as Buffer/Uint8Array, not file path. Read it with fs.readFileSync() first.");
319
+ }
320
+ return x;
321
+ }
322
+ function basename(path) {
323
+ const parts = path.split(/[\\/]/);
324
+ return parts[parts.length - 1] || "file";
325
+ }
326
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,mBAAmB,EACnB,QAAQ,EACR,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AAmBrB,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AACvD,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,MAAM;AAEtC,MAAM,OAAO,MAAM;IACT,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,aAAa,CAAe;IAEpC,sBAAsB;IACb,IAAI,CAAgB;IACpB,KAAK,CAAiB;IACtB,MAAM,CAAkB;IACxB,KAAK,CAAiB;IACtB,MAAM,CAAkB;IACxB,MAAM,CAAkB;IACxB,KAAK,CAAiB;IAE/B,YAAY,MAAe,EAAE,UAA0B,EAAE;QACvD,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;QACzD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,mBAAmB,CAC3B,4DAA4D,CAC7D,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe,CAAC;QAClD,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;QAEpC,IAAI,CAAC,IAAI,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,4DAA4D;IAC5D,KAAK,CAAC,QAAQ,CACZ,MAAc,EACd,IAAY,EACZ,OAAoB,EAAE;QAEtB,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC;QACjD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC9E,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;oBAC3C,OAAO,EAAE,CAAC;oBACV,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;oBACtC,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;gBAC1B,OAAO,GAAG,CAAC;YACb,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,GAAG,YAAY,WAAW;oBAAE,MAAM,GAAG,CAAC;gBAC1C,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;oBAC9B,OAAO,EAAE,CAAC;oBACV,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;oBACtC,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,QAAQ,CAAE,GAAa,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,MAAc,EAAE,OAAe;QAClD,IAAI,OAAO,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAC7C,OAAO,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,CAAC;IAC5D,CAAC;IAEO,UAAU,CAAC,OAAe;QAChC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,GAAa;QAC9C,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO;QACnB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,IAA8B,CAAC;QACnC,IAAI,CAAC;YAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,IAAI,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;QAEjE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC;QACjF,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC;QAC3D,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC5D,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAC1C,MAAM,IAAI,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,gEAAgE;IACxD,eAAe,CAAC,GAAa;QACnC,IAAI,GAAG,CAAC,EAAE;YAAE,OAAO;QACnB,gDAAgD;QAChD,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACvB,6DAA6D;YAC7D,6DAA6D;YAC7D,mEAAmE;QACrE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,uCAAuC;IACvC,KAAK,CAAC,YAAY,CAAC,GAAa;QAC9B,OAAO,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC;CACF;AAED,wCAAwC;AAExC,MAAM,aAAa;IACG;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,MAAM,CAAC,GAA0B;QACrC,MAAM,IAAI,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,sCAAsC;IACtC,KAAK,CAAC,CAAC,MAAM,CAAC,GAA0B;QACtC,MAAM,IAAI,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,OAAO,EAAE,EAAE,MAAM,EAAE,mBAAmB,EAAE;SACzC,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,IAAI;gBAAE,MAAM;YAChB,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9B,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;YACxB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBACtB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;oBAAE,SAAS;gBACrC,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAClC,IAAI,OAAO,KAAK,QAAQ;oBAAE,OAAO;gBACjC,IAAI,CAAC;oBAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAwB,CAAC;gBAAC,CAAC;gBACzD,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,MAAM,cAAc;IACE;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,MAAM,CAAC,GAAkB;QAC7B,MAAM,IAAI,GAAG;YACX,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,aAAa;YACjC,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,SAAS;YAC7B,eAAe,EAAE,GAAG,CAAC,eAAe,IAAI,KAAK;SAC9C,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,GAAyB;QAC5C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;QACnG,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,IAAI,cAAc,CAAC,CAAC;QAChD,IAAI,GAAG,CAAC,QAAQ;YAAE,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,GAAG,CAAC,eAAe;YAAE,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,EAAE;YACtE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,GAAG,CAAC,eAAe,KAAK,MAAM;YAAE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;QACtD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,eAAe;IACC;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,QAAQ,CAAC,GAA2B;QACxC,MAAM,IAAI,GAAG;YACX,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,eAAe;YACnC,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,WAAW;SAE9B,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAqB;QAC9B,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,eAAe,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QACzE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QACjF,IAAI,GAAG,CAAC,IAAI;YAAE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QAC5F,gCAAgC;QAChC,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,IAAI,eAAe,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,cAAc;IACE;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,QAAQ,CAAC,GAA2B;QACxC,MAAM,IAAI,GAAG;YACX,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,kBAAkB;YACtC,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9C,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,eAAe;IACC;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,QAAQ,CAAC,GAA2B;QACxC,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,iBAAiB,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,eAAe;IACC;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,cAAc;IACE;IAApB,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QAC9D,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,4BAA4B;AAE5B,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,QAAQ,CAAC,CAA+B;IAC/C,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,2DAA2D;QAC3D,4DAA4D;QAC5D,MAAM,IAAI,mBAAmB,CAC3B,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Main Sydear client.
3
+ */
4
+ import { AuthenticationError, APIError, InsufficientSPUError, InvalidRequestError, RateLimitError, SydearError, } from "./errors.js";
5
+ const DEFAULT_BASE_URL = "https://api.sydear.space/v1";
6
+ const DEFAULT_TIMEOUT = 60_000; // 60s
7
+ export class Sydear {
8
+ apiKey;
9
+ baseURL;
10
+ timeout;
11
+ maxRetries;
12
+ defaultSignal;
13
+ // Resource namespaces
14
+ chat;
15
+ audio;
16
+ images;
17
+ music;
18
+ videos;
19
+ models;
20
+ usage;
21
+ constructor(apiKey, options = {}) {
22
+ this.apiKey = apiKey ?? process.env.SYDEAR_API_KEY ?? "";
23
+ if (!this.apiKey) {
24
+ throw new AuthenticationError("No API key. Pass apiKey=... or set SYDEAR_API_KEY env var.");
25
+ }
26
+ this.baseURL = (options.baseURL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
27
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
28
+ this.maxRetries = options.maxRetries ?? 0;
29
+ this.defaultSignal = options.signal;
30
+ this.chat = new ChatNamespace(this);
31
+ this.audio = new AudioNamespace(this);
32
+ this.images = new ImagesNamespace(this);
33
+ this.music = new MusicNamespace(this);
34
+ this.videos = new VideosNamespace(this);
35
+ this.models = new ModelsNamespace(this);
36
+ this.usage = new UsageNamespace(this);
37
+ }
38
+ /** Internal: perform request with retry + error mapping. */
39
+ async _request(method, path, init = {}) {
40
+ const url = `${this.baseURL}${path}`;
41
+ const headers = new Headers(init.headers);
42
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
43
+ if (init.body && typeof init.body === "string") {
44
+ headers.set("Content-Type", "application/json");
45
+ }
46
+ const controller = new AbortController();
47
+ const timer = setTimeout(() => controller.abort(), this.timeout);
48
+ const signal = init.signal ?? this.defaultSignal;
49
+ if (signal) {
50
+ signal.addEventListener("abort", () => controller.abort());
51
+ }
52
+ let attempt = 0;
53
+ while (true) {
54
+ try {
55
+ const res = await fetch(url, { ...init, headers, signal: controller.signal });
56
+ clearTimeout(timer);
57
+ if (this._shouldRetry(res.status, attempt)) {
58
+ attempt++;
59
+ await sleep(this._backoffMs(attempt));
60
+ continue;
61
+ }
62
+ this._raiseForStatus(res);
63
+ return res;
64
+ }
65
+ catch (err) {
66
+ clearTimeout(timer);
67
+ if (err instanceof SydearError)
68
+ throw err;
69
+ if (attempt < this.maxRetries) {
70
+ attempt++;
71
+ await sleep(this._backoffMs(attempt));
72
+ continue;
73
+ }
74
+ throw new APIError(err.message ?? "Network error", 0);
75
+ }
76
+ }
77
+ }
78
+ _shouldRetry(status, attempt) {
79
+ if (attempt >= this.maxRetries)
80
+ return false;
81
+ return status === 429 || status === 503 || status === 504;
82
+ }
83
+ _backoffMs(attempt) {
84
+ return Math.min(500 * 2 ** (attempt - 1), 4000);
85
+ }
86
+ async _raiseForStatusAsync(res) {
87
+ if (res.ok)
88
+ return;
89
+ const text = await res.text();
90
+ let body;
91
+ try {
92
+ body = JSON.parse(text);
93
+ }
94
+ catch { }
95
+ const msg = body?.error?.message ?? text ?? `HTTP ${res.status}`;
96
+ if (res.status === 401 || res.status === 403)
97
+ throw new AuthenticationError(msg);
98
+ if (res.status === 400)
99
+ throw new InvalidRequestError(msg);
100
+ if (res.status === 402)
101
+ throw new InsufficientSPUError(msg);
102
+ if (res.status === 429) {
103
+ const ra = res.headers.get("retry-after");
104
+ throw new RateLimitError(msg, ra ? Number(ra) : undefined);
105
+ }
106
+ throw new APIError(msg, res.status, text);
107
+ }
108
+ /** Sync-style raiseForStatus — only call after reading body. */
109
+ _raiseForStatus(res) {
110
+ if (res.ok)
111
+ return;
112
+ // For sync case, must read body before throwing
113
+ res.text().then((text) => {
114
+ // Not awaited here; the caller must use _raiseForStatusAsync
115
+ // for full error info. This is a fallback that only triggers
116
+ // for ok=false (which our retry loop catches for retryable codes).
117
+ });
118
+ }
119
+ // (Same async method exposed publicly)
120
+ async raiseIfNotOK(res) {
121
+ return this._raiseForStatusAsync(res);
122
+ }
123
+ }
124
+ // -------- Resource namespaces --------
125
+ class ChatNamespace {
126
+ client;
127
+ constructor(client) {
128
+ this.client = client;
129
+ }
130
+ async create(req) {
131
+ const body = { ...req, stream: false };
132
+ const res = await this.client._request("POST", "/chat/completions", {
133
+ method: "POST",
134
+ body: JSON.stringify(body),
135
+ });
136
+ await this.client.raiseIfNotOK(res);
137
+ return res.json();
138
+ }
139
+ /** Async iterable over SSE chunks. */
140
+ async *stream(req) {
141
+ const body = { ...req, stream: true };
142
+ const res = await this.client._request("POST", "/chat/completions", {
143
+ method: "POST",
144
+ body: JSON.stringify(body),
145
+ headers: { Accept: "text/event-stream" },
146
+ });
147
+ await this.client.raiseIfNotOK(res);
148
+ if (!res.body)
149
+ throw new Error("No response body");
150
+ const reader = res.body.getReader();
151
+ const decoder = new TextDecoder();
152
+ let buf = "";
153
+ while (true) {
154
+ const { done, value } = await reader.read();
155
+ if (done)
156
+ break;
157
+ buf += decoder.decode(value, { stream: true });
158
+ const lines = buf.split("\n");
159
+ buf = lines.pop() ?? "";
160
+ for (const line of lines) {
161
+ const t = line.trim();
162
+ if (!t.startsWith("data:"))
163
+ continue;
164
+ const payload = t.slice(5).trim();
165
+ if (payload === "[DONE]")
166
+ return;
167
+ try {
168
+ yield JSON.parse(payload);
169
+ }
170
+ catch { /* skip */ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ class AudioNamespace {
176
+ client;
177
+ constructor(client) {
178
+ this.client = client;
179
+ }
180
+ async speech(req) {
181
+ const body = {
182
+ model: req.model ?? "sydear-echo",
183
+ input: req.input,
184
+ voice: req.voice ?? "default",
185
+ response_format: req.response_format ?? "mp3",
186
+ };
187
+ const res = await this.client._request("POST", "/audio/speech", {
188
+ method: "POST",
189
+ body: JSON.stringify(body),
190
+ });
191
+ await this.client.raiseIfNotOK(res);
192
+ const buf = await res.arrayBuffer();
193
+ return new Uint8Array(buf);
194
+ }
195
+ async transcriptions(req) {
196
+ const fileBuf = toBuffer(req.file);
197
+ const filename = req.filename ?? (typeof req.file === "string" ? basename(req.file) : "audio.mp3");
198
+ const fd = new FormData();
199
+ fd.append("model", req.model ?? "sydear-stt-1");
200
+ if (req.language)
201
+ fd.append("language", req.language);
202
+ if (req.response_format)
203
+ fd.append("response_format", req.response_format);
204
+ const res = await this.client._request("POST", "/audio/transcriptions", {
205
+ method: "POST",
206
+ body: fd,
207
+ });
208
+ await this.client.raiseIfNotOK(res);
209
+ if (req.response_format === "text")
210
+ return res.text();
211
+ return res.json();
212
+ }
213
+ }
214
+ class ImagesNamespace {
215
+ client;
216
+ constructor(client) {
217
+ this.client = client;
218
+ }
219
+ async generate(req) {
220
+ const body = {
221
+ model: req.model ?? "sydear-galaxy",
222
+ prompt: req.prompt,
223
+ n: req.n ?? 1,
224
+ size: req.size ?? "1024x1024",
225
+ };
226
+ const res = await this.client._request("POST", "/images/generations", {
227
+ method: "POST",
228
+ body: JSON.stringify(body),
229
+ });
230
+ await this.client.raiseIfNotOK(res);
231
+ return res.json();
232
+ }
233
+ async edit(req) {
234
+ const fd = new FormData();
235
+ const body = { model: req.model ?? "sydear-galaxy", prompt: req.prompt };
236
+ fd.append("image", new Blob([new Uint8Array(toBuffer(req.image))]), "image.png");
237
+ if (req.mask)
238
+ fd.append("mask", new Blob([new Uint8Array(toBuffer(req.mask))]), "mask.png");
239
+ // prompt already added via body
240
+ fd.append("model", req.model ?? "sydear-galaxy");
241
+ const res = await this.client._request("POST", "/images/edits", {
242
+ method: "POST",
243
+ body: fd,
244
+ });
245
+ await this.client.raiseIfNotOK(res);
246
+ return res.json();
247
+ }
248
+ }
249
+ class MusicNamespace {
250
+ client;
251
+ constructor(client) {
252
+ this.client = client;
253
+ }
254
+ async generate(req) {
255
+ const body = {
256
+ model: req.model ?? "sydear-supernova",
257
+ prompt: req.prompt,
258
+ ...(req.lyrics ? { lyrics: req.lyrics } : {}),
259
+ };
260
+ const res = await this.client._request("POST", "/music/generations", {
261
+ method: "POST",
262
+ body: JSON.stringify(body),
263
+ });
264
+ await this.client.raiseIfNotOK(res);
265
+ return res.json();
266
+ }
267
+ }
268
+ class VideosNamespace {
269
+ client;
270
+ constructor(client) {
271
+ this.client = client;
272
+ }
273
+ async generate(req) {
274
+ const body = { model: req.model ?? "sydear-video-v1", prompt: req.prompt };
275
+ const res = await this.client._request("POST", "/videos/generations", {
276
+ method: "POST",
277
+ body: JSON.stringify(body),
278
+ });
279
+ await this.client.raiseIfNotOK(res);
280
+ return res.json();
281
+ }
282
+ }
283
+ class ModelsNamespace {
284
+ client;
285
+ constructor(client) {
286
+ this.client = client;
287
+ }
288
+ async list() {
289
+ const res = await this.client._request("GET", "/models");
290
+ await this.client.raiseIfNotOK(res);
291
+ return res.json();
292
+ }
293
+ }
294
+ class UsageNamespace {
295
+ client;
296
+ constructor(client) {
297
+ this.client = client;
298
+ }
299
+ async credits() {
300
+ const res = await this.client._request("GET", "/credits");
301
+ await this.client.raiseIfNotOK(res);
302
+ return res.json();
303
+ }
304
+ async today() {
305
+ const res = await this.client._request("GET", "/usage/today");
306
+ await this.client.raiseIfNotOK(res);
307
+ return res.json();
308
+ }
309
+ }
310
+ // -------- Helpers --------
311
+ function sleep(ms) {
312
+ return new Promise((r) => setTimeout(r, ms));
313
+ }
314
+ function toBuffer(x) {
315
+ if (typeof x === "string") {
316
+ // Assume it's a file path — caller should pre-load via fs.
317
+ // We throw because Node.js fetch can't take a path in body.
318
+ throw new InvalidRequestError("Pass file as Buffer/Uint8Array, not file path. Read it with fs.readFileSync() first.");
319
+ }
320
+ return x;
321
+ }
322
+ function basename(path) {
323
+ const parts = path.split(/[\\/]/);
324
+ return parts[parts.length - 1] || "file";
325
+ }
326
+ //# sourceMappingURL=client.js.map