Bläddra i källkod

Message rendering (#6868)

Co-authored-by: luowei <glpat-EjySCyNjWiLqAED-YmwM>
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
tags/0.8.0
Charlie.Wei 1 år sedan
förälder
incheckning
3230f4a0ec
Inget konto är kopplat till bidragsgivarens mejladress

+ 119
- 0
web/app/components/base/audio-gallery/AudioPlayer.module.css Visa fil

.audioPlayer {
display: flex;
flex-direction: row;
align-items: center;
background-color: #ffffff;
border-radius: 10px;
padding: 8px;
min-width: 240px;
max-width: 420px;
max-height: 40px;
backdrop-filter: blur(5px);
border: 1px solid rgba(16, 24, 40, 0.08);
box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05);
gap: 8px;
}

.playButton {
display: inline-flex;
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #296DFF;
color: white;
border: none;
cursor: pointer;
align-items: center;
justify-content: center;
transition: background-color 0.1s;
flex-shrink: 0;
}

.playButton:hover {
background-color: #3367d6;
}

.playButton:disabled {
background-color: #bdbdbf;
}

.audioControls {
flex-grow: 1;
}

.progressBarContainer {
height: 32px;
display: flex;
align-items: center;
justify-content: center;
}

.waveform {
position: relative;
display: flex;
cursor: pointer;
height: 24px;
width: 100%;
flex-grow: 1;
align-items: center;
justify-content: center;
}

.progressBar {
position: absolute;
top: 0;
left: 0;
opacity: 0.5;
border-radius: 2px;
flex: none;
order: 55;
flex-grow: 0;
height: 100%;
background-color: rgba(66, 133, 244, 0.3);
pointer-events: none;
}

.timeDisplay {
/* position: absolute; */
color: #296DFF;
border-radius: 2px;
order: 0;
height: 100%;
width: 50px;
display: inline-flex;
align-items: center;
justify-content: center;
}

/* .currentTime {
position: absolute;
bottom: calc(100% + 5px);
transform: translateX(-50%);
background-color: rgba(255,255,255,.8);
padding: 2px 4px;
border-radius:10px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.08);
} */

.duration {
background-color: rgba(255, 255, 255, 0.8);
padding: 2px 4px;
border-radius: 10px;
}

.source_unavailable {
border: none;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
position: absolute;
color: #bdbdbf;
}

.playButton svg path,
.playButton svg rect{
fill:currentColor;
}

+ 320
- 0
web/app/components/base/audio-gallery/AudioPlayer.tsx Visa fil

import React, { useCallback, useEffect, useRef, useState } from 'react'
import { t } from 'i18next'
import styles from './AudioPlayer.module.css'
import Toast from '@/app/components/base/toast'

type AudioPlayerProps = {
src: string
}

const AudioPlayer: React.FC<AudioPlayerProps> = ({ src }) => {
const [isPlaying, setIsPlaying] = useState(false)
const [currentTime, setCurrentTime] = useState(0)
const [duration, setDuration] = useState(0)
const [waveformData, setWaveformData] = useState<number[]>([])
const [bufferedTime, setBufferedTime] = useState(0)
const audioRef = useRef<HTMLAudioElement>(null)
const canvasRef = useRef<HTMLCanvasElement>(null)
const [hasStartedPlaying, setHasStartedPlaying] = useState(false)
const [hoverTime, setHoverTime] = useState(0)
const [isAudioAvailable, setIsAudioAvailable] = useState(true)

useEffect(() => {
const audio = audioRef.current
if (!audio)
return

const handleError = () => {
setIsAudioAvailable(false)
}

const setAudioData = () => {
setDuration(audio.duration)
}

const setAudioTime = () => {
setCurrentTime(audio.currentTime)
}

const handleProgress = () => {
if (audio.buffered.length > 0)
setBufferedTime(audio.buffered.end(audio.buffered.length - 1))
}

const handleEnded = () => {
setIsPlaying(false)
}

audio.addEventListener('loadedmetadata', setAudioData)
audio.addEventListener('timeupdate', setAudioTime)
audio.addEventListener('progress', handleProgress)
audio.addEventListener('ended', handleEnded)
audio.addEventListener('error', handleError)

// Preload audio metadata
audio.load()

// Delayed generation of waveform data
// eslint-disable-next-line @typescript-eslint/no-use-before-define
const timer = setTimeout(() => generateWaveformData(src), 1000)

return () => {
audio.removeEventListener('loadedmetadata', setAudioData)
audio.removeEventListener('timeupdate', setAudioTime)
audio.removeEventListener('progress', handleProgress)
audio.removeEventListener('ended', handleEnded)
audio.removeEventListener('error', handleError)
clearTimeout(timer)
}
}, [src])

const generateWaveformData = async (audioSrc: string) => {
if (!window.AudioContext && !(window as any).webkitAudioContext) {
setIsAudioAvailable(false)
Toast.notify({
type: 'error',
message: 'Web Audio API is not supported in this browser',
})
return null
}

const url = new URL(src)
const isHttp = url.protocol === 'http:' || url.protocol === 'https:'
if (!isHttp) {
setIsAudioAvailable(false)
return null
}

const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
const samples = 70

try {
const response = await fetch(audioSrc, { mode: 'cors' })
if (!response || !response.ok) {
setIsAudioAvailable(false)
return null
}

const arrayBuffer = await response.arrayBuffer()
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
const channelData = audioBuffer.getChannelData(0)
const blockSize = Math.floor(channelData.length / samples)
const waveformData: number[] = []

for (let i = 0; i < samples; i++) {
let sum = 0
for (let j = 0; j < blockSize; j++)
sum += Math.abs(channelData[i * blockSize + j])

// Apply nonlinear scaling to enhance small amplitudes
waveformData.push((sum / blockSize) * 5)
}

// Normalized waveform data
const maxAmplitude = Math.max(...waveformData)
const normalizedWaveform = waveformData.map(amp => amp / maxAmplitude)

setWaveformData(normalizedWaveform)
setIsAudioAvailable(true)
}
catch (error) {
const waveform: number[] = []
let prevValue = Math.random()

for (let i = 0; i < samples; i++) {
const targetValue = Math.random()
const interpolatedValue = prevValue + (targetValue - prevValue) * 0.3
waveform.push(interpolatedValue)
prevValue = interpolatedValue
}

const maxAmplitude = Math.max(...waveform)
const randomWaveform = waveform.map(amp => amp / maxAmplitude)

setWaveformData(randomWaveform)
setIsAudioAvailable(true)
}
finally {
await audioContext.close()
}
}

const togglePlay = useCallback(() => {
const audio = audioRef.current
if (audio && isAudioAvailable) {
if (isPlaying) {
setHasStartedPlaying(false)
audio.pause()
}
else {
setHasStartedPlaying(true)
audio.play().catch(error => console.error('Error playing audio:', error))
}

setIsPlaying(!isPlaying)
}
else {
Toast.notify({
type: 'error',
message: 'Audio element not found',
})
setIsAudioAvailable(false)
}
}, [isAudioAvailable, isPlaying])

const handleCanvasInteraction = useCallback((e: React.MouseEvent | React.TouchEvent) => {
e.preventDefault()

const getClientX = (event: React.MouseEvent | React.TouchEvent): number => {
if ('touches' in event)
return event.touches[0].clientX
return event.clientX
}

const updateProgress = (clientX: number) => {
const canvas = canvasRef.current
const audio = audioRef.current
if (!canvas || !audio)
return

const rect = canvas.getBoundingClientRect()
const percent = Math.min(Math.max(0, clientX - rect.left), rect.width) / rect.width
const newTime = percent * duration

// Removes the buffer check, allowing drag to any location
audio.currentTime = newTime
setCurrentTime(newTime)

if (!isPlaying) {
setIsPlaying(true)
audio.play().catch((error) => {
Toast.notify({
type: 'error',
message: `Error playing audio: ${error}`,
})
setIsPlaying(false)
})
}
}

updateProgress(getClientX(e))
}, [duration, isPlaying])

const formatTime = (time: number) => {
const minutes = Math.floor(time / 60)
const seconds = Math.floor(time % 60)
return `${minutes}:${seconds.toString().padStart(2, '0')}`
}

const drawWaveform = useCallback(() => {
const canvas = canvasRef.current
if (!canvas)
return

const ctx = canvas.getContext('2d')
if (!ctx)
return

const width = canvas.width
const height = canvas.height
const data = waveformData

ctx.clearRect(0, 0, width, height)

const barWidth = width / data.length
const playedWidth = (currentTime / duration) * width
const cornerRadius = 2

// Draw waveform bars
data.forEach((value, index) => {
let color

if (index * barWidth <= playedWidth)
color = '#296DFF'
else if ((index * barWidth / width) * duration <= hoverTime)
color = 'rgba(21,90,239,.40)'
else
color = 'rgba(21,90,239,.20)'

const barHeight = value * height
const rectX = index * barWidth
const rectY = (height - barHeight) / 2
const rectWidth = barWidth * 0.5
const rectHeight = barHeight

ctx.lineWidth = 1
ctx.fillStyle = color
if (ctx.roundRect) {
ctx.beginPath()
ctx.roundRect(rectX, rectY, rectWidth, rectHeight, cornerRadius)
ctx.fill()
}
else {
ctx.fillRect(rectX, rectY, rectWidth, rectHeight)
}
})
}, [currentTime, duration, hoverTime, waveformData])

useEffect(() => {
drawWaveform()
}, [drawWaveform, bufferedTime, hasStartedPlaying])

const handleMouseMove = useCallback((e: React.MouseEvent) => {
const canvas = canvasRef.current
const audio = audioRef.current
if (!canvas || !audio)
return

const rect = canvas.getBoundingClientRect()
const percent = Math.min(Math.max(0, e.clientX - rect.left), rect.width) / rect.width
const time = percent * duration

// Check if the hovered position is within a buffered range before updating hoverTime
for (let i = 0; i < audio.buffered.length; i++) {
if (time >= audio.buffered.start(i) && time <= audio.buffered.end(i)) {
setHoverTime(time)
break
}
}
}, [duration])

return (
<div className={styles.audioPlayer}>
<audio ref={audioRef} src={src} preload="auto"/>
<button className={styles.playButton} onClick={togglePlay} disabled={!isAudioAvailable}>
{isPlaying
? (
<svg viewBox="0 0 24 24" width="16" height="16">
<rect x="7" y="6" width="3" height="12" rx="1.5" ry="1.5"/>
<rect x="15" y="6" width="3" height="12" rx="1.5" ry="1.5"/>
</svg>
)
: (
<svg viewBox="0 0 24 24" width="16" height="16">
<path d="M8 5v14l11-7z" fill="currentColor"/>
</svg>
)}
</button>
<div className={isAudioAvailable ? styles.audioControls : styles.audioControls_disabled} hidden={!isAudioAvailable}>
<div className={styles.progressBarContainer}>
<canvas
ref={canvasRef}
className={styles.waveform}
onClick={handleCanvasInteraction}
onMouseMove={handleMouseMove}
onMouseDown={handleCanvasInteraction}
/>
{/* <div className={styles.currentTime} style={{ left: `${(currentTime / duration) * 81}%`, bottom: '29px' }}>
{formatTime(currentTime)}
</div> */}
<div className={styles.timeDisplay}>
<span className={styles.duration}>{formatTime(duration)}</span>
</div>
</div>
</div>
<div className={styles.source_unavailable} hidden={isAudioAvailable}>{t('common.operation.audioSourceUnavailable')}</div>
</div>
)
}

