sanity-plugin-mux-input 4.0.3 → 4.1.1

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/dist/index.d.ts CHANGED
@@ -214,6 +214,7 @@ interface MuxAsset {
214
214
  status: 'preparing' | 'ready' | 'errored';
215
215
  duration: number;
216
216
  max_stored_resolution: 'Audio only' | 'SD' | 'HD' | 'FHD' | 'UHD';
217
+ max_resolution_tier?: '2160p' | '1440p' | '1080p';
217
218
  max_stored_frame_rate: -1 | number;
218
219
  aspect_ratio: `${number}:${number}`;
219
220
  playback_ids: MuxPlaybackId[];
@@ -225,7 +226,7 @@ interface MuxAsset {
225
226
  live_stream_id?: string;
226
227
  master?: {
227
228
  status: 'ready' | 'preparing' | 'errored';
228
- url: string;
229
+ url?: string;
229
230
  };
230
231
  master_access: 'temporary' | 'none';
231
232
  mp4_support: 'standard' | 'none';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/util/types.ts","../src/_exports/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/util/types.ts","../src/_exports/index.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, getPreviewValueWithFallback, DocumentPreviewPresence, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, useCurrentUser, isReference, useProjectId, useDataset, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
1
+ import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, DocumentPreviewPresence, getPreviewValueWithFallback, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, useCurrentUser, isReference, useProjectId, useDataset, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
2
2
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
3
- import { ErrorOutlineIcon, InfoOutlineIcon, RetryIcon, CheckmarkCircleIcon, RetrieveIcon, ChevronLeftIcon, ChevronRightIcon, SyncIcon, SortIcon, UploadIcon, TranslateIcon, DownloadIcon, AddIcon, ChevronUpIcon, ChevronDownIcon, TrashIcon, EditIcon, WarningOutlineIcon, PublishIcon, DocumentIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, CheckmarkIcon, LockIcon, PlayIcon, PlugIcon, EllipsisHorizontalIcon, ImageIcon, ResetIcon, WarningFilledIcon, DocumentVideoIcon } from "@sanity/icons";
3
+ import { ErrorOutlineIcon, InfoOutlineIcon, RetryIcon, CheckmarkCircleIcon, RetrieveIcon, ChevronLeftIcon, ChevronRightIcon, SyncIcon, SortIcon, DownloadIcon, UploadIcon, TranslateIcon, AddIcon, ChevronUpIcon, ChevronDownIcon, TrashIcon, EditIcon, WarningOutlineIcon, PublishIcon, DocumentIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, CheckmarkIcon, LockIcon, PlayIcon, PlugIcon, EllipsisHorizontalIcon, ImageIcon, ResetIcon, WarningFilledIcon, DocumentVideoIcon } from "@sanity/icons";
4
4
  import { Dialog, Stack, Card, Text, Button, useTheme_v2, Flex, Box, TextInput, Checkbox, Code, Inline, Spinner, Heading, Label as Label$1, Radio, MenuButton, Menu, MenuItem, useToast, Autocomplete, Tooltip, TabList, Tab, TabPanel, Grid, useClickOutsideEvent, Popover, MenuDivider, rem } from "@sanity/ui";
5
- import { createContext, useState, useCallback, useMemo, useContext, useReducer, useId, memo, useRef, useEffect, Suspense, isValidElement, forwardRef } from "react";
5
+ import { createContext, useState, useCallback, useMemo, useContext, useReducer, useId, memo, useRef, useEffect, Suspense, isValidElement } from "react";
6
6
  import compact from "lodash/compact.js";
7
7
  import toLower from "lodash/toLower.js";
8
8
  import trim from "lodash/trim.js";
@@ -142,7 +142,7 @@ function useDialogState() {
142
142
  const PLUGIN_VERSION_QUERY = {
143
143
  sanityVersion: (
144
144
  // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature
145
- "4.0.3"
145
+ "4.1.1"
146
146
  )
147
147
  };
148
148
  function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId) {
@@ -250,7 +250,7 @@ const useSaveSecrets = (client, secrets) => useCallback(async ({
250
250
  signingKeyPrivate,
251
251
  drmConfigId
252
252
  };
253
- }, [client, secrets]), name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, AUDIO_ASPECT_RATIO = 5 / 1, path$1 = ["token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate", "drmConfigId"], useSecretsDocumentValues = () => {
253
+ }, [client, secrets]), name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, MEZZANINE_LEARN_MORE_URL = "https://www.mux.com/docs/guides/download-for-offline-editing#enable-master-access", THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, AUDIO_ASPECT_RATIO = 5 / 1, path$1 = ["token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate", "drmConfigId"], useSecretsDocumentValues = () => {
254
254
  const {
255
255
  error,
256
256
  isLoading,
@@ -638,6 +638,23 @@ function deleteTextTrack(client, assetId, trackId) {
638
638
  query: PLUGIN_VERSION_QUERY
639
639
  });
640
640
  }
641
+ function updateMasterAccess(client, assetId, masterAccess) {
642
+ const {
643
+ dataset
644
+ } = client.config();
645
+ return client.request({
646
+ url: `/addons/mux/assets/${dataset}/${assetId}/master-access`,
647
+ withCredentials: !0,
648
+ method: "PUT",
649
+ body: {
650
+ master_access: masterAccess
651
+ },
652
+ headers: {
653
+ "Content-Type": "application/json"
654
+ },
655
+ query: PLUGIN_VERSION_QUERY
656
+ });
657
+ }
641
658
  const ASSETS_PER_PAGE = 100;
642
659
  async function fetchMuxAssetsPage(client, cursor) {
643
660
  try {
@@ -1135,19 +1152,19 @@ const PageSelector = (props) => {
1135
1152
  function addKeysToMuxData(data) {
1136
1153
  return {
1137
1154
  ...data,
1138
- tracks: data.tracks?.map((track) => ({
1155
+ tracks: data.tracks?.map((track, index) => ({
1139
1156
  ...track,
1140
- _key: uuid()
1157
+ _key: track.id || `track-${index}`
1141
1158
  })),
1142
- playback_ids: data.playback_ids?.map((playbackId) => ({
1159
+ playback_ids: data.playback_ids?.map((playbackId, index) => ({
1143
1160
  ...playbackId,
1144
- _key: uuid()
1161
+ _key: playbackId.id || `playback-${index}`
1145
1162
  })),
1146
1163
  static_renditions: data.static_renditions ? {
1147
1164
  ...data.static_renditions,
1148
- files: data.static_renditions.files?.map((file) => ({
1165
+ files: data.static_renditions.files?.map((file, index) => ({
1149
1166
  ...file,
1150
- _key: uuid()
1167
+ _key: file.id || `rendition-${index}`
1151
1168
  }))
1152
1169
  } : void 0
1153
1170
  };
@@ -1393,6 +1410,144 @@ function StopWatchIcon(props) {
1393
1410
  /* @__PURE__ */ jsx("path", { d: "M192 32h128v48H192z", fill: "currentColor" })
1394
1411
  ] });
1395
1412
  }
1413
+ const POLL_INTERVAL_MS = 3e3;
1414
+ function getMezzanineStatus(asset) {
1415
+ const master = asset.data?.master;
1416
+ return master?.status === "preparing" ? "preparing" : master?.status === "ready" && master.url ? "ready" : master?.status === "errored" ? "errored" : "disabled";
1417
+ }
1418
+ function useMezzanine(asset) {
1419
+ const client = useClient(), toast = useToast(), master = asset.data?.master, [busy, setBusy] = useState(!1), [expired, setExpired] = useState(!1), [prevAssetId, setPrevAssetId] = useState(asset.assetId);
1420
+ prevAssetId !== asset.assetId && (setPrevAssetId(asset.assetId), setExpired(!1));
1421
+ const resolution = useMemo(() => asset.data?.max_resolution_tier || asset.data?.max_stored_resolution || void 0, [asset.data?.max_resolution_tier, asset.data?.max_stored_resolution]), status = getMezzanineStatus(asset), persist = useCallback(async (data) => {
1422
+ asset._id && await client.patch(asset._id).set({
1423
+ status: data.status,
1424
+ data: addKeysToMuxData(data)
1425
+ }).commit({
1426
+ returnDocuments: !1
1427
+ });
1428
+ }, [asset._id, client]), refresh = useCallback(async () => {
1429
+ if (!asset.assetId || !asset._id) return;
1430
+ const {
1431
+ data
1432
+ } = await getAsset(client, asset.assetId);
1433
+ return await persist(data), data;
1434
+ }, [asset.assetId, asset._id, client, persist]);
1435
+ useEffect(() => {
1436
+ if (master?.status !== "preparing" || !asset.assetId || !asset._id) return;
1437
+ let cancelled = !1, running = !1;
1438
+ const interval = setInterval(async () => {
1439
+ if (!running) {
1440
+ running = !0;
1441
+ try {
1442
+ const data = await refresh();
1443
+ if (cancelled) return;
1444
+ (!data || data.master?.status !== "preparing") && clearInterval(interval);
1445
+ } catch (error) {
1446
+ console.error("Failed to poll mezzanine status:", error);
1447
+ } finally {
1448
+ running = !1;
1449
+ }
1450
+ }
1451
+ }, POLL_INTERVAL_MS);
1452
+ return () => {
1453
+ cancelled = !0, clearInterval(interval);
1454
+ };
1455
+ }, [master?.status, asset.assetId, asset._id, refresh]);
1456
+ const enable = useCallback(async () => {
1457
+ if (!(!asset.assetId || !asset._id)) {
1458
+ setBusy(!0), setExpired(!1);
1459
+ try {
1460
+ const {
1461
+ data
1462
+ } = await updateMasterAccess(client, asset.assetId, "temporary");
1463
+ await persist(data);
1464
+ } catch (error) {
1465
+ toast.push({
1466
+ status: "error",
1467
+ title: "Could not enable the mezzanine file",
1468
+ description: error instanceof Error ? error.message : "Please try again"
1469
+ });
1470
+ } finally {
1471
+ setBusy(!1);
1472
+ }
1473
+ }
1474
+ }, [asset.assetId, asset._id, client, persist, toast]), download = useCallback(async () => {
1475
+ if (asset.assetId) {
1476
+ setBusy(!0);
1477
+ try {
1478
+ const data = await refresh(), url = data?.master?.status === "ready" ? data.master.url : void 0;
1479
+ url ? (setExpired(!1), triggerMezzanineDownload(url)) : setExpired(!0);
1480
+ } catch (error) {
1481
+ toast.push({
1482
+ status: "error",
1483
+ title: "Could not download the mezzanine file",
1484
+ description: error instanceof Error ? error.message : "Please try again"
1485
+ });
1486
+ } finally {
1487
+ setBusy(!1);
1488
+ }
1489
+ }
1490
+ }, [asset.assetId, refresh, toast]);
1491
+ return {
1492
+ status,
1493
+ busy,
1494
+ expired,
1495
+ resolution,
1496
+ enable,
1497
+ download
1498
+ };
1499
+ }
1500
+ function triggerMezzanineDownload(masterUrl) {
1501
+ if (typeof window > "u") return;
1502
+ const anchor = document.createElement("a");
1503
+ anchor.href = masterUrl, anchor.target = "_blank", anchor.rel = "noopener noreferrer", document.body.appendChild(anchor), anchor.click(), document.body.removeChild(anchor);
1504
+ }
1505
+ function MezzanineExplanation() {
1506
+ return /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
1507
+ /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "When you enable the mezzanine file, Mux creates a copy equivalent in quality to your original video \u2014 ideal for offline editing or archiving. Unlike the streamable MP4 (static) renditions, it is not meant for streaming." }),
1508
+ /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "The file is prepared in the background and may take a few minutes depending on the asset's duration and resolution. Enabling is free and the download stays available for 24 hours." })
1509
+ ] });
1510
+ }
1511
+ function Mezzanine({
1512
+ asset,
1513
+ withExplanation = !0
1514
+ }) {
1515
+ const {
1516
+ status,
1517
+ busy,
1518
+ expired,
1519
+ resolution,
1520
+ enable,
1521
+ download
1522
+ } = useMezzanine(asset), assetReady = asset.status === "ready" || asset.data?.status === "ready", isReady = status === "ready" && !expired, isPreparing = status === "preparing", showExplanation = !isReady && !isPreparing;
1523
+ return /* @__PURE__ */ jsx(Card, { padding: 3, radius: 2, tone: "transparent", border: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
1524
+ /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 3, children: [
1525
+ /* @__PURE__ */ jsx(Label$1, { muted: !0, size: 1, children: "Mezzanine" }),
1526
+ /* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsx("a", { href: MEZZANINE_LEARN_MORE_URL, target: "_blank", rel: "noopener noreferrer", children: "Learn more" }) })
1527
+ ] }),
1528
+ /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1529
+ /* @__PURE__ */ jsx(Text, { size: 1, muted: !isReady, children: "mezzanine.mp4" }),
1530
+ resolution && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: resolution })
1531
+ ] }),
1532
+ withExplanation && showExplanation && /* @__PURE__ */ jsx(MezzanineExplanation, {}),
1533
+ showExplanation && (expired || status === "errored") && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1534
+ expired && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "The previous mezzanine file expired. Enable it again to download." }),
1535
+ status === "errored" && /* @__PURE__ */ jsx(Text, { size: 1, style: {
1536
+ color: "var(--card-critical-color)"
1537
+ }, children: "Mux could not prepare the mezzanine file. Please try again." })
1538
+ ] }),
1539
+ isPreparing && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Preparing the mezzanine file\u2026 this can take a few minutes. You can close this and come back later." }),
1540
+ isReady && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Ready to download. The link stays available for about 24 hours." }),
1541
+ /* @__PURE__ */ jsx(Flex, { justify: "flex-end", gap: 2, children: isPreparing ? /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
1542
+ /* @__PURE__ */ jsx(Spinner, { muted: !0, size: 1 }),
1543
+ /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Preparing\u2026" })
1544
+ ] }) : isReady ? /* @__PURE__ */ jsx(Button, { icon: DownloadIcon, text: "Download", tone: "positive", fontSize: 1, padding: 3, loading: busy, disabled: busy, onClick: () => {
1545
+ download();
1546
+ } }) : /* @__PURE__ */ jsx(Button, { text: status === "errored" ? "Try again" : "Enable", tone: "primary", fontSize: 1, padding: 3, loading: busy, disabled: busy || !assetReady, onClick: () => {
1547
+ enable();
1548
+ } }) })
1549
+ ] }) });
1550
+ }
1396
1551
  function useResyncAsset(options) {
1397
1552
  const client = useClient(), toast = useToast(), [resyncState, setResyncState] = useState("idle"), [resyncError, setResyncError] = useState(null), showToast = options?.showToast ?? !1, resyncAsset = useCallback(async (asset) => {
1398
1553
  if (!asset.assetId) {
@@ -1625,6 +1780,7 @@ const SUPPORTED_MUX_LANGUAGES = [{
1625
1780
  code: "bg",
1626
1781
  state: "Beta"
1627
1782
  }];
1783
+ SUPPORTED_MUX_LANGUAGES.map((l) => l.code);
1628
1784
  function isCustomTextTrack(track) {
1629
1785
  return track.type !== "autogenerated";
1630
1786
  }
@@ -1820,7 +1976,7 @@ function AddCaptionDialog({
1820
1976
  textAlign: "center"
1821
1977
  }, children: "Or enter the caption file URL" }),
1822
1978
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1823
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "vtt-url", children: "Caption File URL (.vtt or .srt)" }),
1979
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "vtt-url", children: "Caption File URL (.vtt or .srt)" }),
1824
1980
  /* @__PURE__ */ jsx(TextInput, { id: "vtt-url", placeholder: "https://example.com/subtitles.vtt", value: vttUrl, onChange: (e) => {
1825
1981
  setVttUrl(e.currentTarget.value), setSelectedFile(null);
1826
1982
  }, disabled: isSubmitting })
