sanity-plugin-mux-input 3.0.4 → 3.0.5

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.
Files changed (92) hide show
  1. package/README.md +0 -2
  2. package/dist/index.cjs +2876 -4400
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +134 -193
  5. package/dist/index.d.cts.map +1 -0
  6. package/dist/index.d.ts +134 -193
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +2877 -4401
  9. package/dist/index.js.map +1 -1
  10. package/package.json +36 -36
  11. package/src/_exports/index.ts +1 -1
  12. package/src/actions/assets.ts +5 -5
  13. package/src/actions/secrets.ts +5 -6
  14. package/src/actions/upload.ts +32 -34
  15. package/src/components/AddCaptionDialog.tsx +3 -3
  16. package/src/components/ConfigureApi.tsx +7 -7
  17. package/src/components/DraggableWatermark.tsx +15 -7
  18. package/src/components/EditCaptionDialog.tsx +6 -5
  19. package/src/components/EditThumbnailDialog.tsx +4 -5
  20. package/src/components/ErrorBoundaryCard.tsx +1 -0
  21. package/src/components/FileInputButton.tsx +1 -1
  22. package/src/components/FileInputMenuItem.tsx +10 -10
  23. package/src/components/ImportVideosFromMux.tsx +0 -3
  24. package/src/components/MuxLogo.tsx +1 -1
  25. package/src/components/Onboard.tsx +1 -1
  26. package/src/components/PageSelector.tsx +1 -1
  27. package/src/components/Player.styled.tsx +0 -44
  28. package/src/components/Player.tsx +1 -1
  29. package/src/components/PlayerActionsMenu.tsx +3 -2
  30. package/src/components/ResyncMetadata.tsx +4 -6
  31. package/src/components/SelectAsset.tsx +2 -2
  32. package/src/components/SelectSortOptions.tsx +3 -3
  33. package/src/components/TextTracksEditor.tsx +2 -2
  34. package/src/components/TextTracksManager.tsx +5 -4
  35. package/src/components/UploadConfiguration.tsx +17 -15
  36. package/src/components/UploadPlaceholder.tsx +1 -1
  37. package/src/components/UploadProgress.tsx +4 -4
  38. package/src/components/Uploader.styled.tsx +1 -2
  39. package/src/components/Uploader.tsx +15 -14
  40. package/src/components/VideoDetails/DeleteDialog.tsx +2 -1
  41. package/src/components/VideoDetails/VideoDetails.tsx +3 -3
  42. package/src/components/VideoDetails/useVideoDetails.ts +2 -2
  43. package/src/components/VideoInBrowser.tsx +1 -1
  44. package/src/components/VideoMetadata.tsx +1 -1
  45. package/src/components/VideoPlayer.tsx +12 -6
  46. package/src/components/VideoThumbnail.tsx +4 -3
  47. package/src/components/VideosBrowser.tsx +1 -1
  48. package/src/components/documentPreview/DocumentPreview.tsx +4 -3
  49. package/src/components/documentPreview/PaneItemPreview.tsx +5 -12
  50. package/src/components/uploadConfiguration/PlaybackPolicy.tsx +3 -3
  51. package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +2 -2
  52. package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +1 -1
  53. package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +2 -2
  54. package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +4 -4
  55. package/src/components/withFocusRing/withFocusRing.ts +1 -1
  56. package/src/context/DialogStateContext.tsx +3 -6
  57. package/src/context/DrmPlaybackWarningContext.tsx +14 -10
  58. package/src/hooks/useAccessControl.ts +1 -1
  59. package/src/hooks/useAssetDocumentValues.ts +2 -2
  60. package/src/hooks/useAssets.ts +11 -6
  61. package/src/hooks/useCancelUpload.ts +2 -2
  62. package/src/hooks/useDocReferences.ts +2 -2
  63. package/src/hooks/useFetchFileSize.ts +4 -3
  64. package/src/hooks/useImportMuxAssets.ts +3 -3
  65. package/src/hooks/useInView.ts +3 -4
  66. package/src/hooks/useMediaMetadata.ts +5 -4
  67. package/src/hooks/useMuxAssets.ts +15 -15
  68. package/src/hooks/useMuxPolling.ts +6 -3
  69. package/src/hooks/useResyncAsset.ts +1 -1
  70. package/src/hooks/useResyncMuxMetadata.ts +4 -11
  71. package/src/hooks/useSaveSecrets.ts +4 -4
  72. package/src/hooks/useSecretsDocumentValues.ts +1 -1
  73. package/src/util/asserters.ts +0 -13
  74. package/src/util/convertWatermarkToMux.ts +4 -4
  75. package/src/util/createUrlParamsObject.ts +3 -3
  76. package/src/util/extractFiles.ts +3 -3
  77. package/src/util/formatBytes.ts +0 -1
  78. package/src/util/formatSeconds.ts +0 -1
  79. package/src/util/generateJwt.ts +3 -3
  80. package/src/util/getAnimatedPosterSrc.ts +1 -1
  81. package/src/util/getPlaybackPolicy.ts +6 -6
  82. package/src/util/getPosterSrc.ts +1 -1
  83. package/src/util/pluginVersion.ts +5 -1
  84. package/src/util/readSecrets.ts +1 -1
  85. package/src/util/textTracks.ts +5 -5
  86. package/src/util/tryWithSuspend.ts +1 -1
  87. package/src/util/types.ts +2 -32
  88. package/src/components/InputError.tsx +0 -17
  89. package/src/components/documentPreview/paneItemTypes.ts +0 -7
  90. package/src/util/areSecretsSignable.ts +0 -5
  91. package/src/util/getStoryboardSrc.ts +0 -27
  92. package/src/util/isSigned.ts +0 -20