export default AudioPlayer

+ 12
- 0
web/app/components/base/audio-gallery/index.tsx Visa fil

import React from 'react'
import AudioPlayer from './AudioPlayer'

type Props = {
srcs: string[]
}

const AudioGallery: React.FC<Props> = ({ srcs }) => {
return (<><br/>{srcs.map((src, index) => (<AudioPlayer key={`audio_${index}`} src={src}/>))}</>)
}

export default React.memo(AudioGallery)

+ 38
- 0
web/app/components/base/image-uploader/audio-preview.tsx Visa fil

import type { FC } from 'react'
import { createPortal } from 'react-dom'
import { RiCloseLine } from '@remixicon/react'

type AudioPreviewProps = {
url: string
title: string
onCancel: () => void
}
const AudioPreview: FC<AudioPreviewProps> = ({
url,
title,
onCancel,
}) => {
return createPortal(
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}>
<div>
<audio controls title={title} autoPlay={false} preload="metadata">
<source
type="audio/mpeg"
src={url}
className='max-w-full max-h-full'
/>
</audio>
</div>
<div
className='absolute top-6 right-6 flex items-center justify-center w-8 h-8 bg-white/[0.08] rounded-lg backdrop-blur-[2px] cursor-pointer'
onClick={onCancel}
>
<RiCloseLine className='w-4 h-4 text-gray-500'/>
</div>
</div>
,
document.body,
)
}

export default AudioPreview

+ 38
- 2
web/app/components/base/image-uploader/image-preview.tsx Visa fil

import type { FC } from 'react' import type { FC } from 'react'
import { useRef } from 'react'
import { t } from 'i18next'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
import { RiCloseLine } from '@remixicon/react'
import { RiCloseLine, RiExternalLinkLine } from '@remixicon/react'
import Tooltip from '@/app/components/base/tooltip'
import { randomString } from '@/utils'


