@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/README.md +236 -0
- package/dist/index.d.mts +919 -0
- package/dist/index.d.ts +919 -0
- package/dist/index.js +1205 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1158 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +34 -0
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
|