@zorveus/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1205 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ APIConnectionError: () => APIConnectionError,
24
+ APIStatusError: () => APIStatusError,
25
+ AuthenticationError: () => AuthenticationError,
26
+ CapExceededError: () => CapExceededError,
27
+ CreditGrantExpiredError: () => CreditGrantExpiredError,
28
+ InsufficientFundsError: () => InsufficientFundsError,
29
+ InternalServerError: () => InternalServerError,
30
+ NotFoundError: () => NotFoundError,
31
+ PermissionDeniedError: () => PermissionDeniedError,
32
+ RateLimitError: () => RateLimitError,
33
+ UnprocessableEntityError: () => UnprocessableEntityError,
34
+ Zorveus: () => Zorveus,
35
+ ZorveusBusinessError: () => ZorveusBusinessError,
36
+ ZorveusError: () => ZorveusError,
37
+ ZorveusInferenceClient: () => ZorveusInferenceClient,
38
+ ZorveusOAuth: () => ZorveusOAuth,
39
+ ZorveusServiceClient: () => ZorveusServiceClient,
40
+ assertDecimalString: () => assertDecimalString,
41
+ createAPIError: () => createAPIError,
42
+ formatGatewayMetadata: () => formatGatewayMetadata,
43
+ isValidDecimalString: () => isValidDecimalString
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/http/headers.ts
48
+ function buildHeaders(options) {
49
+ const headers = {
50
+ Accept: "application/json"
51
+ };
52
+ if (typeof window === "undefined") {
53
+ headers["User-Agent"] = "@zorveus/sdk/0.1.0";
54
+ }
55
+ if (options.contentType) {
56
+ headers["Content-Type"] = options.contentType;
57
+ }
58
+ if (options.apiKey) {
59
+ headers["Authorization"] = `Bearer ${options.apiKey}`;
60
+ }
61
+ if (options.defaultHeaders) {
62
+ Object.assign(headers, options.defaultHeaders);
63
+ }
64
+ if (options.customHeaders) {
65
+ Object.assign(headers, options.customHeaders);
66
+ }
67
+ return headers;
68
+ }
69
+
70
+ // src/errors/zorveus-error.ts
71
+ var ZorveusError = class extends Error {
72
+ status;
73
+ code;
74
+ param;
75
+ type;
76
+ headers;
77
+ rawBody;
78
+ constructor(message, options = {}) {
79
+ super(message);
80
+ this.name = "ZorveusError";
81
+ this.status = options.status;
82
+ this.code = options.code;
83
+ this.param = options.param;
84
+ this.type = options.type;
85
+ this.headers = options.headers;
86
+ this.rawBody = options.rawBody;
87
+ if (options.cause) {
88
+ this.cause = options.cause;
89
+ }
90
+ Object.setPrototypeOf(this, new.target.prototype);
91
+ }
92
+ };
93
+ var APIConnectionError = class extends ZorveusError {
94
+ constructor(message = "Connection to Zorveus API failed", options = {}) {
95
+ super(message, options);
96
+ this.name = "APIConnectionError";
97
+ if (options.cause) {
98
+ this.cause = options.cause;
99
+ }
100
+ }
101
+ };
102
+ var APIStatusError = class extends ZorveusError {
103
+ constructor(message, options) {
104
+ super(message, options);
105
+ this.name = "APIStatusError";
106
+ }
107
+ };
108
+ var AuthenticationError = class extends APIStatusError {
109
+ constructor(message = "Invalid or expired Zorveus credentials", options = {}) {
110
+ super(message, { ...options, status: options.status ?? 401 });
111
+ this.name = "AuthenticationError";
112
+ }
113
+ };
114
+ var PermissionDeniedError = class extends APIStatusError {
115
+ constructor(message = "Permission denied for this operation or model", options = {}) {
116
+ super(message, { ...options, status: options.status ?? 403 });
117
+ this.name = "PermissionDeniedError";
118
+ }
119
+ };
120
+ var NotFoundError = class extends APIStatusError {
121
+ constructor(message = "Resource not found", options = {}) {
122
+ super(message, { ...options, status: options.status ?? 404 });
123
+ this.name = "NotFoundError";
124
+ }
125
+ };
126
+ var UnprocessableEntityError = class extends APIStatusError {
127
+ constructor(message = "Request validation failed", options = {}) {
128
+ super(message, { ...options, status: options.status ?? 422 });
129
+ this.name = "UnprocessableEntityError";
130
+ }
131
+ };
132
+ var RateLimitError = class extends APIStatusError {
133
+ constructor(message = "Rate limit exceeded. Please retry after some time.", options = {}) {
134
+ super(message, { ...options, status: options.status ?? 429 });
135
+ this.name = "RateLimitError";
136
+ }
137
+ };
138
+ var InternalServerError = class extends APIStatusError {
139
+ constructor(message = "Zorveus internal server error", options = {}) {
140
+ super(message, { ...options, status: options.status ?? 500 });
141
+ this.name = "InternalServerError";
142
+ }
143
+ };
144
+ var ZorveusBusinessError = class extends APIStatusError {
145
+ constructor(message, options) {
146
+ super(message, options);
147
+ this.name = "ZorveusBusinessError";
148
+ }
149
+ };
150
+ var InsufficientFundsError = class extends ZorveusBusinessError {
151
+ constructor(message = "Wallet balance exhausted. Top up required.", options = {}) {
152
+ super(message, { ...options, status: options.status ?? 402, code: options.code ?? "insufficient_funds" });
153
+ this.name = "InsufficientFundsError";
154
+ }
155
+ };
156
+ var CapExceededError = class extends ZorveusBusinessError {
157
+ constructor(message = "Spending cap limit reached", options = {}) {
158
+ super(message, { ...options, status: options.status ?? 402, code: options.code ?? "cap_exceeded" });
159
+ this.name = "CapExceededError";
160
+ }
161
+ };
162
+ var CreditGrantExpiredError = class extends ZorveusBusinessError {
163
+ constructor(message = "Product user credit grant has expired", options = {}) {
164
+ super(message, { ...options, status: options.status ?? 403, code: options.code ?? "credit_grant_expired" });
165
+ this.name = "CreditGrantExpiredError";
166
+ }
167
+ };
168
+ function createAPIError(status, body, headers) {
169
+ let message = `Request failed with status ${status}`;
170
+ let code;
171
+ let param;
172
+ let type;
173
+ let parsedBody = body;
174
+ if (typeof body === "string") {
175
+ try {
176
+ parsedBody = JSON.parse(body);
177
+ } catch {
178
+ try {
179
+ parsedBody = JSON.parse(body.replace(/'/g, '"'));
180
+ } catch {
181
+ const codeMatch = body.match(/['"]code['"]\s*:\s*['"]([^'"]+)['"]/);
182
+ const msgMatch = body.match(/['"]message['"]\s*:\s*['"]([^'"]+)['"]/);
183
+ if (msgMatch?.[1]) message = msgMatch[1];
184
+ if (codeMatch?.[1]) code = codeMatch[1];
185
+ }
186
+ }
187
+ }
188
+ if (parsedBody && typeof parsedBody === "object") {
189
+ const obj = parsedBody;
190
+ if (obj.error && typeof obj.error === "object") {
191
+ const err = obj.error;
192
+ if (typeof err.message === "string") message = err.message;
193
+ if (typeof err.code === "string") code = err.code;
194
+ if (typeof err.param === "string") param = err.param;
195
+ if (typeof err.type === "string") type = err.type;
196
+ } else if (typeof obj.detail === "string") {
197
+ message = obj.detail;
198
+ } else if (Array.isArray(obj.detail) && obj.detail.length > 0) {
199
+ const first = obj.detail[0];
200
+ if (first && typeof first.msg === "string") {
201
+ message = first.msg;
202
+ }
203
+ } else if (typeof obj.message === "string") {
204
+ message = obj.message;
205
+ }
206
+ }
207
+ const options = { status, code, param, type, headers, rawBody: body };
208
+ const normalizedCode = (code || "").toLowerCase();
209
+ if (normalizedCode.includes("cap_exceed") || normalizedCode.includes("spend_cap") || message.toLowerCase().includes("spending cap")) {
210
+ return new CapExceededError(message, options);
211
+ }
212
+ if (normalizedCode.includes("insufficient_funds") || normalizedCode.includes("balance_exhausted") || normalizedCode.includes("insufficient_balance") || normalizedCode.includes("wallet_empty") || message.toLowerCase().includes("insufficient funds") || message.toLowerCase().includes("balance exhausted") || message.toLowerCase().includes("wallet is empty")) {
213
+ return new InsufficientFundsError(message, options);
214
+ }
215
+ if (normalizedCode.includes("grant_expired")) {
216
+ return new CreditGrantExpiredError(message, options);
217
+ }
218
+ if (status === 401) {
219
+ return new AuthenticationError(message, options);
220
+ }
221
+ if (status === 402) {
222
+ return new InsufficientFundsError(message, options);
223
+ }
224
+ if (status === 403) {
225
+ return new PermissionDeniedError(message, options);
226
+ }
227
+ if (status === 404) {
228
+ return new NotFoundError(message, options);
229
+ }
230
+ if (status === 422) {
231
+ return new UnprocessableEntityError(message, options);
232
+ }
233
+ if (status === 429) {
234
+ return new RateLimitError(message, options);
235
+ }
236
+ if (status >= 500) {
237
+ return new InternalServerError(message, options);
238
+ }
239
+ return new APIStatusError(message, options);
240
+ }
241
+
242
+ // src/http/transport.ts
243
+ var HTTPTransport = class {
244
+ apiKey;
245
+ baseURL;
246
+ gatewayBaseURL;
247
+ timeout;
248
+ maxRetries;
249
+ defaultHeaders;
250
+ fetchFn;
251
+ constructor(options) {
252
+ if (!options || !options.apiKey) {
253
+ throw new Error("HTTPTransport initialized without an apiKey.");
254
+ }
255
+ this.apiKey = options.apiKey;
256
+ this.baseURL = (options.baseURL || "https://api.zorveus.com").replace(/\/+$/, "");
257
+ this.gatewayBaseURL = (options.gatewayBaseURL || `${this.baseURL}/v1`).replace(/\/+$/, "");
258
+ this.timeout = options.timeout ?? 6e4;
259
+ this.maxRetries = options.maxRetries ?? 2;
260
+ this.defaultHeaders = options.defaultHeaders || {};
261
+ this.fetchFn = options.fetch || globalThis.fetch.bind(globalThis);
262
+ }
263
+ /**
264
+ * Executes an HTTP request with timeout, strict idempotency-aware retries, and error mapping.
265
+ */
266
+ async request(path, options = {}) {
267
+ const method = options.method || "GET";
268
+ const isGateway = options.isGateway ?? false;
269
+ const rootUrl = isGateway ? this.gatewayBaseURL : this.baseURL;
270
+ const url = this.buildUrl(rootUrl, path, options.query);
271
+ const isJsonBody = options.body !== void 0 && !(options.body instanceof FormData);
272
+ const contentType = isJsonBody ? "application/json" : void 0;
273
+ const customHeaders = { ...options.headers };
274
+ if (options.idempotencyKey) {
275
+ customHeaders["X-Idempotency-Key"] = options.idempotencyKey;
276
+ }
277
+ const headers = buildHeaders({
278
+ apiKey: this.apiKey,
279
+ defaultHeaders: this.defaultHeaders,
280
+ customHeaders,
281
+ contentType
282
+ });
283
+ const isSafeMethod = method === "GET" || method === "HEAD" || method === "OPTIONS";
284
+ const isIdempotent = isSafeMethod || Boolean(options.isIdempotent || options.idempotencyKey);
285
+ const maxRetries = isIdempotent ? options.maxRetries ?? this.maxRetries : 0;
286
+ const timeoutMs = options.timeout ?? this.timeout;
287
+ if (options.signal?.aborted) {
288
+ throw new APIConnectionError("Request was cancelled by user");
289
+ }
290
+ let attempt = 0;
291
+ while (true) {
292
+ const controller = new AbortController();
293
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
294
+ const onAbort = () => controller.abort();
295
+ if (options.signal) {
296
+ options.signal.addEventListener("abort", onAbort, { once: true });
297
+ }
298
+ try {
299
+ const bodyContent = isJsonBody ? JSON.stringify(options.body) : options.body;
300
+ const response = await this.fetchFn(url.toString(), {
301
+ method,
302
+ headers,
303
+ body: bodyContent,
304
+ signal: controller.signal
305
+ });
306
+ if (options.stream) {
307
+ if (!response.ok) {
308
+ const errorBody = await this.parseResponseBody(response);
309
+ throw createAPIError(response.status, errorBody, this.extractHeaders(response.headers));
310
+ }
311
+ if (!response.body) {
312
+ throw new APIConnectionError("Streaming response body is null");
313
+ }
314
+ return response.body;
315
+ }
316
+ if (!response.ok) {
317
+ const errorBody = await this.parseResponseBody(response);
318
+ const shouldRetry = isIdempotent && this.shouldRetryStatus(response.status) && attempt < maxRetries;
319
+ if (shouldRetry) {
320
+ attempt++;
321
+ const delay = this.calculateRetryDelay(attempt, response.headers.get("retry-after"));
322
+ await this.sleep(delay);
323
+ continue;
324
+ }
325
+ throw createAPIError(response.status, errorBody, this.extractHeaders(response.headers));
326
+ }
327
+ if (response.status === 204) {
328
+ return void 0;
329
+ }
330
+ const data = await this.parseResponseBody(response);
331
+ return data;
332
+ } catch (error) {
333
+ if (error && typeof error === "object" && "status" in error) {
334
+ throw error;
335
+ }
336
+ const isAbortError = error instanceof Error && error.name === "AbortError";
337
+ const wasUserAborted = options.signal?.aborted;
338
+ if (isAbortError && wasUserAborted) {
339
+ throw new APIConnectionError("Request was cancelled by user", { cause: error });
340
+ }
341
+ const isTimeout = isAbortError && !wasUserAborted;
342
+ const errorMessage = isTimeout ? `Request timed out after ${timeoutMs}ms` : "Network request failed";
343
+ if (isIdempotent && attempt < maxRetries) {
344
+ attempt++;
345
+ const delay = this.calculateRetryDelay(attempt);
346
+ await this.sleep(delay);
347
+ continue;
348
+ }
349
+ throw new APIConnectionError(errorMessage, { cause: error });
350
+ } finally {
351
+ clearTimeout(timeoutId);
352
+ if (options.signal) {
353
+ options.signal.removeEventListener("abort", onAbort);
354
+ }
355
+ }
356
+ }
357
+ }
358
+ buildUrl(base, path, query) {
359
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
360
+ const url = new URL(`${base}${normalizedPath}`);
361
+ if (query) {
362
+ for (const [key, value] of Object.entries(query)) {
363
+ if (value === void 0 || value === null) {
364
+ continue;
365
+ }
366
+ if (Array.isArray(value)) {
367
+ for (const item of value) {
368
+ if (item !== void 0 && item !== null) {
369
+ url.searchParams.append(key, String(item));
370
+ }
371
+ }
372
+ } else {
373
+ url.searchParams.append(key, String(value));
374
+ }
375
+ }
376
+ }
377
+ return url;
378
+ }
379
+ async parseResponseBody(response) {
380
+ const text = await response.text();
381
+ if (!text) {
382
+ return null;
383
+ }
384
+ try {
385
+ return JSON.parse(text);
386
+ } catch {
387
+ return text;
388
+ }
389
+ }
390
+ extractHeaders(headers) {
391
+ const result = {};
392
+ headers.forEach((value, key) => {
393
+ result[key] = value;
394
+ });
395
+ return result;
396
+ }
397
+ shouldRetryStatus(status) {
398
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
399
+ }
400
+ calculateRetryDelay(attempt, retryAfterHeader) {
401
+ if (retryAfterHeader) {
402
+ const parsedSeconds = parseInt(retryAfterHeader, 10);
403
+ if (!isNaN(parsedSeconds) && parsedSeconds > 0) {
404
+ return parsedSeconds * 1e3;
405
+ }
406
+ const parsedDate = Date.parse(retryAfterHeader);
407
+ if (!isNaN(parsedDate)) {
408
+ const diff = parsedDate - Date.now();
409
+ if (diff > 0) {
410
+ return diff;
411
+ }
412
+ }
413
+ }
414
+ const baseDelay = 500;
415
+ const maxBackoff = Math.min(1e4, baseDelay * Math.pow(2, Math.max(0, attempt - 1)));
416
+ const jitter = Math.floor(Math.random() * maxBackoff);
417
+ return Math.max(baseDelay, jitter);
418
+ }
419
+ sleep(ms) {
420
+ return new Promise((resolve) => setTimeout(resolve, ms));
421
+ }
422
+ };
423
+
424
+ // src/http/sse.ts
425
+ async function* parseSSEStream(stream) {
426
+ const reader = stream.getReader();
427
+ const decoder = new TextDecoder("utf-8");
428
+ let buffer = "";
429
+ try {
430
+ while (true) {
431
+ const { done, value } = await reader.read();
432
+ if (done) {
433
+ break;
434
+ }
435
+ buffer += decoder.decode(value, { stream: true });
436
+ const lines = buffer.split(/\r?\n/);
437
+ buffer = lines.pop() ?? "";
438
+ for (const line of lines) {
439
+ const trimmed = line.trim();
440
+ if (!trimmed || trimmed.startsWith(":")) {
441
+ continue;
442
+ }
443
+ if (trimmed.startsWith("data:")) {
444
+ const dataContent = trimmed.slice(5).trim();
445
+ if (dataContent === "[DONE]") {
446
+ return;
447
+ }
448
+ try {
449
+ const parsed = JSON.parse(dataContent);
450
+ yield parsed;
451
+ } catch {
452
+ }
453
+ }
454
+ }
455
+ }
456
+ if (buffer.trim()) {
457
+ const trimmed = buffer.trim();
458
+ if (trimmed.startsWith("data:")) {
459
+ const dataContent = trimmed.slice(5).trim();
460
+ if (dataContent !== "[DONE]") {
461
+ try {
462
+ const parsed = JSON.parse(dataContent);
463
+ yield parsed;
464
+ } catch {
465
+ }
466
+ }
467
+ }
468
+ }
469
+ } finally {
470
+ try {
471
+ await reader.cancel();
472
+ } catch {
473
+ }
474
+ reader.releaseLock();
475
+ }
476
+ }
477
+
478
+ // src/types/chat.ts
479
+ function formatGatewayMetadata(meta) {
480
+ if (!meta) return void 0;
481
+ const result = {};
482
+ if (meta.externalUserId) {
483
+ result.external_user_id = meta.externalUserId;
484
+ }
485
+ if (meta.displayName !== void 0 || meta.userEmail !== void 0 || meta.metadata !== void 0) {
486
+ result.product_user = {
487
+ display_name: meta.displayName ?? null,
488
+ email: meta.userEmail ?? null,
489
+ metadata: meta.metadata ?? null
490
+ };
491
+ }
492
+ return Object.keys(result).length > 0 ? result : void 0;
493
+ }
494
+
495
+ // src/resources/chat/completions.ts
496
+ var Completions = class {
497
+ transport;
498
+ constructor(transport) {
499
+ this.transport = transport;
500
+ }
501
+ async create(params, options = {}) {
502
+ const isStreaming = Boolean(params.stream);
503
+ const { zorveusMetadata, metadata: explicitMetadata, ...requestBody } = params;
504
+ const gatewayMetadata = formatGatewayMetadata(zorveusMetadata);
505
+ const combinedMetadata = explicitMetadata ? { ...gatewayMetadata, ...explicitMetadata } : gatewayMetadata;
506
+ const payload = {
507
+ ...requestBody,
508
+ ...combinedMetadata ? { metadata: combinedMetadata } : {}
509
+ };
510
+ if (isStreaming) {
511
+ const responseStream = await this.transport.request(
512
+ "/chat/completions",
513
+ {
514
+ method: "POST",
515
+ body: { ...payload, stream: true },
516
+ isGateway: true,
517
+ stream: true,
518
+ ...options
519
+ }
520
+ );
521
+ return parseSSEStream(responseStream);
522
+ }
523
+ return this.transport.request("/chat/completions", {
524
+ method: "POST",
525
+ body: payload,
526
+ isGateway: true,
527
+ stream: false,
528
+ ...options
529
+ });
530
+ }
531
+ };
532
+
533
+ // src/resources/chat/index.ts
534
+ var Chat = class {
535
+ completions;
536
+ constructor(transport) {
537
+ this.completions = new Completions(transport);
538
+ }
539
+ };
540
+
541
+ // src/resources/embeddings.ts
542
+ var Embeddings = class {
543
+ transport;
544
+ constructor(transport) {
545
+ this.transport = transport;
546
+ }
547
+ /**
548
+ * Creates an embedding vector representing the input text.
549
+ */
550
+ async create(params, options = {}) {
551
+ const { zorveusMetadata, ...requestBody } = params;
552
+ const gatewayMetadata = formatGatewayMetadata(zorveusMetadata);
553
+ const payload = {
554
+ ...requestBody,
555
+ ...gatewayMetadata ? { metadata: gatewayMetadata } : {}
556
+ };
557
+ return this.transport.request("/embeddings", {
558
+ method: "POST",
559
+ body: payload,
560
+ isGateway: true,
561
+ ...options
562
+ });
563
+ }
564
+ };
565
+
566
+ // src/resources/models.ts
567
+ var Models = class {
568
+ transport;
569
+ constructor(transport) {
570
+ this.transport = transport;
571
+ }
572
+ /**
573
+ * Lists available models on the Zorveus gateway.
574
+ */
575
+ async list(params = {}, options = {}) {
576
+ const query = {};
577
+ if (params.routeStatus) {
578
+ query.route_status = params.routeStatus;
579
+ }
580
+ return this.transport.request("/models", {
581
+ method: "GET",
582
+ query,
583
+ isGateway: true,
584
+ ...options
585
+ });
586
+ }
587
+ /**
588
+ * Retrieves information about a specific model.
589
+ */
590
+ async retrieve(modelId, options = {}) {
591
+ return this.transport.request(`/models/${encodeURIComponent(modelId)}`, {
592
+ method: "GET",
593
+ isGateway: true,
594
+ ...options
595
+ });
596
+ }
597
+ };
598
+
599
+ // src/client.ts
600
+ var ZorveusInferenceClient = class {
601
+ chat;
602
+ embeddings;
603
+ models;
604
+ transport;
605
+ constructor(options) {
606
+ if (!options || !options.apiKey) {
607
+ throw new Error(
608
+ "ZorveusInferenceClient requires an 'apiKey' (Inference Key or OAuth Access Token)."
609
+ );
610
+ }
611
+ const baseURL = options.baseURL ? options.baseURL.replace(/\/+$/, "") : options.gatewayBaseURL ? options.gatewayBaseURL.replace(/\/v1\/?$/, "").replace(/\/+$/, "") : "https://api.zorveus.com";
612
+ const gatewayBaseURL = (options.gatewayBaseURL || `${baseURL}/v1`).replace(/\/+$/, "");
613
+ this.transport = new HTTPTransport({
614
+ apiKey: options.apiKey,
615
+ baseURL,
616
+ gatewayBaseURL,
617
+ timeout: options.timeout,
618
+ maxRetries: options.maxRetries,
619
+ defaultHeaders: options.defaultHeaders,
620
+ fetch: options.fetch
621
+ });
622
+ this.chat = new Chat(this.transport);
623
+ this.embeddings = new Embeddings(this.transport);
624
+ this.models = new Models(this.transport);
625
+ }
626
+ /**
627
+ * Retrieves live spend, budget cap, and balance for the active inference key (`GET /inference-keys/usage`).
628
+ */
629
+ async getUsage(options = {}) {
630
+ return this.transport.request("/inference-keys/usage", {
631
+ method: "GET",
632
+ ...options
633
+ });
634
+ }
635
+ };
636
+ var Zorveus = class extends ZorveusInferenceClient {
637
+ };
638
+
639
+ // src/utils/decimal.ts
640
+ function isValidDecimalString(value) {
641
+ if (typeof value !== "string") {
642
+ return false;
643
+ }
644
+ const trimmed = value.trim();
645
+ if (!trimmed) {
646
+ return false;
647
+ }
648
+ const decimalRegex = /^-?\d+(\.\d+)?$/;
649
+ return decimalRegex.test(trimmed);
650
+ }
651
+ function assertDecimalString(value, fieldName) {
652
+ if (typeof value === "number") {
653
+ return value.toFixed(4);
654
+ }
655
+ if (isValidDecimalString(value)) {
656
+ return value.trim();
657
+ }
658
+ throw new TypeError(
659
+ `Field '${fieldName}' must be a valid decimal string (e.g. "15.0000"), received: ${JSON.stringify(value)}`
660
+ );
661
+ }
662
+
663
+ // src/resources/product-users.ts
664
+ var ProductUsers = class {
665
+ transport;
666
+ constructor(transport) {
667
+ this.transport = transport;
668
+ }
669
+ /**
670
+ * Upserts a product user by external user ID (`PUT /product-users/by-external-id`).
671
+ * Creates the user if they do not exist, or updates their profile if they do.
672
+ */
673
+ async createOrUpdate(params, options = {}) {
674
+ const payload = {
675
+ ...params.appId ? { app_id: params.appId } : {},
676
+ external_user_id: params.externalUserId,
677
+ display_name: params.displayName ?? null,
678
+ email: params.email ?? null,
679
+ metadata: params.metadata ?? null
680
+ };
681
+ const query = params.orgId ? { org_id: params.orgId } : void 0;
682
+ return this.transport.request("/product-users/by-external-id", {
683
+ method: "PUT",
684
+ body: payload,
685
+ query,
686
+ ...options
687
+ });
688
+ }
689
+ /**
690
+ * Alias for `createOrUpdate` (`PUT /product-users/by-external-id`).
691
+ */
692
+ async upsert(params, options = {}) {
693
+ return this.createOrUpdate(params, options);
694
+ }
695
+ /**
696
+ * Retrieves a single product end-user by ID (`GET /product-users/{product_end_user_id}`).
697
+ */
698
+ async get(productEndUserId, options = {}) {
699
+ return this.transport.request(
700
+ `/product-users/${encodeURIComponent(productEndUserId)}`,
701
+ {
702
+ method: "GET",
703
+ ...options
704
+ }
705
+ );
706
+ }
707
+ /**
708
+ * Retrieves a product user profile by external ID (`GET /product-users/by-external-id`).
709
+ * Returns complete profile with usage, active cap, and live credits.
710
+ */
711
+ async getByExternalId(params, options = {}) {
712
+ const query = {
713
+ app_id: params.appId,
714
+ external_user_id: params.externalUserId
715
+ };
716
+ if (params.orgId) {
717
+ query.org_id = params.orgId;
718
+ }
719
+ return this.transport.request("/product-users/by-external-id", {
720
+ method: "GET",
721
+ query,
722
+ ...options
723
+ });
724
+ }
725
+ /**
726
+ * Retrieves a product user's live credit summary by external ID (`GET /product-users/by-external-id/credit-summary`).
727
+ */
728
+ async getCreditSummaryByExternalId(params, options = {}) {
729
+ const query = {
730
+ app_id: params.appId,
731
+ external_user_id: params.externalUserId
732
+ };
733
+ if (params.currency) {
734
+ query.currency = params.currency;
735
+ }
736
+ if (params.orgId) {
737
+ query.org_id = params.orgId;
738
+ }
739
+ return this.transport.request(
740
+ "/product-users/by-external-id/credit-summary",
741
+ {
742
+ method: "GET",
743
+ query,
744
+ ...options
745
+ }
746
+ );
747
+ }
748
+ /**
749
+ * Lists product end-users for an organization (`GET /product-users`).
750
+ */
751
+ async list(params = {}, options = {}) {
752
+ const query = {};
753
+ if (params.orgId) query.org_id = params.orgId;
754
+ if (params.limit !== void 0) query.limit = params.limit;
755
+ if (params.offset !== void 0) query.offset = params.offset;
756
+ return this.transport.request("/product-users", {
757
+ method: "GET",
758
+ query,
759
+ ...options
760
+ });
761
+ }
762
+ /**
763
+ * Grants startup-funded AI credits to a product user (`POST /product-users/{id}/credit-grants`).
764
+ * Validates amount as a strict financial decimal string.
765
+ */
766
+ async grantCredit(productEndUserId, params, options = {}) {
767
+ const amount = assertDecimalString(params.amount, "grantCredit.amount");
768
+ const payload = {
769
+ app_id: params.appId,
770
+ amount,
771
+ currency: params.currency || "USD",
772
+ reason: params.reason ?? null,
773
+ expires_at: params.expiresAt ?? null,
774
+ metadata: params.metadata ?? null
775
+ };
776
+ const query = params.orgId ? { org_id: params.orgId } : void 0;
777
+ return this.transport.request(
778
+ `/product-users/${encodeURIComponent(productEndUserId)}/credit-grants`,
779
+ {
780
+ method: "POST",
781
+ body: payload,
782
+ query,
783
+ ...options
784
+ }
785
+ );
786
+ }
787
+ /**
788
+ * Grants credits to an end user by external ID (`POST /product-users/by-external-id/credit-grants`).
789
+ * Automatically provisions the product user if they do not exist yet.
790
+ */
791
+ async grantCreditByExternalId(params, options = {}) {
792
+ const amount = assertDecimalString(params.amount, "grantCreditByExternalId.amount");
793
+ const payload = {
794
+ app_id: params.appId,
795
+ external_user_id: params.externalUserId,
796
+ display_name: params.displayName ?? null,
797
+ email: params.email ?? null,
798
+ amount,
799
+ currency: params.currency || "USD",
800
+ source: params.source ?? null,
801
+ reason: params.reason ?? null,
802
+ expires_at: params.expiresAt ?? null,
803
+ metadata: params.metadata ?? null
804
+ };
805
+ const query = params.orgId ? { org_id: params.orgId } : void 0;
806
+ return this.transport.request(
807
+ "/product-users/by-external-id/credit-grants",
808
+ {
809
+ method: "POST",
810
+ body: payload,
811
+ query,
812
+ ...options
813
+ }
814
+ );
815
+ }
816
+ /**
817
+ * Lists credit grants for a product user (`GET /product-users/{id}/credit-grants`).
818
+ * Accepts either an external user ID or a Zorveus product user ID.
819
+ */
820
+ async listCreditGrants(userIdentifier, params = {}, options = {}) {
821
+ const query = {};
822
+ if (params.appId) query.app_id = params.appId;
823
+ if (params.orgId) query.org_id = params.orgId;
824
+ if (params.limit !== void 0) query.limit = params.limit;
825
+ if (params.offset !== void 0) query.offset = params.offset;
826
+ return this.transport.request(
827
+ `/product-users/${encodeURIComponent(userIdentifier)}/credit-grants`,
828
+ {
829
+ method: "GET",
830
+ query,
831
+ ...options
832
+ }
833
+ );
834
+ }
835
+ /**
836
+ * Lists credit grants for a product user by external ID (`GET /product-users/by-external-id/credit-grants`).
837
+ */
838
+ async listCreditGrantsByExternalId(params, options = {}) {
839
+ const query = {
840
+ app_id: params.appId,
841
+ external_user_id: params.externalUserId
842
+ };
843
+ if (params.status) query.status = params.status;
844
+ if (params.source) query.source = params.source;
845
+ if (params.limit !== void 0) query.limit = params.limit;
846
+ if (params.orgId) query.org_id = params.orgId;
847
+ return this.transport.request(
848
+ "/product-users/by-external-id/credit-grants",
849
+ {
850
+ method: "GET",
851
+ query,
852
+ ...options
853
+ }
854
+ );
855
+ }
856
+ /**
857
+ * Revokes an active credit grant (`POST /product-users/{id}/credit-grants/{grantId}/revoke`).
858
+ */
859
+ async revokeCredit(productEndUserId, creditGrantId, options = {}) {
860
+ return this.transport.request(
861
+ `/product-users/${encodeURIComponent(productEndUserId)}/credit-grants/${encodeURIComponent(creditGrantId)}/revoke`,
862
+ {
863
+ method: "POST",
864
+ ...options
865
+ }
866
+ );
867
+ }
868
+ };
869
+
870
+ // src/resources/provider-credentials.ts
871
+ var ProviderCredentials = class {
872
+ transport;
873
+ constructor(transport) {
874
+ this.transport = transport;
875
+ }
876
+ /**
877
+ * Registers an organization BYOK provider credential via Service Key (`POST /provider-credentials/org-programmatic`).
878
+ */
879
+ async create(params, options = {}) {
880
+ const payload = {
881
+ provider: params.provider,
882
+ credential_name: params.credentialName,
883
+ api_key: params.apiKey,
884
+ secret_kind: params.secretKind || "api_key",
885
+ model_policies: params.modelPolicies || [],
886
+ provider_config: params.providerConfig ?? null,
887
+ routing_mode: params.routingMode || "auto_resolve",
888
+ routing_priority: params.routingPriority ?? 100
889
+ };
890
+ const query = params.orgId ? { org_id: params.orgId } : void 0;
891
+ return this.transport.request(
892
+ "/provider-credentials/org-programmatic",
893
+ {
894
+ method: "POST",
895
+ body: payload,
896
+ query,
897
+ ...options
898
+ }
899
+ );
900
+ }
901
+ /**
902
+ * Lists BYOK provider credentials for an organization (`GET /provider-credentials/org-programmatic`).
903
+ */
904
+ async list(params = {}, options = {}) {
905
+ const query = {};
906
+ if (params.orgId) query.org_id = params.orgId;
907
+ if (params.status) query.status = params.status;
908
+ return this.transport.request(
909
+ "/provider-credentials/org-programmatic",
910
+ {
911
+ method: "GET",
912
+ query,
913
+ ...options
914
+ }
915
+ );
916
+ }
917
+ /**
918
+ * Rotates a provider credential secret (`POST /provider-credentials/org-programmatic/{id}/rotate`).
919
+ */
920
+ async rotate(providerCredentialId, params, options = {}) {
921
+ const payload = {
922
+ api_key: params.apiKey,
923
+ secret_kind: params.secretKind || "api_key"
924
+ };
925
+ const query = params.orgId ? { org_id: params.orgId } : void 0;
926
+ return this.transport.request(
927
+ `/provider-credentials/org-programmatic/${encodeURIComponent(providerCredentialId)}/rotate`,
928
+ {
929
+ method: "POST",
930
+ body: payload,
931
+ query,
932
+ ...options
933
+ }
934
+ );
935
+ }
936
+ /**
937
+ * Deletes a provider credential (`DELETE /provider-credentials/org-programmatic/{id}`).
938
+ */
939
+ async delete(providerCredentialId, options = {}) {
940
+ return this.transport.request(
941
+ `/provider-credentials/org-programmatic/${encodeURIComponent(providerCredentialId)}`,
942
+ {
943
+ method: "DELETE",
944
+ ...options
945
+ }
946
+ );
947
+ }
948
+ /**
949
+ * Lists supported AI provider catalog (`GET /provider-credentials/providers`).
950
+ */
951
+ async listProviders(options = {}) {
952
+ return this.transport.request(
953
+ "/provider-credentials/providers",
954
+ {
955
+ method: "GET",
956
+ ...options
957
+ }
958
+ );
959
+ }
960
+ };
961
+
962
+ // src/service-client.ts
963
+ var ZorveusServiceClient = class {
964
+ productUsers;
965
+ providerCredentials;
966
+ transport;
967
+ constructor(options) {
968
+ if (!options || !options.apiKey) {
969
+ throw new Error(
970
+ "ZorveusServiceClient requires an 'apiKey' (Organization Service Key 'zrv_service_...')."
971
+ );
972
+ }
973
+ const baseURL = (options.baseURL || "https://api.zorveus.com").replace(/\/+$/, "");
974
+ this.transport = new HTTPTransport({
975
+ apiKey: options.apiKey,
976
+ baseURL,
977
+ timeout: options.timeout,
978
+ maxRetries: options.maxRetries,
979
+ defaultHeaders: options.defaultHeaders,
980
+ fetch: options.fetch
981
+ });
982
+ this.productUsers = new ProductUsers(this.transport);
983
+ this.providerCredentials = new ProviderCredentials(this.transport);
984
+ }
985
+ };
986
+
987
+ // src/utils/crypto.ts
988
+ function getCrypto() {
989
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
990
+ return globalThis.crypto;
991
+ }
992
+ throw new Error("Web Crypto API (crypto.subtle) is not available in the current environment.");
993
+ }
994
+ function base64UrlEncode(buffer) {
995
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
996
+ let binary = "";
997
+ for (let i = 0; i < bytes.byteLength; i++) {
998
+ binary += String.fromCharCode(bytes[i]);
999
+ }
1000
+ const base64 = typeof btoa === "function" ? btoa(binary) : Buffer.from(bytes).toString("base64");
1001
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1002
+ }
1003
+ function generateRandomString(byteLength = 32) {
1004
+ const crypto = getCrypto();
1005
+ const randomBytes = new Uint8Array(byteLength);
1006
+ crypto.getRandomValues(randomBytes);
1007
+ return base64UrlEncode(randomBytes);
1008
+ }
1009
+ async function sha256Base64Url(plainText) {
1010
+ const crypto = getCrypto();
1011
+ const encoder = new TextEncoder();
1012
+ const data = encoder.encode(plainText);
1013
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
1014
+ return base64UrlEncode(hashBuffer);
1015
+ }
1016
+
1017
+ // src/oauth.ts
1018
+ var ZorveusOAuth = class {
1019
+ /**
1020
+ * Generates an RFC 7636 PKCE code_verifier, code_challenge (S256), and CSRF state parameter.
1021
+ */
1022
+ static async generatePKCE(byteLength = 32) {
1023
+ const codeVerifier = generateRandomString(byteLength);
1024
+ const codeChallenge = await sha256Base64Url(codeVerifier);
1025
+ const state = generateRandomString(32);
1026
+ return {
1027
+ codeVerifier,
1028
+ codeChallenge,
1029
+ state
1030
+ };
1031
+ }
1032
+ /**
1033
+ * Constructs the Zorveus OAuth PKCE consent URL.
1034
+ */
1035
+ static getAuthorizationUrl(params) {
1036
+ const baseUrl = (params.baseURL || "https://api.zorveus.com").replace(/\/+$/, "");
1037
+ const url = new URL(`${baseUrl}/oauth/authorize`);
1038
+ url.searchParams.set("client_id", params.clientId);
1039
+ url.searchParams.set("redirect_uri", params.redirectUri);
1040
+ url.searchParams.set("state", params.state);
1041
+ url.searchParams.set("code_challenge", params.codeChallenge);
1042
+ url.searchParams.set("code_challenge_method", "S256");
1043
+ url.searchParams.set("response_type", "code");
1044
+ const scopes = params.scopes ? Array.isArray(params.scopes) ? params.scopes.join(" ") : params.scopes : "inference:write models:*";
1045
+ url.searchParams.set("scope", scopes);
1046
+ return url.toString();
1047
+ }
1048
+ /**
1049
+ * Validates OAuth redirect parameters against expected CSRF state.
1050
+ */
1051
+ static validateCallback(options) {
1052
+ let params;
1053
+ if (typeof options.urlOrParams === "string") {
1054
+ const urlStr = options.urlOrParams;
1055
+ const queryIdx = urlStr.indexOf("?");
1056
+ const search = queryIdx !== -1 ? urlStr.slice(queryIdx) : urlStr;
1057
+ params = new URLSearchParams(search);
1058
+ } else if (options.urlOrParams instanceof URLSearchParams) {
1059
+ params = options.urlOrParams;
1060
+ } else if (options.urlOrParams && typeof options.urlOrParams === "object") {
1061
+ params = new URLSearchParams();
1062
+ for (const [key, value] of Object.entries(options.urlOrParams)) {
1063
+ if (value !== void 0 && value !== null && value !== "undefined" && value !== "null") {
1064
+ params.set(key, String(value));
1065
+ }
1066
+ }
1067
+ } else {
1068
+ params = new URLSearchParams();
1069
+ }
1070
+ const rawError = params.get("error");
1071
+ const isRealError = rawError && rawError !== "undefined" && rawError !== "null";
1072
+ if (isRealError) {
1073
+ const rawDesc = params.get("error_description");
1074
+ const errorDescription = rawDesc && rawDesc !== "undefined" && rawDesc !== "null" ? rawDesc : void 0;
1075
+ return {
1076
+ valid: false,
1077
+ error: rawError,
1078
+ errorDescription
1079
+ };
1080
+ }
1081
+ const rawCode = params.get("code");
1082
+ const code = rawCode && rawCode !== "undefined" && rawCode !== "null" ? rawCode : void 0;
1083
+ if (!code) {
1084
+ return {
1085
+ valid: false,
1086
+ error: "invalid_response",
1087
+ errorDescription: "Missing authorization code in redirect params"
1088
+ };
1089
+ }
1090
+ const rawState = params.get("state");
1091
+ const state = rawState && rawState !== "undefined" && rawState !== "null" ? rawState : void 0;
1092
+ if (options.expectedState && state !== options.expectedState) {
1093
+ return {
1094
+ valid: false,
1095
+ error: "state_mismatch",
1096
+ errorDescription: "State parameter does not match expected CSRF token"
1097
+ };
1098
+ }
1099
+ return {
1100
+ valid: true,
1101
+ code,
1102
+ state
1103
+ };
1104
+ }
1105
+ /**
1106
+ * Exchanges an OAuth authorization code for a Zorveus inference key using application/x-www-form-urlencoded.
1107
+ */
1108
+ static async exchangeToken(params) {
1109
+ const baseUrl = (params.baseURL || "https://api.zorveus.com").replace(/\/+$/, "");
1110
+ const url = `${baseUrl}/oauth/token`;
1111
+ const bodyParams = new URLSearchParams();
1112
+ bodyParams.append("grant_type", "authorization_code");
1113
+ bodyParams.append("client_id", params.clientId);
1114
+ bodyParams.append("code", params.code);
1115
+ bodyParams.append("code_verifier", params.codeVerifier);
1116
+ bodyParams.append("redirect_uri", params.redirectUri);
1117
+ if (params.clientSecret) {
1118
+ bodyParams.append("client_secret", params.clientSecret);
1119
+ }
1120
+ const headers = {
1121
+ "Content-Type": "application/x-www-form-urlencoded",
1122
+ Accept: "application/json"
1123
+ };
1124
+ if (typeof window === "undefined") {
1125
+ headers["User-Agent"] = "@zorveus/sdk/0.1.0";
1126
+ }
1127
+ const response = await fetch(url, {
1128
+ method: "POST",
1129
+ headers,
1130
+ body: bodyParams.toString()
1131
+ });
1132
+ if (!response.ok) {
1133
+ let errorBody;
1134
+ try {
1135
+ errorBody = await response.json();
1136
+ } catch {
1137
+ errorBody = await response.text();
1138
+ }
1139
+ throw createAPIError(response.status, errorBody);
1140
+ }
1141
+ const tokenData = await response.json();
1142
+ return tokenData;
1143
+ }
1144
+ /**
1145
+ * Revokes an existing OAuth token or app connection using application/x-www-form-urlencoded.
1146
+ */
1147
+ static async revokeToken(params) {
1148
+ const baseUrl = (params.baseURL || "https://api.zorveus.com").replace(/\/+$/, "");
1149
+ const url = `${baseUrl}/oauth/revoke`;
1150
+ const bodyParams = new URLSearchParams();
1151
+ bodyParams.append("token", params.token);
1152
+ if (params.clientId) {
1153
+ bodyParams.append("client_id", params.clientId);
1154
+ }
1155
+ if (params.clientSecret) {
1156
+ bodyParams.append("client_secret", params.clientSecret);
1157
+ }
1158
+ const headers = {
1159
+ "Content-Type": "application/x-www-form-urlencoded",
1160
+ Accept: "application/json"
1161
+ };
1162
+ if (typeof window === "undefined") {
1163
+ headers["User-Agent"] = "@zorveus/sdk/0.1.0";
1164
+ }
1165
+ const response = await fetch(url, {
1166
+ method: "POST",
1167
+ headers,
1168
+ body: bodyParams.toString()
1169
+ });
1170
+ if (!response.ok) {
1171
+ let errorBody;
1172
+ try {
1173
+ errorBody = await response.json();
1174
+ } catch {
1175
+ errorBody = await response.text();
1176
+ }
1177
+ throw createAPIError(response.status, errorBody);
1178
+ }
1179
+ }
1180
+ };
1181
+ // Annotate the CommonJS export names for ESM import in node:
1182
+ 0 && (module.exports = {
1183
+ APIConnectionError,
1184
+ APIStatusError,
1185
+ AuthenticationError,
1186
+ CapExceededError,
1187
+ CreditGrantExpiredError,
1188
+ InsufficientFundsError,
1189
+ InternalServerError,
1190
+ NotFoundError,
1191
+ PermissionDeniedError,
1192
+ RateLimitError,
1193
+ UnprocessableEntityError,
1194
+ Zorveus,
1195
+ ZorveusBusinessError,
1196
+ ZorveusError,
1197
+ ZorveusInferenceClient,
1198
+ ZorveusOAuth,
1199
+ ZorveusServiceClient,
1200
+ assertDecimalString,
1201
+ createAPIError,
1202
+ formatGatewayMetadata,
1203
+ isValidDecimalString
1204
+ });
1205
+ //# sourceMappingURL=index.js.map