package/package.json CHANGED
@@ -1,63 +1,62 @@
1
1
  {
2
2
  "name": "sanity-plugin-mux-input",
3
- "version": "3.0.4",
3
+ "version": "3.0.5",
4
4
  "description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
5
5
  "keywords": [
6
- "sanity",
7
- "video",
8
- "mux",
9
6
  "input",
7
+ "media",
8
+ "mux",
10
9
  "plugin",
10
+ "sanity",
11
11
  "sanity-plugin",
12
- "media"
12
+ "video"
13
13
  ],
14
14
  "homepage": "https://github.com/sanity-io/plugins/tree/main/plugins/sanity-plugin-mux-input#readme",
15
15
  "bugs": {
16
16
  "url": "https://github.com/sanity-io/plugins/issues"
17
17
  },
18
+ "license": "MIT",
19
+ "author": "Sanity.io <hello@sanity.io>",
18
20
  "repository": {
19
21
  "type": "git",
20
22
  "url": "git+ssh://git@github.com/sanity-io/plugins.git",
21
23
  "directory": "plugins/sanity-plugin-mux-input"
22
24
  },
23
- "license": "MIT",
24
- "author": "Sanity.io <hello@sanity.io>",
25
- "sideEffects": false,
25
+ "files": [
26
+ "src",
27
+ "dist",
28
+ "sanity.json",
29
+ "v2-incompatible.js"
30
+ ],
26
31
  "type": "module",
32
+ "sideEffects": false,
33
+ "main": "./dist/index.cjs",
34
+ "types": "./dist/index.d.ts",
27
35
  "exports": {
28
36
  ".": {
29
- "source": "./src/_exports/index.ts",
30
37
  "import": "./dist/index.js",
31
38
  "require": "./dist/index.cjs",
32
39
  "default": "./dist/index.js"
33
40
  },
34
41
  "./package.json": "./package.json"
35
42
  },
36
- "main": "./dist/index.cjs",
37
- "types": "./dist/index.d.ts",
38
- "files": [
39
- "src",
40
- "dist",
41
- "sanity.json",
42
- "v2-incompatible.js"
43
- ],
44
43
  "dependencies": {
45
- "@mux/mux-player": "^3.8.0",
46
- "@mux/mux-player-react": "^3.8.0",
47
- "@mux/upchunk": "^3.4.0",
44
+ "@mux/mux-player": "^3.13.0",
45
+ "@mux/mux-player-react": "^3.13.0",
46
+ "@mux/upchunk": "^3.5.0",
48
47
  "@sanity/icons": "^3.7.4",
49
- "@sanity/incompatible-plugin": "^1.0.4",
48
+ "@sanity/incompatible-plugin": "^1.0.5",
50
49
  "@sanity/ui": "^3.2.0",
51
- "@sanity/uuid": "^3.0.2",
52
- "iso-639-1": "^3.1.2",
50
+ "@sanity/uuid": "^3.0.3",
51
+ "iso-639-1": "^3.1.5",
53
52
  "jsonwebtoken-esm": "^1.0.5",
54
53
  "lodash": "^4.17.21",
55
54
  "react-rx": "^4.2.2",
56
55
  "rxjs": "^7.8.2",
57
56
  "scroll-into-view-if-needed": "^3.1.0",
58
57
  "suspend-react": "^0.1.3",
59
- "swr": "^2.2.5",
60
- "type-fest": "^4.18.2",
58
+ "swr": "^2.4.1",
59
+ "type-fest": "^4.41.0",
61
60
  "use-device-pixel-ratio": "^1.1.2",
62
61
  "use-error-boundary": "^2.0.6"
63
62
  },
@@ -66,15 +65,18 @@
66
65
  "@sanity/pkg-utils": "^10.5.7",
67
66
  "@types/lodash": "^4.17.24",
68
67
  "@types/node": "^24.13.2",
69
- "@types/react": "^19.0.10",
70
- "@types/react-is": "^19.0.0",
71
- "react": "^19.0.0",
72
- "react-dom": "^19.0.0",
73
- "react-is": "^19.0.0",
68
+ "@types/react": "^19.2.17",
69
+ "@types/react-is": "^19.2.0",
70
+ "babel-plugin-styled-components": "^2.3.0",
71
+ "react": "^19.2.7",
72
+ "react-dom": "^19.2.7",
73
+ "react-is": "^19.2.7",
74
74
  "sanity": "^6.1.0",
75
- "styled-components": "^6.1.15",
75
+ "styled-components": "^6.4.2",
76
76
  "typescript": "5.9.3",
77
- "@sanity/plugin-kit": "5.0.1"
77
+ "@repo/package.config": "0.0.0",
78
+ "@repo/tsconfig": "0.0.0",
79
+ "@sanity/plugin-kit": "5.0.2"
78
80
  },
