diff --git a/packages/convert/.eslintrc b/packages/convert/.eslintrc new file mode 100644 index 00000000000..2e5e81887f8 --- /dev/null +++ b/packages/convert/.eslintrc @@ -0,0 +1,8 @@ +{ + "extends": ["@jonny/eslint-config/react"], + "rules": { + "no-console": "error", + "react/function-component-definition": "off", + "react/require-default-props": "off", + }, +} diff --git a/packages/convert/.gitignore b/packages/convert/.gitignore new file mode 100644 index 00000000000..abaef0cfda2 --- /dev/null +++ b/packages/convert/.gitignore @@ -0,0 +1,5 @@ +node_modules + +/.cache +build +.env diff --git a/packages/convert/README.md b/packages/convert/README.md new file mode 100644 index 00000000000..799ca0846dd --- /dev/null +++ b/packages/convert/README.md @@ -0,0 +1,18 @@ +# @remotion/convert + +Video conversion tool - convert.remotion.dev + +[![NPM Downloads](https://img.shields.io/npm/dm/@remotion/convert.svg?style=flat&color=black&label=Downloads)](https://npmcharts.com/compare/@remotion/convert?minimal=true) + +## Installation + +```bash +npm install @remotion/convert --save-exact +``` + +When installing a Remotion package, make sure to align the version of all `remotion` and `@remotion/*` packages to the same version. +Remove the `^` character from the version number to use the exact version. + +## Usage + +See the [documentation](https://convert.remotion.dev) for more information. diff --git a/packages/convert/app/components/AudioTrackOverview.tsx b/packages/convert/app/components/AudioTrackOverview.tsx new file mode 100644 index 00000000000..d30dc1b3455 --- /dev/null +++ b/packages/convert/app/components/AudioTrackOverview.tsx @@ -0,0 +1,35 @@ +import type {AudioTrack} from '@remotion/media-parser'; +import {Table, TableBody, TableCell, TableRow} from './ui/table'; + +export const AudioTrackOverview: React.FC<{ + readonly track: AudioTrack; +}> = ({track}) => { + return ( + + + + Type + Audio + + + Codec + + {track.codecWithoutConfig} + + + + WebCodecs Codec String + {track.codec} + + + Channels + {track.numberOfChannels} + + + Sample Rate + {track.sampleRate} + + +
+ ); +}; diff --git a/packages/convert/app/components/ContainerOverview.tsx b/packages/convert/app/components/ContainerOverview.tsx new file mode 100644 index 00000000000..7856e9909c2 --- /dev/null +++ b/packages/convert/app/components/ContainerOverview.tsx @@ -0,0 +1,116 @@ +import {Table, TableBody, TableCell, TableRow} from '@/components/ui/table'; +import type { + Dimensions, + MediaParserAudioCodec, + MediaParserVideoCodec, + ParseMediaContainer, +} from '@remotion/media-parser'; +import React from 'react'; +import {formatBytes} from '~/lib/format-bytes'; +import {Skeleton} from './ui/skeleton'; + +const formatSeconds = (seconds: number) => { + const minutes = Math.floor(seconds / 60); + const secondsLeft = seconds % 60; + + return `${minutes}:${secondsLeft < 10 ? '0' : ''}${Math.round(secondsLeft)} min`; +}; + +export const ContainerOverview: React.FC<{ + readonly dimensions: Dimensions | null; + readonly durationInSeconds: number | null; + readonly videoCodec: MediaParserVideoCodec | null; + readonly audioCodec: MediaParserAudioCodec | null; + readonly size: number | null; + readonly fps: number | null | undefined; + readonly container: ParseMediaContainer | null; +}> = ({ + container, + dimensions, + videoCodec, + durationInSeconds, + audioCodec, + size, + fps, +}) => { + return ( + + + + Size + + {size === null ? ( + + ) : ( + <>{formatBytes(size)} + )} + + + + Container + + {container ? ( + <>{String(container)} + ) : ( + + )} + + + + Duration + + {durationInSeconds === null ? ( + + ) : ( + <>{formatSeconds(durationInSeconds)} + )} + + + + Dimensions + + {dimensions === null ? ( + + ) : ( + <> + {dimensions.width}x{dimensions.height} + + )} + + + + Frame Rate + + {fps === undefined ? ( + + ) : fps ? ( + <>{fps} FPS + ) : ( + 'N/A' + )} + + + + Video Codec + + {videoCodec === null ? ( + + ) : ( + videoCodec + )} + + + + Audio Codec + + {audioCodec === null ? ( + + ) : ( + audioCodec + )} + + + +
+ ); +}; diff --git a/packages/convert/app/components/ConvertUi.tsx b/packages/convert/app/components/ConvertUi.tsx new file mode 100644 index 00000000000..df825a4b182 --- /dev/null +++ b/packages/convert/app/components/ConvertUi.tsx @@ -0,0 +1,98 @@ +import {Button} from '@/components/ui/button'; +import {CardContent, CardTitle} from '@/components/ui/card'; +import {Label} from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import {convertMedia} from '@remotion/webcodecs'; +import {useCallback, useState} from 'react'; +import {Badge} from './ui/badge'; + +export default function ConvertUI({src}: {readonly src: string}) { + const [abortController] = useState( + () => new AbortController(), + ); + + const [container, setContainer] = useState('webm'); + const [videoCodec, setVideoCodec] = useState('vp8'); + const [audioCodec, setAudioCodec] = useState('opus'); + + const onClick = useCallback(async () => { + await convertMedia({ + src, + onVideoFrame: () => { + // console.log('frame', frame); + return Promise.resolve(); + }, + onMediaStateUpdate: () => { + // console.log('update', s); + }, + videoCodec: videoCodec as 'vp8', + audioCodec: audioCodec as 'opus', + to: container as 'webm', + signal: abortController.signal, + }); + }, [abortController.signal, src, container, videoCodec, audioCodec]); + + return ( +
+ +
+
+ Convert video +
+ Alpha +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+ ); +} diff --git a/packages/convert/app/components/Probe.tsx b/packages/convert/app/components/Probe.tsx new file mode 100644 index 00000000000..e0274a38dac --- /dev/null +++ b/packages/convert/app/components/Probe.tsx @@ -0,0 +1,286 @@ +import type { + Dimensions, + MediaParserAudioCodec, + MediaParserVideoCodec, + ParseMediaContainer, + TracksField, +} from '@remotion/media-parser'; +import {parseMedia} from '@remotion/media-parser'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import {AudioTrackOverview} from './AudioTrackOverview'; +import {ContainerOverview} from './ContainerOverview'; +import {SourceLabel} from './SourceLabel'; +import {TrackSwitcher} from './TrackSwitcher'; +import {VideoThumbnail} from './VideoThumbnail'; +import {VideoTrackOverview} from './VideoTrackOverview'; +import {Button} from './ui/button'; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from './ui/card'; +import {ScrollArea} from './ui/scroll-area'; +import {Separator} from './ui/separator'; +import {Skeleton} from './ui/skeleton'; + +export const Probe: React.FC<{ + readonly src: string; + readonly setProbeDetails: React.Dispatch>; + readonly probeDetails: boolean; +}> = ({src, probeDetails, setProbeDetails}) => { + const [audioCodec, setAudioCodec] = useState( + null, + ); + const [fps, setFps] = useState(undefined); + const [durationInSeconds, setDurationInSeconds] = useState( + null, + ); + const [dimensions, setDimensions] = useState(null); + const [name, setName] = useState(null); + const [videoCodec, setVideoCodec] = useState( + null, + ); + const [size, setSize] = useState(null); + const [tracks, setTracks] = useState(null); + const [container, setContainer] = useState(null); + const [thumbnail, setThumbnail] = useState(null); + + const getStart = useCallback(() => { + const controller = new AbortController(); + let hasFps = false; + let hasDuration = false; + let hasDimensions = false; + let hasVideoCodec = false; + let hasAudioCodec = false; + let hasSize = false; + let hasName = false; + let hasFrame = false; + let hasContainer = false; + let hasTracks = false; + + const cancelIfDone = () => { + if ( + hasFps && + hasDuration && + hasDimensions && + hasVideoCodec && + hasAudioCodec && + hasSize && + hasName && + hasFrame && + hasContainer && + hasTracks + ) { + controller.abort(new Error('Cancelled (all info)')); + } + }; + + parseMedia({ + src, + fields: { + dimensions: true, + videoCodec: true, + size: true, + durationInSeconds: true, + audioCodec: true, + fps: true, + name: true, + tracks: true, + container: true, + }, + signal: controller.signal, + onVideoTrack: async (track) => { + if (typeof VideoDecoder === 'undefined') { + return null; + } + + let frames = 0; + + const decoder = new VideoDecoder({ + error: (error) => { + // eslint-disable-next-line no-console + console.log(error); + }, + output(frame) { + frames++; + if (frames < 30) { + frame.close(); + return; + } + + setThumbnail((f) => { + if (f) { + frame.close(); + return f; + } + + return frame; + }); + hasFrame = true; + cancelIfDone(); + }, + }); + + if (!(await VideoDecoder.isConfigSupported(track)).supported) { + return null; + } + + // TODO: See if possible + decoder.configure(track); + return (sample) => { + if (hasFrame) { + return; + } + + decoder.decode(new EncodedVideoChunk(sample)); + }; + }, + onContainer(c) { + hasContainer = true; + setContainer(c); + cancelIfDone(); + }, + onAudioCodec: (codec) => { + hasAudioCodec = true; + setAudioCodec(codec); + cancelIfDone(); + }, + onFps: (f) => { + hasFps = true; + setFps(f); + cancelIfDone(); + }, + onDurationInSeconds: (d) => { + hasDuration = true; + setDurationInSeconds(d); + cancelIfDone(); + }, + onName: (n) => { + hasName = true; + setName(n); + cancelIfDone(); + }, + onDimensions(dim) { + hasDimensions = true; + setDimensions(dim); + cancelIfDone(); + }, + onVideoCodec: (codec) => { + hasVideoCodec = true; + setVideoCodec(codec); + cancelIfDone(); + }, + onTracks: (trx) => { + hasTracks = true; + setTracks(trx); + cancelIfDone(); + }, + onSize(s) { + hasSize = true; + setSize(s); + cancelIfDone(); + }, + }) + .then(() => {}) + .catch((err) => { + if ((err as Error).stack?.includes('Cancelled')) { + return; + } + + // eslint-disable-next-line no-console + console.log(err); + }); + + return controller; + }, [src]); + + useEffect(() => { + const start = getStart(); + return () => { + start.abort(new Error('Cancelled (strict mode)')); + }; + }, [getStart]); + + const onClick = useCallback(() => { + setProbeDetails((p) => !p); + }, [setProbeDetails]); + + const sortedTracks = useMemo( + () => + tracks + ? [...tracks.audioTracks, ...tracks.videoTracks].sort( + (a, b) => a.trackId - b.trackId, + ) + : [], + [tracks], + ); + + const [trackDetails, setTrackDetails] = useState(null); + + const selectedTrack = useMemo(() => { + if (!probeDetails || trackDetails === null) { + return null; + } + + return sortedTracks[trackDetails]; + }, [probeDetails, sortedTracks, trackDetails]); + + return ( + + + + + {name ? name : } + + + + + + {sortedTracks.length && probeDetails ? ( +
+ { + setTrackDetails(track); + }} + sortedTracks={sortedTracks} + /> +
+ ) : null} + + + {selectedTrack === null ? ( + + ) : selectedTrack.type === 'video' ? ( + + ) : selectedTrack.type === 'audio' ? ( + + ) : null} + + + + +
+ + + + ); +}; diff --git a/packages/convert/app/components/SourceLabel.tsx b/packages/convert/app/components/SourceLabel.tsx new file mode 100644 index 00000000000..8e3d5ca3592 --- /dev/null +++ b/packages/convert/app/components/SourceLabel.tsx @@ -0,0 +1,29 @@ +import React from 'react'; + +export const SourceLabel: React.FC<{ + readonly src: string | File; +}> = ({src}) => { + if (src instanceof File) { + return
From file
; + } + + const url = new URL(src as string); + + const origin = url.origin + .replace(/^https?:\/\//, '') + .replace(/^http:\/\//, ''); + + return ( + + From{' '} + + {origin} + + + ); +}; diff --git a/packages/convert/app/components/TrackSwitcher.tsx b/packages/convert/app/components/TrackSwitcher.tsx new file mode 100644 index 00000000000..8b8181168f7 --- /dev/null +++ b/packages/convert/app/components/TrackSwitcher.tsx @@ -0,0 +1,45 @@ +import type {AudioTrack, VideoTrack} from '@remotion/media-parser'; +import React from 'react'; +import {Button} from './ui/button'; +import {Separator} from './ui/separator'; + +export const TrackSwitcher: React.FC<{ + readonly sortedTracks: (AudioTrack | VideoTrack)[]; + readonly onTrack: (trackNumber: number | null) => void; + readonly selectedTrack: number | null; +}> = ({sortedTracks, onTrack, selectedTrack}) => { + const goToOverview = () => { + onTrack(null); + }; + + return ( +
+ {sortedTracks.length ? ( +
+
+ + {sortedTracks.map((trk, i) => { + return ( + + + + + ); + })} +
+
+
+ ) : null} +
+ ); +}; diff --git a/packages/convert/app/components/VideoThumbnail.tsx b/packages/convert/app/components/VideoThumbnail.tsx new file mode 100644 index 00000000000..cf9b0530871 --- /dev/null +++ b/packages/convert/app/components/VideoThumbnail.tsx @@ -0,0 +1,42 @@ +import {useEffect, useRef} from 'react'; + +const THUMBNAIL_WIDTH = 350; +const THUMBNAIL_HEIGHT = Math.round((THUMBNAIL_WIDTH / 16) * 9); + +export const VideoThumbnail: React.FC<{ + readonly thumbnail: VideoFrame | null; +}> = ({thumbnail}) => { + const ref = useRef(null); + + useEffect(() => { + if (!thumbnail) { + return; + } + + createImageBitmap(thumbnail, { + resizeWidth: THUMBNAIL_WIDTH, + resizeHeight: THUMBNAIL_HEIGHT, + }).then((bitmap) => { + const twoDContext = ref.current?.getContext('2d'); + if (!twoDContext) { + return; + } + + twoDContext.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height); + thumbnail.close(); + }); + }, [thumbnail]); + + return ( + + ); +}; diff --git a/packages/convert/app/components/VideoTrackOverview.tsx b/packages/convert/app/components/VideoTrackOverview.tsx new file mode 100644 index 00000000000..69bc7646bc3 --- /dev/null +++ b/packages/convert/app/components/VideoTrackOverview.tsx @@ -0,0 +1,83 @@ +import {Table, TableBody, TableCell, TableRow} from '@/components/ui/table'; +import type {VideoTrack} from '@remotion/media-parser'; +import React from 'react'; + +export const VideoTrackOverview: React.FC<{ + readonly track: VideoTrack; +}> = ({track}) => { + return ( + + + + Type + Video + + + Codec + + {track.codecWithoutConfig} + + + + WebCodecs Codec String + {track.codec} + + + Dimensions + + {track.width}x{track.height} + + + + Timescale + {track.timescale} + + + Sample Aspect Ratio + + {track.sampleAspectRatio.numerator}: + {track.sampleAspectRatio.denominator} + + + + Rotation + {track.rotation}° + + + Unrotated dimensions + + {track.codedWidth}x{track.codedHeight} + + + + Color Primaries + + {track.color.primaries ?? 'N/A'} + + + + Color Matrix + + {track.color.matrixCoefficients ?? 'N/A'} + + + + Color Transfer Characteristics + + {track.color.transferCharacteristics ?? 'N/A'} + + + + Color Full Range + + {track.color.fullRange + ? 'Yes' + : track.color.fullRange === false + ? 'No' + : 'N/A'} + + + +
+ ); +}; diff --git a/packages/convert/app/components/ui/badge.tsx b/packages/convert/app/components/ui/badge.tsx new file mode 100644 index 00000000000..9b213de3f31 --- /dev/null +++ b/packages/convert/app/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "~/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/packages/convert/app/components/ui/button.tsx b/packages/convert/app/components/ui/button.tsx new file mode 100644 index 00000000000..fc8995ef38b --- /dev/null +++ b/packages/convert/app/components/ui/button.tsx @@ -0,0 +1,56 @@ +import {Slot} from '@radix-ui/react-slot'; +import {cva, type VariantProps} from 'class-variance-authority'; +import * as React from 'react'; + +import {cn} from '~/lib/utils'; + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + readonly asChild?: boolean; +} + +const Button = React.forwardRef( + ({className, variant, size, asChild = false, ...props}, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + }, +); +Button.displayName = 'Button'; + +export {Button, buttonVariants}; diff --git a/packages/convert/app/components/ui/card.tsx b/packages/convert/app/components/ui/card.tsx new file mode 100644 index 00000000000..3f29afb427f --- /dev/null +++ b/packages/convert/app/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; + +import {cn} from '~/lib/utils'; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +
+)); +Card.displayName = 'Card'; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +
+)); +CardHeader.displayName = 'CardHeader'; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +

+)); +CardTitle.displayName = 'CardTitle'; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +

+)); +CardDescription.displayName = 'CardDescription'; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +

+)); +CardContent.displayName = 'CardContent'; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => ( +
+)); +CardFooter.displayName = 'CardFooter'; + +export {Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle}; diff --git a/packages/convert/app/components/ui/input.tsx b/packages/convert/app/components/ui/input.tsx new file mode 100644 index 00000000000..bfd674868fb --- /dev/null +++ b/packages/convert/app/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; + +import {cn} from '~/lib/utils'; + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({className, type, ...props}, ref) => { + return ( + + ); + }, +); +Input.displayName = 'Input'; + +export {Input}; diff --git a/packages/convert/app/components/ui/label.tsx b/packages/convert/app/components/ui/label.tsx new file mode 100644 index 00000000000..dbefb85dd8c --- /dev/null +++ b/packages/convert/app/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "~/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/packages/convert/app/components/ui/scroll-area.tsx b/packages/convert/app/components/ui/scroll-area.tsx new file mode 100644 index 00000000000..e5881c6365b --- /dev/null +++ b/packages/convert/app/components/ui/scroll-area.tsx @@ -0,0 +1,46 @@ +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; +import * as React from 'react'; + +import {cn} from '~/lib/utils'; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, orientation = 'vertical', ...props}, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, children, ...props}, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +export {ScrollArea, ScrollBar}; diff --git a/packages/convert/app/components/ui/select.tsx b/packages/convert/app/components/ui/select.tsx new file mode 100644 index 00000000000..f69b6737f2b --- /dev/null +++ b/packages/convert/app/components/ui/select.tsx @@ -0,0 +1,158 @@ +import * as React from "react" +import * as SelectPrimitive from "@radix-ui/react-select" +import { Check, ChevronDown, ChevronUp } from "lucide-react" + +import { cn } from "~/lib/utils" + +const Select = SelectPrimitive.Root + +const SelectGroup = SelectPrimitive.Group + +const SelectValue = SelectPrimitive.Value + +const SelectTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + span]:line-clamp-1", + className + )} + {...props} + > + {children} + + + + +)) +SelectTrigger.displayName = SelectPrimitive.Trigger.displayName + +const SelectScrollUpButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName + +const SelectScrollDownButton = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +SelectScrollDownButton.displayName = + SelectPrimitive.ScrollDownButton.displayName + +const SelectContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, position = "popper", ...props }, ref) => ( + + + + + {children} + + + + +)) +SelectContent.displayName = SelectPrimitive.Content.displayName + +const SelectLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectLabel.displayName = SelectPrimitive.Label.displayName + +const SelectItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)) +SelectItem.displayName = SelectPrimitive.Item.displayName + +const SelectSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SelectSeparator.displayName = SelectPrimitive.Separator.displayName + +export { + Select, + SelectGroup, + SelectValue, + SelectTrigger, + SelectContent, + SelectLabel, + SelectItem, + SelectSeparator, + SelectScrollUpButton, + SelectScrollDownButton, +} diff --git a/packages/convert/app/components/ui/separator.tsx b/packages/convert/app/components/ui/separator.tsx new file mode 100644 index 00000000000..464677ff8cf --- /dev/null +++ b/packages/convert/app/components/ui/separator.tsx @@ -0,0 +1,29 @@ +import * as React from "react" +import * as SeparatorPrimitive from "@radix-ui/react-separator" + +import { cn } from "~/lib/utils" + +const Separator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, orientation = "horizontal", decorative = true, ...props }, + ref + ) => ( + + ) +) +Separator.displayName = SeparatorPrimitive.Root.displayName + +export { Separator } diff --git a/packages/convert/app/components/ui/skeleton.tsx b/packages/convert/app/components/ui/skeleton.tsx new file mode 100644 index 00000000000..a01adc3e055 --- /dev/null +++ b/packages/convert/app/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "~/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/packages/convert/app/components/ui/table.tsx b/packages/convert/app/components/ui/table.tsx new file mode 100644 index 00000000000..b3b371107ad --- /dev/null +++ b/packages/convert/app/components/ui/table.tsx @@ -0,0 +1,117 @@ +import * as React from "react" + +import { cn } from "~/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/packages/convert/app/lib/format-bytes.ts b/packages/convert/app/lib/format-bytes.ts new file mode 100644 index 00000000000..6811b1cf5d6 --- /dev/null +++ b/packages/convert/app/lib/format-bytes.ts @@ -0,0 +1,142 @@ +const BYTE_UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + +const BIBYTE_UNITS = [ + 'B', + 'kiB', + 'MiB', + 'GiB', + 'TiB', + 'PiB', + 'EiB', + 'ZiB', + 'YiB', +]; + +const BIT_UNITS = [ + 'b', + 'kbit', + 'Mbit', + 'Gbit', + 'Tbit', + 'Pbit', + 'Ebit', + 'Zbit', + 'Ybit', +]; + +const BIBIT_UNITS = [ + 'b', + 'kibit', + 'Mibit', + 'Gibit', + 'Tibit', + 'Pibit', + 'Eibit', + 'Zibit', + 'Yibit', +]; + +/* +Formats the given number using `Number#toLocaleString`. +- If locale is a string, the value is expected to be a locale-key (for example: `de`). +- If locale is true, the system default locale is used for translation. +- If no value for locale is specified, the number is returned unmodified. +*/ +const toLocaleString = ( + number: number, + locale: string, + options?: Intl.NumberFormatOptions, +): string => { + if (typeof locale === 'string' || Array.isArray(locale)) { + return number.toLocaleString(locale, options); + } + + if (locale === true || options !== undefined) { + return number.toLocaleString(undefined, options); + } + + return String(number); +}; + +export const formatBytes = ( + number: number, + options: Intl.NumberFormatOptions & { + locale: string; + bits?: boolean; + binary?: boolean; + signed: boolean; + } = { + locale: 'en-US', + signed: false, + maximumFractionDigits: 1, + }, +) => { + if (!Number.isFinite(number)) { + throw new TypeError( + `Expected a finite number, got ${typeof number}: ${number}`, + ); + } + + options = {bits: false, binary: false, ...options}; + + const UNITS = options.bits + ? options.binary + ? BIBIT_UNITS + : BIT_UNITS + : options.binary + ? BIBYTE_UNITS + : BYTE_UNITS; + + if (options.signed && number === 0) { + return `0 $ { + UNITS[0] + }`; + } + + const isNegative = number < 0; + const prefix = isNegative ? '-' : options.signed ? '+' : ''; + + if (isNegative) { + number = -number; + } + + let localeOptions; + + if (options.minimumFractionDigits !== undefined) { + localeOptions = { + minimumFractionDigits: options.minimumFractionDigits, + }; + } + + if (options.maximumFractionDigits !== undefined) { + localeOptions = { + maximumFractionDigits: options.maximumFractionDigits, + ...localeOptions, + }; + } + + if (number < 1) { + const numString = toLocaleString(number, options.locale, localeOptions); + return prefix + numString + ' ' + UNITS[0]; + } + + const exponent = Math.min( + Math.floor( + options.binary + ? Math.log(number) / Math.log(1024) + : Math.log10(number) / 3, + ), + UNITS.length - 1, + ); + number /= (options.binary ? 1024 : 1000) ** exponent; + + const numberString = toLocaleString( + Number(number), + options.locale, + localeOptions, + ); + + const unit = UNITS[exponent]; + + return prefix + numberString + ' ' + unit; +}; diff --git a/packages/convert/app/lib/utils.ts b/packages/convert/app/lib/utils.ts new file mode 100644 index 00000000000..bd0c391ddd1 --- /dev/null +++ b/packages/convert/app/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/convert/app/root.tsx b/packages/convert/app/root.tsx new file mode 100644 index 00000000000..3d3d7332071 --- /dev/null +++ b/packages/convert/app/root.tsx @@ -0,0 +1,30 @@ +import { + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from "@remix-run/react"; +import "./tailwind.css"; + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ); +} + +export default function App() { + return ; +} diff --git a/packages/convert/app/routes/_index.tsx b/packages/convert/app/routes/_index.tsx new file mode 100644 index 00000000000..ee6b034c156 --- /dev/null +++ b/packages/convert/app/routes/_index.tsx @@ -0,0 +1,31 @@ +import type {MetaFunction} from '@remix-run/node'; +import {useState} from 'react'; +import ConvertUI from '~/components/ConvertUi'; +import {Probe} from '~/components/Probe'; + +export const meta: MetaFunction = () => { + return [ + {title: 'Remotion Convert'}, + {name: 'description', content: 'Fast video conersion in the browser.'}, + ]; +}; + +const src = + 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'; + +const Index = () => { + const [probeDetails, setProbeDetails] = useState(false); + + return ( +
+ + {probeDetails ? null : } +
+ ); +}; + +export default Index; diff --git a/packages/convert/app/tailwind.css b/packages/convert/app/tailwind.css new file mode 100644 index 00000000000..4937c0424c8 --- /dev/null +++ b/packages/convert/app/tailwind.css @@ -0,0 +1,66 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + --radius: 0.5rem + } + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55% + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/packages/convert/components.json b/packages/convert/components.json new file mode 100644 index 00000000000..b146500c00c --- /dev/null +++ b/packages/convert/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "app/tailwind.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "~/components", + "utils": "~/lib/utils", + "ui": "~/components/ui", + "lib": "~/lib", + "hooks": "~/hooks" + } +} \ No newline at end of file diff --git a/packages/convert/package.json b/packages/convert/package.json new file mode 100644 index 00000000000..8c8bfb4a8ae --- /dev/null +++ b/packages/convert/package.json @@ -0,0 +1,50 @@ +{ + "name": "@remotion/convert", + "version": "4.0.209", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "build-page": "remix vite:build", + "dev": "remix vite:dev", + "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", + "typecheck": "tsc" + }, + "dependencies": { + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-select": "^2.1.1", + "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@remix-run/node": "^2.11.2", + "@remix-run/react": "^2.11.2", + "@remix-run/serve": "^2.11.2", + "@remotion/media-parser": "workspace:*", + "@remotion/webcodecs": "workspace:*", + "@vercel/remix": "^2.11.2", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "isbot": "^4.1.0", + "lucide-react": "^0.439.0", + "react": "18.3.1", + "react-dom": "18.3.1", + "tailwind-merge": "^2.5.2", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@remix-run/dev": "^2.11.2", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.38", + "tailwindcss": "^3.4.4", + "vite": "^5.1.0", + "vite-tsconfig-paths": "^4.2.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "repository": { + "url": "https://github.com/remotion-dev/remotion/tree/main/packages/convert" + }, + "homepage": "https://convert.remotion.dev", + "description": "Video conversion tool - convert.remotion.dev" +} diff --git a/packages/convert/postcss.config.js b/packages/convert/postcss.config.js new file mode 100644 index 00000000000..2aa7205d4b4 --- /dev/null +++ b/packages/convert/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/packages/convert/public/favicon.ico b/packages/convert/public/favicon.ico new file mode 100644 index 00000000000..76cef1e1032 Binary files /dev/null and b/packages/convert/public/favicon.ico differ diff --git a/packages/convert/tailwind.config.ts b/packages/convert/tailwind.config.ts new file mode 100644 index 00000000000..cd58796294a --- /dev/null +++ b/packages/convert/tailwind.config.ts @@ -0,0 +1,58 @@ +import type { Config } from "tailwindcss"; + +export default { + darkMode: ["class"], + content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: { + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + } + } + }, + plugins: [require("tailwindcss-animate")], +} satisfies Config; diff --git a/packages/convert/tsconfig.json b/packages/convert/tsconfig.json new file mode 100644 index 00000000000..4717142e535 --- /dev/null +++ b/packages/convert/tsconfig.json @@ -0,0 +1,40 @@ +{ + "extends": "../tsconfig.settings.json", + "include": [ + "**/*.ts", + "**/*.tsx", + "**/.server/**/*.ts", + "**/.server/**/*.tsx", + "**/.client/**/*.ts", + "**/.client/**/*.tsx" + ], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["@remix-run/node", "vite/client"], + "isolatedModules": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "target": "ES2022", + "strict": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./app/*"], + "@/*": ["./app/*"] + }, + + // Vite takes care of building everything, not tsc. + "noEmit": true + }, + "references": [ + { + "path": "../media-parser" + } + ] +} diff --git a/packages/convert/vite.config.ts b/packages/convert/vite.config.ts new file mode 100644 index 00000000000..85c57392f6f --- /dev/null +++ b/packages/convert/vite.config.ts @@ -0,0 +1,17 @@ +import {vitePlugin as remix} from '@remix-run/dev'; +import {installGlobals} from '@remix-run/node'; +import {vercelPreset} from '@vercel/remix/vite'; +import path from 'path'; +import {defineConfig} from 'vite'; +import tsconfigPaths from 'vite-tsconfig-paths'; + +installGlobals(); + +export default defineConfig({ + plugins: [remix({presets: [vercelPreset()]}), tsconfigPaths()], + resolve: { + alias: { + '@': path.resolve(__dirname, './app'), + }, + }, +}); diff --git a/packages/docs/blog/2021-08-11-remotion-2-3.mdx b/packages/docs/blog/2021-08-11-remotion-2-3.mdx index 0b2b43666e9..550d2716a92 100644 --- a/packages/docs/blog/2021-08-11-remotion-2-3.mdx +++ b/packages/docs/blog/2021-08-11-remotion-2-3.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Remotion Creator author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%202.3&description=%3CStill%20/%3E%20component,%20renderStill()%20API,%20optimized%20editor%20and%20CLI,%20Server%20rendering%20template +image: /img/remotion-2-3.png --- Remotion 2.3 is out and features [first-class support for still images](/docs/stills)! diff --git a/packages/docs/blog/2021-09-27-remotion-2-4.mdx b/packages/docs/blog/2021-09-27-remotion-2-4.mdx index 8970ba26f76..0ff7b2c4b66 100644 --- a/packages/docs/blog/2021-09-27-remotion-2-4.mdx +++ b/packages/docs/blog/2021-09-27-remotion-2-4.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Remotion Creator author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%202.4&description=Redesigned%20editor,%20UI%20helpers%20and%20%20%22New%20composition%22%20dialog +image: /img/remotion-2-4.png --- In this release, we are revamping the Remotion Preview interface to make it easier on the eyes and add new features. While Remotion will always be about leveraging code instead of clicking buttons, we want to add complementary helpers to help you get your videos done faster! diff --git a/packages/docs/blog/2021-10-26-remotion-2-5.mdx b/packages/docs/blog/2021-10-26-remotion-2-5.mdx index 36b55eafbac..d43571a1fd3 100644 --- a/packages/docs/blog/2021-10-26-remotion-2-5.mdx +++ b/packages/docs/blog/2021-10-26-remotion-2-5.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Remotion Creator author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%202.5&description=Loop%20component,%20In/Out%20Markers,%20Variable%20playback%20rate%20and%20more! +image: /img/remotion-2-5.png --- # Remotion 2.5 diff --git a/packages/docs/blog/2022-01-05-remotion-2-6.mdx b/packages/docs/blog/2022-01-05-remotion-2-6.mdx index 49380526c67..10c04282f21 100644 --- a/packages/docs/blog/2022-01-05-remotion-2-6.mdx +++ b/packages/docs/blog/2022-01-05-remotion-2-6.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Remotion Creator author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%202.6&description=@remotion/player,%20/public%20folder%20and%20a%20new%20error%20overlay +image: /img/remotion-2-6.png --- The biggest announcement of this release is that the [`@remotion/player`](/player) package is now generally available - but not just that, we have some other sweet new features too! diff --git a/packages/docs/blog/2022-04-26-remotion-3-0.mdx b/packages/docs/blog/2022-04-26-remotion-3-0.mdx index 27e5ac81ab6..09828327179 100644 --- a/packages/docs/blog/2022-04-26-remotion-3-0.mdx +++ b/packages/docs/blog/2022-04-26-remotion-3-0.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Chief Hacker @ Remotion author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%203.0&description=@remotion/lambda,%20faster%20rendering,%20renderMedia()%20and%20React%2018 +image: /img/remotion-3-0.png --- After more than 10 months in development and 1400 commits, it feels so good to announce Remotion 3.0! diff --git a/packages/docs/blog/2022-07-14-remotion-3-1.mdx b/packages/docs/blog/2022-07-14-remotion-3-1.mdx index 3997c468a46..34c6cc05256 100644 --- a/packages/docs/blog/2022-07-14-remotion-3-1.mdx +++ b/packages/docs/blog/2022-07-14-remotion-3-1.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Chief Hacker @ Remotion author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%203.1&description=GIFs,%20%3COffthreadVideo%3E,%20Springs%20with%20duration,%20TailwindCSS +image: /img/remotion-3-1.png --- import Tabs from '@theme/Tabs'; diff --git a/packages/docs/blog/2022-08-10-remotion-3-2.mdx b/packages/docs/blog/2022-08-10-remotion-3-2.mdx index bc281a8c665..07c627372b9 100644 --- a/packages/docs/blog/2022-08-10-remotion-3-2.mdx +++ b/packages/docs/blog/2022-08-10-remotion-3-2.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Chief Hacker @ Remotion author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%203.2&description=Lottie,%20Skia,%20zoomable%20timeline,%20muted%20renders,%20stability%20and%20speed +image: /img/remotion-3-2.png --- import Tabs from '@theme/Tabs'; diff --git a/packages/docs/blog/2022-11-17-remotion-3-3.mdx b/packages/docs/blog/2022-11-17-remotion-3-3.mdx index cdb9a4369ae..5467bc20719 100644 --- a/packages/docs/blog/2022-11-17-remotion-3-3.mdx +++ b/packages/docs/blog/2022-11-17-remotion-3-3.mdx @@ -5,7 +5,7 @@ author: Jonny Burger author_title: Chief Hacker @ Remotion author_url: https://github.com/JonnyBurger author_image_url: https://avatars2.githubusercontent.com/u/1629785?s=460&u=12eb94da6070d00fc924761ce06e3a428d01b7e9&v=4 -image: https://remotion-still.herokuapp.com/PreviewCard.png?title=Remotion%203.3&description=FFmpeg%20now%20auto-installs,%20Packages%20for%20Google%20Fonts,%20Motion%20Blur,%20Noise,%20SVG%20paths%20and%2030%20more%20features +image: /img/remotion-3-3.png --- import Tabs from '@theme/Tabs'; diff --git a/packages/docs/components/LandingPage/DeveloperCommunityStats.tsx b/packages/docs/components/LandingPage/CommunityStatItems.tsx similarity index 75% rename from packages/docs/components/LandingPage/DeveloperCommunityStats.tsx rename to packages/docs/components/LandingPage/CommunityStatItems.tsx index 0e43e1f18e4..ab0f4493a0a 100644 --- a/packages/docs/components/LandingPage/DeveloperCommunityStats.tsx +++ b/packages/docs/components/LandingPage/CommunityStatItems.tsx @@ -1,49 +1,5 @@ -import {useColorMode} from '@docusaurus/theme-common'; import React from 'react'; - -// Shared styles -const useStyles = (isDarkTheme: boolean) => ({ - container: { - maxWidth: '700px', - margin: '0 auto', - textAlign: 'center' as const, - justifyContent: 'center', - }, - title: { - fontSize: '2.5rem', - fontWeight: 'bold', - marginBottom: '0.5rem', - }, - subtitle: { - fontSize: '1.25rem', - marginBottom: '1.5rem', - }, - statsGrid: { - display: 'flex', - flexWrap: 'wrap' as const, - justifyContent: 'space-between', - gap: '1rem', - width: '100%', - alignItems: 'center', - }, - statItem: { - backgroundColor: 'var(--ifm-background-surface-color)', - borderRadius: '0.5rem', - border: `5px solid ${isDarkTheme ? '#E3E3E3' : '#000000'}`, - padding: '0.3rem', - boxShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)', - lineHeight: '1', - display: 'flex', - flexWrap: 'wrap' as const, - justifyContent: 'center', - alignItems: 'center', - alignContent: 'center', - flex: '1 1 30%', // Flex-grow, flex-shrink, and flex-basis for responsive scaling - minWidth: '200px', // Minimum width to ensure readability - minHeight: '80px', // Minimum height to ensure readability - maxHeight: '110px', // Maximum height to ensure readability - }, -}); +import styles from './CommunityStats.module.css'; // StatItemContent component const StatItemContent: React.FC<{ @@ -71,7 +27,6 @@ const StatItemContent: React.FC<{ height, fontSize, fontWeight, - border: '1px solid #000000', display: 'flex', justifyContent: 'center', alignItems: 'center', @@ -82,13 +37,12 @@ const StatItemContent: React.FC<{ ); -const InstallsPerMonth: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - const svgFillColor = isDarkTheme ? '#E3E3E3' : 'black'; - +export const InstallsPerMonth: React.FC = () => { return ( -
+
{ > } @@ -122,7 +76,7 @@ const InstallsPerMonth: React.FC = () => {
@@ -130,12 +84,12 @@ const InstallsPerMonth: React.FC = () => { ); }; -const PagesOfDocs: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - const svgFillColor = isDarkTheme ? '#E3E3E3' : 'black'; +export const PagesOfDocs: React.FC = () => { return ( -
+
{ > } width="40px" /> { ); }; -// TemplatesAndExamples component -const TemplatesAndExamples: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); +export const TemplatesAndExamples: React.FC = () => ( +
+ + +
+); + +export const GitHubStars: React.FC = () => { return (
- - -
- ); -}; - -const GitHubStars: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - const svgFillColor = isDarkTheme ? '#E3E3E3' : 'black'; - - return ( -
{ > } @@ -243,13 +191,9 @@ const GitHubStars: React.FC = () => { ); }; -const DiscordMembers: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - const svgFillColor = isDarkTheme ? '#E3E3E3' : 'black'; - +export const DiscordMembers: React.FC = () => { return ( -
+
{ > } @@ -308,33 +252,19 @@ const DiscordMembers: React.FC = () => { ); }; -const Contributors: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - const svgFillColor = isDarkTheme ? '#E3E3E3' : 'black'; - +export const Contributors: React.FC = () => { return (
-
-
+
+
{ > } @@ -378,25 +308,3 @@ const Contributors: React.FC = () => {
); }; - -const DeveloperCommunityStats4: React.FC = () => { - const {isDarkTheme} = useColorMode(); - const styles = useStyles(isDarkTheme); - - return ( -
-

Developer community stats

-

A thriving community of developers.

-
- - - - - - -
-
- ); -}; - -export default DeveloperCommunityStats4; diff --git a/packages/docs/components/LandingPage/CommunityStats.module.css b/packages/docs/components/LandingPage/CommunityStats.module.css new file mode 100644 index 00000000000..31869ebaaf4 --- /dev/null +++ b/packages/docs/components/LandingPage/CommunityStats.module.css @@ -0,0 +1,68 @@ +.container { + max-width: 700px; + margin: 0 auto; + text-align: center; + justify-content: center; +} + +.title { + font-size: 2.5rem; + font-weight: bold; + margin-bottom: 0.5rem; +} + +.subtitle { + font-size: 1.25rem; + margin-bottom: 1.5rem; +} + +.statsGrid { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 1rem; + width: 100%; + align-items: center; +} + +.statItemLink { + text-decoration: none; + color: inherit; + display: contents; /* "display: contents" causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself. This can be useful when a wrapper element should be ignored when using CSS grid or similar layout techniques. */ +} + +.statItemLink:hover, +.statItemLink:focus, +.statItemLink:active { + text-decoration: none; + color: inherit; +} + +.statItem { + background-color: var(--ifm-background-surface-color); + border-radius: 0.5rem; + border: 5px solid var(--text-color); + padding: 0.3rem; + box-shadow: + 0 1px 3px rgba(0, 0, 0, 0.12), + 0 1px 2px rgba(0, 0, 0, 0.24); + line-height: 1; + display: flex; + flex-wrap: wrap; + justify-content: center; + align-items: center; + align-content: center; + flex: 1 1 30%; + min-width: 200px; + min-height: 80px; + max-height: 110px; + flex: 1 1 30%; /* Makes the items grow/shrink consistently */ + transition: + transform 0.2s, + box-shadow 0.2s; +} + +.statItem:hover { + transform: scale(0.95); + box-shadow: var(--box-shadow); +} diff --git a/packages/docs/components/LandingPage/CommunityStats.tsx b/packages/docs/components/LandingPage/CommunityStats.tsx new file mode 100644 index 00000000000..4f29e8461dc --- /dev/null +++ b/packages/docs/components/LandingPage/CommunityStats.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { + Contributors, + DiscordMembers, + GitHubStars, + InstallsPerMonth, + PagesOfDocs, + TemplatesAndExamples, +} from './CommunityStatItems'; +import styles from './CommunityStats.module.css'; + +const CommunityStats: React.FC = () => ( +
+

Never build alone

+

Join a thriving community of developers.

+ +
+); + +export default CommunityStats; diff --git a/packages/docs/components/LandingPage/DeveloperCommunityStats2-SharedComponent.tsx b/packages/docs/components/LandingPage/DeveloperCommunityStats2-SharedComponent.tsx deleted file mode 100644 index eb8ad250cdd..00000000000 --- a/packages/docs/components/LandingPage/DeveloperCommunityStats2-SharedComponent.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import {useColorMode} from '@docusaurus/theme-common'; -import React from 'react'; - -export const StatItemContent: React.FC<{ - content: React.ReactNode; - width: string; - height?: string; - fontSize?: string; - fontWeight?: React.CSSProperties['fontWeight']; - className?: string; // Add className prop -}> = ({content, width, height = 'auto', fontSize, fontWeight, className}) => ( -
- {content} -
-); - -export const useSvgFillColor = () => { - const {isDarkTheme} = useColorMode(); - return isDarkTheme ? '#E3E3E3' : 'black'; -}; diff --git a/packages/docs/components/LandingPage/DeveloperCommunityStats2-StatComponents.tsx b/packages/docs/components/LandingPage/DeveloperCommunityStats2-StatComponents.tsx deleted file mode 100644 index 7f7d037cb12..00000000000 --- a/packages/docs/components/LandingPage/DeveloperCommunityStats2-StatComponents.tsx +++ /dev/null @@ -1,257 +0,0 @@ -import React from 'react'; -import { - StatItemContent, - useSvgFillColor, -} from './DeveloperCommunityStats2-SharedComponent'; - -export const InstallsPerMonth: React.FC = () => { - const svgFillColor = useSvgFillColor(); - - return ( -
- - - - - } - width="25%" - /> - -
- ); -}; - -export const PagesOfDocs: React.FC = () => { - const svgFillColor = useSvgFillColor(); - return ( -
- - - - } - width="25%" - /> - - -
- ); -}; - -export const TemplatesAndExamples: React.FC = () => ( -
- - -
-); - -export const GitHubStars: React.FC = () => { - const svgFillColor = useSvgFillColor(); - - return ( -
- - - - } - width="25%" - /> - - -
- ); -}; - -export const DiscordMembers: React.FC = () => { - const svgFillColor = useSvgFillColor(); - - return ( -
-
-
- - -
-
- - - - } - width="100%" - /> -
-
-
- ); -}; - -export const Contributors: React.FC = () => { - const svgFillColor = useSvgFillColor(); - - return ( -
-
-
- - - - } - width="150%" - /> -
-
- - -
-
-
- ); -}; diff --git a/packages/docs/components/LandingPage/DeveloperCommunityStats2.module.css b/packages/docs/components/LandingPage/DeveloperCommunityStats2.module.css deleted file mode 100644 index 0f99666480b..00000000000 --- a/packages/docs/components/LandingPage/DeveloperCommunityStats2.module.css +++ /dev/null @@ -1,59 +0,0 @@ -.developer-stats-container { - max-width: 67%; - width: 67%; - margin: 0 auto; - text-align: center; -} - -.developer-stats-title { - font-size: 2.5rem; - font-weight: bold; - margin-bottom: 0.5rem; -} - -.developer-stats-subtitle { - font-size: 1.25rem; - margin-bottom: 1.5rem; -} - -.developer-stats-grid { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - gap: 1rem; - width: 100%; -} - -.stat-item { - background-color: var(--ifm-background-surface-color); - border-radius: 0.5rem; - border: 5px solid #000000; - padding: 0.3rem; - box-shadow: - 0 1px 3px rgba(0, 0, 0, 0.12), - 0 1px 2px rgba(0, 0, 0, 0.24); - line-height: 1; - display: flex; - flex-wrap: wrap; - justify-content: center; - align-items: center; - align-content: center; -} - -.stat-item-content { - border: 1px solid #000000; - display: flex; - justify-content: center; - align-items: center; - text-align: center; -} - -.stat-item-large-text { - font-size: 2.5rem; - font-weight: bold; -} - -.stat-item-small-text { - font-size: 1rem; - font-weight: bold; -} diff --git a/packages/docs/components/LandingPage/DeveloperCommunityStats2.tsx b/packages/docs/components/LandingPage/DeveloperCommunityStats2.tsx deleted file mode 100644 index a2e2f18f458..00000000000 --- a/packages/docs/components/LandingPage/DeveloperCommunityStats2.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { - Contributors, - DiscordMembers, - GitHubStars, - InstallsPerMonth, - PagesOfDocs, - TemplatesAndExamples, -} from './DeveloperCommunityStats2-StatComponents'; -import './DeveloperCommunityStats2.module.css'; - -const DeveloperCommunityStats2: React.FC = () => ( -
-

Developer community stats

-

- A thriving community of developers. -

-
- - - - - - -
-
-); - -export default DeveloperCommunityStats2; diff --git a/packages/docs/components/LandingPage/EvaluateRemotionSection.tsx b/packages/docs/components/LandingPage/EvaluateRemotionSection.tsx index 017e9d18391..4c5bf0f7be1 100644 --- a/packages/docs/components/LandingPage/EvaluateRemotionSection.tsx +++ b/packages/docs/components/LandingPage/EvaluateRemotionSection.tsx @@ -52,6 +52,7 @@ const EvaluateRemotionSection: React.FC = () => { className={styles.aknow} target="_blank" href="https://cal.com/remotion/evaluate" + style={{textDecoration: 'none'}} > Schedule a call @@ -66,7 +67,11 @@ const EvaluateRemotionSection: React.FC = () => {

- + Remotion Experts diff --git a/packages/docs/docs/media-parser/parse-media.mdx b/packages/docs/docs/media-parser/parse-media.mdx index fdc64186864..ce7099c85b7 100644 --- a/packages/docs/docs/media-parser/parse-media.mdx +++ b/packages/docs/docs/media-parser/parse-media.mdx @@ -3,7 +3,7 @@ image: /generated/articles-docs-media-parser-parse-media.png id: parse-media title: parseMedia() slug: /media-parser/parse-media -crumb: "@remotion/media-parser" +crumb: '@remotion/media-parser' --- _Part of the [`@remotion/media-parser`](/docs/media-parser) package._ @@ -39,7 +39,7 @@ import {parseMedia} from '@remotion/media-parser'; import {nodeReader} from '@remotion/media-parser/node'; const result = await parseMedia({ - src: '/Users/jonnyburger/Downloads/my-video.mp4', + src: '/Users/jonnyburger/Downloads/my-video.mp4', fields: { durationInSeconds: true, dimensions: true, @@ -63,6 +63,7 @@ If you pass a `File` object, you must also pass `webFileReader` as the `reader` ### `fields?` An object specifying which fields you'd like to receive. +If you like to receive the field, pass `true` as the value. Possible fields are: #### `dimensions` @@ -79,6 +80,24 @@ _number | null_ The duration of the video in seconds. +#### `name` + +_string_ + +The name of the file. + +#### `container` + +_"mp4" | "webm" | null_ + +The container of the file. + +#### `size` + +_number | null_ + +The size of the input in bytes. + #### `boxes` The internal structure of the video. Unstable, internal data structure, refer to the TypeScript types to see what's inside. @@ -110,7 +129,7 @@ The data structure of them is not yet stable. _`{width: number, height: number}`_ -The dimensions of the video before rotation. +The dimensions of the video before rotation. #### `rotation` @@ -125,7 +144,6 @@ Default value: `fetchReader`, which uses `fetch()` to read the video. If you pass [`nodeReader`](/docs/media-parser/node-reader), you must also pass a local file path as the `src` argument. If you pass [`webFileReader`](/docs/media-parser/web-file-reader), you must also pass a `File` as the `src` argument. - ### `onVideoTrack?` A callback that is called when a video track is detected. @@ -143,7 +161,7 @@ const onVideoTrack: OnVideoTrack = (track) => { console.log(track); return (sample) => { - console.log(new EncodedVideoChunk(sample)) + console.log(new EncodedVideoChunk(sample)); }; }; ``` @@ -166,17 +184,42 @@ const onAudioTrack: OnAudioTrack = (track) => { console.log(track); return (sample) => { - console.log(new EncodedAudioChunk(sample)) + console.log(new EncodedAudioChunk(sample)); }; }; ``` - ### `signal?` An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance. If the signal is aborted, the parser will stop reading the media and stop the decoding process and throw an error. +### Callbacks + +Each field also has a callback that allows you to retrieve the value as soon as it is obtained without waiting for the function to resolve. +You must pass `true` as the value for the field in order for the callback to be called. + +```tsx twoslash title="Using a callback" +// @module: es2022 +// @target: es2017 + +import {parseMedia} from '@remotion/media-parser'; + +const result = await parseMedia({ + src: 'https://example.com/my-video.mp4', + fields: { + durationInSeconds: true, + dimensions: true, + }, + onDurationInSeconds: (durationInSeconds) => { + console.log(durationInSeconds); + }, + onDimensions: (dimensions) => { + console.log(dimensions); + }, +}); +``` + ## See also - [Source code for this function](https://github.com/remotion-dev/remotion/blob/main/packages/media-parser/src/parse-media.ts) diff --git a/packages/docs/docs/resources.mdx b/packages/docs/docs/resources.mdx index 480889adfcc..e743d047127 100644 --- a/packages/docs/docs/resources.mdx +++ b/packages/docs/docs/resources.mdx @@ -124,6 +124,7 @@ See the [Showcase](/showcase) for videos made with Remotion. - [Remotion Tutorial by Alfonso Graziano](https://www.youtube.com/watch?v=r4v1J7ozxIg) - [Timing animations](https://www.youtube.com/watch?v=WigIALCnEvw) - ["Create a video from a podcast with Remotion and AI"](https://www.youtube.com/watch?v=EGxBBL91nRM) +- [Football Graphics](https://www.youtube.com/watch?v=BI8IWwaDt8s) ## Tooling diff --git a/packages/docs/src/components/TeamCards.tsx b/packages/docs/src/components/TeamCards.tsx index 11152d274df..bb167f49899 100644 --- a/packages/docs/src/components/TeamCards.tsx +++ b/packages/docs/src/components/TeamCards.tsx @@ -108,7 +108,11 @@ export const TeamCardsLayout: React.FC<{}> = () => { { <>
- + Twitter @@ -121,6 +125,7 @@ export const TeamCardsLayout: React.FC<{}> = () => {
@@ -138,7 +143,11 @@ export const TeamCardsLayout: React.FC<{}> = () => { }} >
- + GitHub @@ -147,7 +156,11 @@ export const TeamCardsLayout: React.FC<{}> = () => {
- + E-Mail @@ -196,7 +209,11 @@ export const TeamCardsLayout: React.FC<{}> = () => { { <>
- + Twitter @@ -209,7 +226,8 @@ export const TeamCardsLayout: React.FC<{}> = () => {
LinkedIn @@ -222,7 +240,11 @@ export const TeamCardsLayout: React.FC<{}> = () => { { <>
- + GitHub @@ -231,7 +253,11 @@ export const TeamCardsLayout: React.FC<{}> = () => {
- + E-Mail diff --git a/packages/docs/src/pages/index.tsx b/packages/docs/src/pages/index.tsx index 87b2d84ab69..2eeea419f7f 100644 --- a/packages/docs/src/pages/index.tsx +++ b/packages/docs/src/pages/index.tsx @@ -7,8 +7,7 @@ import { VideoAppsTitle, } from '../../components/LambdaSplash/VideoAppsTitle'; import {BackgroundAnimation} from '../../components/LandingPage/BackgroundAnimation'; -import DeveloperCommunityStats from '../../components/LandingPage/DeveloperCommunityStats'; -import DeveloperCommunityStats2 from '../../components/LandingPage/DeveloperCommunityStats2'; +import CommunityStats from '../../components/LandingPage/CommunityStats'; import EvaluateRemotionSection from '../../components/LandingPage/EvaluateRemotionSection'; import {NewsletterButton} from '../../components/LandingPage/NewsletterButton'; import {Pricing} from '../../components/LandingPage/Pricing'; @@ -20,9 +19,6 @@ import {Parametrize} from '../../components/LandingPage/parametrize'; import {RealMP4Videos} from '../../components/LandingPage/real-mp4-videos'; import styles from './landing.module.css'; -const SHOW_DEVELOPER_COMMUNITY_STATS = false; -const SHOW_TRUSTED_BY_BANNER = true; - const NewLanding: React.FC = () => { return ( @@ -43,14 +39,6 @@ const NewLanding: React.FC = () => {

- {SHOW_DEVELOPER_COMMUNITY_STATS && ( - <> - -
- - - )} -


@@ -74,11 +62,12 @@ const NewLanding: React.FC = () => {

+ +

- - {SHOW_TRUSTED_BY_BANNER && } +
diff --git a/packages/docs/static/img/remotion-2-3.png b/packages/docs/static/img/remotion-2-3.png new file mode 100644 index 00000000000..1eb68ff8272 Binary files /dev/null and b/packages/docs/static/img/remotion-2-3.png differ diff --git a/packages/docs/static/img/remotion-2-4.png b/packages/docs/static/img/remotion-2-4.png new file mode 100644 index 00000000000..764802e531f Binary files /dev/null and b/packages/docs/static/img/remotion-2-4.png differ diff --git a/packages/docs/static/img/remotion-2-5.png b/packages/docs/static/img/remotion-2-5.png new file mode 100644 index 00000000000..a26a0671ffc Binary files /dev/null and b/packages/docs/static/img/remotion-2-5.png differ diff --git a/packages/docs/static/img/remotion-2-6.png b/packages/docs/static/img/remotion-2-6.png new file mode 100644 index 00000000000..9dabf75c011 Binary files /dev/null and b/packages/docs/static/img/remotion-2-6.png differ diff --git a/packages/docs/static/img/remotion-3-0.png b/packages/docs/static/img/remotion-3-0.png new file mode 100644 index 00000000000..b3db1bfc426 Binary files /dev/null and b/packages/docs/static/img/remotion-3-0.png differ diff --git a/packages/docs/static/img/remotion-3-1.png b/packages/docs/static/img/remotion-3-1.png new file mode 100644 index 00000000000..f540f417d56 Binary files /dev/null and b/packages/docs/static/img/remotion-3-1.png differ diff --git a/packages/docs/static/img/remotion-3-2.png b/packages/docs/static/img/remotion-3-2.png new file mode 100644 index 00000000000..4088d32d656 Binary files /dev/null and b/packages/docs/static/img/remotion-3-2.png differ diff --git a/packages/docs/static/img/remotion-3-3.png b/packages/docs/static/img/remotion-3-3.png new file mode 100644 index 00000000000..4088d32d656 Binary files /dev/null and b/packages/docs/static/img/remotion-3-3.png differ diff --git a/packages/example/public/vp8-opus-5-1-channels.webm b/packages/example/public/vp8-opus-5-1-channels.webm new file mode 100644 index 00000000000..a272ee5aae8 Binary files /dev/null and b/packages/example/public/vp8-opus-5-1-channels.webm differ diff --git a/packages/example/src/DecoderDemo.tsx b/packages/example/src/DecoderDemo.tsx index eaa277c75e7..4c373590e63 100644 --- a/packages/example/src/DecoderDemo.tsx +++ b/packages/example/src/DecoderDemo.tsx @@ -55,6 +55,10 @@ export const DecoderDemo: React.FC = () => { label="transparent-with-dar.webm" src={staticFile('transparent-with-dar.webm')} /> +
); diff --git a/packages/example/src/Encoder/SrcEncoder.tsx b/packages/example/src/Encoder/SrcEncoder.tsx index aa431c58328..74efdb08120 100644 --- a/packages/example/src/Encoder/SrcEncoder.tsx +++ b/packages/example/src/Encoder/SrcEncoder.tsx @@ -1,18 +1,5 @@ -import { - MediaFn, - MediaParserInternals, - OnAudioTrack, - OnVideoTrack, - VideoTrack, - parseMedia, -} from '@remotion/media-parser'; -import {webFsWriter} from '@remotion/media-parser/web-fs'; -import { - createAudioDecoder, - createAudioEncoder, - createVideoDecoder, - createVideoEncoder, -} from '@remotion/webcodecs'; +import {VideoTrack} from '@remotion/media-parser'; +import {ConvertMediaState, convertMedia} from '@remotion/webcodecs'; import React, {useCallback, useRef, useState} from 'react'; import {flushSync} from 'react-dom'; import {AbsoluteFill} from 'remotion'; @@ -48,53 +35,29 @@ const SampleLabel: React.FC<{ const SampleCount: React.FC<{ count: number; label: string; - errored: boolean; -}> = ({count, label, errored}) => { +}> = ({count, label}) => { return ( -
+
{label} {count}
); }; -type State = { - videoFrames: number; - audioFrames: number; - encodedVideoFrames: number; - encodedAudioFrames: number; - videoError: DOMException | null; - audioError: DOMException | null; -}; - export const SrcEncoder: React.FC<{ src: string; label: string; }> = ({src, label}) => { - const [state, setRawState] = useState({ - audioFrames: 0, - videoFrames: 0, + const [state, setState] = useState({ + decodedAudioFrames: 0, + decodedVideoFrames: 0, encodedVideoFrames: 0, encodedAudioFrames: 0, - audioError: null, - videoError: null, }); - const stateRef = useRef(state); const [downloadFn, setDownloadFn] = useState void)>(null); - - const setState: React.Dispatch> = useCallback( - (newState) => { - if (typeof newState === 'function') { - stateRef.current = newState(stateRef.current); - setRawState(stateRef.current); - return; - } - stateRef.current = newState; - setRawState(newState); - }, - [], - ); + const [abortfn, setAbortFn] = useState void)>(null); + const [error, setError] = useState(null); const ref = useRef(null); @@ -157,193 +120,45 @@ export const SrcEncoder: React.FC<{ context.drawImage(image, fitted.left, 0, fitted.width, fitted.height); } } - flushSync(() => { - setState((s) => ({...s, videoFrames: s.videoFrames + 1})); - }); }, - [setState], - ); - - const onVideoTrack = useCallback( - (mediaState: MediaFn): OnVideoTrack => - async (track) => { - if (!mediaState) { - throw new Error('mediaState is null'); - } - - const {trackNumber} = await mediaState.addTrack({ - type: 'video', - color: { - transferChracteristics: 'bt709', - matrixCoefficients: 'bt709', - primaries: 'bt709', - fullRange: true, - }, - width: track.codedWidth, - height: track.codedHeight, - codecId: 'V_VP8', - }); - - const videoEncoder = await createVideoEncoder({ - width: track.displayAspectWidth, - height: track.displayAspectHeight, - onChunk: async (chunk) => { - await mediaState.addSample(chunk, trackNumber); - const newDuration = Math.round( - (chunk.timestamp + (chunk.duration ?? 0)) / 1000, - ); - await mediaState.updateDuration(newDuration); - flushSync(() => { - setState((s) => ({ - ...s, - encodedVideoFrames: s.encodedVideoFrames + 1, - })); - }); - }, - onError: (err) => { - // TODO: Do error handling - console.log(err); - }, - }); - if (videoEncoder === null) { - setState((s) => ({ - ...s, - videoError: new DOMException('Video encoder not supported'), - })); - return null; - } - - const videoDecoder = await createVideoDecoder({ - track, - onFrame: async (frame) => { - await onVideoFrame(frame, track); - await videoEncoder.encodeFrame(frame); - frame.close(); - }, - onError: (err) => { - // TODO: Do error handling - console.log(err); - }, - }); - if (videoDecoder === null) { - setState((s) => ({ - ...s, - videoError: new DOMException('Video decoder not supported'), - })); - return null; - } - - mediaState.addWaitForFinishPromise(async () => { - await videoDecoder.waitForFinish(); - await videoEncoder.waitForFinish(); - videoDecoder.close(); - videoEncoder.close(); - }); - - return async (chunk) => { - await videoDecoder.processSample(chunk); - }; - }, - [onVideoFrame, setState], - ); - - const onAudioTrack = useCallback( - (mediaState: MediaFn): OnAudioTrack => - async (track) => { - const {trackNumber} = await mediaState.addTrack({ - type: 'audio', - codecId: 'A_OPUS', - numberOfChannels: track.numberOfChannels, - sampleRate: track.sampleRate, - }); - - const audioEncoder = await createAudioEncoder({ - onChunk: async (chunk) => { - await mediaState.addSample(chunk, trackNumber); - - flushSync(() => { - setState((s) => ({ - ...s, - encodedAudioFrames: s.encodedAudioFrames + 1, - })); - }); - }, - sampleRate: track.sampleRate, - numberOfChannels: track.numberOfChannels, - onError: (err) => { - // TODO: Do error handling - console.log(err); - }, - }); - - if (!audioEncoder) { - setState((s) => ({ - ...s, - audioError: new DOMException('Audio encoder not supported'), - })); - return null; - } - - const audioDecoder = await createAudioDecoder({ - track, - onFrame: async (frame) => { - await audioEncoder.encodeFrame(frame); - - flushSync(() => { - setState((s) => ({...s, audioFrames: s.audioFrames + 1})); - }); - frame.close(); - }, - onError(error) { - // TODO: Do better error handling - setState((s) => ({...s, audioError: error})); - }, - }); - - if (!audioDecoder) { - setState((s) => ({ - ...s, - audioError: new DOMException('Audio decoder not supported'), - })); - return null; - } - - mediaState.addWaitForFinishPromise(async () => { - await audioDecoder.waitForFinish(); - await audioEncoder.waitForFinish(); - audioDecoder.close(); - audioEncoder.close(); - }); - - return async (audioSample) => { - await audioDecoder.processSample(audioSample); - }; - }, - [setState], + [], ); - const onClick = useCallback(() => { - MediaParserInternals.createMedia(webFsWriter) - .then((state) => { - parseMedia({ - src, - onVideoTrack: onVideoTrack(state), - onAudioTrack: onAudioTrack(state), - }) - .then(() => { - return state.waitForFinish(); - }) - .then(() => { - setDownloadFn(() => state.save); - }) - .catch((err) => { - console.error(err); + const onClick = useCallback(async () => { + try { + const abortController = new AbortController(); + setAbortFn(() => () => abortController.abort()); + const fn = await convertMedia({ + src, + onVideoFrame, + onMediaStateUpdate: (s) => { + flushSync(() => { + setState(() => s); }); - }) - .catch((err) => { - console.error(err); + }, + videoCodec: 'vp8', + audioCodec: 'opus', + to: 'webm', + signal: abortController.signal, + }); + setDownloadFn(() => { + return async () => { + const file = await fn.save(); + const a = document.createElement('a'); + a.href = URL.createObjectURL(file); + a.download = 'hithere'; + a.click(); + + setTimeout(() => { + fn.remove(); + }, 1000); + }; }); - }, [onAudioTrack, onVideoTrack, src]); + } catch (err) { + console.log(err); + setError(err as Error); + } + }, [onVideoFrame, src]); return (
{label}{' '}
- + + {error ? ( +
{error.message}
+ ) : downloadFn ? ( + + ) : abortfn ? ( + + ) : ( + + )}
- - - - + + + +
- - {downloadFn ? ( - - ) : null}
diff --git a/packages/example/src/Root.tsx b/packages/example/src/Root.tsx index 86781df7054..69ad6d8a9b2 100644 --- a/packages/example/src/Root.tsx +++ b/packages/example/src/Root.tsx @@ -1444,7 +1444,7 @@ export const Index: React.FC = () => { diff --git a/packages/media-parser/.npmignore b/packages/media-parser/.npmignore index 6d3592b24a3..0c8f929351d 100644 --- a/packages/media-parser/.npmignore +++ b/packages/media-parser/.npmignore @@ -1,2 +1,9 @@ dist/test vp8-segments +input.webm +src +tsconfig.json +tsconfig.tsbuildinfo +bundle.ts +.turbo +.eslintrc diff --git a/packages/media-parser/buffer.js b/packages/media-parser/buffer.js new file mode 100644 index 00000000000..17d096daa38 --- /dev/null +++ b/packages/media-parser/buffer.js @@ -0,0 +1,2 @@ +// For backwards compatibility when you use Metro +module.exports = require('./dist/writers/buffer'); diff --git a/packages/media-parser/bundle.ts b/packages/media-parser/bundle.ts new file mode 100644 index 00000000000..61b0c2c7581 --- /dev/null +++ b/packages/media-parser/bundle.ts @@ -0,0 +1,30 @@ +import {build} from 'bun'; +import path from 'path'; + +if (process.env.NODE_ENV !== 'production') { + throw new Error('This script must be run using NODE_ENV=production'); +} + +const output = await build({ + entrypoints: [ + 'src/index.ts', + 'src/readers/from-web-file.ts', + 'src/readers/from-fetch.ts', + 'src/readers/from-node.ts', + 'src/writers/buffer.ts', + 'src/writers/web-fs.ts', + ], + external: ['stream'], + naming: '[name].mjs', + target: 'node', +}); +if (!output.success) { + process.exit(1); +} + +for (const file of output.outputs) { + const str = await file.text(); + const out = path.join('dist', 'esm', file.path); + + await Bun.write(out, str); +} diff --git a/packages/media-parser/fetch.js b/packages/media-parser/fetch.js new file mode 100644 index 00000000000..43cde069adf --- /dev/null +++ b/packages/media-parser/fetch.js @@ -0,0 +1,2 @@ +// For backwards compatibility when you use Metro +module.exports = require('./dist/readers/from-fetch'); diff --git a/packages/media-parser/node.js b/packages/media-parser/node.js new file mode 100644 index 00000000000..ecc324667ce --- /dev/null +++ b/packages/media-parser/node.js @@ -0,0 +1,2 @@ +// For backwards compatibility when you use Metro +module.exports = require('./dist/readers/from-node'); diff --git a/packages/media-parser/package.json b/packages/media-parser/package.json index dc3a968d96b..43b302a426c 100644 --- a/packages/media-parser/package.json +++ b/packages/media-parser/package.json @@ -10,7 +10,8 @@ "formatting": "prettier src --check", "lint": "eslint src --ext ts,tsx", "test": "bun test src/test", - "watch": "tsc -w" + "watch": "tsc -w", + "build": "bun --env-file=../.env.bundle bundle.ts" }, "devDependencies": { "@remotion/renderer": "workspace:*", @@ -23,11 +24,42 @@ "url": "https://github.com/remotion-dev/remotion/issues" }, "exports": { - ".": "./dist/index.js", - "./node": "./dist/readers/from-node.js", - "./fetch": "./dist/readers/from-fetch.js", - "./web-file": "./dist/readers/from-web-file.js", - "./web-fs": "./dist/writers/web-fs.js", + ".": { + "require": "./dist/index.js", + "module": "./dist/esm/index.mjs", + "types": "./dist/index.d.ts", + "import": "./dist/esm/index.mjs" + }, + "./node": { + "require": "./dist/readers/from-node.js", + "module": "./dist/esm/from-node.mjs", + "types": "./dist/readers/from-node.d.ts", + "import": "./dist/esm/from-node.mjs" + }, + "./fetch": { + "require": "./dist/readers/from-fetch.js", + "module": "./dist/esm/from-fetch.mjs", + "types": "./dist/readers/from-fetch.d.ts", + "import": "./dist/esm/from-fetch.mjs" + }, + "./web-file": { + "require": "./dist/readers/from-web-file.js", + "module": "./dist/esm/from-web-file.mjs", + "types": "./dist/readers/from-web-file.d.ts", + "import": "./dist/esm/from-web-file.mjs" + }, + "./web-fs": { + "require": "./dist/writers/web-fs.js", + "module": "./dist/esm/web-fs.mjs", + "types": "./dist/writers/web-fs.d.ts", + "import": "./dist/esm/web-fs.mjs" + }, + "./buffer": { + "require": "./dist/writers/buffer.js", + "module": "./dist/esm/buffer.mjs", + "types": "./dist/writers/buffer.d.ts", + "import": "./dist/esm/buffer.mjs" + }, "./package.json": "./package.json" }, "typesVersions": { @@ -43,6 +75,9 @@ ], "web-fs": [ "dist/writers/web-fs.d.ts" + ], + "buffer": [ + "dist/writers/buffer.d.ts" ] } }, diff --git a/packages/media-parser/src/boxes/iso-base-media/get-sample-positions-from-track.ts b/packages/media-parser/src/boxes/iso-base-media/get-sample-positions-from-track.ts index 93b6a396ffe..8b856242ef4 100644 --- a/packages/media-parser/src/boxes/iso-base-media/get-sample-positions-from-track.ts +++ b/packages/media-parser/src/boxes/iso-base-media/get-sample-positions-from-track.ts @@ -3,6 +3,7 @@ import type {SamplePosition} from '../../get-sample-positions'; import {getSamplePositions} from '../../get-sample-positions'; import type {IsoBaseMediaBox} from '../../parse-result'; import {getSamplesFromMoof} from '../../samples-from-moof'; +import type {TrakBox} from './trak/trak'; import { getCttsBox, getStcoBox, @@ -11,8 +12,7 @@ import { getStszBox, getSttsBox, getTkhdBox, -} from '../../traversal'; -import type {TrakBox} from './trak/trak'; +} from './traversal'; export const getSamplePositionsFromTrack = ( trakBox: TrakBox, diff --git a/packages/media-parser/src/boxes/iso-base-media/make-track.ts b/packages/media-parser/src/boxes/iso-base-media/make-track.ts index 7614dd36437..208f8028bb4 100644 --- a/packages/media-parser/src/boxes/iso-base-media/make-track.ts +++ b/packages/media-parser/src/boxes/iso-base-media/make-track.ts @@ -1,4 +1,5 @@ import { + getAudioCodecFromTrack, getAudioCodecStringFromTrak, getNumberOfChannelsFromTrak, getSampleRate, @@ -13,12 +14,17 @@ import { applyTkhdBox, getDisplayAspectRatio, getSampleAspectRatio, - getVideoSample, + getStsdVideoConfig, } from '../../get-sample-aspect-ratio'; import type {AudioTrack, OtherTrack, VideoTrack} from '../../get-tracks'; -import {getVideoCodecString} from '../../get-video-codec'; -import {getTkhdBox, getVideoDescriptors} from '../../traversal'; +import { + getIsoBmColrConfig, + getVideoCodecFromIsoTrak, + getVideoCodecString, + getVideoPrivateData, +} from '../../get-video-codec'; import type {TrakBox} from './trak/trak'; +import {getTkhdBox, getVideoDescriptors} from './traversal'; export const makeBaseMediaTrack = ( trakBox: TrakBox, @@ -58,6 +64,8 @@ export const makeBaseMediaTrack = ( sampleRate, description, trakBox, + codecPrivate: null, + codecWithoutConfig: getAudioCodecFromTrack(trakBox), }; } @@ -70,7 +78,7 @@ export const makeBaseMediaTrack = ( }; } - const videoSample = getVideoSample(trakBox); + const videoSample = getStsdVideoConfig(trakBox); if (!videoSample) { throw new Error('No video sample'); } @@ -95,6 +103,8 @@ export const makeBaseMediaTrack = ( throw new Error('Could not find video codec'); } + const privateData = getVideoPrivateData(trakBox); + const track: VideoTrack = { type: 'video', trackId: tkhdBox.trackId, @@ -111,6 +121,14 @@ export const makeBaseMediaTrack = ( displayAspectHeight, rotation, trakBox, + codecPrivate: privateData, + color: getIsoBmColrConfig(trakBox) ?? { + fullRange: null, + matrixCoefficients: null, + primaries: null, + transferCharacteristics: null, + }, + codecWithoutConfig: getVideoCodecFromIsoTrak(trakBox), }; return track; }; diff --git a/packages/media-parser/src/boxes/iso-base-media/mdat/mdat.ts b/packages/media-parser/src/boxes/iso-base-media/mdat/mdat.ts index a3a177e3733..5058ed4b24d 100644 --- a/packages/media-parser/src/boxes/iso-base-media/mdat/mdat.ts +++ b/packages/media-parser/src/boxes/iso-base-media/mdat/mdat.ts @@ -3,9 +3,9 @@ import type {BufferIterator} from '../../../buffer-iterator'; import {getTracks, hasTracks} from '../../../get-tracks'; import type {AnySegment} from '../../../parse-result'; import type {ParserContext} from '../../../parser-context'; -import {getMoofBox} from '../../../traversal'; import {getSamplePositionsFromTrack} from '../get-sample-positions-from-track'; import type {TrakBox} from '../trak/trak'; +import {getMoofBox} from '../traversal'; export interface MdatBox { type: 'mdat-box'; @@ -20,12 +20,14 @@ export const parseMdat = async ({ fileOffset, existingBoxes, options, + signal, }: { data: BufferIterator; size: number; fileOffset: number; existingBoxes: AnySegment[]; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const alreadyHas = hasTracks(existingBoxes); if (!alreadyHas) { @@ -66,6 +68,10 @@ export const parseMdat = async ({ // eslint-disable-next-line no-constant-condition while (true) { + if (signal && signal.aborted) { + break; + } + const samplesWithIndex = flatSamples.find((sample) => { return sample.samplePosition.offset === data.counter.getOffset(); }); diff --git a/packages/media-parser/src/boxes/iso-base-media/moov/moov.ts b/packages/media-parser/src/boxes/iso-base-media/moov/moov.ts index c6624145e98..fe82939e452 100644 --- a/packages/media-parser/src/boxes/iso-base-media/moov/moov.ts +++ b/packages/media-parser/src/boxes/iso-base-media/moov/moov.ts @@ -14,11 +14,13 @@ export const parseMoov = async ({ offset, size, options, + signal, }: { iterator: BufferIterator; offset: number; size: number; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const children = await parseBoxes({ iterator, @@ -28,6 +30,7 @@ export const parseMoov = async ({ options, continueMdat: false, littleEndian: false, + signal, }); if (children.status === 'incomplete') { diff --git a/packages/media-parser/src/boxes/iso-base-media/process-box.ts b/packages/media-parser/src/boxes/iso-base-media/process-box.ts index 081e887753d..b0112b91118 100644 --- a/packages/media-parser/src/boxes/iso-base-media/process-box.ts +++ b/packages/media-parser/src/boxes/iso-base-media/process-box.ts @@ -8,7 +8,6 @@ import type { } from '../../parse-result'; import type {BoxAndNext, PartialMdatBox} from '../../parse-video'; import type {ParserContext} from '../../parser-context'; -import {hasSkippedMdatProcessing} from '../../traversal'; import {parseEsds} from './esds/esds'; import {parseFtyp} from './ftyp'; import {makeBaseMediaTrack} from './make-track'; @@ -33,6 +32,7 @@ import {parseTfdt} from './tfdt'; import {getTfhd} from './tfhd'; import {parseTkhd} from './tkhd'; import {parseTrak} from './trak/trak'; +import {hasSkippedMdatProcessing} from './traversal'; import {parseTrun} from './trun'; const getChildren = async ({ @@ -41,12 +41,14 @@ const getChildren = async ({ bytesRemainingInBox, options, littleEndian, + signal, }: { boxType: string; iterator: BufferIterator; bytesRemainingInBox: number; options: ParserContext; littleEndian: boolean; + signal: AbortSignal | null; }) => { const parseChildren = boxType === 'mdia' || @@ -67,6 +69,7 @@ const getChildren = async ({ options, continueMdat: false, littleEndian, + signal, }); if (parsed.status === 'incomplete') { @@ -90,12 +93,14 @@ export const parseMdatPartially = async ({ fileOffset, parsedBoxes, options, + signal, }: { iterator: BufferIterator; boxSize: number; fileOffset: number; parsedBoxes: AnySegment[]; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const box = await parseMdat({ data: iterator, @@ -103,6 +108,7 @@ export const parseMdatPartially = async ({ fileOffset, existingBoxes: parsedBoxes, options, + signal, }); if ( @@ -130,12 +136,14 @@ export const processBox = async ({ parsedBoxes, options, littleEndian, + signal, }: { iterator: BufferIterator; allowIncompleteBoxes: boolean; parsedBoxes: AnySegment[]; options: ParserContext; littleEndian: boolean; + signal: AbortSignal | null; }): Promise => { const fileOffset = iterator.counter.getOffset(); const bytesRemaining = iterator.bytesRemaining(); @@ -205,6 +213,7 @@ export const processBox = async ({ fileOffset, parsedBoxes, options, + signal, }); } } @@ -293,6 +302,7 @@ export const processBox = async ({ offset: fileOffset, size: boxSize, options, + signal, }); return { @@ -401,6 +411,7 @@ export const processBox = async ({ size: boxSize, options, littleEndian, + signal, }); return { @@ -417,6 +428,7 @@ export const processBox = async ({ offset: fileOffset, size: boxSize, options, + signal, }); return { @@ -433,6 +445,7 @@ export const processBox = async ({ size: boxSize, offsetAtStart: fileOffset, options, + signal, }); const transformedTrack = makeBaseMediaTrack(box); if (transformedTrack) { @@ -571,6 +584,7 @@ export const processBox = async ({ fileOffset, existingBoxes: parsedBoxes, options, + signal, }); return { @@ -590,6 +604,7 @@ export const processBox = async ({ bytesRemainingInBox, options, littleEndian, + signal, }); return { @@ -614,6 +629,7 @@ export const parseBoxes = async ({ options, continueMdat, littleEndian, + signal, }: { iterator: BufferIterator; maxBytes: number; @@ -622,6 +638,7 @@ export const parseBoxes = async ({ options: ParserContext; continueMdat: false | PartialMdatBox; littleEndian: boolean; + signal: AbortSignal | null; }): Promise => { let boxes: IsoBaseMediaBox[] = initialBoxes; const initialOffset = iterator.counter.getOffset(); @@ -638,6 +655,7 @@ export const parseBoxes = async ({ fileOffset: continueMdat.fileOffset, parsedBoxes: initialBoxes, options, + signal, }) : await processBox({ iterator, @@ -645,6 +663,7 @@ export const parseBoxes = async ({ parsedBoxes: initialBoxes, options, littleEndian, + signal, }); if (result.type === 'incomplete') { @@ -664,6 +683,7 @@ export const parseBoxes = async ({ options, continueMdat: false, littleEndian, + signal, }); }, skipTo: null, @@ -684,6 +704,7 @@ export const parseBoxes = async ({ options, continueMdat: result, littleEndian, + signal, }), ); }, @@ -712,6 +733,7 @@ export const parseBoxes = async ({ options, continueMdat: false, littleEndian, + signal, }); }, skipTo: result.skipTo, @@ -735,6 +757,7 @@ export const parseBoxes = async ({ options, continueMdat: false, littleEndian, + signal, }); }, skipTo: mdatState.fileOffset, diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/avcc.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/avcc.ts index 17a8ae5a49a..304befc8758 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/avcc.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/avcc.ts @@ -2,7 +2,7 @@ import type {BufferIterator} from '../../../buffer-iterator'; export interface AvccBox { type: 'avcc-box'; - description: Uint8Array; + privateData: Uint8Array; configurationString: string; } @@ -26,11 +26,11 @@ export const parseAvcc = ({ data.counter.decrement(4); - const description = data.getSlice(size - 8); + const privateData = data.getSlice(size - 8); return { type: 'avcc-box', - description, + privateData, configurationString: str, }; }; diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/ctts.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/ctts.ts index 9315c3488e4..44fbf2d821d 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/ctts.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/ctts.ts @@ -39,12 +39,9 @@ export const parseCtts = ({ // V1 = signed, V0 = unsigned // however some files are buggy - // Let's do the same thing as mp4box but uint32, based on our test set of videos + // Let's do the same thing as mp4box // https://github.com/gpac/mp4box.js/blob/c6cc468145bc5b031b866446111f29c8b620dbe6/src/parsing/ctts.js#L2 - const sampleOffset = iterator.getUint32(); - if (sampleOffset < 0) { - throw new Error('ctts box uses negative values without using version 1'); - } + const sampleOffset = iterator.getInt32(); entries.push({ sampleCount, diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/hvcc.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/hvcc.ts index 3a55a0971d0..181a46152f5 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/hvcc.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/hvcc.ts @@ -3,7 +3,7 @@ import {getHvc1CodecString} from '../../../make-hvc1-codec-strings'; export interface HvccBox { type: 'hvcc-box'; - data: Uint8Array; + privateData: Uint8Array; configurationString: string; } @@ -16,7 +16,7 @@ export const parseHvcc = ({ size: number; offset: number; }): HvccBox => { - const raw = data.getSlice(size - 8); + const privateData = data.getSlice(size - 8); data.counter.decrement(size - 8); const constraintString = getHvc1CodecString(data); @@ -26,7 +26,7 @@ export const parseHvcc = ({ return { type: 'hvcc-box', - data: raw, + privateData, configurationString: constraintString, }; }; diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/mebx.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/mebx.ts index 76dd7851272..7670ce346a4 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/mebx.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/mebx.ts @@ -17,12 +17,14 @@ export const parseMebx = async ({ size, options, littleEndian, + signal, }: { iterator: BufferIterator; offset: number; size: number; options: ParserContext; littleEndian: boolean; + signal: AbortSignal | null; }): Promise => { // reserved, 6 bit iterator.discard(6); @@ -37,6 +39,7 @@ export const parseMebx = async ({ options, continueMdat: false, littleEndian, + signal, }); if (children.status === 'incomplete') { diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/samples.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/samples.ts index b65b2b97113..0d2301ac3ed 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/samples.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/samples.ts @@ -120,9 +120,11 @@ const audioTags = [ export const processSample = async ({ iterator, options, + signal, }: { iterator: BufferIterator; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const fileOffset = iterator.counter.getOffset(); const bytesRemaining = iterator.bytesRemaining(); @@ -163,6 +165,7 @@ export const processSample = async ({ const version = iterator.getUint16(); const revisionLevel = iterator.getUint16(); const vendor = iterator.getSlice(4); + if (version === 0) { const numberOfChannels = iterator.getUint16(); const sampleSize = iterator.getUint16(); @@ -180,6 +183,7 @@ export const processSample = async ({ options, continueMdat: false, littleEndian: false, + signal, }); if (children.status === 'incomplete') { @@ -234,6 +238,7 @@ export const processSample = async ({ options, continueMdat: false, littleEndian: false, + signal, }); if (children.status === 'incomplete') { @@ -264,6 +269,64 @@ export const processSample = async ({ }; } + if (version === 2) { + const numberOfChannels = iterator.getUint16(); + const sampleSize = iterator.getUint16(); + const compressionId = iterator.getUint16(); + const packetSize = iterator.getUint16(); + iterator.getFixedPointUnsigned1616Number(); // LQ sample rate; + + iterator.getUint32(); // ignore + const higherSampleRate = iterator.getFloat64(); + iterator.getUint32(); // ignore; + iterator.getUint32(); // ignore, always 0x7F000000? + const bitsPerCodedSample = iterator.getUint32(); + iterator.getUint32(); // ignore; + const bytesPerFrame = iterator.getUint32(); + const samplesPerPacket = iterator.getUint32(); + + const bytesRemainingInBox = + boxSize - (iterator.counter.getOffset() - fileOffset); + + const children = await parseBoxes({ + iterator, + allowIncompleteBoxes: false, + maxBytes: bytesRemainingInBox, + initialBoxes: [], + options, + continueMdat: false, + littleEndian: false, + signal, + }); + + if (children.status === 'incomplete') { + throw new Error('Incomplete boxes are not allowed'); + } + + return { + sample: { + format: boxFormat, + offset: fileOffset, + dataReferenceIndex, + version, + revisionLevel, + vendor: [...Array.from(new Uint8Array(vendor))], + size: boxSize, + type: 'audio', + numberOfChannels, + sampleSize, + compressionId, + packetSize, + sampleRate: higherSampleRate, + samplesPerPacket, + bytesPerPacket: null, + bytesPerFrame, + bitsPerSample: bitsPerCodedSample, + children: children.segments, + }, + }; + } + throw new Error(`Unsupported version ${version}`); } @@ -286,15 +349,20 @@ export const processSample = async ({ const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset); - const children = await parseBoxes({ - iterator, - allowIncompleteBoxes: false, - maxBytes: bytesRemainingInBox, - initialBoxes: [], - options, - continueMdat: false, - littleEndian: false, - }); + const children = + bytesRemainingInBox > 8 + ? await parseBoxes({ + iterator, + allowIncompleteBoxes: false, + maxBytes: bytesRemainingInBox, + initialBoxes: [], + options, + continueMdat: false, + littleEndian: false, + signal, + }) + : (iterator.discard(bytesRemainingInBox), + {status: 'done', segments: []}); if (children.status === 'incomplete') { throw new Error('Incomplete boxes are not allowed'); @@ -333,10 +401,12 @@ export const parseSamples = async ({ iterator, maxBytes, options, + signal, }: { iterator: BufferIterator; maxBytes: number; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const samples: Sample[] = []; const initialOffset = iterator.counter.getOffset(); @@ -348,6 +418,7 @@ export const parseSamples = async ({ const {sample} = await processSample({ iterator, options, + signal, }); if (sample) { diff --git a/packages/media-parser/src/boxes/iso-base-media/stsd/stsd.ts b/packages/media-parser/src/boxes/iso-base-media/stsd/stsd.ts index 92ce5a4c8ee..618dd85d0ed 100644 --- a/packages/media-parser/src/boxes/iso-base-media/stsd/stsd.ts +++ b/packages/media-parser/src/boxes/iso-base-media/stsd/stsd.ts @@ -15,11 +15,13 @@ export const parseStsd = async ({ offset, size, options, + signal, }: { iterator: BufferIterator; offset: number; size: number; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const version = iterator.getUint8(); if (version !== 0) { @@ -37,6 +39,7 @@ export const parseStsd = async ({ iterator, maxBytes: bytesRemainingInBox, options, + signal, }); if (boxes.length !== numberOfEntries) { diff --git a/packages/media-parser/src/boxes/iso-base-media/trak/trak.ts b/packages/media-parser/src/boxes/iso-base-media/trak/trak.ts index 4dbdb3a778c..1975069d880 100644 --- a/packages/media-parser/src/boxes/iso-base-media/trak/trak.ts +++ b/packages/media-parser/src/boxes/iso-base-media/trak/trak.ts @@ -14,11 +14,13 @@ export const parseTrak = async ({ size, offsetAtStart, options, + signal, }: { data: BufferIterator; size: number; offsetAtStart: number; options: ParserContext; + signal: AbortSignal | null; }): Promise => { const children = await parseBoxes({ iterator: data, @@ -28,6 +30,7 @@ export const parseTrak = async ({ options, continueMdat: false, littleEndian: false, + signal, }); if (children.status === 'incomplete') { diff --git a/packages/media-parser/src/boxes/iso-base-media/traversal.ts b/packages/media-parser/src/boxes/iso-base-media/traversal.ts new file mode 100644 index 00000000000..b73ca8d178b --- /dev/null +++ b/packages/media-parser/src/boxes/iso-base-media/traversal.ts @@ -0,0 +1,305 @@ +import type {AnySegment, IsoBaseMediaBox, RegularBox} from '../../parse-result'; +import type {FtypBox} from './ftyp'; +import type {MdhdBox} from './mdhd'; +import type {MoovBox} from './moov/moov'; +import type {MvhdBox} from './mvhd'; +import type {CttsBox} from './stsd/ctts'; +import type {StcoBox} from './stsd/stco'; +import type {StscBox} from './stsd/stsc'; +import type {StsdBox} from './stsd/stsd'; +import type {StssBox} from './stsd/stss'; +import type {StszBox} from './stsd/stsz'; +import type {SttsBox} from './stsd/stts'; +import type {TfdtBox} from './tfdt'; +import type {TfhdBox} from './tfhd'; +import type {TkhdBox} from './tkhd'; +import type {TrakBox} from './trak/trak'; +import type {TrunBox} from './trun'; + +export const getFtypBox = (segments: AnySegment[]): FtypBox | null => { + const ftypBox = segments.find((s) => s.type === 'ftyp-box'); + if (!ftypBox || ftypBox.type !== 'ftyp-box') { + return null; + } + + return ftypBox; +}; + +export const getMoovBox = (segments: AnySegment[]): MoovBox | null => { + const moovBox = segments.find((s) => s.type === 'moov-box'); + if (!moovBox || moovBox.type !== 'moov-box') { + return null; + } + + return moovBox; +}; + +export const getMoofBox = (main: AnySegment[]): IsoBaseMediaBox | null => { + const moofBox = main.find( + (s) => s.type === 'regular-box' && s.boxType === 'moof', + ); + + if (!moofBox || moofBox.type !== 'regular-box') { + return null; + } + + return moofBox; +}; + +export const getMvhdBox = (moovBox: MoovBox): MvhdBox | null => { + const mvHdBox = moovBox.children.find((s) => s.type === 'mvhd-box'); + + if (!mvHdBox || mvHdBox.type !== 'mvhd-box') { + return null; + } + + return mvHdBox; +}; + +export const getTraks = (moovBox: MoovBox): TrakBox[] => { + return moovBox.children.filter((s) => s.type === 'trak-box') as TrakBox[]; +}; + +export const getTkhdBox = (trakBox: TrakBox): TkhdBox | null => { + const tkhdBox = trakBox.children.find( + (s) => s.type === 'tkhd-box', + ) as TkhdBox | null; + + return tkhdBox; +}; + +export const getMdiaBox = (trakBox: TrakBox): RegularBox | null => { + const mdiaBox = trakBox.children.find( + (s) => s.type === 'regular-box' && s.boxType === 'mdia', + ); + + if (!mdiaBox || mdiaBox.type !== 'regular-box') { + return null; + } + + return mdiaBox; +}; + +export const getMdhdBox = (trakBox: TrakBox): MdhdBox | null => { + const mdiaBox = getMdiaBox(trakBox); + + if (!mdiaBox) { + return null; + } + + const mdhdBox = mdiaBox.children.find( + (c) => c.type === 'mdhd-box', + ) as MdhdBox | null; + + return mdhdBox; +}; + +export const getStblBox = (trakBox: TrakBox): RegularBox | null => { + const mdiaBox = getMdiaBox(trakBox); + + if (!mdiaBox) { + return null; + } + + const minfBox = mdiaBox.children.find( + (s) => s.type === 'regular-box' && s.boxType === 'minf', + ); + + if (!minfBox || minfBox.type !== 'regular-box') { + return null; + } + + const stblBox = minfBox.children.find( + (s) => s.type === 'regular-box' && s.boxType === 'stbl', + ); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + return stblBox; +}; + +export const getStsdBox = (trakBox: TrakBox): StsdBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const stsdBox = stblBox.children.find( + (s) => s.type === 'stsd-box', + ) as StsdBox | null; + + return stsdBox; +}; + +export const getVideoDescriptors = (trakBox: TrakBox): Uint8Array | null => { + const stsdBox = getStsdBox(trakBox); + + if (!stsdBox) { + return null; + } + + const descriptors = stsdBox.samples.map((s) => { + return s.type === 'video' + ? s.descriptors.map((d) => { + return d.type === 'avcc-box' + ? d.privateData + : d.type === 'hvcc-box' + ? d.privateData + : null; + }) + : []; + }); + + return descriptors.flat(1).filter(Boolean)[0] ?? null; +}; + +export const getStcoBox = (trakBox: TrakBox): StcoBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const stcoBox = stblBox.children.find( + (s) => s.type === 'stco-box', + ) as StcoBox | null; + + return stcoBox; +}; + +export const getSttsBox = (trakBox: TrakBox): SttsBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const sttsBox = stblBox.children.find( + (s) => s.type === 'stts-box', + ) as SttsBox | null; + + return sttsBox; +}; + +export const getCttsBox = (trakBox: TrakBox): CttsBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const cttsBox = stblBox.children.find( + (s) => s.type === 'ctts-box', + ) as CttsBox | null; + + return cttsBox; +}; + +export const getStszBox = (trakBox: TrakBox): StszBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const stszBox = stblBox.children.find( + (s) => s.type === 'stsz-box', + ) as StszBox | null; + + return stszBox; +}; + +export const getStscBox = (trakBox: TrakBox): StscBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const stcoBox = stblBox.children.find( + (b) => b.type === 'stsc-box', + ) as StscBox | null; + + return stcoBox; +}; + +export const getStssBox = (trakBox: TrakBox): StssBox | null => { + const stblBox = getStblBox(trakBox); + + if (!stblBox || stblBox.type !== 'regular-box') { + return null; + } + + const stssBox = stblBox.children.find( + (b) => b.type === 'stss-box', + ) as StssBox | null; + + return stssBox; +}; + +export const getTfdtBox = (segment: IsoBaseMediaBox): TfdtBox | null => { + if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { + throw new Error('Expected traf-box'); + } + + const tfhdBox = segment.children.find((c) => c.type === 'tfdt-box'); + + if (!tfhdBox || tfhdBox.type !== 'tfdt-box') { + throw new Error('Expected tfhd-box'); + } + + return tfhdBox; +}; + +export const getTfhdBox = (segment: IsoBaseMediaBox): TfhdBox | null => { + if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { + throw new Error('Expected traf-box'); + } + + const tfhdBox = segment.children.find( + (c) => c.type === 'tfhd-box', + ) as TfhdBox; + + if (!tfhdBox || tfhdBox.type !== 'tfhd-box') { + throw new Error('Expected tfhd-box'); + } + + return tfhdBox; +}; + +export const getTrunBoxes = (segment: IsoBaseMediaBox): TrunBox[] => { + if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { + throw new Error('Expected traf-box'); + } + + const trunBoxes = segment.children.filter((c) => c.type === 'trun-box'); + + return trunBoxes as TrunBox[]; +}; + +export const hasSkippedMdatProcessing = (anySegment: AnySegment[]) => { + const mdat = anySegment.find((b) => b.type === 'mdat-box'); + if (!mdat) { + return { + skipped: false as const, + }; + } + + if (mdat.type !== 'mdat-box') { + throw new Error('Expected mdat-box'); + } + + if (mdat.samplesProcessed) { + return { + skipped: false as const, + }; + } + + return { + skipped: true, + fileOffset: mdat.fileOffset, + }; +}; diff --git a/packages/media-parser/src/boxes/webm/color.ts b/packages/media-parser/src/boxes/webm/color.ts new file mode 100644 index 00000000000..3d5f79c7cce --- /dev/null +++ b/packages/media-parser/src/boxes/webm/color.ts @@ -0,0 +1,143 @@ +import type {VideoTrackColorParams} from '../../get-tracks'; +import {makeMatroskaBytes} from './make-header'; +import type {ColourSegment} from './segments/all-segments'; +import { + getMatrixCoefficientsSegment, + getPrimariesSegment, + getRangeSegment, + getTransferCharacteristicsSegment, +} from './traversal'; + +export const parseColorSegment = ( + colourSegment: ColourSegment, +): VideoTrackColorParams => { + const transferCharacteristics = + getTransferCharacteristicsSegment(colourSegment); + const matrixCoefficients = getMatrixCoefficientsSegment(colourSegment); + const primaries = getPrimariesSegment(colourSegment); + const range = getRangeSegment(colourSegment); + + return { + transferCharacteristics: transferCharacteristics + ? transferCharacteristics.value.value === 1 + ? 'bt709' + : transferCharacteristics.value.value === 6 + ? 'smpte170m' + : transferCharacteristics.value.value === 13 + ? 'iec61966-2-1' + : null + : null, + matrixCoefficients: matrixCoefficients + ? matrixCoefficients.value.value === 1 + ? 'bt709' + : matrixCoefficients.value.value === 6 + ? 'smpte170m' + : matrixCoefficients.value.value === 5 + ? 'bt470bg' + : null + : null, + primaries: primaries + ? primaries.value.value === 1 + ? 'bt709' + : primaries.value.value === 6 + ? 'smpte170m' + : primaries.value.value === 5 + ? 'bt470bg' + : null + : null, + fullRange: + transferCharacteristics?.value.value && matrixCoefficients?.value.value + ? null + : range + ? Boolean(range?.value.value) + : null, + }; +}; + +export const makeMatroskaColorBytes = ({ + transferCharacteristics, + matrixCoefficients, + primaries, + fullRange, +}: VideoTrackColorParams) => { + const rangeValue = + transferCharacteristics && matrixCoefficients + ? 3 + : fullRange === true + ? 2 + : fullRange === false + ? 1 + : 0; + + // https://datatracker.ietf.org/doc/draft-ietf-cellar-matroska/ + // 5.1.4.1.28.27 + const primariesValue = + primaries === 'bt709' + ? 1 + : primaries === 'smpte170m' + ? 6 + : primaries === 'bt470bg' + ? 5 + : 2; + + const transferChracteristicsValue = + transferCharacteristics === 'bt709' + ? 1 + : transferCharacteristics === 'smpte170m' + ? 6 + : transferCharacteristics === 'iec61966-2-1' + ? 13 + : 2; + + if (matrixCoefficients === 'rgb') { + throw new Error('Cannot encode Matroska in RGB'); + } + + const matrixCoefficientsValue = + matrixCoefficients === 'bt709' + ? 1 + : matrixCoefficients === 'bt470bg' + ? 5 + : matrixCoefficients === 'smpte170m' + ? 6 + : 2; + + return makeMatroskaBytes({ + type: 'Colour', + minVintWidth: null, + value: [ + { + type: 'TransferCharacteristics', + value: { + value: transferChracteristicsValue, + byteLength: null, + }, + minVintWidth: null, + }, + { + type: 'MatrixCoefficients', + value: { + value: matrixCoefficientsValue, + byteLength: null, + }, + minVintWidth: null, + }, + { + type: 'Primaries', + value: { + value: primariesValue, + byteLength: null, + }, + minVintWidth: null, + }, + { + type: 'Range', + value: { + value: rangeValue, + byteLength: null, + }, + minVintWidth: null, + }, + ], + }); +}; diff --git a/packages/media-parser/src/boxes/webm/description.ts b/packages/media-parser/src/boxes/webm/description.ts index 572f58002de..7c7ea990116 100644 --- a/packages/media-parser/src/boxes/webm/description.ts +++ b/packages/media-parser/src/boxes/webm/description.ts @@ -1,6 +1,6 @@ import {getArrayBufferIterator} from '../../buffer-iterator'; -import {getCodecSegment, getPrivateData} from '../../traversal'; import type {TrackEntry} from './segments/all-segments'; +import {getCodecSegment, getPrivateData} from './traversal'; export const getAudioDescription = ( track: TrackEntry, diff --git a/packages/media-parser/src/boxes/webm/get-ready-tracks.ts b/packages/media-parser/src/boxes/webm/get-ready-tracks.ts index cdfa511fd29..0d44810ebc2 100644 --- a/packages/media-parser/src/boxes/webm/get-ready-tracks.ts +++ b/packages/media-parser/src/boxes/webm/get-ready-tracks.ts @@ -1,7 +1,7 @@ import type {Track} from '../../get-tracks'; -import {getTracksSegment} from '../../traversal'; -import {getTrack} from './get-track'; +import {getTrack} from './make-track'; import type {MainSegment} from './segments/all-segments'; +import {getTracksSegment} from './traversal'; export const getTracksFromMatroska = ( segment: MainSegment, diff --git a/packages/media-parser/src/boxes/webm/get-sample-from-block.ts b/packages/media-parser/src/boxes/webm/get-sample-from-block.ts index ecbcb448f28..e3366ee0f96 100644 --- a/packages/media-parser/src/boxes/webm/get-sample-from-block.ts +++ b/packages/media-parser/src/boxes/webm/get-sample-from-block.ts @@ -33,7 +33,7 @@ export const getSampleFromBlock = ( throw new Error('Not enough data to get track number, should not happen'); } - const timecodeRelativeToCluster = iterator.getUint16(); + const timecodeRelativeToCluster = iterator.getInt16(); const {keyframe} = parseBlockFlags( iterator, diff --git a/packages/media-parser/src/boxes/webm/get-track.ts b/packages/media-parser/src/boxes/webm/make-track.ts similarity index 73% rename from packages/media-parser/src/boxes/webm/get-track.ts rename to packages/media-parser/src/boxes/webm/make-track.ts index b545f86ea88..b12d83fa3bf 100644 --- a/packages/media-parser/src/boxes/webm/get-track.ts +++ b/packages/media-parser/src/boxes/webm/make-track.ts @@ -1,9 +1,20 @@ import {getArrayBufferIterator} from '../../buffer-iterator'; -import type {AudioTrack, VideoTrack} from '../../get-tracks'; +import type { + AudioTrack, + MediaParserAudioCodec, + MediaParserVideoCodec, + VideoTrack, +} from '../../get-tracks'; import {getHvc1CodecString} from '../../make-hvc1-codec-strings'; +import {parseAv1PrivateData} from './av1-codec-private'; +import {parseColorSegment} from './color'; +import {getAudioDescription} from './description'; +import type {CodecIdSegment, TrackEntry} from './segments/all-segments'; +import {trackTypeToString} from './segments/track-entry'; import { getBitDepth, getCodecSegment, + getColourSegment, getDisplayHeightSegment, getDisplayWidthSegment, getHeightSegment, @@ -13,11 +24,7 @@ import { getTrackId, getTrackTypeSegment, getWidthSegment, -} from '../../traversal'; -import {parseAv1PrivateData} from './av1-codec-private'; -import {getAudioDescription} from './description'; -import type {CodecIdSegment, TrackEntry} from './segments/all-segments'; -import {trackTypeToString} from './segments/track-entry'; +} from './traversal'; const getDescription = (track: TrackEntry): undefined | Uint8Array => { const codec = getCodecSegment(track); @@ -35,6 +42,34 @@ const getDescription = (track: TrackEntry): undefined | Uint8Array => { return undefined; }; +const getMatroskaVideoCodecWithoutConfigString = ({ + codecSegment: codec, +}: { + codecSegment: CodecIdSegment; +}): MediaParserVideoCodec => { + if (codec.value === 'V_VP8') { + return 'vp8'; + } + + if (codec.value === 'V_VP9') { + return 'vp9'; + } + + if (codec.value === 'V_MPEG4/ISO/AVC') { + return 'h264'; + } + + if (codec.value === 'V_AV1') { + return 'av1'; + } + + if (codec.value === 'V_MPEGH/ISO/HEVC') { + return 'h265'; + } + + throw new Error(`Unknown codec: ${codec.value}`); +}; + const getMatroskaVideoCodecString = ({ track, codecSegment: codec, @@ -89,6 +124,59 @@ const getMatroskaVideoCodecString = ({ throw new Error(`Unknown codec: ${codec.value}`); }; +export const getMatroskaAudioCodecWithoutConfigString = ({ + track, +}: { + track: TrackEntry; +}): MediaParserAudioCodec => { + const codec = getCodecSegment(track); + if (!codec) { + throw new Error('Expected codec segment'); + } + + if (codec.value === 'A_OPUS') { + return 'opus'; + } + + if (codec.value === 'A_VORBIS') { + return 'vorbis'; + } + + if (codec.value === 'A_PCM/INT/LIT') { + // https://github.com/ietf-wg-cellar/matroska-specification/issues/142#issuecomment-330004950 + // Audio samples MUST be considered as signed values, except if the audio bit depth is 8 which MUST be interpreted as unsigned values. + + const bitDepth = getBitDepth(track); + if (bitDepth === null) { + throw new Error('Expected bit depth'); + } + + if (bitDepth === 8) { + return 'pcm-u8'; + } + + if (bitDepth === 16) { + return 'pcm-s16'; + } + + if (bitDepth === 24) { + return 'pcm-s24'; + } + + throw new Error('Unknown audio format'); + } + + if (codec.value === 'A_AAC') { + return `aac`; + } + + if (codec.value === 'A_MPEG/L3') { + return 'mp3'; + } + + throw new Error(`Unknown codec: ${codec.value}`); +}; + const getMatroskaAudioCodecString = (track: TrackEntry): string => { const codec = getCodecSegment(track); if (!codec) { @@ -200,10 +288,12 @@ export const getTrack = ({ return null; } + const codecPrivate = getPrivateData(track); const codecString = getMatroskaVideoCodecString({ track, codecSegment: codec, }); + const colour = getColourSegment(track); if (!codecString) { return null; @@ -231,12 +321,25 @@ export const getTrack = ({ : width.value.value, rotation: 0, trakBox: null, + codecPrivate, + color: colour + ? parseColorSegment(colour) + : { + fullRange: null, + matrixCoefficients: null, + primaries: null, + transferCharacteristics: null, + }, + codecWithoutConfig: getMatroskaVideoCodecWithoutConfigString({ + codecSegment: codec, + }), }; } if (trackTypeToString(trackType.value.value) === 'audio') { const sampleRate = getSampleRate(track); const numberOfChannels = getNumberOfChannels(track); + const codecPrivate = getPrivateData(track); if (sampleRate === null) { throw new Error('Could not find sample rate or number of channels'); } @@ -250,6 +353,10 @@ export const getTrack = ({ sampleRate, description: getAudioDescription(track), trakBox: null, + codecPrivate, + codecWithoutConfig: getMatroskaAudioCodecWithoutConfigString({ + track, + }), }; } diff --git a/packages/media-parser/src/boxes/webm/parse-ebml.ts b/packages/media-parser/src/boxes/webm/parse-ebml.ts index 10ec5b8a194..d4e5f9cd647 100644 --- a/packages/media-parser/src/boxes/webm/parse-ebml.ts +++ b/packages/media-parser/src/boxes/webm/parse-ebml.ts @@ -3,7 +3,7 @@ import {type BufferIterator} from '../../buffer-iterator'; import type {ParserContext} from '../../parser-context'; import type {VideoSample} from '../../webcodec-sample-types'; import {getSampleFromBlock} from './get-sample-from-block'; -import {getTrack} from './get-track'; +import {getTrack} from './make-track'; import type {PossibleEbml} from './segments/all-segments'; import {ebmlMap} from './segments/all-segments'; diff --git a/packages/media-parser/src/boxes/webm/segments/all-segments.ts b/packages/media-parser/src/boxes/webm/segments/all-segments.ts index 0ced8117460..ff8023fd9f8 100644 --- a/packages/media-parser/src/boxes/webm/segments/all-segments.ts +++ b/packages/media-parser/src/boxes/webm/segments/all-segments.ts @@ -542,12 +542,12 @@ export const color = { type: 'children', } as const satisfies Ebml; -export const transfer = { +export const transferCharacteristics = { name: 'TransferCharacteristics', type: 'uint', } as const satisfies Ebml; -export const matrix = { +export const matrixCoefficients = { name: 'MatrixCoefficients', type: 'uint', } as const satisfies Ebml; @@ -673,6 +673,13 @@ export const cluster = { } as const satisfies Ebml; export type CodecIdSegment = EbmlParsed; +export type ColourSegment = EbmlParsed; +export type TransferCharacteristicsSegment = EbmlParsed< + typeof transferCharacteristics +>; +export type PrimariesSegment = EbmlParsed; +export type RangeSegment = EbmlParsed; +export type MatrixCoefficientsSegment = EbmlParsed; export type TrackTypeSegment = EbmlParsed; export type WidthSegment = EbmlParsed; export type HeightSegment = EbmlParsed; @@ -865,8 +872,8 @@ export const ebmlMap = { name: 'Cluster', type: 'children', }, - [matroskaElements.TransferCharacteristics]: transfer, - [matroskaElements.MatrixCoefficients]: matrix, + [matroskaElements.TransferCharacteristics]: transferCharacteristics, + [matroskaElements.MatrixCoefficients]: matrixCoefficients, [matroskaElements.Primaries]: primaries, [matroskaElements.Range]: range, [matroskaElements.ChromaSitingHorz]: ChromaSitingHorz, diff --git a/packages/media-parser/src/boxes/webm/traversal.ts b/packages/media-parser/src/boxes/webm/traversal.ts index 9d419431571..dbee3fbc9e6 100644 --- a/packages/media-parser/src/boxes/webm/traversal.ts +++ b/packages/media-parser/src/boxes/webm/traversal.ts @@ -1,9 +1,23 @@ import type {AnySegment} from '../../parse-result'; import type { + AudioSegment, + ClusterSegment, CodecIdSegment, + ColourSegment, + DisplayHeightSegment, + DisplayWidthSegment, + HeightSegment, MainSegment, + MatrixCoefficientsSegment, + PrimariesSegment, + RangeSegment, + TimestampScaleSegment, TrackEntry, TrackNumberSegment, + TrackTypeSegment, + TransferCharacteristicsSegment, + VideoSegment, + WidthSegment, } from './segments/all-segments'; export const getMainSegment = (segments: AnySegment[]): MainSegment | null => { @@ -43,3 +57,284 @@ export const getTrackByNumber = (tracks: TrackEntry[], id: number) => { return trackNumber?.value === id; }); }; + +export const getTrackId = (track: TrackEntry): number => { + const trackId = track.value.find((b) => b.type === 'TrackNumber'); + if (!trackId || trackId.type !== 'TrackNumber') { + throw new Error('Expected track number segment'); + } + + return trackId.value.value; +}; + +export const getCodecSegment = (track: TrackEntry): CodecIdSegment | null => { + const codec = track.value.find((b) => b.type === 'CodecID'); + if (!codec || codec.type !== 'CodecID') { + return null; + } + + return codec; +}; + +export const getColourSegment = (track: TrackEntry): ColourSegment | null => { + const videoSegment = getVideoSegment(track); + if (!videoSegment) { + return null; + } + + const colour = videoSegment.value.find((b) => b.type === 'Colour'); + if (!colour || colour.type !== 'Colour') { + return null; + } + + return colour; +}; + +export const getTransferCharacteristicsSegment = ( + color: ColourSegment, +): TransferCharacteristicsSegment | null => { + if (!color || color.type !== 'Colour') { + return null; + } + + const box = color.value.find((b) => b.type === 'TransferCharacteristics'); + if (!box || box.type !== 'TransferCharacteristics') { + return null; + } + + return box; +}; + +export const getMatrixCoefficientsSegment = ( + color: ColourSegment, +): MatrixCoefficientsSegment | null => { + if (!color || color.type !== 'Colour') { + return null; + } + + const box = color.value.find((b) => b.type === 'MatrixCoefficients'); + if (!box || box.type !== 'MatrixCoefficients') { + return null; + } + + return box; +}; + +export const getPrimariesSegment = ( + color: ColourSegment, +): PrimariesSegment | null => { + if (!color || color.type !== 'Colour') { + return null; + } + + const box = color.value.find((b) => b.type === 'Primaries'); + if (!box || box.type !== 'Primaries') { + return null; + } + + return box; +}; + +export const getRangeSegment = (color: ColourSegment): RangeSegment | null => { + if (!color || color.type !== 'Colour') { + return null; + } + + const box = color.value.find((b) => b.type === 'Range'); + if (!box || box.type !== 'Range') { + return null; + } + + return box; +}; + +export const getDisplayHeightSegment = ( + track: TrackEntry, +): DisplayHeightSegment | null => { + const videoSegment = getVideoSegment(track); + if (!videoSegment) { + return null; + } + + const displayHeight = videoSegment.value.find( + (b) => b.type === 'DisplayHeight', + ); + + if (!displayHeight || displayHeight.type !== 'DisplayHeight') { + return null; + } + + return displayHeight; +}; + +export const getTrackTypeSegment = ( + track: TrackEntry, +): TrackTypeSegment | null => { + const trackType = track.value.find((b) => b.type === 'TrackType'); + if (!trackType || trackType.type !== 'TrackType') { + return null; + } + + return trackType; +}; + +export const getWidthSegment = (track: TrackEntry): WidthSegment | null => { + const videoSegment = getVideoSegment(track); + if (!videoSegment) { + return null; + } + + const width = videoSegment.value.find((b) => b.type === 'PixelWidth'); + + if (!width || width.type !== 'PixelWidth') { + return null; + } + + return width; +}; + +export const getHeightSegment = (track: TrackEntry): HeightSegment | null => { + const videoSegment = getVideoSegment(track); + if (!videoSegment) { + return null; + } + + const height = videoSegment.value.find((b) => b.type === 'PixelHeight'); + + if (!height || height.type !== 'PixelHeight') { + return null; + } + + return height; +}; + +export const getDisplayWidthSegment = ( + track: TrackEntry, +): DisplayWidthSegment | null => { + const videoSegment = getVideoSegment(track); + if (!videoSegment) { + return null; + } + + const displayWidth = videoSegment.value.find( + (b) => b.type === 'DisplayWidth', + ); + + if (!displayWidth || displayWidth.type !== 'DisplayWidth') { + return null; + } + + return displayWidth; +}; + +export const getTracksSegment = (segment: MainSegment) => { + const tracksSegment = segment.value.find((b) => b.type === 'Tracks'); + if (!tracksSegment || tracksSegment.type !== 'Tracks') { + return null; + } + + return tracksSegment; +}; + +export const getTimescaleSegment = ( + segment: MainSegment, +): TimestampScaleSegment | null => { + const infoSegment = segment.value.find((b) => b.type === 'Info'); + + if (!infoSegment || infoSegment.type !== 'Info') { + return null; + } + + const timescale = infoSegment.value.find((b) => b.type === 'TimestampScale'); + + if (!timescale || timescale.type !== 'TimestampScale') { + return null; + } + + return timescale as TimestampScaleSegment; +}; + +export const getVideoSegment = (track: TrackEntry): VideoSegment | null => { + const videoSegment = track.value.find((b) => b.type === 'Video'); + if (!videoSegment || videoSegment.type !== 'Video') { + return null; + } + + return videoSegment ?? null; +}; + +export const getAudioSegment = (track: TrackEntry): AudioSegment | null => { + const audioSegment = track.value.find((b) => b.type === 'Audio'); + if (!audioSegment || audioSegment.type !== 'Audio') { + return null; + } + + return audioSegment ?? null; +}; + +export const getSampleRate = (track: TrackEntry): number | null => { + const audioSegment = getAudioSegment(track); + if (!audioSegment) { + return null; + } + + const samplingFrequency = audioSegment.value.find( + (b) => b.type === 'SamplingFrequency', + ); + + if (!samplingFrequency || samplingFrequency.type !== 'SamplingFrequency') { + return null; + } + + return samplingFrequency.value.value; +}; + +export const getNumberOfChannels = (track: TrackEntry): number => { + const audioSegment = getAudioSegment(track); + if (!audioSegment) { + throw new Error('Could not find audio segment'); + } + + const channels = audioSegment.value.find((b) => b.type === 'Channels'); + + if (!channels || channels.type !== 'Channels') { + return 1; + } + + return channels.value.value; +}; + +export const getBitDepth = (track: TrackEntry): number | null => { + const audioSegment = getAudioSegment(track); + if (!audioSegment) { + return null; + } + + const bitDepth = audioSegment.value.find((b) => b.type === 'BitDepth'); + + if (!bitDepth || bitDepth.type !== 'BitDepth') { + return null; + } + + return bitDepth.value.value; +}; + +export const getPrivateData = (track: TrackEntry): Uint8Array | null => { + const privateData = track.value.find((b) => b.type === 'CodecPrivate'); + + if (!privateData || privateData.type !== 'CodecPrivate') { + return null; + } + + return privateData.value; +}; + +export const getClusterSegment = ( + segment: MainSegment, +): ClusterSegment | null => { + const clusterSegment = segment.value.find((b) => b.type === 'Cluster') as + | ClusterSegment + | undefined; + + return clusterSegment ?? null; +}; diff --git a/packages/media-parser/src/create/cluster.ts b/packages/media-parser/src/create/cluster.ts index 4eba16e6198..3f704acb913 100644 --- a/packages/media-parser/src/create/cluster.ts +++ b/packages/media-parser/src/create/cluster.ts @@ -11,6 +11,14 @@ import {CREATE_TIME_SCALE} from './timescale'; const maxClusterTimestamp = 2 ** 15; +export type AudioOrVideoSample = { + timestamp: number; + type: 'key' | 'delta'; + copyTo(destination: AllowSharedBufferSource): void; + byteLength: number; + duration: number | null; +}; + export const timestampToClusterTimestamp = (timestamp: number) => { return Math.round((timestamp / CREATE_TIME_SCALE) * 1000); }; @@ -28,7 +36,7 @@ export const makeCluster = async (w: Writer, timestamp: number) => { CLUSTER_MIN_VINT_WIDTH; await w.write(cluster.bytes); - const addSample = async (chunk: EncodedVideoChunk, trackNumber: number) => { + const addSample = async (chunk: AudioOrVideoSample, trackNumber: number) => { const arr = new Uint8Array(chunk.byteLength); chunk.copyTo(arr); const timecodeRelativeToCluster = diff --git a/packages/media-parser/src/create/create-media.ts b/packages/media-parser/src/create/create-media.ts index 2464e024336..48a47b76c94 100644 --- a/packages/media-parser/src/create/create-media.ts +++ b/packages/media-parser/src/create/create-media.ts @@ -5,6 +5,7 @@ import { type BytesAndOffset, } from '../boxes/webm/segments/all-segments'; import type {WriterInterface} from '../writers/writer'; +import type {AudioOrVideoSample} from './cluster'; import {makeCluster} from './cluster'; import {makeDurationWithPadding} from './make-duration-with-padding'; import {createMatroskaCues, type Cue} from './matroska-cues'; @@ -25,8 +26,9 @@ import { import {CREATE_TIME_SCALE} from './timescale'; export type MediaFn = { - save: () => Promise; - addSample: (chunk: EncodedVideoChunk, trackNumber: number) => Promise; + save: () => Promise; + remove: () => Promise; + addSample: (chunk: AudioOrVideoSample, trackNumber: number) => Promise; updateDuration: (duration: number) => Promise; addTrack: ( track: @@ -109,7 +111,6 @@ export const createMedia = async ( const clusterOffset = w.getWrittenByteCount(); let currentCluster = await makeCluster(w, 0); - // TODO: Also create a `Cues` seek element seeks.push({ hexString: matroskaElements.Cluster, byte: clusterOffset - seekHeadOffset, @@ -120,11 +121,9 @@ export const createMedia = async ( trackNumbers, }); - await updateSeekWrite(); - const trackNumberProgresses: Record = {}; - const getClusterOrMakeNew = async (chunk: EncodedVideoChunk) => { + const getClusterOrMakeNew = async (chunk: AudioOrVideoSample) => { const smallestProgress = Math.min(...Object.values(trackNumberProgresses)); if ( !currentCluster.shouldMakeNewCluster( @@ -146,9 +145,16 @@ export const createMedia = async ( return currentCluster; }; - const addSample = async (chunk: EncodedVideoChunk, trackNumber: number) => { + const addSample = async (chunk: AudioOrVideoSample, trackNumber: number) => { trackNumberProgresses[trackNumber] = chunk.timestamp; const cluster = await getClusterOrMakeNew(chunk); + + const newDuration = Math.round( + (chunk.timestamp + (chunk.duration ?? 0)) / 1000, + ); + + await updateDuration(newDuration); + return cluster.addSample(chunk, trackNumber); }; @@ -173,7 +179,11 @@ export const createMedia = async ( return { save: async () => { - await w.save(); + const file = await w.save(); + return file; + }, + remove: async () => { + await w.remove(); }, addSample: (chunk, trackNumber) => { operationProm.current = operationProm.current.then(() => @@ -206,6 +216,12 @@ export const createMedia = async ( async waitForFinish() { await Promise.all(waitForFinishPromises.map((p) => p())); await operationProm.current; + seeks.push({ + hexString: matroskaElements.Cues, + byte: w.getWrittenByteCount() - seekHeadOffset, + }); + await updateSeekWrite(); + await w.write(createMatroskaCues(cues).bytes); const segmentSize = w.getWrittenByteCount() - segmentOffset; await w.waitForFinish(); diff --git a/packages/media-parser/src/create/matroska-trackentry.ts b/packages/media-parser/src/create/matroska-trackentry.ts index 2e78908e478..a8ffdc8a94f 100644 --- a/packages/media-parser/src/create/matroska-trackentry.ts +++ b/packages/media-parser/src/create/matroska-trackentry.ts @@ -1,107 +1,21 @@ +import {makeMatroskaColorBytes} from '../boxes/webm/color'; import {makeMatroskaBytes, padMatroskaBytes} from '../boxes/webm/make-header'; -import type {BytesAndOffset} from '../boxes/webm/segments/all-segments'; - -export type MatroskaColorParams = { - transferChracteristics: 'bt709' | 'smpte170m' | 'iec61966-2-1' | null; - matrixCoefficients: 'bt709' | 'bt470bg' | 'rgb' | 'smpte170m' | null; - primaries: 'bt709' | 'smpte170m' | 'bt470bg' | null; - fullRange: boolean | null; -}; - -export const makeMatroskaColorBytes = ({ - transferChracteristics, - matrixCoefficients, - primaries, - fullRange, -}: MatroskaColorParams) => { - const rangeValue = - transferChracteristics && matrixCoefficients - ? 3 - : fullRange === true - ? 2 - : fullRange === false - ? 1 - : 0; - - // https://datatracker.ietf.org/doc/draft-ietf-cellar-matroska/ - // 5.1.4.1.28.27 - const primariesValue = - primaries === 'bt709' - ? 1 - : primaries === 'smpte170m' - ? 6 - : primaries === 'bt470bg' - ? 5 - : 2; - - const transferChracteristicsValue = - transferChracteristics === 'bt709' - ? 1 - : transferChracteristics === 'smpte170m' - ? 6 - : transferChracteristics === 'iec61966-2-1' - ? 13 - : 2; - - if (matrixCoefficients === 'rgb') { - throw new Error('Cannot encode Matroska in RGB'); - } - - const matrixCoefficientsValue = - matrixCoefficients === 'bt709' - ? 1 - : matrixCoefficients === 'bt470bg' - ? 5 - : matrixCoefficients === 'smpte170m' - ? 6 - : 2; - - return makeMatroskaBytes({ - type: 'Colour', - minVintWidth: null, - value: [ - { - type: 'TransferCharacteristics', - value: { - value: transferChracteristicsValue, - byteLength: null, - }, - minVintWidth: null, - }, - { - type: 'MatrixCoefficients', - value: { - value: matrixCoefficientsValue, - byteLength: null, - }, - minVintWidth: null, - }, - { - type: 'Primaries', - value: { - value: primariesValue, - byteLength: null, - }, - minVintWidth: null, - }, - { - type: 'Range', - value: { - value: rangeValue, - byteLength: null, - }, - minVintWidth: null, - }, - ], - }); -}; +import type { + BytesAndOffset, + PossibleEbmlOrUint8Array, +} from '../boxes/webm/segments/all-segments'; +import type { + MediaParserAudioCodec, + MediaParserVideoCodec, + VideoTrackColorParams, +} from '../get-tracks'; export const makeMatroskaVideoBytes = ({ color, width, height, }: { - color: MatroskaColorParams; + color: VideoTrackColorParams; width: number; height: number; }) => { @@ -142,26 +56,101 @@ export const makeMatroskaVideoBytes = ({ export type MakeTrackAudio = { trackNumber: number; - codecId: string; + codec: MediaParserAudioCodec; numberOfChannels: number; sampleRate: number; type: 'audio'; + codecPrivate: Uint8Array | null; }; export type MakeTrackVideo = { - color: MatroskaColorParams; + color: VideoTrackColorParams; width: number; height: number; trackNumber: number; - codecId: string; + codec: MediaParserVideoCodec; type: 'video'; + codecPrivate: Uint8Array | null; +}; + +const makeVideoCodecId = (codecId: MediaParserVideoCodec) => { + if (codecId === 'vp8') { + return 'V_VP8'; + } + + if (codecId === 'vp9') { + return 'V_VP9'; + } + + if (codecId === 'h264') { + return 'V_MPEG4/ISO/AVC'; + } + + if (codecId === 'av1') { + return 'V_AV1'; + } + + if (codecId === 'h265') { + return 'V_MPEGH/ISO/HEVC'; + } + + if (codecId === 'prores') { + return 'V_PRORES'; + } + + throw new Error(`Unknown codec: ${codecId satisfies never}`); +}; + +const makeAudioCodecId = (codecId: MediaParserAudioCodec) => { + if (codecId === 'opus') { + return 'A_OPUS'; + } + + if (codecId === 'aac') { + return 'A_AAC'; + } + + if (codecId === 'mp3') { + return 'A_MPEG/L3'; + } + + if (codecId === 'vorbis') { + return 'A_VORBIS'; + } + + if (codecId === 'pcm-u8') { + return 'A_PCM/INT/LIT'; + } + + if (codecId === 'pcm-s16') { + return 'A_PCM/INT/LIT'; + } + + if (codecId === 'pcm-s24') { + return 'A_PCM/INT/LIT'; + } + + if (codecId === 'pcm-s32') { + return 'A_PCM/INT/LIT'; + } + + if (codecId === 'pcm-f32') { + return 'A_PCM/INT/LIT'; + } + + if (codecId === 'aiff') { + throw new Error('aiff is not supported in Matroska'); + } + + throw new Error(`Unknown codec: ${codecId satisfies never}`); }; export const makeMatroskaAudioTrackEntryBytes = ({ trackNumber, - codecId, - numberOfChannels: audioChannels, + codec, + numberOfChannels, sampleRate, + codecPrivate, }: MakeTrackAudio) => { return makeMatroskaBytes({ type: 'TrackEntry', @@ -198,7 +187,7 @@ export const makeMatroskaAudioTrackEntryBytes = ({ }, { type: 'CodecID', - value: codecId, + value: makeAudioCodecId(codec), minVintWidth: null, }, { @@ -208,7 +197,7 @@ export const makeMatroskaAudioTrackEntryBytes = ({ type: 'Channels', minVintWidth: null, value: { - value: audioChannels, + value: numberOfChannels, byteLength: null, }, }, @@ -231,7 +220,14 @@ export const makeMatroskaAudioTrackEntryBytes = ({ ], minVintWidth: null, }, - ], + codecPrivate + ? { + type: 'CodecPrivate', + minVintWidth: null, + value: codecPrivate, + } + : null, + ].filter(Boolean) as PossibleEbmlOrUint8Array[], }); }; @@ -240,7 +236,8 @@ export const makeMatroskaVideoTrackEntryBytes = ({ width, height, trackNumber, - codecId, + codec, + codecPrivate, }: MakeTrackVideo) => { return makeMatroskaBytes({ type: 'TrackEntry', @@ -282,7 +279,7 @@ export const makeMatroskaVideoTrackEntryBytes = ({ }, { type: 'CodecID', - value: codecId, + value: makeVideoCodecId(codec), minVintWidth: null, }, { @@ -298,7 +295,14 @@ export const makeMatroskaVideoTrackEntryBytes = ({ width, height, }), - ], + codecPrivate + ? { + type: 'CodecPrivate', + minVintWidth: null, + value: codecPrivate, + } + : null, + ].filter(Boolean) as PossibleEbmlOrUint8Array[], }); }; diff --git a/packages/media-parser/src/emit-available-info.ts b/packages/media-parser/src/emit-available-info.ts new file mode 100644 index 00000000000..620fb72ed6a --- /dev/null +++ b/packages/media-parser/src/emit-available-info.ts @@ -0,0 +1,193 @@ +import {getAudioCodec} from './get-audio-codec'; +import {getContainer} from './get-container'; +import type {Dimensions} from './get-dimensions'; +import {getDimensions} from './get-dimensions'; +import {getDuration} from './get-duration'; +import {getFps} from './get-fps'; +import {getTracks} from './get-tracks'; +import {getVideoCodec} from './get-video-codec'; +import type { + AllParseMediaFields, + Options, + ParseMediaCallbacks, + ParseMediaFields, + ParseMediaResult, +} from './options'; +import type {ParseResult} from './parse-result'; +import type {ParserState} from './parser-state'; + +export const emitAvailableInfo = ({ + hasInfo, + parseResult, + moreFields, + state, + returnValue, + contentLength, + name, +}: { + hasInfo: Record, boolean>; + parseResult: ParseResult; + moreFields: ParseMediaCallbacks; + state: ParserState; + returnValue: ParseMediaResult; + contentLength: number | null; + name: string; +}) => { + const keys = Object.keys(hasInfo) as (keyof Options)[]; + + for (const key of keys) { + if (key === 'boxes') { + if (hasInfo.boxes && returnValue.boxes === undefined) { + moreFields.onBoxes?.(parseResult.segments); + returnValue.boxes = parseResult.segments; + } + + continue; + } + + if (key === 'durationInSeconds') { + if ( + hasInfo.durationInSeconds && + returnValue.durationInSeconds === undefined + ) { + const durationInSeconds = getDuration(parseResult.segments, state); + moreFields.onDurationInSeconds?.(durationInSeconds); + returnValue.durationInSeconds = durationInSeconds; + } + + continue; + } + + if (key === 'dimensions') { + if (hasInfo.dimensions && returnValue.dimensions === undefined) { + const dimensionsQueried = getDimensions(parseResult.segments, state); + const dimensions: Dimensions = { + height: dimensionsQueried.height, + width: dimensionsQueried.width, + }; + moreFields.onDimensions?.(dimensions); + returnValue.dimensions = dimensions; + } + + continue; + } + + if (key === 'unrotatedDimensions') { + if ( + returnValue.unrotatedDimensions === undefined && + hasInfo.unrotatedDimensions + ) { + const dimensionsQueried = getDimensions(parseResult.segments, state); + const unrotatedDimensions: Dimensions = { + height: dimensionsQueried.unrotatedHeight, + width: dimensionsQueried.unrotatedWidth, + }; + + moreFields.onUnrotatedDimensions?.(unrotatedDimensions); + returnValue.unrotatedDimensions = unrotatedDimensions; + } + + continue; + } + + if (key === 'rotation') { + if (returnValue.rotation === undefined && hasInfo.rotation) { + const dimensionsQueried = getDimensions(parseResult.segments, state); + const {rotation} = dimensionsQueried; + + moreFields.onRotation?.(rotation); + returnValue.rotation = rotation; + } + + continue; + } + + if (key === 'fps') { + if (returnValue.fps === undefined && hasInfo.fps) { + const fps = getFps(parseResult.segments); + moreFields.onFps?.(fps); + returnValue.fps = fps; + } + + continue; + } + + if (key === 'videoCodec') { + if (returnValue.videoCodec === undefined && hasInfo.videoCodec) { + const videoCodec = getVideoCodec(parseResult.segments); + moreFields.onVideoCodec?.(videoCodec); + returnValue.videoCodec = videoCodec; + } + + continue; + } + + if (key === 'audioCodec') { + if (returnValue.audioCodec === undefined && hasInfo.audioCodec) { + const audioCodec = getAudioCodec(parseResult.segments, state); + moreFields.onAudioCodec?.(audioCodec); + returnValue.audioCodec = audioCodec; + } + + continue; + } + + if (key === 'tracks') { + if ( + hasInfo.tracks && + returnValue.videoTracks === undefined && + returnValue.audioTracks === undefined + ) { + const {videoTracks, audioTracks} = getTracks( + parseResult.segments, + state, + ); + moreFields.onTracks?.({videoTracks, audioTracks}); + returnValue.videoTracks = videoTracks; + returnValue.audioTracks = audioTracks; + } + + continue; + } + + if (key === 'internalStats') { + if (hasInfo.internalStats && returnValue.internalStats === undefined) { + const internalStats = state.getInternalStats(); + moreFields.onInternalStats?.(internalStats); + returnValue.internalStats = internalStats; + } + + continue; + } + + if (key === 'size') { + if (returnValue.size === undefined && hasInfo.size) { + moreFields.onSize?.(contentLength); + returnValue.size = contentLength; + } + + continue; + } + + if (key === 'name') { + if (returnValue.name === undefined && hasInfo.name) { + moreFields.onName?.(name); + returnValue.name = name; + } + + continue; + } + + if (key === 'container') { + if (returnValue.container === undefined && hasInfo.container) { + const container = getContainer(parseResult.segments); + moreFields.onContainer?.(container); + returnValue.container = container; + } + + continue; + } + + throw new Error(`Unhandled key: ${key satisfies never}`); + } +}; diff --git a/packages/media-parser/src/get-audio-codec.ts b/packages/media-parser/src/get-audio-codec.ts index 7bb80f38343..87ddc88dd79 100644 --- a/packages/media-parser/src/get-audio-codec.ts +++ b/packages/media-parser/src/get-audio-codec.ts @@ -3,15 +3,18 @@ import type {EsdsBox} from './boxes/iso-base-media/esds/esds'; import type {MoovBox} from './boxes/iso-base-media/moov/moov'; import type {AudioSample} from './boxes/iso-base-media/stsd/samples'; import type {TrakBox} from './boxes/iso-base-media/trak/trak'; -import type {MainSegment} from './boxes/webm/segments/all-segments'; +import {getStsdBox, getTraks} from './boxes/iso-base-media/traversal'; import {trakBoxContainsAudio} from './get-fps'; -import type {KnownAudioCodecs} from './options'; +import {getTracks, type MediaParserAudioCodec} from './get-tracks'; import type {AnySegment} from './parse-result'; -import {getMoovBox, getStsdBox, getTraks} from './traversal'; +import type {ParserState} from './parser-state'; -export const hasAudioCodec = (boxes: AnySegment[]): boolean => { +export const hasAudioCodec = ( + boxes: AnySegment[], + state: ParserState, +): boolean => { try { - return getAudioCodec(boxes) !== null; + return getAudioCodec(boxes, state) !== null; } catch (e) { return false; } @@ -162,42 +165,6 @@ export const getAudioCodecFromIso = (moov: MoovBox) => { return getAudioCodecFromTrak(trakBox); }; -export const getAudioCodecFromMatroska = (mainSegment: MainSegment) => { - const tracksSegment = mainSegment.value.find((b) => b.type === 'Tracks'); - if (!tracksSegment || tracksSegment.type !== 'Tracks') { - return null; - } - - for (const track of tracksSegment.value) { - if (track.type === 'TrackEntry') { - const trackType = track.value.find((b) => b.type === 'CodecID'); - if (trackType && trackType.type === 'CodecID') { - if (trackType.value === 'A_OPUS') { - return 'opus'; - } - - if (trackType.value === 'A_VORBIS') { - return 'vorbis'; - } - - if (trackType.value === 'A_PCM/INT/LIT') { - return 'pcm'; - } - - if (trackType.value === 'A_AAC') { - return 'aac'; - } - - if (trackType.value === 'A_MPEG/L3') { - return 'mp3'; - } - } - } - } - - return null; -}; - export const getAudioCodecStringFromTrak = ( trak: TrakBox, ): {codecString: string; description: Uint8Array | undefined} => { @@ -228,43 +195,61 @@ export const getAudioCodecStringFromTrak = ( }; }; -export const getAudioCodec = (boxes: AnySegment[]): KnownAudioCodecs | null => { - const moovBox = getMoovBox(boxes); +const getAudioCodecFromAudioCodecInfo = (codec: AudioCodecInfo) => { + if (codec.format === 'sowt') { + return 'aiff'; + } - if (moovBox) { - const codec = getAudioCodecFromIso(moovBox); + if (codec.format === 'mp4a') { + if (codec.primarySpecificator === 0x40) { + return 'aac'; + } - if (!codec) { - return null; + if (codec.primarySpecificator === 0x6b) { + return 'mp3'; } - if (codec.format === 'sowt') { - return 'aiff'; + if (codec.primarySpecificator === null) { + return 'aac'; } - if (codec.format === 'mp4a') { - if (codec.primarySpecificator === 0x40) { - return 'aac'; - } + throw new Error('Unknown mp4a codec: ' + codec.primarySpecificator); + } - if (codec.primarySpecificator === 0x6b) { - return 'mp3'; - } + throw new Error('Unknown audio format: ' + codec.format); +}; - if (codec.primarySpecificator === null) { - return 'aac'; - } +export const getAudioCodecFromTrack = (track: TrakBox) => { + const audioSample = getAudioCodecFromTrak(track); + if (!audioSample) { + throw new Error('Could not find audio sample'); + } - throw new Error('Unknown mp4a codec: ' + codec.primarySpecificator); - } + return getAudioCodecFromAudioCodecInfo(audioSample); +}; + +export const getAudioCodec = ( + boxes: AnySegment[], + parserState: ParserState, +): MediaParserAudioCodec | null => { + const tracks = getTracks(boxes, parserState); + const allTracks = + tracks.audioTracks.length + + tracks.otherTracks.length + + tracks.videoTracks.length; - throw new Error('Unknown audio format: ' + codec.format); + if (allTracks === 0) { + throw new Error('No tracks yet'); } - const mainSegment = boxes.find((b) => b.type === 'Segment'); - if (!mainSegment || mainSegment.type !== 'Segment') { + const audioTrack = tracks.audioTracks[0]; + if (!audioTrack) { return null; } - return getAudioCodecFromMatroska(mainSegment); + if (audioTrack.type === 'audio') { + return audioTrack.codecWithoutConfig; + } + + return null; }; diff --git a/packages/media-parser/src/get-container.ts b/packages/media-parser/src/get-container.ts new file mode 100644 index 00000000000..095efe23537 --- /dev/null +++ b/packages/media-parser/src/get-container.ts @@ -0,0 +1,28 @@ +import {getMoovBox} from './boxes/iso-base-media/traversal'; +import {getMainSegment} from './boxes/webm/traversal'; +import type {ParseMediaContainer} from './options'; +import type {AnySegment} from './parse-result'; + +export const getContainer = ( + segments: AnySegment[], +): ParseMediaContainer | null => { + const moovBox = getMoovBox(segments); + if (moovBox) { + return 'mp4'; + } + + const mainSegment = getMainSegment(segments); + if (mainSegment) { + return 'webm'; + } + + return null; +}; + +export const hasContainer = (boxes: AnySegment[]): boolean => { + try { + return getContainer(boxes) !== null; + } catch (e) { + return false; + } +}; diff --git a/packages/media-parser/src/get-duration.ts b/packages/media-parser/src/get-duration.ts index 5e3ea60b3ad..7be1acba840 100644 --- a/packages/media-parser/src/get-duration.ts +++ b/packages/media-parser/src/get-duration.ts @@ -1,10 +1,14 @@ import {getSamplePositionsFromTrack} from './boxes/iso-base-media/get-sample-positions-from-track'; import type {TrakBox} from './boxes/iso-base-media/trak/trak'; +import { + getMoofBox, + getMoovBox, + getMvhdBox, +} from './boxes/iso-base-media/traversal'; import type {DurationSegment} from './boxes/webm/segments/all-segments'; import {getTracks} from './get-tracks'; import type {AnySegment} from './parse-result'; import type {ParserState} from './parser-state'; -import {getMoofBox, getMoovBox, getMvhdBox} from './traversal'; const getDurationFromMatroska = (segments: AnySegment[]): number | null => { const mainSegment = segments.find((s) => s.type === 'Segment'); diff --git a/packages/media-parser/src/get-fps.ts b/packages/media-parser/src/get-fps.ts index fd098fb9628..72c0df02540 100644 --- a/packages/media-parser/src/get-fps.ts +++ b/packages/media-parser/src/get-fps.ts @@ -1,13 +1,13 @@ import type {SttsBox} from './boxes/iso-base-media/stsd/stts'; import type {TrakBox} from './boxes/iso-base-media/trak/trak'; -import type {AnySegment} from './parse-result'; import { getMdhdBox, getMoovBox, getStsdBox, getSttsBox, getTraks, -} from './traversal'; +} from './boxes/iso-base-media/traversal'; +import type {AnySegment} from './parse-result'; const calculateFps = ({ sttsBox, diff --git a/packages/media-parser/src/get-sample-aspect-ratio.ts b/packages/media-parser/src/get-sample-aspect-ratio.ts index c1ed4cb6f59..9e3d77da21a 100644 --- a/packages/media-parser/src/get-sample-aspect-ratio.ts +++ b/packages/media-parser/src/get-sample-aspect-ratio.ts @@ -6,36 +6,36 @@ import type {PaspBox} from './boxes/iso-base-media/stsd/pasp'; import type {VideoSample} from './boxes/iso-base-media/stsd/samples'; import type {TkhdBox} from './boxes/iso-base-media/tkhd'; import type {TrakBox} from './boxes/iso-base-media/trak/trak'; +import {getStsdBox} from './boxes/iso-base-media/traversal'; import type {Dimensions} from './get-dimensions'; -import {getStsdBox} from './traversal'; type AspectRatio = { numerator: number; denominator: number; }; -export const getVideoSample = (trakBox: TrakBox): VideoSample | null => { +export const getStsdVideoConfig = (trakBox: TrakBox): VideoSample | null => { const stsdBox = getStsdBox(trakBox); if (!stsdBox) { return null; } - const videoSample = stsdBox.samples.find((s) => s.type === 'video'); - if (!videoSample || videoSample.type !== 'video') { + const videoConfig = stsdBox.samples.find((s) => s.type === 'video'); + if (!videoConfig || videoConfig.type !== 'video') { return null; } - return videoSample; + return videoConfig; }; export const getAvccBox = (trakBox: TrakBox): AvccBox | null => { - const videoSample = getVideoSample(trakBox); - if (!videoSample) { + const videoConfig = getStsdVideoConfig(trakBox); + if (!videoConfig) { return null; } - const avccBox = videoSample.descriptors.find((c) => c.type === 'avcc-box'); + const avccBox = videoConfig.descriptors.find((c) => c.type === 'avcc-box'); if (!avccBox || avccBox.type !== 'avcc-box') { return null; @@ -45,12 +45,12 @@ export const getAvccBox = (trakBox: TrakBox): AvccBox | null => { }; export const getAv1CBox = (trakBox: TrakBox): Av1CBox | null => { - const videoSample = getVideoSample(trakBox); - if (!videoSample) { + const videoConfig = getStsdVideoConfig(trakBox); + if (!videoConfig) { return null; } - const av1cBox = videoSample.descriptors.find((c) => c.type === 'av1C-box'); + const av1cBox = videoConfig.descriptors.find((c) => c.type === 'av1C-box'); if (!av1cBox || av1cBox.type !== 'av1C-box') { return null; @@ -60,12 +60,12 @@ export const getAv1CBox = (trakBox: TrakBox): Av1CBox | null => { }; export const getPaspBox = (trakBox: TrakBox): PaspBox | null => { - const videoSample = getVideoSample(trakBox); - if (!videoSample) { + const videoConfig = getStsdVideoConfig(trakBox); + if (!videoConfig) { return null; } - const paspBox = videoSample.descriptors.find((c) => c.type === 'pasp-box'); + const paspBox = videoConfig.descriptors.find((c) => c.type === 'pasp-box'); if (!paspBox || paspBox.type !== 'pasp-box') { return null; @@ -75,12 +75,12 @@ export const getPaspBox = (trakBox: TrakBox): PaspBox | null => { }; export const getHvccBox = (trakBox: TrakBox): HvccBox | null => { - const videoSample = getVideoSample(trakBox); - if (!videoSample) { + const videoConfig = getStsdVideoConfig(trakBox); + if (!videoConfig) { return null; } - const hvccBox = videoSample.descriptors.find((c) => c.type === 'hvcc-box'); + const hvccBox = videoConfig.descriptors.find((c) => c.type === 'hvcc-box'); if (!hvccBox || hvccBox.type !== 'hvcc-box') { return null; diff --git a/packages/media-parser/src/get-tracks.ts b/packages/media-parser/src/get-tracks.ts index dbcf7797aaf..4dcc6da6770 100644 --- a/packages/media-parser/src/get-tracks.ts +++ b/packages/media-parser/src/get-tracks.ts @@ -1,23 +1,55 @@ import {makeBaseMediaTrack} from './boxes/iso-base-media/make-track'; import type {MoovBox} from './boxes/iso-base-media/moov/moov'; import type {TrakBox} from './boxes/iso-base-media/trak/trak'; +import { + getMoovBox, + getMvhdBox, + getTraks, +} from './boxes/iso-base-media/traversal'; import {getTracksFromMatroska} from './boxes/webm/get-ready-tracks'; -import {getMainSegment} from './boxes/webm/traversal'; +import {getMainSegment, getTracksSegment} from './boxes/webm/traversal'; import type {AnySegment} from './parse-result'; import type {ParserState} from './parser-state'; -import {getMoovBox, getMvhdBox, getTracksSegment, getTraks} from './traversal'; type SampleAspectRatio = { numerator: number; denominator: number; }; +export type VideoTrackColorParams = { + transferCharacteristics: 'bt709' | 'smpte170m' | 'iec61966-2-1' | null; + matrixCoefficients: 'bt709' | 'bt470bg' | 'rgb' | 'smpte170m' | null; + primaries: 'bt709' | 'smpte170m' | 'bt470bg' | null; + fullRange: boolean | null; +}; + +export type MediaParserVideoCodec = + | 'vp8' + | 'vp9' + | 'h264' + | 'av1' + | 'h265' + | 'prores'; + +export type MediaParserAudioCodec = + | 'opus' + | 'aac' + | 'mp3' + | 'vorbis' + | 'pcm-u8' + | 'pcm-s16' + | 'pcm-s24' + | 'pcm-s32' + | 'pcm-f32' + | 'aiff'; + export type VideoTrack = { type: 'video'; trackId: number; description: Uint8Array | undefined; timescale: number; codec: string; + codecWithoutConfig: MediaParserVideoCodec; sampleAspectRatio: SampleAspectRatio; width: number; height: number; @@ -27,6 +59,8 @@ export type VideoTrack = { codedHeight: number; rotation: number; trakBox: TrakBox | null; + codecPrivate: Uint8Array | null; + color: VideoTrackColorParams; }; export type AudioTrack = { @@ -34,10 +68,12 @@ export type AudioTrack = { trackId: number; timescale: number; codec: string; + codecWithoutConfig: MediaParserAudioCodec; numberOfChannels: number; sampleRate: number; description: Uint8Array | undefined; trakBox: TrakBox | null; + codecPrivate: Uint8Array | null; }; export type OtherTrack = { diff --git a/packages/media-parser/src/get-video-codec.ts b/packages/media-parser/src/get-video-codec.ts index 8319424eaa9..b61c8aa7cdd 100644 --- a/packages/media-parser/src/get-video-codec.ts +++ b/packages/media-parser/src/get-video-codec.ts @@ -1,5 +1,10 @@ /* eslint-disable max-depth */ import type {TrakBox} from './boxes/iso-base-media/trak/trak'; +import { + getMoovBox, + getStsdBox, + getTraks, +} from './boxes/iso-base-media/traversal'; import {parseAv1PrivateData} from './boxes/webm/av1-codec-private'; import {trakBoxContainsVideo} from './get-fps'; import { @@ -7,11 +12,10 @@ import { getAvccBox, getColrBox, getHvccBox, - getVideoSample, + getStsdVideoConfig, } from './get-sample-aspect-ratio'; -import type {KnownVideoCodecs} from './options'; +import type {MediaParserVideoCodec, VideoTrackColorParams} from './get-tracks'; import type {AnySegment} from './parse-result'; -import {getMoovBox, getStsdBox, getTraks} from './traversal'; export const hasVideoCodec = (boxes: AnySegment[]): boolean => { try { @@ -21,8 +25,76 @@ export const hasVideoCodec = (boxes: AnySegment[]): boolean => { } }; +export const getVideoPrivateData = (trakBox: TrakBox): Uint8Array | null => { + const videoSample = getStsdVideoConfig(trakBox); + const avccBox = getAvccBox(trakBox); + const hvccBox = getHvccBox(trakBox); + const av1cBox = getAv1CBox(trakBox); + + if (!videoSample) { + return null; + } + + if (avccBox) { + return avccBox.privateData; + } + + if (hvccBox) { + return hvccBox.privateData; + } + + if (av1cBox) { + return av1cBox.privateData; + } + + return null; +}; + +export const getIsoBmColrConfig = ( + trakBox: TrakBox, +): VideoTrackColorParams | null => { + const videoSample = getStsdVideoConfig(trakBox); + if (!videoSample) { + return null; + } + + const colrAtom = getColrBox(videoSample); + if (!colrAtom) { + return null; + } + + // https://github.com/bbc/qtff-parameter-editor + return { + fullRange: colrAtom.fullRangeFlag, + matrixCoefficients: + colrAtom.matrixIndex === 1 + ? 'bt709' + : colrAtom.matrixIndex === 5 + ? 'bt470bg' + : colrAtom.matrixIndex === 6 + ? 'smpte170m' + : null, + primaries: + colrAtom.primaries === 1 + ? 'bt709' + : colrAtom.primaries === 5 + ? 'bt470bg' + : colrAtom.primaries === 6 + ? 'smpte170m' + : null, + transferCharacteristics: + colrAtom.transfer === 1 + ? 'bt709' + : colrAtom.transfer === 6 + ? 'smpte170m' + : colrAtom.transfer === 13 + ? 'iec61966-2-1' + : null, + }; +}; + export const getVideoCodecString = (trakBox: TrakBox): string | null => { - const videoSample = getVideoSample(trakBox); + const videoSample = getStsdVideoConfig(trakBox); const avccBox = getAvccBox(trakBox); const hvccBox = getHvccBox(trakBox); const av1cBox = getAv1CBox(trakBox); @@ -47,32 +119,76 @@ export const getVideoCodecString = (trakBox: TrakBox): string | null => { return videoSample.format; }; -export const getVideoCodec = (boxes: AnySegment[]): KnownVideoCodecs | null => { +export const getVideoCodecFromIsoTrak = (trakBox: TrakBox) => { + const stsdBox = getStsdBox(trakBox); + if (stsdBox && stsdBox.type === 'stsd-box') { + const videoSample = stsdBox.samples.find((s) => s.type === 'video'); + if (videoSample && videoSample.type === 'video') { + if (videoSample.format === 'hvc1') { + return 'h265'; + } + + if (videoSample.format === 'avc1') { + return 'h264'; + } + + if (videoSample.format === 'av01') { + return 'av1'; + } + + // ap4h: ProRes 4444 + if (videoSample.format === 'ap4h') { + return 'prores'; + } + + // ap4x: ap4x: ProRes 4444 XQ + if (videoSample.format === 'ap4x') { + return 'prores'; + } + + // apch: ProRes 422 High Quality + if (videoSample.format === 'apch') { + return 'prores'; + } + + // apcn: ProRes 422 Standard Definition + if (videoSample.format === 'apcn') { + return 'prores'; + } + + // apcs: ProRes 422 LT + if (videoSample.format === 'apcs') { + return 'prores'; + } + + // apco: ProRes 422 Proxy + if (videoSample.format === 'apco') { + return 'prores'; + } + + // aprh: ProRes RAW High Quality + if (videoSample.format === 'aprh') { + return 'prores'; + } + + // aprn: ProRes RAW Standard Definition + if (videoSample.format === 'aprn') { + return 'prores'; + } + } + } + + throw new Error('Could not find video codec'); +}; + +export const getVideoCodec = ( + boxes: AnySegment[], +): MediaParserVideoCodec | null => { const moovBox = getMoovBox(boxes); if (moovBox) { const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0]; if (trakBox) { - const stsdBox = getStsdBox(trakBox); - if (stsdBox && stsdBox.type === 'stsd-box') { - const videoSample = stsdBox.samples.find((s) => s.type === 'video'); - if (videoSample && videoSample.type === 'video') { - if (videoSample.format === 'hvc1') { - return 'h265'; - } - - if (videoSample.format === 'avc1') { - return 'h264'; - } - - if (videoSample.format === 'av01') { - return 'av1'; - } - - if (videoSample.format === 'ap4h') { - return 'prores'; - } - } - } + return getVideoCodecFromIsoTrak(trakBox); } } diff --git a/packages/media-parser/src/has-all-info.ts b/packages/media-parser/src/has-all-info.ts index f00076e93d2..ec2c23dd7e6 100644 --- a/packages/media-parser/src/has-all-info.ts +++ b/packages/media-parser/src/has-all-info.ts @@ -1,45 +1,25 @@ import {hasAudioCodec} from './get-audio-codec'; +import {hasContainer} from './get-container'; import {hasDimensions} from './get-dimensions'; import {hasDuration} from './get-duration'; import {hasFps} from './get-fps'; import {hasTracks} from './get-tracks'; import {hasVideoCodec} from './get-video-codec'; -import type {Options} from './options'; +import type {Options, ParseMediaFields} from './options'; import type {ParseResult} from './parse-result'; import type {ParserState} from './parser-state'; -export const hasAllInfo = ( - options: Options< - boolean, - boolean, - boolean, - boolean, - boolean, - boolean, - boolean, - boolean, - boolean, - boolean - >, +export const getAvailableInfo = ( + options: Options, parseResult: ParseResult, state: ParserState, -) => { - const keys = Object.entries(options) - .filter(([, value]) => value) - .map(([key]) => key) as (keyof Options< - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - >)[]; - - return keys.every((key) => { +): Record, boolean> => { + const keys = Object.entries(options).filter(([, value]) => value) as [ + keyof Options, + boolean, + ][]; + + const infos = keys.map(([key]) => { if (key === 'boxes') { return parseResult.status === 'done'; } @@ -57,7 +37,7 @@ export const hasAllInfo = ( } if (key === 'fps') { - return hasFps(parseResult.segments) !== null; + return hasFps(parseResult.segments); } if (key === 'videoCodec') { @@ -65,7 +45,7 @@ export const hasAllInfo = ( } if (key === 'audioCodec') { - return hasAudioCodec(parseResult.segments); + return hasAudioCodec(parseResult.segments, state); } if (key === 'tracks') { @@ -76,6 +56,30 @@ export const hasAllInfo = ( return false; } + if (key === 'size') { + return true; + } + + if (key === 'name') { + return true; + } + + if (key === 'container') { + return hasContainer(parseResult.segments); + } + throw new Error(`Unknown key: ${key satisfies never}`); }); + + const entries: [keyof Options, boolean][] = []; + let i = 0; + + for (const [key] of keys) { + entries.push([key, infos[i++]]); + } + + return Object.fromEntries(entries) as Record< + keyof Options, + boolean + >; }; diff --git a/packages/media-parser/src/index.ts b/packages/media-parser/src/index.ts index 8554b2c5d16..3853bff5148 100644 --- a/packages/media-parser/src/index.ts +++ b/packages/media-parser/src/index.ts @@ -1,6 +1,22 @@ import {createMedia} from './create/create-media'; -export {AudioTrack, OtherTrack, Track, VideoTrack} from './get-tracks'; +export { + AudioTrack, + MediaParserAudioCodec, + MediaParserVideoCodec, + OtherTrack, + Track, + VideoTrack, + VideoTrackColorParams, +} from './get-tracks'; + +export type { + Options, + ParseMediaContainer, + ParseMediaFields, + ParseMediaResult, + TracksField, +} from './options'; export {parseMedia} from './parse-media'; export { AudioSample, @@ -12,6 +28,7 @@ export { } from './webcodec-sample-types'; export type {MediaFn} from './create/create-media'; +export {Dimensions} from './get-dimensions'; export const MediaParserInternals = { createMedia, diff --git a/packages/media-parser/src/options.ts b/packages/media-parser/src/options.ts index 2e37ba323d3..435811122e7 100644 --- a/packages/media-parser/src/options.ts +++ b/packages/media-parser/src/options.ts @@ -1,19 +1,16 @@ import type {} from './boxes/iso-base-media/mdat/mdat'; import type {Dimensions} from './get-dimensions'; -import type {AudioTrack, VideoTrack} from './get-tracks'; +import type { + AudioTrack, + MediaParserAudioCodec, + MediaParserVideoCodec, + VideoTrack, +} from './get-tracks'; import type {AnySegment} from './parse-result'; import type {InternalStats} from './parser-state'; import type {ReaderInterface} from './readers/reader'; import type {OnAudioTrack, OnVideoTrack} from './webcodec-sample-types'; -export type KnownVideoCodecs = - | 'h264' - | 'h265' - | 'vp8' - | 'vp9' - | 'av1' - | 'prores'; - export type KnownAudioCodecs = | 'aac' | 'mp3' @@ -23,96 +20,132 @@ export type KnownAudioCodecs = | 'vorbis' | 'unknown'; -export type Options< - EnableDimensions extends boolean, - EnableDuration extends boolean, - EnableBoxes extends boolean, - EnableFps extends boolean, - EnableVideoCodec extends boolean, - EnableAudioCodec extends boolean, - EnableTracks extends boolean, - EnableRotation extends boolean, - EnableUnrotatedDimensions extends boolean, - EnableInternalStats extends boolean, -> = { - dimensions?: EnableDimensions; - durationInSeconds?: EnableDuration; - boxes?: EnableBoxes; - fps?: EnableFps; - videoCodec?: EnableVideoCodec; - audioCodec?: EnableAudioCodec; - tracks?: EnableTracks; - rotation?: EnableRotation; - unrotatedDimensions?: EnableUnrotatedDimensions; - internalStats?: EnableInternalStats; +export type ParseMediaFields = { + dimensions: boolean; + durationInSeconds: boolean; + boxes: boolean; + fps: boolean; + videoCodec: boolean; + audioCodec: boolean; + tracks: boolean; + rotation: boolean; + unrotatedDimensions: boolean; + internalStats: boolean; + size: boolean; + name: boolean; + container: boolean; }; -export type Metadata< - EnableDimensions extends boolean, - EnableDuration extends boolean, - EnableBoxes extends boolean, - EnableFps extends boolean, - EnableVideoCodec extends boolean, - EnableAudioCodec extends boolean, - EnableTracks extends boolean, - EnableRotation extends boolean, - EnableUnrotatedDimensions extends boolean, - EnableInternalStats extends boolean, -> = (EnableDimensions extends true ? {dimensions: Dimensions} : {}) & - (EnableDuration extends true ? {durationInSeconds: number | null} : {}) & - (EnableBoxes extends true ? {boxes: AnySegment[]} : {}) & - (EnableFps extends true ? {fps: number | null} : {}) & - (EnableVideoCodec extends true ? {videoCodec: KnownVideoCodecs | null} : {}) & - (EnableAudioCodec extends true ? {audioCodec: KnownAudioCodecs | null} : {}) & - (EnableTracks extends true - ? {videoTracks: VideoTrack[]; audioTracks: AudioTrack[]} - : {}) & - (EnableRotation extends true ? {rotation: number | null} : {}) & - (EnableUnrotatedDimensions extends true - ? {unrotatedDimensions: Dimensions} +export type AllParseMediaFields = { + dimensions: true; + durationInSeconds: true; + boxes: true; + fps: true; + videoCodec: true; + audioCodec: true; + tracks: true; + rotation: true; + unrotatedDimensions: true; + internalStats: true; + size: true; + name: true; + container: true; +}; + +export type Options = { + dimensions?: Fields['dimensions']; + durationInSeconds?: Fields['durationInSeconds']; + boxes?: Fields['boxes']; + fps?: Fields['fps']; + videoCodec?: Fields['videoCodec']; + audioCodec?: Fields['audioCodec']; + tracks?: Fields['tracks']; + rotation?: Fields['rotation']; + unrotatedDimensions?: Fields['unrotatedDimensions']; + internalStats?: Fields['internalStats']; + size?: Fields['size']; + name?: Fields['name']; + container?: Fields['container']; +}; + +export type TracksField = { + videoTracks: VideoTrack[]; + audioTracks: AudioTrack[]; +}; + +export type ParseMediaContainer = 'mp4' | 'webm'; + +export type ParseMediaCallbacks> = + (Fields['dimensions'] extends true + ? {onDimensions?: (dimensions: Dimensions) => void} : {}) & - (EnableInternalStats extends true ? {internalStats: InternalStats} : {}); + (Fields['durationInSeconds'] extends true + ? {onDurationInSeconds?: (durationInSeconds: number | null) => void} + : {}) & + (Fields['boxes'] extends true + ? {onBoxes?: (boxes: AnySegment[]) => void} + : {}) & + (Fields['fps'] extends true ? {onFps?: (fps: number | null) => void} : {}) & + (Fields['videoCodec'] extends true + ? {onVideoCodec?: (codec: MediaParserVideoCodec | null) => void} + : {}) & + (Fields['audioCodec'] extends true + ? {onAudioCodec?: (codec: MediaParserAudioCodec | null) => void} + : {}) & + (Fields['tracks'] extends true + ? {onTracks?: (tracks: TracksField) => void} + : {}) & + (Fields['rotation'] extends true + ? {onRotation?: (rotation: number | null) => void} + : {}) & + (Fields['unrotatedDimensions'] extends true + ? {onUnrotatedDimensions?: (dimensions: Dimensions) => void} + : {}) & + (Fields['internalStats'] extends true + ? {onInternalStats?: (stats: InternalStats) => void} + : {}) & + (Fields['size'] extends true + ? {onSize?: (size: number | null) => void} + : {}) & + (Fields['name'] extends true ? {onName?: (name: string) => void} : {}) & + (Fields['container'] extends true + ? {onContainer?: (container: ParseMediaContainer | null) => void} + : {}); + +export type ParseMediaResult> = + (Fields['dimensions'] extends true ? {dimensions: Dimensions} : {}) & + (Fields['durationInSeconds'] extends true + ? {durationInSeconds: number | null} + : {}) & + (Fields['boxes'] extends true ? {boxes: AnySegment[]} : {}) & + (Fields['fps'] extends true ? {fps: number | null} : {}) & + (Fields['videoCodec'] extends true + ? {videoCodec: MediaParserVideoCodec | null} + : {}) & + (Fields['audioCodec'] extends true + ? {audioCodec: MediaParserAudioCodec | null} + : {}) & + (Fields['tracks'] extends true ? TracksField : {}) & + (Fields['rotation'] extends true ? {rotation: number | null} : {}) & + (Fields['unrotatedDimensions'] extends true + ? {unrotatedDimensions: Dimensions} + : {}) & + (Fields['internalStats'] extends true + ? {internalStats: InternalStats} + : {}) & + (Fields['size'] extends true ? {size: number | null} : {}) & + (Fields['name'] extends true ? {name: string} : {}) & + (Fields['container'] extends true + ? {container: ParseMediaContainer | null} + : {}); -export type ParseMedia = < - EnableDimensions extends boolean, - EnableDuration extends boolean, - EnableBoxes extends boolean, - EnableFps extends boolean, - EnableVideoCodec extends boolean, - EnableAudioCodec extends boolean, - EnableTracks extends boolean, - EnableRotation extends boolean, - EnableUnrotatedDimensions extends boolean, - EnableInternalStats extends boolean, ->(options: { - src: string | File; - fields?: Options< - EnableDimensions, - EnableDuration, - EnableBoxes, - EnableFps, - EnableVideoCodec, - EnableAudioCodec, - EnableTracks, - EnableRotation, - EnableUnrotatedDimensions, - EnableInternalStats - >; - reader?: ReaderInterface; - onAudioTrack?: OnAudioTrack; - onVideoTrack?: OnVideoTrack; - signal?: AbortSignal; -}) => Promise< - Metadata< - EnableDimensions, - EnableDuration, - EnableBoxes, - EnableFps, - EnableVideoCodec, - EnableAudioCodec, - EnableTracks, - EnableRotation, - EnableUnrotatedDimensions, - EnableInternalStats - > ->; +export type ParseMedia = >( + options: { + src: string | File; + fields?: F; + reader?: ReaderInterface; + onAudioTrack?: OnAudioTrack; + onVideoTrack?: OnVideoTrack; + signal?: AbortSignal; + } & ParseMediaCallbacks, +) => Promise>; diff --git a/packages/media-parser/src/parse-media.ts b/packages/media-parser/src/parse-media.ts index 3fdf5679bb9..a3b2bb47ecf 100644 --- a/packages/media-parser/src/parse-media.ts +++ b/packages/media-parser/src/parse-media.ts @@ -1,14 +1,14 @@ /* eslint-disable max-depth */ import type {BufferIterator} from './buffer-iterator'; import {getArrayBufferIterator} from './buffer-iterator'; -import {getAudioCodec} from './get-audio-codec'; -import {getDimensions} from './get-dimensions'; -import {getDuration} from './get-duration'; -import {getFps} from './get-fps'; -import {getTracks} from './get-tracks'; -import {getVideoCodec} from './get-video-codec'; -import {hasAllInfo} from './has-all-info'; -import type {Metadata, ParseMedia} from './options'; +import {emitAvailableInfo} from './emit-available-info'; +import {getAvailableInfo} from './has-all-info'; +import type { + AllParseMediaFields, + ParseMedia, + ParseMediaCallbacks, + ParseMediaResult, +} from './options'; import type {ParseResult} from './parse-result'; import {parseVideo} from './parse-video'; import type {ParserContext} from './parser-context'; @@ -22,27 +22,22 @@ export const parseMedia: ParseMedia = async ({ onAudioTrack, onVideoTrack, signal, + ...more }) => { const state = makeParserState({ hasAudioCallbacks: onAudioTrack !== null, hasVideoCallbacks: onVideoTrack !== null, signal, }); - const {reader, contentLength} = await readerInterface.read(src, null, signal); + const {reader, contentLength, name} = await readerInterface.read( + src, + null, + signal, + ); let currentReader = reader; - const returnValue = {} as Metadata< - true, - true, - true, - true, - true, - true, - true, - true, - true, - true - >; + const returnValue = {} as ParseMediaResult; + const moreFields = more as ParseMediaCallbacks; let iterator: BufferIterator | null = null; let parseResult: ParseResult | null = null; @@ -64,7 +59,7 @@ export const parseMedia: ParseMedia = async ({ throw new Error('Aborted'); } - const result = await currentReader.read(); + const result = await currentReader.reader.read(); if (iterator) { if (!result.done) { @@ -87,20 +82,26 @@ export const parseMedia: ParseMedia = async ({ parseResult = await parseVideo({ iterator, options, + signal: signal ?? null, }); } + const availableInfo = getAvailableInfo(fields ?? {}, parseResult, state); + const hasAllInfo = Object.values(availableInfo).every(Boolean); + + emitAvailableInfo({ + hasInfo: availableInfo, + moreFields, + parseResult, + state, + returnValue, + contentLength, + name, + }); + // TODO Better: Check if no active listeners are registered // Also maybe check for canSkipVideoData - if ( - hasAllInfo(fields ?? {}, parseResult, state) && - !onVideoTrack && - !onAudioTrack - ) { - if (!currentReader.closed) { - currentReader.cancel(new Error('has all information')); - } - + if (hasAllInfo && !onVideoTrack && !onAudioTrack) { break; } @@ -109,10 +110,6 @@ export const parseMedia: ParseMedia = async ({ parseResult.status === 'incomplete' && parseResult.skipTo !== null ) { - if (!currentReader.closed) { - currentReader.cancel(new Error('skipped ahead')); - } - const {reader: newReader} = await readerInterface.read( src, parseResult.skipTo, @@ -123,60 +120,32 @@ export const parseMedia: ParseMedia = async ({ } } - if (!parseResult) { - throw new Error('Could not parse video'); - } - - if (fields?.dimensions) { - const dimensions = getDimensions(parseResult.segments, state); - returnValue.dimensions = { - width: dimensions.width, - height: dimensions.height, - }; - } - - if (fields?.unrotatedDimensions) { - const dimensions = getDimensions(parseResult.segments, state); - returnValue.unrotatedDimensions = { - width: dimensions.unrotatedWidth, - height: dimensions.unrotatedHeight, - }; - } - - if (fields?.rotation) { - const dimensions = getDimensions(parseResult.segments, state); - returnValue.rotation = dimensions.rotation; - } - - if (fields?.durationInSeconds) { - returnValue.durationInSeconds = getDuration(parseResult.segments, state); - } - - if (fields?.fps) { - returnValue.fps = getFps(parseResult.segments); - } - - if (fields?.videoCodec) { - returnValue.videoCodec = getVideoCodec(parseResult.segments); - } - - if (fields?.audioCodec) { - returnValue.audioCodec = getAudioCodec(parseResult.segments); - } - - if (fields?.tracks) { - const {audioTracks, videoTracks} = getTracks(parseResult.segments, state); - returnValue.audioTracks = audioTracks; - returnValue.videoTracks = videoTracks; - } - - if (fields?.boxes) { - returnValue.boxes = parseResult.segments; - } + // Force assign + emitAvailableInfo({ + hasInfo: { + boxes: true, + durationInSeconds: true, + dimensions: true, + fps: true, + videoCodec: true, + audioCodec: true, + tracks: true, + rotation: true, + unrotatedDimensions: true, + internalStats: true, + size: true, + name: true, + container: true, + }, + moreFields, + parseResult, + state, + returnValue, + contentLength, + name, + }); - if (fields?.internalStats) { - returnValue.internalStats = state.getInternalStats(); - } + currentReader.abort(); iterator?.destroy(); return returnValue; diff --git a/packages/media-parser/src/parse-video.ts b/packages/media-parser/src/parse-video.ts index 1411888de40..6eb13c102c9 100644 --- a/packages/media-parser/src/parse-video.ts +++ b/packages/media-parser/src/parse-video.ts @@ -25,9 +25,11 @@ export type BoxAndNext = export const parseVideo = ({ iterator, options, + signal, }: { iterator: BufferIterator; options: ParserContext; + signal: AbortSignal | null; }): Promise => { if (iterator.bytesRemaining() === 0) { return Promise.resolve({ @@ -37,6 +39,7 @@ export const parseVideo = ({ return parseVideo({ iterator, options, + signal, }); }, skipTo: null, @@ -68,6 +71,7 @@ export const parseVideo = ({ options, continueMdat: false, littleEndian: false, + signal, }); } diff --git a/packages/media-parser/src/parser-state.ts b/packages/media-parser/src/parser-state.ts index c4cb127b7ea..01b2e9314fb 100644 --- a/packages/media-parser/src/parser-state.ts +++ b/packages/media-parser/src/parser-state.ts @@ -1,7 +1,10 @@ import type {OnTrackEntrySegment} from './boxes/webm/segments'; import type {TrackInfo} from './boxes/webm/segments/track-entry'; -import {getTrackCodec, getTrackTimestampScale} from './boxes/webm/traversal'; -import {getTrackId} from './traversal'; +import { + getTrackCodec, + getTrackId, + getTrackTimestampScale, +} from './boxes/webm/traversal'; import type { AudioSample, OnAudioSample, diff --git a/packages/media-parser/src/readers/from-fetch.ts b/packages/media-parser/src/readers/from-fetch.ts index 19a3d5d2607..e6b81aeb3e5 100644 --- a/packages/media-parser/src/readers/from-fetch.ts +++ b/packages/media-parser/src/readers/from-fetch.ts @@ -24,6 +24,8 @@ export const fetchReader: ReaderInterface = { ); } + const controller = new AbortController(); + const res = await fetch(resolvedUrl, { headers: range === null @@ -35,11 +37,19 @@ export const fetchReader: ReaderInterface = { : { Range: `bytes=${`${range[0]}-${range[1]}`}`, }, - signal, + signal: controller.signal, // Disable Next.js caching cache: 'no-store', }); + signal?.addEventListener( + 'abort', + () => { + controller.abort(); + }, + {once: true}, + ); + if ( res.status.toString().startsWith('4') || res.status.toString().startsWith('5') @@ -54,6 +64,10 @@ export const fetchReader: ReaderInterface = { const length = res.headers.get('content-length'); const contentLength = length === null ? null : parseInt(length, 10); + const contentDisposition = res.headers.get('content-disposition'); + const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1]; + + const fallbackName = src.split('/').pop(); const reader = res.body.getReader(); @@ -61,13 +75,24 @@ export const fetchReader: ReaderInterface = { signal.addEventListener( 'abort', () => { - reader.cancel(); + reader.cancel().catch(() => { + // Prevent unhandled rejection in Firefox + }); }, {once: true}, ); } - return {reader, contentLength}; + return { + reader: { + reader, + abort: () => { + controller.abort(); + }, + }, + contentLength, + name: name ?? (fallbackName as string), + }; }, getLength: async (src) => { if (typeof src !== 'string') { diff --git a/packages/media-parser/src/readers/from-node.ts b/packages/media-parser/src/readers/from-node.ts index a1683bebd97..b4c153c651a 100644 --- a/packages/media-parser/src/readers/from-node.ts +++ b/packages/media-parser/src/readers/from-node.ts @@ -9,6 +9,8 @@ export const nodeReader: ReaderInterface = { throw new Error('src must be a string when using `nodeReader`'); } + const controller = new AbortController(); + const stream = createReadStream(src, { start: range === null ? 0 : typeof range === 'number' ? range : range[0], end: @@ -17,8 +19,17 @@ export const nodeReader: ReaderInterface = { : typeof range === 'number' ? Infinity : range[1], - signal, + signal: controller.signal, }); + + signal?.addEventListener( + 'abort', + () => { + controller.abort(); + }, + {once: true}, + ); + const stats = await stat(src); const reader = Readable.toWeb( @@ -29,15 +40,21 @@ export const nodeReader: ReaderInterface = { signal.addEventListener( 'abort', () => { - reader.cancel(); + reader.cancel().catch(() => {}); }, {once: true}, ); } return { - reader, + reader: { + reader, + abort: () => { + controller.abort(); + }, + }, contentLength: stats.size, + name: src.split('/').pop() as string, }; }, getLength: async (src) => { diff --git a/packages/media-parser/src/readers/from-web-file.ts b/packages/media-parser/src/readers/from-web-file.ts index fc9bd630077..3a0fb803431 100644 --- a/packages/media-parser/src/readers/from-web-file.ts +++ b/packages/media-parser/src/readers/from-web-file.ts @@ -16,11 +16,23 @@ export const webFileReader: ReaderInterface = { const reader = new FileReader(); reader.readAsArrayBuffer(file); + const controller = new AbortController(); + + if (controller) { + controller.signal.addEventListener( + 'abort', + () => { + reader.abort(); + }, + {once: true}, + ); + } + if (signal) { signal.addEventListener( 'abort', () => { - reader.abort(); + controller.abort(); }, {once: true}, ); @@ -29,8 +41,14 @@ export const webFileReader: ReaderInterface = { return new Promise((resolve, reject) => { reader.onload = () => { resolve({ - reader: part.stream().getReader(), + reader: { + reader: part.stream().getReader(), + abort() { + controller.abort(); + }, + }, contentLength: file.size, + name: file.name, }); }; diff --git a/packages/media-parser/src/readers/reader.ts b/packages/media-parser/src/readers/reader.ts index 43bc988b35c..c88189af25f 100644 --- a/packages/media-parser/src/readers/reader.ts +++ b/packages/media-parser/src/readers/reader.ts @@ -1,6 +1,12 @@ -type ReadResult = { +type Reader = { reader: ReadableStreamDefaultReader; + abort: () => void; +}; + +type ReadResult = { + reader: Reader; contentLength: number | null; + name: string; }; type ReadContent = ( src: string | File, diff --git a/packages/media-parser/src/samples-from-moof.ts b/packages/media-parser/src/samples-from-moof.ts index 8ba9a14261e..cbfbc6036ab 100644 --- a/packages/media-parser/src/samples-from-moof.ts +++ b/packages/media-parser/src/samples-from-moof.ts @@ -1,6 +1,10 @@ +import { + getTfdtBox, + getTfhdBox, + getTrunBoxes, +} from './boxes/iso-base-media/traversal'; import type {SamplePosition} from './get-sample-positions'; import type {AnySegment, IsoBaseMediaBox} from './parse-result'; -import {getTfdtBox, getTfhdBox, getTrunBoxes} from './traversal'; const getSamplesFromTraf = ( trafSegment: IsoBaseMediaBox, diff --git a/packages/media-parser/src/test/av1.test.ts b/packages/media-parser/src/test/av1.test.ts index d8d14dc61f5..74a35424cd7 100644 --- a/packages/media-parser/src/test/av1.test.ts +++ b/packages/media-parser/src/test/av1.test.ts @@ -1,10 +1,10 @@ import {RenderInternals} from '@remotion/renderer'; import {expect, test} from 'bun:test'; +import {getMoovBox, getTraks} from '../boxes/iso-base-media/traversal'; import {trakBoxContainsVideo} from '../get-fps'; import {getAv1CBox} from '../get-sample-aspect-ratio'; import {parseMedia} from '../parse-media'; import {nodeReader} from '../readers/from-node'; -import {getMoovBox, getTraks} from '../traversal'; test('AV1 in MP4', async () => { const parsed = await parseMedia({ diff --git a/packages/media-parser/src/test/stream-local.test.ts b/packages/media-parser/src/test/stream-local.test.ts index 812951f7283..385d7572e17 100644 --- a/packages/media-parser/src/test/stream-local.test.ts +++ b/packages/media-parser/src/test/stream-local.test.ts @@ -1,5 +1,6 @@ import {RenderInternals} from '@remotion/renderer'; import {expect, test} from 'bun:test'; +import type {MediaParserAudioCodec} from '../get-tracks'; import {parseMedia} from '../parse-media'; import {nodeReader} from '../readers/from-node'; @@ -148,6 +149,16 @@ test('Should stream AV1', async () => { displayAspectWidth: 1920, rotation: 0, trakBox: null, + codecPrivate: new Uint8Array([ + 129, 8, 12, 0, 10, 14, 0, 0, 0, 66, 171, 191, 195, 118, 0, 8, 8, 8, 8, 32, + ]), + color: { + fullRange: null, + transferCharacteristics: 'bt709', + matrixCoefficients: 'bt709', + primaries: 'bt709', + }, + codecWithoutConfig: 'av1', }); expect(parsed.audioTracks.length).toBe(0); expect(videoTracks).toBe(1); @@ -303,6 +314,14 @@ test('Should stream variable fps video', async () => { displayAspectWidth: 1280, rotation: 0, trakBox: null, + codecPrivate: null, + color: { + fullRange: null, + transferCharacteristics: null, + matrixCoefficients: null, + primaries: null, + }, + codecWithoutConfig: 'vp8', }); expect(parsed.audioTracks.length).toBe(1); expect(parsed.audioTracks[0]).toEqual({ @@ -314,6 +333,10 @@ test('Should stream variable fps video', async () => { sampleRate: 48000, description: undefined, trakBox: null, + codecPrivate: new Uint8Array([ + 79, 112, 117, 115, 72, 101, 97, 100, 1, 1, 0, 0, 128, 187, 0, 0, 0, 0, 0, + ]), + codecWithoutConfig: 'opus', }); expect(audioTracks).toBe(1); expect(samples).toBe(381); @@ -354,7 +377,7 @@ test('Should stream MKV video', async () => { expect(parsed.dimensions.height).toBe(1080); expect(parsed.durationInSeconds).toBe(0.333); expect(parsed.videoCodec).toBe('h264'); - expect(parsed.audioCodec).toBe('pcm'); + expect(parsed.audioCodec).toBe('pcm-s16'); expect(parsed.rotation).toBe(0); expect(parsed.fps).toBe(null); @@ -592,6 +615,14 @@ test('Stretched VP8', async () => { displayAspectHeight: 1080, displayAspectWidth: 1920, rotation: 0, + codecPrivate: null, + color: { + fullRange: null, + transferCharacteristics: null, + matrixCoefficients: null, + primaries: null, + }, + codecWithoutConfig: 'vp8', }); }); @@ -667,12 +698,16 @@ test('MP3 in matroska', async () => { test('Should stream OPUS', async () => { let audioSamples = 0; + let audioCodec: MediaParserAudioCodec | null = null; const parsed = await parseMedia({ src: RenderInternals.exampleVideos.opusWebm, fields: { tracks: true, audioCodec: true, }, + onAudioCodec: (codec) => { + audioCodec = codec; + }, reader: nodeReader, onAudioTrack: (track) => { expect(track.codec).toEqual('opus'); @@ -684,7 +719,8 @@ test('Should stream OPUS', async () => { }, }); - expect(parsed.audioCodec).toEqual('opus'); + // @ts-expect-error + expect(audioCodec).toEqual('opus'); expect(parsed.audioTracks.length).toBe(1); expect(audioSamples).toBe(167); }); diff --git a/packages/media-parser/src/test/stream-samples.test.ts b/packages/media-parser/src/test/stream-samples.test.ts index 385cb4aedc7..c58e9fb0f90 100644 --- a/packages/media-parser/src/test/stream-samples.test.ts +++ b/packages/media-parser/src/test/stream-samples.test.ts @@ -40,6 +40,18 @@ test('Stream samples', async () => { displayAspectHeight: 1080, displayAspectWidth: 1080, rotation: 0, + codecPrivate: new Uint8Array([ + 1, 100, 0, 32, 255, 225, 0, 32, 103, 100, 0, 32, 172, 217, 64, 68, 2, 39, + 150, 92, 5, 168, 16, 16, 45, 40, 0, 0, 3, 0, 8, 0, 0, 3, 1, 224, 120, 193, + 140, 176, 1, 0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0, + ]), + color: { + fullRange: null, + transferCharacteristics: null, + matrixCoefficients: null, + primaries: null, + }, + codecWithoutConfig: 'h264', }); expect(getSamplePositionsFromTrack(trakBox as TrakBox, null)); @@ -55,6 +67,8 @@ test('Stream samples', async () => { codec: 'mp3', sampleRate: 48000, description: undefined, + codecPrivate: null, + codecWithoutConfig: 'mp3', }); expect(getSamplePositionsFromTrack(trakBox2 as TrakBox, null)).toEqual([ { diff --git a/packages/media-parser/src/test/stsd.test.ts b/packages/media-parser/src/test/stsd.test.ts index 2c2db8abc1b..9f21a1459fe 100644 --- a/packages/media-parser/src/test/stsd.test.ts +++ b/packages/media-parser/src/test/stsd.test.ts @@ -53,6 +53,7 @@ test('Should be able to parse a STSD audio box correctly', async () => { }), nullifySamples: false, }, + signal: null, }); expect(parsed).toEqual({ @@ -219,6 +220,7 @@ test('Should be able to parse a STSD video box correctly', async () => { }), nullifySamples: false, }, + signal: null, }); expect(parsed.sample).toEqual({ size: 158, @@ -245,7 +247,7 @@ test('Should be able to parse a STSD video box correctly', async () => { colorTableId: -1, descriptors: [ { - description: new Uint8Array([ + privateData: new Uint8Array([ 1, 100, 0, 32, 255, 225, 0, 27, 103, 100, 0, 32, 172, 217, 64, 68, 2, 39, 150, 92, 4, 64, 0, 0, 3, 0, 64, 0, 0, 12, 3, 198, 12, 101, 128, 1, 0, 6, 104, 235, 224, 140, 178, 44, 253, 248, 248, 0, diff --git a/packages/media-parser/src/traversal.ts b/packages/media-parser/src/traversal.ts deleted file mode 100644 index f6508c4bfcb..00000000000 --- a/packages/media-parser/src/traversal.ts +++ /dev/null @@ -1,528 +0,0 @@ -import type {FtypBox} from './boxes/iso-base-media/ftyp'; -import type {MdhdBox} from './boxes/iso-base-media/mdhd'; -import type {MoovBox} from './boxes/iso-base-media/moov/moov'; -import type {MvhdBox} from './boxes/iso-base-media/mvhd'; -import type {CttsBox} from './boxes/iso-base-media/stsd/ctts'; -import type {StcoBox} from './boxes/iso-base-media/stsd/stco'; -import type {StscBox} from './boxes/iso-base-media/stsd/stsc'; -import type {StsdBox} from './boxes/iso-base-media/stsd/stsd'; -import type {StssBox} from './boxes/iso-base-media/stsd/stss'; -import type {StszBox} from './boxes/iso-base-media/stsd/stsz'; -import type {SttsBox} from './boxes/iso-base-media/stsd/stts'; -import type {TfdtBox} from './boxes/iso-base-media/tfdt'; -import type {TfhdBox} from './boxes/iso-base-media/tfhd'; -import type {TkhdBox} from './boxes/iso-base-media/tkhd'; -import type {TrakBox} from './boxes/iso-base-media/trak/trak'; -import type {TrunBox} from './boxes/iso-base-media/trun'; -import type { - AudioSegment, - ClusterSegment, - CodecIdSegment, - DisplayHeightSegment, - DisplayWidthSegment, - HeightSegment, - MainSegment, - TimestampScaleSegment, - TrackEntry, - TrackTypeSegment, - VideoSegment, - WidthSegment, -} from './boxes/webm/segments/all-segments'; -import type {AnySegment, IsoBaseMediaBox, RegularBox} from './parse-result'; - -export const getFtypBox = (segments: AnySegment[]): FtypBox | null => { - const ftypBox = segments.find((s) => s.type === 'ftyp-box'); - if (!ftypBox || ftypBox.type !== 'ftyp-box') { - return null; - } - - return ftypBox; -}; - -export const getMoovBox = (segments: AnySegment[]): MoovBox | null => { - const moovBox = segments.find((s) => s.type === 'moov-box'); - if (!moovBox || moovBox.type !== 'moov-box') { - return null; - } - - return moovBox; -}; - -export const getMoofBox = (main: AnySegment[]): IsoBaseMediaBox | null => { - const moofBox = main.find( - (s) => s.type === 'regular-box' && s.boxType === 'moof', - ); - - if (!moofBox || moofBox.type !== 'regular-box') { - return null; - } - - return moofBox; -}; - -export const getMvhdBox = (moovBox: MoovBox): MvhdBox | null => { - const mvHdBox = moovBox.children.find((s) => s.type === 'mvhd-box'); - - if (!mvHdBox || mvHdBox.type !== 'mvhd-box') { - return null; - } - - return mvHdBox; -}; - -export const getTraks = (moovBox: MoovBox): TrakBox[] => { - return moovBox.children.filter((s) => s.type === 'trak-box') as TrakBox[]; -}; - -export const getTkhdBox = (trakBox: TrakBox): TkhdBox | null => { - const tkhdBox = trakBox.children.find( - (s) => s.type === 'tkhd-box', - ) as TkhdBox | null; - - return tkhdBox; -}; - -export const getMdiaBox = (trakBox: TrakBox): RegularBox | null => { - const mdiaBox = trakBox.children.find( - (s) => s.type === 'regular-box' && s.boxType === 'mdia', - ); - - if (!mdiaBox || mdiaBox.type !== 'regular-box') { - return null; - } - - return mdiaBox; -}; - -export const getMdhdBox = (trakBox: TrakBox): MdhdBox | null => { - const mdiaBox = getMdiaBox(trakBox); - - if (!mdiaBox) { - return null; - } - - const mdhdBox = mdiaBox.children.find( - (c) => c.type === 'mdhd-box', - ) as MdhdBox | null; - - return mdhdBox; -}; - -export const getStblBox = (trakBox: TrakBox): RegularBox | null => { - const mdiaBox = getMdiaBox(trakBox); - - if (!mdiaBox) { - return null; - } - - const minfBox = mdiaBox.children.find( - (s) => s.type === 'regular-box' && s.boxType === 'minf', - ); - - if (!minfBox || minfBox.type !== 'regular-box') { - return null; - } - - const stblBox = minfBox.children.find( - (s) => s.type === 'regular-box' && s.boxType === 'stbl', - ); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - return stblBox; -}; - -export const getStsdBox = (trakBox: TrakBox): StsdBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const stsdBox = stblBox.children.find( - (s) => s.type === 'stsd-box', - ) as StsdBox | null; - - return stsdBox; -}; - -export const getVideoDescriptors = (trakBox: TrakBox): Uint8Array | null => { - const stsdBox = getStsdBox(trakBox); - - if (!stsdBox) { - return null; - } - - const descriptors = stsdBox.samples.map((s) => { - return s.type === 'video' - ? s.descriptors.map((d) => { - return d.type === 'avcc-box' - ? d.description - : d.type === 'hvcc-box' - ? d.data - : null; - }) - : []; - }); - - return descriptors.flat(1).filter(Boolean)[0] ?? null; -}; - -export const getStcoBox = (trakBox: TrakBox): StcoBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const stcoBox = stblBox.children.find( - (s) => s.type === 'stco-box', - ) as StcoBox | null; - - return stcoBox; -}; - -export const getSttsBox = (trakBox: TrakBox): SttsBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const sttsBox = stblBox.children.find( - (s) => s.type === 'stts-box', - ) as SttsBox | null; - - return sttsBox; -}; - -export const getCttsBox = (trakBox: TrakBox): CttsBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const cttsBox = stblBox.children.find( - (s) => s.type === 'ctts-box', - ) as CttsBox | null; - - return cttsBox; -}; - -export const getStszBox = (trakBox: TrakBox): StszBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const stszBox = stblBox.children.find( - (s) => s.type === 'stsz-box', - ) as StszBox | null; - - return stszBox; -}; - -export const getStscBox = (trakBox: TrakBox): StscBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const stcoBox = stblBox.children.find( - (b) => b.type === 'stsc-box', - ) as StscBox | null; - - return stcoBox; -}; - -export const getStssBox = (trakBox: TrakBox): StssBox | null => { - const stblBox = getStblBox(trakBox); - - if (!stblBox || stblBox.type !== 'regular-box') { - return null; - } - - const stssBox = stblBox.children.find( - (b) => b.type === 'stss-box', - ) as StssBox | null; - - return stssBox; -}; - -export const getTfdtBox = (segment: IsoBaseMediaBox): TfdtBox | null => { - if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { - throw new Error('Expected traf-box'); - } - - const tfhdBox = segment.children.find((c) => c.type === 'tfdt-box'); - - if (!tfhdBox || tfhdBox.type !== 'tfdt-box') { - throw new Error('Expected tfhd-box'); - } - - return tfhdBox; -}; - -export const getTfhdBox = (segment: IsoBaseMediaBox): TfhdBox | null => { - if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { - throw new Error('Expected traf-box'); - } - - const tfhdBox = segment.children.find( - (c) => c.type === 'tfhd-box', - ) as TfhdBox; - - if (!tfhdBox || tfhdBox.type !== 'tfhd-box') { - throw new Error('Expected tfhd-box'); - } - - return tfhdBox; -}; - -export const getTrunBoxes = (segment: IsoBaseMediaBox): TrunBox[] => { - if (segment.type !== 'regular-box' || segment.boxType !== 'traf') { - throw new Error('Expected traf-box'); - } - - const trunBoxes = segment.children.filter((c) => c.type === 'trun-box'); - - return trunBoxes as TrunBox[]; -}; - -export const getClusterSegment = ( - segment: MainSegment, -): ClusterSegment | null => { - const clusterSegment = segment.value.find((b) => b.type === 'Cluster') as - | ClusterSegment - | undefined; - - return clusterSegment ?? null; -}; - -export const getTracksSegment = (segment: MainSegment) => { - const tracksSegment = segment.value.find((b) => b.type === 'Tracks'); - if (!tracksSegment || tracksSegment.type !== 'Tracks') { - return null; - } - - return tracksSegment; -}; - -export const getTimescaleSegment = ( - segment: MainSegment, -): TimestampScaleSegment | null => { - const infoSegment = segment.value.find((b) => b.type === 'Info'); - - if (!infoSegment || infoSegment.type !== 'Info') { - return null; - } - - const timescale = infoSegment.value.find((b) => b.type === 'TimestampScale'); - - if (!timescale || timescale.type !== 'TimestampScale') { - return null; - } - - return timescale as TimestampScaleSegment; -}; - -export const getVideoSegment = (track: TrackEntry): VideoSegment | null => { - const videoSegment = track.value.find((b) => b.type === 'Video'); - if (!videoSegment || videoSegment.type !== 'Video') { - return null; - } - - return videoSegment ?? null; -}; - -export const getAudioSegment = (track: TrackEntry): AudioSegment | null => { - const audioSegment = track.value.find((b) => b.type === 'Audio'); - if (!audioSegment || audioSegment.type !== 'Audio') { - return null; - } - - return audioSegment ?? null; -}; - -export const getSampleRate = (track: TrackEntry): number | null => { - const audioSegment = getAudioSegment(track); - if (!audioSegment) { - return null; - } - - const samplingFrequency = audioSegment.value.find( - (b) => b.type === 'SamplingFrequency', - ); - - if (!samplingFrequency || samplingFrequency.type !== 'SamplingFrequency') { - return null; - } - - return samplingFrequency.value.value; -}; - -export const getNumberOfChannels = (track: TrackEntry): number => { - const audioSegment = getAudioSegment(track); - if (!audioSegment) { - throw new Error('Could not find audio segment'); - } - - const channels = audioSegment.value.find((b) => b.type === 'Channels'); - - if (!channels || channels.type !== 'Channels') { - return 1; - } - - return channels.value.value; -}; - -export const getBitDepth = (track: TrackEntry): number | null => { - const audioSegment = getAudioSegment(track); - if (!audioSegment) { - return null; - } - - const bitDepth = audioSegment.value.find((b) => b.type === 'BitDepth'); - - if (!bitDepth || bitDepth.type !== 'BitDepth') { - return null; - } - - return bitDepth.value.value; -}; - -export const getPrivateData = (track: TrackEntry): Uint8Array | null => { - const privateData = track.value.find((b) => b.type === 'CodecPrivate'); - - if (!privateData || privateData.type !== 'CodecPrivate') { - return null; - } - - return privateData.value; -}; - -export const getWidthSegment = (track: TrackEntry): WidthSegment | null => { - const videoSegment = getVideoSegment(track); - if (!videoSegment) { - return null; - } - - const width = videoSegment.value.find((b) => b.type === 'PixelWidth'); - - if (!width || width.type !== 'PixelWidth') { - return null; - } - - return width; -}; - -export const getHeightSegment = (track: TrackEntry): HeightSegment | null => { - const videoSegment = getVideoSegment(track); - if (!videoSegment) { - return null; - } - - const height = videoSegment.value.find((b) => b.type === 'PixelHeight'); - - if (!height || height.type !== 'PixelHeight') { - return null; - } - - return height; -}; - -export const getDisplayWidthSegment = ( - track: TrackEntry, -): DisplayWidthSegment | null => { - const videoSegment = getVideoSegment(track); - if (!videoSegment) { - return null; - } - - const displayWidth = videoSegment.value.find( - (b) => b.type === 'DisplayWidth', - ); - - if (!displayWidth || displayWidth.type !== 'DisplayWidth') { - return null; - } - - return displayWidth; -}; - -export const getDisplayHeightSegment = ( - track: TrackEntry, -): DisplayHeightSegment | null => { - const videoSegment = getVideoSegment(track); - if (!videoSegment) { - return null; - } - - const displayHeight = videoSegment.value.find( - (b) => b.type === 'DisplayHeight', - ); - - if (!displayHeight || displayHeight.type !== 'DisplayHeight') { - return null; - } - - return displayHeight; -}; - -export const getTrackTypeSegment = ( - track: TrackEntry, -): TrackTypeSegment | null => { - const trackType = track.value.find((b) => b.type === 'TrackType'); - if (!trackType || trackType.type !== 'TrackType') { - return null; - } - - return trackType; -}; - -export const getTrackId = (track: TrackEntry): number => { - const trackId = track.value.find((b) => b.type === 'TrackNumber'); - if (!trackId || trackId.type !== 'TrackNumber') { - throw new Error('Expected track number segment'); - } - - return trackId.value.value; -}; - -export const getCodecSegment = (track: TrackEntry): CodecIdSegment | null => { - const codec = track.value.find((b) => b.type === 'CodecID'); - if (!codec || codec.type !== 'CodecID') { - return null; - } - - return codec; -}; - -export const hasSkippedMdatProcessing = (anySegment: AnySegment[]) => { - const mdat = anySegment.find((b) => b.type === 'mdat-box'); - if (!mdat) { - return { - skipped: false as const, - }; - } - - if (mdat.type !== 'mdat-box') { - throw new Error('Expected mdat-box'); - } - - if (mdat.samplesProcessed) { - return { - skipped: false as const, - }; - } - - return { - skipped: true, - fileOffset: mdat.fileOffset, - }; -}; diff --git a/packages/media-parser/src/writers/buffer.ts b/packages/media-parser/src/writers/buffer.ts new file mode 100644 index 00000000000..9be50244b1d --- /dev/null +++ b/packages/media-parser/src/writers/buffer.ts @@ -0,0 +1,67 @@ +import type {Writer, WriterInterface} from './writer'; + +const createContent = () => { + const buf = new ArrayBuffer(0, { + // TODO: Educate that the buffer is limited to 100MB + maxByteLength: 100_000_000, + }); + if (!buf.resize) { + throw new Error('Could not create buffer writer'); + } + + let data = new Uint8Array(buf); + + const write = (newData: Uint8Array) => { + const oldLength = buf.byteLength; + const newLength = oldLength + newData.byteLength; + buf.resize(newLength); + const newArray = new Uint8Array(buf); + newArray.set(newData, oldLength); + data = newArray; + }; + + const updateDataAt = (position: number, newData: Uint8Array) => { + const newArray = new Uint8Array(buf); + newArray.set(newData, position); + data = newArray; + }; + + let writPromise = Promise.resolve(); + + let removed = false; + + const writer: Writer = { + write: (arr: Uint8Array) => { + writPromise = writPromise.then(() => write(arr)); + return writPromise; + }, + save: () => { + if (removed) { + return Promise.reject( + new Error('Already called .remove() on the result'), + ); + } + + // TODO: Unhardcode name + return Promise.resolve(new File([data], 'hithere', {})); + }, + remove() { + removed = true; + data = new Uint8Array(0); + return Promise.resolve(); + }, + getWrittenByteCount: () => buf.byteLength, + updateDataAt: (position: number, newData: Uint8Array) => { + writPromise = writPromise.then(() => updateDataAt(position, newData)); + return writPromise; + }, + waitForFinish: async () => { + await writPromise; + }, + }; + return Promise.resolve(writer); +}; + +export const bufferWriter: WriterInterface = { + createContent, +}; diff --git a/packages/media-parser/src/writers/web-fs.ts b/packages/media-parser/src/writers/web-fs.ts index c7a8ab513a2..db537529a21 100644 --- a/packages/media-parser/src/writers/web-fs.ts +++ b/packages/media-parser/src/writers/web-fs.ts @@ -24,6 +24,12 @@ const createContent = async () => { await writable.seek(written); }; + const remove = async () => { + await directoryHandle.removeEntry(filename, { + recursive: true, + }); + }; + const writer: Writer = { write: (arr: Uint8Array) => { writPromise = writPromise.then(() => write(arr)); @@ -36,21 +42,11 @@ const createContent = async () => { // Ignore, could already be closed } - const picker = await window.showSaveFilePicker({ - suggestedName: `${Math.random().toString().replace('.', '')}.webm`, - }); - const newHandle = await directoryHandle.getFileHandle(filename, { create: true, }); const newFile = await newHandle.getFile(); - const pickerWriteable = await picker.createWritable(); - const stream = newFile.stream(); - await stream.pipeTo(pickerWriteable); - - await directoryHandle.removeEntry(filename, { - recursive: true, - }); + return newFile; }, getWrittenByteCount: () => written, updateDataAt: (position: number, data: Uint8Array) => { @@ -60,6 +56,7 @@ const createContent = async () => { waitForFinish: async () => { await writPromise; }, + remove, }; return writer; @@ -68,3 +65,16 @@ const createContent = async () => { export const webFsWriter: WriterInterface = { createContent, }; + +export const canUseWebFsWriter = async () => { + const directoryHandle = await navigator.storage.getDirectory(); + const fileHandle = await directoryHandle.getFileHandle( + 'remotion-probe-web-fs-support', + { + create: true, + }, + ); + + const canUse = fileHandle.createWritable !== undefined; + return canUse; +}; diff --git a/packages/media-parser/src/writers/writer.ts b/packages/media-parser/src/writers/writer.ts index 07ab09001f4..3948a5ddf23 100644 --- a/packages/media-parser/src/writers/writer.ts +++ b/packages/media-parser/src/writers/writer.ts @@ -1,9 +1,10 @@ export type Writer = { write: (arr: Uint8Array) => Promise; - save: () => Promise; + save: () => Promise; getWrittenByteCount: () => number; updateDataAt: (position: number, data: Uint8Array) => Promise; waitForFinish: () => Promise; + remove: () => Promise; }; type CreateContent = () => Promise; diff --git a/packages/media-parser/web-file.js b/packages/media-parser/web-file.js new file mode 100644 index 00000000000..6268f88221b --- /dev/null +++ b/packages/media-parser/web-file.js @@ -0,0 +1,2 @@ +// For backwards compatibility when you use Metro +module.exports = require('./dist/readers/from-web-file'); diff --git a/packages/media-parser/web-fs.js b/packages/media-parser/web-fs.js new file mode 100644 index 00000000000..b8eeefef5b0 --- /dev/null +++ b/packages/media-parser/web-fs.js @@ -0,0 +1,2 @@ +// For backwards compatibility when you use Metro +module.exports = require('./dist/writers/web-fs'); diff --git a/packages/renderer/src/example-videos.ts b/packages/renderer/src/example-videos.ts index 96e660e2c3b..eb1dd7dc7be 100644 --- a/packages/renderer/src/example-videos.ts +++ b/packages/renderer/src/example-videos.ts @@ -48,4 +48,5 @@ export const exampleVideos = { matroskaH265Aac: path.join(examplePackage, 'public', 'matroska-h265-aac.mkv'), opusWebm: path.join(examplePackage, 'public', 'opus.webm'), avi: path.join(examplePackage, 'public', 'example.avi'), + opus51Webm: path.join(examplePackage, 'public', 'vp8-opus-5-1-channels.webm'), }; diff --git a/packages/studio-shared/src/package-info.ts b/packages/studio-shared/src/package-info.ts index a91731bf4a7..e0981f5a998 100644 --- a/packages/studio-shared/src/package-info.ts +++ b/packages/studio-shared/src/package-info.ts @@ -61,6 +61,7 @@ export const packages = [ 'media-parser', 'zod-types', 'webcodecs', + 'convert', ] as const; export type Pkgs = (typeof packages)[number]; @@ -130,7 +131,8 @@ export const descriptions: {[key in Pkgs]: string | null} = { 'docusaurus-plugin': null, 'animated-emoji': 'Google Fonts Animated Emojis as Remotion components', serverless: 'A runtime for distributed rendering', - webcodecs: 'Private experimental package', + webcodecs: 'Media conversion in the browser', + convert: 'Video conversion tool - convert.remotion.dev', }; export const apiDocs: {[key in Pkgs]: string | null} = { @@ -198,4 +200,5 @@ export const apiDocs: {[key in Pkgs]: string | null} = { transitions: 'https://www.remotion.dev/transitions', 'animated-emoji': 'https://www.remotion.dev/docs/animated-emoji', webcodecs: null, + convert: 'https://convert.remotion.dev', }; diff --git a/packages/webcodecs/README.md b/packages/webcodecs/README.md index 527f16909cf..db4835738fc 100644 --- a/packages/webcodecs/README.md +++ b/packages/webcodecs/README.md @@ -1,6 +1,6 @@ # @remotion/webcodecs -Private experimental package +Media conversion in the browser [![NPM Downloads](https://img.shields.io/npm/dm/@remotion/webcodecs.svg?style=flat&color=black&label=Downloads)](https://npmcharts.com/compare/@remotion/webcodecs?minimal=true) diff --git a/packages/webcodecs/bundle.ts b/packages/webcodecs/bundle.ts new file mode 100644 index 00000000000..e4ac0181d14 --- /dev/null +++ b/packages/webcodecs/bundle.ts @@ -0,0 +1,18 @@ +import {build} from 'bun'; + +if (process.env.NODE_ENV !== 'production') { + throw new Error('This script must be run using NODE_ENV=production'); +} + +const output = await build({ + entrypoints: ['src/index.ts'], + naming: '[name].mjs', + external: ['@remotion/media-parser'], +}); + +const [file] = output.outputs; +const text = await file.text(); + +await Bun.write('dist/esm/index.mjs', text); + +export {}; diff --git a/packages/webcodecs/package.json b/packages/webcodecs/package.json index 158b20b8892..c62736e7dfe 100644 --- a/packages/webcodecs/package.json +++ b/packages/webcodecs/package.json @@ -2,6 +2,8 @@ "name": "@remotion/webcodecs", "version": "4.0.209", "main": "dist/index.js", + "types": "dist/index.d.ts", + "module": "dist/esm/index.mjs", "sideEffects": false, "repository": { "url": "https://github.com/remotion-dev/remotion/tree/main/packages/webcodecs" @@ -12,7 +14,7 @@ "scripts": { "formatting": "prettier src --check", "lint": "eslint src --ext ts,tsx", - "build": "tsc -d", + "build": "tsc -d && bun --env-file=../.env.bundle bundle.ts", "watch": "tsc -w" }, "files": [ @@ -20,13 +22,16 @@ ], "author": "Jonny Burger ", "license": "SEE LICENSE IN LICENSE.md", - "dependencies": {}, + "dependencies": { + "@remotion/media-parser": "workspace:*" + }, "peerDependencies": {}, "devDependencies": { - "@remotion/media-parser": "workspace:*", "@types/dom-webcodecs": "0.1.11" }, "keywords": [], - "private": true, - "description": "Private experimental package" + "publishConfig": { + "access": "public" + }, + "description": "Media conversion in the browser" } diff --git a/packages/webcodecs/src/audio-decoder-config.ts b/packages/webcodecs/src/audio-decoder-config.ts new file mode 100644 index 00000000000..e5731a8cce1 --- /dev/null +++ b/packages/webcodecs/src/audio-decoder-config.ts @@ -0,0 +1,13 @@ +export const getAudioDecoderConfig = async ( + config: AudioDecoderConfig, +): Promise => { + if (typeof AudioDecoder === 'undefined') { + return null; + } + + if ((await AudioDecoder.isConfigSupported(config)).supported) { + return config; + } + + return null; +}; diff --git a/packages/webcodecs/src/audio-decoder.ts b/packages/webcodecs/src/audio-decoder.ts index d4ce9981cca..d123d482422 100644 --- a/packages/webcodecs/src/audio-decoder.ts +++ b/packages/webcodecs/src/audio-decoder.ts @@ -1,4 +1,4 @@ -import type {AudioSample, AudioTrack} from '@remotion/media-parser'; +import type {AudioSample} from '@remotion/media-parser'; export type WebCodecsAudioDecoder = { processSample: (audioSample: AudioSample) => Promise; @@ -8,23 +8,19 @@ export type WebCodecsAudioDecoder = { flush: () => Promise; }; -export const createAudioDecoder = async ({ - track, +export const createAudioDecoder = ({ onFrame, onError, + signal, + config, }: { - track: AudioTrack; onFrame: (frame: AudioData) => Promise; onError: (error: DOMException) => void; -}): Promise => { - if (typeof AudioDecoder === 'undefined') { - return null; - } - - const {supported, config} = await AudioDecoder.isConfigSupported(track); - - if (!supported) { - return null; + signal: AbortSignal; + config: AudioDecoderConfig; +}): WebCodecsAudioDecoder => { + if (signal.aborted) { + throw new Error('Not creating audio decoder, already aborted'); } let outputQueue = Promise.resolve(); @@ -47,6 +43,23 @@ export const createAudioDecoder = async ({ }, }); + const close = () => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + signal.removeEventListener('abort', onAbort); + + if (audioDecoder.state === 'closed') { + return; + } + + audioDecoder.close(); + }; + + const onAbort = () => { + close(); + }; + + signal.addEventListener('abort', onAbort); + const getQueueSize = () => { return audioDecoder.decodeQueueSize + outputQueueSize; }; @@ -96,9 +109,7 @@ export const createAudioDecoder = async ({ await waitForFinish(); await outputQueue; }, - close: () => { - audioDecoder.close(); - }, + close, getQueueSize, flush: async () => { await audioDecoder.flush(); diff --git a/packages/webcodecs/src/audio-encoder-config.ts b/packages/webcodecs/src/audio-encoder-config.ts new file mode 100644 index 00000000000..1cbb916a889 --- /dev/null +++ b/packages/webcodecs/src/audio-encoder-config.ts @@ -0,0 +1,13 @@ +export const getAudioEncoderConfig = async ( + config: AudioEncoderConfig, +): Promise => { + if (typeof AudioEncoder === 'undefined') { + return null; + } + + if ((await AudioEncoder.isConfigSupported(config)).supported) { + return config; + } + + return null; +}; diff --git a/packages/webcodecs/src/audio-encoder.ts b/packages/webcodecs/src/audio-encoder.ts index 682e64b0be3..23887b80489 100644 --- a/packages/webcodecs/src/audio-encoder.ts +++ b/packages/webcodecs/src/audio-encoder.ts @@ -1,3 +1,5 @@ +import type {ConvertMediaAudioCodec} from './codec-id'; + export type WebCodecsAudioEncoder = { encodeFrame: (audioData: AudioData) => Promise; waitForFinish: () => Promise; @@ -6,19 +8,21 @@ export type WebCodecsAudioEncoder = { flush: () => Promise; }; -export const createAudioEncoder = async ({ +export const createAudioEncoder = ({ onChunk, - sampleRate, - numberOfChannels, onError, + codec, + signal, + config: audioEncoderConfig, }: { onChunk: (chunk: EncodedAudioChunk) => Promise; - sampleRate: number; - numberOfChannels: number; onError: (error: DOMException) => void; -}): Promise => { - if (typeof AudioEncoder === 'undefined') { - return null; + codec: ConvertMediaAudioCodec; + signal: AbortSignal; + config: AudioEncoderConfig; +}): WebCodecsAudioEncoder => { + if (signal.aborted) { + throw new Error('Not creating audio encoder, already aborted'); } let prom = Promise.resolve(); @@ -41,17 +45,24 @@ export const createAudioEncoder = async ({ }, }); - const audioEncoderConfig: AudioEncoderConfig = { - codec: 'opus', - numberOfChannels, - sampleRate, - bitrate: 128000, + const close = () => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + signal.removeEventListener('abort', onAbort); + if (encoder.state === 'closed') { + return; + } + + encoder.close(); + }; + + const onAbort = () => { + close(); }; - const config = await AudioEncoder.isConfigSupported(audioEncoderConfig); + signal.addEventListener('abort', onAbort); - if (!config.supported) { - return null; + if (codec !== 'opus') { + throw new Error('Only `codec: "opus"` is supported currently'); } const getQueueSize = () => { @@ -86,6 +97,11 @@ export const createAudioEncoder = async ({ await waitForDequeue(); } + // @ts-expect-error - can have changed in the meanwhile + if (encoder.state === 'closed') { + return; + } + encoder.encode(audioData); }; @@ -101,9 +117,7 @@ export const createAudioEncoder = async ({ await waitForFinish(); await prom; }, - close: () => { - encoder.close(); - }, + close, getQueueSize, flush: async () => { await encoder.flush(); diff --git a/packages/webcodecs/src/codec-id.ts b/packages/webcodecs/src/codec-id.ts new file mode 100644 index 00000000000..ee61efe095d --- /dev/null +++ b/packages/webcodecs/src/codec-id.ts @@ -0,0 +1,3 @@ +export type ConvertMediaVideoCodec = 'vp8'; + +export type ConvertMediaAudioCodec = 'opus'; diff --git a/packages/webcodecs/src/convert-media.ts b/packages/webcodecs/src/convert-media.ts new file mode 100644 index 00000000000..94e608b3223 --- /dev/null +++ b/packages/webcodecs/src/convert-media.ts @@ -0,0 +1,148 @@ +import type {OnAudioTrack, VideoTrack} from '@remotion/media-parser'; +import { + MediaParserInternals, + parseMedia, + type OnVideoTrack, +} from '@remotion/media-parser'; +import {bufferWriter} from '@remotion/media-parser/buffer'; +import {canUseWebFsWriter, webFsWriter} from '@remotion/media-parser/web-fs'; +import type {ConvertMediaAudioCodec, ConvertMediaVideoCodec} from './codec-id'; +import Error from './error-cause'; +import {makeAudioTrackHandler} from './on-audio-track'; +import {makeVideoTrackHandler} from './on-video-track'; +import { + defaultResolveAudioAction, + type ResolveAudioActionFn, +} from './resolve-audio-action'; +import { + defaultResolveVideoAction, + type ResolveVideoActionFn, +} from './resolve-video-action'; +import {withResolvers} from './with-resolvers'; + +export type ConvertMediaState = { + decodedVideoFrames: number; + decodedAudioFrames: number; + encodedVideoFrames: number; + encodedAudioFrames: number; +}; + +export type ConvertMediaTo = 'webm'; + +export type ConvertMediaResult = { + save: () => Promise; + remove: () => Promise; +}; + +export const convertMedia = async ({ + src, + onVideoFrame, + onMediaStateUpdate, + audioCodec, + to, + videoCodec, + signal: userPassedAbortSignal, + onAudioTrack: userAudioResolver, + onVideoTrack: userVideoResolver, +}: { + src: string | File; + to: ConvertMediaTo; + onVideoFrame?: (inputFrame: VideoFrame, track: VideoTrack) => Promise; + onMediaStateUpdate?: (state: ConvertMediaState) => void; + videoCodec: ConvertMediaVideoCodec; + audioCodec: ConvertMediaAudioCodec; + signal?: AbortSignal; + onAudioTrack?: ResolveAudioActionFn; + onVideoTrack?: ResolveVideoActionFn; +}): Promise => { + if (to !== 'webm') { + return Promise.reject( + new TypeError('Only `to: "webm"` is supported currently'), + ); + } + + if (audioCodec !== 'opus') { + return Promise.reject( + new TypeError('Only `audioCodec: "opus"` is supported currently'), + ); + } + + if (videoCodec !== 'vp8') { + return Promise.reject( + new TypeError('Only `videoCodec: "vp8"` is supported currently'), + ); + } + + const {promise, resolve, reject} = withResolvers(); + const controller = new AbortController(); + + const abortConversion = (errCause: Error) => { + reject(errCause); + + if (!controller.signal.aborted) { + controller.abort(); + } + }; + + const onUserAbort = () => { + abortConversion(new Error('Conversion aborted by user')); + }; + + userPassedAbortSignal?.addEventListener('abort', onUserAbort); + + const convertMediaState: ConvertMediaState = { + decodedAudioFrames: 0, + decodedVideoFrames: 0, + encodedVideoFrames: 0, + encodedAudioFrames: 0, + }; + + const canUseWebFs = await canUseWebFsWriter(); + + const state = await MediaParserInternals.createMedia( + canUseWebFs ? webFsWriter : bufferWriter, + ); + + const onVideoTrack: OnVideoTrack = makeVideoTrackHandler({ + state, + onVideoFrame: onVideoFrame ?? null, + onMediaStateUpdate: onMediaStateUpdate ?? null, + abortConversion, + convertMediaState, + controller, + videoCodec, + onVideoTrack: userVideoResolver ?? defaultResolveVideoAction, + }); + + const onAudioTrack: OnAudioTrack = makeAudioTrackHandler({ + abortConversion, + audioCodec, + controller, + convertMediaState, + onMediaStateUpdate: onMediaStateUpdate ?? null, + state, + onAudioTrack: userAudioResolver ?? defaultResolveAudioAction, + bitrate: 128000, + }); + + parseMedia({ + src, + onVideoTrack, + onAudioTrack, + signal: controller.signal, + }) + .then(() => { + return state.waitForFinish(); + }) + .then(() => { + resolve({save: state.save, remove: state.remove}); + }) + .catch((err) => { + reject(err); + }) + .finally(() => { + userPassedAbortSignal?.removeEventListener('abort', onUserAbort); + }); + + return promise; +}; diff --git a/packages/webcodecs/src/error-cause.ts b/packages/webcodecs/src/error-cause.ts new file mode 100644 index 00000000000..b233189161c --- /dev/null +++ b/packages/webcodecs/src/error-cause.ts @@ -0,0 +1,9 @@ +declare const BaseError: ErrorConstructor; + +declare class Error extends BaseError { + constructor(reason?: string, options?: {cause?: unknown}); + + cause: unknown; +} + +export default Error; diff --git a/packages/webcodecs/src/index.ts b/packages/webcodecs/src/index.ts index c233d7f0a08..bc310787b3e 100644 --- a/packages/webcodecs/src/index.ts +++ b/packages/webcodecs/src/index.ts @@ -1,4 +1,5 @@ export {createAudioDecoder} from './audio-decoder'; export {createAudioEncoder} from './audio-encoder'; +export {ConvertMediaState, ConvertMediaTo, convertMedia} from './convert-media'; export {createVideoDecoder} from './video-decoder'; export {createVideoEncoder} from './video-encoder'; diff --git a/packages/webcodecs/src/on-audio-track.ts b/packages/webcodecs/src/on-audio-track.ts new file mode 100644 index 00000000000..5154f3ed294 --- /dev/null +++ b/packages/webcodecs/src/on-audio-track.ts @@ -0,0 +1,155 @@ +import type {MediaFn, OnAudioTrack} from '@remotion/media-parser'; +import {createAudioDecoder} from './audio-decoder'; +import {getAudioDecoderConfig} from './audio-decoder-config'; +import {createAudioEncoder} from './audio-encoder'; +import {getAudioEncoderConfig} from './audio-encoder-config'; +import type {ConvertMediaAudioCodec} from './codec-id'; +import type {ConvertMediaState} from './convert-media'; +import Error from './error-cause'; +import type {ResolveAudioActionFn} from './resolve-audio-action'; +import {resolveAudioAction} from './resolve-audio-action'; + +export const makeAudioTrackHandler = + ({ + state, + audioCodec, + convertMediaState, + controller, + abortConversion, + onMediaStateUpdate, + onAudioTrack, + bitrate, + }: { + state: MediaFn; + audioCodec: ConvertMediaAudioCodec; + convertMediaState: ConvertMediaState; + controller: AbortController; + abortConversion: (errCause: Error) => void; + onMediaStateUpdate: null | ((state: ConvertMediaState) => void); + onAudioTrack: ResolveAudioActionFn; + bitrate: number; + }): OnAudioTrack => + async (track) => { + const audioEncoderConfig = await getAudioEncoderConfig({ + codec: audioCodec, + numberOfChannels: track.numberOfChannels, + sampleRate: track.sampleRate, + bitrate, + }); + const audioDecoderConfig = await getAudioDecoderConfig({ + codec: track.codec, + numberOfChannels: track.numberOfChannels, + sampleRate: track.sampleRate, + description: track.description, + }); + + const audioOperation = await resolveAudioAction({ + audioDecoderConfig, + audioEncoderConfig, + audioCodec, + track, + resolverFunction: onAudioTrack, + }); + + if (audioOperation === 'drop') { + return null; + } + + if (audioOperation === 'copy') { + const addedTrack = await state.addTrack({ + type: 'audio', + codec: audioCodec, + numberOfChannels: track.numberOfChannels, + sampleRate: track.sampleRate, + codecPrivate: track.codecPrivate, + }); + + return async (audioSample) => { + await state.addSample( + new EncodedAudioChunk(audioSample), + addedTrack.trackNumber, + ); + convertMediaState.encodedAudioFrames++; + onMediaStateUpdate?.({...convertMediaState}); + }; + } + + if (!audioEncoderConfig) { + abortConversion( + new Error( + `Could not configure audio encoder of track ${track.trackId}`, + ), + ); + return null; + } + + if (!audioDecoderConfig) { + abortConversion( + new Error( + `Could not configure audio decoder of track ${track.trackId}`, + ), + ); + return null; + } + + const {trackNumber} = await state.addTrack({ + type: 'audio', + codec: audioCodec, + numberOfChannels: track.numberOfChannels, + sampleRate: track.sampleRate, + codecPrivate: null, + }); + + const audioEncoder = createAudioEncoder({ + onChunk: async (chunk) => { + await state.addSample(chunk, trackNumber); + convertMediaState.encodedAudioFrames++; + onMediaStateUpdate?.({...convertMediaState}); + }, + onError: (err) => { + abortConversion( + new Error( + `Audio encoder of ${track.trackId} failed (see .cause of this error)`, + { + cause: err, + }, + ), + ); + }, + codec: audioCodec, + signal: controller.signal, + config: audioEncoderConfig, + }); + + const audioDecoder = createAudioDecoder({ + onFrame: async (frame) => { + await audioEncoder.encodeFrame(frame); + convertMediaState.decodedAudioFrames++; + onMediaStateUpdate?.(convertMediaState); + frame.close(); + }, + onError(error) { + abortConversion( + new Error( + `Audio decoder of track ${track.trackId} failed (see .cause of this error)`, + { + cause: error, + }, + ), + ); + }, + signal: controller.signal, + config: audioDecoderConfig, + }); + + state.addWaitForFinishPromise(async () => { + await audioDecoder.waitForFinish(); + await audioEncoder.waitForFinish(); + audioDecoder.close(); + audioEncoder.close(); + }); + + return async (audioSample) => { + await audioDecoder.processSample(audioSample); + }; + }; diff --git a/packages/webcodecs/src/on-video-track.ts b/packages/webcodecs/src/on-video-track.ts new file mode 100644 index 00000000000..375db6c0d6c --- /dev/null +++ b/packages/webcodecs/src/on-video-track.ts @@ -0,0 +1,149 @@ +import type {MediaFn, OnVideoTrack, VideoTrack} from '@remotion/media-parser'; +import type {ConvertMediaVideoCodec} from './codec-id'; +import type {ConvertMediaState} from './convert-media'; +import Error from './error-cause'; +import type {ResolveVideoActionFn} from './resolve-video-action'; +import {resolveVideoAction} from './resolve-video-action'; +import {createVideoDecoder} from './video-decoder'; +import {getVideoDecoderConfigWithHardwareAcceleration} from './video-decoder-config'; +import {createVideoEncoder} from './video-encoder'; +import {getVideoEncoderConfig} from './video-encoder-config'; + +export const makeVideoTrackHandler = + ({ + state, + onVideoFrame, + onMediaStateUpdate, + abortConversion, + convertMediaState, + controller, + videoCodec, + onVideoTrack, + }: { + state: MediaFn; + onVideoFrame: + | null + | ((frame: VideoFrame, track: VideoTrack) => Promise); + onMediaStateUpdate: null | ((state: ConvertMediaState) => void); + abortConversion: (errCause: Error) => void; + convertMediaState: ConvertMediaState; + controller: AbortController; + videoCodec: ConvertMediaVideoCodec; + onVideoTrack: ResolveVideoActionFn; + }): OnVideoTrack => + async (track) => { + const videoEncoderConfig = await getVideoEncoderConfig({ + codec: videoCodec, + height: track.displayAspectHeight, + width: track.displayAspectWidth, + }); + const videoDecoderConfig = + await getVideoDecoderConfigWithHardwareAcceleration(track); + const videoOperation = await resolveVideoAction({ + videoDecoderConfig, + videoEncoderConfig, + track, + videoCodec, + resolverFunction: onVideoTrack, + }); + + if (videoOperation === 'drop') { + return null; + } + + if (videoOperation === 'copy') { + const videoTrack = await state.addTrack({ + type: 'video', + color: track.color, + width: track.codedWidth, + height: track.codedHeight, + codec: track.codecWithoutConfig, + codecPrivate: track.codecPrivate, + }); + return (sample) => { + state.addSample(new EncodedVideoChunk(sample), videoTrack.trackNumber); + convertMediaState.decodedVideoFrames++; + onMediaStateUpdate?.({...convertMediaState}); + }; + } + + if (videoEncoderConfig === null) { + abortConversion( + new Error( + `Could not configure video encoder of track ${track.trackId}`, + ), + ); + return null; + } + + if (videoDecoderConfig === null) { + abortConversion( + new Error( + `Could not configure video decoder of track ${track.trackId}`, + ), + ); + return null; + } + + const {trackNumber} = await state.addTrack({ + type: 'video', + color: track.color, + width: track.codedWidth, + height: track.codedHeight, + codec: videoCodec, + codecPrivate: null, + }); + + const videoEncoder = createVideoEncoder({ + onChunk: async (chunk) => { + await state.addSample(chunk, trackNumber); + convertMediaState.encodedVideoFrames++; + onMediaStateUpdate?.({...convertMediaState}); + }, + onError: (err) => { + abortConversion( + new Error( + `Video encoder of track ${track.trackId} failed (see .cause of this error)`, + { + cause: err, + }, + ), + ); + }, + signal: controller.signal, + config: videoEncoderConfig, + }); + + const videoDecoder = createVideoDecoder({ + config: videoDecoderConfig, + onFrame: async (frame) => { + await onVideoFrame?.(frame, track); + await videoEncoder.encodeFrame(frame); + convertMediaState.decodedVideoFrames++; + onMediaStateUpdate?.({...convertMediaState}); + frame.close(); + }, + onError: (err) => { + abortConversion( + new Error( + `Video decoder of track ${track.trackId} failed (see .cause of this error)`, + { + cause: err, + }, + ), + ); + }, + signal: controller.signal, + }); + + state.addWaitForFinishPromise(async () => { + await videoDecoder.waitForFinish(); + await videoEncoder.waitForFinish(); + videoDecoder.close(); + videoEncoder.close(); + }); + + return async (chunk) => { + await videoDecoder.processSample(chunk); + }; + }; diff --git a/packages/webcodecs/src/resolve-audio-action.ts b/packages/webcodecs/src/resolve-audio-action.ts new file mode 100644 index 00000000000..4d5d18a4465 --- /dev/null +++ b/packages/webcodecs/src/resolve-audio-action.ts @@ -0,0 +1,60 @@ +import type {AudioTrack, MediaParserAudioCodec} from '@remotion/media-parser'; +import type {ConvertMediaAudioCodec} from './codec-id'; + +export type AudioOperation = 'reencode' | 'copy' | 'drop'; + +const canCopyAudioTrack = ( + inputCodec: MediaParserAudioCodec, + outputCodec: ConvertMediaAudioCodec, +) => { + if (outputCodec === 'opus') { + return inputCodec === 'opus'; + } + + throw new Error(`Unhandled codec: ${outputCodec satisfies never}`); +}; + +export type ResolveAudioActionFn = (options: { + canReencode: boolean; + canCopy: boolean; +}) => AudioOperation | Promise; + +export const defaultResolveAudioAction: ResolveAudioActionFn = ({ + canReencode, + canCopy, +}) => { + if (canCopy) { + return 'copy'; + } + + if (canReencode) { + return 'reencode'; + } + + // TODO: Make a fail option? + return 'drop'; +}; + +export const resolveAudioAction = async ({ + audioDecoderConfig, + audioEncoderConfig, + track, + audioCodec, + resolverFunction, +}: { + audioDecoderConfig: AudioDecoderConfig | null; + audioEncoderConfig: AudioEncoderConfig | null; + track: AudioTrack; + audioCodec: ConvertMediaAudioCodec; + resolverFunction: ResolveAudioActionFn; +}): Promise => { + const canReencode = Boolean(audioDecoderConfig && audioEncoderConfig); + const canCopy = canCopyAudioTrack(track.codecWithoutConfig, audioCodec); + + const resolved = await resolverFunction({ + canReencode, + canCopy, + }); + + return resolved; +}; diff --git a/packages/webcodecs/src/resolve-video-action.ts b/packages/webcodecs/src/resolve-video-action.ts new file mode 100644 index 00000000000..f10ee58f18a --- /dev/null +++ b/packages/webcodecs/src/resolve-video-action.ts @@ -0,0 +1,60 @@ +import type {MediaParserVideoCodec, VideoTrack} from '@remotion/media-parser'; +import type {ConvertMediaVideoCodec} from './codec-id'; + +export type VideoOperation = 'reencode' | 'copy' | 'drop'; + +const canCopyVideoTrack = ( + inputCodec: MediaParserVideoCodec, + outputCodec: ConvertMediaVideoCodec, +) => { + if (outputCodec === 'vp8') { + return inputCodec === 'vp8'; + } + + throw new Error(`Unhandled codec: ${outputCodec satisfies never}`); +}; + +export type ResolveVideoActionFn = (options: { + canReencode: boolean; + canCopy: boolean; +}) => VideoOperation | Promise; + +export const defaultResolveVideoAction: ResolveVideoActionFn = ({ + canReencode, + canCopy, +}) => { + if (canCopy) { + return 'copy'; + } + + if (canReencode) { + return 'reencode'; + } + + // TODO: Make a fail option? + return 'drop'; +}; + +export const resolveVideoAction = async ({ + videoDecoderConfig, + videoEncoderConfig, + track, + videoCodec, + resolverFunction, +}: { + videoDecoderConfig: VideoDecoderConfig | null; + videoEncoderConfig: VideoEncoderConfig | null; + videoCodec: ConvertMediaVideoCodec; + track: VideoTrack; + resolverFunction: ResolveVideoActionFn; +}): Promise => { + const canReencode = Boolean(videoDecoderConfig && videoEncoderConfig); + const canCopy = canCopyVideoTrack(track.codecWithoutConfig, videoCodec); + + const resolved = await resolverFunction({ + canReencode, + canCopy, + }); + + return resolved; +}; diff --git a/packages/webcodecs/src/get-config.ts b/packages/webcodecs/src/video-decoder-config.ts similarity index 50% rename from packages/webcodecs/src/get-config.ts rename to packages/webcodecs/src/video-decoder-config.ts index 8ed21577e1f..fded739f53e 100644 --- a/packages/webcodecs/src/get-config.ts +++ b/packages/webcodecs/src/video-decoder-config.ts @@ -1,6 +1,10 @@ export const getVideoDecoderConfigWithHardwareAcceleration = async ( config: VideoDecoderConfig, ): Promise => { + if (typeof VideoDecoder === 'undefined') { + return null; + } + const hardware: VideoDecoderConfig = { ...config, hardwareAcceleration: 'prefer-hardware', @@ -21,27 +25,3 @@ export const getVideoDecoderConfigWithHardwareAcceleration = async ( return null; }; - -export const getVideoEncoderConfigWithHardwareAcceleration = async ( - config: VideoEncoderConfig, -): Promise => { - const hardware: VideoEncoderConfig = { - ...config, - hardwareAcceleration: 'prefer-hardware', - }; - - if ((await VideoEncoder.isConfigSupported(hardware)).supported) { - return hardware; - } - - const software: VideoEncoderConfig = { - ...config, - hardwareAcceleration: 'prefer-software', - }; - - if ((await VideoEncoder.isConfigSupported(software)).supported) { - return software; - } - - return null; -}; diff --git a/packages/webcodecs/src/video-decoder.ts b/packages/webcodecs/src/video-decoder.ts index 2f8e61f1e9f..72d19070dcd 100644 --- a/packages/webcodecs/src/video-decoder.ts +++ b/packages/webcodecs/src/video-decoder.ts @@ -1,5 +1,4 @@ -import type {VideoSample, VideoTrack} from '@remotion/media-parser'; -import {getVideoDecoderConfigWithHardwareAcceleration} from './get-config'; +import type {VideoSample} from '@remotion/media-parser'; export type WebCodecsVideoDecoder = { processSample: (videoSample: VideoSample) => Promise; @@ -9,25 +8,17 @@ export type WebCodecsVideoDecoder = { flush: () => Promise; }; -export const createVideoDecoder = async ({ - track, +export const createVideoDecoder = ({ onFrame, onError, + signal, + config, }: { - track: VideoTrack; onFrame: (frame: VideoFrame) => Promise; onError: (error: DOMException) => void; -}): Promise => { - if (typeof VideoDecoder === 'undefined') { - return null; - } - - const config = await getVideoDecoderConfigWithHardwareAcceleration(track); - - if (!config) { - return null; - } - + signal: AbortSignal; + config: VideoDecoderConfig; +}): WebCodecsVideoDecoder => { let outputQueue = Promise.resolve(); let outputQueueSize = 0; let dequeueResolver = () => {}; @@ -48,6 +39,22 @@ export const createVideoDecoder = async ({ }, }); + const close = () => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + signal.removeEventListener('abort', onAbort); + if (videoDecoder.state === 'closed') { + return; + } + + videoDecoder.close(); + }; + + const onAbort = () => { + close(); + }; + + signal.addEventListener('abort', onAbort); + const getQueueSize = () => { return videoDecoder.decodeQueueSize + outputQueueSize; }; @@ -78,6 +85,11 @@ export const createVideoDecoder = async ({ await waitForDequeue(); } + // @ts-expect-error - can have changed in the meanwhile + if (videoDecoder.state === 'closed') { + return; + } + if (sample.type === 'key') { await videoDecoder.flush(); } @@ -98,9 +110,7 @@ export const createVideoDecoder = async ({ await outputQueue; await inputQueue; }, - close: () => { - videoDecoder.close(); - }, + close, getQueueSize, flush: async () => { await videoDecoder.flush(); diff --git a/packages/webcodecs/src/video-encoder-config.ts b/packages/webcodecs/src/video-encoder-config.ts new file mode 100644 index 00000000000..534c0b635e1 --- /dev/null +++ b/packages/webcodecs/src/video-encoder-config.ts @@ -0,0 +1,27 @@ +export const getVideoEncoderConfig = async ( + config: VideoEncoderConfig, +): Promise => { + if (typeof VideoEncoder === 'undefined') { + return null; + } + + const hardware: VideoEncoderConfig = { + ...config, + hardwareAcceleration: 'prefer-hardware', + }; + + if ((await VideoEncoder.isConfigSupported(hardware)).supported) { + return hardware; + } + + const software: VideoEncoderConfig = { + ...config, + hardwareAcceleration: 'prefer-software', + }; + + if ((await VideoEncoder.isConfigSupported(software)).supported) { + return software; + } + + return null; +}; diff --git a/packages/webcodecs/src/video-encoder.ts b/packages/webcodecs/src/video-encoder.ts index ceb767f5ac5..b99c5ed3e42 100644 --- a/packages/webcodecs/src/video-encoder.ts +++ b/packages/webcodecs/src/video-encoder.ts @@ -1,5 +1,3 @@ -import {getVideoEncoderConfigWithHardwareAcceleration} from './get-config'; - export type WebCodecsVideoEncoder = { encodeFrame: (videoFrame: VideoFrame) => Promise; waitForFinish: () => Promise; @@ -8,19 +6,19 @@ export type WebCodecsVideoEncoder = { flush: () => Promise; }; -export const createVideoEncoder = async ({ - width, - height, +export const createVideoEncoder = ({ onChunk, onError, + signal, + config, }: { - width: number; - height: number; onChunk: (chunk: EncodedVideoChunk) => Promise; onError: (error: DOMException) => void; -}): Promise => { - if (typeof VideoEncoder === 'undefined') { - return Promise.resolve(null); + signal: AbortSignal; + config: VideoEncoderConfig; +}): WebCodecsVideoEncoder => { + if (signal.aborted) { + throw new Error('Not creating video encoder, already aborted'); } let outputQueue = Promise.resolve(); @@ -43,15 +41,21 @@ export const createVideoEncoder = async ({ }, }); - const config = await getVideoEncoderConfigWithHardwareAcceleration({ - codec: 'vp8', - height, - width, - }); + const close = () => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + signal.removeEventListener('abort', onAbort); + if (encoder.state === 'closed') { + return; + } - if (!config) { - return null; - } + encoder.close(); + }; + + const onAbort = () => { + close(); + }; + + signal.addEventListener('abort', onAbort); const getQueueSize = () => { return encoder.encodeQueueSize + outputQueueSize; @@ -85,6 +89,11 @@ export const createVideoEncoder = async ({ await waitForDequeue(); } + // @ts-expect-error - can have changed in the meanwhile + if (encoder.state === 'closed') { + return; + } + encoder.encode(frame, { keyFrame: framesProcessed % 40 === 0, }); @@ -103,9 +112,7 @@ export const createVideoEncoder = async ({ await outputQueue; await waitForFinish(); }, - close: () => { - encoder.close(); - }, + close, getQueueSize, flush: async () => { await encoder.flush(); diff --git a/packages/webcodecs/src/with-resolvers.ts b/packages/webcodecs/src/with-resolvers.ts new file mode 100644 index 00000000000..729ec7784ab --- /dev/null +++ b/packages/webcodecs/src/with-resolvers.ts @@ -0,0 +1,16 @@ +interface WebCodecsPromiseWithResolvers { + promise: Promise; + resolve: (value: T | PromiseLike) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + reject: (reason?: any) => void; +} + +export const withResolvers = function () { + let resolve: WebCodecsPromiseWithResolvers['resolve']; + let reject: WebCodecsPromiseWithResolvers['reject']; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return {promise, resolve: resolve!, reject: reject!}; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b47c314bf60..9b9f916259e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -328,6 +328,85 @@ importers: packages/compositor-win32-x64-msvc: {} + packages/convert: + dependencies: + '@radix-ui/react-label': + specifier: ^2.1.0 + version: 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-scroll-area': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-select': + specifier: ^2.1.1 + version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-separator': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.1.0 + version: 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@remix-run/node': + specifier: ^2.11.2 + version: 2.11.2(typescript@5.3.3) + '@remix-run/react': + specifier: ^2.11.2 + version: 2.11.2(react-dom@18.3.1)(react@18.3.1)(typescript@5.3.3) + '@remix-run/serve': + specifier: ^2.11.2 + version: 2.11.2(typescript@5.3.3) + '@remotion/media-parser': + specifier: workspace:* + version: link:../media-parser + '@remotion/webcodecs': + specifier: workspace:* + version: link:../webcodecs + '@vercel/remix': + specifier: ^2.11.2 + version: 2.11.2(@remix-run/dev@2.11.2)(@remix-run/node@2.11.2)(@remix-run/server-runtime@2.11.2)(react-dom@18.3.1)(react@18.3.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + isbot: + specifier: ^4.1.0 + version: 4.4.0 + lucide-react: + specifier: ^0.439.0 + version: 0.439.0(react@18.3.1) + react: + specifier: 18.3.1 + version: 18.3.1 + react-dom: + specifier: 18.3.1 + version: 18.3.1(react@18.3.1) + tailwind-merge: + specifier: ^2.5.2 + version: 2.5.2 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.10) + devDependencies: + '@remix-run/dev': + specifier: ^2.11.2 + version: 2.11.2(@remix-run/react@2.11.2)(@remix-run/serve@2.11.2)(typescript@5.3.3)(vite@5.4.3) + autoprefixer: + specifier: ^10.4.19 + version: 10.4.19(postcss@8.4.39) + postcss: + specifier: ^8.4.38 + version: 8.4.39 + tailwindcss: + specifier: ^3.4.4 + version: 3.4.10 + vite: + specifier: ^5.1.0 + version: 5.4.3 + vite-tsconfig-paths: + specifier: ^4.2.1 + version: 4.3.2(typescript@5.3.3)(vite@5.4.3) + packages/core: devDependencies: '@happy-dom/global-registrator': @@ -1609,10 +1688,11 @@ importers: version: 18.3.1(react@18.3.1) packages/webcodecs: - devDependencies: + dependencies: '@remotion/media-parser': specifier: workspace:* version: link:../media-parser + devDependencies: '@types/dom-webcodecs': specifier: 0.1.11 version: 0.1.11 @@ -1801,7 +1881,6 @@ packages: /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - dev: false /@ampproject/remapping@2.1.2: resolution: {integrity: sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==} @@ -3114,7 +3193,6 @@ packages: dependencies: '@babel/highlight': 7.24.7 picocolors: 1.0.1 - dev: false /@babel/compat-data@7.15.0: resolution: {integrity: sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==} @@ -3126,14 +3204,9 @@ packages: engines: {node: '>=6.9.0'} dev: false - /@babel/compat-data@7.24.4: - resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} - engines: {node: '>=6.9.0'} - /@babel/compat-data@7.24.9: resolution: {integrity: sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==} engines: {node: '>=6.9.0'} - dev: false /@babel/core@7.15.5: resolution: {integrity: sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==} @@ -3186,14 +3259,14 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.4) + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.10 + '@babel/helper-compilation-targets': 7.24.8 + '@babel/helper-module-transforms': 7.24.9(@babel/core@7.24.4) '@babel/helpers': 7.24.4 - '@babel/parser': 7.24.4 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 + '@babel/parser': 7.24.8 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.8 '@babel/types': 7.24.0 convert-source-map: 2.0.0 debug: 4.3.6(supports-color@5.5.0) @@ -3229,7 +3302,6 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - dev: false /@babel/generator@7.24.4: resolution: {integrity: sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==} @@ -3239,6 +3311,7 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 + dev: false /@babel/helper-annotate-as-pure@7.15.4: resolution: {integrity: sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==} @@ -3265,7 +3338,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.9 - dev: false /@babel/helper-builder-binary-assignment-operator-visitor@7.15.4: resolution: {integrity: sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==} @@ -3324,16 +3396,6 @@ packages: semver: 6.3.1 dev: false - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.24.4 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.23.2 - lru-cache: 5.1.1 - semver: 6.3.1 - /@babel/helper-compilation-targets@7.24.8: resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==} engines: {node: '>=6.9.0'} @@ -3343,7 +3405,6 @@ packages: browserslist: 4.23.2 lru-cache: 5.1.1 semver: 6.3.1 - dev: false /@babel/helper-create-class-features-plugin@7.15.4(@babel/core@7.15.5): resolution: {integrity: sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==} @@ -3380,7 +3441,6 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-create-regexp-features-plugin@7.14.5(@babel/core@7.15.5): resolution: {integrity: sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==} @@ -3425,7 +3485,7 @@ packages: '@babel/helper-compilation-targets': 7.19.1(@babel/core@7.15.5) '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.19.0 - '@babel/traverse': 7.19.1(supports-color@5.5.0) + '@babel/traverse': 7.24.8 debug: 4.3.6(supports-color@5.5.0) lodash.debounce: 4.0.8 resolve: 1.22.2 @@ -3457,13 +3517,13 @@ packages: /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} + dev: false /@babel/helper-environment-visitor@7.24.7: resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.9 - dev: false /@babel/helper-explode-assignable-expression@7.15.4: resolution: {integrity: sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==} @@ -3477,7 +3537,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-get-function-arity': 7.15.4 - '@babel/template': 7.18.10 + '@babel/template': 7.24.7 '@babel/types': 7.24.0 dev: false @@ -3493,8 +3553,9 @@ packages: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.24.0 + '@babel/template': 7.24.7 '@babel/types': 7.24.0 + dev: false /@babel/helper-function-name@7.24.7: resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} @@ -3502,7 +3563,6 @@ packages: dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.9 - dev: false /@babel/helper-get-function-arity@7.15.4: resolution: {integrity: sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==} @@ -3530,13 +3590,13 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 + dev: false /@babel/helper-hoist-variables@7.24.7: resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.9 - dev: false /@babel/helper-member-expression-to-functions@7.15.4: resolution: {integrity: sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==} @@ -3553,7 +3613,6 @@ packages: '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-module-imports@7.15.4: resolution: {integrity: sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==} @@ -3574,6 +3633,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 + dev: true /@babel/helper-module-imports@7.24.7: resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} @@ -3583,7 +3643,6 @@ packages: '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-module-transforms@7.15.7: resolution: {integrity: sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==} @@ -3617,19 +3676,6 @@ packages: - supports-color dev: false - /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.4): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.24.4 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - /@babel/helper-module-transforms@7.24.9(@babel/core@7.24.4): resolution: {integrity: sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==} engines: {node: '>=6.9.0'} @@ -3644,7 +3690,6 @@ packages: '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-optimise-call-expression@7.15.4: resolution: {integrity: sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==} @@ -3658,7 +3703,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.9 - dev: false /@babel/helper-plugin-utils@7.14.5: resolution: {integrity: sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==} @@ -3683,7 +3727,6 @@ packages: /@babel/helper-plugin-utils@7.24.8: resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-remap-async-to-generator@7.15.4: resolution: {integrity: sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==} @@ -3716,7 +3759,7 @@ packages: dependencies: '@babel/helper-member-expression-to-functions': 7.15.4 '@babel/helper-optimise-call-expression': 7.15.4 - '@babel/traverse': 7.19.1(supports-color@5.5.0) + '@babel/traverse': 7.24.8 '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color @@ -3734,7 +3777,6 @@ packages: '@babel/helper-optimise-call-expression': 7.24.7 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-simple-access@7.15.4: resolution: {integrity: sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==} @@ -3750,12 +3792,6 @@ packages: '@babel/types': 7.24.0 dev: false - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - /@babel/helper-simple-access@7.24.7: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} @@ -3764,7 +3800,6 @@ packages: '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-skip-transparent-expression-wrappers@7.15.4: resolution: {integrity: sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==} @@ -3781,7 +3816,6 @@ packages: '@babel/types': 7.24.9 transitivePeerDependencies: - supports-color - dev: false /@babel/helper-split-export-declaration@7.15.4: resolution: {integrity: sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==} @@ -3802,13 +3836,13 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 + dev: false /@babel/helper-split-export-declaration@7.24.7: resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.9 - dev: false /@babel/helper-string-parser@7.18.10: resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} @@ -3822,7 +3856,6 @@ packages: /@babel/helper-string-parser@7.24.8: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-identifier@7.15.7: resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} @@ -3841,7 +3874,6 @@ packages: /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-option@7.14.5: resolution: {integrity: sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==} @@ -3853,22 +3885,17 @@ packages: engines: {node: '>=6.9.0'} dev: false - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.24.8: resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-wrap-function@7.15.4: resolution: {integrity: sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-function-name': 7.19.0 - '@babel/template': 7.18.10 - '@babel/traverse': 7.19.1(supports-color@5.5.0) + '@babel/helper-function-name': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.8 '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color @@ -3913,7 +3940,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.24.0 - '@babel/traverse': 7.24.1 + '@babel/traverse': 7.24.8 '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color @@ -3939,7 +3966,7 @@ packages: resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 @@ -3952,7 +3979,6 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 - dev: false /@babel/parser@7.15.7: resolution: {integrity: sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==} @@ -3977,20 +4003,12 @@ packages: dependencies: '@babel/types': 7.24.0 - /@babel/parser@7.24.4: - resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.24.0 - /@babel/parser@7.24.8: resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==} engines: {node: '>=6.0.0'} hasBin: true dependencies: '@babel/types': 7.24.0 - dev: false /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.4): resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==} @@ -4298,6 +4316,15 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: false + /@babel/plugin-syntax-decorators@7.24.7(@babel/core@7.24.4): + resolution: {integrity: sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.4 + '@babel/helper-plugin-utils': 7.24.8 + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.15.5): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: @@ -4429,7 +4456,6 @@ packages: dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.24.8 - dev: false /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.15.5): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} @@ -4597,7 +4623,6 @@ packages: dependencies: '@babel/core': 7.24.4 '@babel/helper-plugin-utils': 7.24.8 - dev: false /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.4): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} @@ -5068,7 +5093,6 @@ packages: '@babel/helper-simple-access': 7.24.7 transitivePeerDependencies: - supports-color - dev: false /@babel/plugin-transform-modules-systemjs@7.15.4(@babel/core@7.15.5): resolution: {integrity: sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==} @@ -5687,7 +5711,6 @@ packages: '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.4) transitivePeerDependencies: - supports-color - dev: false /@babel/plugin-transform-unicode-escapes@7.14.5(@babel/core@7.15.5): resolution: {integrity: sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==} @@ -6013,7 +6036,6 @@ packages: '@babel/plugin-transform-typescript': 7.24.8(@babel/core@7.24.4) transitivePeerDependencies: - supports-color - dev: false /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} @@ -6052,7 +6074,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: false /@babel/template@7.15.4: resolution: {integrity: sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==} @@ -6087,14 +6108,13 @@ packages: '@babel/code-frame': 7.24.7 '@babel/parser': 7.24.8 '@babel/types': 7.24.9 - dev: false /@babel/traverse@7.15.4: resolution: {integrity: sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.0 + '@babel/generator': 7.24.10 '@babel/helper-function-name': 7.15.4 '@babel/helper-hoist-variables': 7.15.4 '@babel/helper-split-export-declaration': 7.15.4 @@ -6129,7 +6149,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.24.2 - '@babel/generator': 7.24.4 + '@babel/generator': 7.24.10 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 @@ -6140,6 +6160,7 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: false /@babel/traverse@7.24.8: resolution: {integrity: sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==} @@ -6157,7 +6178,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: false /@babel/types@7.15.6: resolution: {integrity: sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==} @@ -6191,7 +6211,6 @@ packages: '@babel/helper-string-parser': 7.24.8 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - dev: false /@colors/colors@1.5.0: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -6271,9 +6290,9 @@ packages: peerDependencies: postcss: ^8.4 dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.13) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.1) postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /@csstools/postcss-color-function@2.2.2(postcss@8.4.31): @@ -6354,9 +6373,9 @@ packages: peerDependencies: postcss: ^8.4 dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.13) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.1) postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /@csstools/postcss-logical-float-and-clear@1.0.1(postcss@8.4.31): @@ -6463,7 +6482,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /@csstools/postcss-stepped-value-functions@2.1.1(postcss@8.4.31): @@ -6510,13 +6529,13 @@ packages: postcss: 8.4.31 dev: false - /@csstools/selector-specificity@2.2.0(postcss-selector-parser@6.0.13): + /@csstools/selector-specificity@2.2.0(postcss-selector-parser@6.1.1): resolution: {integrity: sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==} engines: {node: ^14 || ^16 || >=18} peerDependencies: postcss-selector-parser: ^6.0.10 dependencies: - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /@discoveryjs/json-ext@0.5.7: @@ -6581,7 +6600,7 @@ packages: '@docusaurus/utils': 3.4.0(@docusaurus/types@3.4.0)(@swc/core@1.3.80) '@docusaurus/utils-common': 3.4.0(@docusaurus/types@3.4.0) '@docusaurus/utils-validation': 3.4.0(@docusaurus/types@3.4.0)(@swc/core@1.3.80) - autoprefixer: 10.4.14(postcss@8.4.33) + autoprefixer: 10.4.19(postcss@8.4.39) babel-loader: 9.1.3(@babel/core@7.24.4)(webpack@5.94.0) babel-plugin-dynamic-import-node: 2.3.3 boxen: 6.2.1 @@ -6595,7 +6614,7 @@ packages: core-js: 3.37.1 css-loader: 6.11.0(webpack@5.94.0) css-minimizer-webpack-plugin: 5.0.1(clean-css@5.3.3)(webpack@5.94.0) - cssnano: 6.1.2(postcss@8.4.33) + cssnano: 6.1.2(postcss@8.4.39) del: 6.1.1 detect-port: 1.6.1 escape-html: 1.0.3 @@ -6610,8 +6629,8 @@ packages: lodash: 4.17.21 mini-css-extract-plugin: 2.9.0(webpack@5.94.0) p-map: 4.0.0 - postcss: 8.4.33 - postcss-loader: 7.3.4(postcss@8.4.33)(typescript@5.3.3)(webpack@5.94.0) + postcss: 8.4.39 + postcss-loader: 7.3.4(postcss@8.4.39)(typescript@5.3.3)(webpack@5.94.0) prompts: 2.4.2 react: 18.3.1 react-dev-utils: 12.0.1(eslint@8.56.0)(typescript@5.3.3)(webpack@5.94.0) @@ -7109,7 +7128,7 @@ packages: infima: 0.2.0-alpha.43 lodash: 4.17.21 nprogress: 0.2.0 - postcss: 8.4.33 + postcss: 8.4.39 prism-react-renderer: 2.3.1(react@18.3.1) prismjs: 1.29.0 react: 18.3.1 @@ -7376,6 +7395,9 @@ packages: resolution: {integrity: sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==} dev: false + /@emotion/hash@0.9.2: + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + /@emotion/is-prop-valid@1.2.0: resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==} dependencies: @@ -7394,6 +7416,22 @@ packages: resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} dev: false + /@esbuild/aix-ppc64@0.21.5: + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + optional: true + + /@esbuild/android-arm64@0.17.6: + resolution: {integrity: sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -7410,6 +7448,14 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm64@0.21.5: + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + /@esbuild/android-arm@0.15.18: resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} engines: {node: '>=12'} @@ -7419,6 +7465,14 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.17.6: + resolution: {integrity: sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} @@ -7435,6 +7489,22 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm@0.21.5: + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-x64@0.17.6: + resolution: {integrity: sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} @@ -7451,6 +7521,22 @@ packages: requiresBuild: true optional: true + /@esbuild/android-x64@0.21.5: + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/darwin-arm64@0.17.6: + resolution: {integrity: sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} @@ -7467,6 +7553,22 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-arm64@0.21.5: + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/darwin-x64@0.17.6: + resolution: {integrity: sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} @@ -7483,6 +7585,22 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-x64@0.21.5: + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/freebsd-arm64@0.17.6: + resolution: {integrity: sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} @@ -7499,6 +7617,22 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-arm64@0.21.5: + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/freebsd-x64@0.17.6: + resolution: {integrity: sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} @@ -7515,6 +7649,22 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-x64@0.21.5: + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/linux-arm64@0.17.6: + resolution: {integrity: sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} @@ -7531,26 +7681,58 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-arm@0.18.20: - resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + /@esbuild/linux-arm64@0.21.5: + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} - cpu: [arm] + cpu: [arm64] os: [linux] requiresBuild: true optional: true - /@esbuild/linux-arm@0.18.6: - resolution: {integrity: sha512-C+5kb6rgsGMmvIdUI7v1PPgC98A6BMv233e97aXZ5AE03iMdlILFD/20HlHrOi0x2CzbspXn9HOnlE4/Ijn5Kw==} + /@esbuild/linux-arm@0.17.6: + resolution: {integrity: sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw==} engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true optional: true - /@esbuild/linux-ia32@0.18.20: - resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} - cpu: [ia32] + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm@0.18.6: + resolution: {integrity: sha512-C+5kb6rgsGMmvIdUI7v1PPgC98A6BMv233e97aXZ5AE03iMdlILFD/20HlHrOi0x2CzbspXn9HOnlE4/Ijn5Kw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm@0.21.5: + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ia32@0.17.6: + resolution: {integrity: sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] os: [linux] requiresBuild: true optional: true @@ -7563,6 +7745,14 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ia32@0.21.5: + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-loong64@0.15.18: resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} engines: {node: '>=12'} @@ -7572,6 +7762,14 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.17.6: + resolution: {integrity: sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} @@ -7588,6 +7786,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-loong64@0.21.5: + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-mips64el@0.17.6: + resolution: {integrity: sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} @@ -7604,6 +7818,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-mips64el@0.21.5: + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ppc64@0.17.6: + resolution: {integrity: sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} @@ -7620,6 +7850,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ppc64@0.21.5: + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-riscv64@0.17.6: + resolution: {integrity: sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} @@ -7636,6 +7882,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-riscv64@0.21.5: + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-s390x@0.17.6: + resolution: {integrity: sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} @@ -7652,6 +7914,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-s390x@0.21.5: + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-x64@0.17.6: + resolution: {integrity: sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} @@ -7668,6 +7946,22 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-x64@0.21.5: + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/netbsd-x64@0.17.6: + resolution: {integrity: sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} @@ -7684,6 +7978,22 @@ packages: requiresBuild: true optional: true + /@esbuild/netbsd-x64@0.21.5: + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-x64@0.17.6: + resolution: {integrity: sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} @@ -7700,6 +8010,22 @@ packages: requiresBuild: true optional: true + /@esbuild/openbsd-x64@0.21.5: + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/sunos-x64@0.17.6: + resolution: {integrity: sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} @@ -7716,6 +8042,22 @@ packages: requiresBuild: true optional: true + /@esbuild/sunos-x64@0.21.5: + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + + /@esbuild/win32-arm64@0.17.6: + resolution: {integrity: sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} @@ -7732,6 +8074,22 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-arm64@0.21.5: + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-ia32@0.17.6: + resolution: {integrity: sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} @@ -7748,6 +8106,22 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-ia32@0.21.5: + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-x64@0.17.6: + resolution: {integrity: sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} @@ -7764,6 +8138,14 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-x64@0.21.5: + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7817,6 +8199,34 @@ packages: - typescript dev: true + /@floating-ui/core@1.6.7: + resolution: {integrity: sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==} + dependencies: + '@floating-ui/utils': 0.2.7 + dev: false + + /@floating-ui/dom@1.6.10: + resolution: {integrity: sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==} + dependencies: + '@floating-ui/core': 1.6.7 + '@floating-ui/utils': 0.2.7 + dev: false + + /@floating-ui/react-dom@2.1.1(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.6.10 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@floating-ui/utils@0.2.7: + resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==} + dev: false + /@google-cloud/artifact-registry@3.4.0: resolution: {integrity: sha512-49yycYMdkLNVLsMM63ughlioFR0iVrle9D7pQWAfdQMsnnNE80x8ryjUPWDb00wHnHiwWLz508VZrZDA3FzP9g==} engines: {node: '>=14.0.0'} @@ -8024,6 +8434,17 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.0.1 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8121,6 +8542,9 @@ packages: resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} dev: false + /@jspm/core@2.0.1: + resolution: {integrity: sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==} + /@leichtgewicht/ip-codec@2.0.3: resolution: {integrity: sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==} dev: false @@ -8167,7 +8591,6 @@ packages: vfile: 5.3.7 transitivePeerDependencies: - supports-color - dev: false /@mdx-js/mdx@3.0.1: resolution: {integrity: sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==} @@ -8327,6 +8750,53 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.13.0 + /@npmcli/fs@3.1.1: + resolution: {integrity: sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + semver: 7.5.3 + + /@npmcli/git@4.1.0: + resolution: {integrity: sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/promise-spawn': 6.0.2 + lru-cache: 7.18.3 + npm-pick-manifest: 8.0.2 + proc-log: 3.0.0 + promise-inflight: 1.0.1 + promise-retry: 2.0.1 + semver: 7.5.3 + which: 3.0.1 + transitivePeerDependencies: + - bluebird + + /@npmcli/package-json@4.0.1: + resolution: {integrity: sha512-lRCEGdHZomFsURroh522YvA/2cVb9oPIJrjHanCJZkiasz1BzcnLr3tBJhlV7S86MBJBuAQ33is2D60YitZL2Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/git': 4.1.0 + glob: 10.4.5 + hosted-git-info: 6.1.1 + json-parse-even-better-errors: 3.0.2 + normalize-package-data: 5.0.0 + proc-log: 3.0.0 + semver: 7.5.3 + transitivePeerDependencies: + - bluebird + + /@npmcli/promise-spawn@6.0.2: + resolution: {integrity: sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + which: 3.0.1 + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + optional: true + /@pkgr/utils@2.3.1: resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -8407,37 +8877,532 @@ packages: resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} dev: false - /@react-spring/animated@9.6.1(react@18.3.1): - resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==} + /@radix-ui/number@1.1.0: + resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + dev: false + + /@radix-ui/primitive@1.1.0: + resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + dev: false + + /@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-spring/shared': 9.6.1(react@18.3.1) - '@react-spring/types': 9.6.1 + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@react-spring/core@9.6.1(react@18.3.1): - resolution: {integrity: sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==} + /@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true dependencies: - '@react-spring/animated': 9.6.1(react@18.3.1) - '@react-spring/rafz': 9.6.1 - '@react-spring/shared': 9.6.1(react@18.3.1) - '@react-spring/types': 9.6.1 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@react-spring/rafz@9.6.1: - resolution: {integrity: sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==} - dev: false - - /@react-spring/shared@9.6.1(react@18.3.1): - resolution: {integrity: sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==} + /@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-context@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-direction@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-id@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-label@2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/rect': 1.1.0 + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-scroll-area@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-select@2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-8iRDfyLtzxlprOo9IicnzvpsO1wNCkuwzzCM+Z5Rb5tNOpCdMvcc2AkzX0Fz+Tz9v6NJ5B/7EEgyZveo4FBRfQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.1)(react@18.3.1) + dev: false + + /@radix-ui/react-separator@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-slot@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-previous@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-rect@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/rect': 1.1.0 + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-size@1.1.0(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + react: 18.3.1 + dev: false + + /@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/rect@1.1.0: + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + dev: false + + /@react-spring/animated@9.6.1(react@18.3.1): + resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/shared': 9.6.1(react@18.3.1) + '@react-spring/types': 9.6.1 + react: 18.3.1 + dev: false + + /@react-spring/core@9.6.1(react@18.3.1): + resolution: {integrity: sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@react-spring/animated': 9.6.1(react@18.3.1) + '@react-spring/rafz': 9.6.1 + '@react-spring/shared': 9.6.1(react@18.3.1) + '@react-spring/types': 9.6.1 + react: 18.3.1 + dev: false + + /@react-spring/rafz@9.6.1: + resolution: {integrity: sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==} + dev: false + + /@react-spring/shared@9.6.1(react@18.3.1): + resolution: {integrity: sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: '@react-spring/rafz': 9.6.1 '@react-spring/types': 9.6.1 react: 18.3.1 @@ -8540,13 +9505,343 @@ packages: three: 0.158.0 zustand: 3.7.2(react@18.3.1) - /@rive-app/canvas-advanced@2.19.3: - resolution: {integrity: sha512-AcUsPH8ve7pV6QABN0ekwSpIJN0Fudjp+bqYxFUwbtXnE2wvoA0d2yzAtJeVwNQtFKboyfHovNgPIQ9tEdB4VA==} - dev: false + /@remix-run/dev@2.11.2(@remix-run/react@2.11.2)(@remix-run/serve@2.11.2)(typescript@5.3.3)(vite@5.4.3): + resolution: {integrity: sha512-9DGb2UOIO4jOdws04Z+KmCeEBqbP36XvJZdcd4w16wDGI0I1ZY1c5ro58tB/7zPwN40s9MD9UzCYm6P+EkdeAg==} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + '@remix-run/react': ^2.11.2 + '@remix-run/serve': ^2.11.2 + typescript: ^5.1.0 + vite: ^5.1.0 + wrangler: ^3.28.2 + peerDependenciesMeta: + '@remix-run/serve': + optional: true + typescript: + optional: true + vite: + optional: true + wrangler: + optional: true + dependencies: + '@babel/core': 7.24.4 + '@babel/generator': 7.24.10 + '@babel/parser': 7.24.1 + '@babel/plugin-syntax-decorators': 7.24.7(@babel/core@7.24.4) + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.4) + '@babel/preset-typescript': 7.24.7(@babel/core@7.24.4) + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.0 + '@mdx-js/mdx': 2.3.0 + '@npmcli/package-json': 4.0.1 + '@remix-run/node': 2.11.2(typescript@5.3.3) + '@remix-run/react': 2.11.2(react-dom@18.3.1)(react@18.3.1)(typescript@5.3.3) + '@remix-run/router': 1.19.1 + '@remix-run/serve': 2.11.2(typescript@5.3.3) + '@remix-run/server-runtime': 2.11.2(typescript@5.3.3) + '@types/mdx': 2.0.5 + '@vanilla-extract/integration': 6.5.0 + arg: 5.0.2 + cacache: 17.1.4 + chalk: 4.1.2 + chokidar: 3.5.3 + cross-spawn: 7.0.3 + dotenv: 16.4.5 + es-module-lexer: 1.5.4 + esbuild: 0.17.6 + esbuild-plugins-node-modules-polyfill: 1.6.6(esbuild@0.17.6) + execa: 5.1.1 + exit-hook: 2.2.1 + express: 4.19.2 + fs-extra: 10.1.0 + get-port: 5.1.1 + gunzip-maybe: 1.4.2 + jsesc: 3.0.2 + json5: 2.2.3 + lodash: 4.17.21 + lodash.debounce: 4.0.8 + minimatch: 9.0.3 + ora: 5.4.1 + picocolors: 1.0.1 + picomatch: 2.3.1 + pidtree: 0.6.0 + postcss: 8.4.39 + postcss-discard-duplicates: 5.1.0(postcss@8.4.39) + postcss-load-config: 4.0.1(postcss@8.4.39) + postcss-modules: 6.0.0(postcss@8.4.39) + prettier: 2.8.4 + pretty-ms: 7.0.1 + react-refresh: 0.14.0 + remark-frontmatter: 4.0.1 + remark-mdx-frontmatter: 1.1.1 + semver: 7.5.3 + set-cookie-parser: 2.7.0 + tar-fs: 2.1.1 + tsconfig-paths: 4.2.0 + typescript: 5.3.3 + vite: 5.4.3 + ws: 7.5.5 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - bluebird + - bufferutil + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - ts-node + - utf-8-validate + + /@remix-run/express@2.11.2(express@4.19.2)(typescript@5.3.3): + resolution: {integrity: sha512-ebyvHJKRBDgQGNBMxsILt21IwMTjGxQxlr0VNxRJo5rNd5CcuULpx/PPmsBc1gsc/Jx9aUXpT7a9l0UEOc6+jw==} + engines: {node: '>=18.0.0'} + peerDependencies: + express: ^4.19.2 + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@remix-run/node': 2.11.2(typescript@5.3.3) + express: 4.19.2 + typescript: 5.3.3 + + /@remix-run/node@2.11.2(typescript@5.3.3): + resolution: {integrity: sha512-gRNFM61EOYWNmYgf+pvBt6MrirWlkDz1G6RQsJNowtRqbYoy05AdDe5HiHGF5w8ZMAZVeXnZiwbL0Nt7ykYBCA==} + engines: {node: '>=18.0.0'} + peerDependencies: + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@remix-run/server-runtime': 2.11.2(typescript@5.3.3) + '@remix-run/web-fetch': 4.4.2 + '@web3-storage/multipart-parser': 1.0.0 + cookie-signature: 1.2.1 + source-map-support: 0.5.21 + stream-slice: 0.1.2 + typescript: 5.3.3 + undici: 6.19.8 + + /@remix-run/react@2.11.2(react-dom@18.3.1)(react@18.3.1)(typescript@5.3.3): + resolution: {integrity: sha512-SjjuK3aD/9wnIC5r0ZBNCpVSwEwt67YOQM7DCXhHiS8BtCvAxWEC4k4t8CvO9IwBG0gczqxzSqASH7U1RVtWqw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@remix-run/router': 1.19.1 + '@remix-run/server-runtime': 2.11.2(typescript@5.3.3) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.26.1(react@18.3.1) + react-router-dom: 6.26.1(react-dom@18.3.1)(react@18.3.1) + turbo-stream: 2.3.0 + typescript: 5.3.3 + + /@remix-run/router@1.19.1: + resolution: {integrity: sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==} + engines: {node: '>=14.0.0'} + + /@remix-run/serve@2.11.2(typescript@5.3.3): + resolution: {integrity: sha512-f1ETbCAlkSO3kg1zcQyLVHxI2r1TXqV2nfPgX/5+7QmA1dEHJD3OhvSmbvopwSMSfi1jzuyRbJo04yK4aJ8ztg==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + '@remix-run/express': 2.11.2(express@4.19.2)(typescript@5.3.3) + '@remix-run/node': 2.11.2(typescript@5.3.3) + chokidar: 3.5.3 + compression: 1.7.4 + express: 4.19.2 + get-port: 5.1.1 + morgan: 1.10.0 + source-map-support: 0.5.21 + transitivePeerDependencies: + - supports-color + - typescript + + /@remix-run/server-runtime@2.11.2(typescript@5.3.3): + resolution: {integrity: sha512-abG6ENj0X3eHqDxqO2thWM2NSEiPnqyt58z1BbiQCv+t8g0Zuqd5QHbB4wzdNvfS0vKhg+jJiigcJneAc4sZzw==} + engines: {node: '>=18.0.0'} + peerDependencies: + typescript: ^5.1.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@remix-run/router': 1.19.1 + '@types/cookie': 0.6.0 + '@web3-storage/multipart-parser': 1.0.0 + cookie: 0.6.0 + set-cookie-parser: 2.7.0 + source-map: 0.7.3 + turbo-stream: 2.3.0 + typescript: 5.3.3 + + /@remix-run/web-blob@3.1.0: + resolution: {integrity: sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==} + dependencies: + '@remix-run/web-stream': 1.1.0 + web-encoding: 1.1.5 + + /@remix-run/web-fetch@4.4.2: + resolution: {integrity: sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==} + engines: {node: ^10.17 || >=12.3} + dependencies: + '@remix-run/web-blob': 3.1.0 + '@remix-run/web-file': 3.1.0 + '@remix-run/web-form-data': 3.1.0 + '@remix-run/web-stream': 1.1.0 + '@web3-storage/multipart-parser': 1.0.0 + abort-controller: 3.0.0 + data-uri-to-buffer: 3.0.1 + mrmime: 1.0.1 + + /@remix-run/web-file@3.1.0: + resolution: {integrity: sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==} + dependencies: + '@remix-run/web-blob': 3.1.0 + + /@remix-run/web-form-data@3.1.0: + resolution: {integrity: sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==} + dependencies: + web-encoding: 1.1.5 + + /@remix-run/web-stream@1.1.0: + resolution: {integrity: sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==} + dependencies: + web-streams-polyfill: 3.3.3 + + /@rive-app/canvas-advanced@2.19.3: + resolution: {integrity: sha512-AcUsPH8ve7pV6QABN0ekwSpIJN0Fudjp+bqYxFUwbtXnE2wvoA0d2yzAtJeVwNQtFKboyfHovNgPIQ9tEdB4VA==} + dev: false + + /@rive-app/canvas-advanced@2.3.0: + resolution: {integrity: sha512-JzgY8aSvWbuigoJ+8x1lHW8or0syQz8hxpRdPijkCCp/GJYRPvBstYdJPbHk2nbv5+BV+8Rv4zRw96wKFVsvKQ==} + dev: false + + /@rollup/rollup-android-arm-eabi@4.21.2: + resolution: {integrity: sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==} + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + + /@rollup/rollup-android-arm64@4.21.2: + resolution: {integrity: sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + + /@rollup/rollup-darwin-arm64@4.21.2: + resolution: {integrity: sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@rollup/rollup-darwin-x64@4.21.2: + resolution: {integrity: sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.21.2: + resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.21.2: + resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.21.2: + resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.21.2: + resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.21.2: + resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.21.2: + resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.21.2: + resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.21.2: + resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.21.2: + resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.21.2: + resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.21.2: + resolution: {integrity: sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true - /@rive-app/canvas-advanced@2.3.0: - resolution: {integrity: sha512-JzgY8aSvWbuigoJ+8x1lHW8or0syQz8hxpRdPijkCCp/GJYRPvBstYdJPbHk2nbv5+BV+8Rv4zRw96wKFVsvKQ==} - dev: false + /@rollup/rollup-win32-x64-msvc@4.21.2: + resolution: {integrity: sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true /@shopify/react-native-skia@1.2.2(react@18.3.1): resolution: {integrity: sha512-YlDNJXTCstlOmyJxeQjaTaef8ACLuEPMDrSgEichQM3ELlWuU1HTSVbpXW2x4LbbEDPXwu/aF/16MUN8pzzcmA==} @@ -9438,6 +10733,15 @@ packages: engines: {node: '>=10.13.0'} dev: false + /@ts-morph/common@0.11.1: + resolution: {integrity: sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==} + dependencies: + fast-glob: 3.2.12 + minimatch: 3.1.2 + mkdirp: 1.0.4 + path-browserify: 1.0.1 + dev: false + /@tsconfig/docusaurus@1.0.5: resolution: {integrity: sha512-KM/TuJa9fugo67dTGx+ktIqf3fVc077J6jwHu845Hex4EQf7LABlNonP/mohDKT0cmncdtlYVHHF74xR/YpThg==} dev: true @@ -9446,7 +10750,6 @@ packages: resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} dependencies: '@types/estree': 1.0.5 - dev: false /@types/aria-query@4.2.2: resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} @@ -9541,6 +10844,9 @@ packages: '@types/node': 20.14.11 dev: false + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + /@types/css-font-loading-module@0.0.7: resolution: {integrity: sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==} dev: true @@ -9549,7 +10855,6 @@ packages: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: '@types/ms': 0.7.31 - dev: false /@types/dom-webcodecs@0.1.11: resolution: {integrity: sha512-yPEZ3z7EohrmOxbk/QTAa0yonMFkNkjnVXqbGb7D4rMr+F1dGQ8ZUFxXkyLLJuiICPejZ0AZE9Rrk9wUCczx4A==} @@ -9562,11 +10867,9 @@ packages: resolution: {integrity: sha512-3qvGd0z8F2ENTGr/GG1yViqfiKmRfrXVx5sJyHGFu3z7m5g5utCQtGp/g29JnjflhtQJBv1WDQukHiT58xPcYQ==} dependencies: '@types/estree': 1.0.5 - dev: false /@types/estree@1.0.0: resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} - dev: false /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -9614,7 +10917,6 @@ packages: resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==} dependencies: '@types/unist': 2.0.6 - dev: false /@types/hast@3.0.4: resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -9690,7 +10992,6 @@ packages: resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==} dependencies: '@types/unist': 2.0.6 - dev: false /@types/mdast@4.0.4: resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -9700,7 +11001,6 @@ packages: /@types/mdx@2.0.5: resolution: {integrity: sha512-76CqzuD6Q7LC+AtbPqrvD9AqsN0k8bsYo2bM2J8pmNldP1aIPAbzUQ7QbobyXL4eLr1wK5x8FZFe8eF/ubRuBg==} - dev: false /@types/mime-types@2.1.1: resolution: {integrity: sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==} @@ -9722,7 +11022,6 @@ packages: /@types/ms@0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} - dev: false /@types/nlcst@1.0.0: resolution: {integrity: sha512-3TGCfOcy8R8mMQ4CNSNOe3PG66HttvjcLzCoOpvXvDtfWOTi+uT/rxeOKm/qEwbM4SNe1O/PjdiBK2YcTjU4OQ==} @@ -10541,6 +11840,90 @@ packages: react: 18.3.1 dev: false + /@vanilla-extract/babel-plugin-debug-ids@1.0.6: + resolution: {integrity: sha512-C188vUEYmw41yxg3QooTs8r1IdbDQQ2mH7L5RkORBnHx74QlmsNfqVmKwAVTgrlYt8JoRaWMtPfGm/Ql0BNQrA==} + dependencies: + '@babel/core': 7.24.4 + transitivePeerDependencies: + - supports-color + + /@vanilla-extract/css@1.15.5: + resolution: {integrity: sha512-N1nQebRWnXvlcmu9fXKVUs145EVwmWtMD95bpiEKtvehHDpUhmO1l2bauS7FGYKbi3dU1IurJbGpQhBclTr1ng==} + dependencies: + '@emotion/hash': 0.9.2 + '@vanilla-extract/private': 1.0.6 + css-what: 6.1.0 + cssesc: 3.0.0 + csstype: 3.1.1 + dedent: 1.5.3 + deep-object-diff: 1.1.9 + deepmerge: 4.3.1 + lru-cache: 10.4.3 + media-query-parser: 2.0.2 + modern-ahocorasick: 1.0.1 + picocolors: 1.0.1 + transitivePeerDependencies: + - babel-plugin-macros + + /@vanilla-extract/integration@6.5.0: + resolution: {integrity: sha512-E2YcfO8vA+vs+ua+gpvy1HRqvgWbI+MTlUpxA8FvatOvybuNcWAY0CKwQ/Gpj7rswYKtC6C7+xw33emM6/ImdQ==} + dependencies: + '@babel/core': 7.24.4 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.4) + '@vanilla-extract/babel-plugin-debug-ids': 1.0.6 + '@vanilla-extract/css': 1.15.5 + esbuild: 0.18.6 + eval: 0.1.8 + find-up: 5.0.0 + javascript-stringify: 2.1.0 + lodash: 4.17.21 + mlly: 1.5.0 + outdent: 0.8.0 + vite: 5.4.3 + vite-node: 1.6.0 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + /@vanilla-extract/private@1.0.6: + resolution: {integrity: sha512-ytsG/JLweEjw7DBuZ/0JCN4WAQgM9erfSTdS1NQY778hFQSZ6cfCDEZZ0sgVm4k54uNz6ImKB33AYvSR//fjxw==} + + /@vercel/remix@2.11.2(@remix-run/dev@2.11.2)(@remix-run/node@2.11.2)(@remix-run/server-runtime@2.11.2)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-5UZ4TZV8hDvaCUhEns4ph2f1ty9mZYTw8wbKyamwypErrZNZEA+PqqdyfIx/4EE6vKJ//loRo/PB2tR5NTxnxw==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@remix-run/dev': 2.11.2 + '@remix-run/node': 2.11.2 + '@remix-run/server-runtime': 2.11.2 + react: '*' + react-dom: '*' + dependencies: + '@remix-run/dev': 2.11.2(@remix-run/react@2.11.2)(@remix-run/serve@2.11.2)(typescript@5.3.3)(vite@5.4.3) + '@remix-run/node': 2.11.2(typescript@5.3.3) + '@remix-run/server-runtime': 2.11.2(typescript@5.3.3) + '@vercel/static-config': 3.0.0 + isbot: 3.8.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + ts-morph: 12.0.0 + dev: false + + /@vercel/static-config@3.0.0: + resolution: {integrity: sha512-2qtvcBJ1bGY0dYGYh3iM7yGKkk971FujLEDXzuW5wcZsPr1GSEjO/w2iSr3qve6nDDtBImsGoDEnus5FI4+fIw==} + dependencies: + ajv: 8.6.3 + json-schema-to-ts: 1.6.4 + ts-morph: 12.0.0 + dev: false + /@vitejs/plugin-react@2.2.0(vite@3.2.10): resolution: {integrity: sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -10607,6 +11990,9 @@ packages: resolution: {integrity: sha512-ukOMWnCg1tCvT7WnDfsUKQOFDQGsyR5tNgRpwmqi+5/vzU3ghdDXzvIM4IOPdSb3OeSsBNvmSL8nxIVOqi2WXA==} dev: false + /@web3-storage/multipart-parser@1.0.0: + resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} + /@webassemblyjs/ast@1.12.1: resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} dependencies: @@ -10733,6 +12119,11 @@ packages: /@xtuc/long@4.2.2: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + /@zxing/text-encoding@0.9.0: + resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} + requiresBuild: true + optional: true + /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} deprecated: Use your platform's native atob() and btoa() methods instead @@ -10742,7 +12133,6 @@ packages: engines: {node: '>=6.5'} dependencies: event-target-shim: 5.0.1 - dev: false /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -10750,7 +12140,6 @@ packages: dependencies: mime-types: 2.1.34 negotiator: 0.6.3 - dev: false /acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} @@ -10822,7 +12211,6 @@ packages: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - dev: false /ajv-formats@2.1.1(ajv@8.11.0): resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} @@ -10868,6 +12256,15 @@ packages: uri-js: 4.4.1 dev: false + /ajv@8.6.3: + resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + dev: false + /algoliasearch-helper@3.22.2(algoliasearch@4.24.0): resolution: {integrity: sha512-3YQ6eo7uYOCHeQ2ZpD+OoT3aJJwMNKEnwtu8WMzm81XmBOSCwRjQditH9CeSOQ38qhHkuGw23pbq+kULkIJLcw==} peerDependencies: @@ -10916,7 +12313,6 @@ packages: /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -10937,11 +12333,9 @@ packages: /ansi-styles@6.1.0: resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==} engines: {node: '>=12'} - dev: false /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: false /anymatch@3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} @@ -10952,7 +12346,6 @@ packages: /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: false /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -10963,6 +12356,13 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + /aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + dependencies: + tslib: 2.6.2 + dev: false + /aria-query@5.0.0: resolution: {integrity: sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==} engines: {node: '>=6.0'} @@ -10992,7 +12392,6 @@ packages: /array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - dev: false /array-flatten@2.1.2: resolution: {integrity: sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==} @@ -11103,7 +12502,6 @@ packages: /astring@1.8.6: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true - dev: false /astro@2.0.14: resolution: {integrity: sha512-BiXnHyK3rj5Uz45V5p9jRi0xtJc/zxhCxnXYAekHHF1bVvvoa3aXMwl0GZ3Bc0mxP6vPLmbRcjNKdqfyZn1B3Q==} @@ -11209,19 +12607,19 @@ packages: postcss-value-parser: 4.2.0 dev: false - /autoprefixer@10.4.14(postcss@8.4.33): - resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} + /autoprefixer@10.4.19(postcss@8.4.31): + resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.21.5 + browserslist: 4.23.2 caniuse-lite: 1.0.30001636 - fraction.js: 4.2.0 + fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.33 + picocolors: 1.0.1 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false @@ -11239,7 +12637,6 @@ packages: picocolors: 1.0.1 postcss: 8.4.39 postcss-value-parser: 4.2.0 - dev: false /available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -11375,7 +12772,6 @@ packages: /bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - dev: false /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -11396,6 +12792,12 @@ packages: pascalcase: 0.1.1 dev: false + /basic-auth@2.0.1: + resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} + engines: {node: '>= 0.8'} + dependencies: + safe-buffer: 5.1.2 + /batch@0.6.1: resolution: {integrity: sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=} dev: false @@ -11423,7 +12825,6 @@ packages: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.0 - dev: true /bl@5.1.0: resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} @@ -11454,6 +12855,25 @@ packages: - supports-color dev: false + /body-parser@1.20.2: + resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + /bonjour-service@1.0.11: resolution: {integrity: sha512-drMprzr2rDTCtgEE3VgdA9uUFaUHF+jXduwYSThHJnKMYM+FhI9Z3ph+TX3xy0LtgYHae6CHYPJ/2UnK8nQHcA==} dependencies: @@ -11534,6 +12954,11 @@ packages: dependencies: fill-range: 7.0.1 + /browserify-zlib@0.1.4: + resolution: {integrity: sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==} + dependencies: + pako: 0.2.9 + /browserslist@4.14.2: resolution: {integrity: sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -11599,7 +13024,6 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true /buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -11625,17 +13049,32 @@ packages: /bytes@3.0.0: resolution: {integrity: sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=} engines: {node: '>= 0.8'} - dev: false /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - dev: false /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + /cacache@17.1.4: + resolution: {integrity: sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/fs': 3.1.1 + fs-minipass: 3.0.3 + glob: 10.4.5 + lru-cache: 7.18.3 + minipass: 7.1.2 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 4.0.0 + ssri: 10.0.6 + tar: 6.2.1 + unique-filename: 3.0.0 + /cache-base@1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -11709,7 +13148,6 @@ packages: /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - dev: false /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} @@ -11752,7 +13190,6 @@ packages: /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - dev: false /chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} @@ -11793,19 +13230,15 @@ packages: /character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - dev: false /character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - dev: false /character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - dev: false /character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - dev: false /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -11852,12 +13285,10 @@ packages: /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - dev: true /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - dev: false /chroma-js@1.4.1: resolution: {integrity: sha512-jTwQiT859RTFN/vIf7s+Vl/Z2LcMrvMv3WUFmd/4u76AdlFC0NTNgqEEFPcRiHmAswPsMiQEDZLM8vX8qXpZNQ==} @@ -11882,6 +13313,12 @@ packages: static-extend: 0.1.2 dev: false + /class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + dependencies: + clsx: 2.0.0 + dev: false + /clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -11892,13 +13329,18 @@ packages: /clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - dev: false /cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} dev: false + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + /cli-cursor@4.0.0: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -11909,7 +13351,6 @@ packages: /cli-spinners@2.7.0: resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} engines: {node: '>=6'} - dev: false /cli-table3@0.6.5: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} @@ -11958,7 +13399,6 @@ packages: /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: false /cloudevents@8.0.1: resolution: {integrity: sha512-E8BC4CpxF60q+6jqFctWG8pnFo9S9s3nVStyg9FgVUZ5v0DEdbT+gLYcxFNJBWc2ATNZmC8CUm4FaBWbgVj1Sw==} @@ -11977,11 +13417,20 @@ packages: engines: {node: '>=6'} dev: false + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + /clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} dev: false + /code-block-writer@10.1.1: + resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==} + dev: false + /collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} dev: false @@ -12054,7 +13503,6 @@ packages: /comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - dev: false /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} @@ -12067,7 +13515,6 @@ packages: /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: false /commander@5.1.0: resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} @@ -12105,7 +13552,6 @@ packages: engines: {node: '>= 0.6'} dependencies: mime-db: 1.51.0 - dev: false /compression@1.7.4: resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} @@ -12120,7 +13566,6 @@ packages: vary: 1.1.2 transitivePeerDependencies: - supports-color - dev: false /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -12175,12 +13620,14 @@ packages: engines: {node: '>= 0.6'} dependencies: safe-buffer: 5.2.1 - dev: false /content-type@1.0.4: resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} engines: {node: '>= 0.6'} - dev: false + + /content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} /convert-source-map@1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} @@ -12193,7 +13640,10 @@ packages: /cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - dev: false + + /cookie-signature@1.2.1: + resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==} + engines: {node: '>=6.6.0'} /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} @@ -12205,6 +13655,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + /copy-anything@3.0.5: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} @@ -12272,7 +13726,6 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: false /cosmiconfig@6.0.0: resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} @@ -12341,7 +13794,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /css-color-keywords@1.0.0: @@ -12349,15 +13802,6 @@ packages: engines: {node: '>=4'} dev: false - /css-declaration-sorter@7.2.0(postcss@8.4.33): - resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - postcss: ^8.0.9 - dependencies: - postcss: 8.4.33 - dev: false - /css-declaration-sorter@7.2.0(postcss@8.4.39): resolution: {integrity: sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==} engines: {node: ^14 || ^16 || >=18} @@ -12373,9 +13817,9 @@ packages: peerDependencies: postcss: ^8.4 dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.13) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.1) postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 postcss-value-parser: 4.2.0 dev: false @@ -12410,12 +13854,12 @@ packages: webpack: optional: true dependencies: - icss-utils: 5.1.0(postcss@8.4.33) - postcss: 8.4.33 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.33) - postcss-modules-local-by-default: 4.0.5(postcss@8.4.33) - postcss-modules-scope: 3.2.0(postcss@8.4.33) - postcss-modules-values: 4.0.0(postcss@8.4.33) + icss-utils: 5.1.0(postcss@8.4.39) + postcss: 8.4.39 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.39) + postcss-modules-local-by-default: 4.0.5(postcss@8.4.39) + postcss-modules-scope: 3.2.0(postcss@8.4.39) + postcss-modules-values: 4.0.0(postcss@8.4.39) postcss-value-parser: 4.2.0 semver: 7.5.4 webpack: 5.94.0(@swc/core@1.3.80) @@ -12448,9 +13892,9 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.25 clean-css: 5.3.3 - cssnano: 6.1.2(postcss@8.4.33) + cssnano: 6.1.2(postcss@8.4.39) jest-worker: 29.7.0 - postcss: 8.4.33 + postcss: 8.4.39 schema-utils: 4.2.0 serialize-javascript: 6.0.1 webpack: 5.94.0(@swc/core@1.3.80) @@ -12512,7 +13956,6 @@ packages: /css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} - dev: false /cssdb@7.6.0: resolution: {integrity: sha512-Nna7rph8V0jC6+JBY4Vk4ndErUmfJfV6NJCaZdurL0omggabiy+QB2HCQtu5c/ACLZ0I7REv7A4QyPIoYzZx0w==} @@ -12522,7 +13965,6 @@ packages: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - dev: false /cssnano-preset-advanced@6.1.2(postcss@8.4.39): resolution: {integrity: sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==} @@ -12540,45 +13982,6 @@ packages: postcss-zindex: 6.0.2(postcss@8.4.39) dev: false - /cssnano-preset-default@6.1.2(postcss@8.4.33): - resolution: {integrity: sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - css-declaration-sorter: 7.2.0(postcss@8.4.33) - cssnano-utils: 4.0.2(postcss@8.4.33) - postcss: 8.4.33 - postcss-calc: 9.0.1(postcss@8.4.33) - postcss-colormin: 6.1.0(postcss@8.4.33) - postcss-convert-values: 6.1.0(postcss@8.4.33) - postcss-discard-comments: 6.0.2(postcss@8.4.33) - postcss-discard-duplicates: 6.0.3(postcss@8.4.33) - postcss-discard-empty: 6.0.3(postcss@8.4.33) - postcss-discard-overridden: 6.0.2(postcss@8.4.33) - postcss-merge-longhand: 6.0.5(postcss@8.4.33) - postcss-merge-rules: 6.1.1(postcss@8.4.33) - postcss-minify-font-values: 6.1.0(postcss@8.4.33) - postcss-minify-gradients: 6.0.3(postcss@8.4.33) - postcss-minify-params: 6.1.0(postcss@8.4.33) - postcss-minify-selectors: 6.0.4(postcss@8.4.33) - postcss-normalize-charset: 6.0.2(postcss@8.4.33) - postcss-normalize-display-values: 6.0.2(postcss@8.4.33) - postcss-normalize-positions: 6.0.2(postcss@8.4.33) - postcss-normalize-repeat-style: 6.0.2(postcss@8.4.33) - postcss-normalize-string: 6.0.2(postcss@8.4.33) - postcss-normalize-timing-functions: 6.0.2(postcss@8.4.33) - postcss-normalize-unicode: 6.1.0(postcss@8.4.33) - postcss-normalize-url: 6.0.2(postcss@8.4.33) - postcss-normalize-whitespace: 6.0.2(postcss@8.4.33) - postcss-ordered-values: 6.0.2(postcss@8.4.33) - postcss-reduce-initial: 6.1.0(postcss@8.4.33) - postcss-reduce-transforms: 6.0.2(postcss@8.4.33) - postcss-svgo: 6.0.3(postcss@8.4.33) - postcss-unique-selectors: 6.0.4(postcss@8.4.33) - dev: false - /cssnano-preset-default@6.1.2(postcss@8.4.39): resolution: {integrity: sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==} engines: {node: ^14 || ^16 || >=18.0} @@ -12618,15 +14021,6 @@ packages: postcss-unique-selectors: 6.0.4(postcss@8.4.39) dev: false - /cssnano-utils@4.0.2(postcss@8.4.33): - resolution: {integrity: sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - dev: false - /cssnano-utils@4.0.2(postcss@8.4.39): resolution: {integrity: sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -12636,15 +14030,15 @@ packages: postcss: 8.4.39 dev: false - /cssnano@6.1.2(postcss@8.4.33): + /cssnano@6.1.2(postcss@8.4.39): resolution: {integrity: sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==} engines: {node: ^14 || ^16 || >=18.0} peerDependencies: postcss: ^8.4.31 dependencies: - cssnano-preset-default: 6.1.2(postcss@8.4.33) + cssnano-preset-default: 6.1.2(postcss@8.4.39) lilconfig: 3.1.2 - postcss: 8.4.33 + postcss: 8.4.39 dev: false /csso@5.0.5: @@ -12680,6 +14074,10 @@ packages: type: 1.2.0 dev: false + /data-uri-to-buffer@3.0.1: + resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==} + engines: {node: '>= 6'} + /data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -12730,7 +14128,6 @@ packages: optional: true dependencies: ms: 2.0.0 - dev: false /debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} @@ -12773,7 +14170,6 @@ packages: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} dependencies: character-entities: 2.0.2 - dev: false /decode-uri-component@0.2.0: resolution: {integrity: sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==} @@ -12786,6 +14182,14 @@ packages: dependencies: mimic-response: 3.1.0 + /dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} @@ -12799,6 +14203,9 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + /deep-object-diff@1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + /deepmerge-ts@4.3.0: resolution: {integrity: sha512-if3ZYdkD2dClhnXR5reKtG98cwyaRT1NeugQoAPTTfsOpV9kqyeiBF9Qa5RHjemb3KzD5ulqygv6ED3t5j9eJw==} engines: {node: '>=12.4.0'} @@ -12812,7 +14219,6 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - dev: false /default-gateway@6.0.3: resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} @@ -12825,7 +14231,6 @@ packages: resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} dependencies: clone: 1.0.4 - dev: false /defer-to-connect@2.0.1: resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} @@ -12901,15 +14306,22 @@ packages: engines: {node: '>= 0.6'} dev: false + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: false /destroy@1.0.4: resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} dev: false + /destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + /detect-gpu@5.0.34: resolution: {integrity: sha512-iHYDY2iy6OVvJVmTXvMrp5+OROP0Q62qTlrsC7wl3kZmm6yVAoOhQx5cIIxTVEEIZe1M1aPVI3RgsbG/Z6/7PQ==} dependencies: @@ -12921,6 +14333,10 @@ packages: engines: {node: '>=8'} dev: true + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + /detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} dev: false @@ -12959,12 +14375,10 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: false /diff@5.1.0: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} engines: {node: '>=0.3.1'} - dev: false /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} @@ -12974,7 +14388,6 @@ packages: /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: false /dns-equal@1.0.0: resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} @@ -13080,6 +14493,10 @@ packages: is-obj: 2.0.0 dev: false + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + /dotenv@9.0.2: resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==} engines: {node: '>=10'} @@ -13098,6 +14515,14 @@ packages: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: false + /duplexify@3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 2.3.8 + stream-shift: 1.0.3 + /duplexify@4.1.2: resolution: {integrity: sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==} dependencies: @@ -13118,7 +14543,6 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: false /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -13128,7 +14552,6 @@ packages: /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - dev: false /electron-to-chromium@1.4.828: resolution: {integrity: sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw==} @@ -13142,11 +14565,9 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: false /emojilib@2.4.0: resolution: {integrity: sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==} @@ -13163,7 +14584,6 @@ packages: /encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} - dev: false /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -13189,6 +14609,9 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + /err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -13283,6 +14706,9 @@ packages: /es-module-lexer@1.2.1: resolution: {integrity: sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==} + /es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + /es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} engines: {node: '>= 0.4'} @@ -13486,6 +14912,17 @@ packages: dev: true optional: true + /esbuild-plugins-node-modules-polyfill@1.6.6(esbuild@0.17.6): + resolution: {integrity: sha512-0wDvliv65SCaaGtmoITnmXqqiUzU+ggFupnOgkEo2B9cQ+CUt58ql2+EY6dYoEsoqiHRu2NuTrFUJGMJEgMmLw==} + engines: {node: '>=14.0.0'} + peerDependencies: + esbuild: '>=0.14.0 ^0.23.0' + dependencies: + '@jspm/core': 2.0.1 + esbuild: 0.17.6 + local-pkg: 0.5.0 + resolve.exports: 2.0.2 + /esbuild-sunos-64@0.15.18: resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} engines: {node: '>=12'} @@ -13552,6 +14989,35 @@ packages: esbuild-windows-arm64: 0.15.18 dev: true + /esbuild@0.17.6: + resolution: {integrity: sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.17.6 + '@esbuild/android-arm64': 0.17.6 + '@esbuild/android-x64': 0.17.6 + '@esbuild/darwin-arm64': 0.17.6 + '@esbuild/darwin-x64': 0.17.6 + '@esbuild/freebsd-arm64': 0.17.6 + '@esbuild/freebsd-x64': 0.17.6 + '@esbuild/linux-arm': 0.17.6 + '@esbuild/linux-arm64': 0.17.6 + '@esbuild/linux-ia32': 0.17.6 + '@esbuild/linux-loong64': 0.17.6 + '@esbuild/linux-mips64el': 0.17.6 + '@esbuild/linux-ppc64': 0.17.6 + '@esbuild/linux-riscv64': 0.17.6 + '@esbuild/linux-s390x': 0.17.6 + '@esbuild/linux-x64': 0.17.6 + '@esbuild/netbsd-x64': 0.17.6 + '@esbuild/openbsd-x64': 0.17.6 + '@esbuild/sunos-x64': 0.17.6 + '@esbuild/win32-arm64': 0.17.6 + '@esbuild/win32-ia32': 0.17.6 + '@esbuild/win32-x64': 0.17.6 + /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -13610,6 +15076,36 @@ packages: '@esbuild/win32-ia32': 0.18.6 '@esbuild/win32-x64': 0.18.6 + /esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -13621,7 +15117,6 @@ packages: /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - dev: false /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -13859,7 +15354,6 @@ packages: resolution: {integrity: sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w==} dependencies: '@types/estree': 1.0.5 - dev: false /estree-util-attach-comments@3.0.0: resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} @@ -13873,7 +15367,6 @@ packages: '@types/estree-jsx': 1.0.0 estree-util-is-identifier-name: 2.1.0 estree-walker: 3.0.3 - dev: false /estree-util-build-jsx@3.0.1: resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} @@ -13884,9 +15377,11 @@ packages: estree-walker: 3.0.3 dev: false + /estree-util-is-identifier-name@1.1.0: + resolution: {integrity: sha512-OVJZ3fGGt9By77Ix9NhaRbzfbDV/2rx9EP7YIDJTmsZSEc5kYn2vWcNccYyahJL2uAQZK2a5Or2i0wtIKTPoRQ==} + /estree-util-is-identifier-name@2.1.0: resolution: {integrity: sha512-bEN9VHRyXAUOjkKVQVvArFym08BTWB0aJPppZZr0UNyAqWsLaVfAqP7hbaTJjzHifmB5ebnR8Wm7r7yGN/HonQ==} - dev: false /estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} @@ -13898,7 +15393,6 @@ packages: '@types/estree-jsx': 1.0.0 astring: 1.8.6 source-map: 0.7.3 - dev: false /estree-util-to-js@2.0.0: resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} @@ -13908,6 +15402,12 @@ packages: source-map: 0.7.3 dev: false + /estree-util-value-to-estree@1.3.0: + resolution: {integrity: sha512-Y+ughcF9jSUJvncXwqRageavjrNPAI+1M/L3BI3PyLp1nmgYTGUXU6t5z1Y7OWuThoDdhPME07bQU+d5LxdJqw==} + engines: {node: '>=12.0.0'} + dependencies: + is-plain-obj: 3.0.0 + /estree-util-value-to-estree@3.1.2: resolution: {integrity: sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==} dependencies: @@ -13919,7 +15419,6 @@ packages: dependencies: '@types/estree-jsx': 1.0.0 '@types/unist': 2.0.6 - dev: false /estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} @@ -13932,7 +15431,6 @@ packages: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} dependencies: '@types/estree': 1.0.0 - dev: false /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} @@ -13946,7 +15444,6 @@ packages: /etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - dev: false /eval@0.1.8: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} @@ -13954,12 +15451,10 @@ packages: dependencies: '@types/node': 20.14.11 require-like: 0.1.2 - dev: false /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} - dev: false /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -14012,6 +15507,10 @@ packages: strip-final-newline: 3.0.0 dev: false + /exit-hook@2.2.1: + resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} + engines: {node: '>=6'} + /expand-brackets@2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} @@ -14070,6 +15569,44 @@ packages: - supports-color dev: false + /express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.2 + content-disposition: 0.5.4 + content-type: 1.0.4 + cookie: 0.6.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.11.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + /ext@1.6.0: resolution: {integrity: sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==} dependencies: @@ -14093,7 +15630,6 @@ packages: /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false /extglob@2.0.4: resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} @@ -14156,6 +15692,16 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -14195,7 +15741,6 @@ packages: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} dependencies: format: 0.2.2 - dev: false /faye-websocket@0.11.4: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} @@ -14285,6 +15830,20 @@ packages: - supports-color dev: false + /finalhandler@1.2.0: + resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + /find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -14374,6 +15933,13 @@ packages: engines: {node: '>=0.10.0'} dev: false + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + /fork-ts-checker-webpack-plugin@4.1.6(eslint@8.56.0)(typescript@5.3.3)(webpack@5.94.0): resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} engines: {node: '>=6.11.5', yarn: '>=1.0.0'} @@ -14463,7 +16029,6 @@ packages: /format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} - dev: false /formdata-node@4.4.1: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} @@ -14476,7 +16041,6 @@ packages: /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - dev: false /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} @@ -14484,7 +16048,6 @@ packages: /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - dev: false /fragment-cache@0.2.1: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} @@ -14496,11 +16059,17 @@ packages: /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} - dev: false /fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.0 /fs-extra@11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} @@ -14526,7 +16095,12 @@ packages: engines: {node: '>= 8'} dependencies: minipass: 3.1.5 - dev: false + + /fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 7.1.2 /fs-monkey@1.0.3: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} @@ -14606,6 +16180,11 @@ packages: - supports-color dev: false + /generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + dependencies: + loader-utils: 3.2.0 + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -14628,10 +16207,19 @@ packages: has-symbols: 1.0.3 hasown: 2.0.2 + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + /get-own-enumerable-property-symbols@3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: false + /get-port@5.1.1: + resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} + engines: {node: '>=8'} + /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -14686,8 +16274,20 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + /glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + /glob@7.1.6: resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -14695,7 +16295,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: false /glob@7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} @@ -14786,7 +16385,6 @@ packages: /globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - dev: false /glsl-noise@0.0.0: resolution: {integrity: sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==} @@ -14941,6 +16539,17 @@ packages: - supports-color dev: false + /gunzip-maybe@1.4.2: + resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} + hasBin: true + dependencies: + browserify-zlib: 0.1.4 + is-deflate: 1.0.0 + is-gzip: 1.0.0 + peek-stream: 1.1.3 + pumpify: 1.5.1 + through2: 2.0.5 + /gzip-size@5.1.1: resolution: {integrity: sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==} engines: {node: '>=6'} @@ -15137,7 +16746,6 @@ packages: zwitch: 2.0.4 transitivePeerDependencies: - supports-color - dev: false /hast-util-to-estree@3.1.0: resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==} @@ -15225,7 +16833,6 @@ packages: /hast-util-whitespace@2.0.1: resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==} - dev: false /hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -15286,6 +16893,12 @@ packages: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: false + /hosted-git-info@6.1.1: + resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + lru-cache: 7.18.3 + /hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} dependencies: @@ -15424,6 +17037,16 @@ packages: toidentifier: 1.0.1 dev: false + /http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + /http-parser-js@0.5.3: resolution: {integrity: sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==} dev: false @@ -15434,7 +17057,7 @@ packages: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.6(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -15488,7 +17111,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.6(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -15522,7 +17145,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 - dev: false /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -15539,6 +17161,14 @@ packages: postcss: 8.4.33 dev: false + /icss-utils@5.1.0(postcss@8.4.39): + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + postcss: 8.4.39 + /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -15588,7 +17218,6 @@ packages: /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - dev: false /infima@0.2.0-alpha.43: resolution: {integrity: sha512-2uw57LvUqW0rK/SWYnd/2rRfxNA5DDNOh33jxF7fy46VWoNhGxiUQyVZHbBMjQ33mQem0cjdDVwgWVAmlRfgyQ==} @@ -15619,7 +17248,6 @@ packages: /inline-style-parser@0.1.1: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} - dev: false /inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} @@ -15647,7 +17275,6 @@ packages: /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - dev: false /ipaddr.js@2.0.1: resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==} @@ -15670,14 +17297,12 @@ packages: /is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - dev: false /is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} dependencies: is-alphabetical: 2.0.1 is-decimal: 2.0.1 - dev: false /is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} @@ -15685,7 +17310,6 @@ packages: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: false /is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} @@ -15734,7 +17358,6 @@ packages: /is-buffer@2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} engines: {node: '>=4'} - dev: false /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} @@ -15780,7 +17403,9 @@ packages: /is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - dev: false + + /is-deflate@1.0.0: + resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} /is-descriptor@0.1.6: resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==} @@ -15837,7 +17462,6 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: false /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} @@ -15851,9 +17475,12 @@ packages: dependencies: is-extglob: 2.1.1 + /is-gzip@1.0.0: + resolution: {integrity: sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==} + engines: {node: '>=0.10.0'} + /is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - dev: false /is-installed-globally@0.4.0: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} @@ -15863,6 +17490,10 @@ packages: is-path-inside: 3.0.3 dev: false + /is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + /is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -15921,12 +17552,10 @@ packages: /is-plain-obj@3.0.0: resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} engines: {node: '>=10'} - dev: false /is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - dev: false /is-plain-object@2.0.4: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} @@ -15942,7 +17571,6 @@ packages: resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} dependencies: '@types/estree': 1.0.5 - dev: false /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -16003,6 +17631,10 @@ packages: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} dev: false + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + /is-unicode-supported@1.3.0: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} @@ -16054,11 +17686,20 @@ packages: /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: false /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + /isbot@3.8.0: + resolution: {integrity: sha512-vne1mzQUTR+qsMLeCBL9+/tgnDXRyc2pygLGl/WsgA+EZKIiB5Ehu0CiVTHIIk30zhJ24uGz4M5Ppse37aR0Hg==} + engines: {node: '>=12'} + dev: false + + /isbot@4.4.0: + resolution: {integrity: sha512-8ZvOWUA68kyJO4hHJdWjyreq7TYNWTS9y15IzeqVdKxR9pPr3P/3r9AHcoIv9M0Rllkao5qWz2v1lmcyKIVCzQ==} + engines: {node: '>=18'} + dev: false + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -16092,6 +17733,16 @@ packages: '@types/react-reconciler': 0.28.0 react: 18.3.1 + /jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + /javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + /jest-util@29.7.0: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -16130,7 +17781,6 @@ packages: /jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true - dev: false /joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} @@ -16217,6 +17867,11 @@ packages: engines: {node: '>=4'} hasBin: true + /jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + /json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} dependencies: @@ -16229,6 +17884,17 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + /json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + /json-schema-to-ts@1.6.4: + resolution: {integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==} + dependencies: + '@types/json-schema': 7.0.13 + ts-toolbelt: 6.15.5 + dev: false + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -16282,7 +17948,6 @@ packages: universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 - dev: false /jsx-ast-utils@2.4.1: resolution: {integrity: sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==} @@ -16356,7 +18021,6 @@ packages: /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - dev: false /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} @@ -16392,7 +18056,6 @@ packages: /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} - dev: false /lilconfig@3.1.2: resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} @@ -16401,7 +18064,6 @@ packages: /lines-and-columns@1.1.6: resolution: {integrity: sha512-8ZmlJFVK9iCmtLz19HpSsR8HaAMWBT284VMNednLwlIMDP2hJDCIhUp0IZ2xUcZ+Ob6BM0VvCSJwzASDM45NLQ==} - dev: false /load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} @@ -16446,7 +18108,6 @@ packages: /loader-utils@3.2.0: resolution: {integrity: sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==} engines: {node: '>= 12.13.0'} - dev: false /loadjs@4.2.0: resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==} @@ -16456,6 +18117,13 @@ packages: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} + /local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} + engines: {node: '>=14'} + dependencies: + mlly: 1.5.0 + pkg-types: 1.0.3 + /locate-path@3.0.0: resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} engines: {node: '>=6'} @@ -16486,15 +18154,13 @@ packages: /lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: false /lodash.clamp@4.0.3: resolution: {integrity: sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==} dev: false /lodash.debounce@4.0.8: - resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=} - dev: false + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -16520,6 +18186,13 @@ packages: /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + /log-symbols@5.1.0: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} @@ -16534,7 +18207,6 @@ packages: /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - dev: false /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} @@ -16566,6 +18238,9 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false + /lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -16577,6 +18252,18 @@ packages: dependencies: yallist: 4.0.0 + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + /lucide-react@0.439.0(react@18.3.1): + resolution: {integrity: sha512-PafSWvDTpxdtNEndS2HIHxcNAbd54OaqSYJO90/b63rab2HWYqDbH194j0i82ZFdWOAcf0AHinRykXRRK2PJbw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + dependencies: + react: 18.3.1 + dev: false + /lz-string@1.4.4: resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==} hasBin: true @@ -16633,7 +18320,6 @@ packages: /markdown-extensions@1.1.1: resolution: {integrity: sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==} engines: {node: '>=0.10.0'} - dev: false /markdown-extensions@2.0.0: resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} @@ -16656,7 +18342,6 @@ packages: '@types/mdast': 3.0.10 '@types/unist': 2.0.6 unist-util-visit: 4.1.2 - dev: false /mdast-util-directive@3.0.0: resolution: {integrity: sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==} @@ -16708,7 +18393,6 @@ packages: uvu: 0.5.6 transitivePeerDependencies: - supports-color - dev: false /mdast-util-from-markdown@2.0.1: resolution: {integrity: sha512-aJEUyzZ6TzlsX2s5B4Of7lN7EQtAxvtradMMglCQDyaTFgse6CmtmdJ15ElnVRlCg1vpNyVtbem0PWzlNieZsA==} @@ -16729,6 +18413,13 @@ packages: - supports-color dev: false + /mdast-util-frontmatter@1.0.1: + resolution: {integrity: sha512-JjA2OjxRqAa8wEG8hloD0uTU0kdn8kbtOWpPP94NBkfAlbxn4S8gCGf/9DwFtEeGPXrDcNXdiDjVaRdUFqYokw==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-to-markdown: 1.5.0 + micromark-extension-frontmatter: 1.1.1 + /mdast-util-frontmatter@2.0.1: resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} dependencies: @@ -16877,7 +18568,6 @@ packages: mdast-util-to-markdown: 1.5.0 transitivePeerDependencies: - supports-color - dev: false /mdast-util-mdx-expression@2.0.0: resolution: {integrity: sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==} @@ -16909,7 +18599,6 @@ packages: vfile-message: 3.1.4 transitivePeerDependencies: - supports-color - dev: false /mdast-util-mdx-jsx@3.1.2: resolution: {integrity: sha512-eKMQDeywY2wlHc97k5eD8VC+9ASMjN8ItEZQNGwJ6E0XWKiW/Z0V5/H8pvoXUf+y+Mj0VIgeRRbujBmFn4FTyA==} @@ -16941,7 +18630,6 @@ packages: mdast-util-to-markdown: 1.5.0 transitivePeerDependencies: - supports-color - dev: false /mdast-util-mdx@3.0.0: resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} @@ -16965,7 +18653,6 @@ packages: mdast-util-to-markdown: 1.5.0 transitivePeerDependencies: - supports-color - dev: false /mdast-util-mdxjs-esm@2.0.1: resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} @@ -16985,7 +18672,6 @@ packages: dependencies: '@types/mdast': 3.0.10 unist-util-is: 5.2.0 - dev: false /mdast-util-phrasing@4.1.0: resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} @@ -17005,7 +18691,6 @@ packages: unist-util-generated: 2.0.1 unist-util-position: 4.0.4 unist-util-visit: 4.1.2 - dev: false /mdast-util-to-hast@13.2.0: resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} @@ -17032,7 +18717,6 @@ packages: micromark-util-decode-string: 1.0.2 unist-util-visit: 4.1.2 zwitch: 2.0.4 - dev: false /mdast-util-to-markdown@2.1.0: resolution: {integrity: sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==} @@ -17051,7 +18735,6 @@ packages: resolution: {integrity: sha512-tGvhT94e+cVnQt8JWE9/b3cUQZWS732TJxXHktvP+BYo62PpYD53Ls/6cC60rW21dW+txxiM4zMdc6abASvZKA==} dependencies: '@types/mdast': 3.0.10 - dev: false /mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} @@ -17067,10 +18750,14 @@ packages: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} dev: false + /media-query-parser@2.0.2: + resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} + dependencies: + '@babel/runtime': 7.24.8 + /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} - dev: false /memfs@3.4.3: resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} @@ -17081,7 +18768,6 @@ packages: /merge-descriptors@1.0.1: resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==} - dev: false /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -17104,7 +18790,6 @@ packages: /methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - dev: false /microevent.ts@0.1.1: resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==} @@ -17129,7 +18814,6 @@ packages: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 uvu: 0.5.6 - dev: false /micromark-core-commonmark@2.0.1: resolution: {integrity: sha512-CUQyKr1e///ZODyD1U3xit6zXwy1a8q2a1S1HKtIlmgvurrEpaw/Y9y6KSIbF8P59cn/NjzHyO+Q2fAyYLQrAA==} @@ -17164,6 +18848,14 @@ packages: parse-entities: 4.0.1 dev: false + /micromark-extension-frontmatter@1.1.1: + resolution: {integrity: sha512-m2UH9a7n3W8VAH9JO9y01APpPKmNNNs71P0RbknEmYSaZU5Ghogv38BYO94AI5Xw6OYfxZRdHZZ2nYjs/Z+SZQ==} + dependencies: + fault: 2.0.1 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + micromark-util-types: 1.0.2 + /micromark-extension-frontmatter@2.0.0: resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} dependencies: @@ -17329,7 +19021,6 @@ packages: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 uvu: 0.5.6 - dev: false /micromark-extension-mdx-expression@3.0.0: resolution: {integrity: sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==} @@ -17357,7 +19048,6 @@ packages: micromark-util-types: 1.0.2 uvu: 0.5.6 vfile-message: 3.1.4 - dev: false /micromark-extension-mdx-jsx@3.0.0: resolution: {integrity: sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==} @@ -17378,7 +19068,6 @@ packages: resolution: {integrity: sha512-7MSuj2S7xjOQXAjjkbjBsHkMtb+mDGVW6uI2dBL9snOBCbZmoNgDAeZ0nSn9j3T42UE/g2xVNMn18PJxZvkBEA==} dependencies: micromark-util-types: 1.0.2 - dev: false /micromark-extension-mdx-md@2.0.0: resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} @@ -17398,7 +19087,6 @@ packages: unist-util-position-from-estree: 1.1.2 uvu: 0.5.6 vfile-message: 3.1.4 - dev: false /micromark-extension-mdxjs-esm@3.0.0: resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} @@ -17425,7 +19113,6 @@ packages: micromark-extension-mdxjs-esm: 1.0.5 micromark-util-combine-extensions: 1.0.0 micromark-util-types: 1.0.2 - dev: false /micromark-extension-mdxjs@3.0.0: resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} @@ -17446,7 +19133,6 @@ packages: micromark-util-character: 1.1.0 micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 - dev: false /micromark-factory-destination@2.0.0: resolution: {integrity: sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==} @@ -17463,7 +19149,6 @@ packages: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 uvu: 0.5.6 - dev: false /micromark-factory-label@2.0.0: resolution: {integrity: sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==} @@ -17485,7 +19170,6 @@ packages: unist-util-position-from-estree: 1.1.2 uvu: 0.5.6 vfile-message: 3.1.4 - dev: false /micromark-factory-mdx-expression@2.0.1: resolution: {integrity: sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==} @@ -17505,7 +19189,6 @@ packages: dependencies: micromark-util-character: 1.1.0 micromark-util-types: 1.0.2 - dev: false /micromark-factory-space@2.0.0: resolution: {integrity: sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==} @@ -17522,7 +19205,6 @@ packages: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 uvu: 0.5.6 - dev: false /micromark-factory-title@2.0.0: resolution: {integrity: sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==} @@ -17540,7 +19222,6 @@ packages: micromark-util-character: 1.1.0 micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 - dev: false /micromark-factory-whitespace@2.0.0: resolution: {integrity: sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==} @@ -17556,7 +19237,6 @@ packages: dependencies: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 - dev: false /micromark-util-character@2.1.0: resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} @@ -17569,7 +19249,6 @@ packages: resolution: {integrity: sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g==} dependencies: micromark-util-symbol: 1.0.1 - dev: false /micromark-util-chunked@2.0.0: resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} @@ -17583,7 +19262,6 @@ packages: micromark-util-character: 1.1.0 micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 - dev: false /micromark-util-classify-character@2.0.0: resolution: {integrity: sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==} @@ -17598,7 +19276,6 @@ packages: dependencies: micromark-util-chunked: 1.0.0 micromark-util-types: 1.0.2 - dev: false /micromark-util-combine-extensions@2.0.0: resolution: {integrity: sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==} @@ -17611,7 +19288,6 @@ packages: resolution: {integrity: sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w==} dependencies: micromark-util-symbol: 1.0.1 - dev: false /micromark-util-decode-numeric-character-reference@2.0.1: resolution: {integrity: sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==} @@ -17626,7 +19302,6 @@ packages: micromark-util-character: 1.1.0 micromark-util-decode-numeric-character-reference: 1.0.0 micromark-util-symbol: 1.0.1 - dev: false /micromark-util-decode-string@2.0.0: resolution: {integrity: sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==} @@ -17639,7 +19314,6 @@ packages: /micromark-util-encode@1.0.1: resolution: {integrity: sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA==} - dev: false /micromark-util-encode@2.0.0: resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} @@ -17656,7 +19330,6 @@ packages: micromark-util-types: 1.0.2 uvu: 0.5.6 vfile-message: 3.1.4 - dev: false /micromark-util-events-to-acorn@2.0.2: resolution: {integrity: sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==} @@ -17673,7 +19346,6 @@ packages: /micromark-util-html-tag-name@1.1.0: resolution: {integrity: sha512-BKlClMmYROy9UiV03SwNmckkjn8QHVaWkqoAqzivabvdGcwNGMMMH/5szAnywmsTBUzDsU57/mFi0sp4BQO6dA==} - dev: false /micromark-util-html-tag-name@2.0.0: resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} @@ -17683,7 +19355,6 @@ packages: resolution: {integrity: sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg==} dependencies: micromark-util-symbol: 1.0.1 - dev: false /micromark-util-normalize-identifier@2.0.0: resolution: {integrity: sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==} @@ -17695,7 +19366,6 @@ packages: resolution: {integrity: sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw==} dependencies: micromark-util-types: 1.0.2 - dev: false /micromark-util-resolve-all@2.0.0: resolution: {integrity: sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==} @@ -17709,7 +19379,6 @@ packages: micromark-util-character: 1.1.0 micromark-util-encode: 1.0.1 micromark-util-symbol: 1.0.1 - dev: false /micromark-util-sanitize-uri@2.0.0: resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} @@ -17726,7 +19395,6 @@ packages: micromark-util-symbol: 1.0.1 micromark-util-types: 1.0.2 uvu: 0.5.6 - dev: false /micromark-util-subtokenize@2.0.1: resolution: {integrity: sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==} @@ -17739,7 +19407,6 @@ packages: /micromark-util-symbol@1.0.1: resolution: {integrity: sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ==} - dev: false /micromark-util-symbol@2.0.0: resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} @@ -17747,7 +19414,6 @@ packages: /micromark-util-types@1.0.2: resolution: {integrity: sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w==} - dev: false /micromark-util-types@2.0.0: resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} @@ -17775,7 +19441,6 @@ packages: uvu: 0.5.6 transitivePeerDependencies: - supports-color - dev: false /micromark@4.0.0: resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} @@ -17865,7 +19530,6 @@ packages: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} hasBin: true - dev: false /mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} @@ -17927,24 +19591,50 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + /minimist@1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: false + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: false + + /minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.1.5 + + /minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.1.5 + + /minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + dependencies: + minipass: 3.1.5 /minipass@3.1.5: resolution: {integrity: sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==} engines: {node: '>=8'} dependencies: yallist: 4.0.0 - dev: false /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - dev: false + + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -17952,7 +19642,6 @@ packages: dependencies: minipass: 3.1.5 yallist: 4.0.0 - dev: false /mixin-deep@1.3.2: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} @@ -17964,13 +19653,11 @@ packages: /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - dev: false /mlly@1.5.0: resolution: {integrity: sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==} @@ -17980,10 +19667,28 @@ packages: pkg-types: 1.0.3 ufo: 1.3.2 + /modern-ahocorasick@1.0.1: + resolution: {integrity: sha512-yoe+JbhTClckZ67b2itRtistFKf8yPYelHLc7e5xAwtNAXxM6wJTUx2C7QeVSJFDzKT7bCIFyBVybPMKvmB9AA==} + + /morgan@1.10.0: + resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==} + engines: {node: '>= 0.8.0'} + dependencies: + basic-auth: 2.0.1 + debug: 2.6.9 + depd: 2.0.0 + on-finished: 2.3.0 + on-headers: 1.0.2 + transitivePeerDependencies: + - supports-color + /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - dev: false + + /mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} /mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} @@ -17992,14 +19697,12 @@ packages: /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: false /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: false /multicast-dns@7.2.4: resolution: {integrity: sha512-XkCYOU+rr2Ft3LI6w4ye51M3VK31qJXFIxu0XLw169PtKG0Zx47OrXeVW/GCYOfpC9s1yyyf1S+L8/4LY0J9Zw==} @@ -18019,7 +19722,6 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: false /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} @@ -18064,7 +19766,6 @@ packages: /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - dev: false /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -18196,6 +19897,15 @@ packages: validate-npm-package-license: 3.0.4 dev: false + /normalize-package-data@5.0.0: + resolution: {integrity: sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + hosted-git-info: 6.1.1 + is-core-module: 2.13.1 + semver: 7.5.3 + validate-npm-package-license: 3.0.4 + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -18203,7 +19913,6 @@ packages: /normalize-range@0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - dev: false /normalize-url@6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} @@ -18214,6 +19923,34 @@ packages: engines: {node: '>=14.16'} dev: false + /npm-install-checks@6.3.0: + resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + semver: 7.5.3 + + /npm-normalize-package-bin@3.0.1: + resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + /npm-package-arg@10.1.0: + resolution: {integrity: sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + hosted-git-info: 6.1.1 + proc-log: 3.0.0 + semver: 7.5.3 + validate-npm-package-name: 5.0.1 + + /npm-pick-manifest@8.0.2: + resolution: {integrity: sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + npm-install-checks: 6.3.0 + npm-normalize-package-bin: 3.0.1 + npm-package-arg: 10.1.0 + semver: 7.5.3 + /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -18256,7 +19993,6 @@ packages: /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: false /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -18340,12 +20076,16 @@ packages: engines: {node: '>= 0.8'} dependencies: ee-first: 1.1.1 - dev: false + + /on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 /on-headers@1.0.2: resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} engines: {node: '>= 0.8'} - dev: false /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -18428,6 +20168,20 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 + /ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.7.0 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + /ora@6.1.2: resolution: {integrity: sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -18449,6 +20203,9 @@ packages: url-parse: 1.5.3 dev: false + /outdent@0.8.0: + resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + /p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -18509,7 +20266,6 @@ packages: engines: {node: '>=10'} dependencies: aggregate-error: 3.1.0 - dev: false /p-retry@4.6.1: resolution: {integrity: sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==} @@ -18524,6 +20280,9 @@ packages: engines: {node: '>=6'} dev: false + /package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + /package-json@8.1.1: resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} engines: {node: '>=14.16'} @@ -18534,6 +20293,9 @@ packages: semver: 7.5.3 dev: false + /pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + /param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: @@ -18558,7 +20320,6 @@ packages: is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 - dev: false /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} @@ -18578,6 +20339,10 @@ packages: unist-util-visit-children: 2.0.2 dev: false + /parse-ms@2.1.0: + resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} + engines: {node: '>=6'} + /parse-numeric-range@1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} dev: false @@ -18601,7 +20366,6 @@ packages: /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - dev: false /pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -18615,6 +20379,10 @@ packages: engines: {node: '>=0.10.0'} dev: false + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: false + /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -18649,9 +20417,15 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + /path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} - dev: false /path-to-regexp@1.8.0: resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==} @@ -18677,6 +20451,13 @@ packages: /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + /peek-stream@1.1.3: + resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==} + dependencies: + buffer-from: 1.1.2 + duplexify: 3.7.1 + through2: 2.0.5 + /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -18686,7 +20467,6 @@ packages: '@types/estree': 1.0.5 estree-walker: 3.0.3 is-reference: 3.0.1 - dev: false /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -18698,10 +20478,14 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: false /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} @@ -18711,7 +20495,6 @@ packages: /pirates@4.0.5: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} - dev: false /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -18786,18 +20569,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 - dev: false - - /postcss-calc@9.0.1(postcss@8.4.33): - resolution: {integrity: sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.2.2 - dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.0.13 - postcss-value-parser: 4.2.0 + postcss-selector-parser: 6.1.1 dev: false /postcss-calc@9.0.1(postcss@8.4.39): @@ -18807,7 +20579,7 @@ packages: postcss: ^8.2.2 dependencies: postcss: 8.4.39 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 postcss-value-parser: 4.2.0 dev: false @@ -18851,19 +20623,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-colormin@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - caniuse-api: 3.0.0 - colord: 2.9.3 - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-colormin@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==} engines: {node: ^14 || ^16 || >=18.0} @@ -18877,17 +20636,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-convert-values@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-convert-values@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==} engines: {node: ^14 || ^16 || >=18.0} @@ -18935,7 +20683,7 @@ packages: '@csstools/css-parser-algorithms': 2.1.1(@csstools/css-tokenizer@2.1.1) '@csstools/css-tokenizer': 2.1.1 postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /postcss-dir-pseudo-class@7.0.2(postcss@8.4.31): @@ -18945,16 +20693,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 - dev: false - - /postcss-discard-comments@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 + postcss-selector-parser: 6.1.1 dev: false /postcss-discard-comments@6.0.2(postcss@8.4.39): @@ -18966,14 +20705,13 @@ packages: postcss: 8.4.39 dev: false - /postcss-discard-duplicates@6.0.3(postcss@8.4.33): - resolution: {integrity: sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==} - engines: {node: ^14 || ^16 || >=18.0} + /postcss-discard-duplicates@5.1.0(postcss@8.4.39): + resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} + engines: {node: ^10 || ^12 || >=14.0} peerDependencies: - postcss: ^8.4.31 + postcss: ^8.2.15 dependencies: - postcss: 8.4.33 - dev: false + postcss: 8.4.39 /postcss-discard-duplicates@6.0.3(postcss@8.4.39): resolution: {integrity: sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==} @@ -18984,15 +20722,6 @@ packages: postcss: 8.4.39 dev: false - /postcss-discard-empty@6.0.3(postcss@8.4.33): - resolution: {integrity: sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - dev: false - /postcss-discard-empty@6.0.3(postcss@8.4.39): resolution: {integrity: sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19002,15 +20731,6 @@ packages: postcss: 8.4.39 dev: false - /postcss-discard-overridden@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - dev: false - /postcss-discard-overridden@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19048,7 +20768,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /postcss-focus-within@7.0.2(postcss@8.4.31): @@ -19058,7 +20778,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /postcss-font-variant@5.0.0(postcss@8.4.31): @@ -19088,17 +20808,16 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-import@15.1.0(postcss@8.4.33): + /postcss-import@15.1.0(postcss@8.4.39): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} peerDependencies: postcss: ^8.0.0 dependencies: - postcss: 8.4.33 + postcss: 8.4.39 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.2 - dev: false /postcss-initial@4.0.1(postcss@8.4.31): resolution: {integrity: sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==} @@ -19108,15 +20827,14 @@ packages: postcss: 8.4.31 dev: false - /postcss-js@4.0.1(postcss@8.4.33): + /postcss-js@4.0.1(postcss@8.4.39): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.4.21 dependencies: camelcase-css: 2.0.1 - postcss: 8.4.33 - dev: false + postcss: 8.4.39 /postcss-lab-function@5.2.2(postcss@8.4.31): resolution: {integrity: sha512-O5LrVYzOD3anfPqvSL1HiQ8PpKAav74Gst3pXgZBHSFo6t5sws3dLGTQMnw4hgn1t064SODWAjb9KcC39N820A==} @@ -19131,7 +20849,7 @@ packages: postcss: 8.4.31 dev: false - /postcss-load-config@4.0.1(postcss@8.4.33): + /postcss-load-config@4.0.1(postcss@8.4.39): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} peerDependencies: @@ -19144,9 +20862,8 @@ packages: optional: true dependencies: lilconfig: 2.1.0 - postcss: 8.4.33 + postcss: 8.4.39 yaml: 2.2.2 - dev: false /postcss-loader@7.3.0(postcss@8.4.31)(webpack@5.94.0): resolution: {integrity: sha512-qLAFjvR2BFNz1H930P7mj1iuWJFjGey/nVhimfOAAQ1ZyPpcClAxP8+A55Sl8mBvM+K2a9Pjgdj10KpANWrNfw==} @@ -19163,7 +20880,7 @@ packages: webpack: 5.94.0 dev: false - /postcss-loader@7.3.4(postcss@8.4.33)(typescript@5.3.3)(webpack@5.94.0): + /postcss-loader@7.3.4(postcss@8.4.39)(typescript@5.3.3)(webpack@5.94.0): resolution: {integrity: sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==} engines: {node: '>= 14.15.0'} peerDependencies: @@ -19172,7 +20889,7 @@ packages: dependencies: cosmiconfig: 8.3.6(typescript@5.3.3) jiti: 1.21.6 - postcss: 8.4.33 + postcss: 8.4.39 semver: 7.5.4 webpack: 5.94.0(@swc/core@1.3.80) transitivePeerDependencies: @@ -19200,17 +20917,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-merge-longhand@6.0.5(postcss@8.4.33): - resolution: {integrity: sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - stylehacks: 6.1.1(postcss@8.4.33) - dev: false - /postcss-merge-longhand@6.0.5(postcss@8.4.39): resolution: {integrity: sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==} engines: {node: ^14 || ^16 || >=18.0} @@ -19222,19 +20928,6 @@ packages: stylehacks: 6.1.1(postcss@8.4.39) dev: false - /postcss-merge-rules@6.1.1(postcss@8.4.33): - resolution: {integrity: sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - caniuse-api: 3.0.0 - cssnano-utils: 4.0.2(postcss@8.4.33) - postcss: 8.4.33 - postcss-selector-parser: 6.1.1 - dev: false - /postcss-merge-rules@6.1.1(postcss@8.4.39): resolution: {integrity: sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19248,16 +20941,6 @@ packages: postcss-selector-parser: 6.1.1 dev: false - /postcss-minify-font-values@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-font-values@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==} engines: {node: ^14 || ^16 || >=18.0} @@ -19268,18 +20951,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-minify-gradients@6.0.3(postcss@8.4.33): - resolution: {integrity: sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - colord: 2.9.3 - cssnano-utils: 4.0.2(postcss@8.4.33) - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-gradients@6.0.3(postcss@8.4.39): resolution: {integrity: sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==} engines: {node: ^14 || ^16 || >=18.0} @@ -19292,18 +20963,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-minify-params@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - cssnano-utils: 4.0.2(postcss@8.4.33) - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-params@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==} engines: {node: ^14 || ^16 || >=18.0} @@ -19316,16 +20975,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-minify-selectors@6.0.4(postcss@8.4.33): - resolution: {integrity: sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.1.1 - dev: false - /postcss-minify-selectors@6.0.4(postcss@8.4.39): resolution: {integrity: sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19345,14 +20994,13 @@ packages: postcss: 8.4.33 dev: false - /postcss-modules-extract-imports@3.1.0(postcss@8.4.33): + /postcss-modules-extract-imports@3.1.0(postcss@8.4.39): resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.33 - dev: false + postcss: 8.4.39 /postcss-modules-local-by-default@4.0.0(postcss@8.4.33): resolution: {integrity: sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==} @@ -19366,17 +21014,16 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-modules-local-by-default@4.0.5(postcss@8.4.33): + /postcss-modules-local-by-default@4.0.5(postcss@8.4.39): resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.33) - postcss: 8.4.33 - postcss-selector-parser: 6.0.13 + icss-utils: 5.1.0(postcss@8.4.39) + postcss: 8.4.39 + postcss-selector-parser: 6.1.1 postcss-value-parser: 4.2.0 - dev: false /postcss-modules-scope@3.0.0(postcss@8.4.33): resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==} @@ -19388,15 +21035,14 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /postcss-modules-scope@3.2.0(postcss@8.4.33): + /postcss-modules-scope@3.2.0(postcss@8.4.39): resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.0.13 - dev: false + postcss: 8.4.39 + postcss-selector-parser: 6.1.1 /postcss-modules-values@4.0.0(postcss@8.4.33): resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} @@ -19408,15 +21054,38 @@ packages: postcss: 8.4.33 dev: false - /postcss-nested@6.0.1(postcss@8.4.33): + /postcss-modules-values@4.0.0(postcss@8.4.39): + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + dependencies: + icss-utils: 5.1.0(postcss@8.4.39) + postcss: 8.4.39 + + /postcss-modules@6.0.0(postcss@8.4.39): + resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==} + peerDependencies: + postcss: ^8.0.0 + dependencies: + generic-names: 4.0.0 + icss-utils: 5.1.0(postcss@8.4.39) + lodash.camelcase: 4.3.0 + postcss: 8.4.39 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.39) + postcss-modules-local-by-default: 4.0.5(postcss@8.4.39) + postcss-modules-scope: 3.2.0(postcss@8.4.39) + postcss-modules-values: 4.0.0(postcss@8.4.39) + string-hash: 1.1.3 + + /postcss-nested@6.0.1(postcss@8.4.39): resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.0.13 - dev: false + postcss: 8.4.39 + postcss-selector-parser: 6.1.1 /postcss-nesting@11.2.2(postcss@8.4.31): resolution: {integrity: sha512-aOTiUniAB1bcPE6GGiynWRa6PZFPhOTAm5q3q5cem6QeSijIHHkWr6gs65ukCZMXeak8yXeZVbBJET3VM+HlhA==} @@ -19424,18 +21093,9 @@ packages: peerDependencies: postcss: ^8.4 dependencies: - '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.13) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.1) postcss: 8.4.31 - postcss-selector-parser: 6.0.13 - dev: false - - /postcss-normalize-charset@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 + postcss-selector-parser: 6.1.1 dev: false /postcss-normalize-charset@6.0.2(postcss@8.4.39): @@ -19447,16 +21107,6 @@ packages: postcss: 8.4.39 dev: false - /postcss-normalize-display-values@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-display-values@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==} engines: {node: ^14 || ^16 || >=18.0} @@ -19467,16 +21117,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-positions@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-positions@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==} engines: {node: ^14 || ^16 || >=18.0} @@ -19487,16 +21127,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-repeat-style@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-repeat-style@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19507,16 +21137,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-string@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-string@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19527,16 +21147,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-timing-functions@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-timing-functions@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==} engines: {node: ^14 || ^16 || >=18.0} @@ -19547,17 +21157,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-unicode@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-unicode@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==} engines: {node: ^14 || ^16 || >=18.0} @@ -19569,16 +21168,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-url@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-url@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==} engines: {node: ^14 || ^16 || >=18.0} @@ -19589,16 +21178,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-whitespace@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-whitespace@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==} engines: {node: ^14 || ^16 || >=18.0} @@ -19618,17 +21197,6 @@ packages: postcss: 8.4.31 dev: false - /postcss-ordered-values@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - cssnano-utils: 4.0.2(postcss@8.4.33) - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-ordered-values@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==} engines: {node: ^14 || ^16 || >=18.0} @@ -19696,7 +21264,7 @@ packages: '@csstools/postcss-text-decoration-shorthand': 2.2.4(postcss@8.4.31) '@csstools/postcss-trigonometric-functions': 2.1.1(postcss@8.4.31) '@csstools/postcss-unset-value': 2.0.1(postcss@8.4.31) - autoprefixer: 10.4.14(postcss@8.4.31) + autoprefixer: 10.4.19(postcss@8.4.31) browserslist: 4.21.5 css-blank-pseudo: 5.0.2(postcss@8.4.31) css-has-pseudo: 5.0.2(postcss@8.4.31) @@ -19739,7 +21307,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /postcss-reduce-idents@6.0.3(postcss@8.4.39): @@ -19752,17 +21320,6 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-reduce-initial@6.1.0(postcss@8.4.33): - resolution: {integrity: sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - caniuse-api: 3.0.0 - postcss: 8.4.33 - dev: false - /postcss-reduce-initial@6.1.0(postcss@8.4.39): resolution: {integrity: sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==} engines: {node: ^14 || ^16 || >=18.0} @@ -19774,16 +21331,6 @@ packages: postcss: 8.4.39 dev: false - /postcss-reduce-transforms@6.0.2(postcss@8.4.33): - resolution: {integrity: sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - dev: false - /postcss-reduce-transforms@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==} engines: {node: ^14 || ^16 || >=18.0} @@ -19809,7 +21356,7 @@ packages: postcss: ^8.4 dependencies: postcss: 8.4.31 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.1.1 dev: false /postcss-selector-parser@6.0.13: @@ -19826,7 +21373,6 @@ packages: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: false /postcss-sort-media-queries@5.2.0(postcss@8.4.39): resolution: {integrity: sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==} @@ -19838,17 +21384,6 @@ packages: sort-css-media-queries: 2.2.0 dev: false - /postcss-svgo@6.0.3(postcss@8.4.33): - resolution: {integrity: sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==} - engines: {node: ^14 || ^16 || >= 18} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-value-parser: 4.2.0 - svgo: 3.3.2 - dev: false - /postcss-svgo@6.0.3(postcss@8.4.39): resolution: {integrity: sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==} engines: {node: ^14 || ^16 || >= 18} @@ -19860,16 +21395,6 @@ packages: svgo: 3.3.2 dev: false - /postcss-unique-selectors@6.0.4(postcss@8.4.33): - resolution: {integrity: sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - postcss: 8.4.33 - postcss-selector-parser: 6.1.1 - dev: false - /postcss-unique-selectors@6.0.4(postcss@8.4.39): resolution: {integrity: sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==} engines: {node: ^14 || ^16 || >=18.0} @@ -19882,7 +21407,6 @@ packages: /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: false /postcss-zindex@6.0.2(postcss@8.4.39): resolution: {integrity: sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==} @@ -19918,6 +21442,14 @@ packages: picocolors: 1.0.1 source-map-js: 1.2.0 + /postcss@8.4.45: + resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + /potpack@1.0.1: resolution: {integrity: sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==} dev: false @@ -19986,7 +21518,6 @@ packages: resolution: {integrity: sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==} engines: {node: '>=10.13.0'} hasBin: true - dev: false /prettier@3.2.5: resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} @@ -20018,6 +21549,12 @@ packages: ansi-styles: 5.2.0 react-is: 17.0.2 + /pretty-ms@7.0.1: + resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} + engines: {node: '>=10'} + dependencies: + parse-ms: 2.1.0 + /pretty-time@1.1.0: resolution: {integrity: sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==} engines: {node: '>=4'} @@ -20043,15 +21580,33 @@ packages: engines: {node: '>=6'} dev: false + /proc-log@3.0.0: + resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: false /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} dev: false + /promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + /promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + /prompts@2.4.0: resolution: {integrity: sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==} engines: {node: '>= 6'} @@ -20077,7 +21632,6 @@ packages: /property-information@6.2.0: resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} - dev: false /proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -20115,17 +21669,29 @@ packages: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - dev: false /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + /pump@2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: end-of-stream: 1.4.4 once: 1.4.0 + /pumpify@1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + dependencies: + duplexify: 3.7.1 + inherits: 2.0.4 + pump: 2.0.1 + /pumpify@2.0.1: resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==} dependencies: @@ -20158,6 +21724,12 @@ packages: pngjs: 7.0.0 dev: true + /qs@6.11.0: + resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.6 + /qs@6.9.7: resolution: {integrity: sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==} engines: {node: '>=0.6'} @@ -20196,7 +21768,6 @@ packages: /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - dev: false /rangetouch@2.0.1: resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==} @@ -20212,6 +21783,15 @@ packages: unpipe: 1.0.0 dev: false + /raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + /rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -20422,13 +22002,47 @@ packages: /react-refresh@0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} - dev: true /react-refresh@0.9.0: resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==} engines: {node: '>=0.10.0'} dev: false + /react-remove-scroll-bar@2.3.6(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + react-style-singleton: 2.2.1(@types/react@18.3.1)(react@18.3.1) + tslib: 2.6.2 + dev: false + + /react-remove-scroll@2.5.7(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.1)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.1)(react@18.3.1) + tslib: 2.6.2 + use-callback-ref: 1.3.2(@types/react@18.3.1)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.1)(react@18.3.1) + dev: false + /react-router-config@5.1.1(react-router@5.3.4)(react@18.3.1): resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==} peerDependencies: @@ -20455,6 +22069,18 @@ packages: tiny-warning: 1.0.3 dev: false + /react-router-dom@6.26.1(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + dependencies: + '@remix-run/router': 1.19.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.26.1(react@18.3.1) + /react-router@5.3.4(react@18.3.1): resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: @@ -20472,6 +22098,32 @@ packages: tiny-warning: 1.0.3 dev: false + /react-router@6.26.1(react@18.3.1): + resolution: {integrity: sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + dependencies: + '@remix-run/router': 1.19.1 + react: 18.3.1 + + /react-style-singleton@2.2.1(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.3.1 + tslib: 2.6.2 + dev: false + /react-use-measure@2.1.1(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==} peerDependencies: @@ -20506,7 +22158,6 @@ packages: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: false /read-pkg-up@7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -20537,7 +22188,6 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: false /readable-stream@3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} @@ -20618,7 +22268,6 @@ packages: /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: false /regenerator-transform@0.14.5: resolution: {integrity: sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==} @@ -20790,6 +22439,14 @@ packages: unified: 11.0.5 dev: false + /remark-frontmatter@4.0.1: + resolution: {integrity: sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-frontmatter: 1.0.1 + micromark-extension-frontmatter: 1.1.1 + unified: 10.1.2 + /remark-frontmatter@5.0.0: resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} dependencies: @@ -20825,6 +22482,15 @@ packages: - supports-color dev: false + /remark-mdx-frontmatter@1.1.1: + resolution: {integrity: sha512-7teX9DW4tI2WZkXS4DBxneYSY7NHiXl4AKdWDO9LXVweULlCT8OPWsOjLEnMIXViN1j+QcY8mfbq3k0EK6x3uA==} + engines: {node: '>=12.2.0'} + dependencies: + estree-util-is-identifier-name: 1.1.0 + estree-util-value-to-estree: 1.3.0 + js-yaml: 4.1.0 + toml: 3.0.0 + /remark-mdx@2.3.0: resolution: {integrity: sha512-g53hMkpM0I98MU266IzDFMrTD980gNF3BJnkyFcmN+dD873mQeD5rdMO3Y2X+x8umQfbSE0PcoEDl7ledSA+2g==} dependencies: @@ -20832,7 +22498,6 @@ packages: micromark-extension-mdxjs: 1.0.1 transitivePeerDependencies: - supports-color - dev: false /remark-mdx@3.0.1: resolution: {integrity: sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==} @@ -20851,7 +22516,6 @@ packages: unified: 10.1.2 transitivePeerDependencies: - supports-color - dev: false /remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} @@ -20871,7 +22535,6 @@ packages: '@types/mdast': 3.0.10 mdast-util-to-hast: 12.3.0 unified: 10.1.2 - dev: false /remark-rehype@11.1.0: resolution: {integrity: sha512-z3tJrAs2kIs1AqIIy6pzHmAHlF1hWQ+OdY4/hv+Wxe35EhyLKcajL33iUEn3ScxtFox9nUvRufR/Zre8Q08H/g==} @@ -20951,7 +22614,6 @@ packages: /require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} - dev: false /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -20972,6 +22634,10 @@ packages: deprecated: https://github.com/lydell/resolve-url#deprecated dev: false + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + /resolve@1.22.2: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true @@ -21000,6 +22666,13 @@ packages: lowercase-keys: 3.0.0 dev: false + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + /restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -21070,6 +22743,10 @@ packages: - supports-color dev: false + /retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -21101,6 +22778,31 @@ packages: optionalDependencies: fsevents: 2.3.3 + /rollup@4.21.2: + resolution: {integrity: sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.21.2 + '@rollup/rollup-android-arm64': 4.21.2 + '@rollup/rollup-darwin-arm64': 4.21.2 + '@rollup/rollup-darwin-x64': 4.21.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.2 + '@rollup/rollup-linux-arm-musleabihf': 4.21.2 + '@rollup/rollup-linux-arm64-gnu': 4.21.2 + '@rollup/rollup-linux-arm64-musl': 4.21.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.2 + '@rollup/rollup-linux-riscv64-gnu': 4.21.2 + '@rollup/rollup-linux-s390x-gnu': 4.21.2 + '@rollup/rollup-linux-x64-gnu': 4.21.2 + '@rollup/rollup-linux-x64-musl': 4.21.2 + '@rollup/rollup-win32-arm64-msvc': 4.21.2 + '@rollup/rollup-win32-ia32-msvc': 4.21.2 + '@rollup/rollup-win32-x64-msvc': 4.21.2 + fsevents: 2.3.3 + /rtl-detect@1.0.4: resolution: {integrity: sha512-EBR4I2VDSSYr7PkBmFy04uhycIpDKp+21p/jARYXlCSjQksTBQcJ0HFUPOO79EPPH5JS6VAhiIQbycf0O3JAxQ==} dev: false @@ -21112,7 +22814,7 @@ packages: dependencies: escalade: 3.1.2 picocolors: 1.0.1 - postcss: 8.4.33 + postcss: 8.4.39 strip-json-comments: 3.1.1 dev: false @@ -21130,7 +22832,6 @@ packages: engines: {node: '>=6'} dependencies: mri: 1.2.0 - dev: false /safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} @@ -21143,7 +22844,6 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: false /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -21375,6 +23075,26 @@ packages: - supports-color dev: false + /send@0.18.0: + resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + /serialize-javascript@6.0.1: resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} dependencies: @@ -21420,10 +23140,24 @@ packages: - supports-color dev: false + /serve-static@1.15.0: + resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.18.0 + transitivePeerDependencies: + - supports-color + /server-destroy@1.0.1: resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==} dev: false + /set-cookie-parser@2.7.0: + resolution: {integrity: sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==} + /set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -21460,7 +23194,6 @@ packages: /setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: false /shallow-clone@3.0.1: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} @@ -21567,7 +23300,10 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: false + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} /simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -21739,7 +23475,6 @@ packages: /source-map@0.7.3: resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} engines: {node: '>= 8'} - dev: false /source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} @@ -21755,29 +23490,24 @@ packages: /space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - dev: false /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 spdx-license-ids: 3.0.13 - dev: false /spdx-exceptions@2.3.0: resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} - dev: false /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 spdx-license-ids: 3.0.13 - dev: false /spdx-license-ids@3.0.13: resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} - dev: false /spdy-transport@3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} @@ -21821,6 +23551,12 @@ packages: engines: {node: '>=12'} dev: false + /ssri@10.0.6: + resolution: {integrity: sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + minipass: 7.1.2 + /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -21845,6 +23581,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + /std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} @@ -21867,7 +23607,9 @@ packages: /stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - dev: false + + /stream-slice@0.1.2: + resolution: {integrity: sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==} /streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} @@ -21881,6 +23623,9 @@ packages: queue-tick: 1.0.1 dev: true + /string-hash@1.1.3: + resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -21888,7 +23633,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: false /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -21897,7 +23641,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.0.1 - dev: false /string.prototype.codepointat@0.2.1: resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} @@ -21948,7 +23691,6 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: false /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -21960,7 +23702,6 @@ packages: dependencies: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 - dev: false /stringify-object@3.3.0: resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} @@ -21989,7 +23730,6 @@ packages: engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: false /strip-bom-string@1.0.0: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} @@ -21999,7 +23739,6 @@ packages: /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: false /strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} @@ -22051,7 +23790,6 @@ packages: resolution: {integrity: sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==} dependencies: inline-style-parser: 0.1.1 - dev: false /style-to-object@1.0.6: resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==} @@ -22100,17 +23838,6 @@ packages: react: 18.3.1 dev: false - /stylehacks@6.1.1(postcss@8.4.33): - resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} - engines: {node: ^14 || ^16 || >=18.0} - peerDependencies: - postcss: ^8.4.31 - dependencies: - browserslist: 4.23.2 - postcss: 8.4.33 - postcss-selector-parser: 6.1.1 - dev: false - /stylehacks@6.1.1(postcss@8.4.39): resolution: {integrity: sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==} engines: {node: ^14 || ^16 || >=18.0} @@ -22127,14 +23854,13 @@ packages: engines: {node: '>=8'} hasBin: true dependencies: - '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 glob: 7.1.6 lines-and-columns: 1.1.6 mz: 2.7.0 pirates: 4.0.5 ts-interface-checker: 0.1.13 - dev: false /suf-log@2.5.3: resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==} @@ -22223,6 +23949,18 @@ packages: tslib: 2.6.2 dev: false + /tailwind-merge@2.5.2: + resolution: {integrity: sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==} + dev: false + + /tailwindcss-animate@1.0.7(tailwindcss@3.4.10): + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + tailwindcss: 3.4.10 + dev: false + /tailwindcss@3.3.2: resolution: {integrity: sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==} engines: {node: '>=14.0.0'} @@ -22242,11 +23980,11 @@ packages: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.0 - postcss: 8.4.33 - postcss-import: 15.1.0(postcss@8.4.33) - postcss-js: 4.0.1(postcss@8.4.33) - postcss-load-config: 4.0.1(postcss@8.4.33) - postcss-nested: 6.0.1(postcss@8.4.33) + postcss: 8.4.39 + postcss-import: 15.1.0(postcss@8.4.39) + postcss-js: 4.0.1(postcss@8.4.39) + postcss-load-config: 4.0.1(postcss@8.4.39) + postcss-nested: 6.0.1(postcss@8.4.39) postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 resolve: 1.22.2 @@ -22255,6 +23993,36 @@ packages: - ts-node dev: false + /tailwindcss@3.4.10: + resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.5.3 + 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.6 + lilconfig: 2.1.0 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.39 + postcss-import: 15.1.0(postcss@8.4.39) + postcss-js: 4.0.1(postcss@8.4.39) + postcss-load-config: 4.0.1(postcss@8.4.39) + postcss-nested: 6.0.1(postcss@8.4.39) + postcss-selector-parser: 6.1.1 + resolve: 1.22.2 + sucrase: 3.32.0 + transitivePeerDependencies: + - ts-node + /tapable@1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} engines: {node: '>=6'} @@ -22271,7 +24039,6 @@ packages: mkdirp-classic: 0.5.3 pump: 3.0.0 tar-stream: 2.2.0 - dev: true /tar-fs@3.0.4: resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} @@ -22290,7 +24057,6 @@ packages: fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.0 - dev: true /tar-stream@3.1.6: resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} @@ -22310,7 +24076,6 @@ packages: minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 - dev: false /teeny-request@8.0.3: resolution: {integrity: sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==} @@ -22454,13 +24219,11 @@ packages: engines: {node: '>=0.8'} dependencies: thenify: 3.3.1 - dev: false /thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} dependencies: any-promise: 1.3.0 - dev: false /three-mesh-bvh@0.6.8(three@0.158.0): resolution: {integrity: sha512-EGebF9DZx1S8+7OZYNNTT80GXJZVf+UYXD/HyTg/e2kR/ApofIFfUS4ZzIHNnUVIadpnLSzM4n96wX+l7GMbnQ==} @@ -22487,6 +24250,12 @@ packages: /three@0.158.0: resolution: {integrity: sha512-TALj4EOpdDPF1henk2Q+s17K61uEAAWQ7TJB68nr7FKxqwyDr3msOt5IWdbGm4TaWKjrtWS8DJJWe9JnvsWOhQ==} + /through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + /thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} dev: false @@ -22567,7 +24336,9 @@ packages: /toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - dev: false + + /toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} @@ -22601,7 +24372,6 @@ packages: /trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - dev: false /troika-three-text@0.47.2(three@0.158.0): resolution: {integrity: sha512-qylT0F+U7xGs+/PEf3ujBdJMYWbn0Qci0kLqI5BJG2kW1wdg4T1XSxneypnF05DxFqJhEzuaOR9S2SjiyknMng==} @@ -22629,7 +24399,6 @@ packages: /trough@2.1.0: resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} - dev: false /ts-api-utils@1.0.3(typescript@5.3.3): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} @@ -22641,6 +24410,16 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + /ts-morph@12.0.0: + resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==} + dependencies: + '@ts-morph/common': 0.11.1 + code-block-writer: 10.1.1 + dev: false + + /ts-toolbelt@6.15.5: + resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==} dev: false /ts-unused-exports@7.0.3(typescript@5.3.3): @@ -22654,6 +24433,19 @@ packages: typescript: 5.3.3 dev: false + /tsconfck@3.1.3(typescript@5.3.3): + resolution: {integrity: sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.3.3 + dev: true + /tsconfig-paths@3.11.0: resolution: {integrity: sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==} dependencies: @@ -22663,6 +24455,14 @@ packages: strip-bom: 3.0.0 dev: false + /tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + dependencies: + json5: 2.2.3 + minimist: 1.2.6 + strip-bom: 3.0.0 + /tsconfig-resolver@3.0.1: resolution: {integrity: sha512-ZHqlstlQF449v8glscGRXzL6l2dZvASPCdXJRWG4gHEZlUVx2Jtmr+a2zeVG4LCsKhDXKRj5R3h0C/98UcVAQg==} dependencies: @@ -22740,6 +24540,9 @@ packages: dev: false optional: true + /turbo-stream@2.3.0: + resolution: {integrity: sha512-PhEr9mdexoVv+rJkQ3c8TjrN3DUghX37GNJkSMksoPR4KrXIPnM2MnqRt07sViIqX9IdlhrgtTSyjoVOASq6cg==} + /turbo-windows-64@1.13.3: resolution: {integrity: sha512-Nudr4bRChfJzBPzEmpVV85VwUYRCGKecwkBFpbp2a4NtrJ3+UP1VZES653ckqCu2FRyRuS0n03v9euMbAvzH+Q==} cpu: [x64] @@ -22818,7 +24621,6 @@ packages: dependencies: media-typer: 0.3.0 mime-types: 2.1.34 - dev: false /type@1.2.0: resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==} @@ -22913,6 +24715,10 @@ packages: busboy: 1.6.0 dev: false + /undici@6.19.8: + resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==} + engines: {node: '>=18.17'} + /unherit@3.0.1: resolution: {integrity: sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==} dev: false @@ -22960,7 +24766,6 @@ packages: is-plain-obj: 4.1.0 trough: 2.1.0 vfile: 5.3.7 - dev: false /unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -22984,6 +24789,18 @@ packages: set-value: 2.0.1 dev: false + /unique-filename@3.0.0: + resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + unique-slug: 4.0.0 + + /unique-slug@4.0.0: + resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + /unique-string@3.0.0: resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} engines: {node: '>=12'} @@ -22993,7 +24810,6 @@ packages: /unist-util-generated@2.0.1: resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==} - dev: false /unist-util-is@4.1.0: resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} @@ -23001,7 +24817,6 @@ packages: /unist-util-is@5.2.0: resolution: {integrity: sha512-Glt17jWwZeyqrFqOK0pF1Ded5U3yzJnFr8CG1GMjCWTp9zDo2p+cmD6pWbZU8AgM5WU3IzRv6+rBwhzsGh6hBQ==} - dev: false /unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} @@ -23020,7 +24835,6 @@ packages: resolution: {integrity: sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww==} dependencies: '@types/unist': 2.0.6 - dev: false /unist-util-position-from-estree@2.0.0: resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} @@ -23032,7 +24846,6 @@ packages: resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==} dependencies: '@types/unist': 2.0.6 - dev: false /unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} @@ -23045,7 +24858,6 @@ packages: dependencies: '@types/unist': 2.0.6 unist-util-visit: 4.1.2 - dev: false /unist-util-remove-position@5.0.0: resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} @@ -23058,7 +24870,6 @@ packages: resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} dependencies: '@types/unist': 2.0.6 - dev: false /unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} @@ -23084,7 +24895,6 @@ packages: dependencies: '@types/unist': 2.0.6 unist-util-is: 5.2.0 - dev: false /unist-util-visit-parents@6.0.1: resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} @@ -23107,7 +24917,6 @@ packages: '@types/unist': 2.0.6 unist-util-is: 5.2.0 unist-util-visit-parents: 5.1.3 - dev: false /unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} @@ -23124,12 +24933,10 @@ packages: /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - dev: false /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - dev: false /unset-value@1.0.0: resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} @@ -23240,6 +25047,37 @@ packages: react: 18.3.1 dev: false + /use-callback-ref@1.3.2(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + tslib: 2.6.2 + dev: false + + /use-sidecar@1.1.2(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.6.2 + dev: false + /use@3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} engines: {node: '>=0.10.0'} @@ -23256,7 +25094,6 @@ packages: is-generator-function: 1.0.10 is-typed-array: 1.1.13 which-typed-array: 1.1.15 - dev: false /utila@0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} @@ -23270,7 +25107,6 @@ packages: /utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - dev: false /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} @@ -23291,14 +25127,16 @@ packages: diff: 5.1.0 kleur: 4.1.5 sade: 1.8.1 - dev: false /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - dev: false + + /validate-npm-package-name@5.0.1: + resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} /value-equal@1.0.1: resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==} @@ -23307,7 +25145,6 @@ packages: /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - dev: false /vfile-location@4.1.0: resolution: {integrity: sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==} @@ -23328,7 +25165,6 @@ packages: dependencies: '@types/unist': 2.0.6 unist-util-stringify-position: 3.0.3 - dev: false /vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} @@ -23344,7 +25180,6 @@ packages: is-buffer: 2.0.5 unist-util-stringify-position: 3.0.3 vfile-message: 3.1.4 - dev: false /vfile@6.0.2: resolution: {integrity: sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==} @@ -23375,6 +25210,44 @@ packages: - supports-color - terser + /vite-node@1.6.0: + resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.6(supports-color@5.5.0) + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.4.3 + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + /vite-tsconfig-paths@4.3.2(typescript@5.3.3)(vite@5.4.3): + resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + debug: 4.3.6(supports-color@5.5.0) + globrex: 0.1.2 + tsconfck: 3.1.3(typescript@5.3.3) + vite: 5.4.3 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /vite@3.2.10: resolution: {integrity: sha512-Dx3olBo/ODNiMVk/cA5Yft9Ws+snLOXrhLtrI3F4XLt4syz2Yg8fayZMWScPKoz12v5BUv7VEmQHnsfpY80fYw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -23437,7 +25310,7 @@ packages: optional: true dependencies: esbuild: 0.18.20 - postcss: 8.4.33 + postcss: 8.4.39 rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 @@ -23479,6 +25352,43 @@ packages: optionalDependencies: fsevents: 2.3.3 + /vite@5.4.3: + resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.21.5 + postcss: 8.4.45 + rollup: 4.21.2 + optionalDependencies: + fsevents: 2.3.3 + /vitefu@0.2.4(vite@4.5.2): resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==} peerDependencies: @@ -23715,7 +25625,13 @@ packages: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.3 - dev: false + + /web-encoding@1.1.5: + resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} + dependencies: + util: 0.12.5 + optionalDependencies: + '@zxing/text-encoding': 0.9.0 /web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -23724,7 +25640,6 @@ packages: /web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} - dev: false /web-streams-polyfill@4.0.0-beta.3: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} @@ -23765,7 +25680,7 @@ packages: gzip-size: 6.0.0 html-escaper: 2.0.2 opener: 1.5.2 - picocolors: 1.0.0 + picocolors: 1.0.1 sirv: 2.0.4 ws: 7.5.5 transitivePeerDependencies: @@ -24102,6 +26017,13 @@ packages: dependencies: isexe: 2.0.0 + /which@3.0.1: + resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + isexe: 2.0.0 + /why-is-node-running@2.2.2: resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} engines: {node: '>=8'} @@ -24134,7 +26056,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: false /wrap-ansi@8.0.1: resolution: {integrity: sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==} @@ -24152,7 +26073,6 @@ packages: ansi-styles: 6.1.0 string-width: 5.1.2 strip-ansi: 7.0.1 - dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -24177,7 +26097,6 @@ packages: optional: true utf-8-validate: optional: true - dev: false /ws@8.17.1: resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} @@ -24210,6 +26129,10 @@ packages: /xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -24229,7 +26152,6 @@ packages: /yaml@2.2.2: resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==} engines: {node: '>= 14'} - dev: false /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} @@ -24293,7 +26215,6 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - dev: false '@www.remotion.pro/pkg/cube-transition/1.0.1/docs(@remotion/transitions@packages+transitions)(react@18.3.1)(remotion@packages+core)': resolution: {tarball: https://www.remotion.pro/pkg/cube-transition/1.0.1/docs} diff --git a/tsconfig.json b/tsconfig.json index 0b20036ad3e..f224fe76ac5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -153,6 +153,9 @@ { "path": "./packages/webcodecs" }, + { + "path": "./packages/convert" + }, { "path": "./packages/zod-types" } diff --git a/turbo.json b/turbo.json index b2a485414ea..04eb2de7a87 100644 --- a/turbo.json +++ b/turbo.json @@ -76,6 +76,20 @@ "@remotion/example#test", "@remotion/example#build" ] + }, + "@remotion/media-parser#build": { + "dependsOn": ["//#ts-build"], + "outputs": ["dist/esm/**"] + }, + "@remotion/webcodecs#build": { + "dependsOn": ["^@remotion/media-parser#build"], + "outputs": ["dist/esm/**"] + }, + "@remotion/convert#build-page": { + "dependsOn": ["^@remotion/webcodecs#build"] + }, + "convert": { + "dependsOn": ["^@remotion/convert#build-page"] } } }