@byte_fluffy/nexra-sdk 0.1.0-alpha.52 → 0.1.0-alpha.53
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 +15 -110
- package/dist/catalog.d.ts +3 -3
- package/dist/catalog.js +2 -2
- package/dist/{chunk-V3KBU3J5.js → chunk-LWJWWD7Z.js} +6605 -8237
- package/dist/chunk-RBKLCJ3H.js +745 -0
- package/dist/{chunk-LEZWVFQH.js → chunk-V3F6VPMP.js} +115 -8
- package/dist/{errors-DJZuAKoO.d.ts → errors-BXPUVOh7.d.ts} +2 -2
- package/dist/index.d.ts +12 -11
- package/dist/index.js +16 -466
- package/dist/{json-Cz0MkWQn.d.ts → json-dnsDzk-s.d.ts} +1 -1
- package/dist/language.d.ts +3 -3
- package/dist/language.js +28 -243
- package/dist/{media-DzOxLGs-.d.ts → media-IaOdOMQC.d.ts} +14 -2
- package/dist/{media-geometry-COln1N_2.d.ts → media-geometry-B92BvuQL.d.ts} +3 -2
- package/dist/media.d.ts +2 -2
- package/dist/media.js +1 -1
- package/dist/node.d.ts +17 -0
- package/dist/node.js +78 -0
- package/dist/types.d.ts +5 -5
- package/dist/{voices-xyPqhQqR.d.ts → voices-Dc94LfyS.d.ts} +42 -5
- package/package.json +7 -1
package/dist/index.js
CHANGED
|
@@ -1,489 +1,37 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssetsClient,
|
|
3
|
+
ModelsClient,
|
|
4
|
+
NexraClient,
|
|
5
|
+
NexraTranscriptionError,
|
|
6
|
+
TasksClient,
|
|
7
|
+
TranscriptionClient,
|
|
8
|
+
VoicesClient,
|
|
9
|
+
createNexra,
|
|
10
|
+
verifyWebhook
|
|
11
|
+
} from "./chunk-RBKLCJ3H.js";
|
|
1
12
|
import {
|
|
2
13
|
ceilDecimal,
|
|
3
14
|
multiplyDecimal
|
|
4
15
|
} from "./chunk-FCH5IQP5.js";
|
|
5
16
|
import {
|
|
6
17
|
CatalogClient,
|
|
7
|
-
HttpTransport,
|
|
8
18
|
NexraApiError,
|
|
9
19
|
NexraTaskError,
|
|
10
20
|
NexraWaitTimeoutError,
|
|
11
21
|
applyMediaGeometry,
|
|
12
|
-
applyNoWatermark,
|
|
13
22
|
decodeMediaGeometry,
|
|
14
23
|
encodeMediaGeometry,
|
|
15
24
|
formatModelDisplayName,
|
|
16
25
|
getModelSpec,
|
|
17
|
-
jsonBody,
|
|
18
26
|
listModelSpecs,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
queryString,
|
|
22
|
-
sleep
|
|
23
|
-
} from "./chunk-V3KBU3J5.js";
|
|
27
|
+
projectMediaGeometry
|
|
28
|
+
} from "./chunk-LWJWWD7Z.js";
|
|
24
29
|
import {
|
|
25
30
|
MEDIA_KINDS,
|
|
26
31
|
TASK_STATUSES,
|
|
27
|
-
createTaskRequest,
|
|
28
32
|
extractUpstreamErrorMessage,
|
|
29
33
|
isTerminalTaskStatus
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
|
|
32
|
-
// src/assets.ts
|
|
33
|
-
var AssetsClient = class {
|
|
34
|
-
constructor(transport) {
|
|
35
|
-
this.transport = transport;
|
|
36
|
-
}
|
|
37
|
-
transport;
|
|
38
|
-
async upload(file, options = {}) {
|
|
39
|
-
const name = options.name ?? (isFile(file) ? file.name : void 0);
|
|
40
|
-
const headers = new Headers({
|
|
41
|
-
"content-type": file.type || "application/octet-stream",
|
|
42
|
-
"x-nexra-asset-kind": options.kind ?? inferKind(file.type)
|
|
43
|
-
});
|
|
44
|
-
if (name) headers.set("x-nexra-file-name", encodeURIComponent(name));
|
|
45
|
-
return this.transport.json(
|
|
46
|
-
"/assets",
|
|
47
|
-
{
|
|
48
|
-
method: "POST",
|
|
49
|
-
body: file,
|
|
50
|
-
headers,
|
|
51
|
-
signal: options.signal
|
|
52
|
-
},
|
|
53
|
-
{ retryable: false }
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
import(request, signal) {
|
|
57
|
-
return this.transport.json("/assets/import", {
|
|
58
|
-
method: "POST",
|
|
59
|
-
...jsonBody(request),
|
|
60
|
-
signal
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
get(assetId, signal) {
|
|
64
|
-
return this.transport.json(`/assets/${encodeURIComponent(assetId)}`, {
|
|
65
|
-
signal
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
certifyForSeedance(asset, request = {}, signal) {
|
|
69
|
-
const assetId = typeof asset === "string" ? asset : asset.id;
|
|
70
|
-
return this.transport.json(
|
|
71
|
-
`/assets/${encodeURIComponent(assetId)}/certifications/seedance`,
|
|
72
|
-
{
|
|
73
|
-
method: "POST",
|
|
74
|
-
...jsonBody(request),
|
|
75
|
-
signal
|
|
76
|
-
},
|
|
77
|
-
{ retryable: false }
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
getSeedanceCertification(asset, signal) {
|
|
81
|
-
const assetId = typeof asset === "string" ? asset : asset.id;
|
|
82
|
-
return this.transport.json(
|
|
83
|
-
`/assets/${encodeURIComponent(assetId)}/certifications/seedance`,
|
|
84
|
-
{ signal }
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
async waitForSeedanceCertification(asset, options = {}) {
|
|
88
|
-
const pollIntervalMs = positiveInteger(options.pollIntervalMs ?? 2e3, "pollIntervalMs");
|
|
89
|
-
const timeoutMs = positiveInteger(options.timeoutMs ?? 3e5, "timeoutMs");
|
|
90
|
-
const deadline = Date.now() + timeoutMs;
|
|
91
|
-
while (true) {
|
|
92
|
-
const certification = await this.getSeedanceCertification(asset, options.signal);
|
|
93
|
-
if (certification.status !== "processing") return certification;
|
|
94
|
-
if (Date.now() >= deadline) {
|
|
95
|
-
throw new Error("Timed out waiting for Seedance Asset certification");
|
|
96
|
-
}
|
|
97
|
-
await wait(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())), options.signal);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
download(asset, signal) {
|
|
101
|
-
const assetId = typeof asset === "string" ? asset : asset.id;
|
|
102
|
-
return this.transport.response(`/assets/${encodeURIComponent(assetId)}/content`, {
|
|
103
|
-
signal
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
async stream(asset, signal) {
|
|
107
|
-
const response = await this.download(asset, signal);
|
|
108
|
-
if (!response.body) throw new Error("Asset response did not contain a body stream");
|
|
109
|
-
return response.body;
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
function positiveInteger(value, name) {
|
|
113
|
-
if (!Number.isSafeInteger(value) || value < 1) throw new TypeError(`${name} must be a positive integer`);
|
|
114
|
-
return value;
|
|
115
|
-
}
|
|
116
|
-
async function wait(milliseconds, signal) {
|
|
117
|
-
if (signal?.aborted) throw signal.reason;
|
|
118
|
-
await new Promise((resolve, reject) => {
|
|
119
|
-
const timer = setTimeout(resolve, milliseconds);
|
|
120
|
-
signal?.addEventListener("abort", () => {
|
|
121
|
-
clearTimeout(timer);
|
|
122
|
-
reject(signal.reason);
|
|
123
|
-
}, { once: true });
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
function inferKind(mimeType) {
|
|
127
|
-
if (mimeType.startsWith("image/")) return "image";
|
|
128
|
-
if (mimeType.startsWith("video/")) return "video";
|
|
129
|
-
if (mimeType.startsWith("audio/")) return "audio";
|
|
130
|
-
if (mimeType.startsWith("text/") || mimeType === "application/pdf") return "document";
|
|
131
|
-
if (mimeType.includes("zip") || mimeType.includes("tar")) return "archive";
|
|
132
|
-
return "other";
|
|
133
|
-
}
|
|
134
|
-
function isFile(value) {
|
|
135
|
-
return typeof File !== "undefined" && value instanceof File;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// src/models.ts
|
|
139
|
-
function withModelDisplayName(model) {
|
|
140
|
-
return { ...model, displayName: formatModelDisplayName(model.displayName, model.slug ? { modelId: model.slug } : void 0) };
|
|
141
|
-
}
|
|
142
|
-
var ModelsClient = class {
|
|
143
|
-
constructor(transport) {
|
|
144
|
-
this.transport = transport;
|
|
145
|
-
}
|
|
146
|
-
transport;
|
|
147
|
-
async search(params = {}, signal) {
|
|
148
|
-
const page = await this.transport.json(
|
|
149
|
-
`/models${queryString({
|
|
150
|
-
q: params.query,
|
|
151
|
-
modality: params.modality,
|
|
152
|
-
operation: params.operation,
|
|
153
|
-
category: params.category,
|
|
154
|
-
limit: params.limit,
|
|
155
|
-
cursor: params.cursor
|
|
156
|
-
})}`,
|
|
157
|
-
{ signal }
|
|
158
|
-
);
|
|
159
|
-
return { ...page, data: page.data.map(withModelDisplayName) };
|
|
160
|
-
}
|
|
161
|
-
async get(model, signal) {
|
|
162
|
-
const detail = await this.transport.json(`/models/${encodeURIComponent(model)}`, {
|
|
163
|
-
signal
|
|
164
|
-
});
|
|
165
|
-
return {
|
|
166
|
-
...withModelDisplayName(detail),
|
|
167
|
-
...detail.familyVersions ? { familyVersions: detail.familyVersions.map(withModelDisplayName) } : {}
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
schema(model, signal) {
|
|
171
|
-
return this.transport.json(
|
|
172
|
-
`/models/${encodeURIComponent(model)}/schema`,
|
|
173
|
-
{ signal }
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
resources(model, resource, signal) {
|
|
177
|
-
return this.transport.json(
|
|
178
|
-
`/models/${encodeURIComponent(model)}/resources/${encodeURIComponent(resource)}`,
|
|
179
|
-
{ signal }
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// src/voices.ts
|
|
185
|
-
var VoicesClient = class {
|
|
186
|
-
constructor(transport) {
|
|
187
|
-
this.transport = transport;
|
|
188
|
-
}
|
|
189
|
-
transport;
|
|
190
|
-
async list(signal) {
|
|
191
|
-
const response = await this.transport.json("/voices", { signal });
|
|
192
|
-
return response.data;
|
|
193
|
-
}
|
|
194
|
-
get(voiceId, signal) {
|
|
195
|
-
return this.transport.json(`/voices/${encodeURIComponent(voiceId)}`, { signal });
|
|
196
|
-
}
|
|
197
|
-
create(request, options) {
|
|
198
|
-
if (!options.idempotencyKey.trim()) throw new TypeError("Idempotency-Key is required");
|
|
199
|
-
return this.transport.json("/voices", {
|
|
200
|
-
method: "POST",
|
|
201
|
-
...jsonBody(request),
|
|
202
|
-
headers: { "content-type": "application/json", "idempotency-key": options.idempotencyKey },
|
|
203
|
-
signal: options.signal
|
|
204
|
-
}, { retryable: true });
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
// src/input.ts
|
|
209
|
-
async function normalizeTaskInput(input, assets, signal) {
|
|
210
|
-
const normalized = await normalizeValue(input, assets, signal, /* @__PURE__ */ new WeakSet());
|
|
211
|
-
if (!isPlainObject(normalized)) {
|
|
212
|
-
throw new TypeError("Task input must be a JSON object");
|
|
213
|
-
}
|
|
214
|
-
return normalized;
|
|
215
|
-
}
|
|
216
|
-
async function normalizeValue(value, assets, signal, ancestors) {
|
|
217
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
218
|
-
return value;
|
|
219
|
-
}
|
|
220
|
-
if (typeof value === "number") {
|
|
221
|
-
if (!Number.isFinite(value)) throw new TypeError("Task input numbers must be finite");
|
|
222
|
-
return value;
|
|
223
|
-
}
|
|
224
|
-
if (value instanceof URL) return value.toString();
|
|
225
|
-
if (typeof Blob !== "undefined" && value instanceof Blob) {
|
|
226
|
-
const uploaded = await assets.upload(value, { signal });
|
|
227
|
-
return { assetId: uploaded.id };
|
|
228
|
-
}
|
|
229
|
-
if (isMediaAsset(value)) {
|
|
230
|
-
return { assetId: value.id };
|
|
231
|
-
}
|
|
232
|
-
if (isAssetReference(value)) return { assetId: value.assetId };
|
|
233
|
-
if (Array.isArray(value)) {
|
|
234
|
-
assertNotCircular(value, ancestors);
|
|
235
|
-
const normalized = await Promise.all(
|
|
236
|
-
value.map((item) => normalizeValue(item, assets, signal, ancestors))
|
|
237
|
-
);
|
|
238
|
-
ancestors.delete(value);
|
|
239
|
-
return normalized;
|
|
240
|
-
}
|
|
241
|
-
if (isPlainObject(value)) {
|
|
242
|
-
assertNotCircular(value, ancestors);
|
|
243
|
-
const normalized = {};
|
|
244
|
-
for (const [key, item] of Object.entries(value)) {
|
|
245
|
-
if (item === void 0) continue;
|
|
246
|
-
normalized[key] = await normalizeValue(item, assets, signal, ancestors);
|
|
247
|
-
}
|
|
248
|
-
ancestors.delete(value);
|
|
249
|
-
return normalized;
|
|
250
|
-
}
|
|
251
|
-
throw new TypeError(`Task input contains a non-serializable ${typeof value} value`);
|
|
252
|
-
}
|
|
253
|
-
function assertNotCircular(value, ancestors) {
|
|
254
|
-
if (ancestors.has(value)) throw new TypeError("Task input cannot contain circular references");
|
|
255
|
-
ancestors.add(value);
|
|
256
|
-
}
|
|
257
|
-
function isPlainObject(value) {
|
|
258
|
-
if (!value || typeof value !== "object") return false;
|
|
259
|
-
const prototype = Object.getPrototypeOf(value);
|
|
260
|
-
return prototype === Object.prototype || prototype === null;
|
|
261
|
-
}
|
|
262
|
-
function isAssetReference(value) {
|
|
263
|
-
return isPlainObject(value) && typeof value.assetId === "string";
|
|
264
|
-
}
|
|
265
|
-
function isMediaAsset(value) {
|
|
266
|
-
return isPlainObject(value) && typeof value.id === "string" && typeof value.kind === "string" && typeof value.status === "string" && typeof value.source === "string";
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// src/tasks.ts
|
|
270
|
-
var TasksClient = class {
|
|
271
|
-
constructor(transport, assets) {
|
|
272
|
-
this.transport = transport;
|
|
273
|
-
this.assets = assets;
|
|
274
|
-
}
|
|
275
|
-
transport;
|
|
276
|
-
assets;
|
|
277
|
-
async create(model, input, options = {}) {
|
|
278
|
-
const schema = getModelSpec(model)?.operations[0]?.inputSchema;
|
|
279
|
-
const mapped = schema && input && typeof input === "object" && !Array.isArray(input) ? applyNoWatermark(schema, applyMediaGeometry(schema, input)) : input;
|
|
280
|
-
const normalizedInput = await normalizeTaskInput(mapped, this.assets, options.signal);
|
|
281
|
-
const body = createTaskRequest(model, normalizedInput, {
|
|
282
|
-
quoteToken: options.quoteToken,
|
|
283
|
-
submittedAt: options.submittedAt,
|
|
284
|
-
metadata: options.metadata,
|
|
285
|
-
callback_url: options.callback_url,
|
|
286
|
-
webhook: options.webhook,
|
|
287
|
-
schemaVersion: options.schemaVersion
|
|
288
|
-
});
|
|
289
|
-
const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
|
|
290
|
-
return this.transport.json(
|
|
291
|
-
"/tasks",
|
|
292
|
-
{
|
|
293
|
-
method: "POST",
|
|
294
|
-
...jsonBody(body),
|
|
295
|
-
headers: {
|
|
296
|
-
...jsonBody(body).headers,
|
|
297
|
-
"idempotency-key": idempotencyKey
|
|
298
|
-
},
|
|
299
|
-
signal: options.signal
|
|
300
|
-
},
|
|
301
|
-
{ retryable: true }
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
get(taskId, signal) {
|
|
305
|
-
return this.transport.json(`/tasks/${encodeURIComponent(taskId)}`, {
|
|
306
|
-
signal
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
list(params = {}, signal) {
|
|
310
|
-
return this.transport.json(
|
|
311
|
-
`/tasks${queryString({
|
|
312
|
-
status: params.status,
|
|
313
|
-
model: params.model,
|
|
314
|
-
limit: params.limit,
|
|
315
|
-
cursor: params.cursor
|
|
316
|
-
})}`,
|
|
317
|
-
{ signal }
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
cancel(taskId, signal) {
|
|
321
|
-
return this.transport.json(
|
|
322
|
-
`/tasks/${encodeURIComponent(taskId)}/cancel`,
|
|
323
|
-
{ method: "POST", signal },
|
|
324
|
-
{ retryable: true }
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
async *watch(taskId, options = {}) {
|
|
328
|
-
let lastEventId = options.lastEventId;
|
|
329
|
-
let reconnects = 0;
|
|
330
|
-
let reconnectDelay = 500;
|
|
331
|
-
const maxReconnects = options.maxReconnects ?? 5;
|
|
332
|
-
while (true) {
|
|
333
|
-
const headers = new Headers({ accept: "text/event-stream" });
|
|
334
|
-
if (lastEventId) headers.set("last-event-id", lastEventId);
|
|
335
|
-
const response = await this.transport.response(
|
|
336
|
-
`/tasks/${encodeURIComponent(taskId)}/events`,
|
|
337
|
-
{ headers, signal: options.signal },
|
|
338
|
-
{ retryable: false }
|
|
339
|
-
);
|
|
340
|
-
let reachedTerminalState = false;
|
|
341
|
-
for await (const serverEvent of parseServerSentEvents(response)) {
|
|
342
|
-
if (serverEvent.id) lastEventId = serverEvent.id;
|
|
343
|
-
if (serverEvent.retry !== void 0) reconnectDelay = serverEvent.retry;
|
|
344
|
-
const event = JSON.parse(serverEvent.data);
|
|
345
|
-
yield event;
|
|
346
|
-
if (event.status && isTerminalTaskStatus(event.status)) {
|
|
347
|
-
const task = event.payload?.task;
|
|
348
|
-
const deliveryPreparing = task && typeof task === "object" && !Array.isArray(task) && task.deliveryStatus === "preparing";
|
|
349
|
-
if (!deliveryPreparing) reachedTerminalState = true;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
if (reachedTerminalState) return;
|
|
353
|
-
if (reconnects >= maxReconnects) return;
|
|
354
|
-
reconnects += 1;
|
|
355
|
-
await sleep(reconnectDelay, options.signal);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
async wait(taskId, options = {}) {
|
|
359
|
-
const timeoutController = new AbortController();
|
|
360
|
-
const timeoutMs = options.timeoutMs;
|
|
361
|
-
const timeout = timeoutMs ? setTimeout(() => timeoutController.abort("nexra_wait_timeout"), timeoutMs) : void 0;
|
|
362
|
-
const signal = combineSignals(options.signal, timeoutMs ? timeoutController.signal : void 0);
|
|
363
|
-
try {
|
|
364
|
-
const current = await this.get(taskId, signal);
|
|
365
|
-
if (isTerminalTaskStatus(current.status) && current.deliveryStatus !== "preparing") return current;
|
|
366
|
-
try {
|
|
367
|
-
for await (const event of this.watch(taskId, {
|
|
368
|
-
signal,
|
|
369
|
-
lastEventId: options.lastEventId,
|
|
370
|
-
maxReconnects: options.maxReconnects
|
|
371
|
-
})) {
|
|
372
|
-
await options.onEvent?.(event);
|
|
373
|
-
}
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (signal?.aborted) throw error;
|
|
376
|
-
if (error instanceof NexraApiError && ![405, 406, 501].includes(error.status)) {
|
|
377
|
-
throw error;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
while (true) {
|
|
381
|
-
const task = await this.get(taskId, signal);
|
|
382
|
-
if (isTerminalTaskStatus(task.status) && task.deliveryStatus !== "preparing") return task;
|
|
383
|
-
await sleep(options.pollIntervalMs ?? 1e3, signal);
|
|
384
|
-
}
|
|
385
|
-
} catch (error) {
|
|
386
|
-
if (timeoutController.signal.aborted && timeoutMs) {
|
|
387
|
-
throw new NexraWaitTimeoutError(taskId, timeoutMs);
|
|
388
|
-
}
|
|
389
|
-
throw error;
|
|
390
|
-
} finally {
|
|
391
|
-
if (timeout) clearTimeout(timeout);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
async run(model, input, options = {}) {
|
|
395
|
-
const task = await this.create(model, input, options);
|
|
396
|
-
let completed;
|
|
397
|
-
try {
|
|
398
|
-
completed = await this.wait(task.id, options);
|
|
399
|
-
} catch (error) {
|
|
400
|
-
if (options.cancelOnAbort && options.signal?.aborted) {
|
|
401
|
-
await this.cancel(task.id).catch(() => void 0);
|
|
402
|
-
}
|
|
403
|
-
throw error;
|
|
404
|
-
}
|
|
405
|
-
if (completed.status !== "succeeded") {
|
|
406
|
-
throw new NexraTaskError(completed);
|
|
407
|
-
}
|
|
408
|
-
return {
|
|
409
|
-
taskId: completed.id,
|
|
410
|
-
output: completed.output,
|
|
411
|
-
assets: completed.assets ?? [],
|
|
412
|
-
task: completed
|
|
413
|
-
};
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
function combineSignals(first, second) {
|
|
417
|
-
const signals = [first, second].filter((signal) => Boolean(signal));
|
|
418
|
-
if (signals.length === 0) return void 0;
|
|
419
|
-
if (signals.length === 1) return signals[0];
|
|
420
|
-
return AbortSignal.any(signals);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// src/client.ts
|
|
424
|
-
var NexraClient = class {
|
|
425
|
-
assets;
|
|
426
|
-
catalog;
|
|
427
|
-
models;
|
|
428
|
-
tasks;
|
|
429
|
-
voices;
|
|
430
|
-
constructor(options = {}) {
|
|
431
|
-
const transport = new HttpTransport(options);
|
|
432
|
-
this.assets = new AssetsClient(transport);
|
|
433
|
-
this.catalog = new CatalogClient(transport);
|
|
434
|
-
this.models = new ModelsClient(transport);
|
|
435
|
-
this.tasks = new TasksClient(transport, this.assets);
|
|
436
|
-
this.voices = new VoicesClient(transport);
|
|
437
|
-
}
|
|
438
|
-
run(model, input, options = {}) {
|
|
439
|
-
return this.tasks.run(model, input, options);
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
function createNexra(options = {}) {
|
|
443
|
-
return new NexraClient(options);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// src/webhooks.ts
|
|
447
|
-
async function verifyWebhook(request, secret, options = {}) {
|
|
448
|
-
const webhookId = request.headers.get("nexra-webhook-id");
|
|
449
|
-
const timestamp = request.headers.get("nexra-webhook-timestamp");
|
|
450
|
-
const signatureHeader = request.headers.get("nexra-webhook-signature");
|
|
451
|
-
if (!webhookId || !timestamp || !signatureHeader) return false;
|
|
452
|
-
const timestampSeconds = Number(timestamp);
|
|
453
|
-
if (!Number.isFinite(timestampSeconds)) return false;
|
|
454
|
-
const nowSeconds = Math.floor((options.now ?? /* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
455
|
-
if (Math.abs(nowSeconds - timestampSeconds) > (options.toleranceSeconds ?? 300)) {
|
|
456
|
-
return false;
|
|
457
|
-
}
|
|
458
|
-
const body = await request.clone().text();
|
|
459
|
-
const signedPayload = `${webhookId}.${timestamp}.${body}`;
|
|
460
|
-
const key = await crypto.subtle.importKey(
|
|
461
|
-
"raw",
|
|
462
|
-
new TextEncoder().encode(secret),
|
|
463
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
464
|
-
false,
|
|
465
|
-
["sign"]
|
|
466
|
-
);
|
|
467
|
-
const digest = new Uint8Array(
|
|
468
|
-
await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(signedPayload))
|
|
469
|
-
);
|
|
470
|
-
const expected = toBase64Url(digest);
|
|
471
|
-
const signatures = signatureHeader.split(" ").flatMap((part) => part.split(",")).map((part) => part.trim()).filter((part) => part.startsWith("v1=")).map((part) => part.slice(3));
|
|
472
|
-
return signatures.some((signature) => timingSafeEqual(signature, expected));
|
|
473
|
-
}
|
|
474
|
-
function toBase64Url(bytes) {
|
|
475
|
-
let binary = "";
|
|
476
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
477
|
-
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
478
|
-
}
|
|
479
|
-
function timingSafeEqual(left, right) {
|
|
480
|
-
if (left.length !== right.length) return false;
|
|
481
|
-
let difference = 0;
|
|
482
|
-
for (let index = 0; index < left.length; index += 1) {
|
|
483
|
-
difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
484
|
-
}
|
|
485
|
-
return difference === 0;
|
|
486
|
-
}
|
|
34
|
+
} from "./chunk-V3F6VPMP.js";
|
|
487
35
|
export {
|
|
488
36
|
AssetsClient,
|
|
489
37
|
CatalogClient,
|
|
@@ -492,9 +40,11 @@ export {
|
|
|
492
40
|
NexraApiError,
|
|
493
41
|
NexraClient,
|
|
494
42
|
NexraTaskError,
|
|
43
|
+
NexraTranscriptionError,
|
|
495
44
|
NexraWaitTimeoutError,
|
|
496
45
|
TASK_STATUSES,
|
|
497
46
|
TasksClient,
|
|
47
|
+
TranscriptionClient,
|
|
498
48
|
VoicesClient,
|
|
499
49
|
applyMediaGeometry,
|
|
500
50
|
ceilDecimal,
|
package/dist/language.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { APICallError, LanguageModelV4 } from '@ai-sdk/provider';
|
|
2
2
|
import { NexraLanguageProtocol } from './catalog.js';
|
|
3
3
|
export { NexraLanguageModelBinding } from './catalog.js';
|
|
4
|
-
import { F as FetchLike } from './media-geometry-
|
|
5
|
-
import { N as NexraError } from './errors-
|
|
6
|
-
import './json-
|
|
4
|
+
import { F as FetchLike } from './media-geometry-B92BvuQL.js';
|
|
5
|
+
import { N as NexraError } from './errors-BXPUVOh7.js';
|
|
6
|
+
import './json-dnsDzk-s.js';
|
|
7
7
|
|
|
8
8
|
type NativeErrorContext = {
|
|
9
9
|
url: string;
|