79
81
  "peerDependencies": {
80
82
  "react": "^18.3 || ^19",
@@ -85,13 +87,11 @@
85
87
  "engines": {
86
88
  "node": ">=20.19 <22 || >=22.12"
87
89
  },
88
- "publishConfig": {
89
- "access": "public"
90
- },
91
90
  "sanityExchangeUrl": "https://www.sanity.io/plugins/sanity-plugin-mux-input",
92
- "browserslist": "extends @sanity/browserslist-config",
93
91
  "sanityPlugin": {
94
92
  "verifyPackage": {
93
+ "tsc": false,
94
+ "tsconfig": false,
95
95
  "srcIndex": false,
96
96
  "scripts": false,
97
97
  "eslintImports": false
@@ -54,7 +54,7 @@ export const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig)
54
54
  }
55
55
  const config: PluginConfig = {
56
56
  ...defaultConfig,
57
- ...(userConfig || {}),
57
+ ...userConfig,
58
58
  ...convertLegacyConfig(userConfig || {}),
59
59
  }
60
60
  return {
@@ -26,14 +26,14 @@ export async function deleteAsset({
26
26
 
27
27
  try {
28
28
  await client.delete(asset._id)
29
- } catch (error) {
29
+ } catch {
30
30
  return 'failed-sanity'
31
31
  }
32
32
 
33
33
  if (deleteOnMux && asset?.assetId) {
34
34
  try {
35
35
  await deleteAssetOnMux(client, asset.assetId)
36
- } catch (error) {
36
+ } catch {
37
37
  return 'failed-mux'
38
38
  }
39
39
  }
@@ -53,7 +53,7 @@ export function getAsset(client: SanityClient, assetId: string) {
53
53
 
54
54
  export function listAssets(
55
55
  client: SanityClient,
56
- options: {limit?: number; cursor?: string | null}
56
+ options: {limit?: number; cursor?: string | null},
57
57
  ) {
58
58
  const {dataset} = client.config()
59
59
  const query: {limit?: string; cursor?: string} = {}
@@ -84,7 +84,7 @@ export function addTextTrackFromUrl(
84
84
  language_code: string
85
85
  name: string
86
86
  text_type?: 'subtitles'
87
- }
87
+ },
88
88
  ) {
89
89
  const {dataset} = client.config()
90
90
 
@@ -116,7 +116,7 @@ export function generateSubtitles(
116
116
  options: {
117
117
  language_code: string
118
118
  name: string
119
- }
119
+ },
120
120
  ) {
121
121
  const {dataset} = client.config()
122
122
  return client.request<{data: MuxAsset}>({
@@ -13,7 +13,6 @@ interface SecretsDocument {
13
13
  signingKeyPrivate: string
14
14
  drmConfigId: string
15
15
  }
16
- // eslint-disable-next-line max-params
17
16
  export function saveSecrets(
18
17
  client: SanityClient,
19
18
  token: string,
@@ -21,7 +20,7 @@ export function saveSecrets(
21
20
  enableSignedUrls: boolean,
22
21
  signingKeyId: string,
23
22
  signingKeyPrivate: string,
24
- drmConfigId: string
23
+ drmConfigId: string,
25
24
  ): Promise<SecretsDocument> {
26
25
  const doc: SecretsDocument = {
27
26
  _id: 'secrets.mux',
@@ -57,7 +56,7 @@ export async function createSigningKeys(client: SanityClient) {
57
56
  error.response?.statusCode === 401
58
57
  ? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has "System" permissions'
59
58
  : error.message
60
- throw new Error(message)
59
+ throw new Error(message, {cause: error})
61
60
  }
62
61
  }
63
62
 
@@ -74,7 +73,7 @@ export function testSecrets(client: SanityClient) {
74
73
  export async function haveValidSigningKeys(
75
74
  client: SanityClient,
76
75
  signingKeyId: string,
77
- signingKeyPrivate: string
76
+ signingKeyPrivate: string,
78
77
  ) {
79
78
  if (!(signingKeyId && signingKeyPrivate)) {
80
79
  return false
@@ -93,7 +92,7 @@ export async function haveValidSigningKeys(
93
92
  //
94
93
  return !!(res.data && res.data.id)
95
94
  } catch (e) {
96
- console.error('Error fetching signingKeyId', signingKeyId, 'assuming it is not valid')
95
+ console.error('Error fetching signingKeyId', signingKeyId, 'assuming it is not valid', e)
97
96
  return false
98
97
  }
99
98
  }
@@ -106,6 +105,6 @@ export function testSecretsObservable(client: SanityClient) {
106
105
  withCredentials: true,
107
106
  method: 'GET',
108
107
  query: PLUGIN_VERSION_QUERY,
109
- })
108
+ }),
110
109
  )
111
110
  }
@@ -18,13 +18,13 @@ function sanitizeOverlaySettingsInPlace(settings: MuxNewAssetSettings) {
18
18
  const overlay = (input as {overlay_settings?: Record<string, unknown>}).overlay_settings
19
19
  if (!overlay) continue
20
20
 
21
- const hm = roundPxString(overlay.horizontal_margin)
22
- const vm = roundPxString(overlay.vertical_margin)
23
- const w = roundPxString(overlay.width)
21
+ const hm = roundPxString(overlay['horizontal_margin'])
22
+ const vm = roundPxString(overlay['vertical_margin'])
23
+ const w = roundPxString(overlay['width'])
24
24
 
25
- if (hm) overlay.horizontal_margin = hm
26
- if (vm) overlay.vertical_margin = vm
27
- if (w) overlay.width = w
25
+ if (hm) overlay['horizontal_margin'] = hm
26
+ if (vm) overlay['vertical_margin'] = vm
27
+ if (w) overlay['width'] = w
28
28
  }
29
29
  }
30
30
 
@@ -38,7 +38,7 @@ function sanitizePxStringsInJson(json: string): string {
38
38
  })
39
39
  }
40
40
 
41
- export function cancelUpload(client: SanityClient, uuid: string) {
41
+ function cancelUpload(client: SanityClient, uuid: string) {
42
42
  return client.observable.request({
43
43
  url: `/addons/mux/uploads/${client.config().dataset}/${uuid}`,
44
44
  withCredentials: true,
@@ -51,7 +51,6 @@ export function uploadUrl({
51
51
  url,
52
52
  settings,
53
53
  client,
54
- watermark,
55
54
  }: {
56
55
  url: string
57
56
  settings: MuxNewAssetSettings
@@ -70,12 +69,15 @@ export function uploadUrl({
70
69
  const uuid = generateUuid()
71
70
  const muxBody = settings
72
71
  if (!muxBody.input) muxBody.input = [{type: 'video'}]
73
- muxBody.input[0].url = validUrl
72
+ muxBody.input[0]!.url = validUrl
74
73
  sanitizeOverlaySettingsInPlace(muxBody)
75
74
 
76
- const query = {
75
+ const query: Record<string, string> = {
77
76
  muxBody: sanitizePxStringsInJson(JSON.stringify(muxBody)),
78
- filename: validUrl.split('/').slice(-1)[0],
77
+ }
78
+ const filename = validUrl.split('/').slice(-1)[0]
79
+ if (filename) {
80
+ query['filename'] = filename
79
81
  }
80
82
 
81
83
  const dataset = client.config().dataset
@@ -89,7 +91,7 @@ export function uploadUrl({
89
91
  'Content-Type': 'application/json',
90
92
  },
91
93
  query: {...query, ...PLUGIN_VERSION_QUERY},
92
- })
94
+ }),
93
95
  ).pipe(
94
96
  mergeMap((result) => {
95
97
  const asset =
@@ -100,12 +102,12 @@ export function uploadUrl({
100
102
  return throwError(new Error('No asset document returned'))
101
103
  }
102
104
  return of({type: 'success' as const, id: uuid, asset})
103
- })
105
+ }),
104
106
  )
105
- })
106
- )
107
+ }),
108
+ ),
107
109
  )