type ImagePreviewProps = { type ImagePreviewProps = {
url: string url: string
title: string
onCancel: () => void onCancel: () => void
} }
const ImagePreview: FC<ImagePreviewProps> = ({ const ImagePreview: FC<ImagePreviewProps> = ({
url, url,
title,
onCancel, onCancel,
}) => { }) => {
const selector = useRef(`copy-tooltip-${randomString(4)}`)

const openInNewTab = () => {
// Open in a new window, considering the case when the page is inside an iframe
if (url.startsWith('http')) {
window.open(url, '_blank')
}
else if (url.startsWith('data:image')) {
// Base64 image
const win = window.open()
win?.document.write(`<img src="${url}" alt="${title}" />`)
}
else {
console.error('Unable to open image', url)
}
}

return createPortal( return createPortal(
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}> <div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img <img
alt='preview image'
alt={title}
src={url} src={url}
className='max-w-full max-h-full' className='max-w-full max-h-full'
/> />
> >
<RiCloseLine className='w-4 h-4 text-white' /> <RiCloseLine className='w-4 h-4 text-white' />
</div> </div>
<Tooltip
selector={selector.current}
content={(t('common.operation.openInNewTab') ?? 'Open in new tab')}
className='z-10'
>
<div
className='absolute top-6 right-16 flex items-center justify-center w-8 h-8 rounded-lg cursor-pointer'
onClick={openInNewTab}
>
<RiExternalLinkLine className='w-4 h-4 text-white' />
</div>
</Tooltip>
</div>, </div>,
document.body, document.body,
) )

+ 38
- 0
web/app/components/base/image-uploader/video-preview.tsx Visa fil

import type { FC } from 'react'
import { createPortal } from 'react-dom'
import { RiCloseLine } from '@remixicon/react'

type VideoPreviewProps = {
url: string
title: string
onCancel: () => void
}
const VideoPreview: FC<VideoPreviewProps> = ({
url,
title,
onCancel,
}) => {
return createPortal(
<div className='fixed inset-0 p-8 flex items-center justify-center bg-black/80 z-[1000]' onClick={e => e.stopPropagation()}>
<div>
<video controls title={title} autoPlay={false} preload="metadata">
<source
type="video/mp4"
src={url}
className='max-w-full max-h-full'
/>
</video>
</div>
<div
className='absolute top-6 right-6 flex items-center justify-center w-8 h-8 bg-white/[0.08] rounded-lg backdrop-blur-[2px] cursor-pointer'
onClick={onCancel}
>
<RiCloseLine className='w-4 h-4 text-gray-500'/>
</div>
</div>
,
document.body,
)
}

export default VideoPreview

+ 78
- 27
web/app/components/base/markdown.tsx Visa fil

import RemarkMath from 'remark-math' import RemarkMath from 'remark-math'
import RemarkBreaks from 'remark-breaks' import RemarkBreaks from 'remark-breaks'
import RehypeKatex from 'rehype-katex' import RehypeKatex from 'rehype-katex'
import RehypeRaw from 'rehype-raw'
import RemarkGfm from 'remark-gfm' import RemarkGfm from 'remark-gfm'
import SyntaxHighlighter from 'react-syntax-highlighter' import SyntaxHighlighter from 'react-syntax-highlighter'
import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs' import { atelierHeathLight } from 'react-syntax-highlighter/dist/esm/styles/hljs'
import SVGBtn from '@/app/components/base/svg' import SVGBtn from '@/app/components/base/svg'
import Flowchart from '@/app/components/base/mermaid' import Flowchart from '@/app/components/base/mermaid'
import ImageGallery from '@/app/components/base/image-gallery' import ImageGallery from '@/app/components/base/image-gallery'
import { useChatContext } from '@/app/components/base/chat/chat/context'
import VideoGallery from '@/app/components/base/video-gallery'
import AudioGallery from '@/app/components/base/audio-gallery'


// Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD // Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD
const capitalizationLanguageNameMap: Record<string, string> = { const capitalizationLanguageNameMap: Record<string, string> = {
markdown: 'MarkDown', markdown: 'MarkDown',
makefile: 'MakeFile', makefile: 'MakeFile',
echarts: 'ECharts', echarts: 'ECharts',
shell: 'Shell',
powershell: 'PowerShell',
json: 'JSON',
latex: 'Latex',
} }
const getCorrectCapitalizationLanguageName = (language: string) => { const getCorrectCapitalizationLanguageName = (language: string) => {
if (!language) if (!language)
) )
} }


// eslint-disable-next-line unused-imports/no-unused-vars
const useLazyLoad = (ref: RefObject<Element>): boolean => { const useLazyLoad = (ref: RefObject<Element>): boolean => {
const [isIntersecting, setIntersecting] = useState<boolean>(false) const [isIntersecting, setIntersecting] = useState<boolean>(false)


> >
<div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div> <div className='text-[13px] text-gray-500 font-normal'>{languageShowName}</div>
<div style={{ display: 'flex' }}> <div style={{ display: 'flex' }}>
{language === 'mermaid'
&& <SVGBtn
isSVG={isSVG}
setIsSVG={setIsSVG}
/>
}
{language === 'mermaid' && <SVGBtn isSVG={isSVG} setIsSVG={setIsSVG} />}
<CopyBtn <CopyBtn
className='mr-1' className='mr-1'
value={String(children).replace(/\n$/, '')} value={String(children).replace(/\n$/, '')}


CodeBlock.displayName = 'CodeBlock' CodeBlock.displayName = 'CodeBlock'


const VideoBlock: CodeComponent = memo(({ node }) => {
const srcs = node.children.filter(child => 'properties' in child).map(child => (child as any).properties.src)
if (srcs.length === 0)
return null
return <VideoGallery key={srcs.join()} srcs={srcs} />
})
VideoBlock.displayName = 'VideoBlock'

const AudioBlock: CodeComponent = memo(({ node }) => {
const srcs = node.children.filter(child => 'properties' in child).map(child => (child as any).properties.src)
if (srcs.length === 0)
return null
return <AudioGallery key={srcs.join()} srcs={srcs} />
})
AudioBlock.displayName = 'AudioBlock'

const Paragraph = (paragraph: any) => {
const { node }: any = paragraph
const children_node = node.children
if (children_node && children_node[0] && 'tagName' in children_node[0] && children_node[0].tagName === 'img') {
return (
<>
<ImageGallery srcs={[children_node[0].properties.src]} />
<div>{paragraph.children.slice(1)}</div>
</>
)
}
return <div>{paragraph.children}</div>
}

const Img = ({ src }: any) => {
return (<ImageGallery srcs={[src]} />)
}

const Link = ({ node, ...props }: any) => {
if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) {
// eslint-disable-next-line react-hooks/rules-of-hooks
const { onSend } = useChatContext()
const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1])

return <abbr className="underline decoration-dashed !decoration-primary-700 cursor-pointer" onClick={() => onSend?.(hidden_text)} title={node.children[0]?.value}>{node.children[0]?.value}</abbr>
}
else {
return <a {...props} target="_blank" className="underline decoration-dashed !decoration-primary-700 cursor-pointer">{node.children[0] ? node.children[0]?.value : 'Download'}</a>
}
}