@@ -1828,7 +1984,7 @@ function AddCaptionDialog({
1828
1984
  ] })
1829
1985
  ] }),
1830
1986
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1831
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "caption-name", children: "Audio name" }),
1987
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "caption-name", children: "Audio name" }),
1832
1988
  /* @__PURE__ */ jsx(Autocomplete, { id: "caption-name", value: selectedLanguage?.value || "", onChange: (newValue) => {
1833
1989
  const selected = (isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS$1).find((opt) => opt.value === newValue);
1834
1990
  selected && (setSelectedLanguage(selected), setLanguageCode(selected.value), setName(selected.label));
@@ -1840,7 +1996,7 @@ function AddCaptionDialog({
1840
1996
  ] }) }), disabled: isSubmitting })
1841
1997
  ] }),
1842
1998
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
1843
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "caption-language", children: "Language Code" }),
1999
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "caption-language", children: "Language Code" }),
1844
2000
  /* @__PURE__ */ jsx(TextInput, { id: "caption-language", placeholder: "en-US", value: languageCode, onChange: (e) => {
1845
2001
  setLanguageCode(e.currentTarget.value), selectedLanguage && selectedLanguage.value !== e.currentTarget.value && (setSelectedLanguage(null), (!name2 || name2 === selectedLanguage.label) && setName(""));
1846
2002
  }, disabled: isSubmitting })
