UNPKG

sanity-plugin-mux-input

Version:

An input component that integrates Sanity Studio with Mux video encoding/hosting service.

1,325 lines 340 kB
import { DocumentPreviewPresence, FormField, LinearProgress, PatchEvent, PreviewCard, SanityDefaultPreview, TextWithTone, collate, createHookFromObservableFactory, definePlugin, getPreviewStateObservable, getPreviewValueWithFallback, isRecord, isReference, set, setIfMissing, truncateString, unset, useClient, useCurrentUser, useDataset, useDocumentPresence, useDocumentPreviewStore, useDocumentStore, useDocumentValues, useFormattedDuration, useProjectId, useSchema, useTimeAgo } from "sanity"; import { c } from "react/compiler-runtime"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { SearchIcon } from "@sanity/icons/Search"; import { Autocomplete, Box, Button, Card, Checkbox, Code, Dialog, Flex, Grid, Heading, Inline, Label, Menu, MenuButton, MenuDivider, MenuItem, Popover, Radio, Spinner, Stack, Tab, TabList, TabPanel, Text, TextInput, Tooltip, rem, useClickOutsideEvent, useTheme_v2, useToast } from "@sanity/ui"; import { Suspense, createContext, isValidElement, memo, useCallback, useContext, useEffect, useId, useMemo, useReducer, useRef, useState } from "react"; import { compact, isNumber, isString, toLower, trim, uniq, words } from "lodash"; import { clear, preload, suspend } from "suspend-react"; import { Observable, Subject, concat, defer, from, of, throwError, timer } from "rxjs"; import { css, styled } from "styled-components"; import { CheckmarkCircleIcon } from "@sanity/icons/CheckmarkCircle"; import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline"; import { InfoOutlineIcon } from "@sanity/icons/InfoOutline"; import { RetrieveIcon } from "@sanity/icons/Retrieve"; import { RetryIcon } from "@sanity/icons/Retry"; import { uuid } from "@sanity/uuid"; import { catchError, concatMap, expand, mergeMap, mergeMapTo, switchMap, takeUntil, tap } from "rxjs/operators"; import { ChevronLeftIcon } from "@sanity/icons/ChevronLeft"; import { ChevronRightIcon } from "@sanity/icons/ChevronRight"; import { SyncIcon } from "@sanity/icons/Sync"; import { SortIcon } from "@sanity/icons/Sort"; import { CalendarIcon } from "@sanity/icons/Calendar"; import { CheckmarkIcon } from "@sanity/icons/Checkmark"; import { ClockIcon } from "@sanity/icons/Clock"; import { CropIcon } from "@sanity/icons/Crop"; import { EditIcon } from "@sanity/icons/Edit"; import { RevertIcon } from "@sanity/icons/Revert"; import { TagIcon } from "@sanity/icons/Tag"; import { TrashIcon } from "@sanity/icons/Trash"; import { DownloadIcon } from "@sanity/icons/Download"; import { AddIcon } from "@sanity/icons/Add"; import { ChevronDownIcon } from "@sanity/icons/ChevronDown"; import { ChevronUpIcon } from "@sanity/icons/ChevronUp"; import { TranslateIcon } from "@sanity/icons/Translate"; import { UploadIcon } from "@sanity/icons/Upload"; import LanguagesList from "iso-639-1"; import "@mux/mux-player-react"; import MuxPlayer from "@mux/mux-player-react/lazy"; import { getDevicePixelRatio } from "use-device-pixel-ratio"; import { DocumentIcon } from "@sanity/icons/Document"; import { IntentLink } from "sanity/router"; import { WarningOutlineIcon } from "@sanity/icons/WarningOutline"; import { useObservable } from "react-rx"; import { PublishIcon } from "@sanity/icons/Publish"; import { LockIcon } from "@sanity/icons/Lock"; import { PlayIcon } from "@sanity/icons/Play"; import useSWR from "swr"; import scrollIntoView from "scroll-into-view-if-needed"; import { useErrorBoundary } from "use-error-boundary"; import { PlugIcon } from "@sanity/icons/Plug"; import { UpChunk } from "@mux/upchunk"; import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal"; import { ImageIcon } from "@sanity/icons/Image"; import { ResetIcon } from "@sanity/icons/Reset"; import { isValidElementType } from "react-is"; import { DocumentVideoIcon } from "@sanity/icons/DocumentVideo"; import { WarningFilledIcon } from "@sanity/icons/WarningFilled"; /** * Icon of a monitor with a play button. * Credits: material design icons & react-icons */ const ToolIcon = () => { let $ = c(1), t0; return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsx("svg", { stroke: "currentColor", fill: "currentColor", strokeWidth: "0", viewBox: "0 0 24 24", height: "1em", width: "1em", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z" }) }), $[0] = t0) : t0 = $[0], t0; }, SUPPORTED_MUX_LANGUAGES = [ { label: "English", code: "en", state: "Stable" }, { label: "Spanish", code: "es", state: "Stable" }, { label: "Italian", code: "it", state: "Stable" }, { label: "Portuguese", code: "pt", state: "Stable" }, { label: "German", code: "de", state: "Stable" }, { label: "French", code: "fr", state: "Stable" }, { label: "Polish", code: "pl", state: "Beta" }, { label: "Russian", code: "ru", state: "Beta" }, { label: "Dutch", code: "nl", state: "Beta" }, { label: "Catalan", code: "ca", state: "Beta" }, { label: "Turkish", code: "tr", state: "Beta" }, { label: "Swedish", code: "sv", state: "Beta" }, { label: "Ukrainian", code: "uk", state: "Beta" }, { label: "Norwegian", code: "no", state: "Beta" }, { label: "Finnish", code: "fi", state: "Beta" }, { label: "Slovak", code: "sk", state: "Beta" }, { label: "Greek", code: "el", state: "Beta" }, { label: "Czech", code: "cs", state: "Beta" }, { label: "Croatian", code: "hr", state: "Beta" }, { label: "Danish", code: "da", state: "Beta" }, { label: "Romanian", code: "ro", state: "Beta" }, { label: "Bulgarian", code: "bg", state: "Beta" } ]; SUPPORTED_MUX_LANGUAGES.map((l) => l.code); function isCustomTextTrack(track) { return track.type !== "autogenerated"; } function isAutogeneratedTrack(track) { return track.type === "autogenerated"; } const LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY = "mux-plugin-has-shown-drm-playback-warning", DrmPlaybackWarningContext = createContext({ hasShownWarning: !1, setHasWarnedAboutDrmPlayback: () => null }), DrmPlaybackWarningContextProvider = (t0) => { let $ = c(8), { config, children } = t0, warningDisabled = config?.disableDrmPlaybackWarning ?? !1, t1; $[0] === warningDisabled ? t1 = $[1] : (t1 = warningDisabled || window.localStorage.getItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY) === "true", $[0] = warningDisabled, $[1] = t1); let [hasWarnedAboutDrmPlayback, setHasWarnedAboutDrmPlayback] = useState(t1), t2; $[2] === Symbol.for("react.memo_cache_sentinel") ? (t2 = (b) => { window.localStorage.setItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY, b.toString()), setHasWarnedAboutDrmPlayback(b); }, $[2] = t2) : t2 = $[2]; let setHasShownWarning = t2, t3; $[3] === hasWarnedAboutDrmPlayback ? t3 = $[4] : (t3 = { hasShownWarning: hasWarnedAboutDrmPlayback, setHasWarnedAboutDrmPlayback: setHasShownWarning }, $[3] = hasWarnedAboutDrmPlayback, $[4] = t3); let value = t3, t4; return $[5] !== children || $[6] !== value ? (t4 = /* @__PURE__ */ jsx(DrmPlaybackWarningContext.Provider, { value, children }), $[5] = children, $[6] = value, $[7] = t4) : t4 = $[7], t4; }, useDrmPlaybackWarningContext = () => useContext(DrmPlaybackWarningContext), DRMWarningDialog = (t0) => { let $ = c(12), { onClose } = t0, { setHasWarnedAboutDrmPlayback } = useDrmPlaybackWarningContext(), t1; $[0] !== onClose || $[1] !== setHasWarnedAboutDrmPlayback ? (t1 = () => { setHasWarnedAboutDrmPlayback(!0), onClose(); }, $[0] = onClose, $[1] = setHasWarnedAboutDrmPlayback, $[2] = t1) : t1 = $[2]; let _onClose = t1, t2; $[3] === _onClose ? t2 = $[4] : (t2 = /* @__PURE__ */ jsx(Stack, { padding: 3, children: /* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "primary", onClick: _onClose, text: "Ok" }) }), $[3] = _onClose, $[4] = t2); let t3; $[5] === Symbol.for("react.memo_cache_sentinel") ? (t3 = [ 3, 3, 3 ], $[5] = t3) : t3 = $[5]; let t4; $[6] === Symbol.for("react.memo_cache_sentinel") ? (t4 = /* @__PURE__ */ jsx(Card, { padding: t3, radius: 2, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "DRM-protected playback will generate a license with a small associated cost. The plugin will attempt to play signed or public playback IDs instead whenever possible." }) }) }), $[6] = t4) : t4 = $[6]; let t5; $[7] === Symbol.for("react.memo_cache_sentinel") ? (t5 = [ 3, 3, 3 ], $[7] = t5) : t5 = $[7]; let t6; $[8] === Symbol.for("react.memo_cache_sentinel") ? (t6 = /* @__PURE__ */ jsxs(Stack, { space: 3, padding: 3, children: [t4, /* @__PURE__ */ jsx(Card, { padding: t5, radius: 2, tone: "suggest", children: /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "This is a one time warning. If it persists, you can disable it from your plugin configuration." }) }) })] }), $[8] = t6) : t6 = $[8]; let t7; return $[9] !== _onClose || $[10] !== t2 ? (t7 = /* @__PURE__ */ jsx(Dialog, { open: !0, id: "drm-playback-warn", onClose: _onClose, header: "DRM Playback Warning", footer: t2, children: t6 }), $[9] = _onClose, $[10] = t2, $[11] = t7) : t7 = $[11], t7; }, SANITY_API_VERSION = "2024-03-05"; function useClient$1() { let $ = c(1), t0; return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = { apiVersion: SANITY_API_VERSION }, $[0] = t0) : t0 = $[0], useClient(t0); } const SPECIAL_CHARS = /([^!@#$%^&*(),\\/?";:{}|[\]+<>\s-])+/g, STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/; function tokenize(string) { return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, "")); } function toGroqParams(terms) { return terms.reduce((acc, term, i) => (acc[`t${i}`] = `*${term}*`, acc), {}); } /** * Convert a string into an array of tokenized terms. * * Any (multi word) text wrapped in double quotes will be treated as "phrases", or separate tokens that * will not have its special characters removed. * E.g.`"the" "fantastic mr" fox fox book` =\> ["the", `"fantastic mr"`, "fox", "book"] * * Phrases wrapped in quotes are assigned relevance scoring differently from regular words. * * @internal */ function extractTermsFromQuery(query) { let quotedQueries = [], unquotedQuery = query.replace(/("[^"]*")/g, (match) => words(match).length > 1 ? (quotedQueries.push(match), "") : match), quotedTerms = quotedQueries.map((str) => trim(toLower(str))), remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery)))); return [...quotedTerms, ...remainingTerms]; } /** * Create GROQ constraints, given search terms and the full spec of available document types and fields. * Essentially a large list of all possible fields (joined by logical OR) to match our search terms against. */ function createConstraints(terms, includeAssetId) { let searchPaths = includeAssetId ? ["filename", "assetId"] : ["filename"]; return terms.map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`)).filter((constraint) => constraint.length > 0).map((constraint) => `(${constraint.join(" || ")})`); } function createSearchFilter(query) { let terms = extractTermsFromQuery(query); return { filter: createConstraints(terms, query.length >= 8), params: { ...toGroqParams(terms) } }; } const ASSET_SORT_OPTIONS = { createdDesc: { groq: "_createdAt desc", label: "Newest first" }, createdAsc: { groq: "_createdAt asc", label: "First created (oldest)" }, filenameAsc: { groq: "filename asc", label: "By filename (A-Z)" }, filenameDesc: { groq: "filename desc", label: "By filename (Z-A)" } }, useAssetDocuments = createHookFromObservableFactory(({ documentStore, sort, searchQuery }) => { let search = createSearchFilter(searchQuery), filter = ["_type == \"mux.videoAsset\"", ...search.filter].filter(Boolean).join(" && "), sortFragment = ASSET_SORT_OPTIONS[sort].groq; return documentStore.listenQuery(`*[${filter}] | order(${sortFragment})`, search.params, { apiVersion: SANITY_API_VERSION }); }); function useAssets() { let $ = c(13), documentStore = useDocumentStore(), [sort, setSort] = useState("createdDesc"), [searchQuery, setSearchQuery] = useState(""), t0; $[0] !== documentStore || $[1] !== searchQuery || $[2] !== sort ? (t0 = { documentStore, sort, searchQuery }, $[0] = documentStore, $[1] = searchQuery, $[2] = sort, $[3] = t0) : t0 = $[3]; let [t1, isLoading] = useAssetDocuments(t0), t2; $[4] === t1 ? t2 = $[5] : (t2 = t1 === void 0 ? [] : t1, $[4] = t1, $[5] = t2); let assetDocuments = t2, t3; $[6] === assetDocuments ? t3 = $[7] : (t3 = collate(assetDocuments).map(_temp$9), $[6] = assetDocuments, $[7] = t3); let assets = t3, t4; return $[8] !== assets || $[9] !== isLoading || $[10] !== searchQuery || $[11] !== sort ? (t4 = { assets, isLoading, sort, searchQuery, setSort, setSearchQuery }, $[8] = assets, $[9] = isLoading, $[10] = searchQuery, $[11] = sort, $[12] = t4) : t4 = $[12], t4; } function _temp$9(collated) { return { ...collated.draft || collated.published, _id: collated.id }; } function useDialogState() { return useState(!1); } const PLUGIN_VERSION_QUERY = { sanityVersion: "5.0.7" }; function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId) { let doc = { _id: "secrets.mux", _type: "mux.apiKey", token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId }; return doc.signingKeyId = enableSignedUrls ? signingKeyId : "", doc.signingKeyPrivate = enableSignedUrls ? signingKeyPrivate : "", client.createOrReplace(doc); } async function createSigningKeys(client) { try { let { dataset } = client.config(); return await client.request({ url: `/addons/mux/signing-keys/${dataset}`, withCredentials: !0, method: "POST", query: PLUGIN_VERSION_QUERY }); } catch (error) { console.error("Error creating signing keys", error); let message = error.response?.statusCode === 401 ? "Unauthorized - Failed to create the Signing Key. Please ensure that the token has \"System\" permissions" : error.message; throw Error(message, { cause: error }); } } function testSecrets(client) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/secrets/${dataset}/test`, withCredentials: !0, method: "GET", query: PLUGIN_VERSION_QUERY }); } async function haveValidSigningKeys(client, signingKeyId, signingKeyPrivate) { if (!(signingKeyId && signingKeyPrivate)) return !1; let { dataset } = client.config(); try { let res = await client.request({ url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`, withCredentials: !0, method: "GET", query: PLUGIN_VERSION_QUERY }); return !!(res.data && res.data.id); } catch (e) { return console.error("Error fetching signingKeyId", signingKeyId, "assuming it is not valid", e), !1; } } function testSecretsObservable(client) { let { dataset } = client.config(); return defer(() => client.observable.request({ url: `/addons/mux/secrets/${dataset}/test`, withCredentials: !0, method: "GET", query: PLUGIN_VERSION_QUERY })); } const useSaveSecrets = (client, secrets) => useCallback(async ({ token, secretKey, enableSignedUrls, drmConfigId }) => { let { signingKeyId, signingKeyPrivate } = secrets; try { if (await saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId), !(await testSecrets(client))?.status && token && secretKey) throw Error("Invalid secrets"); } catch (err) { throw console.error("Error while trying to save secrets:", err), err; } if (enableSignedUrls && !await haveValidSigningKeys(client, signingKeyId, signingKeyPrivate)) try { let { data } = await createSigningKeys(client); signingKeyId = data.id, signingKeyPrivate = data.private_key, await saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId ?? ""); } catch (err_0) { throw console.log("Error while creating and saving signing key:", err_0?.message), err_0; } return { token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId }; }, [client, secrets]), name = "mux-input", cacheNs = "sanity-plugin-mux-input", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 16 / 9, path$1 = [ "token", "secretKey", "enableSignedUrls", "signingKeyId", "signingKeyPrivate", "drmConfigId" ], useSecretsDocumentValues = () => { let $ = c(15), { error, isLoading, value } = useDocumentValues("secrets.mux", path$1), exists = !!value, t0 = value?.token || null, t1 = value?.secretKey || null, t2 = value?.enableSignedUrls || !1, t3 = value?.signingKeyId || null, t4 = value?.signingKeyPrivate || null, t5 = value?.drmConfigId || null, t6; $[0] !== t0 || $[1] !== t1 || $[2] !== t2 || $[3] !== t3 || $[4] !== t4 || $[5] !== t5 ? (t6 = { token: t0, secretKey: t1, enableSignedUrls: t2, signingKeyId: t3, signingKeyPrivate: t4, drmConfigId: t5 }, $[0] = t0, $[1] = t1, $[2] = t2, $[3] = t3, $[4] = t4, $[5] = t5, $[6] = t6) : t6 = $[6]; let secrets = t6, t7 = !exists, t8 = !secrets?.token || !secrets?.secretKey, t9; $[7] !== secrets || $[8] !== t7 || $[9] !== t8 ? (t9 = { isInitialSetup: t7, needsSetup: t8, secrets }, $[7] = secrets, $[8] = t7, $[9] = t8, $[10] = t9) : t9 = $[10]; let cache = t9, t10; return $[11] !== cache || $[12] !== error || $[13] !== isLoading ? (t10 = { error, isLoading, value: cache }, $[11] = cache, $[12] = error, $[13] = isLoading, $[14] = t10) : t10 = $[14], t10; }; function init({ token, secretKey, enableSignedUrls, drmConfigId }) { return { submitting: !1, error: null, token: token ?? "", secretKey: secretKey ?? "", enableSignedUrls: enableSignedUrls ?? !1, drmConfigId: drmConfigId ?? "" }; } function reducer(state, action) { switch (action?.type) { case "submit": return { ...state, submitting: !0, error: null }; case "error": return { ...state, submitting: !1, error: action.payload }; case "reset": return init(action.payload); case "change": return { ...state, [action.payload.name]: action.payload.value }; default: throw Error(`Unknown action type: ${action?.type}`); } } const useSecretsFormState = (secrets) => useReducer(reducer, secrets, init), _id = "secrets.mux"; function readSecrets(client) { let { projectId, dataset } = client.config(); return suspend(async () => { let data = await client.fetch("*[_id == $_id][0]{\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId\n }", { _id }); return { token: data?.token || null, secretKey: data?.secretKey || null, enableSignedUrls: !!data?.enableSignedUrls || !1, signingKeyId: data?.signingKeyId || null, signingKeyPrivate: data?.signingKeyPrivate || null, drmConfigId: data?.drmConfigId || null }; }, [ cacheNs, _id, projectId, dataset ]); } function MuxLogo(t0) { let $ = c(12), { height: t1 } = t0, height = t1 === void 0 ? 26 : t1, id = useId(), fillColor = useTheme_v2().color._dark ? "white" : "black", titleId = `${id}-title`, t2; $[0] === Symbol.for("react.memo_cache_sentinel") ? (t2 = { fillRule: "nonzero" }, $[0] = t2) : t2 = $[0]; let pathStyle = t2, t3 = `${height}px`, t4; $[1] === t3 ? t4 = $[2] : (t4 = { height: t3 }, $[1] = t3, $[2] = t4); let t5, t6, t7; $[3] === Symbol.for("react.memo_cache_sentinel") ? (t5 = /* @__PURE__ */ jsx("path", { d: "M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486", style: pathStyle }), t6 = /* @__PURE__ */ jsx("path", { d: "M1537.51,468.511c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m-275.883,-218.509l-143.33,143.329c-24.402,24.402 -24.402,63.966 0,88.368c24.402,24.402 63.967,24.402 88.369,-0l143.33,-143.329l143.328,143.329c24.402,24.4 63.967,24.402 88.369,-0c24.403,-24.402 24.403,-63.966 0.001,-88.368l-143.33,-143.329l0.001,-0.004l143.329,-143.329c24.402,-24.402 24.402,-63.965 0,-88.367c-24.402,-24.402 -63.967,-24.402 -88.369,-0l-143.329,143.328l-143.329,-143.328c-24.402,-24.401 -63.967,-24.402 -88.369,-0c-24.402,24.402 -24.402,63.965 0,88.367l143.329,143.329l0,0.004Z", style: pathStyle }), t7 = /* @__PURE__ */ jsx("path", { d: "M437.511,468.521c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m23.915,-463.762c-23.348,-9.672 -50.226,-4.327 -68.096,13.544l-143.331,143.329l-143.33,-143.329c-17.871,-17.871 -44.747,-23.216 -68.096,-13.544c-23.349,9.671 -38.574,32.455 -38.574,57.729l0,375.026c0,34.51 27.977,62.486 62.487,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-224.173l80.843,80.844c24.404,24.402 63.965,24.402 88.369,-0l80.843,-80.844l0,224.173c0,34.51 27.976,62.486 62.486,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-375.026c0,-25.274 -15.224,-48.058 -38.573,-57.729", style: pathStyle }), $[3] = t5, $[4] = t6, $[5] = t7) : (t5 = $[3], t6 = $[4], t7 = $[5]); let t8; $[6] === fillColor ? t8 = $[7] : (t8 = /* @__PURE__ */ jsxs("g", { id: "Layer-1", fill: fillColor, children: [ t5, t6, t7 ] }), $[6] = fillColor, $[7] = t8); let t9; return $[8] !== t4 || $[9] !== t8 || $[10] !== titleId ? (t9 = /* @__PURE__ */ jsx("svg", { "aria-labelledby": titleId, style: t4, viewBox: "0 0 1600 500", version: "1.1", xmlns: "http://www.w3.org/2000/svg", xmlSpace: "preserve", children: t8 }), $[8] = t4, $[9] = t8, $[10] = titleId, $[11] = t9) : t9 = $[11], t9; } const Logo = styled.span.withConfig({ displayName: "Logo", componentId: "sc-1qgvus-0" })`display:inline-block;height:0.8em;margin-right:1em;transform:translate(0.3em,-0.2em);`, Header = () => { let $ = c(1), t0; return $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Logo, { children: /* @__PURE__ */ jsx(MuxLogo, { height: 13 }) }), "API Credentials"] }), $[0] = t0) : t0 = $[0], t0; }; function FormField$1(props) { let $ = c(15), { children, title, description, inputId } = props, t0; $[0] === title ? t0 = $[1] : (t0 = title || /* @__PURE__ */ jsx("em", { children: "Untitled" }), $[0] = title, $[1] = t0); let t1; $[2] !== inputId || $[3] !== t0 ? (t1 = /* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, weight: "semibold", size: 1, children: t0 }), $[2] = inputId, $[3] = t0, $[4] = t1) : t1 = $[4]; let t2; $[5] === description ? t2 = $[6] : (t2 = description && /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, children: description }), $[5] = description, $[6] = t2); let t3; $[7] !== t1 || $[8] !== t2 ? (t3 = /* @__PURE__ */ jsx(Flex, { align: "flex-end", children: /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [t1, t2] }) }) }), $[7] = t1, $[8] = t2, $[9] = t3) : t3 = $[9]; let t4; $[10] === children ? t4 = $[11] : (t4 = /* @__PURE__ */ jsx("div", { children }), $[10] = children, $[11] = t4); let t5; return $[12] !== t3 || $[13] !== t4 ? (t5 = /* @__PURE__ */ jsxs(Stack, { space: 1, children: [t3, t4] }), $[12] = t3, $[13] = t4, $[14] = t5) : t5 = $[14], t5; } var FormField_default = memo(FormField$1); const fieldNames = [ "token", "secretKey", "enableSignedUrls", "drmConfigId" ]; function ConfigureApiDialog(t0) { let $ = c(91), { secrets, setDialogState } = t0, client = useClient$1(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = secrets.token && secrets.secretKey, t1; $[0] === setDialogState ? t1 = $[1] : (t1 = () => setDialogState(!1), $[0] = setDialogState, $[1] = t1); let handleClose = t1, dirty = secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls || secrets.drmConfigId !== state.drmConfigId, id = `ConfigureApi${useId()}`, t2; $[2] === id ? t2 = $[3] : (t2 = fieldNames.map((field) => `${id}-${field}`), $[2] = id, $[3] = t2); let [tokenId, secretKeyId, enableSignedUrlsId, drmConfigIdId] = t2, firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), t3; $[4] !== client || $[5] !== dispatch || $[6] !== handleSaveSecrets || $[7] !== setDialogState || $[8] !== state ? (t3 = (event) => { if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) { saving.current = !0, dispatch({ type: "submit" }); let { token, secretKey, enableSignedUrls, drmConfigId } = state; handleSaveSecrets({ token, secretKey, enableSignedUrls, drmConfigId }).then((savedSecrets) => { let { projectId, dataset } = client.config(); clear([ cacheNs, _id, projectId, dataset ]), preload(() => Promise.resolve(savedSecrets), [ cacheNs, _id, projectId, dataset ]), setDialogState(!1); }).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => { saving.current = !1; }); } }, $[4] = client, $[5] = dispatch, $[6] = handleSaveSecrets, $[7] = setDialogState, $[8] = state, $[9] = t3) : t3 = $[9]; let handleSubmit = t3, t4; $[10] === dispatch ? t4 = $[11] : (t4 = (event_0) => { dispatch({ type: "change", payload: { name: "token", value: event_0.currentTarget.value } }); }, $[10] = dispatch, $[11] = t4); let handleChangeToken = t4, t5; $[12] === dispatch ? t5 = $[13] : (t5 = (event_1) => { dispatch({ type: "change", payload: { name: "secretKey", value: event_1.currentTarget.value } }); }, $[12] = dispatch, $[13] = t5); let handleChangeSecretKey = t5, t6; $[14] === dispatch ? t6 = $[15] : (t6 = (event_2) => { dispatch({ type: "change", payload: { name: "enableSignedUrls", value: event_2.currentTarget.checked } }); }, $[14] = dispatch, $[15] = t6); let handleChangeEnableSignedUrls = t6, t7; $[16] === dispatch ? t7 = $[17] : (t7 = (event_3) => { dispatch({ type: "change", payload: { name: "drmConfigId", value: event_3.currentTarget.value } }); }, $[16] = dispatch, $[17] = t7); let handleChangeDrmConfigId = t7, t8, t9; $[18] === Symbol.for("react.memo_cache_sentinel") ? (t8 = () => { firstField.current && firstField.current.focus(); }, t9 = [firstField], $[18] = t8, $[19] = t9) : (t8 = $[18], t9 = $[19]), useEffect(t8, t9); let t10; $[20] === Symbol.for("react.memo_cache_sentinel") ? (t10 = /* @__PURE__ */ jsx(Header, {}), $[20] = t10) : t10 = $[20]; let t11; $[21] === hasSecretsInitially ? t11 = $[22] : (t11 = !hasSecretsInitially && /* @__PURE__ */ jsx(Card, { padding: [ 3, 3, 3 ], radius: 2, shadow: 1, tone: "primary", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [/* @__PURE__ */ jsxs(Text, { size: 1, children: [ "To set up a new access token, go to your", " ", /* @__PURE__ */ jsx("a", { href: "https://dashboard.mux.com/settings/access-tokens", target: "_blank", rel: "noreferrer noopener", children: "account on mux.com" }), "." ] }), /* @__PURE__ */ jsxs(Text, { size: 1, children: [ "The access token needs permissions: ", /* @__PURE__ */ jsx("strong", { children: "Mux Video " }), "(Full Access) and ", /* @__PURE__ */ jsx("strong", { children: "Mux Data" }), " (Read)", /* @__PURE__ */ jsx("br", {}), "To use Signed URLs, the token must also have System permissions.", /* @__PURE__ */ jsx("br", {}), "The credentials will be stored safely in a hidden document only available to editors." ] })] }) }), $[21] = hasSecretsInitially, $[22] = t11); let t12 = state.token ?? "", t13 = !!state.secretKey || state.enableSignedUrls, t14; $[23] !== handleChangeToken || $[24] !== t12 || $[25] !== t13 || $[26] !== tokenId ? (t14 = /* @__PURE__ */ jsx(TextInput, { id: tokenId, ref: firstField, onChange: handleChangeToken, type: "text", value: t12, required: t13 }), $[23] = handleChangeToken, $[24] = t12, $[25] = t13, $[26] = tokenId, $[27] = t14) : t14 = $[27]; let t15; $[28] !== t14 || $[29] !== tokenId ? (t15 = /* @__PURE__ */ jsx(FormField_default, { title: "Access Token", inputId: tokenId, children: t14 }), $[28] = t14, $[29] = tokenId, $[30] = t15) : t15 = $[30]; let t16 = state.secretKey ?? "", t17 = !!state.token || state.enableSignedUrls, t18; $[31] !== handleChangeSecretKey || $[32] !== secretKeyId || $[33] !== t16 || $[34] !== t17 ? (t18 = /* @__PURE__ */ jsx(TextInput, { id: secretKeyId, onChange: handleChangeSecretKey, type: "text", value: t16, required: t17 }), $[31] = handleChangeSecretKey, $[32] = secretKeyId, $[33] = t16, $[34] = t17, $[35] = t18) : t18 = $[35]; let t19; $[36] !== secretKeyId || $[37] !== t18 ? (t19 = /* @__PURE__ */ jsx(FormField_default, { title: "Secret Key", inputId: secretKeyId, children: t18 }), $[36] = secretKeyId, $[37] = t18, $[38] = t19) : t19 = $[38]; let t20; $[39] === Symbol.for("react.memo_cache_sentinel") ? (t20 = { display: "block" }, $[39] = t20) : t20 = $[39]; let t21; $[40] !== enableSignedUrlsId || $[41] !== handleChangeEnableSignedUrls || $[42] !== state.enableSignedUrls ? (t21 = /* @__PURE__ */ jsx(Checkbox, { id: enableSignedUrlsId, onChange: handleChangeEnableSignedUrls, checked: state.enableSignedUrls, style: t20 }), $[40] = enableSignedUrlsId, $[41] = handleChangeEnableSignedUrls, $[42] = state.enableSignedUrls, $[43] = t21) : t21 = $[43]; let t22; $[44] === enableSignedUrlsId ? t22 = $[45] : (t22 = /* @__PURE__ */ jsx(Box, { flex: 1, paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx("label", { htmlFor: enableSignedUrlsId, children: "Enable Signed Urls" }) }) }), $[44] = enableSignedUrlsId, $[45] = t22); let t23; $[46] !== t21 || $[47] !== t22 ? (t23 = /* @__PURE__ */ jsxs(Flex, { align: "center", children: [t21, t22] }), $[46] = t21, $[47] = t22, $[48] = t23) : t23 = $[48]; let t24; $[49] !== secrets.signingKeyId || $[50] !== state.enableSignedUrls ? (t24 = secrets.signingKeyId && state.enableSignedUrls ? /* @__PURE__ */ jsx(Card, { padding: [ 3, 3, 3 ], radius: 2, shadow: 1, tone: "caution", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [ /* @__PURE__ */ jsx(Text, { size: 1, children: "The signing key ID that Sanity will use is:" }), /* @__PURE__ */ jsx(Code, { size: 1, children: secrets.signingKeyId }), /* @__PURE__ */ jsxs(Text, { size: 1, children: [ "This key is only used for previewing content in the Sanity UI.", /* @__PURE__ */ jsx("br", {}), "You should generate a different key to use in your application server." ] }) ] }) }) : null, $[49] = secrets.signingKeyId, $[50] = state.enableSignedUrls, $[51] = t24) : t24 = $[51]; let t25; $[52] !== t23 || $[53] !== t24 ? (t25 = /* @__PURE__ */ jsxs(Stack, { space: 4, children: [t23, t24] }), $[52] = t23, $[53] = t24, $[54] = t25) : t25 = $[54]; let t26 = state.drmConfigId ?? "", t27; $[55] !== drmConfigIdId || $[56] !== handleChangeDrmConfigId || $[57] !== t26 ? (t27 = /* @__PURE__ */ jsx(TextInput, { id: drmConfigIdId, onChange: handleChangeDrmConfigId, type: "text", value: t26, required: !1 }), $[55] = drmConfigIdId, $[56] = handleChangeDrmConfigId, $[57] = t26, $[58] = t27) : t27 = $[58]; let t28; $[59] !== drmConfigIdId || $[60] !== t27 ? (t28 = /* @__PURE__ */ jsx(FormField_default, { title: "DRM Configuration ID", inputId: drmConfigIdId, children: t27 }), $[59] = drmConfigIdId, $[60] = t27, $[61] = t28) : t28 = $[61]; let t29; $[62] === Symbol.for("react.memo_cache_sentinel") ? (t29 = [ 3, 3, 3 ], $[62] = t29) : t29 = $[62]; let t30; $[63] === Symbol.for("react.memo_cache_sentinel") ? (t30 = /* @__PURE__ */ jsxs(Text, { size: 1, children: [ "DRM (Digital Rights Management) provides an extra layer of content security for video content streamed from Mux. For additional information check out our", " ", /* @__PURE__ */ jsx("a", { href: "https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos", target: "_blank", rel: "noopener noreferrer", children: "DRM Guide" }), "." ] }), $[63] = t30) : t30 = $[63]; let t31; $[64] === Symbol.for("react.memo_cache_sentinel") ? (t31 = /* @__PURE__ */ jsx(Card, { padding: t29, radius: 2, shadow: 1, tone: "neutral", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [t30, /* @__PURE__ */ jsxs(Text, { size: 1, children: [ /* @__PURE__ */ jsx("a", { href: "https://www.mux.com/support/human", target: "_blank", rel: "noopener noreferrer", children: "Contact us" }), " ", "to get started using DRM." ] })] }) }), $[64] = t31) : t31 = $[64]; let t32 = !dirty, t33; $[65] !== state.submitting || $[66] !== t32 ? (t33 = /* @__PURE__ */ jsx(Button, { text: "Save", disabled: t32, loading: state.submitting, tone: "primary", mode: "default", type: "submit" }), $[65] = state.submitting, $[66] = t32, $[67] = t33) : t33 = $[67]; let t34; $[68] !== handleClose || $[69] !== state.submitting ? (t34 = /* @__PURE__ */ jsx(Button, { disabled: state.submitting, text: "Cancel", mode: "bleed", onClick: handleClose }), $[68] = handleClose, $[69] = state.submitting, $[70] = t34) : t34 = $[70]; let t35; $[71] !== t33 || $[72] !== t34 ? (t35 = /* @__PURE__ */ jsxs(Inline, { space: 2, children: [t33, t34] }), $[71] = t33, $[72] = t34, $[73] = t35) : t35 = $[73]; let t36; $[74] === state.error ? t36 = $[75] : (t36 = state.error && /* @__PURE__ */ jsx(Card, { padding: [ 3, 3, 3 ], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsx(Text, { children: state.error }) }), $[74] = state.error, $[75] = t36); let t37; $[76] !== t11 || $[77] !== t15 || $[78] !== t19 || $[79] !== t25 || $[80] !== t28 || $[81] !== t35 || $[82] !== t36 ? (t37 = /* @__PURE__ */ jsxs(Stack, { space: 4, children: [ t11, t15, t19, t25, t28, t31, t35, t36 ] }), $[76] = t11, $[77] = t15, $[78] = t19, $[79] = t25, $[80] = t28, $[81] = t35, $[82] = t36, $[83] = t37) : t37 = $[83]; let t38; $[84] !== handleSubmit || $[85] !== t37 ? (t38 = /* @__PURE__ */ jsx(Box, { padding: 3, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, noValidate: !0, children: t37 }) }), $[84] = handleSubmit, $[85] = t37, $[86] = t38) : t38 = $[86]; let t39; return $[87] !== handleClose || $[88] !== id || $[89] !== t38 ? (t39 = /* @__PURE__ */ jsx(Dialog, { animate: !0, id, onClose: handleClose, onClickOutside: handleClose, header: t10, zOffset: DIALOGS_Z_INDEX, position: "fixed", width: 1, children: t38 }), $[87] = handleClose, $[88] = id, $[89] = t38, $[90] = t39) : t39 = $[90], t39; } function ConfigureApi() { let $ = c(7), [dialogOpen, setDialogOpen] = useDialogState(), secretDocumentValues = useSecretsDocumentValues(), t0; $[0] === setDialogOpen ? t0 = $[1] : (t0 = () => setDialogOpen("secrets"), $[0] = setDialogOpen, $[1] = t0); let openDialog = t0; if (dialogOpen === "secrets") { let t1; return $[2] !== secretDocumentValues.value.secrets || $[3] !== setDialogOpen ? (t1 = /* @__PURE__ */ jsx(ConfigureApiDialog, { secrets: secretDocumentValues.value.secrets, setDialogState: setDialogOpen }), $[2] = secretDocumentValues.value.secrets, $[3] = setDialogOpen, $[4] = t1) : t1 = $[4], t1; } let t1; return $[5] === openDialog ? t1 = $[6] : (t1 = /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Configure plugin", onClick: openDialog }), $[5] = openDialog, $[6] = t1), t1; } /** * Generates a placeholder title for a Mux asset when no title is available. * This format is used when importing assets that don't have a title in Mux. * * @param assetId - The Mux asset ID * @returns A placeholder title in the format "Asset #[truncated-id]" */ function generateAssetPlaceholder(assetId) { return `Asset #${truncateString(assetId, 15)}`; } /** * Checks if a filename is empty or has the placeholder format. * This is used to determine if a video title should be updated during metadata sync. * * @param filename - The current filename/title of the video * @param assetId - The Mux asset ID to check against * @returns true if the filename is empty or matches the placeholder format */ function isEmptyOrPlaceholderTitle(filename, assetId) { return !filename || filename.trim() === "" || filename === generateAssetPlaceholder(assetId); } function parseMuxDate(date) { return /* @__PURE__ */ new Date(Number(date) * 1e3); } function deleteAssetOnMux(client, assetId) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/${assetId}`, withCredentials: !0, method: "DELETE", query: PLUGIN_VERSION_QUERY }); } async function deleteAsset({ client, asset, deleteOnMux }) { if (!asset?._id) return !0; try { await client.delete(asset._id); } catch { return "failed-sanity"; } if (deleteOnMux && asset?.assetId) try { await deleteAssetOnMux(client, asset.assetId); } catch { return "failed-mux"; } return !0; } function getAsset(client, assetId) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/data/${assetId}`, withCredentials: !0, method: "GET", query: PLUGIN_VERSION_QUERY }); } function listAssets(client, options) { let { dataset } = client.config(), query = {}; return options.limit && (query.limit = options.limit.toString()), options.cursor && (query.cursor = options.cursor), client.request({ url: `/addons/mux/assets/${dataset}/data/list`, withCredentials: !0, method: "GET", query: { ...query, ...PLUGIN_VERSION_QUERY } }); } /** * Adds a new text track to an existing asset using a VTT file URL */ function addTextTrackFromUrl(client, assetId, vttUrl, options) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/${assetId}/tracks`, withCredentials: !0, method: "POST", body: { url: vttUrl, type: "text", language_code: options.language_code, name: options.name, text_type: options.text_type || "subtitles" }, headers: { "Content-Type": "application/json" }, query: PLUGIN_VERSION_QUERY }); } /** * Generates subtitles automatically for an audio track */ function generateSubtitles(client, assetId, audioTrackId, options) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${audioTrackId}/generate-subtitles`, withCredentials: !0, method: "POST", body: { generated_subtitles: [{ language_code: options.language_code, name: options.name }] }, headers: { "Content-Type": "application/json" }, query: PLUGIN_VERSION_QUERY }); } /** * Deletes a text track from an asset */ function deleteTextTrack(client, assetId, trackId) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${trackId}`, withCredentials: !0, method: "DELETE", query: PLUGIN_VERSION_QUERY }); } /** * Updates master access (the "mezzanine" file in Mux's docs) on a Mux asset, via the addon proxy. * @see {@link https://docs.mux.com/api-reference/video/assets/update-asset-master-access} */ function updateMasterAccess(client, assetId, masterAccess) { let { dataset } = client.config(); return client.request({ url: `/addons/mux/assets/${dataset}/${assetId}/master-access`, withCredentials: !0, method: "PUT", body: { master_access: masterAccess }, headers: { "Content-Type": "application/json" }, query: PLUGIN_VERSION_QUERY }); } /** * @docs {@link https://docs.mux.com/api-reference#video/operation/list-assets} */ async function fetchMuxAssetsPage(client, cursor) { try { let response = await listAssets(client, { limit: 100, cursor }); return { cursor, data: response.data, next_cursor: response.next_cursor || null }; } catch { return { cursor, error: { _tag: "FetchError" } }; } } function accumulateIntermediateState(currentState, pageResult) { let currentData = "data" in currentState && currentState.data || [], { validAssets, skippedInThisPage } = ("data" in pageResult && pageResult.data || []).reduce((acc, asset) => { let hasPlaybackIds = asset.playback_ids && asset.playback_ids.length > 0, isDuplicate = currentData.some((a) => a.id === asset.id); return hasPlaybackIds || (acc.skippedInThisPage = !0), hasPlaybackIds && !isDuplicate && acc.validAssets.push(asset), acc; }, { validAssets: [], skippedInThisPage: !1 }); return { ...currentState, data: [...currentData, ...validAssets], error: "error" in pageResult ? pageResult.error : void 0, cursor: "next_cursor" in pageResult ? pageResult.next_cursor : pageResult.cursor, loading: !0, hasSkippedAssetsWithoutPlayback: currentState.hasSkippedAssetsWithoutPlayback || skippedInThisPage }; } function hasMorePages(pageResult) { return typeof pageResult == "object" && "next_cursor" in pageResult && pageResult.next_cursor !== null; } /** * Fetches all assets from a Mux environment. Rules: * - One page at a time * - Uses cursor-based pagination * - We've finished fetching when `next_cursor` is null * - Rate limiting to one request per 2 seconds * - Update state while still fetching to give feedback to users */ function useMuxAssets(t0) { let $ = c(7), { client, enabled } = t0, t1; $[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = { loading: !0, cursor: null }, $[0] = t1) : t1 = $[0]; let [state, setState] = useState(t1), t2; $[1] !== client || $[2] !== enabled || $[3] !== state ? (t2 = () => { if (!enabled) return; let subscription = defer(() => fetchMuxAssetsPage(client, "data" in state && state.data && state.data.length > 0 && !state.error ? state.cursor : null)).pipe(expand((pageResult) => hasMorePages(pageResult) ? timer(2e3).pipe(concatMap(() => defer(() => fetchMuxAssetsPage(client, "next_cursor" in pageResult ? pageResult.next_cursor : null)))) : of()), tap((pageResult_0) => setState((prevState) => accumulateIntermediateState(prevState, pageResult_0)))).subscribe({ complete: () => { setState(_temp$8); } }); return () => subscription.unsubscribe(); }, $[1] = client, $[2] = enabled, $[3] = state, $[4] = t2) : t2 = $[4]; let t3; return $[5] === enabled ? t3 = $[6] : (t3 = [enabled], $[5] = enabled, $[6] = t3), useEffect(t2, t3), state; } function _temp$8(prev) { return { ...prev, loading: !1 }; } function useImportMuxAssets() { let $ = c(27), documentStore = useDocumentStore(), t0; $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = { apiVersion: SANITY_API_VERSION }, $[0] = t0) : t0 = $[0]; let client = useClient(t0), [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore), hasSecrets = !!useSecretsDocumentValues().value.secrets?.secretKey, [importError, setImportError] = useState(), [importState, setImportState] = useState("closed"), dialogOpen = importState !== "closed", t1 = hasSecrets && dialogOpen, t2; $[1] !== client || $[2] !== t1 ? (t2 = { client, enabled: t1 }, $[1] = client, $[2] = t1, $[3] = t2) : t2 = $[3]; let muxAssets = useMuxAssets(t2), t3; $[4] !== assetsInSanity || $[5] !== muxAssets.data ? (t3 = assetsInSanity && muxAssets.data ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity)) : void 0, $[4] = assetsInSanity, $[5] = muxAssets.data, $[6] = t3) : t3 = $[6]; let missingAssets = t3, t4; $[7] === Symbol.for("react.memo_cache_sentinel") ? (t4 = [], $[7] = t4) : t4 = $[7]; let [selectedAssets, setSelectedAssets] = useState(t4), t5; $[8] === importState ? t5 = $[9] : (t5 = () => { importState !== "importing" && setImportState("closed"); }, $[8] = importState, $[9] = t5); let closeDialog = t5, t6; $[10] === importState ? t6 = $[11] : (t6 = () => { importState === "closed" && setImportState("idle"); }, $[10] = importState, $[11] = t6); let openDialog = t6, t7; $[12] !== client || $[13] !== selectedAssets ? (t7 = async function importAssets() { setImportState("importing"); let documents = selectedAssets.flatMap(_temp$7), tx = client.transaction(); documents.forEach((doc) => tx.create(doc)); try { await tx.commit({ returnDocuments: !1 }), setSelectedAssets([]), setImportState("done"); } catch (t8) { let error = t8; setImportState("error"), setImportError(error); } }, $[12] = client, $[13] = selectedAssets, $[14] = t7) : t7 = $[14]; let importAssets = t7, t8; return $[15] !== assetsInSanityLoading || $[16] !== closeDialog || $[17] !== dialogOpen || $[18] !== hasSecrets || $[19] !== importAssets || $[20] !== importError || $[21] !== importState || $[22] !== missingAssets || $[23] !== muxAssets || $[24] !== openDialog || $[25] !== selectedAssets ? (t8 = { assetsInSanityLoading, closeDialog, dialogOpen, importState, importError, hasSecrets, importAssets, missingAssets, muxAssets, openDialog, selectedAssets, setSelectedAssets }, $[15] = assetsInSanityLoading, $[16] = closeDialog, $[17] = dialogOpen, $[18] = hasSecrets, $[19] = importAssets, $[20] = importError, $[21] = importState, $[22] = missingAssets, $[23] = muxAssets, $[24] = openDialog, $[25] = selectedAssets, $[26] = t8) : t8 = $[26], t8; } function _temp$7(asset) { return muxAssetToSanityDocument(asset) || []; } function muxAssetToSanityDocument(asset) { let playbackId = (asset.playback_ids || []).find((p) => p.id)?.id; if (playbackId) return { _id: uuid(), _type: "mux.videoAsset", _updatedAt: (/* @__PURE__ */ new Date()).toISOString(), _createdAt: parseMuxDate(asset.created_at).toISOString(), assetId: asset.id, playbackId, filename: asset.meta?.title ?? generateAssetPlaceholder(asset.id), status: asset.status, data: asset }; } const useAssetsInSanity = createHookFromObservableFactory((documentStore) => documentStore.listenQuery("*[_type == \"mux.videoAsset\"] {\n \"uploadId\": coalesce(uploadId, data.upload_id),\n \"assetId\": coalesce(assetId, data.id),\n }", {}, { apiVersion: SANITY_API_VERSION })); function assetExistsInSanity(asset, existingAssets) { return asset.status === "ready" && existingAssets.some((existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id); } function useInView(ref, t0) { let $ = c(6), t1; $[0] === t0 ? t1 = $[1] : (t1 = t0 === void 0 ? {} : t0, $[0] = t0, $[1] = t1); let options = t1, [inView, setInView] = useState(!1), t2, t3; return $[2] !== options || $[3] !== ref ? (t2 = () => { if (!ref.current) return; let observer = new IntersectionObserver((t4, obs) => { let [entry] = t4, nowInView = entry.isIntersecting && obs.thresholds.some((threshold) => entry.intersectionRatio >= threshold); setInView(nowInView), options?.onChange?.(nowInView); }, options), toObserve = ref.current; return observer.observe(toObserve), () => { toObserve && observer.unobserve(toObserve); }; }, t3 = [options, ref], $[2] = options, $[3] = ref, $[4] = t2, $[5] = t3) : (t2 = $[4], t3 = $[5]), useEffect(t2, t3), inView; } function getPlaybackId(asset, priority = [ "drm", "signed", "public" ]) { try { if (!asset) throw TypeError("Tried to get playback Id with no asset"); let playbackIds = asset.data?.playback_ids; if (playbackIds && playbackIds.length > 0) { for (let policy of priority) { let match = playbackIds.find((entry) => entry.policy === policy); if (match) return match.id; } return playbackIds[0].id; } throw TypeError("Missing playbackId"); } catch (e) { throw console.error("Asset is missing a playbackId", { asset }, e), e; } } function getPlaybackPolicy(asset) { return asset.data?.playback_ids?.find((playbackId) => getPlaybackId(asset, [ "drm", "signed", "public" ]) === playbackId.id) ?? { id: "", policy: "public" }; } function getPlaybackPolicyById(asset, playbackId) { return asset.data?.playback_ids?.find((entry) => playbackId === entry.id); } function hasPlaybackPolicy(data, policy) { return data.advanced_playback_policies && data.advanced_playback_policies.find((p) => p.policy === policy) || data.playback_policy?.find((p) => p === policy); } /** * Uses suspend. Call this with {@link tryWithSuspend} or rethrow the Promise */ function generateJwt(client, playbackId, aud, payload) { let { signingKeyId, signingKeyPrivate } = readSecrets(client); if (!signingKeyId) throw TypeError("Missing `signingKeyId`.\n Check your plugin's configuration"); if (!signingKeyPrivate) throw TypeError("Missing `signingKeyPrivate`.\n Check your plugin's configuration"); let { default: sign } = suspend(() => import("jsonwebtoken-esm/sign"), ["jsonwebtoken-esm/sign"]); return sign(payload ? JSON.parse(JSON.stringify(payload, (_, v) => v ?? void 0)) : {}, atob(signingKeyPrivate), { algorithm: "RS256", keyid: signingKeyId, audience: aud, subject: playbackId, noTimestamp: !0, expiresIn: "12h" }); } /** * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise */ function createUrlParamsObject(cli