export function Markdown(props: { content: string; className?: string }) { export function Markdown(props: { content: string; className?: string }) {
const latexContent = preprocessLaTeX(props.content) const latexContent = preprocessLaTeX(props.content)
return ( return (
<div className={cn(props.className, 'markdown-body')}> <div className={cn(props.className, 'markdown-body')}>
<ReactMarkdown <ReactMarkdown
remarkPlugins={[[RemarkMath, { singleDollarTextMath: false }], RemarkGfm, RemarkBreaks]}
remarkPlugins={[[RemarkGfm, RemarkMath, { singleDollarTextMath: false }], RemarkBreaks]}
rehypePlugins={[ rehypePlugins={[
RehypeKatex as any,
RehypeKatex,
RehypeRaw as any,
// The Rehype plug-in is used to remove the ref attribute of an element
() => {
return (tree) => {
const iterate = (node: any) => {
if (node.type === 'element' && !node.properties?.src && node.properties?.ref && node.properties.ref.startsWith('{') && node.properties.ref.endsWith('}'))
delete node.properties.ref

if (node.children)
node.children.forEach(iterate)
}
tree.children.forEach(iterate)
}
},
]} ]}
components={{ components={{
code: CodeBlock, code: CodeBlock,
img({ src }) {
return (
<ImageGallery srcs={[src || '']} />
)
},
p: (paragraph) => {
const { node }: any = paragraph
if (node.children[0].tagName === 'img') {
const image = node.children[0]

return (
<>
<ImageGallery srcs={[image.properties.src]} />
<p>{paragraph.children.slice(1)}</p>
</>
)
}
return <p>{paragraph.children}</p>
},
img: Img,
video: VideoBlock,
audio: AudioBlock,
a: Link,
p: Paragraph,
}} }}
linkTarget='_blank' linkTarget='_blank'
> >

+ 188
- 0
web/app/components/base/video-gallery/VideoPlayer.module.css Visa fil

.videoPlayer {
position: relative;
width: 100%;
max-width: 800px;
margin: 0 auto;
border-radius: 8px;
overflow: hidden;
}

.video {
width: 100%;
display: block;
}

.controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
transition: opacity 0.3s ease;
}

.controls.hidden {
opacity: 0;
}

.controls.visible {
opacity: 1;
}

.overlay {
background: linear-gradient(to top, rgba(0, 0, 0, 0.7) 0%, transparent 100%);
padding: 20px;
display: flex;
flex-direction: column;
}

.progressBarContainer {
width: 100%;
margin-bottom: 10px;
}

.controlsContent {
display: flex;
justify-content: space-between;
align-items: center;
}

.leftControls, .rightControls {
display: flex;
align-items: center;
}

.playPauseButton, .muteButton, .fullscreenButton {
background: none;
border: none;
color: white;
cursor: pointer;
padding: 4px;
margin-right: 10px;
display: flex;
align-items: center;
justify-content: center;
}

.playPauseButton:hover, .muteButton:hover, .fullscreenButton:hover {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 50%;
}

.time {
color: white;
font-size: 14px;
margin-left: 8px;
}

.volumeControl {
display: flex;
align-items: center;
margin-right: 16px;
}

.volumeSlider {
width: 60px;
height: 4px;
background: rgba(255, 255, 255, 0.3);
border-radius: 2px;
cursor: pointer;
margin-left: 12px;
position: relative;
}

.volumeLevel {
position: absolute;
top: 0;
left: 0;
height: 100%;
background: #ffffff;
border-radius: 2px;
}

.progressBar {
position: relative;
width: 100%;
height: 4px;
background: rgba(255, 255, 255, 0.3);
cursor: pointer;
border-radius: 2px;
overflow: visible;
transition: height 0.2s ease;
}

.progressBar:hover {
height: 6px;
}

.progress {
height: 100%;
background: #ffffff;
transition: width 0.1s ease-in-out;
}

.hoverTimeIndicator {
position: absolute;
bottom: 100%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
pointer-events: none;
white-space: nowrap;
margin-bottom: 8px;
}

.hoverTimeIndicator::after {
content: '';
position: absolute;
top: 100%;
left: 50%;
margin-left: -4px;
border-width: 4px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.7) transparent transparent transparent;
}

.controls.smallSize .controlsContent {
justify-content: space-between;
}

.controls.smallSize .leftControls,
.controls.smallSize .rightControls {
flex: 0 0 auto;
display: flex;
align-items: center;
}

.controls.smallSize .rightControls {
justify-content: flex-end;
}

.controls.smallSize .progressBarContainer {
margin-bottom: 4px;
}

.controls.smallSize .playPauseButton,
.controls.smallSize .muteButton,
.controls.smallSize .fullscreenButton {
padding: 2px;
margin-right: 4px;
}

.controls.smallSize .playPauseButton svg,
.controls.smallSize .muteButton svg,
.controls.smallSize .fullscreenButton svg {
width: 16px;
height: 16px;
}

.controls.smallSize .muteButton {
order: -1;
}

+ 278
- 0
web/app/components/base/video-gallery/VideoPlayer.tsx Visa fil

import React, { useCallback, useEffect, useRef, useState } from 'react'
import styles from './VideoPlayer.module.css'

type VideoPlayerProps = {
src: string
}

const PlayIcon = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 5V19L19 12L8 5Z" fill="currentColor"/>
</svg>
)

const PauseIcon = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 19H10V5H6V19ZM14 5V19H18V5H14Z" fill="currentColor"/>
</svg>
)

const MuteIcon = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 9V15H7L12 20V4L7 9H3ZM16.5 12C16.5 10.23 15.48 8.71 14 7.97V16.02C15.48 15.29 16.5 13.77 16.5 12ZM14 3.23V5.29C16.89 6.15 19 8.83 19 12C19 15.17 16.89 17.85 14 18.71V20.77C18.01 19.86 21 16.28 21 12C21 7.72 18.01 4.14 14 3.23Z" fill="currentColor"/>
</svg>
)

const UnmuteIcon = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.34 2.93L2.93 4.34L7.29 8.7L7 9H3V15H7L12 20V13.41L16.18 17.59C15.69 17.96 15.16 18.27 14.58 18.5V20.58C15.94 20.22 17.15 19.56 18.13 18.67L19.66 20.2L21.07 18.79L4.34 2.93ZM10 15.17L7.83 13H5V11H7.83L10 8.83V15.17ZM19 12C19 12.82 18.85 13.61 18.59 14.34L20.12 15.87C20.68 14.7 21 13.39 21 12C21 7.72 18.01 4.14 14 3.23V5.29C16.89 6.15 19 8.83 19 12ZM12 4L10.12 5.88L12 7.76V4ZM16.5 12C16.5 10.23 15.48 8.71 14 7.97V10.18L16.45 12.63C16.48 12.43 16.5 12.22 16.5 12Z" fill="currentColor"/>
</svg>
)

const FullscreenIcon = () => (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 14H5V19H10V17H7V14ZM5 10H7V7H10V5H5V10ZM17 17H14V19H19V14H17V17ZM14 5V7H17V10H19V5H14Z" fill="currentColor"/>
</svg>
)

const VideoPlayer: React.FC<VideoPlayerProps> = ({ src }) => {
const [isPlaying, setIsPlaying] = useState(false)
const [currentTime, setCurrentTime] = useState(0)
const [duration, setDuration] = useState(0)
const [isMuted, setIsMuted] = useState(false)
const [volume, setVolume] = useState(1)
const [isDragging, setIsDragging] = useState(false)
const [isControlsVisible, setIsControlsVisible] = useState(true)
const [hoverTime, setHoverTime] = useState<number | null>(null)
const videoRef = useRef<HTMLVideoElement>(null)
const progressRef = useRef<HTMLDivElement>(null)
const volumeRef = useRef<HTMLDivElement>(null)
const controlsTimeoutRef = useRef<NodeJS.Timeout | null>(null)
const [isSmallSize, setIsSmallSize] = useState(false)
const containerRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const video = videoRef.current
if (!video)
return

const setVideoData = () => {
setDuration(video.duration)
setVolume(video.volume)
}

const setVideoTime = () => {
setCurrentTime(video.currentTime)
}

const handleEnded = () => {
setIsPlaying(false)
}

video.addEventListener('loadedmetadata', setVideoData)
video.addEventListener('timeupdate', setVideoTime)
video.addEventListener('ended', handleEnded)

return () => {
video.removeEventListener('loadedmetadata', setVideoData)
video.removeEventListener('timeupdate', setVideoTime)
video.removeEventListener('ended', handleEnded)
}
}, [src])

useEffect(() => {
return () => {
if (controlsTimeoutRef.current)
clearTimeout(controlsTimeoutRef.current)
}
}, [])