@@ -2081,7 +2237,7 @@ function EditCaptionDialog({
2081
2237
  ] })
2082
2238
  ] }),
2083
2239
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2084
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "vtt-url", children: "VTT File URL" }),
2240
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "vtt-url", children: "VTT File URL" }),
2085
2241
  /* @__PURE__ */ jsx(TextInput, { id: "vtt-url", placeholder: "https://example.com/subtitles.vtt", value: vttUrl, onChange: (e) => {
2086
2242
  setVttUrl(e.currentTarget.value), setSelectedFile(null);
2087
2243
  }, disabled: isSubmitting }),
@@ -2089,7 +2245,7 @@ function EditCaptionDialog({
2089
2245
  ] })
2090
2246
  ] }),
2091
2247
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2092
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "caption-name", children: "Audio name" }),
2248
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "caption-name", children: "Audio name" }),
2093
2249
  /* @__PURE__ */ jsx(Autocomplete, { id: "caption-name", value: selectedLanguage?.value || "", onChange: (newValue) => {
2094
2250
  const selected = LANGUAGE_OPTIONS.find((opt) => opt.value === newValue);
2095
2251
  selected && (setSelectedLanguage(selected), setLanguageCode(selected.value), setName(selected.label));
@@ -2101,7 +2257,7 @@ function EditCaptionDialog({
2101
2257
  ] }) }), disabled: isSubmitting })
