@mux/ai 0.44.0 → 0.46.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.
@@ -1,3 +1,3 @@
1
- export { D as DEFAULT_STORYBOARD_WIDTH, H as HeatmapOptions, a as HeatmapResponse, L as LOW_CONFIDENCE_THRESHOLD, M as MAX_CUE_TEXT_CHARS, T as ThumbnailOptions, b as TranscriptFetchOptions, c as TranscriptResult, V as VTTCue, d as VTTCueBudgetChunkingOptions, e as VTTDurationChunk, f as VTTDurationChunkingOptions, g as buildTranscriptUrl, h as buildVttFromCueBlocks, j as buildVttFromTranslatedCueBlocks, k as chunkByTokens, l as chunkText, m as chunkVTTCues, n as chunkVTTCuesByBudget, o as chunkVTTCuesByDuration, p as concatenateVttSegments, q as estimateTokenCount, r as extractTextFromVTT, s as extractTimestampedTranscript, t as fetchTranscriptForAsset, u as filterVttByScope, v as findCaptionTrack, w as getHeatmapForAsset, x as getHeatmapForPlaybackId, y as getHeatmapForVideo, z as getReadyTextTracks, A as getReliableLanguageCode, B as getStoryboardUrl, C as getThumbnailUrls, E as parseVTTCues, F as replaceCueText, G as sanitizeUntrustedText, I as secondsToTimestamp, J as splitVttPreambleAndCueBlocks, K as stripVttMetadataBlocks, N as vttTimestampToSeconds } from '../index-C2Pk7bbF.js';
2
- export { q as CompletedShotsResult, r as ErroredShotsResult, H as Hotspot, s as HotspotOptions, t as HotspotResponse, u as PendingShotsResult, v as Shot, w as ShotRequestOptions, x as ShotsResult, y as WaitForShotsOptions, z as getHotspotsForAsset, B as getHotspotsForPlaybackId, D as getHotspotsForVideo, F as getShotsForAsset, G as requestShotsForAsset, J as waitForShotsForAsset } from '../shots-CUI09Ohe.js';
3
- import '@mux/mux-node';
1
+ export { D as DEFAULT_STORYBOARD_WIDTH, H as HeatmapOptions, a as HeatmapResponse, L as LOW_CONFIDENCE_THRESHOLD, M as MAX_CUE_TEXT_CHARS, T as ThumbnailOptions, b as TranscriptFetchOptions, c as TranscriptResult, V as VTTCue, d as VTTCueBudgetChunkingOptions, e as VTTDurationChunk, f as VTTDurationChunkingOptions, g as buildTranscriptUrl, h as buildVttFromCueBlocks, j as buildVttFromTranslatedCueBlocks, k as chunkByTokens, l as chunkText, m as chunkVTTCues, n as chunkVTTCuesByBudget, o as chunkVTTCuesByDuration, p as concatenateVttSegments, q as estimateTokenCount, r as extractTextFromVTT, s as extractTimestampedTranscript, t as fetchTranscriptForAsset, u as filterVttByScope, v as findCaptionTrack, w as getHeatmapForAsset, x as getHeatmapForPlaybackId, y as getHeatmapForVideo, z as getReadyTextTracks, A as getReliableLanguageCode, B as getStoryboardUrl, C as getThumbnailUrls, E as parseVTTCues, F as replaceCueText, G as sanitizeUntrustedText, I as secondsToTimestamp, J as splitVttPreambleAndCueBlocks, K as stripVttMetadataBlocks, N as vttTimestampToSeconds } from '../index-DAuzEXly.js';
2
+ export { q as CompletedShotsResult, r as ErroredShotsResult, H as Hotspot, s as HotspotOptions, t as HotspotResponse, u as PendingShotsResult, v as Shot, w as ShotRequestOptions, x as ShotsResult, y as WaitForShotsOptions, z as getHotspotsForAsset, B as getHotspotsForPlaybackId, D as getHotspotsForVideo, F as getShotsForAsset, G as requestShotsForAsset, J as waitForShotsForAsset } from '../shots-BwpjZDpr.js';
3
+ import '@mux/ts';
@@ -27,12 +27,16 @@ var EnvSchema = z.object({
27
27
  ),
28
28
  MUX_SIGNING_KEY: optionalString("Mux signing key ID for signed playback URLs.", "Used to sign playback URLs"),
29
29
  MUX_PRIVATE_KEY: optionalString("Mux signing private key for signed playback URLs.", "Used to sign playback URLs"),
30
+ MUX_CUSTOM_DOMAIN: optionalString(
31
+ "Mux domain for image.* and stream.* playback URLs, e.g. staging.mux.com or a custom domain (defaults to mux.com).",
32
+ "Mux custom domain"
33
+ ),
30
34
  MUX_IMAGE_URL_OVERRIDE: optionalString(
31
- "Override for Mux image base URL (defaults to https://image.mux.com).",
35
+ "Deprecated: use MUX_CUSTOM_DOMAIN. Override for Mux image base URL (defaults to https://image.mux.com).",
32
36
  "Mux image URL override"
33
37
  ),
34
38
  MUX_STREAM_URL_OVERRIDE: optionalString(
35
- "Override for Mux stream base URL (defaults to https://stream.mux.com).",
39
+ "Deprecated: use MUX_CUSTOM_DOMAIN. Override for Mux stream base URL (defaults to https://stream.mux.com).",
36
40
  "Mux stream URL override"
37
41
  ),
38
42
  MUX_BASE_URL: optionalString(
@@ -151,7 +155,18 @@ function parseEnv() {
151
155
  }
152
156
  return parsedEnv.data;
153
157
  }
158
+ var hasWarnedAboutDeprecatedUrlOverrides = false;
159
+ function warnOnDeprecatedUrlOverrides(parsed) {
160
+ if (hasWarnedAboutDeprecatedUrlOverrides || !parsed.MUX_IMAGE_URL_OVERRIDE && !parsed.MUX_STREAM_URL_OVERRIDE) {
161
+ return;
162
+ }
163
+ hasWarnedAboutDeprecatedUrlOverrides = true;
164
+ console.warn(
165
+ "MUX_IMAGE_URL_OVERRIDE and MUX_STREAM_URL_OVERRIDE are deprecated and will be removed in a future release. Set MUX_CUSTOM_DOMAIN instead (e.g. MUX_CUSTOM_DOMAIN=staging.mux.com for image.staging.mux.com and stream.staging.mux.com)."
166
+ );
167
+ }
154
168
  var env = parseEnv();
169
+ warnOnDeprecatedUrlOverrides(env);
155
170
  var env_default = env;
156
171
 
157
172
  // src/lib/workflow-crypto.ts
@@ -400,7 +415,7 @@ function resolveDirectMuxCredentials(record) {
400
415
  function createWorkflowMuxClient(options) {
401
416
  return {
402
417
  async createClient() {
403
- const { default: MuxClient } = await import("@mux/mux-node");
418
+ const { default: MuxClient } = await import("@mux/ts");
404
419
  return new MuxClient({
405
420
  tokenId: options.tokenId,
406
421
  tokenSecret: options.tokenSecret,
@@ -606,25 +621,22 @@ async function getHeatmapForPlaybackId(playbackId, options = {}) {
606
621
  "use step";
607
622
  return fetchHeatmap("playback-ids", playbackId, options);
608
623
  }
609
- function transformHeatmapResponse(response) {
610
- return {
611
- assetId: response.data.asset_id,
612
- videoId: response.data.video_id,
613
- playbackId: response.data.playback_id,
614
- heatmap: response.data.heatmap,
615
- timeframe: response.timeframe
616
- };
617
- }
618
624
  async function fetchHeatmap(identifierType, id, options) {
619
625
  "use step";
620
626
  const { timeframe = "7:days", credentials } = options;
621
627
  const muxClient = await getMuxClientFromEnv(credentials);
622
628
  const mux = await muxClient.createClient();
623
- const queryParams = new URLSearchParams();
624
- queryParams.append("timeframe[]", timeframe);
625
- const path = `/data/v1/engagement/${identifierType}/${id}/heatmap?${queryParams.toString()}`;
626
- const response = await mux.get(path);
627
- return transformHeatmapResponse(response);
629
+ const query = { timeframe: [timeframe] };
630
+ const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
631
+ const response = await resource.heatmap(id, query);
632
+ const { data } = response;
633
+ return {
634
+ assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
635
+ videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
636
+ playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
637
+ heatmap: data.heatmap,
638
+ timeframe: response.timeframe
639
+ };
628
640
  }
629
641
 
630
642
  // src/primitives/hotspots.ts
@@ -643,37 +655,34 @@ async function getHotspotsForPlaybackId(playbackId, options = {}) {
643
655
  const response = await fetchHotspots("playback-ids", playbackId, options);
644
656
  return response.hotspots;
645
657
  }
646
- function transformHotspotResponse(response) {
647
- return {
648
- assetId: response.data.asset_id,
649
- videoId: response.data.video_id,
650
- playbackId: response.data.playback_id,
651
- hotspots: response.data.hotspots.map((h) => ({
652
- startMs: h.start_ms,
653
- endMs: h.end_ms,
654
- score: h.score
655
- }))
656
- };
657
- }
658
658
  async function fetchHotspots(identifierType, id, options) {
659
659
  "use step";
660
660
  const {
661
661
  limit = 5,
662
662
  orderDirection = "desc",
663
- orderBy = "score",
664
663
  timeframe = "7:days",
665
664
  credentials
666
665
  } = options;
667
666
  const muxClient = await getMuxClientFromEnv(credentials);
668
667
  const mux = await muxClient.createClient();
669
- const queryParams = new URLSearchParams();
670
- queryParams.append("limit", String(limit));
671
- queryParams.append("order_direction", orderDirection);
672
- queryParams.append("order_by", orderBy);
673
- queryParams.append("timeframe[]", timeframe);
674
- const path = `/data/v1/engagement/${identifierType}/${id}/hotspots?${queryParams.toString()}`;
675
- const response = await mux.get(path);
676
- return transformHotspotResponse(response);
668
+ const query = {
669
+ limit,
670
+ order_direction: orderDirection,
671
+ timeframe: [timeframe]
672
+ };
673
+ const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
674
+ const response = await resource.hotspots(id, query);
675
+ const { data } = response;
676
+ return {
677
+ assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
678
+ videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
679
+ playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
680
+ hotspots: data.hotspots.map((h) => ({
681
+ startMs: h.start_ms,
682
+ endMs: h.end_ms,
683
+ score: h.score
684
+ }))
685
+ };
677
686
  }
678
687
 
679
688
  // src/lib/prompt-fragments.ts
@@ -960,9 +969,6 @@ var DEFAULT_POLL_INTERVAL_MS = 2e3;
960
969
  var MIN_POLL_INTERVAL_MS = 1e3;
961
970
  var DEFAULT_MAX_ATTEMPTS = 60;
962
971
  var SHOTS_ALREADY_REQUESTED_MESSAGE = "shots generation has already been requested";
963
- function getShotsPath(assetId) {
964
- return `/video/v1/assets/${assetId}/shots`;
965
- }
966
972
  function mapManifestShots(shots) {
967
973
  let usedDeprecatedField = false;
968
974
  const mapped = shots.map((shot, index) => {
@@ -1002,29 +1008,35 @@ async function fetchShotsFromManifest(shotsManifestUrl) {
1002
1008
  }
1003
1009
  return mapManifestShots(manifest.shots);
1004
1010
  }
1005
- async function transformShotsResponse(response) {
1006
- switch (response.data.status) {
1011
+ async function transformShotsResponse(data) {
1012
+ switch (data.status) {
1007
1013
  case "pending":
1008
1014
  return {
1009
1015
  status: "pending",
1010
- createdAt: response.data.created_at
1016
+ createdAt: data.created_at
1011
1017
  };
1012
- case "errored":
1018
+ case "errored": {
1019
+ const details = data.errors ?? data.error;
1013
1020
  return {
1014
1021
  status: "errored",
1015
- createdAt: response.data.created_at,
1016
- error: response.data.error
1022
+ createdAt: data.created_at,
1023
+ error: {
1024
+ type: details?.type ?? "unknown",
1025
+ messages: details?.messages ?? []
1026
+ }
1017
1027
  };
1028
+ }
1018
1029
  case "completed":
1030
+ if (!data.shots_manifest_url) {
1031
+ throw new Error("Completed shots response is missing shots_manifest_url");
1032
+ }
1019
1033
  return {
1020
1034
  status: "completed",
1021
- createdAt: response.data.created_at,
1022
- shots: await fetchShotsFromManifest(response.data.shots_manifest_url)
1035
+ createdAt: data.created_at,
1036
+ shots: await fetchShotsFromManifest(data.shots_manifest_url)
1023
1037
  };
1024
- default: {
1025
- const exhaustiveCheck = response.data;
1026
- throw new Error(`Unsupported shots response: ${JSON.stringify(exhaustiveCheck)}`);
1027
- }
1038
+ default:
1039
+ throw new Error(`Unsupported shots status '${data.status}'`);
1028
1040
  }
1029
1041
  }
1030
1042
  function sleep(ms) {
@@ -1032,7 +1044,8 @@ function sleep(ms) {
1032
1044
  }
1033
1045
  function isShotsAlreadyRequestedError(error) {
1034
1046
  const statusCode = error?.status ?? error?.statusCode;
1035
- const messages = error?.error?.messages;
1047
+ const body = error?.error;
1048
+ const messages = body?.error?.messages ?? body?.messages;
1036
1049
  const lowerCaseMessages = messages?.map((message) => message.toLowerCase()) ?? [];
1037
1050
  const errorMessage = error instanceof Error ? error.message.toLowerCase() : "";
1038
1051
  return statusCode === 400 && (lowerCaseMessages.some((message) => message.includes(SHOTS_ALREADY_REQUESTED_MESSAGE)) || errorMessage.includes(SHOTS_ALREADY_REQUESTED_MESSAGE));
@@ -1042,11 +1055,8 @@ async function requestShotsForAsset(assetId, options = {}) {
1042
1055
  const { credentials } = options;
1043
1056
  const muxClient = await getMuxClientFromEnv(credentials);
1044
1057
  const mux = await muxClient.createClient();
1045
- const response = await mux.post(
1046
- getShotsPath(assetId),
1047
- { body: {} }
1048
- );
1049
- const result = await transformShotsResponse(response);
1058
+ const data = await mux.video.assets.generateShots(assetId, {});
1059
+ const result = await transformShotsResponse(data);
1050
1060
  if (result.status !== "pending") {
1051
1061
  throw new Error(
1052
1062
  `Expected pending status after requesting shots for asset '${assetId}', received '${result.status}'`
@@ -1059,10 +1069,8 @@ async function getShotsForAsset(assetId, options = {}) {
1059
1069
  const { credentials } = options;
1060
1070
  const muxClient = await getMuxClientFromEnv(credentials);
1061
1071
  const mux = await muxClient.createClient();
1062
- const response = await mux.get(
1063
- getShotsPath(assetId)
1064
- );
1065
- return await transformShotsResponse(response);
1072
+ const data = await mux.video.assets.retrieveShots(assetId);
1073
+ return await transformShotsResponse(data);
1066
1074
  }
1067
1075
  async function waitForShotsForAsset(assetId, options = {}) {
1068
1076
  "use step";
@@ -1104,8 +1112,7 @@ async function waitForShotsForAsset(assetId, options = {}) {
1104
1112
  }
1105
1113
 
1106
1114
  // src/lib/mux-url.ts
1107
- var DEFAULT_MUX_IMAGE_ORIGIN = "https://image.mux.com";
1108
- var DEFAULT_MUX_STREAM_ORIGIN = "https://stream.mux.com";
1115
+ var DEFAULT_MUX_DOMAIN = "mux.com";
1109
1116
  function normalizeOrigin(value, envVarName) {
1110
1117
  const trimmed = value.trim();
1111
1118
  const candidate = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
@@ -1125,39 +1132,62 @@ function normalizeOrigin(value, envVarName) {
1125
1132
  }
1126
1133
  return parsed.origin;
1127
1134
  }
1128
- function getMuxImageOrigin() {
1129
- const override = env_default.MUX_IMAGE_URL_OVERRIDE;
1130
- if (!override) {
1131
- return DEFAULT_MUX_IMAGE_ORIGIN;
1135
+ function buildPlaybackOrigin(service, customDomain, source) {
1136
+ const invalidDomainError = new Error(
1137
+ `Invalid ${source}. Provide a bare hostname (e.g. "media.example.com") with no scheme, port, credentials, query params, hash fragments, or path.`
1138
+ );
1139
+ const trimmed = customDomain.trim();
1140
+ if (!trimmed) {
1141
+ throw invalidDomainError;
1132
1142
  }
1133
- return normalizeOrigin(override, "MUX_IMAGE_URL_OVERRIDE");
1143
+ let parsed;
1144
+ try {
1145
+ parsed = new URL(`https://${service}.${trimmed}`);
1146
+ } catch {
1147
+ throw invalidDomainError;
1148
+ }
1149
+ if (parsed.port || parsed.username || parsed.password || parsed.search || parsed.hash || parsed.pathname !== "/") {
1150
+ throw invalidDomainError;
1151
+ }
1152
+ return parsed.origin;
1134
1153
  }
1135
- function getMuxStreamOrigin() {
1136
- const override = env_default.MUX_STREAM_URL_OVERRIDE;
1137
- if (!override) {
1138
- return DEFAULT_MUX_STREAM_ORIGIN;
1154
+ async function resolveMuxPlaybackOrigin(service, credentials) {
1155
+ "use step";
1156
+ const { muxCustomDomain } = await resolveWorkflowCredentials(credentials);
1157
+ if (muxCustomDomain) {
1158
+ return buildPlaybackOrigin(service, muxCustomDomain, "muxCustomDomain");
1159
+ }
1160
+ const legacyOverrideEnvVarName = service === "image" ? "MUX_IMAGE_URL_OVERRIDE" : "MUX_STREAM_URL_OVERRIDE";
1161
+ const legacyOverride = env_default[legacyOverrideEnvVarName];
1162
+ if (legacyOverride) {
1163
+ return normalizeOrigin(legacyOverride, legacyOverrideEnvVarName);
1164
+ }
1165
+ if (env_default.MUX_CUSTOM_DOMAIN) {
1166
+ return buildPlaybackOrigin(service, env_default.MUX_CUSTOM_DOMAIN, "MUX_CUSTOM_DOMAIN");
1139
1167
  }
1140
- return normalizeOrigin(override, "MUX_STREAM_URL_OVERRIDE");
1168
+ return buildPlaybackOrigin(service, DEFAULT_MUX_DOMAIN, "custom domain");
1169
+ }
1170
+ async function getMuxImageOrigin(credentials) {
1171
+ return resolveMuxPlaybackOrigin("image", credentials);
1172
+ }
1173
+ async function getMuxStreamOrigin(credentials) {
1174
+ return resolveMuxPlaybackOrigin("stream", credentials);
1141
1175
  }
1142
- function getMuxImageBaseUrl(playbackId, assetType) {
1143
- const origin = getMuxImageOrigin();
1176
+ async function getMuxImageBaseUrl(playbackId, assetType, credentials) {
1177
+ const origin = await getMuxImageOrigin(credentials);
1144
1178
  return `${origin}/${playbackId}/${assetType}.png`;
1145
1179
  }
1146
- function getMuxStoryboardBaseUrl(playbackId) {
1147
- return getMuxImageBaseUrl(playbackId, "storyboard");
1180
+ async function getMuxStoryboardBaseUrl(playbackId, credentials) {
1181
+ return getMuxImageBaseUrl(playbackId, "storyboard", credentials);
1148
1182
  }
1149
- function getMuxThumbnailBaseUrl(playbackId) {
1150
- return getMuxImageBaseUrl(playbackId, "thumbnail");
1183
+ async function getMuxThumbnailBaseUrl(playbackId, credentials) {
1184
+ return getMuxImageBaseUrl(playbackId, "thumbnail", credentials);
1151
1185
  }
1152
1186
 
1153
1187
  // src/lib/url-signing.ts
1154
1188
  async function createSigningClient(context) {
1155
- const { default: MuxClient } = await import("@mux/mux-node");
1189
+ const { default: MuxClient } = await import("@mux/ts");
1156
1190
  return new MuxClient({
1157
- // These are not needed for signing, but the SDK requires them
1158
- // Using empty strings as we only need the jwt functionality
1159
- tokenId: env_default.MUX_TOKEN_ID || "",
1160
- tokenSecret: env_default.MUX_TOKEN_SECRET || "",
1161
1191
  jwtSigningKey: context.keyId,
1162
1192
  jwtPrivateKey: context.keySecret
1163
1193
  });
@@ -1191,7 +1221,7 @@ async function signUrl(url, playbackId, type = "video", params, credentials) {
1191
1221
  var DEFAULT_STORYBOARD_WIDTH = 640;
1192
1222
  async function getStoryboardUrl(playbackId, width = DEFAULT_STORYBOARD_WIDTH, shouldSign = false, credentials, scope) {
1193
1223
  "use step";
1194
- const baseUrl = getMuxStoryboardBaseUrl(playbackId);
1224
+ const baseUrl = await getMuxStoryboardBaseUrl(playbackId, credentials);
1195
1225
  const params = { width };
1196
1226
  if (scope?.startTime !== void 0) {
1197
1227
  params.asset_start_time = scope.startTime;
@@ -1520,7 +1550,7 @@ async function getThumbnailUrls(playbackId, duration, options = {}) {
1520
1550
  }
1521
1551
  timestamps = newTimestamps;
1522
1552
  }
1523
- const baseUrl = getMuxThumbnailBaseUrl(playbackId);
1553
+ const baseUrl = await getMuxThumbnailBaseUrl(playbackId, credentials);
1524
1554
  const urlPromises = timestamps.map(async (time) => {
1525
1555
  const url = shouldSign ? await signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials) : `${baseUrl}?time=${time}&width=${width}`;
1526
1556
  return { url, time };
@@ -2037,7 +2067,7 @@ function concatenateVttSegments(segments, preamble = "WEBVTT") {
2037
2067
  }
2038
2068
  async function buildTranscriptUrl(playbackId, trackId, shouldSign = false, credentials) {
2039
2069
  "use step";
2040
- const baseUrl = `${getMuxStreamOrigin()}/${playbackId}/text/${trackId}.vtt`;
2070
+ const baseUrl = `${await getMuxStreamOrigin(credentials)}/${playbackId}/text/${trackId}.vtt`;
2041
2071
  if (shouldSign) {
2042
2072
  return signUrl(baseUrl, playbackId, "video", void 0, credentials);
2043
2073
  }