@apicity/xai 0.6.7 → 0.7.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 +227 -3
- package/dist/src/example.d.ts.map +1 -1
- package/dist/src/example.js +22 -4
- package/dist/src/example.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/middleware.d.ts +2 -22
- package/dist/src/middleware.d.ts.map +1 -1
- package/dist/src/middleware.js +85 -8
- package/dist/src/middleware.js.map +1 -1
- package/dist/src/paygate.d.ts +1 -0
- package/dist/src/paygate.d.ts.map +1 -1
- package/dist/src/paygate.js +12 -0
- package/dist/src/paygate.js.map +1 -1
- package/dist/src/rate-limits.d.ts +23 -0
- package/dist/src/rate-limits.d.ts.map +1 -0
- package/dist/src/rate-limits.js +8 -0
- package/dist/src/rate-limits.js.map +1 -0
- package/dist/src/transport.d.ts +40 -0
- package/dist/src/transport.d.ts.map +1 -0
- package/dist/src/transport.js +136 -0
- package/dist/src/transport.js.map +1 -0
- package/dist/src/types.d.ts +63 -5
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/with-paid-gate.d.ts.map +1 -1
- package/dist/src/with-paid-gate.js +2 -0
- package/dist/src/with-paid-gate.js.map +1 -1
- package/dist/src/xai.d.ts.map +1 -1
- package/dist/src/xai.js +262 -419
- package/dist/src/xai.js.map +1 -1
- package/dist/src/zod.d.ts +144 -10
- package/dist/src/zod.d.ts.map +1 -1
- package/dist/src/zod.js +114 -12
- package/dist/src/zod.js.map +1 -1
- package/package.json +1 -1
package/dist/src/xai.js
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
import { XaiError, } from "./types.js";
|
|
2
|
-
import { XaiChatRequestSchema, XaiImageGenerateRequestSchema, XaiImageEditRequestSchema, XaiVideoGenerateRequestSchema, XaiGrokImagineVideo15ImageToVideoRequestSchema, XaiVideoEditRequestSchema, XaiVideoExtendRequestSchema, XaiBatchCreateRequestSchema, XaiCollectionCreateRequestSchema, XaiCollectionUpdateRequestSchema, XaiDocumentSearchRequestSchema, XaiResponseRequestSchema, XaiResponseCompactRequestSchema, XaiTokenizeTextRequestSchema, XaiRealtimeClientSecretRequestSchema, XaiTtsRequestSchema, XaiSttRequestSchema, XaiCustomVoiceCreateRequestSchema, XaiBillingUsageRequestSchema, XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW, } from "./zod.js";
|
|
2
|
+
import { XaiChatRequestSchema, XaiImageGenerateRequestSchema, XaiImageEditRequestSchema, XaiFilePublicUrlRequestSchema, XaiVideoGenerateRequestSchema, XaiGrokImagineVideo15ImageToVideoRequestSchema, XaiVideoEditRequestSchema, XaiVideoExtendRequestSchema, XaiBatchCreateRequestSchema, XaiCollectionCreateRequestSchema, XaiCollectionUpdateRequestSchema, XaiDocumentSearchRequestSchema, XaiResponseRequestSchema, XaiResponseCompactRequestSchema, XaiTokenizeTextRequestSchema, XaiRealtimeClientSecretRequestSchema, XaiTtsRequestSchema, XaiSttRequestSchema, XaiCustomVoiceCreateRequestSchema, XaiCustomVoiceUpdateRequestSchema, XaiBillingUsageRequestSchema, XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW, } from "./zod.js";
|
|
3
3
|
import { attachExamples } from "./example.js";
|
|
4
|
+
import { createTransport } from "./transport.js";
|
|
4
5
|
import { withPaidGate } from "./with-paid-gate.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
function isXaiErrorEnvelope(body) {
|
|
7
|
+
return (typeof body === "object" &&
|
|
8
|
+
body !== null &&
|
|
9
|
+
"error" in body &&
|
|
10
|
+
typeof body.error === "object");
|
|
11
|
+
}
|
|
12
|
+
function parseXaiErrorBody(status, body) {
|
|
13
|
+
if (isXaiErrorEnvelope(body) && typeof body.error?.message === "string") {
|
|
14
|
+
return { message: `XAI API error ${status}: ${body.error.message}` };
|
|
15
|
+
}
|
|
16
|
+
return { message: `XAI API error: ${status}` };
|
|
17
|
+
}
|
|
18
|
+
async function wrapXaiTransportFailure(fn) {
|
|
19
|
+
try {
|
|
20
|
+
return await fn();
|
|
12
21
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error instanceof XaiError)
|
|
24
|
+
throw error;
|
|
25
|
+
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function readJsonResponse(res) {
|
|
29
|
+
return await wrapXaiTransportFailure(async () => (await res.json()));
|
|
30
|
+
}
|
|
31
|
+
async function readArrayBufferResponse(res) {
|
|
32
|
+
return await wrapXaiTransportFailure(async () => await res.arrayBuffer());
|
|
33
|
+
}
|
|
34
|
+
async function jsonRequest(transport, method, path, body, signal) {
|
|
35
|
+
const res = await transport.raw(path, {
|
|
36
|
+
method,
|
|
37
|
+
headers: body === undefined ? undefined : { "Content-Type": "application/json" },
|
|
38
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
39
|
+
signal,
|
|
40
|
+
});
|
|
41
|
+
return await readJsonResponse(res);
|
|
42
|
+
}
|
|
43
|
+
function isAbortSignal(value) {
|
|
44
|
+
return (typeof value === "object" &&
|
|
45
|
+
value !== null &&
|
|
46
|
+
"aborted" in value &&
|
|
47
|
+
"addEventListener" in value);
|
|
48
|
+
}
|
|
49
|
+
function appendOptionalFormField(form, name, value) {
|
|
50
|
+
if (value !== undefined) {
|
|
51
|
+
form.append(name, value);
|
|
16
52
|
}
|
|
17
53
|
}
|
|
18
54
|
const DEFAULT_VIDEO_POLL_INTERVAL_MS = 5000;
|
|
@@ -25,10 +61,22 @@ function normalizeImageReference(image) {
|
|
|
25
61
|
return rest;
|
|
26
62
|
}
|
|
27
63
|
function normalizeImageEditRequest(req) {
|
|
64
|
+
const { image_file_id, image_file_ids, ...rest } = req;
|
|
65
|
+
const normalized = {
|
|
66
|
+
...rest,
|
|
67
|
+
};
|
|
68
|
+
if (normalized.image === undefined && image_file_id !== undefined) {
|
|
69
|
+
normalized.image = { file_id: image_file_id };
|
|
70
|
+
}
|
|
71
|
+
if (normalized.images === undefined && image_file_ids !== undefined) {
|
|
72
|
+
normalized.images = image_file_ids.map((file_id) => ({ file_id }));
|
|
73
|
+
}
|
|
28
74
|
return {
|
|
29
|
-
...
|
|
30
|
-
image:
|
|
31
|
-
|
|
75
|
+
...normalized,
|
|
76
|
+
image: normalized.image === undefined
|
|
77
|
+
? undefined
|
|
78
|
+
: normalizeImageReference(normalized.image),
|
|
79
|
+
images: normalized.images?.map(normalizeImageReference),
|
|
32
80
|
};
|
|
33
81
|
}
|
|
34
82
|
function normalizeVideoReference(image) {
|
|
@@ -36,11 +84,51 @@ function normalizeVideoReference(image) {
|
|
|
36
84
|
return { url: image };
|
|
37
85
|
return image;
|
|
38
86
|
}
|
|
87
|
+
function normalizeVideoGenerateRequest(req) {
|
|
88
|
+
const { image_file_id, video_file_id, reference_image_file_ids, ...rest } = req;
|
|
89
|
+
const normalized = {
|
|
90
|
+
...rest,
|
|
91
|
+
};
|
|
92
|
+
if (normalized.image === undefined && image_file_id !== undefined) {
|
|
93
|
+
normalized.image = { file_id: image_file_id };
|
|
94
|
+
}
|
|
95
|
+
if (normalized.video === undefined && video_file_id !== undefined) {
|
|
96
|
+
normalized.video = { file_id: video_file_id };
|
|
97
|
+
}
|
|
98
|
+
if (normalized.reference_images === undefined &&
|
|
99
|
+
reference_image_file_ids !== undefined) {
|
|
100
|
+
normalized.reference_images = reference_image_file_ids.map((file_id) => ({
|
|
101
|
+
file_id,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
return normalized;
|
|
105
|
+
}
|
|
106
|
+
function normalizeVideoEditRequest(req) {
|
|
107
|
+
const { video_file_id, ...rest } = req;
|
|
108
|
+
const normalized = {
|
|
109
|
+
...rest,
|
|
110
|
+
};
|
|
111
|
+
if (normalized.video === undefined && video_file_id !== undefined) {
|
|
112
|
+
normalized.video = { file_id: video_file_id };
|
|
113
|
+
}
|
|
114
|
+
return normalized;
|
|
115
|
+
}
|
|
116
|
+
function normalizeVideoExtendRequest(req) {
|
|
117
|
+
const { video_file_id, ...rest } = req;
|
|
118
|
+
const normalized = {
|
|
119
|
+
...rest,
|
|
120
|
+
};
|
|
121
|
+
if (normalized.video === undefined && video_file_id !== undefined) {
|
|
122
|
+
normalized.video = { file_id: video_file_id };
|
|
123
|
+
}
|
|
124
|
+
return normalized;
|
|
125
|
+
}
|
|
39
126
|
function applyVideoGenerationDefaults(req) {
|
|
40
|
-
|
|
41
|
-
|
|
127
|
+
const normalized = normalizeVideoGenerateRequest(req);
|
|
128
|
+
if (normalized.model !== undefined)
|
|
129
|
+
return normalized;
|
|
42
130
|
return {
|
|
43
|
-
...
|
|
131
|
+
...normalized,
|
|
44
132
|
model: XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW,
|
|
45
133
|
};
|
|
46
134
|
}
|
|
@@ -67,95 +155,39 @@ export function createXai(opts) {
|
|
|
67
155
|
const managementBaseURL = opts.managementBaseURL ?? "https://management-api.x.ai/v1";
|
|
68
156
|
const managementRootURL = managementBaseURL.replace(/\/v1\/?$/, "");
|
|
69
157
|
const managementApiKey = opts.managementApiKey ?? opts.apiKey;
|
|
70
|
-
const doFetch = opts.fetch ?? fetch;
|
|
71
158
|
const timeout = opts.timeout ?? 30000;
|
|
159
|
+
const transport = createTransport({
|
|
160
|
+
baseUrl: baseURL,
|
|
161
|
+
timeoutMs: timeout,
|
|
162
|
+
fetchImpl: opts.fetch,
|
|
163
|
+
defaultHeaders: () => ({ Authorization: `Bearer ${opts.apiKey}` }),
|
|
164
|
+
parseErrorBody: parseXaiErrorBody,
|
|
165
|
+
errorClass: XaiError,
|
|
166
|
+
requestFailedPrefix: "XAI request failed",
|
|
167
|
+
});
|
|
168
|
+
const managementTransport = createTransport({
|
|
169
|
+
baseUrl: managementBaseURL,
|
|
170
|
+
timeoutMs: timeout,
|
|
171
|
+
fetchImpl: opts.fetch,
|
|
172
|
+
defaultHeaders: () => ({ Authorization: `Bearer ${managementApiKey}` }),
|
|
173
|
+
parseErrorBody: parseXaiErrorBody,
|
|
174
|
+
errorClass: XaiError,
|
|
175
|
+
requestFailedPrefix: "XAI request failed",
|
|
176
|
+
});
|
|
177
|
+
const managementRootTransport = createTransport({
|
|
178
|
+
baseUrl: managementRootURL,
|
|
179
|
+
timeoutMs: timeout,
|
|
180
|
+
fetchImpl: opts.fetch,
|
|
181
|
+
defaultHeaders: () => ({ Authorization: `Bearer ${managementApiKey}` }),
|
|
182
|
+
parseErrorBody: parseXaiErrorBody,
|
|
183
|
+
errorClass: XaiError,
|
|
184
|
+
requestFailedPrefix: "XAI request failed",
|
|
185
|
+
});
|
|
72
186
|
async function makeRequest(method, path, body, signal) {
|
|
73
|
-
|
|
74
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
75
|
-
if (signal) {
|
|
76
|
-
attachAbortHandler(signal, controller);
|
|
77
|
-
}
|
|
78
|
-
try {
|
|
79
|
-
const headers = {
|
|
80
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
81
|
-
};
|
|
82
|
-
const init = {
|
|
83
|
-
method,
|
|
84
|
-
headers,
|
|
85
|
-
signal: controller.signal,
|
|
86
|
-
};
|
|
87
|
-
if (body !== undefined) {
|
|
88
|
-
headers["Content-Type"] = "application/json";
|
|
89
|
-
init.body = JSON.stringify(body);
|
|
90
|
-
}
|
|
91
|
-
const res = await doFetch(`${baseURL}${path}`, init);
|
|
92
|
-
clearTimeout(timeoutId);
|
|
93
|
-
if (!res.ok) {
|
|
94
|
-
let message = `XAI API error: ${res.status}`;
|
|
95
|
-
let body = null;
|
|
96
|
-
try {
|
|
97
|
-
body = await res.json();
|
|
98
|
-
if (typeof body === "object" && body !== null && "error" in body) {
|
|
99
|
-
const err = body.error;
|
|
100
|
-
if (err?.message) {
|
|
101
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
// ignore parse errors
|
|
107
|
-
}
|
|
108
|
-
throw new XaiError(message, res.status, body);
|
|
109
|
-
}
|
|
110
|
-
return (await res.json());
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
clearTimeout(timeoutId);
|
|
114
|
-
if (error instanceof XaiError)
|
|
115
|
-
throw error;
|
|
116
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
117
|
-
}
|
|
187
|
+
return await jsonRequest(transport, method, path, body, signal);
|
|
118
188
|
}
|
|
119
189
|
async function makeGetTextRequest(path, signal) {
|
|
120
|
-
|
|
121
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
122
|
-
if (signal) {
|
|
123
|
-
attachAbortHandler(signal, controller);
|
|
124
|
-
}
|
|
125
|
-
try {
|
|
126
|
-
const res = await doFetch(`${baseURL}${path}`, {
|
|
127
|
-
method: "GET",
|
|
128
|
-
headers: {
|
|
129
|
-
Authorization: `Bearer ${opts.apiKey}`,
|
|
130
|
-
},
|
|
131
|
-
signal: controller.signal,
|
|
132
|
-
});
|
|
133
|
-
clearTimeout(timeoutId);
|
|
134
|
-
if (!res.ok) {
|
|
135
|
-
let message = `XAI API error: ${res.status}`;
|
|
136
|
-
let body = null;
|
|
137
|
-
try {
|
|
138
|
-
body = await res.json();
|
|
139
|
-
if (typeof body === "object" && body !== null && "error" in body) {
|
|
140
|
-
const err = body.error;
|
|
141
|
-
if (err?.message) {
|
|
142
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
// ignore parse errors
|
|
148
|
-
}
|
|
149
|
-
throw new XaiError(message, res.status, body);
|
|
150
|
-
}
|
|
151
|
-
return await res.text();
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
clearTimeout(timeoutId);
|
|
155
|
-
if (error instanceof XaiError)
|
|
156
|
-
throw error;
|
|
157
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
158
|
-
}
|
|
190
|
+
return await transport.getText(path, { signal });
|
|
159
191
|
}
|
|
160
192
|
function buildQuery(params) {
|
|
161
193
|
const parts = [];
|
|
@@ -174,11 +206,19 @@ export function createXai(opts) {
|
|
|
174
206
|
req.model !== XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW) {
|
|
175
207
|
throw new XaiError(`Grok Imagine image-to-video uses ${XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW}`, 400, { model: req.model });
|
|
176
208
|
}
|
|
177
|
-
const { pollIntervalMs = DEFAULT_VIDEO_POLL_INTERVAL_MS, maxPolls = DEFAULT_VIDEO_MAX_POLLS, image, } = req;
|
|
209
|
+
const { pollIntervalMs = DEFAULT_VIDEO_POLL_INTERVAL_MS, maxPolls = DEFAULT_VIDEO_MAX_POLLS, image, image_file_id, } = req;
|
|
210
|
+
const imageReference = image !== undefined
|
|
211
|
+
? normalizeVideoReference(image)
|
|
212
|
+
: image_file_id !== undefined
|
|
213
|
+
? { file_id: image_file_id }
|
|
214
|
+
: undefined;
|
|
215
|
+
if (imageReference === undefined) {
|
|
216
|
+
throw new XaiError("XAI image-to-video requires image or image_file_id", 400);
|
|
217
|
+
}
|
|
178
218
|
const generationRequest = {
|
|
179
219
|
prompt: req.prompt,
|
|
180
220
|
model: XAI_GROK_IMAGINE_VIDEO_1_5_PREVIEW,
|
|
181
|
-
image:
|
|
221
|
+
image: imageReference,
|
|
182
222
|
};
|
|
183
223
|
if (req.duration !== undefined)
|
|
184
224
|
generationRequest.duration = req.duration;
|
|
@@ -188,6 +228,9 @@ export function createXai(opts) {
|
|
|
188
228
|
if (req.resolution !== undefined) {
|
|
189
229
|
generationRequest.resolution = req.resolution;
|
|
190
230
|
}
|
|
231
|
+
if (req.storage_options !== undefined) {
|
|
232
|
+
generationRequest.storage_options = req.storage_options;
|
|
233
|
+
}
|
|
191
234
|
const start = await makeRequest("POST", "/videos/generations", generationRequest, signal);
|
|
192
235
|
let lastStatus;
|
|
193
236
|
for (let poll = 0; poll < maxPolls; poll++) {
|
|
@@ -218,102 +261,10 @@ export function createXai(opts) {
|
|
|
218
261
|
throw new XaiError(`XAI video generation timed out after ${maxPolls} polls: ${start.request_id}`, 408, lastStatus ?? { request_id: start.request_id });
|
|
219
262
|
}
|
|
220
263
|
async function makeManagementRequest(method, path, body, signal) {
|
|
221
|
-
|
|
222
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
223
|
-
if (signal) {
|
|
224
|
-
attachAbortHandler(signal, controller);
|
|
225
|
-
}
|
|
226
|
-
try {
|
|
227
|
-
const headers = {
|
|
228
|
-
Authorization: `Bearer ${managementApiKey}`,
|
|
229
|
-
};
|
|
230
|
-
const init = {
|
|
231
|
-
method,
|
|
232
|
-
headers,
|
|
233
|
-
signal: controller.signal,
|
|
234
|
-
};
|
|
235
|
-
if (body !== undefined) {
|
|
236
|
-
headers["Content-Type"] = "application/json";
|
|
237
|
-
init.body = JSON.stringify(body);
|
|
238
|
-
}
|
|
239
|
-
const res = await doFetch(`${managementBaseURL}${path}`, init);
|
|
240
|
-
clearTimeout(timeoutId);
|
|
241
|
-
if (!res.ok) {
|
|
242
|
-
let message = `XAI API error: ${res.status}`;
|
|
243
|
-
let errBody = null;
|
|
244
|
-
try {
|
|
245
|
-
errBody = await res.json();
|
|
246
|
-
if (typeof errBody === "object" &&
|
|
247
|
-
errBody !== null &&
|
|
248
|
-
"error" in errBody) {
|
|
249
|
-
const err = errBody.error;
|
|
250
|
-
if (err?.message) {
|
|
251
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
// ignore parse errors
|
|
257
|
-
}
|
|
258
|
-
throw new XaiError(message, res.status, errBody);
|
|
259
|
-
}
|
|
260
|
-
return (await res.json());
|
|
261
|
-
}
|
|
262
|
-
catch (error) {
|
|
263
|
-
clearTimeout(timeoutId);
|
|
264
|
-
if (error instanceof XaiError)
|
|
265
|
-
throw error;
|
|
266
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
267
|
-
}
|
|
264
|
+
return await jsonRequest(managementTransport, method, path, body, signal);
|
|
268
265
|
}
|
|
269
266
|
async function makeManagementRootRequest(method, path, body, signal) {
|
|
270
|
-
|
|
271
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
272
|
-
if (signal) {
|
|
273
|
-
attachAbortHandler(signal, controller);
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
const headers = {
|
|
277
|
-
Authorization: `Bearer ${managementApiKey}`,
|
|
278
|
-
};
|
|
279
|
-
const init = {
|
|
280
|
-
method,
|
|
281
|
-
headers,
|
|
282
|
-
signal: controller.signal,
|
|
283
|
-
};
|
|
284
|
-
if (body !== undefined) {
|
|
285
|
-
headers["Content-Type"] = "application/json";
|
|
286
|
-
init.body = JSON.stringify(body);
|
|
287
|
-
}
|
|
288
|
-
const res = await doFetch(`${managementRootURL}${path}`, init);
|
|
289
|
-
clearTimeout(timeoutId);
|
|
290
|
-
if (!res.ok) {
|
|
291
|
-
let message = `XAI API error: ${res.status}`;
|
|
292
|
-
let errBody = null;
|
|
293
|
-
try {
|
|
294
|
-
errBody = await res.json();
|
|
295
|
-
if (typeof errBody === "object" &&
|
|
296
|
-
errBody !== null &&
|
|
297
|
-
"error" in errBody) {
|
|
298
|
-
const err = errBody.error;
|
|
299
|
-
if (err?.message) {
|
|
300
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
catch {
|
|
305
|
-
// ignore parse errors
|
|
306
|
-
}
|
|
307
|
-
throw new XaiError(message, res.status, errBody);
|
|
308
|
-
}
|
|
309
|
-
return (await res.json());
|
|
310
|
-
}
|
|
311
|
-
catch (error) {
|
|
312
|
-
clearTimeout(timeoutId);
|
|
313
|
-
if (error instanceof XaiError)
|
|
314
|
-
throw error;
|
|
315
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
316
|
-
}
|
|
267
|
+
return await jsonRequest(managementRootTransport, method, path, body, signal);
|
|
317
268
|
}
|
|
318
269
|
function buildManagementQuery(params) {
|
|
319
270
|
const parts = [];
|
|
@@ -332,91 +283,19 @@ export function createXai(opts) {
|
|
|
332
283
|
return parts.length > 0 ? `?${parts.join("&")}` : "";
|
|
333
284
|
}
|
|
334
285
|
async function makeBinaryRequest(path, body, signal) {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"Content-Type": "application/json",
|
|
346
|
-
},
|
|
347
|
-
body: JSON.stringify(body),
|
|
348
|
-
signal: controller.signal,
|
|
349
|
-
});
|
|
350
|
-
clearTimeout(timeoutId);
|
|
351
|
-
if (!res.ok) {
|
|
352
|
-
let message = `XAI API error: ${res.status}`;
|
|
353
|
-
let errBody = null;
|
|
354
|
-
try {
|
|
355
|
-
errBody = await res.json();
|
|
356
|
-
if (typeof errBody === "object" &&
|
|
357
|
-
errBody !== null &&
|
|
358
|
-
"error" in errBody) {
|
|
359
|
-
const err = errBody.error;
|
|
360
|
-
if (err?.message) {
|
|
361
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
catch {
|
|
366
|
-
// ignore parse errors
|
|
367
|
-
}
|
|
368
|
-
throw new XaiError(message, res.status, errBody);
|
|
369
|
-
}
|
|
370
|
-
return await res.arrayBuffer();
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
clearTimeout(timeoutId);
|
|
374
|
-
if (error instanceof XaiError)
|
|
375
|
-
throw error;
|
|
376
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
377
|
-
}
|
|
286
|
+
const res = await transport.raw(path, {
|
|
287
|
+
method: "POST",
|
|
288
|
+
headers: { "Content-Type": "application/json" },
|
|
289
|
+
body: JSON.stringify(body),
|
|
290
|
+
signal,
|
|
291
|
+
});
|
|
292
|
+
return await readArrayBufferResponse(res);
|
|
293
|
+
}
|
|
294
|
+
async function makeGetBinaryRequest(path, signal) {
|
|
295
|
+
return await transport.getBinary(path, { signal });
|
|
378
296
|
}
|
|
379
297
|
async function makeMultipartRequest(path, form, signal) {
|
|
380
|
-
|
|
381
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
382
|
-
if (signal) {
|
|
383
|
-
attachAbortHandler(signal, controller);
|
|
384
|
-
}
|
|
385
|
-
try {
|
|
386
|
-
const res = await doFetch(`${baseURL}${path}`, {
|
|
387
|
-
method: "POST",
|
|
388
|
-
headers: { Authorization: `Bearer ${opts.apiKey}` },
|
|
389
|
-
body: form,
|
|
390
|
-
signal: controller.signal,
|
|
391
|
-
});
|
|
392
|
-
clearTimeout(timeoutId);
|
|
393
|
-
if (!res.ok) {
|
|
394
|
-
let message = `XAI API error: ${res.status}`;
|
|
395
|
-
let errBody = null;
|
|
396
|
-
try {
|
|
397
|
-
errBody = await res.json();
|
|
398
|
-
if (typeof errBody === "object" &&
|
|
399
|
-
errBody !== null &&
|
|
400
|
-
"error" in errBody) {
|
|
401
|
-
const err = errBody.error;
|
|
402
|
-
if (err?.message) {
|
|
403
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
catch {
|
|
408
|
-
// ignore parse errors
|
|
409
|
-
}
|
|
410
|
-
throw new XaiError(message, res.status, errBody);
|
|
411
|
-
}
|
|
412
|
-
return (await res.json());
|
|
413
|
-
}
|
|
414
|
-
catch (error) {
|
|
415
|
-
clearTimeout(timeoutId);
|
|
416
|
-
if (error instanceof XaiError)
|
|
417
|
-
throw error;
|
|
418
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
419
|
-
}
|
|
298
|
+
return await transport.postForm(path, form, { signal });
|
|
420
299
|
}
|
|
421
300
|
// POST https://api.x.ai/v1/batches
|
|
422
301
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
@@ -447,13 +326,20 @@ export function createXai(opts) {
|
|
|
447
326
|
await makeManagementRequest("POST", `/collections/${collectionId}/documents/${fileId}`, req ?? {}, signal);
|
|
448
327
|
},
|
|
449
328
|
});
|
|
450
|
-
// GET https://api.x.ai/v1/files/{
|
|
329
|
+
// GET https://api.x.ai/v1/files/{paramsOrFileIdOrSignal}
|
|
451
330
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
452
|
-
async function getFiles(
|
|
453
|
-
if (typeof
|
|
454
|
-
return makeRequest("GET", `/files/${
|
|
455
|
-
}
|
|
456
|
-
|
|
331
|
+
async function getFiles(paramsOrFileIdOrSignal, signal) {
|
|
332
|
+
if (typeof paramsOrFileIdOrSignal === "string") {
|
|
333
|
+
return makeRequest("GET", `/files/${encodeURIComponent(paramsOrFileIdOrSignal)}`, undefined, signal);
|
|
334
|
+
}
|
|
335
|
+
const queryParams = isAbortSignal(paramsOrFileIdOrSignal)
|
|
336
|
+
? {}
|
|
337
|
+
: (paramsOrFileIdOrSignal ?? {});
|
|
338
|
+
const requestSignal = isAbortSignal(paramsOrFileIdOrSignal)
|
|
339
|
+
? paramsOrFileIdOrSignal
|
|
340
|
+
: signal;
|
|
341
|
+
const query = buildQuery(queryParams);
|
|
342
|
+
return makeRequest("GET", `/files${query}`, undefined, requestSignal);
|
|
457
343
|
}
|
|
458
344
|
const getFilesNamespace = Object.assign(getFiles, {
|
|
459
345
|
// GET https://api.x.ai/v1/files/{fileId}/content
|
|
@@ -566,6 +452,56 @@ export function createXai(opts) {
|
|
|
566
452
|
}, {
|
|
567
453
|
schema: XaiCollectionUpdateRequestSchema,
|
|
568
454
|
});
|
|
455
|
+
// POST https://api.x.ai/v1/custom-voices
|
|
456
|
+
// Docs: https://docs.x.ai/developers/model-capabilities/audio/custom-voices
|
|
457
|
+
const postCustomVoices = Object.assign(async function customVoices(req, signal) {
|
|
458
|
+
const form = new FormData();
|
|
459
|
+
form.append("file", req.file, req.filename ?? "reference");
|
|
460
|
+
appendOptionalFormField(form, "name", req.name);
|
|
461
|
+
appendOptionalFormField(form, "description", req.description);
|
|
462
|
+
appendOptionalFormField(form, "gender", req.gender);
|
|
463
|
+
appendOptionalFormField(form, "accent", req.accent);
|
|
464
|
+
appendOptionalFormField(form, "age", req.age);
|
|
465
|
+
appendOptionalFormField(form, "language", req.language);
|
|
466
|
+
appendOptionalFormField(form, "use_case", req.use_case);
|
|
467
|
+
appendOptionalFormField(form, "tone", req.tone);
|
|
468
|
+
return await makeMultipartRequest("/custom-voices", form, signal);
|
|
469
|
+
}, {
|
|
470
|
+
schema: XaiCustomVoiceCreateRequestSchema,
|
|
471
|
+
});
|
|
472
|
+
// GET https://api.x.ai/v1/custom-voices/{paramsOrVoiceIdOrSignal}
|
|
473
|
+
// Docs: https://docs.x.ai/developers/model-capabilities/audio/custom-voices
|
|
474
|
+
const getCustomVoices = Object.assign(async function listCustomVoices(paramsOrVoiceIdOrSignal, signal) {
|
|
475
|
+
if (typeof paramsOrVoiceIdOrSignal === "string") {
|
|
476
|
+
return await makeRequest("GET", `/custom-voices/${encodeURIComponent(paramsOrVoiceIdOrSignal)}`, undefined, signal);
|
|
477
|
+
}
|
|
478
|
+
const queryParams = isAbortSignal(paramsOrVoiceIdOrSignal)
|
|
479
|
+
? {}
|
|
480
|
+
: (paramsOrVoiceIdOrSignal ?? {});
|
|
481
|
+
const requestSignal = isAbortSignal(paramsOrVoiceIdOrSignal)
|
|
482
|
+
? paramsOrVoiceIdOrSignal
|
|
483
|
+
: signal;
|
|
484
|
+
const query = buildQuery(queryParams);
|
|
485
|
+
return await makeRequest("GET", `/custom-voices${query}`, undefined, requestSignal);
|
|
486
|
+
}, {
|
|
487
|
+
// GET https://api.x.ai/v1/custom-voices/{voiceId}/audio
|
|
488
|
+
// Docs: https://docs.x.ai/developers/model-capabilities/audio/custom-voices
|
|
489
|
+
audio: async function customVoiceAudio(voiceId, signal) {
|
|
490
|
+
return await makeGetBinaryRequest(`/custom-voices/${encodeURIComponent(voiceId)}/audio`, signal);
|
|
491
|
+
},
|
|
492
|
+
});
|
|
493
|
+
// PATCH https://api.x.ai/v1/custom-voices/{voiceId}
|
|
494
|
+
// Docs: https://docs.x.ai/developers/model-capabilities/audio/custom-voices
|
|
495
|
+
const patchCustomVoices = Object.assign(async function updateCustomVoice(voiceId, req, signal) {
|
|
496
|
+
return await makeRequest("PATCH", `/custom-voices/${encodeURIComponent(voiceId)}`, req, signal);
|
|
497
|
+
}, {
|
|
498
|
+
schema: XaiCustomVoiceUpdateRequestSchema,
|
|
499
|
+
});
|
|
500
|
+
// DELETE https://api.x.ai/v1/custom-voices/{voiceId}
|
|
501
|
+
// Docs: https://docs.x.ai/developers/model-capabilities/audio/custom-voices
|
|
502
|
+
async function deleteCustomVoices(voiceId, signal) {
|
|
503
|
+
return await makeRequest("DELETE", `/custom-voices/${encodeURIComponent(voiceId)}`, undefined, signal);
|
|
504
|
+
}
|
|
569
505
|
return attachExamples(withPaidGate("xai", {
|
|
570
506
|
post: {
|
|
571
507
|
v1: {
|
|
@@ -622,14 +558,14 @@ export function createXai(opts) {
|
|
|
622
558
|
// POST https://api.x.ai/v1/videos/edits
|
|
623
559
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
624
560
|
edits: Object.assign(async function edits(req, signal) {
|
|
625
|
-
return await makeRequest("POST", "/videos/edits", req, signal);
|
|
561
|
+
return await makeRequest("POST", "/videos/edits", normalizeVideoEditRequest(req), signal);
|
|
626
562
|
}, {
|
|
627
563
|
schema: XaiVideoEditRequestSchema,
|
|
628
564
|
}),
|
|
629
565
|
// POST https://api.x.ai/v1/videos/extensions
|
|
630
566
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
631
567
|
extensions: Object.assign(async function extensions(req, signal) {
|
|
632
|
-
return await makeRequest("POST", "/videos/extensions", req, signal);
|
|
568
|
+
return await makeRequest("POST", "/videos/extensions", normalizeVideoExtendRequest(req), signal);
|
|
633
569
|
}, {
|
|
634
570
|
schema: XaiVideoExtendRequestSchema,
|
|
635
571
|
}),
|
|
@@ -637,52 +573,31 @@ export function createXai(opts) {
|
|
|
637
573
|
// POST https://api.x.ai/v1/files
|
|
638
574
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
639
575
|
files: Object.assign(async function postFiles(file, filename, purpose, signal) {
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
if (
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
});
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
const err = body
|
|
666
|
-
.error;
|
|
667
|
-
if (err?.message) {
|
|
668
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
catch {
|
|
673
|
-
// ignore parse errors
|
|
674
|
-
}
|
|
675
|
-
throw new XaiError(message, res.status, body);
|
|
676
|
-
}
|
|
677
|
-
return (await res.json());
|
|
678
|
-
}
|
|
679
|
-
catch (error) {
|
|
680
|
-
clearTimeout(timeoutId);
|
|
681
|
-
if (error instanceof XaiError)
|
|
682
|
-
throw error;
|
|
683
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
684
|
-
}
|
|
685
|
-
}, {}),
|
|
576
|
+
const formData = new FormData();
|
|
577
|
+
formData.append("file", file, filename);
|
|
578
|
+
if (purpose !== undefined)
|
|
579
|
+
formData.append("purpose", purpose);
|
|
580
|
+
return await makeMultipartRequest("/files", formData, signal);
|
|
581
|
+
}, {
|
|
582
|
+
// POST https://api.x.ai/v1/files/{fileId}/public-url
|
|
583
|
+
// Docs: https://docs.x.ai/developers/files/public-urls
|
|
584
|
+
publicUrl: Object.assign(async function createFilePublicUrl(fileId, reqOrSignal, signal) {
|
|
585
|
+
const req = isAbortSignal(reqOrSignal)
|
|
586
|
+
? {}
|
|
587
|
+
: (reqOrSignal ?? {});
|
|
588
|
+
const requestSignal = isAbortSignal(reqOrSignal)
|
|
589
|
+
? reqOrSignal
|
|
590
|
+
: signal;
|
|
591
|
+
return await makeRequest("POST", `/files/${encodeURIComponent(fileId)}/public-url`, req, requestSignal);
|
|
592
|
+
}, {
|
|
593
|
+
schema: XaiFilePublicUrlRequestSchema,
|
|
594
|
+
// POST https://api.x.ai/v1/files/{fileId}/public-url/revoke
|
|
595
|
+
// Docs: https://docs.x.ai/developers/files/public-urls
|
|
596
|
+
revoke: async function revokeFilePublicUrl(fileId, signal) {
|
|
597
|
+
return await makeRequest("POST", `/files/${encodeURIComponent(fileId)}/public-url/revoke`, {}, signal);
|
|
598
|
+
},
|
|
599
|
+
}),
|
|
600
|
+
}),
|
|
686
601
|
batches: postBatches,
|
|
687
602
|
documents: {
|
|
688
603
|
// POST https://api.x.ai/v1/documents/search
|
|
@@ -728,17 +643,7 @@ export function createXai(opts) {
|
|
|
728
643
|
}, {
|
|
729
644
|
schema: XaiSttRequestSchema,
|
|
730
645
|
}),
|
|
731
|
-
|
|
732
|
-
// Docs: https://docs.x.ai/docs/api-reference
|
|
733
|
-
customVoices: Object.assign(async function customVoices(req, signal) {
|
|
734
|
-
const form = new FormData();
|
|
735
|
-
form.append("file", req.file, req.filename ?? "reference");
|
|
736
|
-
form.append("name", req.name);
|
|
737
|
-
form.append("language", req.language);
|
|
738
|
-
return await makeMultipartRequest("/custom-voices", form, signal);
|
|
739
|
-
}, {
|
|
740
|
-
schema: XaiCustomVoiceCreateRequestSchema,
|
|
741
|
-
}),
|
|
646
|
+
customVoices: postCustomVoices,
|
|
742
647
|
},
|
|
743
648
|
managementApi: {
|
|
744
649
|
v1: {
|
|
@@ -773,50 +678,12 @@ export function createXai(opts) {
|
|
|
773
678
|
// GET https://api.x.ai/v1/chat/deferred-completion/{requestId}
|
|
774
679
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
775
680
|
deferredCompletion: async function deferredCompletion(requestId, signal) {
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
attachAbortHandler(signal, controller);
|
|
780
|
-
}
|
|
781
|
-
try {
|
|
782
|
-
const res = await doFetch(`${baseURL}/chat/deferred-completion/${encodeURIComponent(requestId)}`, {
|
|
783
|
-
method: "GET",
|
|
784
|
-
headers: { Authorization: `Bearer ${opts.apiKey}` },
|
|
785
|
-
signal: controller.signal,
|
|
786
|
-
});
|
|
787
|
-
clearTimeout(timeoutId);
|
|
788
|
-
if (res.status === 202) {
|
|
789
|
-
return { ready: false, data: null };
|
|
790
|
-
}
|
|
791
|
-
if (!res.ok) {
|
|
792
|
-
let message = `XAI API error: ${res.status}`;
|
|
793
|
-
let body = null;
|
|
794
|
-
try {
|
|
795
|
-
body = await res.json();
|
|
796
|
-
if (typeof body === "object" &&
|
|
797
|
-
body !== null &&
|
|
798
|
-
"error" in body) {
|
|
799
|
-
const err = body
|
|
800
|
-
.error;
|
|
801
|
-
if (err?.message) {
|
|
802
|
-
message = `XAI API error ${res.status}: ${err.message}`;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
catch {
|
|
807
|
-
// ignore parse errors
|
|
808
|
-
}
|
|
809
|
-
throw new XaiError(message, res.status, body);
|
|
810
|
-
}
|
|
811
|
-
const data = (await res.json());
|
|
812
|
-
return { ready: true, data };
|
|
813
|
-
}
|
|
814
|
-
catch (error) {
|
|
815
|
-
clearTimeout(timeoutId);
|
|
816
|
-
if (error instanceof XaiError)
|
|
817
|
-
throw error;
|
|
818
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
681
|
+
const res = await transport.raw(`/chat/deferred-completion/${encodeURIComponent(requestId)}`, { signal });
|
|
682
|
+
if (res.status === 202) {
|
|
683
|
+
return { ready: false, data: null };
|
|
819
684
|
}
|
|
685
|
+
const data = await readJsonResponse(res);
|
|
686
|
+
return { ready: true, data };
|
|
820
687
|
},
|
|
821
688
|
},
|
|
822
689
|
// GET https://api.x.ai/v1/videos/{requestId}
|
|
@@ -830,6 +697,7 @@ export function createXai(opts) {
|
|
|
830
697
|
imageGenerationModels: getImageGenerationModels,
|
|
831
698
|
videoGenerationModels: getVideoGenerationModels,
|
|
832
699
|
batches: getBatchesNamespace,
|
|
700
|
+
customVoices: getCustomVoices,
|
|
833
701
|
},
|
|
834
702
|
managementApi: {
|
|
835
703
|
v1: {
|
|
@@ -882,37 +750,9 @@ export function createXai(opts) {
|
|
|
882
750
|
// DELETE https://api.x.ai/v1/files/{fileId}
|
|
883
751
|
// Docs: https://docs.x.ai/docs/api-reference
|
|
884
752
|
files: async function deleteFiles(fileId, signal) {
|
|
885
|
-
|
|
886
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
887
|
-
if (signal) {
|
|
888
|
-
attachAbortHandler(signal, controller);
|
|
889
|
-
}
|
|
890
|
-
try {
|
|
891
|
-
const res = await doFetch(`${baseURL}/files/${fileId}`, {
|
|
892
|
-
method: "DELETE",
|
|
893
|
-
headers: { Authorization: `Bearer ${opts.apiKey}` },
|
|
894
|
-
signal: controller.signal,
|
|
895
|
-
});
|
|
896
|
-
clearTimeout(timeoutId);
|
|
897
|
-
if (!res.ok) {
|
|
898
|
-
let deleteBody = null;
|
|
899
|
-
try {
|
|
900
|
-
deleteBody = await res.json();
|
|
901
|
-
}
|
|
902
|
-
catch {
|
|
903
|
-
// ignore parse errors
|
|
904
|
-
}
|
|
905
|
-
throw new XaiError(`XAI API error: ${res.status}`, res.status, deleteBody);
|
|
906
|
-
}
|
|
907
|
-
return (await res.json());
|
|
908
|
-
}
|
|
909
|
-
catch (error) {
|
|
910
|
-
clearTimeout(timeoutId);
|
|
911
|
-
if (error instanceof XaiError)
|
|
912
|
-
throw error;
|
|
913
|
-
throw new XaiError(`XAI request failed: ${error}`, 500);
|
|
914
|
-
}
|
|
753
|
+
return await makeRequest("DELETE", `/files/${fileId}`, undefined, signal);
|
|
915
754
|
},
|
|
755
|
+
customVoices: deleteCustomVoices,
|
|
916
756
|
},
|
|
917
757
|
managementApi: {
|
|
918
758
|
v1: {
|
|
@@ -928,6 +768,9 @@ export function createXai(opts) {
|
|
|
928
768
|
},
|
|
929
769
|
},
|
|
930
770
|
patch: {
|
|
771
|
+
v1: {
|
|
772
|
+
customVoices: patchCustomVoices,
|
|
773
|
+
},
|
|
931
774
|
managementApi: {
|
|
932
775
|
v1: {
|
|
933
776
|
collections: {
|