2102
2258
  ] }),
2103
2259
  /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
2104
- /* @__PURE__ */ jsx(Label$1, { htmlFor: "caption-language", children: "Language Code" }),
2260
+ /* @__PURE__ */ jsx(Label$1, { as: "label", htmlFor: "caption-language", children: "Language Code" }),
2105
2261
  /* @__PURE__ */ jsx(TextInput, { id: "caption-language", placeholder: "en-US", value: languageCode, onChange: (e) => {
2106
2262
  setLanguageCode(e.currentTarget.value), selectedLanguage && selectedLanguage.value !== e.currentTarget.value && (setSelectedLanguage(null), (!name2 || name2 === selectedLanguage.label) && setName(""));
2107
2263
  }, disabled: isSubmitting })
@@ -2472,6 +2628,20 @@ function AudioIcon(props) {
2472
2628
  opacity: "0.65"
2473
2629
  }, d: "M10.75 19q.95 0 1.6-.65t.65-1.6V13h3v-2h-4v3.875q-.275-.2-.587-.288t-.663-.087q-.95 0-1.6.65t-.65 1.6t.65 1.6t1.6.65M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z" }) });
2474
2630
  }
2631
+ function MezzanineDialog({
2632
+ asset,
2633
+ onClose
2634
+ }) {
2635
+ const {
2636
+ setDialogState
2637
+ } = useDialogStateContext(), dialogId = `MezzanineDialog${useId()}`, closing = () => {
2638
+ onClose?.(), setDialogState(!1);
2639
+ }, status = getMezzanineStatus(asset);
2640
+ return /* @__PURE__ */ jsx(Dialog, { id: dialogId, header: "Mezzanine file", onClose: closing, zOffset: DIALOGS_Z_INDEX, width: 1, children: /* @__PURE__ */ jsx(Box, { padding: 4, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
2641
+ status !== "preparing" && status !== "ready" && /* @__PURE__ */ jsx(MezzanineExplanation, {}),
2642
+ /* @__PURE__ */ jsx(Mezzanine, { asset, withExplanation: !1 })
2643
+ ] }) }) });
2644
+ }
2475
2645
  function VideoPlayer({
2476
2646
  asset,
2477
2647
  thumbnailWidth = 250,
@@ -2560,7 +2730,7 @@ function VideoPlayer({
2560
2730
  /* @__PURE__ */ jsx(MuxPlayer, { poster: isAudio ? void 0 : poster, ref: muxPlayer, ...props, playsInline: !0, playbackId, tokens, preload: "metadata", crossOrigin: "anonymous", metadata: {
2561
2731
  player_name: "Sanity Admin Dashboard",
2562
2732
  // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature
2563
- player_version: "4.0.3",
2733
+ player_version: "4.1.1",
2564
2734
  page_type: "Preview Player"
2565
2735
  }, audio: isAudio, _hlsConfig: hlsConfig, style: {
2566
2736
  ...!isAudio && {
@@ -2596,7 +2766,8 @@ function VideoPlayer({
2596
2766
  currentTime: muxPlayer?.current?.currentTime
2597
2767
  }
2598
2768
  ),
2599
- dialogState === "edit-captions" && /* @__PURE__ */ jsx(CaptionsDialog, { asset })
2769
+ dialogState === "edit-captions" && /* @__PURE__ */ jsx(CaptionsDialog, { asset }),
2770
+ dialogState === "mezzanine" && /* @__PURE__ */ jsx(MezzanineDialog, { asset })
2600
2771
  ] });
2601
2772
  }
2602
2773
  function assetIsAudio(asset) {
@@ -2943,7 +3114,10 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField, { title: props.labe
2943
3114
  } : void 0, children: [
2944
3115
  /* @__PURE__ */ jsxs(Stack, { space: 4, flex: 1, sizing: "border", children: [
2945
3116
  /* @__PURE__ */ jsx(VideoPlayer, { asset: props.asset, autoPlay: props.asset.autoPlay || !1 }),
2946
- tab === "details" && /* @__PURE__ */ jsx(TextTracksManager, { asset: props.asset, iconOnly: !0, collapseTracks: !0, tracks: displayInfo?.text_tracks || props.asset.data?.tracks?.filter((track) => track.type === "text") || [] })
3117
+ tab === "details" && /* @__PURE__ */ jsxs(Fragment, { children: [
3118
+ /* @__PURE__ */ jsx(TextTracksManager, { asset: props.asset, iconOnly: !0, collapseTracks: !0, tracks: displayInfo?.text_tracks || props.asset.data?.tracks?.filter((track) => track.type === "text") || [] }),
3119
+ /* @__PURE__ */ jsx(Mezzanine, { asset: props.asset })
3120
+ ] })
2947
3121
  ] }),
2948
3122
  /* @__PURE__ */ jsxs(Stack, { space: 4, flex: 1, sizing: "border", children: [
2949
3123
  /* @__PURE__ */ jsxs(TabList, { space: 2, children: [
@@ -3142,22 +3316,31 @@ const useAccessControl = (config) => {
3142
3316
  return !1;
3143
3317
  const files = asset?.data?.static_renditions?.files;
3144
3318
  return !files || files.length === 0 ? !1 : files.some((file) => file.status === "preparing");
3145
- }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files]), shouldFetch = useMemo(() => !!asset?.assetId && (asset?.status === "preparing" || isPreparingStaticRenditions), [asset?.assetId, asset?.status, isPreparingStaticRenditions]);
3319
+ }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files]), shouldFetch = useMemo(() => !!asset?.assetId && (asset?.status === "preparing" || isPreparingStaticRenditions), [asset?.assetId, asset?.status, isPreparingStaticRenditions]), errorLoggedRef = useRef(!1);
3146
3320
  return useSWR(shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null, async () => {
3147
- const {
3148
- data
3149
- } = await client.request({
3150
- url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
3151
- withCredentials: !0,
3152
- method: "GET",
3153
- query: PLUGIN_VERSION_QUERY
3154
- });
3155
- await client.patch(asset._id).set({
3156
- status: data.status,
3157
- data
3158
- }).commit({
3159
- returnDocuments: !1
3160
- });
3321
+ try {
3322
+ const {
3323
+ data
3324
+ } = await client.request({
3325
+ url: `/addons/mux/assets/${dataset}/data/${asset.assetId}`,
3326
+ withCredentials: !0,
3327
+ method: "GET",
3328
+ query: PLUGIN_VERSION_QUERY
3329
+ });
3330
+ if (!asset?._id || !data) return;
3331
+ await client.patch(asset._id).set({
3332
+ status: data.status,
3333
+ data: addKeysToMuxData(data)
3334
+ }).commit({
3335
+ returnDocuments: !1
3336
+ }), errorLoggedRef.current = !1;
3337
+ } catch (error) {
3338
+ errorLoggedRef.current || (errorLoggedRef.current = !0, console.error("[sanity-plugin-mux-input] Mux polling failed", {
3339
+ assetId: asset?.assetId,
3340
+ documentId: asset?._id,
3341
+ error
3342
+ }));
3343
+ }
3161
3344
  }, {
3162
3345
  refreshInterval: 2e3,
3163
3346
  refreshWhenHidden: !0,
@@ -3681,7 +3864,8 @@ const FileButton = /* @__PURE__ */ styled(MenuItem).withConfig({
3681
3864
  opacity: 0;
3682
3865
  }
3683
3866
  `;
3684
- }), FileInputMenuItem = forwardRef(function(props, forwardedRef) {
3867
+ });
3868
+ function FileInputMenuItem(props) {
3685
3869
  const {
3686
3870
  icon: Icon,
3687
3871
  id: idProp,
@@ -3694,6 +3878,7 @@ const FileButton = /* @__PURE__ */ styled(MenuItem).withConfig({
3694
3878
  textAlign,
3695
3879
  text,
3696
3880
  disabled,
3881
+ ref,
3697
3882
  ...rest
3698
3883
  } = props, idHook = useId(), id = idProp || idHook, handleChange = useCallback((event) => {
3699
3884
  onSelect && event.target.files && onSelect(Array.from(event.target.files));
@@ -3704,11 +3889,12 @@ const FileButton = /* @__PURE__ */ styled(MenuItem).withConfig({
3704
3889
  ] }) }),
3705
3890
  text && /* @__PURE__ */ jsx(Text, { align: textAlign, size: fontSize, textOverflow: "ellipsis", children: text })
3706
3891
  ] });
3707
- return /* @__PURE__ */ jsxs(FileButton, { ...rest, htmlFor: id, disabled, ref: forwardedRef, children: [
3892
+ return /* @__PURE__ */ jsxs(FileButton, { ...rest, htmlFor: id, disabled, ref, children: [
3708
3893
  content,
3709
3894
  /* @__PURE__ */ jsx("input", { "data-testid": "file-button-input", accept, capture, id, multiple, onChange: handleChange, type: "file", value: "", disabled })
3710
3895
  ] });
3711
- }), LockCard = styled(Card).withConfig({
3896
+ }
3897
+ const LockCard = styled(Card).withConfig({
3712
3898
  displayName: "LockCard",
3713
3899
  componentId: "sc-aimiq6-0"
3714
3900
  })`position:absolute;top:0;left:0;opacity:0.6;mix-blend-mode:screen;background:transparent;`, LockButton = styled(Button).withConfig({
@@ -3748,6 +3934,8 @@ function PlayerActionsMenu$1(props) {
3748
3934
  /* @__PURE__ */ jsx(MenuItem, { icon: SyncIcon, text: "Resync from Mux", onClick: handleResync, disabled: readOnly || isResyncing })
3749
3935
  ] }),
3750
3936
  /* @__PURE__ */ jsx(MenuDivider, {}),
3937
+ /* @__PURE__ */ jsx(MenuItem, { icon: DownloadIcon, text: "Mezzanine", onClick: () => setDialogState("mezzanine") }),
3938
+ /* @__PURE__ */ jsx(MenuDivider, {}),
3751
3939
  hasConfigAccess && /* @__PURE__ */ jsxs(Fragment, { children: [
3752
3940
  /* @__PURE__ */ jsx(MenuItem, { icon: PlugIcon, text: "Configure API", onClick: () => setDialogState("secrets") }),
3753
3941
  /* @__PURE__ */ jsx(MenuDivider, {})
@@ -5050,23 +5238,26 @@ function withFocusRing(component) {
5050
5238
  `;
5051
5239
  });
5052
5240
  }
5053
- const UploadCardWithFocusRing = withFocusRing(Card), UploadCard = forwardRef(({
5241
+ const UploadCardWithFocusRing = withFocusRing(Card);
5242
+ function UploadCard({
5054
5243
  children,
5055
5244
  tone,
5056
5245
  onPaste,
5057
5246
  onDrop,
5058
5247
  onDragEnter,
5059
5248
  onDragLeave,
5060
- onDragOver
5061
- }, forwardedRef) => {
5249
+ onDragOver,
5250
+ ref
5251
+ }) {
5062
5252
  const inputRef = useRef(null), handleKeyDown = useCallback((event) => {
5063
5253
  event.target.closest("#vtt-url") || (event.ctrlKey || event.metaKey) && event.key === "v" && inputRef.current.focus();
5064
5254
  }, []);
5065
- return /* @__PURE__ */ jsxs(UploadCardWithFocusRing, { tone, ref: forwardedRef, padding: 0, radius: 2, shadow: 0, tabIndex: 0, onKeyDown: handleKeyDown, onPaste, onDrop, onDragEnter, onDragLeave, onDragOver, children: [
5255
+ return /* @__PURE__ */ jsxs(UploadCardWithFocusRing, { tone, ref, padding: 0, radius: 2, shadow: 0, tabIndex: 0, onKeyDown: handleKeyDown, onPaste, onDrop, onDragEnter, onDragLeave, onDragOver, children: [
5066
5256
  /* @__PURE__ */ jsx(HiddenInput$1, { ref: inputRef }),
5067
5257
  children
5068
5258
  ] });
5069
- }), HiddenInput$1 = styled.input.attrs({
5259
+ }
5260
+ const HiddenInput$1 = styled.input.attrs({
5070
5261
  type: "text"
5071
5262
  }).withConfig({
5072
5263
  displayName: "HiddenInput",
@@ -5538,6 +5729,16 @@ const muxVideoSchema = {
5538
5729
  type: "mux.staticRenditionFile"
5539
5730
  }]
5540
5731
  }]
5732
+ }, muxMasterFile = {
5733
+ name: "mux.masterFile",
5734
+ type: "object",
5735
+ fields: [{
5736
+ type: "string",
5737
+ name: "status"
5738
+ }, {
5739
+ type: "string",
5740
+ name: "url"
5741
+ }]
5541
5742
  }, muxAssetData = {
5542
5743
  name: "mux.assetData",
5543
5744
  title: "Mux asset data",
@@ -5602,6 +5803,9 @@ const muxVideoSchema = {
5602
5803
  }, {
5603
5804
  name: "static_renditions",
5604
5805
  type: "mux.staticRenditions"
5806
+ }, {
5807
+ name: "master",
5808
+ type: "mux.masterFile"
5605
5809
  }]
5606
5810
  }, muxVideoAsset = {
5607
5811
  name: "mux.videoAsset",
@@ -5626,7 +5830,7 @@ const muxVideoSchema = {
5626
5830
  type: "mux.assetData",
5627
5831
  name: "data"
5628
5832
  }]
5629
- }, schemaTypes = [muxTrack, muxPlaybackId, muxStaticRenditionFile, muxStaticRenditions, muxAssetData, muxVideoAsset], defaultConfig = {
5833
+ }, schemaTypes = [muxTrack, muxPlaybackId, muxStaticRenditionFile, muxStaticRenditions, muxMasterFile, muxAssetData, muxVideoAsset], defaultConfig = {
5630
5834
  static_renditions: [],
5631
5835
  mp4_support: "none",
5632
5836
  video_quality: "plus",