From 0ac7d03778b6467790e9f3eca7f63a47a36fd78d Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Mon, 13 Jan 2025 15:17:39 -0500 Subject: [PATCH 01/13] audio recording basics --- .../form/PlaygroundFileUploadForm.tsx | 216 +++++++++--------- .../form/PlaygroundMicrophoneForm.tsx | 103 +++++++++ .../form/PlaygroundTypeReferenceForm.tsx | 15 +- .../src/playground/hooks/useAudioRecorder.ts | 110 +++++++++ 4 files changed, 338 insertions(+), 106 deletions(-) create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx create mode 100644 packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index cee8b972ea..942d5cfe4d 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -1,17 +1,17 @@ import { FernButton, FernButtonGroup, FernCard } from "@fern-docs/components"; +import { + Microphone, + MicrophoneSpeaking, + Page, + PagePlusIn, + Undo, + Xmark, +} from "iconoir-react"; +import { motion, AnimatePresence } from "framer-motion"; import cn from "clsx"; -import { uniqBy } from "es-toolkit/array"; -import { Page, PagePlusIn, Xmark } from "iconoir-react"; import numeral from "numeral"; -import { - ChangeEvent, - DragEventHandler, - memo, - useEffect, - useRef, - useState, -} from "react"; -import { WithLabelInternal } from "../WithLabel"; +import { ChangeEvent, DragEventHandler, memo, useRef, useState } from "react"; +import { useAudioRecorder } from "../hooks/useAudioRecorder"; export interface PlaygroundFileUploadFormProps { id: string; @@ -20,95 +20,61 @@ export interface PlaygroundFileUploadFormProps { isOptional?: boolean; onValueChange: (value: readonly File[] | undefined) => void; value: readonly File[] | undefined; + allowAudioRecording?: boolean; } export const PlaygroundFileUploadForm = memo( - ({ id, propertyKey, type, isOptional, onValueChange, value }) => { - // Remove invalid files - // TODO: This is a temporary workaround to remove invalid files from the value. - // this should be handled in a better way - useEffect(() => { - if (value != null) { - const hasInvalidFiles = value.some((f) => !(f instanceof File)); - if (hasInvalidFiles) { - onValueChange(value.filter((f) => f instanceof File)); - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - + ({ + id, + propertyKey, + type, + isOptional, + onValueChange, + value, + allowAudioRecording = true, + }) => { const [drag, setDrag] = useState(false); - const dragOver: DragEventHandler = (e) => { + const ref = useRef(null); + const [ + { isRecording, elapsedTime, volume }, + { startRecording, stopRecording }, + ] = useAudioRecorder(({ file }) => onValueChange([file])); + + const dragOver: DragEventHandler = (e) => { e.preventDefault(); - setDrag(true); }; - const dragEnter: DragEventHandler = (e) => { + const dragEnter: DragEventHandler = (e) => { e.preventDefault(); setDrag(true); }; - const dragLeave: DragEventHandler = (e) => { + const dragLeave: DragEventHandler = (e) => { e.preventDefault(); setDrag(false); }; - const handleChangeFiles = (files: FileList | null | undefined) => { - const filesArray = files != null ? Array.from(files) : []; - if (type === "files") { - // append files - onValueChange(uniqueFiles([...(value ?? []), ...filesArray])); - return; - } else { - // replace files - onValueChange(filesArray.length > 0 ? filesArray : undefined); - } - }; - - const fileDrop: DragEventHandler = (e) => { + const fileDrop: DragEventHandler = (e) => { e.preventDefault(); setDrag(false); - - const files = e.dataTransfer.files; - handleChangeFiles(files); + const files = Array.from(e.dataTransfer.files); + onValueChange(files); }; - const handleRemove = () => { - onValueChange(undefined); + const handleFileChange = (e: ChangeEvent) => { + const files = Array.from(e.target.files ?? []); + onValueChange(files); }; - const handleChange = (e: ChangeEvent) => { - const files = e.target.files; - if (files != null) { - handleChangeFiles(files); - } - - // NOTE: the input is not controlled, so we need to clear it manually... - // every time the user selects a file, we record the change in-state, and then clear the input - // so that the input can be used again to select the same file - if (ref.current != null) { - ref.current.value = ""; - } - }; - - const ref = useRef(null); return ( - + <> ( onDragLeave={dragLeave} onDrop={fileDrop} > - {value == null || value.length === 0 || value[0]?.name == null ? ( -
-
Drop files here to upload
+ {isRecording ? ( +
+ +
+
+
+ +
+ + {Math.floor(elapsedTime / 60) + .toString() + .padStart(2, "0")} + :{(elapsedTime % 60).toString().padStart(2, "0")} + +
+
ref.current?.click()} - text="Browse files" - rounded - variant="outlined" - intent="primary" + variant="minimal" + intent="danger" + onClick={stopRecording} + text="Stop" />
+ ) : value == null || value.length === 0 ? ( +
+
Drop audio files here to upload
+
+ ref.current?.click()} + text="Browse files" + rounded + variant="outlined" + intent="primary" + /> + {allowAudioRecording && ( + } + rounded + variant="outlined" + intent="primary" + /> + )} +
+
) : (
{value.map((file) => ( @@ -145,12 +145,17 @@ export const PlaygroundFileUploadForm = memo(
- - {type === "file" && ( + ref.current?.click()} + size="small" + variant="minimal" + /> + {allowAudioRecording && ( ref.current?.click()} + icon={} + onClick={startRecording} size="small" variant="minimal" /> @@ -160,7 +165,7 @@ export const PlaygroundFileUploadForm = memo( size="small" variant="minimal" onClick={() => { - onValueChange(value.filter((f) => f !== file)); + onValueChange([]); if (ref.current != null) { ref.current.value = ""; } @@ -169,28 +174,31 @@ export const PlaygroundFileUploadForm = memo(
))} - {type === "files" && ( -
- ref.current?.click()} - icon={} - text="Add more files" - rounded - variant="outlined" - intent="primary" - /> -
- )} )}
-
+ ); } ); -PlaygroundFileUploadForm.displayName = "PlaygroundFileUploadForm"; - -function uniqueFiles(files: File[]): readonly File[] | undefined { - return uniqBy(files, (f) => `${f.webkitRelativePath}/${f.name}/${f.size}`); +function WaveformAnimation({ volume }: { volume: number }) { + return ( +
+ {Array.from({ length: 20 }).map((_, i) => ( + + ))} +
+ ); } diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx new file mode 100644 index 0000000000..705356994b --- /dev/null +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -0,0 +1,103 @@ +import { FernButton, FernInput, FernInputProps } from "@fern-docs/components"; +import { Microphone, MicrophoneSpeaking, Undo } from "iconoir-react"; +import { ReactElement } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { useAudioRecorder } from "../hooks/useAudioRecorder"; + +export interface PlaygroundMicrophoneFormProps extends FernInputProps { + onAudioData?: (base64Data: string) => void; +} + +export function PlaygroundMicrophoneForm({ + onAudioData, + ...props +}: PlaygroundMicrophoneFormProps): ReactElement { + const [ + { isRecording, elapsedTime, volume }, + { startRecording, stopRecording }, + ] = useAudioRecorder(({ base64 }) => onAudioData?.(base64)); + + return ( +
+
+
+ + {!isRecording && ( + + + + )} + + + {isRecording && ( + +
+
+
+ +
+ + {Math.floor(elapsedTime / 60) + .toString() + .padStart(2, "0")} + :{(elapsedTime % 60).toString().padStart(2, "0")} + +
+
+
+ )} +
+
+ 0 ? ( + + ) : isRecording ? ( + + ) : ( + + ) + } + intent={isRecording ? "danger" : "primary"} + onClick={isRecording ? stopRecording : startRecording} + disabled={props.disabled} + /> +
+
+ ); +} + +function WaveformAnimation({ volume }: { volume: number }) { + return ( +
+ {Array.from({ length: 20 }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 89ed9fad43..3ec43091db 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -22,6 +22,7 @@ import { PlaygroundListForm } from "./PlaygroundListForm"; import { PlaygroundMapForm } from "./PlaygroundMapForm"; import { PlaygroundObjectForm } from "./PlaygroundObjectForm"; import { PlaygroundUniscriminatedUnionForm } from "./PlaygroundUniscriminatedUnionForm"; +import { PlaygroundMicrophoneForm } from "./PlaygroundMicrophoneForm"; interface PlaygroundTypeReferenceFormProps { id: string; @@ -145,7 +146,6 @@ export const PlaygroundTypeReferenceForm = htmlFor={id} > {hasVoiceIdPlaygroundForm && property?.key === "voice_id" ? ( - // TODO: delete this: + ) : property?.key === "data" || + property?.key === "user_audio_chunk" ? ( + // TODO: change display logic to use either edge config or api property for mic support + ) : ( )} diff --git a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts new file mode 100644 index 0000000000..f89f80dc3e --- /dev/null +++ b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts @@ -0,0 +1,110 @@ +import { useCallback, useEffect, useRef, useState } from "react"; + +interface AudioRecorderState { + isRecording: boolean; + elapsedTime: number; + volume: number; +} + +interface AudioRecorderControls { + startRecording: () => Promise; + stopRecording: () => void; +} + +export function useAudioRecorder( + onAudioData?: (audioData: { base64: string; file: File }) => void +): [AudioRecorderState, AudioRecorderControls] { + const [isRecording, setIsRecording] = useState(false); + const [elapsedTime, setElapsedTime] = useState(0); + const [volume, setVolume] = useState(0.2); + const [mediaRecorder, setMediaRecorder] = useState( + null + ); + const analyserRef = useRef(null); + const animationFrameRef = useRef(); + + const startRecording = useCallback(async () => { + try { + setElapsedTime(0); + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + const recorder = new MediaRecorder(stream); + + const audioContext = new AudioContext(); + const source = audioContext.createMediaStreamSource(stream); + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 256; + source.connect(analyser); + analyserRef.current = analyser; + + const updateVolume = () => { + const dataArray = new Uint8Array(analyser.frequencyBinCount); + analyser.getByteFrequencyData(dataArray); + const average = + dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length; + const normalizedVolume = Math.min(average / 20, 1); + setVolume(normalizedVolume); + animationFrameRef.current = requestAnimationFrame(updateVolume); + }; + + updateVolume(); + + recorder.ondataavailable = (event) => { + if (event.data.size > 0) { + const reader = new FileReader(); + reader.onloadend = () => { + const base64Data = (reader.result as string).split(",")[1] ?? ""; + const file = new File( + [event.data], + `recording-${Date.now()}.webm`, + { + type: event.data.type, + } + ); + onAudioData?.({ base64: base64Data, file }); + }; + reader.readAsDataURL(event.data); + } + }; + + recorder.start(100); + setMediaRecorder(recorder); + setIsRecording(true); + } catch (err) { + console.error("Error accessing microphone:", err); + } + }, [onAudioData]); + + const stopRecording = useCallback(() => { + if (mediaRecorder) { + mediaRecorder.stop(); + mediaRecorder.stream.getTracks().forEach((track) => track.stop()); + setMediaRecorder(null); + setIsRecording(false); + if (animationFrameRef.current) { + cancelAnimationFrame(animationFrameRef.current); + } + analyserRef.current = null; + setVolume(0.2); + } + }, [mediaRecorder]); + + useEffect(() => { + let interval: NodeJS.Timeout; + if (isRecording) { + interval = setInterval(() => { + setElapsedTime((prev) => prev + 1); + }, 1000); + } + return () => { + clearInterval(interval); + if (mediaRecorder) { + stopRecording(); + } + }; + }, [isRecording, mediaRecorder, stopRecording]); + + return [ + { isRecording, elapsedTime, volume }, + { startRecording, stopRecording }, + ]; +} From 03f1fe14f46847172233bf879959b5c47c0d11a6 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Mon, 13 Jan 2025 15:29:00 -0500 Subject: [PATCH 02/13] minor ui fixes --- .../form/PlaygroundFileUploadForm.tsx | 17 +++++++++++------ .../form/PlaygroundMicrophoneForm.tsx | 9 +++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 942d5cfe4d..e764382a18 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -87,9 +87,8 @@ export const PlaygroundFileUploadForm = memo( > {isRecording ? (
- -
-
+
+
@@ -102,10 +101,16 @@ export const PlaygroundFileUploadForm = memo(
+ ) : ( + + ) + } variant="minimal" - intent="danger" - onClick={stopRecording} - text="Stop" + intent={isRecording ? "danger" : "primary"} + onClick={isRecording ? stopRecording : startRecording} />
) : value == null || value.length === 0 ? ( diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx index 705356994b..6ff48cb79f 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -19,14 +19,14 @@ export function PlaygroundMicrophoneForm({ return (
-
+
{!isRecording && (
-
+
@@ -72,6 +72,7 @@ export function PlaygroundMicrophoneForm({ ) } + variant="minimal" intent={isRecording ? "danger" : "primary"} onClick={isRecording ? stopRecording : startRecording} disabled={props.disabled} From ec5c7dd6cbcd2280d74b5178610069798c10f017 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Mon, 13 Jan 2025 15:35:43 -0500 Subject: [PATCH 03/13] refactor --- .../form/PlaygroundFileUploadForm.tsx | 24 +------------------ .../form/PlaygroundMicrophoneForm.tsx | 22 +---------------- .../form/PlaygroundWaveformAnimation.tsx | 22 +++++++++++++++++ 3 files changed, 24 insertions(+), 44 deletions(-) create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index e764382a18..162a0039a2 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -3,15 +3,14 @@ import { Microphone, MicrophoneSpeaking, Page, - PagePlusIn, Undo, Xmark, } from "iconoir-react"; -import { motion, AnimatePresence } from "framer-motion"; import cn from "clsx"; import numeral from "numeral"; import { ChangeEvent, DragEventHandler, memo, useRef, useState } from "react"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; +import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; export interface PlaygroundFileUploadFormProps { id: string; @@ -186,24 +185,3 @@ export const PlaygroundFileUploadForm = memo( ); } ); - -function WaveformAnimation({ volume }: { volume: number }) { - return ( -
- {Array.from({ length: 20 }).map((_, i) => ( - - ))} -
- ); -} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx index 6ff48cb79f..a72d6284b2 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -3,6 +3,7 @@ import { Microphone, MicrophoneSpeaking, Undo } from "iconoir-react"; import { ReactElement } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; +import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; export interface PlaygroundMicrophoneFormProps extends FernInputProps { onAudioData?: (base64Data: string) => void; @@ -81,24 +82,3 @@ export function PlaygroundMicrophoneForm({
); } - -function WaveformAnimation({ volume }: { volume: number }) { - return ( -
- {Array.from({ length: 20 }).map((_, i) => ( - - ))} -
- ); -} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx new file mode 100644 index 0000000000..2fec876f25 --- /dev/null +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx @@ -0,0 +1,22 @@ +import { motion } from "framer-motion"; + +export function WaveformAnimation({ volume }: { volume: number }) { + return ( +
+ {Array.from({ length: 20 }).map((_, i) => ( + + ))} +
+ ); +} From 45cc045d53622df8046bfb3a81e6cec30a07a36f Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Mon, 13 Jan 2025 18:29:59 -0500 Subject: [PATCH 04/13] fix logic --- .../form/PlaygroundFileUploadForm.tsx | 2 +- .../src/playground/hooks/useAudioRecorder.ts | 48 +++++++++++-------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 162a0039a2..d06c4a2098 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -158,7 +158,7 @@ export const PlaygroundFileUploadForm = memo( /> {allowAudioRecording && ( } + icon={} onClick={startRecording} size="small" variant="minimal" diff --git a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts index f89f80dc3e..ac121847bb 100644 --- a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts +++ b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts @@ -22,20 +22,25 @@ export function useAudioRecorder( ); const analyserRef = useRef(null); const animationFrameRef = useRef(); + const chunksRef = useRef([]); const startRecording = useCallback(async () => { try { setElapsedTime(0); + chunksRef.current = []; + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); - const recorder = new MediaRecorder(stream); + const recorder = new MediaRecorder(stream, { + mimeType: "audio/webm;codecs=opus", + }); + // for animation only: const audioContext = new AudioContext(); const source = audioContext.createMediaStreamSource(stream); const analyser = audioContext.createAnalyser(); analyser.fftSize = 256; source.connect(analyser); analyserRef.current = analyser; - const updateVolume = () => { const dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); @@ -45,28 +50,32 @@ export function useAudioRecorder( setVolume(normalizedVolume); animationFrameRef.current = requestAnimationFrame(updateVolume); }; - updateVolume(); recorder.ondataavailable = (event) => { - if (event.data.size > 0) { - const reader = new FileReader(); - reader.onloadend = () => { - const base64Data = (reader.result as string).split(",")[1] ?? ""; - const file = new File( - [event.data], - `recording-${Date.now()}.webm`, - { - type: event.data.type, - } - ); - onAudioData?.({ base64: base64Data, file }); - }; - reader.readAsDataURL(event.data); - } + chunksRef.current.push(event.data); + }; + + recorder.onstop = async () => { + const file = new File( + chunksRef.current, + `recording-${Date.now()}.webm`, + { type: "audio/webm;codecs=opus" } + ); + + const toBase64 = (file: File) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + }); + const base64 = await toBase64(file); + + onAudioData?.({ base64: base64 as string, file }); }; - recorder.start(100); + recorder.start(); setMediaRecorder(recorder); setIsRecording(true); } catch (err) { @@ -85,6 +94,7 @@ export function useAudioRecorder( } analyserRef.current = null; setVolume(0.2); + chunksRef.current = []; } }, [mediaRecorder]); From c5fe7f6b6f7c90b0fef4ddc77185d41f77d65a34 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 11:09:09 -0500 Subject: [PATCH 05/13] audio controls + backend mime type --- fern/apis/fdr/definition/api/v1/read/type.yml | 2 + .../fdr/definition/api/v1/register/type.yml | 2 + .../read/resources/type/types/Base64Type.ts | 1 + .../read/resources/type/types/StringType.ts | 1 + .../resources/type/types/Base64Type.ts | 1 + .../resources/type/types/StringType.ts | 1 + packages/fern-docs/bundle/.gitignore | 1 + packages/fern-docs/ui/package.json | 1 + .../form/PlaygroundAudioControls.tsx | 95 ++++ .../form/PlaygroundFileUploadForm.tsx | 20 +- .../form/PlaygroundMicrophoneForm.tsx | 7 +- .../form/PlaygroundTypeReferenceForm.tsx | 2 +- .../src/playground/hooks/useAudioRecorder.ts | 30 +- .../read/resources/type/types/Base64Type.ts | 1 + .../read/resources/type/types/StringType.ts | 1 + .../resources/type/types/Base64Type.ts | 1 + .../resources/type/types/StringType.ts | 1 + pnpm-lock.yaml | 438 +++++++++++------- .../read/resources/type/types/Base64Type.d.ts | 1 + .../read/resources/type/types/StringType.d.ts | 1 + .../resources/type/types/Base64Type.d.ts | 1 + .../resources/type/types/StringType.d.ts | 1 + 22 files changed, 420 insertions(+), 190 deletions(-) create mode 100644 packages/fern-docs/bundle/.gitignore create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx diff --git a/fern/apis/fdr/definition/api/v1/read/type.yml b/fern/apis/fdr/definition/api/v1/read/type.yml index d72b0c543d..3e028dfec5 100644 --- a/fern/apis/fdr/definition/api/v1/read/type.yml +++ b/fern/apis/fdr/definition/api/v1/read/type.yml @@ -89,6 +89,7 @@ types: minLength: optional maxLength: optional default: optional + mimeType: optional LongType: properties: @@ -111,6 +112,7 @@ types: Base64Type: properties: default: optional + mimeType: optional DateType: properties: diff --git a/fern/apis/fdr/definition/api/v1/register/type.yml b/fern/apis/fdr/definition/api/v1/register/type.yml index f228c49f2b..5576c5b033 100644 --- a/fern/apis/fdr/definition/api/v1/register/type.yml +++ b/fern/apis/fdr/definition/api/v1/register/type.yml @@ -89,6 +89,7 @@ types: minLength: optional maxLength: optional default: optional + mimeType: optional LongType: properties: @@ -111,6 +112,7 @@ types: Base64Type: properties: default: optional + mimeType: optional DateType: properties: diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts index fbca354844..a1b07e77a6 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts @@ -8,4 +8,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts index fbca354844..a1b07e77a6 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts @@ -8,4 +8,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fern-docs/bundle/.gitignore b/packages/fern-docs/bundle/.gitignore new file mode 100644 index 0000000000..e985853ed8 --- /dev/null +++ b/packages/fern-docs/bundle/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/packages/fern-docs/ui/package.json b/packages/fern-docs/ui/package.json index 862df55b40..4cd01f4820 100644 --- a/packages/fern-docs/ui/package.json +++ b/packages/fern-docs/ui/package.json @@ -122,6 +122,7 @@ "unist-util-visit": "^5.0.0", "url-join": "5.0.0", "use-memo-one": "^1.1.3", + "webm-duration-fix": "^1.0.4", "zod": "^3.23.8" }, "devDependencies": { diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx new file mode 100644 index 0000000000..598a8df232 --- /dev/null +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -0,0 +1,95 @@ +import { FernButton, FernButtonGroup } from "@fern-docs/components"; +import { Download, Play, Pause } from "iconoir-react"; +import { useEffect, useRef, useState } from "react"; + +interface PlaygroundAudioControlsProps { + audioUrl: string | null; + fileName?: string; +} + +export function PlaygroundAudioControls({ + audioUrl, + fileName = "recording.webm", +}: PlaygroundAudioControlsProps) { + const [isPlaying, setIsPlaying] = useState(false); + const [currentTime, setCurrentTime] = useState(0); + const [duration, setDuration] = useState(0); + const [isLoaded, setIsLoaded] = useState(false); + const audioRef = useRef(null); + + useEffect(() => { + if (audioRef.current) { + audioRef.current.onended = () => setIsPlaying(false); + audioRef.current.onloadedmetadata = () => { + const audioDuration = audioRef.current?.duration; + if (audioDuration && !isNaN(audioDuration) && isFinite(audioDuration)) { + setDuration(Math.round(audioDuration)); + setIsLoaded(true); + } + }; + audioRef.current.ontimeupdate = () => { + const currentTime = audioRef.current?.currentTime; + if (currentTime && !isNaN(currentTime) && isFinite(currentTime)) { + setCurrentTime(Math.round(currentTime)); + } + }; + } + }, []); + + const formatTime = (seconds: number) => { + const mins = Math.floor(seconds / 60) + .toString() + .padStart(2, "0"); + const secs = (seconds % 60).toString().padStart(2, "0"); + return `${mins}:${secs}`; + }; + + const handlePlayPause = () => { + if (!audioRef.current || !audioUrl) return; + + if (isPlaying) { + audioRef.current.pause(); + } else { + audioRef.current.play(); + } + setIsPlaying(!isPlaying); + }; + + const handleDownload = () => { + if (!audioUrl) return; + const a = document.createElement("a"); + a.href = audioUrl; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + + if (!audioUrl) return null; + + return ( +
+
+ ); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index d06c4a2098..059c15cb17 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -11,6 +11,7 @@ import numeral from "numeral"; import { ChangeEvent, DragEventHandler, memo, useRef, useState } from "react"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; +import { PlaygroundAudioControls } from "./PlaygroundAudioControls"; export interface PlaygroundFileUploadFormProps { id: string; @@ -35,7 +36,7 @@ export const PlaygroundFileUploadForm = memo( const [drag, setDrag] = useState(false); const ref = useRef(null); const [ - { isRecording, elapsedTime, volume }, + { isRecording, elapsedTime, volume, audioUrl }, { startRecording, stopRecording }, ] = useAudioRecorder(({ file }) => onValueChange([file])); @@ -150,12 +151,17 @@ export const PlaygroundFileUploadForm = memo(
- ref.current?.click()} - size="small" - variant="minimal" - /> + {audioUrl && ( + + )} + {!audioUrl && ( + ref.current?.click()} + size="small" + variant="minimal" + /> + )} {allowAudioRecording && ( } diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx index a72d6284b2..81df3a23c0 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -4,6 +4,7 @@ import { ReactElement } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; +import { PlaygroundAudioControls } from "./PlaygroundAudioControls"; export interface PlaygroundMicrophoneFormProps extends FernInputProps { onAudioData?: (base64Data: string) => void; @@ -14,13 +15,16 @@ export function PlaygroundMicrophoneForm({ ...props }: PlaygroundMicrophoneFormProps): ReactElement { const [ - { isRecording, elapsedTime, volume }, + { isRecording, elapsedTime, volume, audioUrl }, { startRecording, stopRecording }, ] = useAudioRecorder(({ base64 }) => onAudioData?.(base64)); return (
+ {audioUrl && !isRecording && ( + + )}
{!isRecording && ( @@ -73,6 +77,7 @@ export function PlaygroundMicrophoneForm({ ) } + size="small" variant="minimal" intent={isRecording ? "danger" : "primary"} onClick={isRecording ? stopRecording : startRecording} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 3ec43091db..27ecd15da2 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -13,7 +13,7 @@ import { FernTextarea, } from "@fern-docs/components"; import { ReactElement, memo, useCallback } from "react"; -import { useEdgeFlags } from "../../atoms"; +import { useDomain, useEdgeFlags } from "../../atoms"; import { WithLabel } from "../WithLabel"; import { PlaygroundDiscriminatedUnionForm } from "./PlaygroundDescriminatedUnionForm"; import { PlaygroundElevenLabsVoiceIdForm } from "./PlaygroundElevenLabsVoiceIdForm"; diff --git a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts index ac121847bb..fb9734cdf7 100644 --- a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts +++ b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts @@ -1,9 +1,11 @@ import { useCallback, useEffect, useRef, useState } from "react"; +import fixWebmDuration from "webm-duration-fix"; interface AudioRecorderState { isRecording: boolean; elapsedTime: number; volume: number; + audioUrl: string | null; } interface AudioRecorderControls { @@ -23,6 +25,8 @@ export function useAudioRecorder( const analyserRef = useRef(null); const animationFrameRef = useRef(); const chunksRef = useRef([]); + const [audioUrl, setAudioUrl] = useState(null); + const mimeType = "audio/webm;codecs=opus"; const startRecording = useCallback(async () => { try { @@ -31,7 +35,7 @@ export function useAudioRecorder( const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const recorder = new MediaRecorder(stream, { - mimeType: "audio/webm;codecs=opus", + mimeType, }); // for animation only: @@ -57,11 +61,17 @@ export function useAudioRecorder( }; recorder.onstop = async () => { - const file = new File( - chunksRef.current, - `recording-${Date.now()}.webm`, - { type: "audio/webm;codecs=opus" } + const fixedBlob = await fixWebmDuration( + new Blob([...chunksRef.current], { + type: mimeType, + }) ); + const file = new File([fixedBlob], `recording-${Date.now()}.webm`, { + type: mimeType, + }); + + const url = URL.createObjectURL(file); + setAudioUrl(url); const toBase64 = (file: File) => new Promise((resolve, reject) => { @@ -113,8 +123,16 @@ export function useAudioRecorder( }; }, [isRecording, mediaRecorder, stopRecording]); + useEffect(() => { + return () => { + if (audioUrl) { + URL.revokeObjectURL(audioUrl); + } + }; + }, [audioUrl]); + return [ - { isRecording, elapsedTime, volume }, + { isRecording, elapsedTime, volume, audioUrl }, { startRecording, stopRecording }, ]; } diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts index fbca354844..a1b07e77a6 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.ts @@ -8,4 +8,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts index fbca354844..a1b07e77a6 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.ts @@ -8,4 +8,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bdef822178..dfd53ecdc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,10 +68,10 @@ importers: version: 1.47.1 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/express': specifier: ^4.17.13 version: 4.17.21 @@ -131,7 +131,7 @@ importers: version: 5.1.0(eslint@9.17.0(jiti@1.21.7)) eslint-plugin-tailwindcss: specifier: ^3.17.5 - version: 3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) eslint-plugin-vitest: specifier: ^0.5.4 version: 0.5.4(@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)(vitest@2.1.4(@edge-runtime/vm@5.0.0)(@types/node@18.19.33)(jsdom@24.0.0)(less@4.2.0)(sass@1.77.0)(stylus@0.62.0)(terser@5.31.0)) @@ -197,16 +197,16 @@ importers: version: 13.1.0(postcss@8.4.31)(stylelint@16.5.0(typescript@5.7.2)) stylelint-config-tailwindcss: specifier: ^0.0.7 - version: 0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) stylelint-scss: specifier: ^6.0.0 version: 6.3.0(stylelint@16.5.0(typescript@5.7.2)) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) tsx: specifier: ^4.19.2 version: 4.19.2 @@ -221,7 +221,7 @@ importers: version: 8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) typescript-plugin-css-modules: specifier: ^5.1.0 - version: 5.1.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2) + version: 5.1.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2) vitest: specifier: ^2.1.4 version: 2.1.4(@edge-runtime/vm@5.0.0)(@types/node@18.19.33)(jsdom@24.0.0)(less@4.2.0)(sass@1.77.0)(stylus@0.62.0)(terser@5.31.0) @@ -273,7 +273,7 @@ importers: version: 3.0.3 tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) + version: 8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -859,10 +859,10 @@ importers: version: 14.2.9 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/node': specifier: ^18.7.18 version: 18.19.33 @@ -895,7 +895,7 @@ importers: version: 3.4.2 raw-loader: specifier: ^4.0.2 - version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) sass: specifier: ^1.74.1 version: 1.77.0 @@ -904,7 +904,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1086,10 +1086,10 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.5.0 @@ -1149,7 +1149,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1370,10 +1370,10 @@ importers: version: 14.2.9 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/node': specifier: ^18.7.18 version: 18.19.33 @@ -1412,7 +1412,7 @@ importers: version: 3.4.2 raw-loader: specifier: ^4.0.2 - version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7)) + version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) sass: specifier: ^1.74.1 version: 1.77.0 @@ -1421,7 +1421,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1833,7 +1833,7 @@ importers: version: 8.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2)) '@storybook/nextjs': specifier: ^8.4.4 - version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)) + version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) '@storybook/react': specifier: ^8.4.4 version: 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) @@ -1842,7 +1842,7 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))) '@types/hast': specifier: ^3.0.4 version: 3.0.4 @@ -1884,10 +1884,10 @@ importers: version: 2.2.5(react@18.3.1) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2223,6 +2223,9 @@ importers: use-memo-one: specifier: ^1.1.3 version: 1.1.3(react@18.3.1) + webm-duration-fix: + specifier: ^1.0.4 + version: 1.0.4 zod: specifier: ^3.23.8 version: 3.23.8 @@ -2259,7 +2262,7 @@ importers: version: 8.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2)) '@storybook/nextjs': specifier: ^8.4.4 - version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) '@storybook/react': specifier: ^8.4.4 version: 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) @@ -2268,10 +2271,10 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.5.0 @@ -2352,7 +2355,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) ts-essentials: specifier: ^10.0.1 version: 10.0.1(typescript@5.7.2) @@ -2453,7 +2456,7 @@ importers: version: 3.4.2 tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) + version: 8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2582,7 +2585,7 @@ importers: version: 9.17.0(jiti@1.21.7) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2867,7 +2870,7 @@ importers: version: 2.1.2 ts-node: specifier: ^10.9.1 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2985,7 +2988,7 @@ importers: version: 1.52.1(esbuild@0.20.2) ts-node: specifier: ^10.4.0 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) tsconfig-paths: specifier: ^3.9.0 version: 3.15.0 @@ -10194,6 +10197,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ebml-block@1.1.2: + resolution: {integrity: sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg==} + ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -11652,6 +11658,9 @@ packages: peerDependencies: algoliasearch: '>= 3.1 < 6' + int64-buffer@1.1.0: + resolution: {integrity: sha512-94smTCQOvigN4d/2R/YDjz8YVG0Sufvv2aAh8P5m42gwhCsDAJqnbNOrxJsrADuAFAA69Q/ptGzxvNcNuIJcvw==} + internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -16568,6 +16577,9 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webm-duration-fix@1.0.4: + resolution: {integrity: sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==} + webpack-bundle-analyzer@4.10.1: resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==} engines: {node: '>= 10.13.0'} @@ -20354,7 +20366,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -20368,7 +20380,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21126,7 +21138,7 @@ snapshots: dependencies: playwright: 1.47.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: ansi-html-community: 0.0.8 core-js-pure: 3.37.0 @@ -21136,12 +21148,12 @@ snapshots: react-refresh: 0.14.2 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: type-fest: 4.21.0 webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: ansi-html-community: 0.0.8 core-js-pure: 3.37.0 @@ -21151,7 +21163,7 @@ snapshots: react-refresh: 0.14.2 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: type-fest: 4.21.0 webpack-hot-middleware: 2.26.1 @@ -23018,7 +23030,7 @@ snapshots: transitivePeerDependencies: - webpack-sources - '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7)(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 @@ -23027,23 +23039,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.3.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) es-module-lexer: 1.5.2 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) magic-string: 0.30.12 path-browserify: 1.0.1 process: 0.11.10 semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) ts-dedent: 2.2.0 url: 0.11.3 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) - webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) + webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -23055,7 +23067,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 @@ -23064,23 +23076,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.3.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) es-module-lexer: 1.5.2 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) - html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) magic-string: 0.30.12 path-browserify: 1.0.1 process: 0.11.10 semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)) - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) ts-dedent: 2.2.0 url: 0.11.3 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.94.0(@swc/core@1.5.7) - webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) + webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -23176,7 +23188,7 @@ snapshots: dependencies: storybook: 8.4.4(prettier@3.4.2) - '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) @@ -23191,31 +23203,31 @@ snapshots: '@babel/preset-react': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7)(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/test': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 - babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) find-up: 5.0.0 image-size: 1.1.1 loader-utils: 3.2.1 next: '@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)' - node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) pnp-webpack-plugin: 1.7.0(typescript@5.7.2) postcss: 8.4.31 - postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@18.3.1) ts-dedent: 2.2.0 tsconfig-paths: 4.2.0 @@ -23223,7 +23235,7 @@ snapshots: optionalDependencies: sharp: 0.33.3 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -23243,7 +23255,7 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7))': + '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) @@ -23258,31 +23270,31 @@ snapshots: '@babel/preset-react': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)) - '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/test': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 - babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)) - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)) + babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) find-up: 5.0.0 image-size: 1.1.1 loader-utils: 3.2.1 next: '@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)' - node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) pnp-webpack-plugin: 1.7.0(typescript@5.7.2) postcss: 8.4.31 - postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) + postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)) + sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@18.3.1) ts-dedent: 2.2.0 tsconfig-paths: 4.2.0 @@ -23290,7 +23302,7 @@ snapshots: optionalDependencies: sharp: 0.33.3 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -23310,11 +23322,11 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -23326,7 +23338,7 @@ snapshots: semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) tsconfig-paths: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -23337,11 +23349,11 @@ snapshots: - uglify-js - webpack-cli - '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) '@types/node': 22.5.5 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -23353,7 +23365,7 @@ snapshots: semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) tsconfig-paths: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -23385,7 +23397,7 @@ snapshots: dependencies: storybook: 8.4.4(prettier@3.4.2) - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: debug: 4.3.7 endent: 2.1.0 @@ -23395,11 +23407,11 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.2) tslib: 2.8.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: debug: 4.3.7 endent: 2.1.0 @@ -23409,7 +23421,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.2) tslib: 2.8.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - supports-color @@ -23509,7 +23521,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.5.7': optional: true - '@swc/core@1.5.7': + '@swc/core@1.5.7(@swc/helpers@0.5.15)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.7 @@ -23524,6 +23536,7 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.5.7 '@swc/core-win32-ia32-msvc': 1.5.7 '@swc/core-win32-x64-msvc': 1.5.7 + '@swc/helpers': 0.5.15 optional: true '@swc/counter@0.1.3': {} @@ -23546,18 +23559,26 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/forms@0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)))': + '@tailwindcss/forms@0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)))': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) + + '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)))': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) - '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)))': + '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) '@tanem/svg-injector@10.1.68': dependencies: @@ -25872,19 +25893,19 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)): + babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) babel-plugin-istanbul@6.1.1: dependencies: @@ -26649,13 +26670,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + create-jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -26702,7 +26723,7 @@ snapshots: css-functions-list@3.2.2: {} - css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: icss-utils: 5.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -26713,9 +26734,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7)): + css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: icss-utils: 5.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -26726,7 +26747,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) css-select@4.3.0: dependencies: @@ -27363,6 +27384,8 @@ snapshots: eastasianwidth@0.2.0: {} + ebml-block@1.1.2: {} + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -27748,7 +27771,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -27780,7 +27803,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.0 is-glob: 4.0.3 @@ -27854,11 +27877,11 @@ snapshots: - supports-color - typescript - eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))): dependencies: fast-glob: 3.3.2 postcss: 8.4.31 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) eslint-plugin-turbo@2.3.3(eslint@9.17.0(jiti@1.21.7)): dependencies: @@ -28385,7 +28408,7 @@ snapshots: cross-spawn: 7.0.5 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -28400,9 +28423,9 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -28417,7 +28440,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) form-data@2.5.1: dependencies: @@ -29116,7 +29139,7 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -29124,9 +29147,9 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7)): + html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -29134,7 +29157,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) htmlparser2@6.1.0: dependencies: @@ -29341,6 +29364,8 @@ snapshots: qs: 6.9.7 search-insights: 2.17.2 + int64-buffer@1.1.0: {} + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -29759,16 +29784,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-cli@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + create-jest: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -29778,7 +29803,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-config@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -29804,12 +29829,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 18.19.33 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-config@29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -29835,7 +29860,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.12.12 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -30050,7 +30075,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.12.12 + '@types/node': 18.19.33 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -30061,12 +30086,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-cli: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -31641,7 +31666,7 @@ snapshots: node-int64@0.4.0: {} - node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -31668,9 +31693,9 @@ snapshots: url: 0.11.3 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -31697,7 +31722,7 @@ snapshots: url: 0.11.3 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) node-releases@2.0.18: {} @@ -32231,21 +32256,29 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.31 - postcss-load-config@3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + postcss-load-config@3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: postcss: 8.4.31 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) + + postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): + dependencies: + lilconfig: 3.1.3 + yaml: 2.4.2 + optionalDependencies: + postcss: 8.4.31 + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) - postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)): dependencies: lilconfig: 3.1.3 yaml: 2.4.2 optionalDependencies: postcss: 8.4.31 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2) postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(yaml@2.4.2): dependencies: @@ -32256,25 +32289,25 @@ snapshots: tsx: 4.19.2 yaml: 2.4.2 - postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: cosmiconfig: 9.0.0(typescript@5.7.2) jiti: 1.21.0 postcss: 8.4.31 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - typescript - postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)): + postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: cosmiconfig: 9.0.0(typescript@5.7.2) jiti: 1.21.0 postcss: 8.4.31 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - typescript @@ -32665,17 +32698,17 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7)): + raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) rc@1.2.8: dependencies: @@ -33462,17 +33495,17 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: neo-async: 2.6.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: sass: 1.77.0 - sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)): + sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: neo-async: 2.6.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: sass: 1.77.0 @@ -34102,13 +34135,13 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 4.1.0 - style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7)): + style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) style-to-js@1.1.3: dependencies: @@ -34179,10 +34212,10 @@ snapshots: stylelint: 16.5.0(typescript@5.7.2) stylelint-config-recommended: 14.0.0(stylelint@16.5.0(typescript@5.7.2)) - stylelint-config-tailwindcss@0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + stylelint-config-tailwindcss@0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))): dependencies: stylelint: 16.5.0(typescript@5.7.2) - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) stylelint-scss@6.3.0(stylelint@16.5.0(typescript@5.7.2)): dependencies: @@ -34336,11 +34369,11 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 - tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))): dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) - tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -34359,7 +34392,34 @@ snapshots: postcss: 8.4.31 postcss-import: 15.1.0(postcss@8.4.31) postcss-js: 4.0.1(postcss@8.4.31) - postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) + postcss-nested: 6.2.0(postcss@8.4.31) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.4.31 + postcss-import: 15.1.0(postcss@8.4.31) + postcss-js: 4.0.1(postcss@8.4.31) + postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) postcss-nested: 6.2.0(postcss@8.4.31) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -34406,28 +34466,28 @@ snapshots: dependencies: memoizerific: 1.11.3 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) esbuild: 0.20.2 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) terser@5.31.0: dependencies: @@ -34639,7 +34699,7 @@ snapshots: '@ts-morph/common': 0.20.0 code-block-writer: 12.0.0 - ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2): + ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -34647,7 +34707,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 18.19.33 - acorn: 8.11.3 + acorn: 8.14.0 acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 @@ -34657,7 +34717,28 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) + + ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.5.5 + acorn: 8.14.0 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.5.7(@swc/helpers@0.5.15) + optional: true ts-pattern@5.0.5: {} @@ -34698,7 +34779,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2): + tsup@8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2): dependencies: bundle-require: 5.0.0(esbuild@0.20.2) cac: 6.7.14 @@ -34717,7 +34798,7 @@ snapshots: tinyglobby: 0.2.10 tree-kill: 1.2.2 optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) postcss: 8.4.31 typescript: 5.7.2 transitivePeerDependencies: @@ -34875,7 +34956,7 @@ snapshots: transitivePeerDependencies: - supports-color - typescript-plugin-css-modules@5.1.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2): + typescript-plugin-css-modules@5.1.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2): dependencies: '@types/postcss-modules-local-by-default': 4.0.2 '@types/postcss-modules-scope': 3.0.4 @@ -34884,7 +34965,7 @@ snapshots: less: 4.2.0 lodash.camelcase: 4.3.0 postcss: 8.4.31 - postcss-load-config: 3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + postcss-load-config: 3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) postcss-modules-extract-imports: 3.1.0(postcss@8.4.31) postcss-modules-local-by-default: 4.0.5(postcss@8.4.31) postcss-modules-scope: 3.2.0(postcss@8.4.31) @@ -35442,6 +35523,13 @@ snapshots: webidl-conversions@7.0.0: {} + webm-duration-fix@1.0.4: + dependencies: + buffer: 6.0.3 + ebml-block: 1.1.2 + events: 3.3.0 + int64-buffer: 1.1.0 + webpack-bundle-analyzer@4.10.1: dependencies: '@discoveryjs/json-ext': 0.5.7 @@ -35461,7 +35549,7 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -35469,9 +35557,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7)): + webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -35479,7 +35567,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) webpack-hot-middleware@2.26.1: dependencies: @@ -35491,7 +35579,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.94.0(@swc/core@1.5.7): + webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -35513,7 +35601,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -35521,7 +35609,7 @@ snapshots: - esbuild - uglify-js - webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2): + webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -35543,7 +35631,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts index ca0acdc1bb..12bf81d734 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts @@ -3,4 +3,5 @@ */ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.d.ts index d435d177a7..4d6a3c5b3f 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/StringType.d.ts @@ -7,4 +7,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts index ca0acdc1bb..12bf81d734 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts @@ -3,4 +3,5 @@ */ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.d.ts index d435d177a7..4d6a3c5b3f 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/StringType.d.ts @@ -7,4 +7,5 @@ export interface StringType { minLength: number | undefined; maxLength: number | undefined; default: string | undefined; + mimeType: string | undefined; } From fa1e217dc96136baa6bfb62745769fd9906f7070 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 11:44:14 -0500 Subject: [PATCH 06/13] cleanup + hook up backend mimetype --- .../ui/src/playground/form/PlaygroundAudioControls.tsx | 3 ++- .../ui/src/playground/form/PlaygroundMicrophoneForm.tsx | 2 +- .../src/playground/form/PlaygroundTypeReferenceForm.tsx | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx index 598a8df232..6a6a555aec 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -41,7 +41,7 @@ export function PlaygroundAudioControls({ .toString() .padStart(2, "0"); const secs = (seconds % 60).toString().padStart(2, "0"); - return `${mins}:${secs}`; + return mins === "00" ? `${secs}s` : `${mins}:${secs}`; }; const handlePlayPause = () => { @@ -88,6 +88,7 @@ export function PlaygroundAudioControls({ onClick={handleDownload} size="small" variant="minimal" + disabled={!isLoaded} />
diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx index 81df3a23c0..307a4eac15 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -21,7 +21,7 @@ export function PlaygroundMicrophoneForm({ return (
-
+
{audioUrl && !isRecording && ( )} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 27ecd15da2..310703da11 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -153,9 +153,11 @@ export const PlaygroundTypeReferenceForm = onValueChange={onChange} disabled={disabled} /> - ) : property?.key === "data" || - property?.key === "user_audio_chunk" ? ( - // TODO: change display logic to use either edge config or api property for mic support + ) : property?.key === "user_audio_chunk" || // user_audio_chunk hardcoded for ElevenLabs use case + (primitive.value.type === "string" && + primitive.value.mimeType?.startsWith("audio/")) || + (primitive.value.type === "base64" && + primitive.value.mimeType?.startsWith("audio/")) ? ( Date: Tue, 14 Jan 2025 12:04:52 -0500 Subject: [PATCH 07/13] lint fixes --- .../playground/form/PlaygroundAudioControls.tsx | 4 ++-- .../playground/form/PlaygroundFileUploadForm.tsx | 16 ++++++---------- .../form/PlaygroundTypeReferenceForm.tsx | 2 +- .../form/PlaygroundWaveformAnimation.tsx | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx index 6a6a555aec..5d838e3f22 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -44,13 +44,13 @@ export function PlaygroundAudioControls({ return mins === "00" ? `${secs}s` : `${mins}:${secs}`; }; - const handlePlayPause = () => { + const handlePlayPause = async () => { if (!audioRef.current || !audioUrl) return; if (isPlaying) { audioRef.current.pause(); } else { - audioRef.current.play(); + await audioRef.current.play(); } setIsPlaying(!isPlaying); }; diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 059c15cb17..7ff56731a5 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -1,11 +1,5 @@ import { FernButton, FernButtonGroup, FernCard } from "@fern-docs/components"; -import { - Microphone, - MicrophoneSpeaking, - Page, - Undo, - Xmark, -} from "iconoir-react"; +import { Microphone, MicrophoneSpeaking, Page, Xmark } from "iconoir-react"; import cn from "clsx"; import numeral from "numeral"; import { ChangeEvent, DragEventHandler, memo, useRef, useState } from "react"; @@ -25,10 +19,10 @@ export interface PlaygroundFileUploadFormProps { export const PlaygroundFileUploadForm = memo( ({ - id, - propertyKey, + // id, + // propertyKey, type, - isOptional, + // isOptional, onValueChange, value, allowAudioRecording = true, @@ -191,3 +185,5 @@ export const PlaygroundFileUploadForm = memo( ); } ); + +PlaygroundFileUploadForm.displayName = "PlaygroundFileUploadForm"; diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 310703da11..980480189a 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -13,7 +13,7 @@ import { FernTextarea, } from "@fern-docs/components"; import { ReactElement, memo, useCallback } from "react"; -import { useDomain, useEdgeFlags } from "../../atoms"; +import { useEdgeFlags } from "../../atoms"; import { WithLabel } from "../WithLabel"; import { PlaygroundDiscriminatedUnionForm } from "./PlaygroundDescriminatedUnionForm"; import { PlaygroundElevenLabsVoiceIdForm } from "./PlaygroundElevenLabsVoiceIdForm"; diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx index 2fec876f25..2439ff78f1 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx @@ -2,7 +2,7 @@ import { motion } from "framer-motion"; export function WaveformAnimation({ volume }: { volume: number }) { return ( -
+
{Array.from({ length: 20 }).map((_, i) => ( Date: Tue, 14 Jan 2025 12:13:32 -0500 Subject: [PATCH 08/13] add todo --- .../ui/src/playground/form/PlaygroundTypeReferenceForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 980480189a..188a8c682b 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -153,7 +153,7 @@ export const PlaygroundTypeReferenceForm = onValueChange={onChange} disabled={disabled} /> - ) : property?.key === "user_audio_chunk" || // user_audio_chunk hardcoded for ElevenLabs use case + ) : property?.key === "user_audio_chunk" || // TODO(naman): remove hardcoding for ElevenLabs once the backend mimeType is plumbed through (primitive.value.type === "string" && primitive.value.mimeType?.startsWith("audio/")) || (primitive.value.type === "base64" && From def53100858d49ec6f2f478e31a391dde739b61c Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 12:18:42 -0500 Subject: [PATCH 09/13] cleaner --- .../ui/src/playground/form/PlaygroundAudioControls.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx index 5d838e3f22..30a29ed852 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -81,14 +81,14 @@ export function PlaygroundAudioControls({ onClick={handlePlayPause} size="small" variant="minimal" - disabled={!isLoaded} + disabled={!audioUrl} /> } onClick={handleDownload} size="small" variant="minimal" - disabled={!isLoaded} + disabled={!audioUrl} />
From 5c317519a8f8f581bce73093aeb9675736ec8660 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 12:35:18 -0500 Subject: [PATCH 10/13] more cleanup --- .../form/PlaygroundFileUploadForm.tsx | 97 +++++++++++++++++-- .../form/PlaygroundTypeReferenceForm.tsx | 2 + 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 7ff56731a5..7ae979ef70 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -1,11 +1,26 @@ import { FernButton, FernButtonGroup, FernCard } from "@fern-docs/components"; -import { Microphone, MicrophoneSpeaking, Page, Xmark } from "iconoir-react"; +import { + Microphone, + MicrophoneSpeaking, + Page, + Xmark, + PagePlusIn, +} from "iconoir-react"; import cn from "clsx"; +import { uniqBy } from "es-toolkit/array"; import numeral from "numeral"; -import { ChangeEvent, DragEventHandler, memo, useRef, useState } from "react"; +import { + ChangeEvent, + DragEventHandler, + memo, + useEffect, + useRef, + useState, +} from "react"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; import { PlaygroundAudioControls } from "./PlaygroundAudioControls"; +import { WithLabelInternal } from "../WithLabel"; export interface PlaygroundFileUploadFormProps { id: string; @@ -19,14 +34,27 @@ export interface PlaygroundFileUploadFormProps { export const PlaygroundFileUploadForm = memo( ({ - // id, - // propertyKey, + id, + propertyKey, type, - // isOptional, + isOptional, onValueChange, value, allowAudioRecording = true, }) => { + // Remove invalid files + // TODO: This is a temporary workaround to remove invalid files from the value. + // this should be handled in a better way + useEffect(() => { + if (value != null) { + const hasInvalidFiles = value.some((f) => !(f instanceof File)); + if (hasInvalidFiles) { + onValueChange(value.filter((f) => f instanceof File)); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + const [drag, setDrag] = useState(false); const ref = useRef(null); const [ @@ -36,6 +64,7 @@ export const PlaygroundFileUploadForm = memo( const dragOver: DragEventHandler = (e) => { e.preventDefault(); + setDrag(true); }; const dragEnter: DragEventHandler = (e) => { @@ -55,15 +84,47 @@ export const PlaygroundFileUploadForm = memo( onValueChange(files); }; + const handleChangeFiles = (files: FileList | null | undefined) => { + const filesArray = files != null ? Array.from(files) : []; + if (type === "files") { + // append files + onValueChange(uniqueFiles([...(value ?? []), ...filesArray])); + return; + } else { + // replace files + onValueChange(filesArray.length > 0 ? filesArray : undefined); + } + }; + + const handleRemove = () => { + onValueChange(undefined); + }; + const handleFileChange = (e: ChangeEvent) => { - const files = Array.from(e.target.files ?? []); - onValueChange(files); + const files = e.target.files; + if (files != null) { + handleChangeFiles(files); + } + + // Clear input value to allow selecting same file again + if (ref.current != null) { + ref.current.value = ""; + } }; return ( - <> + ( size="small" variant="minimal" onClick={() => { - onValueChange([]); + onValueChange(value.filter((f) => f !== file)); if (ref.current != null) { ref.current.value = ""; } @@ -178,12 +239,28 @@ export const PlaygroundFileUploadForm = memo(
))} + {type === "files" && ( +
+ ref.current?.click()} + icon={} + text="Add more files" + rounded + variant="outlined" + intent="primary" + /> +
+ )}
)} - + ); } ); PlaygroundFileUploadForm.displayName = "PlaygroundFileUploadForm"; + +function uniqueFiles(files: File[]): readonly File[] | undefined { + return uniqBy(files, (f) => `${f.webkitRelativePath}/${f.name}/${f.size}`); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 188a8c682b..f59cbf3482 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -146,6 +146,7 @@ export const PlaygroundTypeReferenceForm = htmlFor={id} > {hasVoiceIdPlaygroundForm && property?.key === "voice_id" ? ( + // TODO: delete this: )} From a724ea850ebbdb995bb1336a47ef47c849049257 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 12:39:40 -0500 Subject: [PATCH 11/13] tiny copy edit --- .../ui/src/playground/form/PlaygroundFileUploadForm.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 7ae979ef70..7a9e6c8535 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -170,7 +170,9 @@ export const PlaygroundFileUploadForm = memo(
) : value == null || value.length === 0 ? (
-
Drop audio files here to upload
+
+ {`Drop audio file${type === "files" ? "s" : ""} here to upload`} +
ref.current?.click()} From f05574576ad6e583a459bbf733a63bf93798dd6c Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 15:27:30 -0500 Subject: [PATCH 12/13] buggy start to multiple mic recording support --- .../form/PlaygroundAudioControls.tsx | 69 ++++++++--- .../form/PlaygroundFileUploadForm.tsx | 112 ++++++++++++++---- .../form/PlaygroundMicrophoneForm.tsx | 22 +++- .../src/playground/hooks/useAudioRecorder.ts | 18 +-- 4 files changed, 160 insertions(+), 61 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx index 30a29ed852..d91879ba68 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -18,23 +18,49 @@ export function PlaygroundAudioControls({ const audioRef = useRef(null); useEffect(() => { - if (audioRef.current) { - audioRef.current.onended = () => setIsPlaying(false); - audioRef.current.onloadedmetadata = () => { - const audioDuration = audioRef.current?.duration; - if (audioDuration && !isNaN(audioDuration) && isFinite(audioDuration)) { - setDuration(Math.round(audioDuration)); - setIsLoaded(true); - } - }; - audioRef.current.ontimeupdate = () => { - const currentTime = audioRef.current?.currentTime; - if (currentTime && !isNaN(currentTime) && isFinite(currentTime)) { - setCurrentTime(Math.round(currentTime)); - } - }; - } - }, []); + setIsPlaying(false); + setCurrentTime(0); + setDuration(0); + setIsLoaded(false); + }, [audioUrl]); + + useEffect(() => { + if (!audioUrl) return; + + const audio = audioRef.current; + if (!audio) return; + + const handleEnded = () => { + setIsPlaying(false); + setCurrentTime(0); + }; + + const handleLoadedMetadata = () => { + const audioDuration = audio.duration; + if (!isNaN(audioDuration) && isFinite(audioDuration)) { + setDuration(Math.round(audioDuration)); + setIsLoaded(true); + } + }; + const handleTimeUpdate = () => { + const currentTime = audio.currentTime; + if (!isNaN(currentTime) && isFinite(currentTime)) { + setCurrentTime(Math.round(currentTime)); + } + }; + + audio.load(); + + audio.addEventListener("ended", handleEnded); + audio.addEventListener("loadedmetadata", handleLoadedMetadata); + audio.addEventListener("timeupdate", handleTimeUpdate); + + return () => { + audio.removeEventListener("ended", handleEnded); + audio.removeEventListener("loadedmetadata", handleLoadedMetadata); + audio.removeEventListener("timeupdate", handleTimeUpdate); + }; + }, [audioUrl]); const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60) @@ -49,10 +75,15 @@ export function PlaygroundAudioControls({ if (isPlaying) { audioRef.current.pause(); + setIsPlaying(false); } else { - await audioRef.current.play(); + try { + await audioRef.current.play(); + setIsPlaying(true); + } catch (error) { + console.error("Error playing audio:", error); + } } - setIsPlaying(!isPlaying); }; const handleDownload = () => { diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index 7a9e6c8535..0d10df0152 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -57,10 +57,47 @@ export const PlaygroundFileUploadForm = memo( const [drag, setDrag] = useState(false); const ref = useRef(null); + const [audioUrls, setAudioUrls] = useState>(new Map()); + const [fileToReplace, setFileToReplace] = useState(null); + + useEffect(() => { + return () => { + audioUrls.forEach((url) => URL.revokeObjectURL(url)); + }; + }, [audioUrls]); + const [ - { isRecording, elapsedTime, volume, audioUrl }, + { isRecording, elapsedTime, volume }, { startRecording, stopRecording }, - ] = useAudioRecorder(({ file }) => onValueChange([file])); + ] = useAudioRecorder(({ file, url }) => { + const newUrls = new Map(audioUrls); + + if (type === "files") { + if (fileToReplace) { + const oldUrl = audioUrls.get(fileToReplace.name); + if (oldUrl) { + URL.revokeObjectURL(oldUrl); + } + newUrls.delete(fileToReplace.name); + + newUrls.set(file.name, url); + setAudioUrls(newUrls); + + onValueChange( + value?.map((f) => (f === fileToReplace ? file : f)) ?? [file] + ); + setFileToReplace(null); + } else { + newUrls.set(file.name, url); + setAudioUrls(newUrls); + onValueChange([...(value ?? []), file]); + } + } else { + audioUrls.forEach((existingUrl) => URL.revokeObjectURL(existingUrl)); + setAudioUrls(new Map([[file.name, url]])); + onValueChange([file]); + } + }); const dragOver: DragEventHandler = (e) => { e.preventDefault(); @@ -96,27 +133,44 @@ export const PlaygroundFileUploadForm = memo( } }; - const handleRemove = () => { - onValueChange(undefined); + const handleRemoveFile = (fileToRemove: File) => { + const url = audioUrls.get(fileToRemove.name); + if (url) { + URL.revokeObjectURL(url); + const newUrls = new Map(audioUrls); + newUrls.delete(fileToRemove.name); + setAudioUrls(newUrls); + } + onValueChange(value?.filter((f) => f !== fileToRemove)); }; const handleFileChange = (e: ChangeEvent) => { const files = e.target.files; if (files != null) { + if (type === "file") { + audioUrls.forEach((url) => URL.revokeObjectURL(url)); + setAudioUrls(new Map()); + } handleChangeFiles(files); } - // Clear input value to allow selecting same file again if (ref.current != null) { ref.current.value = ""; } }; + const handleStartRecording = (fileToReplace?: File) => { + if (fileToReplace) { + setFileToReplace(fileToReplace); + } + startRecording(); + }; + return ( handleRemoveFile(value?.[0]!)} isRequired={!isOptional} typeShorthand={type === "file" ? "file" : "multiple files"} availability={undefined} @@ -183,8 +237,8 @@ export const PlaygroundFileUploadForm = memo( /> {allowAudioRecording && ( } + onClick={() => handleStartRecording()} rounded variant="outlined" intent="primary" @@ -208,10 +262,12 @@ export const PlaygroundFileUploadForm = memo(
- {audioUrl && ( - + {audioUrls.get(file.name) && ( + )} - {!audioUrl && ( + {!audioUrls.get(file.name) && ( ref.current?.click()} @@ -222,7 +278,7 @@ export const PlaygroundFileUploadForm = memo( {allowAudioRecording && ( } - onClick={startRecording} + onClick={() => handleStartRecording(file)} size="small" variant="minimal" /> @@ -231,26 +287,32 @@ export const PlaygroundFileUploadForm = memo( icon={} size="small" variant="minimal" - onClick={() => { - onValueChange(value.filter((f) => f !== file)); - if (ref.current != null) { - ref.current.value = ""; - } - }} + onClick={() => handleRemoveFile(file)} />
))} {type === "files" && (
- ref.current?.click()} - icon={} - text="Add more files" - rounded - variant="outlined" - intent="primary" - /> +
+ ref.current?.click()} + icon={} + text="Add more files" + rounded + variant="outlined" + intent="primary" + /> + {allowAudioRecording && ( + handleStartRecording()} + icon={} + rounded + variant="outlined" + intent="primary" + /> + )} +
)}
diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx index 307a4eac15..e53bbef739 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -1,6 +1,6 @@ import { FernButton, FernInput, FernInputProps } from "@fern-docs/components"; import { Microphone, MicrophoneSpeaking, Undo } from "iconoir-react"; -import { ReactElement } from "react"; +import { ReactElement, useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { useAudioRecorder } from "../hooks/useAudioRecorder"; import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; @@ -14,10 +14,26 @@ export function PlaygroundMicrophoneForm({ onAudioData, ...props }: PlaygroundMicrophoneFormProps): ReactElement { + const [audioUrl, setAudioUrl] = useState(null); + + useEffect(() => { + return () => { + if (audioUrl) { + URL.revokeObjectURL(audioUrl); + } + }; + }, [audioUrl]); + const [ - { isRecording, elapsedTime, volume, audioUrl }, + { isRecording, elapsedTime, volume }, { startRecording, stopRecording }, - ] = useAudioRecorder(({ base64 }) => onAudioData?.(base64)); + ] = useAudioRecorder(({ base64, url }) => { + if (audioUrl) { + URL.revokeObjectURL(audioUrl); + } + setAudioUrl(url); + onAudioData?.(base64); + }); return (
diff --git a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts index fb9734cdf7..1c8a02ae33 100644 --- a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts +++ b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts @@ -14,8 +14,8 @@ interface AudioRecorderControls { } export function useAudioRecorder( - onAudioData?: (audioData: { base64: string; file: File }) => void -): [AudioRecorderState, AudioRecorderControls] { + onAudioData?: (audioData: { base64: string; file: File; url: string }) => void +): [Omit, AudioRecorderControls] { const [isRecording, setIsRecording] = useState(false); const [elapsedTime, setElapsedTime] = useState(0); const [volume, setVolume] = useState(0.2); @@ -25,7 +25,6 @@ export function useAudioRecorder( const analyserRef = useRef(null); const animationFrameRef = useRef(); const chunksRef = useRef([]); - const [audioUrl, setAudioUrl] = useState(null); const mimeType = "audio/webm;codecs=opus"; const startRecording = useCallback(async () => { @@ -71,7 +70,6 @@ export function useAudioRecorder( }); const url = URL.createObjectURL(file); - setAudioUrl(url); const toBase64 = (file: File) => new Promise((resolve, reject) => { @@ -82,7 +80,7 @@ export function useAudioRecorder( }); const base64 = await toBase64(file); - onAudioData?.({ base64: base64 as string, file }); + onAudioData?.({ base64: base64 as string, file, url }); }; recorder.start(); @@ -123,16 +121,8 @@ export function useAudioRecorder( }; }, [isRecording, mediaRecorder, stopRecording]); - useEffect(() => { - return () => { - if (audioUrl) { - URL.revokeObjectURL(audioUrl); - } - }; - }, [audioUrl]); - return [ - { isRecording, elapsedTime, volume, audioUrl }, + { isRecording, elapsedTime, volume }, { startRecording, stopRecording }, ]; } From b6fafc8cb79c8a026a08103c296359d5ce9d741f Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 15:32:14 -0500 Subject: [PATCH 13/13] saving wip --- .../form/PlaygroundAudioControls.tsx | 69 +++++-------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx index d91879ba68..30a29ed852 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -18,49 +18,23 @@ export function PlaygroundAudioControls({ const audioRef = useRef(null); useEffect(() => { - setIsPlaying(false); - setCurrentTime(0); - setDuration(0); - setIsLoaded(false); - }, [audioUrl]); - - useEffect(() => { - if (!audioUrl) return; - - const audio = audioRef.current; - if (!audio) return; - - const handleEnded = () => { - setIsPlaying(false); - setCurrentTime(0); - }; - - const handleLoadedMetadata = () => { - const audioDuration = audio.duration; - if (!isNaN(audioDuration) && isFinite(audioDuration)) { - setDuration(Math.round(audioDuration)); - setIsLoaded(true); - } - }; - const handleTimeUpdate = () => { - const currentTime = audio.currentTime; - if (!isNaN(currentTime) && isFinite(currentTime)) { - setCurrentTime(Math.round(currentTime)); - } - }; - - audio.load(); - - audio.addEventListener("ended", handleEnded); - audio.addEventListener("loadedmetadata", handleLoadedMetadata); - audio.addEventListener("timeupdate", handleTimeUpdate); - - return () => { - audio.removeEventListener("ended", handleEnded); - audio.removeEventListener("loadedmetadata", handleLoadedMetadata); - audio.removeEventListener("timeupdate", handleTimeUpdate); - }; - }, [audioUrl]); + if (audioRef.current) { + audioRef.current.onended = () => setIsPlaying(false); + audioRef.current.onloadedmetadata = () => { + const audioDuration = audioRef.current?.duration; + if (audioDuration && !isNaN(audioDuration) && isFinite(audioDuration)) { + setDuration(Math.round(audioDuration)); + setIsLoaded(true); + } + }; + audioRef.current.ontimeupdate = () => { + const currentTime = audioRef.current?.currentTime; + if (currentTime && !isNaN(currentTime) && isFinite(currentTime)) { + setCurrentTime(Math.round(currentTime)); + } + }; + } + }, []); const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60) @@ -75,15 +49,10 @@ export function PlaygroundAudioControls({ if (isPlaying) { audioRef.current.pause(); - setIsPlaying(false); } else { - try { - await audioRef.current.play(); - setIsPlaying(true); - } catch (error) { - console.error("Error playing audio:", error); - } + await audioRef.current.play(); } + setIsPlaying(!isPlaying); }; const handleDownload = () => {