const showControls = useCallback(() => {
setIsControlsVisible(true)
if (controlsTimeoutRef.current)
clearTimeout(controlsTimeoutRef.current)

controlsTimeoutRef.current = setTimeout(() => setIsControlsVisible(false), 3000)
}, [])

const togglePlayPause = useCallback(() => {
const video = videoRef.current
if (video) {
if (isPlaying)
video.pause()
else video.play().catch(error => console.error('Error playing video:', error))
setIsPlaying(!isPlaying)
}
}, [isPlaying])

const toggleMute = useCallback(() => {
const video = videoRef.current
if (video) {
const newMutedState = !video.muted
video.muted = newMutedState
setIsMuted(newMutedState)
setVolume(newMutedState ? 0 : (video.volume > 0 ? video.volume : 1))
video.volume = newMutedState ? 0 : (video.volume > 0 ? video.volume : 1)
}
}, [])

const toggleFullscreen = useCallback(() => {
const video = videoRef.current
if (video) {
if (document.fullscreenElement)
document.exitFullscreen()
else video.requestFullscreen()
}
}, [])

const formatTime = (time: number) => {
const minutes = Math.floor(time / 60)
const seconds = Math.floor(time % 60)
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}

const updateVideoProgress = useCallback((clientX: number) => {
const progressBar = progressRef.current
const video = videoRef.current
if (progressBar && video) {
const rect = progressBar.getBoundingClientRect()
const pos = (clientX - rect.left) / rect.width
const newTime = pos * video.duration
if (newTime >= 0 && newTime <= video.duration) {
setHoverTime(newTime)
if (isDragging)
video.currentTime = newTime
}
}
}, [isDragging])

const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
updateVideoProgress(e.clientX)
}, [updateVideoProgress])

const handleMouseLeave = useCallback(() => {
if (!isDragging)
setHoverTime(null)
}, [isDragging])

const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault()
setIsDragging(true)
updateVideoProgress(e.clientX)
}, [updateVideoProgress])

useEffect(() => {
const handleGlobalMouseMove = (e: MouseEvent) => {
if (isDragging)
updateVideoProgress(e.clientX)
}

const handleGlobalMouseUp = () => {
setIsDragging(false)
setHoverTime(null)
}

if (isDragging) {
document.addEventListener('mousemove', handleGlobalMouseMove)
document.addEventListener('mouseup', handleGlobalMouseUp)
}

return () => {
document.removeEventListener('mousemove', handleGlobalMouseMove)
document.removeEventListener('mouseup', handleGlobalMouseUp)
}
}, [isDragging, updateVideoProgress])

const checkSize = useCallback(() => {
if (containerRef.current)
setIsSmallSize(containerRef.current.offsetWidth < 400)
}, [])

useEffect(() => {
checkSize()
window.addEventListener('resize', checkSize)
return () => window.removeEventListener('resize', checkSize)
}, [checkSize])

const handleVolumeChange = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
const volumeBar = volumeRef.current
const video = videoRef.current
if (volumeBar && video) {
const rect = volumeBar.getBoundingClientRect()
const newVolume = (e.clientX - rect.left) / rect.width
const clampedVolume = Math.max(0, Math.min(1, newVolume))
video.volume = clampedVolume
setVolume(clampedVolume)
setIsMuted(clampedVolume === 0)
}
}, [])

return (
<div ref={containerRef} className={styles.videoPlayer} onMouseMove={showControls} onMouseEnter={showControls}>
<video ref={videoRef} src={src} className={styles.video} />
<div className={`${styles.controls} ${isControlsVisible ? styles.visible : styles.hidden} ${isSmallSize ? styles.smallSize : ''}`}>
<div className={styles.overlay}>
<div className={styles.progressBarContainer}>
<div
ref={progressRef}
className={styles.progressBar}
onClick={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onMouseDown={handleMouseDown}
>
<div className={styles.progress} style={{ width: `${(currentTime / duration) * 100}%` }} />
{hoverTime !== null && (
<div
className={styles.hoverTimeIndicator}
style={{ left: `${(hoverTime / duration) * 100}%` }}
>
{formatTime(hoverTime)}
</div>
)}
</div>
</div>
<div className={styles.controlsContent}>
<div className={styles.leftControls}>
<button className={styles.playPauseButton} onClick={togglePlayPause}>
{isPlaying ? <PauseIcon /> : <PlayIcon />}
</button>
{!isSmallSize && (<span className={styles.time}>{formatTime(currentTime)} / {formatTime(duration)}</span>)}
</div>
<div className={styles.rightControls}>
<button className={styles.muteButton} onClick={toggleMute}>
{isMuted ? <UnmuteIcon /> : <MuteIcon />}
</button>
{!isSmallSize && (
<div className={styles.volumeControl}>
<div
ref={volumeRef}
className={styles.volumeSlider}
onClick={handleVolumeChange}
onMouseDown={(e) => {
handleVolumeChange(e)
const handleMouseMove = (e: MouseEvent) => handleVolumeChange(e as unknown as React.MouseEvent<HTMLDivElement>)
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove)
document.removeEventListener('mouseup', handleMouseUp)
}
document.addEventListener('mousemove', handleMouseMove)
document.addEventListener('mouseup', handleMouseUp)
}}
>
<div className={styles.volumeLevel} style={{ width: `${volume * 100}%` }} />
</div>
</div>
)}
<button className={styles.fullscreenButton} onClick={toggleFullscreen}>
<FullscreenIcon />
</button>
</div>
</div>
</div>
</div>
</div>
)
}

export default VideoPlayer

+ 12
- 0
web/app/components/base/video-gallery/index.tsx Visa fil

import React from 'react'
import VideoPlayer from './VideoPlayer'

type Props = {
srcs: string[]
}

const VideoGallery: React.FC<Props> = ({ srcs }) => {
return (<><br/>{srcs.map((src, index) => (<><br/><VideoPlayer key={`video_${index}`} src={src}/></>))}</>)
}

export default React.memo(VideoGallery)

+ 6
- 3
web/app/components/base/voice-input/index.tsx Visa fil

type VoiceInputTypes = { type VoiceInputTypes = {
onConverted: (text: string) => void onConverted: (text: string) => void
onCancel: () => void onCancel: () => void
wordTimestamps?: string
} }


const VoiceInput = ({ const VoiceInput = ({
onCancel, onCancel,
onConverted, onConverted,
wordTimestamps,
}: VoiceInputTypes) => { }: VoiceInputTypes) => {
const { t } = useTranslation() const { t } = useTranslation()
const recorder = useRef(new Recorder({ const recorder = useRef(new Recorder({
const mp3File = new File([mp3Blob], 'temp.mp3', { type: 'audio/mp3' }) const mp3File = new File([mp3Blob], 'temp.mp3', { type: 'audio/mp3' })
const formData = new FormData() const formData = new FormData()
formData.append('file', mp3File) formData.append('file', mp3File)
formData.append('word_timestamps', wordTimestamps || 'disabled')


let url = '' let url = ''
let isPublic = false let isPublic = false
onConverted('') onConverted('')
onCancel() onCancel()
} }
}, [])
}, [clearInterval, onCancel, onConverted, params.appId, params.token, pathname, wordTimestamps])
const handleStartRecord = async () => { const handleStartRecord = async () => {
try { try {
await recorder.current.start() await recorder.current.start()
} }
} }
} }
if (originDuration >= 120 && startRecord)
if (originDuration >= 600 && startRecord)
handleStopRecorder() handleStopRecorder()


