@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.
@@ -33,12 +33,16 @@ var EnvSchema = z.object({
33
33
  ),
34
34
  MUX_SIGNING_KEY: optionalString("Mux signing key ID for signed playback URLs.", "Used to sign playback URLs"),
35
35
  MUX_PRIVATE_KEY: optionalString("Mux signing private key for signed playback URLs.", "Used to sign playback URLs"),
36
+ MUX_CUSTOM_DOMAIN: optionalString(
37
+ "Mux domain for image.* and stream.* playback URLs, e.g. staging.mux.com or a custom domain (defaults to mux.com).",
38
+ "Mux custom domain"
39
+ ),
36
40
  MUX_IMAGE_URL_OVERRIDE: optionalString(
37
- "Override for Mux image base URL (defaults to https://image.mux.com).",
41
+ "Deprecated: use MUX_CUSTOM_DOMAIN. Override for Mux image base URL (defaults to https://image.mux.com).",
38
42
  "Mux image URL override"
39
43
  ),
40
44
  MUX_STREAM_URL_OVERRIDE: optionalString(
41
- "Override for Mux stream base URL (defaults to https://stream.mux.com).",
45
+ "Deprecated: use MUX_CUSTOM_DOMAIN. Override for Mux stream base URL (defaults to https://stream.mux.com).",
42
46
  "Mux stream URL override"
43
47
  ),
44
48
  MUX_BASE_URL: optionalString(
@@ -157,7 +161,18 @@ function parseEnv() {
157
161
  }
158
162
  return parsedEnv.data;
159
163
  }
164
+ var hasWarnedAboutDeprecatedUrlOverrides = false;
165
+ function warnOnDeprecatedUrlOverrides(parsed) {
166
+ if (hasWarnedAboutDeprecatedUrlOverrides || !parsed.MUX_IMAGE_URL_OVERRIDE && !parsed.MUX_STREAM_URL_OVERRIDE) {
167
+ return;
168
+ }
169
+ hasWarnedAboutDeprecatedUrlOverrides = true;
170
+ console.warn(
171
+ "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)."
172
+ );
173
+ }
160
174
  var env = parseEnv();
175
+ warnOnDeprecatedUrlOverrides(env);
161
176
  var env_default = env;
162
177
 
163
178
  // src/lib/prompt-fragments.ts
@@ -1158,7 +1173,7 @@ function resolveDirectMuxCredentials(record) {
1158
1173
  function createWorkflowMuxClient(options) {
1159
1174
  return {
1160
1175
  async createClient() {
1161
- const { default: MuxClient } = await import("@mux/mux-node");
1176
+ const { default: MuxClient } = await import("@mux/ts");
1162
1177
  return new MuxClient({
1163
1178
  tokenId: options.tokenId,
1164
1179
  tokenSecret: options.tokenSecret,
@@ -1824,8 +1839,7 @@ function timeRangesOverlap(firstStart, firstEnd, second) {
1824
1839
  }
1825
1840
 
1826
1841
  // src/lib/mux-url.ts
1827
- var DEFAULT_MUX_IMAGE_ORIGIN = "https://image.mux.com";
1828
- var DEFAULT_MUX_STREAM_ORIGIN = "https://stream.mux.com";
1842
+ var DEFAULT_MUX_DOMAIN = "mux.com";
1829
1843
  function normalizeOrigin(value, envVarName) {
1830
1844
  const trimmed = value.trim();
1831
1845
  const candidate = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
@@ -1845,39 +1859,62 @@ function normalizeOrigin(value, envVarName) {
1845
1859
  }
1846
1860
  return parsed.origin;
1847
1861
  }
1848
- function getMuxImageOrigin() {
1849
- const override = env_default.MUX_IMAGE_URL_OVERRIDE;
1850
- if (!override) {
1851
- return DEFAULT_MUX_IMAGE_ORIGIN;
1862
+ function buildPlaybackOrigin(service, customDomain, source) {
1863
+ const invalidDomainError = new Error(
1864
+ `Invalid ${source}. Provide a bare hostname (e.g. "media.example.com") with no scheme, port, credentials, query params, hash fragments, or path.`
1865
+ );
1866
+ const trimmed = customDomain.trim();
1867
+ if (!trimmed) {
1868
+ throw invalidDomainError;
1869
+ }
1870
+ let parsed;
1871
+ try {
1872
+ parsed = new URL(`https://${service}.${trimmed}`);
1873
+ } catch {
1874
+ throw invalidDomainError;
1875
+ }
1876
+ if (parsed.port || parsed.username || parsed.password || parsed.search || parsed.hash || parsed.pathname !== "/") {
1877
+ throw invalidDomainError;
1852
1878
  }
1853
- return normalizeOrigin(override, "MUX_IMAGE_URL_OVERRIDE");
1879
+ return parsed.origin;
1854
1880
  }
1855
- function getMuxStreamOrigin() {
1856
- const override = env_default.MUX_STREAM_URL_OVERRIDE;
1857
- if (!override) {
1858
- return DEFAULT_MUX_STREAM_ORIGIN;
1881
+ async function resolveMuxPlaybackOrigin(service, credentials) {
1882
+ "use step";
1883
+ const { muxCustomDomain } = await resolveWorkflowCredentials(credentials);
1884
+ if (muxCustomDomain) {
1885
+ return buildPlaybackOrigin(service, muxCustomDomain, "muxCustomDomain");
1886
+ }
1887
+ const legacyOverrideEnvVarName = service === "image" ? "MUX_IMAGE_URL_OVERRIDE" : "MUX_STREAM_URL_OVERRIDE";
1888
+ const legacyOverride = env_default[legacyOverrideEnvVarName];
1889
+ if (legacyOverride) {
1890
+ return normalizeOrigin(legacyOverride, legacyOverrideEnvVarName);
1859
1891
  }
1860
- return normalizeOrigin(override, "MUX_STREAM_URL_OVERRIDE");
1892
+ if (env_default.MUX_CUSTOM_DOMAIN) {
1893
+ return buildPlaybackOrigin(service, env_default.MUX_CUSTOM_DOMAIN, "MUX_CUSTOM_DOMAIN");
1894
+ }
1895
+ return buildPlaybackOrigin(service, DEFAULT_MUX_DOMAIN, "custom domain");
1896
+ }
1897
+ async function getMuxImageOrigin(credentials) {
1898
+ return resolveMuxPlaybackOrigin("image", credentials);
1899
+ }
1900
+ async function getMuxStreamOrigin(credentials) {
1901
+ return resolveMuxPlaybackOrigin("stream", credentials);
1861
1902
  }
1862
- function getMuxImageBaseUrl(playbackId, assetType) {
1863
- const origin = getMuxImageOrigin();
1903
+ async function getMuxImageBaseUrl(playbackId, assetType, credentials) {
1904
+ const origin = await getMuxImageOrigin(credentials);
1864
1905
  return `${origin}/${playbackId}/${assetType}.png`;
1865
1906
  }
1866
- function getMuxStoryboardBaseUrl(playbackId) {
1867
- return getMuxImageBaseUrl(playbackId, "storyboard");
1907
+ async function getMuxStoryboardBaseUrl(playbackId, credentials) {
1908
+ return getMuxImageBaseUrl(playbackId, "storyboard", credentials);
1868
1909
  }
1869
- function getMuxThumbnailBaseUrl(playbackId) {
1870
- return getMuxImageBaseUrl(playbackId, "thumbnail");
1910
+ async function getMuxThumbnailBaseUrl(playbackId, credentials) {
1911
+ return getMuxImageBaseUrl(playbackId, "thumbnail", credentials);
1871
1912
  }
1872
1913
 
1873
1914
  // src/lib/url-signing.ts
1874
1915
  async function createSigningClient(context) {
1875
- const { default: MuxClient } = await import("@mux/mux-node");
1916
+ const { default: MuxClient } = await import("@mux/ts");
1876
1917
  return new MuxClient({
1877
- // These are not needed for signing, but the SDK requires them
1878
- // Using empty strings as we only need the jwt functionality
1879
- tokenId: env_default.MUX_TOKEN_ID || "",
1880
- tokenSecret: env_default.MUX_TOKEN_SECRET || "",
1881
1918
  jwtSigningKey: context.keyId,
1882
1919
  jwtPrivateKey: context.keySecret
1883
1920
  });
@@ -1911,7 +1948,7 @@ async function signUrl(url, playbackId, type = "video", params, credentials) {
1911
1948
  var DEFAULT_STORYBOARD_WIDTH = 640;
1912
1949
  async function getStoryboardUrl(playbackId, width = DEFAULT_STORYBOARD_WIDTH, shouldSign = false, credentials, scope) {
1913
1950
  "use step";
1914
- const baseUrl = getMuxStoryboardBaseUrl(playbackId);
1951
+ const baseUrl = await getMuxStoryboardBaseUrl(playbackId, credentials);
1915
1952
  const params = { width };
1916
1953
  if (scope?.startTime !== void 0) {
1917
1954
  params.asset_start_time = scope.startTime;
@@ -2473,7 +2510,7 @@ function concatenateVttSegments(segments, preamble = "WEBVTT") {
2473
2510
  }
2474
2511
  async function buildTranscriptUrl(playbackId, trackId, shouldSign = false, credentials) {
2475
2512
  "use step";
2476
- const baseUrl = `${getMuxStreamOrigin()}/${playbackId}/text/${trackId}.vtt`;
2513
+ const baseUrl = `${await getMuxStreamOrigin(credentials)}/${playbackId}/text/${trackId}.vtt`;
2477
2514
  if (shouldSign) {
2478
2515
  return signUrl(baseUrl, playbackId, "video", void 0, credentials);
2479
2516
  }
@@ -5348,25 +5385,22 @@ async function getHeatmapForAsset(assetId, options = {}) {
5348
5385
  "use step";
5349
5386
  return fetchHeatmap("assets", assetId, options);
5350
5387
  }
5351
- function transformHeatmapResponse(response) {
5352
- return {
5353
- assetId: response.data.asset_id,
5354
- videoId: response.data.video_id,
5355
- playbackId: response.data.playback_id,
5356
- heatmap: response.data.heatmap,
5357
- timeframe: response.timeframe
5358
- };
5359
- }
5360
5388
  async function fetchHeatmap(identifierType, id, options) {
5361
5389
  "use step";
5362
5390
  const { timeframe = "7:days", credentials } = options;
5363
5391
  const muxClient = await getMuxClientFromEnv(credentials);
5364
5392
  const mux = await muxClient.createClient();
5365
- const queryParams = new URLSearchParams();
5366
- queryParams.append("timeframe[]", timeframe);
5367
- const path = `/data/v1/engagement/${identifierType}/${id}/heatmap?${queryParams.toString()}`;
5368
- const response = await mux.get(path);
5369
- return transformHeatmapResponse(response);
5393
+ const query = { timeframe: [timeframe] };
5394
+ const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
5395
+ const response = await resource.heatmap(id, query);
5396
+ const { data } = response;
5397
+ return {
5398
+ assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
5399
+ videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
5400
+ playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
5401
+ heatmap: data.heatmap,
5402
+ timeframe: response.timeframe
5403
+ };
5370
5404
  }
5371
5405
 
5372
5406
  // src/primitives/hotspots.ts
@@ -5375,43 +5409,37 @@ async function getHotspotsForAsset(assetId, options = {}) {
5375
5409
  const response = await fetchHotspots("assets", assetId, options);
5376
5410
  return response.hotspots;
5377
5411
  }
5378
- function transformHotspotResponse(response) {
5379
- return {
5380
- assetId: response.data.asset_id,
5381
- videoId: response.data.video_id,
5382
- playbackId: response.data.playback_id,
5383
- hotspots: response.data.hotspots.map((h) => ({
5384
- startMs: h.start_ms,
5385
- endMs: h.end_ms,
5386
- score: h.score
5387
- }))
5388
- };
5389
- }
5390
5412
  async function fetchHotspots(identifierType, id, options) {
5391
5413
  "use step";
5392
5414
  const {
5393
5415
  limit = 5,
5394
5416
  orderDirection = "desc",
5395
- orderBy = "score",
5396
5417
  timeframe = "7:days",
5397
5418
  credentials
5398
5419
  } = options;
5399
5420
  const muxClient = await getMuxClientFromEnv(credentials);
5400
5421
  const mux = await muxClient.createClient();
5401
- const queryParams = new URLSearchParams();
5402
- queryParams.append("limit", String(limit));
5403
- queryParams.append("order_direction", orderDirection);
5404
- queryParams.append("order_by", orderBy);
5405
- queryParams.append("timeframe[]", timeframe);
5406
- const path = `/data/v1/engagement/${identifierType}/${id}/hotspots?${queryParams.toString()}`;
5407
- const response = await mux.get(path);
5408
- return transformHotspotResponse(response);
5422
+ const query = {
5423
+ limit,
5424
+ order_direction: orderDirection,
5425
+ timeframe: [timeframe]
5426
+ };
5427
+ const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
5428
+ const response = await resource.hotspots(id, query);
5429
+ const { data } = response;
5430
+ return {
5431
+ assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
5432
+ videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
5433
+ playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
5434
+ hotspots: data.hotspots.map((h) => ({
5435
+ startMs: h.start_ms,
5436
+ endMs: h.end_ms,
5437
+ score: h.score
5438
+ }))
5439
+ };
5409
5440
  }
5410
5441
 
5411
5442
  // src/primitives/shots.ts
5412
- function getShotsPath(assetId) {
5413
- return `/video/v1/assets/${assetId}/shots`;
5414
- }
5415
5443
  function mapManifestShots(shots) {
5416
5444
  let usedDeprecatedField = false;
5417
5445
  const mapped = shots.map((shot, index) => {
@@ -5451,29 +5479,35 @@ async function fetchShotsFromManifest(shotsManifestUrl) {
5451
5479
  }
5452
5480
  return mapManifestShots(manifest.shots);
5453
5481
  }
5454
- async function transformShotsResponse(response) {
5455
- switch (response.data.status) {
5482
+ async function transformShotsResponse(data) {
5483
+ switch (data.status) {
5456
5484
  case "pending":
5457
5485
  return {
5458
5486
  status: "pending",
5459
- createdAt: response.data.created_at
5487
+ createdAt: data.created_at
5460
5488
  };
5461
- case "errored":
5489
+ case "errored": {
5490
+ const details = data.errors ?? data.error;
5462
5491
  return {
5463
5492
  status: "errored",
5464
- createdAt: response.data.created_at,
5465
- error: response.data.error
5493
+ createdAt: data.created_at,
5494
+ error: {
5495
+ type: details?.type ?? "unknown",
5496
+ messages: details?.messages ?? []
5497
+ }
5466
5498
  };
5499
+ }
5467
5500
  case "completed":
5501
+ if (!data.shots_manifest_url) {
5502
+ throw new Error("Completed shots response is missing shots_manifest_url");
5503
+ }
5468
5504
  return {
5469
5505
  status: "completed",
5470
- createdAt: response.data.created_at,
5471
- shots: await fetchShotsFromManifest(response.data.shots_manifest_url)
5506
+ createdAt: data.created_at,
5507
+ shots: await fetchShotsFromManifest(data.shots_manifest_url)
5472
5508
  };
5473
- default: {
5474
- const exhaustiveCheck = response.data;
5475
- throw new Error(`Unsupported shots response: ${JSON.stringify(exhaustiveCheck)}`);
5476
- }
5509
+ default:
5510
+ throw new Error(`Unsupported shots status '${data.status}'`);
5477
5511
  }
5478
5512
  }
5479
5513
  async function getShotsForAsset(assetId, options = {}) {
@@ -5481,10 +5515,8 @@ async function getShotsForAsset(assetId, options = {}) {
5481
5515
  const { credentials } = options;
5482
5516
  const muxClient = await getMuxClientFromEnv(credentials);
5483
5517
  const mux = await muxClient.createClient();
5484
- const response = await mux.get(
5485
- getShotsPath(assetId)
5486
- );
5487
- return await transformShotsResponse(response);
5518
+ const data = await mux.video.assets.retrieveShots(assetId);
5519
+ return await transformShotsResponse(data);
5488
5520
  }
5489
5521
 
5490
5522
  // src/workflows/engagement-insights.ts
@@ -5722,7 +5754,7 @@ function mapShotsToHotspots(shots, hotspots) {
5722
5754
  }
5723
5755
  async function getThumbnailUrlsForHotspots(playbackId, hotspots, options = {}) {
5724
5756
  const { width = 640, shouldSign = false, credentials } = options;
5725
- const baseUrl = getMuxThumbnailBaseUrl(playbackId);
5757
+ const baseUrl = await getMuxThumbnailBaseUrl(playbackId, credentials);
5726
5758
  const urlPromises = hotspots.map(async (h) => {
5727
5759
  const time = Math.floor(h.startMs / 1e3);
5728
5760
  if (shouldSign) {
@@ -6823,7 +6855,7 @@ async function getThumbnailUrls(playbackId, duration, options = {}) {
6823
6855
  }
6824
6856
  timestamps = newTimestamps;
6825
6857
  }
6826
- const baseUrl = getMuxThumbnailBaseUrl(playbackId);
6858
+ const baseUrl = await getMuxThumbnailBaseUrl(playbackId, credentials);
6827
6859
  const urlPromises = timestamps.map(async (time) => {
6828
6860
  const url = shouldSign ? await signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials) : `${baseUrl}?time=${time}&width=${width}`;
6829
6861
  return { url, time };
@@ -7287,7 +7319,7 @@ function filterTimestampsWithinExclusiveScope(timestampsMs, scope) {
7287
7319
  async function getThumbnailUrlsFromTimestamps(playbackId, timestampsMs, options) {
7288
7320
  "use step";
7289
7321
  const { width, shouldSign, credentials } = options;
7290
- const baseUrl = getMuxThumbnailBaseUrl(playbackId);
7322
+ const baseUrl = await getMuxThumbnailBaseUrl(playbackId, credentials);
7291
7323
  const times = [...new Set(timestampsMs.map(toThumbnailTimeSeconds))];
7292
7324
  const urlPromises = times.map(async (time) => {
7293
7325
  const url = shouldSign ? await signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials) : `${baseUrl}?time=${time}&width=${width}`;
@@ -8471,7 +8503,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
8471
8503
  { type: "validation_error" }
8472
8504
  );
8473
8505
  }
8474
- let audioUrl = `${getMuxStreamOrigin()}/${playbackId}/audio.m4a`;
8506
+ let audioUrl = `${await getMuxStreamOrigin(credentials)}/${playbackId}/audio.m4a`;
8475
8507
  if (policy === "signed") {
8476
8508
  audioUrl = await signUrl(audioUrl, playbackId, "video", void 0, credentials);
8477
8509
  }