108
- })
110
+ }),
109
111
  )
110
112
  }
111
113
 
@@ -156,35 +158,31 @@ export function uploadFile({
156
158
  },
157
159
  body,
158
160
  query: PLUGIN_VERSION_QUERY,
159
- })
161
+ }),
160
162
  ).pipe(
161
163
  mergeMap((result) => {
162
164
  return createUpChunkObservable(uuid, result.upload.url, file).pipe(
163
- // eslint-disable-next-line no-warning-comments
164
165
  // @TODO type the observable events
165
- // eslint-disable-next-line max-nested-callbacks
166
166
  mergeMap((event) => {
167
167
  if (event.type !== 'success') {
168
168
  return of(event)
169
169
  }
170
170
  return from(updateAssetDocumentFromUpload(client, uuid, watermark)).pipe(
171
- // eslint-disable-next-line max-nested-callbacks
172
- mergeMap((doc) => of({...event, asset: doc}))
171
+ mergeMap((doc) => of({...event, asset: doc})),
173
172
  )
174
173
  }),
175
- // eslint-disable-next-line max-nested-callbacks
176
174
  catchError((err) => {
177
175
  // Delete asset document
178
176
  return cancelUpload(client, uuid).pipe(mergeMapTo(throwError(err)))
179
- })
177
+ }),
180
178
  )
181
- })
182
- )
179
+ }),
180
+ ),
183
181
  )