useEffect(() => { useEffect(() => {
</div> </div>
) )
} }
<div className={`w-[45px] pl-1 text-xs font-medium ${originDuration > 110 ? 'text-[#F04438]' : 'text-gray-700'}`}>{`0${minutes.toFixed(0)}:${seconds >= 10 ? seconds : `0${seconds}`}`}</div>
<div className={`w-[45px] pl-1 text-xs font-medium ${originDuration > 500 ? 'text-[#F04438]' : 'text-gray-700'}`}>{`0${minutes.toFixed(0)}:${seconds >= 10 ? seconds : `0${seconds}`}`}</div>
</div> </div>
</div> </div>
) )

+ 1
- 0
web/i18n/en-US/common.ts Visa fil

params: 'Params', params: 'Params',
duplicate: 'Duplicate', duplicate: 'Duplicate',
rename: 'Rename', rename: 'Rename',
audioSourceUnavailable: 'AudioSource is unavailable',
}, },
errorMsg: { errorMsg: {
fieldRequired: '{{field}} is required', fieldRequired: '{{field}} is required',

+ 1
- 0
web/i18n/zh-Hans/common.ts Visa fil

params: '参数设置', params: '参数设置',
duplicate: '复制', duplicate: '复制',
rename: '重命名', rename: '重命名',
audioSourceUnavailable: '音源不可用',
}, },
errorMsg: { errorMsg: {
fieldRequired: '{{field}} 为必填项', fieldRequired: '{{field}} 为必填项',

+ 1
- 0
web/package.json Visa fil

"reactflow": "^11.11.3", "reactflow": "^11.11.3",
"recordrtc": "^5.6.2", "recordrtc": "^5.6.2",
"rehype-katex": "^6.0.2", "rehype-katex": "^6.0.2",
"rehype-raw": "^7.0.0",
"remark-breaks": "^3.0.2", "remark-breaks": "^3.0.2",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"remark-math": "^5.1.1", "remark-math": "^5.1.1",

+ 273
- 61
web/yarn.lock Visa fil

resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz"
integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==


"@babel/parser@^7.25.4":
version "7.25.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.6.tgz#85660c5ef388cbbf6e3d2a694ee97a38f18afe2f"
integrity sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==
dependencies:
"@babel/types" "^7.25.6"

"@babel/plugin-syntax-async-generators@^7.8.4": "@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4" version "7.8.4"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
"@babel/helper-validator-identifier" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"


"@babel/types@^7.24.0":
version "7.25.2"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125"
integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==
"@babel/types@^7.25.4", "@babel/types@^7.25.6":
version "7.25.6"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.6.tgz#893942ddb858f32ae7a004ec9d3a76b3463ef8e6"
integrity sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==
dependencies: dependencies:
"@babel/helper-string-parser" "^7.24.8" "@babel/helper-string-parser" "^7.24.8"
"@babel/helper-validator-identifier" "^7.24.7" "@babel/helper-validator-identifier" "^7.24.7"


"@sindresorhus/is@^4.0.0": "@sindresorhus/is@^4.0.0":
version "4.6.0" version "4.6.0"
resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==


"@sinonjs/commons@^3.0.0": "@sinonjs/commons@^3.0.0":


"@szmarczak/http-timer@^4.0.5": "@szmarczak/http-timer@^4.0.5":
version "4.0.6" version "4.0.6"
resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
dependencies: dependencies:
defer-to-connect "^2.0.0" defer-to-connect "^2.0.0"


"@types/cacheable-request@^6.0.1": "@types/cacheable-request@^6.0.1":
version "6.0.3" version "6.0.3"
resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
dependencies: dependencies:
"@types/http-cache-semantics" "*" "@types/http-cache-semantics" "*"
dependencies: dependencies:
"@types/unist" "*" "@types/unist" "*"


"@types/hast@^3.0.0":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa"
integrity sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==
dependencies:
"@types/unist" "*"

"@types/http-cache-semantics@*": "@types/http-cache-semantics@*":
version "4.0.4" version "4.0.4"
resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==


"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":


"@types/keyv@^3.1.4": "@types/keyv@^3.1.4":
version "3.1.4" version "3.1.4"
resolved "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
dependencies: dependencies:
"@types/unist" "*" "@types/unist" "*"


"@types/mdast@^4.0.0":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6"
integrity sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==
dependencies:
"@types/unist" "*"

"@types/mdx@^2.0.0": "@types/mdx@^2.0.0":
version "2.0.5" version "2.0.5"
resolved "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.5.tgz" resolved "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.5.tgz"


"@types/responselike@^1.0.0": "@types/responselike@^1.0.0":
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz" resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz"
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==


"@types/unist@^3.0.0":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.2.tgz#6dd61e43ef60b34086287f83683a5c1b2dc53d20"
integrity sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==

"@types/uuid@^9.0.8": "@types/uuid@^9.0.8":
version "9.0.8" version "9.0.8"
resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz"
"@typescript-eslint/types" "5.59.9" "@typescript-eslint/types" "5.59.9"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"


"@ungap/structured-clone@^1.0.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==

"@vue/compiler-core@3.4.25": "@vue/compiler-core@3.4.25":
version "3.4.25" version "3.4.25"
resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz" resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.25.tgz"


bing-translate-api@^4.0.2: bing-translate-api@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.0.2.tgz#52807a128e883bf074b4174c5e674ffca60685e7"
resolved "https://registry.yarnpkg.com/bing-translate-api/-/bing-translate-api-4.0.2.tgz#52807a128e883bf074b4174c5e674ffca60685e7"
integrity sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q== integrity sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==
dependencies: dependencies:
got "^11.8.6" got "^11.8.6"


cacheable-lookup@^5.0.3: cacheable-lookup@^5.0.3:
version "5.0.4" version "5.0.4"
resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==


cacheable-request@^7.0.2: cacheable-request@^7.0.2:
version "7.0.4" version "7.0.4"
resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==
dependencies: dependencies:
clone-response "^1.0.2" clone-response "^1.0.2"


clone-response@^1.0.2: clone-response@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
dependencies: dependencies:
mimic-response "^1.0.0" mimic-response "^1.0.0"


decompress-response@^6.0.0: decompress-response@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
dependencies: dependencies:
mimic-response "^3.1.0" mimic-response "^3.1.0"


defer-to-connect@^2.0.0: defer-to-connect@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==


define-data-property@^1.0.1, define-data-property@^1.1.1: define-data-property@^1.0.1, define-data-property@^1.1.1:
resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==


devlop@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018"
integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==
dependencies:
dequal "^2.0.0"

didyoumean@^1.2.2: didyoumean@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"


end-of-stream@^1.1.0: end-of-stream@^1.1.0:
version "1.4.4" version "1.4.4"
resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies: dependencies:
once "^1.4.0" once "^1.4.0"


get-stream@^5.1.0: get-stream@^5.1.0:
version "5.2.0" version "5.2.0"
resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies: dependencies:
pump "^3.0.0" pump "^3.0.0"


got@^11.8.6: got@^11.8.6:
version "11.8.6" version "11.8.6"
resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
dependencies: dependencies:
"@sindresorhus/is" "^4.0.0" "@sindresorhus/is" "^4.0.0"
vfile-location "^4.0.0" vfile-location "^4.0.0"
web-namespaces "^2.0.0" web-namespaces "^2.0.0"


hast-util-from-parse5@^8.0.0:
version "8.0.1"
resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz#654a5676a41211e14ee80d1b1758c399a0327651"
integrity sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==
dependencies:
"@types/hast" "^3.0.0"
"@types/unist" "^3.0.0"
devlop "^1.0.0"
hastscript "^8.0.0"
property-information "^6.0.0"
vfile "^6.0.0"
vfile-location "^5.0.0"
web-namespaces "^2.0.0"

hast-util-is-element@^2.0.0: hast-util-is-element@^2.0.0:
version "2.1.3" version "2.1.3"
resolved "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz" resolved "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz"
dependencies: dependencies:
"@types/hast" "^2.0.0" "@types/hast" "^2.0.0"


hast-util-parse-selector@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27"
integrity sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==
dependencies:
"@types/hast" "^3.0.0"

hast-util-raw@^9.0.0:
version "9.0.4"
resolved "https://registry.yarnpkg.com/hast-util-raw/-/hast-util-raw-9.0.4.tgz#2da03e37c46eb1a6f1391f02f9b84ae65818f7ed"
integrity sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==
dependencies:
"@types/hast" "^3.0.0"
"@types/unist" "^3.0.0"
"@ungap/structured-clone" "^1.0.0"
hast-util-from-parse5 "^8.0.0"
hast-util-to-parse5 "^8.0.0"
html-void-elements "^3.0.0"
mdast-util-to-hast "^13.0.0"
parse5 "^7.0.0"
unist-util-position "^5.0.0"
unist-util-visit "^5.0.0"
vfile "^6.0.0"
web-namespaces "^2.0.0"
zwitch "^2.0.0"

hast-util-to-estree@^2.0.0: hast-util-to-estree@^2.0.0:
version "2.3.3" version "2.3.3"
resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz" resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz"
unist-util-position "^4.0.0" unist-util-position "^4.0.0"
zwitch "^2.0.0" zwitch "^2.0.0"


hast-util-to-parse5@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz#477cd42d278d4f036bc2ea58586130f6f39ee6ed"
integrity sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==
dependencies:
"@types/hast" "^3.0.0"
comma-separated-tokens "^2.0.0"
devlop "^1.0.0"
property-information "^6.0.0"
space-separated-tokens "^2.0.0"
web-namespaces "^2.0.0"
zwitch "^2.0.0"

hast-util-to-text@^3.1.0: hast-util-to-text@^3.1.0:
version "3.1.2" version "3.1.2"
resolved "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz" resolved "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-3.1.2.tgz"
property-information "^6.0.0" property-information "^6.0.0"
space-separated-tokens "^2.0.0" space-separated-tokens "^2.0.0"


hastscript@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-8.0.0.tgz#4ef795ec8dee867101b9f23cc830d4baf4fd781a"
integrity sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==
dependencies:
"@types/hast" "^3.0.0"
comma-separated-tokens "^2.0.0"
hast-util-parse-selector "^4.0.0"
property-information "^6.0.0"
space-separated-tokens "^2.0.0"

heap@^0.2.6: heap@^0.2.6:
version "0.2.7" version "0.2.7"
resolved "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz" resolved "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz"
dependencies: dependencies:
void-elements "3.1.0" void-elements "3.1.0"


html-void-elements@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-3.0.0.tgz#fc9dbd84af9e747249034d4d62602def6517f1d7"
integrity sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==

htmlparser2@^8.0.1: htmlparser2@^8.0.1:
version "8.0.2" version "8.0.2"
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz" resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz"


http-cache-semantics@^4.0.0: http-cache-semantics@^4.0.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==


http-proxy-agent@^5.0.0: http-proxy-agent@^5.0.0:


http2-wrapper@^1.0.0-beta.5.2: http2-wrapper@^1.0.0-beta.5.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
dependencies: dependencies:
quick-lru "^5.1.1" quick-lru "^5.1.1"


json-buffer@3.0.1: json-buffer@3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==


json-parse-even-better-errors@^2.3.0: json-parse-even-better-errors@^2.3.0:


keyv@^4.0.0: keyv@^4.0.0:
version "4.5.4" version "4.5.4"
resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
dependencies: dependencies:
json-buffer "3.0.1" json-buffer "3.0.1"


lowercase-keys@^2.0.0: lowercase-keys@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==


lowlight@^1.17.0: lowlight@^1.17.0:
integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==


magicast@^0.3.4: magicast@^0.3.4:
version "0.3.4"
resolved "https://registry.npmjs.org/magicast/-/magicast-0.3.4.tgz#bbda1791d03190a24b00ff3dd18151e7fd381d19"
integrity sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q==
version "0.3.5"
resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739"
integrity sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==
dependencies: dependencies:
"@babel/parser" "^7.24.4"
"@babel/types" "^7.24.0"
"@babel/parser" "^7.25.4"
"@babel/types" "^7.25.4"
source-map-js "^1.2.0" source-map-js "^1.2.0"


make-dir@^4.0.0: make-dir@^4.0.0:
unist-util-position "^4.0.0" unist-util-position "^4.0.0"
unist-util-visit "^4.0.0" unist-util-visit "^4.0.0"


mdast-util-to-hast@^13.0.0:
version "13.2.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz#5ca58e5b921cc0a3ded1bc02eed79a4fe4fe41f4"
integrity sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==
dependencies:
"@types/hast" "^3.0.0"
"@types/mdast" "^4.0.0"
"@ungap/structured-clone" "^1.0.0"
devlop "^1.0.0"
micromark-util-sanitize-uri "^2.0.0"
trim-lines "^3.0.0"
unist-util-position "^5.0.0"
unist-util-visit "^5.0.0"
vfile "^6.0.0"

mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz" resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz"
micromark-util-symbol "^1.0.0" micromark-util-symbol "^1.0.0"
micromark-util-types "^1.0.0" micromark-util-types "^1.0.0"


micromark-util-character@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-2.1.0.tgz#31320ace16b4644316f6bf057531689c71e2aee1"
integrity sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==
dependencies:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"

micromark-util-chunked@^1.0.0: micromark-util-chunked@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz" resolved "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz"
resolved "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz" resolved "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz"
integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw== integrity sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==


micromark-util-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz#0921ac7953dc3f1fd281e3d1932decfdb9382ab1"
integrity sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==

micromark-util-events-to-acorn@^1.0.0: micromark-util-events-to-acorn@^1.0.0:
version "1.2.3" version "1.2.3"
resolved "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.3.tgz" resolved "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.2.3.tgz"
micromark-util-encode "^1.0.0" micromark-util-encode "^1.0.0"
micromark-util-symbol "^1.0.0" micromark-util-symbol "^1.0.0"


micromark-util-sanitize-uri@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz#ec8fbf0258e9e6d8f13d9e4770f9be64342673de"
integrity sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==
dependencies:
micromark-util-character "^2.0.0"
micromark-util-encode "^2.0.0"
micromark-util-symbol "^2.0.0"

micromark-util-subtokenize@^1.0.0: micromark-util-subtokenize@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz" resolved "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz"
resolved "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz" resolved "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz"
integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag== integrity sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==


micromark-util-symbol@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz#12225c8f95edf8b17254e47080ce0862d5db8044"
integrity sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==

micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: micromark-util-types@^1.0.0, micromark-util-types@^1.0.1:
version "1.1.0" version "1.1.0"
resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz" resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz"
integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg== integrity sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==


micromark-util-types@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-2.0.0.tgz#63b4b7ffeb35d3ecf50d1ca20e68fc7caa36d95e"
integrity sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==

micromark@^3.0.0: micromark@^3.0.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz" resolved "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz"


mimic-response@^1.0.0: mimic-response@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==


mimic-response@^3.1.0: mimic-response@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==


min-indent@^1.0.0: min-indent@^1.0.0:


normalize-url@^6.0.1: normalize-url@^6.0.1:
version "6.1.0" version "6.1.0"
resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==

normalize-wheel@^1.0.1: normalize-wheel@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"


once@^1.3.0, once@^1.3.1, once@^1.4.0: once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies: dependencies:
wrappy "1" wrappy "1"


p-cancelable@^2.0.0: p-cancelable@^2.0.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==


p-limit@^2.2.0: p-limit@^2.2.0:


pump@^3.0.0: pump@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies: dependencies:
end-of-stream "^1.1.0" end-of-stream "^1.1.0"


quick-lru@^5.1.1: quick-lru@^5.1.1:
version "5.1.1" version "5.1.1"
resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==


rc-input@~1.3.5: rc-input@~1.3.5:
katex "^0.16.0" katex "^0.16.0"
unist-util-visit "^4.0.0" unist-util-visit "^4.0.0"


rehype-raw@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/rehype-raw/-/rehype-raw-7.0.0.tgz#59d7348fd5dbef3807bbaa1d443efd2dd85ecee4"
integrity sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==
dependencies:
"@types/hast" "^3.0.0"
hast-util-raw "^9.0.0"
vfile "^6.0.0"

remark-breaks@^3.0.2: remark-breaks@^3.0.2:
version "3.0.3" version "3.0.3"
resolved "https://registry.npmjs.org/remark-breaks/-/remark-breaks-3.0.3.tgz" resolved "https://registry.npmjs.org/remark-breaks/-/remark-breaks-3.0.3.tgz"


resolve-alpn@^1.0.0: resolve-alpn@^1.0.0:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==


resolve-cwd@^3.0.0: resolve-cwd@^3.0.0:


responselike@^2.0.0: responselike@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
dependencies: dependencies:
lowercase-keys "^2.0.0" lowercase-keys "^2.0.0"


string-width@4.2.3, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3, string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: string-width@4.2.3, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3, string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2:
version "4.2.3" version "4.2.3"
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies: dependencies:
emoji-regex "^8.0.0" emoji-regex "^8.0.0"
character-entities-html4 "^2.0.0" character-entities-html4 "^2.0.0"
character-entities-legacy "^3.0.0" character-entities-legacy "^3.0.0"


"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==


tslib@^2.0.1: tslib@^2.0.1:
version "2.6.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==


tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0: tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0:
version "2.5.3" version "2.5.3"
dependencies: dependencies:
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"


unist-util-is@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-6.0.0.tgz#b775956486aff107a9ded971d996c173374be424"
integrity sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==
dependencies:
"@types/unist" "^3.0.0"

unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0:
version "1.1.2" version "1.1.2"
resolved "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.2.tgz" resolved "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.2.tgz"
dependencies: dependencies:
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"


unist-util-position@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-5.0.0.tgz#678f20ab5ca1207a97d7ea8a388373c9cf896be4"
integrity sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==
dependencies:
"@types/unist" "^3.0.0"

unist-util-remove-position@^4.0.0: unist-util-remove-position@^4.0.0:
version "4.0.2" version "4.0.2"
resolved "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.2.tgz" resolved "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-4.0.2.tgz"
dependencies: dependencies:
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"


unist-util-stringify-position@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz#449c6e21a880e0855bf5aabadeb3a740314abac2"
integrity sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==
dependencies:
"@types/unist" "^3.0.0"

unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1: unist-util-visit-parents@^5.0.0, unist-util-visit-parents@^5.1.1:
version "5.1.3" version "5.1.3"
resolved "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz" resolved "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz"
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"
unist-util-is "^5.0.0" unist-util-is "^5.0.0"


unist-util-visit-parents@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz#4d5f85755c3b8f0dc69e21eca5d6d82d22162815"
integrity sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==
dependencies:
"@types/unist" "^3.0.0"
unist-util-is "^6.0.0"

unist-util-visit@^4.0.0: unist-util-visit@^4.0.0:
version "4.1.2" version "4.1.2"
resolved "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz" resolved "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz"
unist-util-is "^5.0.0" unist-util-is "^5.0.0"
unist-util-visit-parents "^5.1.1" unist-util-visit-parents "^5.1.1"


unist-util-visit@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-5.0.0.tgz#a7de1f31f72ffd3519ea71814cccf5fd6a9217d6"
integrity sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==
dependencies:
"@types/unist" "^3.0.0"
unist-util-is "^6.0.0"
unist-util-visit-parents "^6.0.0"

universalify@^0.2.0: universalify@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"
vfile "^5.0.0" vfile "^5.0.0"


vfile-location@^5.0.0:
version "5.0.3"
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3"
integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==
dependencies:
"@types/unist" "^3.0.0"
vfile "^6.0.0"

vfile-message@^3.0.0: vfile-message@^3.0.0:
version "3.1.4" version "3.1.4"
resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz" resolved "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz"
"@types/unist" "^2.0.0" "@types/unist" "^2.0.0"
unist-util-stringify-position "^3.0.0" unist-util-stringify-position "^3.0.0"


vfile-message@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-4.0.2.tgz#c883c9f677c72c166362fd635f21fc165a7d1181"
integrity sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==
dependencies:
"@types/unist" "^3.0.0"
unist-util-stringify-position "^4.0.0"

vfile@^5.0.0: vfile@^5.0.0:
version "5.3.7" version "5.3.7"
resolved "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz" resolved "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz"
unist-util-stringify-position "^3.0.0" unist-util-stringify-position "^3.0.0"
vfile-message "^3.0.0" vfile-message "^3.0.0"


vfile@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/vfile/-/vfile-6.0.2.tgz#ef49548ea3d270097a67011921411130ceae7deb"
integrity sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==
dependencies:
"@types/unist" "^3.0.0"
unist-util-stringify-position "^4.0.0"
vfile-message "^4.0.0"

vite-code-inspector-plugin@0.13.0: vite-code-inspector-plugin@0.13.0:
version "0.13.0" version "0.13.0"
resolved "https://registry.npmjs.org/vite-code-inspector-plugin/-/vite-code-inspector-plugin-0.13.0.tgz" resolved "https://registry.npmjs.org/vite-code-inspector-plugin/-/vite-code-inspector-plugin-0.13.0.tgz"
resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==


"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
name wrap-ansi-cjs
version "7.0.0" version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
string-width "^4.1.0" string-width "^4.1.0"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"


wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.1.0: wrap-ansi@^8.1.0:
version "8.1.0" version "8.1.0"
resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
zwitch@^2.0.0: zwitch@^2.0.0:
version "2.0.4" version "2.0.4"
resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz" resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz"
integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==
integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==

Laddar…
Avbryt
Spara