@mux/ai 0.6.0 → 0.7.2
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 +27 -23
- package/dist/{index-B6ro59tn.d.ts → index-BMqnP1RV.d.ts} +7 -4
- package/dist/{index-DAlX4SNJ.d.ts → index-DZlygsvb.d.ts} +113 -3
- package/dist/index.d.ts +30 -6
- package/dist/index.js +858 -282
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.d.ts +2 -2
- package/dist/primitives/index.js +189 -21
- package/dist/primitives/index.js.map +1 -1
- package/dist/{types-CqjLMB84.d.ts → types-BQVi_wnh.d.ts} +49 -18
- package/dist/workflows/index.d.ts +2 -2
- package/dist/workflows/index.js +617 -214
- package/dist/workflows/index.js.map +1 -1
- package/package.json +3 -5
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { D as DEFAULT_STORYBOARD_WIDTH, T as ThumbnailOptions,
|
|
2
|
-
import '../types-
|
|
1
|
+
export { D as DEFAULT_STORYBOARD_WIDTH, H as HeatmapOptions, a as HeatmapResponse, b as Hotspot, c as HotspotOptions, d as HotspotResponse, T as ThumbnailOptions, e as TranscriptFetchOptions, f as TranscriptResult, V as VTTCue, g as buildTranscriptUrl, h as chunkByTokens, j as chunkText, k as chunkVTTCues, l as estimateTokenCount, m as extractTextFromVTT, n as extractTimestampedTranscript, o as fetchTranscriptForAsset, p as findCaptionTrack, q as getHeatmapForAsset, r as getHeatmapForPlaybackId, s as getHeatmapForVideo, t as getHotspotsForAsset, u as getHotspotsForPlaybackId, v as getHotspotsForVideo, w as getReadyTextTracks, x as getStoryboardUrl, y as getThumbnailUrls, z as parseVTTCues, A as secondsToTimestamp, B as vttTimestampToSeconds } from '../index-DZlygsvb.js';
|
|
2
|
+
import '../types-BQVi_wnh.js';
|
|
3
3
|
import '@mux/mux-node';
|
package/dist/primitives/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
// src/lib/
|
|
2
|
-
import
|
|
1
|
+
// src/lib/providers.ts
|
|
2
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
3
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
4
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
3
5
|
|
|
4
6
|
// src/env.ts
|
|
5
7
|
import { z } from "zod";
|
|
@@ -54,6 +56,9 @@ var EnvSchema = z.object({
|
|
|
54
56
|
S3_BUCKET: optionalString("Bucket used for caption and audio uploads.", "S3 bucket"),
|
|
55
57
|
S3_ACCESS_KEY_ID: optionalString("Access key ID for S3-compatible uploads.", "S3 access key id"),
|
|
56
58
|
S3_SECRET_ACCESS_KEY: optionalString("Secret access key for S3-compatible uploads.", "S3 secret access key"),
|
|
59
|
+
S3_ALLOWED_ENDPOINT_HOSTS: optionalString(
|
|
60
|
+
"Comma-separated S3 endpoint allowlist (supports exact hosts and *.suffix patterns)."
|
|
61
|
+
),
|
|
57
62
|
EVALITE_RESULTS_ENDPOINT: optionalString(
|
|
58
63
|
"Full URL for posting Evalite results (e.g., https://example.com/api/evalite-results).",
|
|
59
64
|
"Evalite results endpoint"
|
|
@@ -95,11 +100,15 @@ var WORKFLOW_ENCRYPTION_VERSION = 1;
|
|
|
95
100
|
var WORKFLOW_ENCRYPTION_ALGORITHM = "aes-256-gcm";
|
|
96
101
|
var IV_LENGTH_BYTES = 12;
|
|
97
102
|
var AUTH_TAG_LENGTH_BYTES = 16;
|
|
103
|
+
function normalizeBase64Input(value) {
|
|
104
|
+
const cleaned = value.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
|
|
105
|
+
return cleaned?.length % 4 === 0 ? cleaned : cleaned + "=".repeat(4 - cleaned.length % 4);
|
|
106
|
+
}
|
|
98
107
|
function base64ToBytes(value, label) {
|
|
99
108
|
if (!value) {
|
|
100
109
|
throw new Error(`${label} is missing`);
|
|
101
110
|
}
|
|
102
|
-
const normalized =
|
|
111
|
+
const normalized = normalizeBase64Input(value);
|
|
103
112
|
const atobImpl = typeof globalThis.atob === "function" ? globalThis.atob.bind(globalThis) : void 0;
|
|
104
113
|
if (atobImpl) {
|
|
105
114
|
let binary;
|
|
@@ -117,19 +126,18 @@ function base64ToBytes(value, label) {
|
|
|
117
126
|
}
|
|
118
127
|
return bytes2;
|
|
119
128
|
}
|
|
120
|
-
|
|
121
|
-
if (cleaned.length % 4 !== 0) {
|
|
129
|
+
if (normalized.length % 4 !== 0) {
|
|
122
130
|
throw new Error(`${label} is not valid base64`);
|
|
123
131
|
}
|
|
124
|
-
const padding =
|
|
125
|
-
const outputLength =
|
|
132
|
+
const padding = normalized.endsWith("==") ? 2 : normalized.endsWith("=") ? 1 : 0;
|
|
133
|
+
const outputLength = normalized.length / 4 * 3 - padding;
|
|
126
134
|
const bytes = new Uint8Array(outputLength);
|
|
127
135
|
let offset = 0;
|
|
128
|
-
for (let i = 0; i <
|
|
129
|
-
const c0 =
|
|
130
|
-
const c1 =
|
|
131
|
-
const c2 =
|
|
132
|
-
const c3 =
|
|
136
|
+
for (let i = 0; i < normalized.length; i += 4) {
|
|
137
|
+
const c0 = normalized.charCodeAt(i);
|
|
138
|
+
const c1 = normalized.charCodeAt(i + 1);
|
|
139
|
+
const c2 = normalized.charCodeAt(i + 2);
|
|
140
|
+
const c3 = normalized.charCodeAt(i + 3);
|
|
133
141
|
if (c0 === 61 || c1 === 61) {
|
|
134
142
|
throw new Error(`${label} is not valid base64`);
|
|
135
143
|
}
|
|
@@ -250,7 +258,9 @@ async function shouldEnforceEncryptedCredentials() {
|
|
|
250
258
|
function getWorkflowSecretKeyFromEnv() {
|
|
251
259
|
const key = env_default.MUX_AI_WORKFLOW_SECRET_KEY;
|
|
252
260
|
if (!key) {
|
|
253
|
-
throw new Error(
|
|
261
|
+
throw new Error(
|
|
262
|
+
"Workflow secret key is required. Set MUX_AI_WORKFLOW_SECRET_KEY environment variable."
|
|
263
|
+
);
|
|
254
264
|
}
|
|
255
265
|
return key;
|
|
256
266
|
}
|
|
@@ -281,30 +291,182 @@ async function resolveWorkflowCredentials(credentials) {
|
|
|
281
291
|
);
|
|
282
292
|
return { ...resolved, ...decrypted };
|
|
283
293
|
} catch (error) {
|
|
284
|
-
const detail = error instanceof Error ? error.message :
|
|
294
|
+
const detail = error instanceof Error ? error.message : "Unknown error.";
|
|
285
295
|
throw new Error(`Failed to decrypt workflow credentials. ${detail}`);
|
|
286
296
|
}
|
|
287
297
|
}
|
|
288
298
|
if (await shouldEnforceEncryptedCredentials()) {
|
|
289
299
|
throw new Error(
|
|
290
|
-
"Plaintext workflow credentials are not allowed when using Workflow Dev Kit.Pass encrypted credentials (encryptForWorkflow) or resolve secrets via environment variables."
|
|
300
|
+
"Plaintext workflow credentials are not allowed when using Workflow Dev Kit. Pass encrypted credentials (encryptForWorkflow) or resolve secrets via environment variables."
|
|
291
301
|
);
|
|
292
302
|
}
|
|
293
303
|
return { ...resolved, ...credentials };
|
|
294
304
|
}
|
|
305
|
+
function readString(record, key) {
|
|
306
|
+
const value = record?.[key];
|
|
307
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
308
|
+
}
|
|
309
|
+
function resolveDirectMuxCredentials(record) {
|
|
310
|
+
const tokenId = readString(record, "muxTokenId");
|
|
311
|
+
const tokenSecret = readString(record, "muxTokenSecret");
|
|
312
|
+
const signingKey = readString(record, "muxSigningKey");
|
|
313
|
+
const privateKey = readString(record, "muxPrivateKey");
|
|
314
|
+
if (!tokenId && !tokenSecret && !signingKey && !privateKey) {
|
|
315
|
+
return void 0;
|
|
316
|
+
}
|
|
317
|
+
if (!tokenId || !tokenSecret) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"Both muxTokenId and muxTokenSecret are required when passing direct Mux workflow credentials."
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
tokenId,
|
|
324
|
+
tokenSecret,
|
|
325
|
+
signingKey,
|
|
326
|
+
privateKey
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function createWorkflowMuxClient(options) {
|
|
330
|
+
return {
|
|
331
|
+
async createClient() {
|
|
332
|
+
const { default: MuxClient } = await import("@mux/mux-node");
|
|
333
|
+
return new MuxClient({
|
|
334
|
+
tokenId: options.tokenId,
|
|
335
|
+
tokenSecret: options.tokenSecret
|
|
336
|
+
});
|
|
337
|
+
},
|
|
338
|
+
getSigningKey() {
|
|
339
|
+
return options.signingKey;
|
|
340
|
+
},
|
|
341
|
+
getPrivateKey() {
|
|
342
|
+
return options.privateKey;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async function resolveMuxClient(credentials) {
|
|
347
|
+
const resolved = await resolveWorkflowCredentials(credentials);
|
|
348
|
+
const resolvedRecord = resolved;
|
|
349
|
+
const resolvedMuxCredentials = resolveDirectMuxCredentials(resolvedRecord);
|
|
350
|
+
if (resolvedMuxCredentials) {
|
|
351
|
+
return createWorkflowMuxClient(resolvedMuxCredentials);
|
|
352
|
+
}
|
|
353
|
+
const muxTokenId = env_default.MUX_TOKEN_ID;
|
|
354
|
+
const muxTokenSecret = env_default.MUX_TOKEN_SECRET;
|
|
355
|
+
if (!muxTokenId || !muxTokenSecret) {
|
|
356
|
+
throw new Error(
|
|
357
|
+
"Mux credentials are required. Provide muxTokenId/muxTokenSecret via workflow credentials, or set MUX_TOKEN_ID and MUX_TOKEN_SECRET environment variables."
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
return createWorkflowMuxClient({
|
|
361
|
+
tokenId: muxTokenId,
|
|
362
|
+
tokenSecret: muxTokenSecret,
|
|
363
|
+
signingKey: env_default.MUX_SIGNING_KEY,
|
|
364
|
+
privateKey: env_default.MUX_PRIVATE_KEY
|
|
365
|
+
});
|
|
366
|
+
}
|
|
295
367
|
async function resolveMuxSigningContext(credentials) {
|
|
296
368
|
const resolved = await resolveWorkflowCredentials(credentials);
|
|
297
|
-
const
|
|
298
|
-
const
|
|
369
|
+
const resolvedRecord = resolved;
|
|
370
|
+
const keyId = readString(resolvedRecord, "muxSigningKey") ?? env_default.MUX_SIGNING_KEY;
|
|
371
|
+
const keySecret = readString(resolvedRecord, "muxPrivateKey") ?? env_default.MUX_PRIVATE_KEY;
|
|
299
372
|
if (!keyId || !keySecret) {
|
|
300
373
|
return void 0;
|
|
301
374
|
}
|
|
302
375
|
return { keyId, keySecret };
|
|
303
376
|
}
|
|
304
377
|
|
|
378
|
+
// src/lib/client-factory.ts
|
|
379
|
+
async function getMuxClientFromEnv(credentials) {
|
|
380
|
+
return resolveMuxClient(credentials);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// src/primitives/heatmap.ts
|
|
384
|
+
async function getHeatmapForAsset(assetId, options = {}) {
|
|
385
|
+
"use step";
|
|
386
|
+
return fetchHeatmap("assets", assetId, options);
|
|
387
|
+
}
|
|
388
|
+
async function getHeatmapForVideo(videoId, options = {}) {
|
|
389
|
+
"use step";
|
|
390
|
+
return fetchHeatmap("videos", videoId, options);
|
|
391
|
+
}
|
|
392
|
+
async function getHeatmapForPlaybackId(playbackId, options = {}) {
|
|
393
|
+
"use step";
|
|
394
|
+
return fetchHeatmap("playback-ids", playbackId, options);
|
|
395
|
+
}
|
|
396
|
+
function transformHeatmapResponse(response) {
|
|
397
|
+
return {
|
|
398
|
+
assetId: response.asset_id,
|
|
399
|
+
videoId: response.video_id,
|
|
400
|
+
playbackId: response.playback_id,
|
|
401
|
+
heatmap: response.heatmap,
|
|
402
|
+
timeframe: response.timeframe
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
async function fetchHeatmap(identifierType, id, options) {
|
|
406
|
+
"use step";
|
|
407
|
+
const { timeframe = "[24:hours]", credentials } = options;
|
|
408
|
+
const muxClient = await getMuxClientFromEnv(credentials);
|
|
409
|
+
const mux = await muxClient.createClient();
|
|
410
|
+
const queryParams = new URLSearchParams();
|
|
411
|
+
queryParams.append("timeframe[]", timeframe);
|
|
412
|
+
const path = `/data/v1/engagement/${identifierType}/${id}/heatmap?${queryParams.toString()}`;
|
|
413
|
+
const response = await mux.get(path);
|
|
414
|
+
return transformHeatmapResponse(response);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/primitives/hotspots.ts
|
|
418
|
+
async function getHotspotsForAsset(assetId, options = {}) {
|
|
419
|
+
"use step";
|
|
420
|
+
const response = await fetchHotspots("assets", assetId, options);
|
|
421
|
+
return response.hotspots;
|
|
422
|
+
}
|
|
423
|
+
async function getHotspotsForVideo(videoId, options = {}) {
|
|
424
|
+
"use step";
|
|
425
|
+
const response = await fetchHotspots("videos", videoId, options);
|
|
426
|
+
return response.hotspots;
|
|
427
|
+
}
|
|
428
|
+
async function getHotspotsForPlaybackId(playbackId, options = {}) {
|
|
429
|
+
"use step";
|
|
430
|
+
const response = await fetchHotspots("playback-ids", playbackId, options);
|
|
431
|
+
return response.hotspots;
|
|
432
|
+
}
|
|
433
|
+
function transformHotspotResponse(response) {
|
|
434
|
+
return {
|
|
435
|
+
assetId: response.data.asset_id,
|
|
436
|
+
videoId: response.data.video_id,
|
|
437
|
+
playbackId: response.data.playback_id,
|
|
438
|
+
hotspots: response.data.hotspots.map((h) => ({
|
|
439
|
+
startMs: h.start_ms,
|
|
440
|
+
endMs: h.end_ms,
|
|
441
|
+
score: h.score
|
|
442
|
+
}))
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
async function fetchHotspots(identifierType, id, options) {
|
|
446
|
+
"use step";
|
|
447
|
+
const {
|
|
448
|
+
limit = 5,
|
|
449
|
+
orderDirection = "desc",
|
|
450
|
+
orderBy = "score",
|
|
451
|
+
timeframe = "[24:hours]",
|
|
452
|
+
credentials
|
|
453
|
+
} = options;
|
|
454
|
+
const muxClient = await getMuxClientFromEnv(credentials);
|
|
455
|
+
const mux = await muxClient.createClient();
|
|
456
|
+
const queryParams = new URLSearchParams();
|
|
457
|
+
queryParams.append("limit", String(limit));
|
|
458
|
+
queryParams.append("order_direction", orderDirection);
|
|
459
|
+
queryParams.append("order_by", orderBy);
|
|
460
|
+
queryParams.append("timeframe[]", timeframe);
|
|
461
|
+
const path = `/data/v1/engagement/${identifierType}/${id}/hotspots?${queryParams.toString()}`;
|
|
462
|
+
const response = await mux.get(path);
|
|
463
|
+
return transformHotspotResponse(response);
|
|
464
|
+
}
|
|
465
|
+
|
|
305
466
|
// src/lib/url-signing.ts
|
|
306
|
-
function createSigningClient(context) {
|
|
307
|
-
|
|
467
|
+
async function createSigningClient(context) {
|
|
468
|
+
const { default: MuxClient } = await import("@mux/mux-node");
|
|
469
|
+
return new MuxClient({
|
|
308
470
|
// These are not needed for signing, but the SDK requires them
|
|
309
471
|
// Using empty strings as we only need the jwt functionality
|
|
310
472
|
tokenId: env_default.MUX_TOKEN_ID || "",
|
|
@@ -315,7 +477,7 @@ function createSigningClient(context) {
|
|
|
315
477
|
}
|
|
316
478
|
async function signPlaybackId(playbackId, context, type = "video", params) {
|
|
317
479
|
"use step";
|
|
318
|
-
const client = createSigningClient(context);
|
|
480
|
+
const client = await createSigningClient(context);
|
|
319
481
|
const stringParams = params ? Object.fromEntries(
|
|
320
482
|
Object.entries(params).map(([key, value]) => [key, String(value)])
|
|
321
483
|
) : void 0;
|
|
@@ -330,7 +492,7 @@ async function signUrl(url, playbackId, context, type = "video", params, credent
|
|
|
330
492
|
const resolvedContext = context ?? await resolveMuxSigningContext(credentials);
|
|
331
493
|
if (!resolvedContext) {
|
|
332
494
|
throw new Error(
|
|
333
|
-
"Signed playback ID requires signing credentials. Provide muxSigningKey and muxPrivateKey
|
|
495
|
+
"Signed playback ID requires signing credentials. Provide muxSigningKey and muxPrivateKey via workflow credentials or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables."
|
|
334
496
|
);
|
|
335
497
|
}
|
|
336
498
|
const token = await signPlaybackId(playbackId, resolvedContext, type, params);
|
|
@@ -658,6 +820,12 @@ export {
|
|
|
658
820
|
extractTimestampedTranscript,
|
|
659
821
|
fetchTranscriptForAsset,
|
|
660
822
|
findCaptionTrack,
|
|
823
|
+
getHeatmapForAsset,
|
|
824
|
+
getHeatmapForPlaybackId,
|
|
825
|
+
getHeatmapForVideo,
|
|
826
|
+
getHotspotsForAsset,
|
|
827
|
+
getHotspotsForPlaybackId,
|
|
828
|
+
getHotspotsForVideo,
|
|
661
829
|
getReadyTextTracks,
|
|
662
830
|
getStoryboardUrl,
|
|
663
831
|
getThumbnailUrls,
|