184
- })
185
- )
182
+ }),
183
+ ),
186
184
  )
187
- })
185
+ }),
188
186
  )
189
187
  }
190
188
 
@@ -202,7 +200,7 @@ type UploadResponse = {
202
200
  timeout: number
203
201
  }
204
202
  }
205
- export function getUpload(client: SanityClient, assetId: string) {
203
+ function getUpload(client: SanityClient, assetId: string) {
206
204
  const {dataset} = client.config()
207
205
  return client.request<UploadResponse>({
208
206
  url: `/addons/mux/uploads/${dataset}/${assetId}`,
@@ -243,7 +241,7 @@ function pollUpload(client: SanityClient, uuid: string): Promise<UploadResponse>
243
241
  async function updateAssetDocumentFromUpload(
244
242
  client: SanityClient,
245
243
  uuid: string,
246
- _watermark?: WatermarkConfig
244
+ _watermark?: WatermarkConfig,
247
245
  ) {
248
246
  let upload: UploadResponse
249
247
  let asset: {data: MuxAsset}
@@ -264,7 +262,7 @@ async function updateAssetDocumentFromUpload(
264
262
  status: asset.data.status,
265
263
  data: asset.data,
266
264
  assetId: asset.data.id,
267
- playbackId: asset.data.playback_ids[0].id,
265
+ playbackId: asset.data.playback_ids[0]?.id,
268
266
  uploadId: upload.data.id,
269
267
  }
270
268
  return client.createOrReplace(doc).then(() => {
@@ -272,7 +270,7 @@ async function updateAssetDocumentFromUpload(
272
270
  })
273
271
  }
274
272
 
275
- export function testFile(file: File) {
273
+ function testFile(file: File) {
276
274
  if (typeof window !== 'undefined' && file instanceof window.File) {
277
275
  const fileOptions = optionsFromFile({}, file)
278
276
  return of(fileOptions)
@@ -280,7 +278,7 @@ export function testFile(file: File) {
280
278
  return throwError(new Error('Invalid file'))
281
279
  }
282
280
 
283
- export function testUrl(url: string): Observable<string> {
281
+ function testUrl(url: string): Observable<string> {
284
282
  const error = new Error('Invalid URL')
285
283
  if (typeof url !== 'string') {
286
284
  return throwError(error)
@@ -290,7 +288,7 @@ export function testUrl(url: string): Observable<string> {
290
288
  let parsed
291
289
  try {
292
290
  parsed = new URL(formattedUrl)
293
- } catch (err) {
291
+ } catch {
294
292
  return throwError(error)
295
293
  }
296
294
  if (parsed && !parsed.protocol.match(/http:|https:/)) {
@@ -47,7 +47,7 @@ export default function AddCaptionDialog({asset, onAdd, onClose}: Props) {
47
47
  const [vttUrl, setVttUrl] = useState('')
48
48
  const [languageCode, setLanguageCode] = useState('')
49
49
  const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(
50
- null
50
+ null,
51
51
  )
52
52
  const [name, setName] = useState('')
53
53
  const [isSubmitting, setIsSubmitting] = useState(false)
@@ -326,7 +326,7 @@ export default function AddCaptionDialog({asset, onAdd, onClose}: Props) {
326
326
  style={{display: 'none'}}
327
327
  onChange={(e) => {
328
328
  if (e.target.files && e.target.files.length > 0 && !isSubmitting) {
329
- setSelectedFile(e.target.files[0])
329
+ setSelectedFile(e.target.files[0]!)
330
330
  setVttUrl('')
331
331
  }
332
332
  }}
@@ -376,7 +376,7 @@ export default function AddCaptionDialog({asset, onAdd, onClose}: Props) {
376
376
  openButton
377
377
  renderValue={(value) =>
378
378
  (isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS).find(
379
- (l) => l.value === value
379
+ (l) => l.value === value,
380
380
  )?.label || value
381
381
  }
382
382
  renderOption={(option) => (
@@ -46,12 +46,12 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
46
46
  secrets.secretKey !== state.secretKey ||
47
47
  secrets.enableSignedUrls !== state.enableSignedUrls ||
48
48
  secrets.drmConfigId !== state.drmConfigId,
49
- [secrets, state]
49
+ [secrets, state],
50
50
  )
51
51
  const id = `ConfigureApi${useId()}`
52
52
  const [tokenId, secretKeyId, enableSignedUrlsId, drmConfigIdId] = useMemo<typeof fieldNames>(
53
53
  () => fieldNames.map((field) => `${id}-${field}`) as unknown as typeof fieldNames,
54
- [id]
54
+ [id],
55
55
  )
56
56
  const firstField = useRef<HTMLInputElement>(null)
57
57
  const handleSaveSecrets = useSaveSecrets(client, secrets)
@@ -78,7 +78,7 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
78
78
  })
79
79
  }
80
80
  },
81
- [client, dispatch, handleSaveSecrets, setDialogState, state]
81
+ [client, dispatch, handleSaveSecrets, setDialogState, state],
82
82
  )
83
83
  const handleChangeToken = useCallback(
84
84
  (event: React.FormEvent<HTMLInputElement>) => {
@@ -87,7 +87,7 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
87
87
  payload: {name: 'token', value: event.currentTarget.value},
88
88
  })
89
89
  },
90
- [dispatch]
90
+ [dispatch],
91
91
  )
92
92
  const handleChangeSecretKey = useCallback(
93
93
  (event: React.FormEvent<HTMLInputElement>) => {
@@ -96,7 +96,7 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
96
96
  payload: {name: 'secretKey', value: event.currentTarget.value},
97
97
  })
98
98
  },
99
- [dispatch]
99
+ [dispatch],
100
100
  )
101
101
  const handleChangeEnableSignedUrls = useCallback(
102
102
  (event: React.FormEvent<HTMLInputElement>) => {
@@ -105,7 +105,7 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
105
105
  payload: {name: 'enableSignedUrls', value: event.currentTarget.checked},
106
106
  })
107
107
  },
108
- [dispatch]
108
+ [dispatch],
109
109
  )
110
110
  const handleChangeDrmConfigId = useCallback(
111
111
  (event: React.FormEvent<HTMLInputElement>) => {
@@ -114,7 +114,7 @@ export function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialog
114
114
  payload: {name: 'drmConfigId', value: event.currentTarget.value},
115
115
  })
116
116
  },
117
- [dispatch]
117
+ [dispatch],
118
118
  )
119
119
 
120
120
  useEffect(() => {
@@ -208,7 +208,7 @@ export default function DraggableWatermark({
208
208
  onChange(newWatermark)
209
209
  }, 300)
210
210
  },
211
- [onChange]
211
+ [onChange],
212
212
  )
213
213
 
214
214
  useEffect(() => {
@@ -221,6 +221,7 @@ export default function DraggableWatermark({
221
221
 
222
222
  useEffect(() => {
223
223
  if (!isDragging && watermark.position) {
224
+ // oxlint-disable-next-line react/react-compiler
224
225
  setLocalPosition(watermark.position)
225
226
  }
226
227
  }, [watermark.position, isDragging])
@@ -232,7 +233,7 @@ export default function DraggableWatermark({
232
233
  setDragStart({x: e.clientX, y: e.clientY})
233
234
  setStartPosition({x: position.x, y: position.y})
234
235
  },
235
- [position]
236
+ [position],
236
237
  )
237
238
 
238
239
  const handleMouseMove = useCallback(
@@ -271,7 +272,7 @@ export default function DraggableWatermark({
271
272
  watermark,
272
273
  debouncedOnChange,
273
274
  getVideoContentBox,
274
- ]
275
+ ],
275
276
  )
276
277
 
277
278
  const handleMouseUp = useCallback(() => {
@@ -306,6 +307,7 @@ export default function DraggableWatermark({
306
307
  const opacityForRender = hasManualOverlay
307
308
  ? (parseOpacityPercent(watermark.overlay_settings?.opacity) ?? opacity)
308
309
  : opacity
310
+ // oxlint-disable-next-line react/react-compiler
309
311
  const contentBox = getVideoContentBox()
310
312
  const hasContentBox = contentBox.width > 0 && contentBox.height > 0
311
313
 
@@ -336,6 +338,7 @@ export default function DraggableWatermark({
336
338
  ref={watermarkRef}
337
339
  $opacity={opacityForRender}
338
340
  onMouseDown={hasManualOverlay ? undefined : handleMouseDown}
341
+ // oxlint-disable-next-line react/react-compiler
339
342
  style={computeWatermarkStyle()}
340
343
  >
341
344
  <img src={watermark.imageUrl} alt="Watermark" draggable={false} />
@@ -364,14 +367,14 @@ export function WatermarkControls({
364
367
  const [isValid, setIsValid] = useState<boolean | null>(null)
365
368
  const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null)
366
369
  const [mode, setMode] = useState<'canvas' | 'manual'>(
367
- watermark.overlay_settings ? 'manual' : 'canvas'
370
+ watermark.overlay_settings ? 'manual' : 'canvas',
368
371
  )
369
372
 
370
373
  const isUpdatingRef = useRef(false)
371
374
 
372
- const isValidExtension = (extension: string) => {
375
+ const isValidExtension = useCallback((extension: string) => {
373
376
  return extension.endsWith('.png') || extension.endsWith('.jpg') || extension.endsWith('.jpeg')
374
- }
377
+ }, [])
375
378
 
376
379
  const validateUrl = useCallback(
377
380
  (url: string) => {
@@ -461,7 +464,7 @@ export function WatermarkControls({
461
464
  }
462
465
  }, 500)
463
466
  },
464
- [watermark, onChange, onValidationChange]
467
+ [watermark, onChange, onValidationChange, isValidExtension],
465
468
  )
466
469
 
467
470
  useEffect(() => {
@@ -473,6 +476,7 @@ export function WatermarkControls({
473
476
  }, [])
474
477
 
475
478
  useEffect(() => {
479
+ // oxlint-disable-next-line react/react-compiler
476
480
  setMode(watermark.overlay_settings ? 'manual' : 'canvas')
477
481
  }, [watermark.overlay_settings])
478
482
 
@@ -802,6 +806,7 @@ export function WatermarkControls({
802
806
  <>
803
807
  <Box>
804
808
  <Text size={1} weight="medium">
809
+ {/* oxlint-disable-next-line react/react-compiler */}
805
810
  {(() => {
806
811
  const sizePct = watermark.size || 20
807
812
  const contentW = getVideoContentBox().width
@@ -812,17 +817,20 @@ export function WatermarkControls({
812
817
  </Text>
813
818
  <RangeInput
814
819
  type="range"
820
+ // oxlint-disable-next-line react/react-compiler
815
821
  value={(() => {
816
822
  const sizePct = watermark.size || 20
817
823
  const contentW = getVideoContentBox().width
818
824
  if (!contentW) return sizePct
819
825
  return Math.max(1, Math.round((sizePct / 100) * contentW))
820
826
  })()}
827
+ // oxlint-disable-next-line react/react-compiler
821
828
  min={(() => {
822
829
  const contentW = getVideoContentBox().width
823
830
  if (!contentW) return 5
824
831
  return Math.max(1, Math.round(contentW * 0.05))
825
832
  })()}
833
+ // oxlint-disable-next-line react/react-compiler
826
834
  max={(() => {
827
835
  const contentW = getVideoContentBox().width
828
836
  if (!contentW) return 50
@@ -52,7 +52,7 @@ export default function EditCaptionDialog({asset, track, onUpdate, onClose}: Pro
52
52
  () => {
53
53
  const baseCode = track.language_code?.split('-')[0]
54
54
  const found = LANGUAGE_OPTIONS.find(
55
- (opt) => opt.value === track.language_code || opt.value === baseCode
55
+ (opt) => opt.value === track.language_code || opt.value === baseCode,
56
56
  )
57
57
  if (found) return found
58
58
  if (track.name) {
@@ -60,7 +60,7 @@ export default function EditCaptionDialog({asset, track, onUpdate, onClose}: Pro
60
60
  if (foundByName) return foundByName
61
61
  }
62
62
  return null
63
- }
63
+ },
64
64
  )
65
65
  const [name, setName] = useState(track.name || '')
66
66
  const [isSubmitting, setIsSubmitting] = useState(false)
@@ -69,12 +69,13 @@ export default function EditCaptionDialog({asset, track, onUpdate, onClose}: Pro
69
69
  const fileInputRef = useRef<HTMLInputElement>(null)
70
70
 
71
71
  useEffect(() => {
72
+ // oxlint-disable-next-line react/react-compiler
72
73
  setLanguageCode(track.language_code || '')
73
74
  setName(track.name || '')
74
75
  setVttUrl('')
75
76
  const baseCode = track.language_code?.split('-')[0]
76
77
  const foundByCode = LANGUAGE_OPTIONS.find(
77
- (opt) => opt.value === track.language_code || opt.value === baseCode
78
+ (opt) => opt.value === track.language_code || opt.value === baseCode,
78
79
  )
79
80
  const foundByName = track.name ? LANGUAGE_OPTIONS.find((opt) => opt.label === track.name) : null
80
81
  setSelectedLanguage(foundByCode || foundByName || null)
@@ -94,7 +95,7 @@ export default function EditCaptionDialog({asset, track, onUpdate, onClose}: Pro
94
95
  title = 'Cannot download'
95
96
  }
96
97
  } else if (error === 'Track ID is missing' || error === 'Track is not ready yet') {
97
- errorMessage = String(error)
98
+ errorMessage = error
98
99
  title = 'Cannot download'
99
100
  }
100
101
 
@@ -398,7 +399,7 @@ export default function EditCaptionDialog({asset, track, onUpdate, onClose}: Pro
398
399
  style={{display: 'none'}}
399
400
  onChange={(e) => {
400
401
  if (e.target.files && e.target.files.length > 0 && !isSubmitting) {
401
- setSelectedFile(e.target.files[0])
402
+ setSelectedFile(e.target.files[0]!)
402
403
  setVttUrl('')
403
404
  }
404
405
  }}