@mux/ai 0.7.4 → 0.7.6

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.
@@ -138,6 +138,10 @@ var EnvSchema = z.object({
138
138
  ),
139
139
  MUX_SIGNING_KEY: optionalString("Mux signing key ID for signed playback URLs.", "Used to sign playback URLs"),
140
140
  MUX_PRIVATE_KEY: optionalString("Mux signing private key for signed playback URLs.", "Used to sign playback URLs"),
141
+ MUX_IMAGE_URL_OVERRIDE: optionalString(
142
+ "Override for Mux image base URL (defaults to https://image.mux.com).",
143
+ "Mux image URL override"
144
+ ),
141
145
  // Test-only helpers (used by this repo's integration tests)
142
146
  MUX_TEST_ASSET_ID: optionalString("Mux asset ID used by integration tests.", "Mux test asset id"),
143
147
  MUX_TEST_ASSET_ID_CHAPTERS: optionalString("Mux asset ID used by integration tests for chapters.", "Mux test asset id for chapters"),
@@ -424,12 +428,13 @@ function readString(record, key) {
424
428
  function resolveDirectMuxCredentials(record) {
425
429
  const tokenId = readString(record, "muxTokenId");
426
430
  const tokenSecret = readString(record, "muxTokenSecret");
431
+ const authorizationToken = readString(record, "muxAuthorizationToken");
427
432
  const signingKey = readString(record, "muxSigningKey");
428
433
  const privateKey = readString(record, "muxPrivateKey");
429
- if (!tokenId && !tokenSecret && !signingKey && !privateKey) {
434
+ if (!tokenId && !tokenSecret && !authorizationToken && !signingKey && !privateKey) {
430
435
  return void 0;
431
436
  }
432
- if (!tokenId || !tokenSecret) {
437
+ if ((!tokenId || !tokenSecret) && !authorizationToken) {
433
438
  throw new Error(
434
439
  "Both muxTokenId and muxTokenSecret are required when passing direct Mux workflow credentials."
435
440
  );
@@ -437,6 +442,7 @@ function resolveDirectMuxCredentials(record) {
437
442
  return {
438
443
  tokenId,
439
444
  tokenSecret,
445
+ authorizationToken,
440
446
  signingKey,
441
447
  privateKey
442
448
  };
@@ -447,7 +453,8 @@ function createWorkflowMuxClient(options) {
447
453
  const { default: MuxClient } = await import("@mux/mux-node");
448
454
  return new MuxClient({
449
455
  tokenId: options.tokenId,
450
- tokenSecret: options.tokenSecret
456
+ tokenSecret: options.tokenSecret,
457
+ authorizationToken: options.authorizationToken
451
458
  });
452
459
  },
453
460
  getSigningKey() {
@@ -832,6 +839,44 @@ async function withRetry(fn, {
832
839
  throw lastError || new Error("Retry failed with unknown error");
833
840
  }
834
841
 
842
+ // src/lib/mux-image-url.ts
843
+ var DEFAULT_MUX_IMAGE_ORIGIN = "https://image.mux.com";
844
+ function normalizeMuxImageOrigin(value) {
845
+ const trimmed = value.trim();
846
+ const candidate = trimmed.includes("://") ? trimmed : `https://${trimmed}`;
847
+ let parsed;
848
+ try {
849
+ parsed = new URL(candidate);
850
+ } catch {
851
+ throw new Error(
852
+ `Invalid MUX_IMAGE_URL_OVERRIDE. Provide a hostname like "image.example.mux.com" (or a URL origin such as "https://image.example.mux.com").`
853
+ );
854
+ }
855
+ if (parsed.username || parsed.password || parsed.search || parsed.hash || parsed.pathname && parsed.pathname !== "/") {
856
+ throw new Error(
857
+ "Invalid MUX_IMAGE_URL_OVERRIDE. Only a hostname/origin is allowed (no credentials, query params, hash fragments, or path)."
858
+ );
859
+ }
860
+ return parsed.origin;
861
+ }
862
+ function getMuxImageOrigin() {
863
+ const override = env_default.MUX_IMAGE_URL_OVERRIDE;
864
+ if (!override) {
865
+ return DEFAULT_MUX_IMAGE_ORIGIN;
866
+ }
867
+ return normalizeMuxImageOrigin(override);
868
+ }
869
+ function getMuxImageBaseUrl(playbackId, assetType) {
870
+ const origin = getMuxImageOrigin();
871
+ return `${origin}/${playbackId}/${assetType}.png`;
872
+ }
873
+ function getMuxStoryboardBaseUrl(playbackId) {
874
+ return getMuxImageBaseUrl(playbackId, "storyboard");
875
+ }
876
+ function getMuxThumbnailBaseUrl(playbackId) {
877
+ return getMuxImageBaseUrl(playbackId, "thumbnail");
878
+ }
879
+
835
880
  // src/lib/url-signing.ts
836
881
  async function createSigningClient(context) {
837
882
  const { default: MuxClient } = await import("@mux/mux-node");
@@ -856,9 +901,9 @@ async function signPlaybackId(playbackId, context, type = "video", params) {
856
901
  params: stringParams
857
902
  });
858
903
  }
859
- async function signUrl(url, playbackId, context, type = "video", params, credentials) {
904
+ async function signUrl(url, playbackId, type = "video", params, credentials) {
860
905
  "use step";
861
- const resolvedContext = context ?? await resolveMuxSigningContext(credentials);
906
+ const resolvedContext = await resolveMuxSigningContext(credentials);
862
907
  if (!resolvedContext) {
863
908
  throw new Error(
864
909
  "Signed playback ID requires signing credentials. Provide muxSigningKey and muxPrivateKey via workflow credentials or set MUX_SIGNING_KEY and MUX_PRIVATE_KEY environment variables."
@@ -873,9 +918,9 @@ async function signUrl(url, playbackId, context, type = "video", params, credent
873
918
  var DEFAULT_STORYBOARD_WIDTH = 640;
874
919
  async function getStoryboardUrl(playbackId, width = DEFAULT_STORYBOARD_WIDTH, shouldSign = false, credentials) {
875
920
  "use step";
876
- const baseUrl = `https://image.mux.com/${playbackId}/storyboard.png`;
921
+ const baseUrl = getMuxStoryboardBaseUrl(playbackId);
877
922
  if (shouldSign) {
878
- return signUrl(baseUrl, playbackId, void 0, "storyboard", { width }, credentials);
923
+ return signUrl(baseUrl, playbackId, "storyboard", { width }, credentials);
879
924
  }
880
925
  return `${baseUrl}?width=${width}`;
881
926
  }
@@ -992,7 +1037,7 @@ async function buildTranscriptUrl(playbackId, trackId, shouldSign = false, crede
992
1037
  "use step";
993
1038
  const baseUrl = `https://stream.mux.com/${playbackId}/text/${trackId}.vtt`;
994
1039
  if (shouldSign) {
995
- return signUrl(baseUrl, playbackId, void 0, "video", void 0, credentials);
1040
+ return signUrl(baseUrl, playbackId, "video", void 0, credentials);
996
1041
  }
997
1042
  return baseUrl;
998
1043
  }
@@ -2082,10 +2127,10 @@ async function getThumbnailUrls(playbackId, duration, options = {}) {
2082
2127
  }
2083
2128
  timestamps = newTimestamps;
2084
2129
  }
2085
- const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;
2130
+ const baseUrl = getMuxThumbnailBaseUrl(playbackId);
2086
2131
  const urlPromises = timestamps.map(async (time) => {
2087
2132
  if (shouldSign) {
2088
- return signUrl(baseUrl, playbackId, void 0, "thumbnail", { time, width }, credentials);
2133
+ return signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials);
2089
2134
  }
2090
2135
  return `${baseUrl}?time=${time}&width=${width}`;
2091
2136
  });
@@ -2101,11 +2146,10 @@ var DEFAULT_PROVIDER2 = "openai";
2101
2146
  var HIVE_ENDPOINT = "https://api.thehive.ai/api/v2/task/sync";
2102
2147
  var HIVE_SEXUAL_CATEGORIES = [
2103
2148
  "general_nsfw",
2104
- "general_suggestive",
2105
2149
  "yes_sexual_activity",
2106
- "sex_toys",
2107
- "nudity_female",
2108
- "nudity_male"
2150
+ "yes_sex_toy",
2151
+ "yes_female_nudity",
2152
+ "yes_male_nudity"
2109
2153
  ];
2110
2154
  var HIVE_VIOLENCE_CATEGORIES = [
2111
2155
  "gun_in_hand",
@@ -2116,10 +2160,8 @@ var HIVE_VIOLENCE_CATEGORIES = [
2116
2160
  "hanging",
2117
2161
  "noose",
2118
2162
  "human_corpse",
2119
- "emaciated_body",
2120
- "self_harm",
2121
- "animal_abuse",
2122
- "fights",
2163
+ "yes_emaciated_body",
2164
+ "yes_self_harm",
2123
2165
  "garm_death_injury_or_military_conflict"
2124
2166
  ];
2125
2167
  async function processConcurrently(items, processor, maxConcurrent = 5) {
@@ -2263,6 +2305,12 @@ function getHiveCategoryScores(classes, categoryNames) {
2263
2305
  const scoreMap = Object.fromEntries(
2264
2306
  classes.map((c) => [c.class, c.score])
2265
2307
  );
2308
+ const missingCategories = categoryNames.filter((category) => !(category in scoreMap));
2309
+ if (missingCategories.length > 0) {
2310
+ console.warn(
2311
+ `Hive response missing expected categories: ${missingCategories.join(", ")}`
2312
+ );
2313
+ }
2266
2314
  const scores = categoryNames.map((category) => scoreMap[category] || 0);
2267
2315
  return Math.max(...scores, 0);
2268
2316
  }
@@ -2356,11 +2404,11 @@ async function requestHiveModeration(imageUrls, maxConcurrent = 5, submissionMod
2356
2404
  async function getThumbnailUrlsFromTimestamps(playbackId, timestampsMs, options) {
2357
2405
  "use step";
2358
2406
  const { width, shouldSign, credentials } = options;
2359
- const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;
2407
+ const baseUrl = getMuxThumbnailBaseUrl(playbackId);
2360
2408
  const urlPromises = timestampsMs.map(async (tsMs) => {
2361
2409
  const time = Number((tsMs / 1e3).toFixed(2));
2362
2410
  if (shouldSign) {
2363
- return signUrl(baseUrl, playbackId, void 0, "thumbnail", { time, width }, credentials);
2411
+ return signUrl(baseUrl, playbackId, "thumbnail", { time, width }, credentials);
2364
2412
  }
2365
2413
  return `${baseUrl}?time=${time}&width=${width}`;
2366
2414
  });
@@ -3633,7 +3681,7 @@ async function translateAudio(assetId, toLanguageCode, options = {}) {
3633
3681
  }
3634
3682
  let audioUrl = `https://stream.mux.com/${playbackId}/audio.m4a`;
3635
3683
  if (policy === "signed") {
3636
- audioUrl = await signUrl(audioUrl, playbackId, void 0, "video", void 0, credentials);
3684
+ audioUrl = await signUrl(audioUrl, playbackId, "video", void 0, credentials);
3637
3685
  }
3638
3686
  console.warn("\u{1F399}\uFE0F Fetching audio from Mux...");
3639
3687
  let audioBuffer;
@@ -4013,6 +4061,8 @@ async function translateCaptions(assetId, fromLanguageCode, toLanguageCode, opti
4013
4061
  };
4014
4062
  }
4015
4063
  export {
4064
+ HIVE_SEXUAL_CATEGORIES,
4065
+ HIVE_VIOLENCE_CATEGORIES,
4016
4066
  SUMMARY_KEYWORD_LIMIT,
4017
4067
  askQuestions,
4018
4068
  burnedInCaptionsSchema,