mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-17 18:35:19 +02:00
feat: init video presentation agent
This commit is contained in:
parent
40d949b7d5
commit
b28f135a96
37 changed files with 3567 additions and 24 deletions
|
|
@ -472,21 +472,21 @@ export function DocumentsTableShell({
|
|||
setBulkDeleteConfirmOpen(false);
|
||||
}, [deletableSelectedIds, bulkDeleteDocuments, deleteDocument]);
|
||||
|
||||
const bulkDeleteBar = hasDeletableSelection ? (
|
||||
<div className="flex items-center justify-center py-1.5 border-b border-border/50 bg-destructive/5 shrink-0 animate-in fade-in slide-in-from-top-1 duration-150">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBulkDeleteConfirmOpen(true)}
|
||||
className="flex items-center gap-1.5 px-3 py-1 rounded-md bg-destructive text-destructive-foreground shadow-sm text-xs font-medium hover:bg-destructive/90 transition-colors"
|
||||
>
|
||||
<Trash2 size={12} />
|
||||
Delete ({deletableSelectedIds.length} selected)
|
||||
</button>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className="bg-sidebar overflow-hidden select-none border-t border-border/50 flex-1 flex flex-col min-h-0 relative">
|
||||
{/* Floating bulk delete pill */}
|
||||
{hasDeletableSelection && (
|
||||
<div className="absolute left-1/2 -translate-x-1/2 top-2 md:top-9 z-20 animate-in fade-in slide-in-from-top-1 duration-150">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBulkDeleteConfirmOpen(true)}
|
||||
className="flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-destructive text-destructive-foreground shadow-md text-xs font-medium"
|
||||
>
|
||||
<Trash2 size={12} />
|
||||
Delete ({deletableSelectedIds.length} selected)
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className="bg-sidebar overflow-hidden select-none border-t border-border/50 flex-1 flex flex-col min-h-0">
|
||||
{/* Desktop Table View */}
|
||||
<div className="hidden md:flex md:flex-col flex-1 min-h-0">
|
||||
<Table className="table-fixed w-full">
|
||||
|
|
@ -526,6 +526,7 @@ export function DocumentsTableShell({
|
|||
</TableRow>
|
||||
</TableHeader>
|
||||
</Table>
|
||||
{bulkDeleteBar}
|
||||
{loading ? (
|
||||
<div className="flex-1 overflow-auto">
|
||||
<Table className="table-fixed w-full">
|
||||
|
|
@ -777,6 +778,9 @@ export function DocumentsTableShell({
|
|||
)}
|
||||
</div>
|
||||
|
||||
{/* Mobile bulk delete bar */}
|
||||
<div className="md:hidden">{bulkDeleteBar}</div>
|
||||
|
||||
{/* Mobile Card View */}
|
||||
{loading ? (
|
||||
<div className="md:hidden divide-y divide-border/50 flex-1 overflow-auto">
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import type { ThinkingStep } from "@/components/tool-ui/deepagent-thinking";
|
|||
import { DisplayImageToolUI } from "@/components/tool-ui/display-image";
|
||||
import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast";
|
||||
import { GenerateReportToolUI } from "@/components/tool-ui/generate-report";
|
||||
import { GenerateVideoPresentationToolUI } from "@/components/tool-ui/video-presentation";
|
||||
import {
|
||||
CreateGoogleDriveFileToolUI,
|
||||
DeleteGoogleDriveFileToolUI,
|
||||
|
|
@ -148,6 +149,7 @@ function extractMentionedDocuments(content: unknown): MentionedDocumentInfo[] {
|
|||
const TOOLS_WITH_UI = new Set([
|
||||
"generate_podcast",
|
||||
"generate_report",
|
||||
"generate_video_presentation",
|
||||
"link_preview",
|
||||
"display_image",
|
||||
"delete_notion_page",
|
||||
|
|
@ -1662,6 +1664,7 @@ export default function NewChatPage() {
|
|||
<AssistantRuntimeProvider runtime={runtime}>
|
||||
<GeneratePodcastToolUI />
|
||||
<GenerateReportToolUI />
|
||||
<GenerateVideoPresentationToolUI />
|
||||
<LinkPreviewToolUI />
|
||||
<DisplayImageToolUI />
|
||||
<ScrapeWebpageToolUI />
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { ReportPanel } from "@/components/report-panel/report-panel";
|
|||
import { DisplayImageToolUI } from "@/components/tool-ui/display-image";
|
||||
import { GeneratePodcastToolUI } from "@/components/tool-ui/generate-podcast";
|
||||
import { GenerateReportToolUI } from "@/components/tool-ui/generate-report";
|
||||
import { GenerateVideoPresentationToolUI } from "@/components/tool-ui/video-presentation";
|
||||
import { LinkPreviewToolUI } from "@/components/tool-ui/link-preview";
|
||||
import { ScrapeWebpageToolUI } from "@/components/tool-ui/scrape-webpage";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
|
|
@ -45,6 +46,7 @@ export function PublicChatView({ shareToken }: PublicChatViewProps) {
|
|||
{/* Tool UIs for rendering tool results */}
|
||||
<GeneratePodcastToolUI />
|
||||
<GenerateReportToolUI />
|
||||
<GenerateVideoPresentationToolUI />
|
||||
<LinkPreviewToolUI />
|
||||
<DisplayImageToolUI />
|
||||
<ScrapeWebpageToolUI />
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export {
|
|||
} from "./display-image";
|
||||
export { GeneratePodcastToolUI } from "./generate-podcast";
|
||||
export { GenerateReportToolUI } from "./generate-report";
|
||||
export { GenerateVideoPresentationToolUI } from "./video-presentation";
|
||||
export { CreateGoogleDriveFileToolUI, DeleteGoogleDriveFileToolUI } from "./google-drive";
|
||||
export {
|
||||
Image,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
"use client";
|
||||
|
||||
import React, { useMemo } from "react";
|
||||
import { Player } from "@remotion/player";
|
||||
import { Sequence, AbsoluteFill } from "remotion";
|
||||
import { Audio } from "@remotion/media";
|
||||
import { FPS } from "@/lib/remotion/constants";
|
||||
|
||||
export interface CompiledSlide {
|
||||
component: React.ComponentType;
|
||||
title: string;
|
||||
code: string;
|
||||
durationInFrames: number;
|
||||
audioUrl?: string;
|
||||
}
|
||||
|
||||
function CombinedComposition({ scenes }: { scenes: CompiledSlide[] }) {
|
||||
let offset = 0;
|
||||
|
||||
return (
|
||||
<AbsoluteFill>
|
||||
{scenes.map((scene, i) => {
|
||||
const from = offset;
|
||||
offset += scene.durationInFrames;
|
||||
return (
|
||||
<Sequence key={i} from={from} durationInFrames={scene.durationInFrames}>
|
||||
<scene.component />
|
||||
{scene.audioUrl && <Audio src={scene.audioUrl} />}
|
||||
</Sequence>
|
||||
);
|
||||
})}
|
||||
</AbsoluteFill>
|
||||
);
|
||||
}
|
||||
|
||||
export function buildCompositionComponent(slides: CompiledSlide[]): React.FC {
|
||||
const scenesSnapshot = [...slides];
|
||||
const Comp: React.FC = () => <CombinedComposition scenes={scenesSnapshot} />;
|
||||
return Comp;
|
||||
}
|
||||
|
||||
interface CombinedPlayerProps {
|
||||
slides: CompiledSlide[];
|
||||
}
|
||||
|
||||
export function CombinedPlayer({ slides }: CombinedPlayerProps) {
|
||||
const CompositionWithScenes = useMemo(() => {
|
||||
const scenesSnapshot = [...slides];
|
||||
const Comp: React.FC = () => <CombinedComposition scenes={scenesSnapshot} />;
|
||||
return Comp;
|
||||
}, [slides]);
|
||||
|
||||
const totalFrames = useMemo(
|
||||
() => slides.reduce((sum, s) => sum + s.durationInFrames, 0),
|
||||
[slides],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl border shadow-2xl shadow-purple-500/5">
|
||||
<Player
|
||||
component={CompositionWithScenes}
|
||||
durationInFrames={totalFrames}
|
||||
fps={FPS}
|
||||
compositionWidth={1920}
|
||||
compositionHeight={1080}
|
||||
style={{ width: "100%", aspectRatio: "16/9" }}
|
||||
controls
|
||||
autoPlay
|
||||
loop
|
||||
acknowledgeRemotionLicense
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,682 @@
|
|||
"use client";
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { makeAssistantToolUI } from "@assistant-ui/react";
|
||||
import {
|
||||
AlertCircleIcon,
|
||||
Download,
|
||||
Film,
|
||||
Loader2,
|
||||
Presentation,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { z } from "zod";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { baseApiService } from "@/lib/apis/base-api.service";
|
||||
import { authenticatedFetch } from "@/lib/auth-utils";
|
||||
import { compileCheck, compileToComponent } from "@/lib/remotion/compile-check";
|
||||
import { FPS } from "@/lib/remotion/constants";
|
||||
import {
|
||||
CombinedPlayer,
|
||||
buildCompositionComponent,
|
||||
type CompiledSlide,
|
||||
} from "./combined-player";
|
||||
|
||||
const GenerateVideoPresentationArgsSchema = z.object({
|
||||
source_content: z.string(),
|
||||
video_title: z.string().nullish(),
|
||||
user_prompt: z.string().nullish(),
|
||||
});
|
||||
|
||||
const GenerateVideoPresentationResultSchema = z.object({
|
||||
status: z.enum(["pending", "generating", "ready", "failed"]),
|
||||
video_presentation_id: z.number().nullish(),
|
||||
title: z.string().nullish(),
|
||||
message: z.string().nullish(),
|
||||
error: z.string().nullish(),
|
||||
});
|
||||
|
||||
const VideoPresentationStatusResponseSchema = z.object({
|
||||
status: z.enum(["pending", "generating", "ready", "failed"]),
|
||||
id: z.number(),
|
||||
title: z.string(),
|
||||
slides: z
|
||||
.array(
|
||||
z.object({
|
||||
slide_number: z.number(),
|
||||
title: z.string(),
|
||||
subtitle: z.string().nullish(),
|
||||
content_in_markdown: z.string().nullish(),
|
||||
speaker_transcripts: z.array(z.string()).nullish(),
|
||||
background_explanation: z.string().nullish(),
|
||||
audio_url: z.string().nullish(),
|
||||
duration_seconds: z.number().nullish(),
|
||||
duration_in_frames: z.number().nullish(),
|
||||
}),
|
||||
)
|
||||
.nullish(),
|
||||
scene_codes: z
|
||||
.array(
|
||||
z.object({
|
||||
slide_number: z.number(),
|
||||
code: z.string(),
|
||||
title: z.string().nullish(),
|
||||
}),
|
||||
)
|
||||
.nullish(),
|
||||
slide_count: z.number().nullish(),
|
||||
});
|
||||
|
||||
type GenerateVideoPresentationArgs = z.infer<typeof GenerateVideoPresentationArgsSchema>;
|
||||
type GenerateVideoPresentationResult = z.infer<typeof GenerateVideoPresentationResultSchema>;
|
||||
type VideoPresentationStatusResponse = z.infer<typeof VideoPresentationStatusResponseSchema>;
|
||||
|
||||
function parseStatusResponse(data: unknown): VideoPresentationStatusResponse | null {
|
||||
const result = VideoPresentationStatusResponseSchema.safeParse(data);
|
||||
if (!result.success) {
|
||||
console.warn("Invalid video presentation status:", result.error.issues);
|
||||
return null;
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
|
||||
function GeneratingState({ title }: { title: string }) {
|
||||
return (
|
||||
<div className="my-4 overflow-hidden rounded-xl border border-primary/20 bg-linear-to-br from-primary/5 to-primary/10 p-4 sm:p-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4">
|
||||
<div className="relative shrink-0">
|
||||
<div className="flex size-12 sm:size-16 items-center justify-center rounded-full bg-primary/20">
|
||||
<Film className="size-6 sm:size-8 text-primary" />
|
||||
</div>
|
||||
<div className="absolute inset-1 animate-ping rounded-full bg-primary/20" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-foreground text-sm sm:text-lg leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
<div className="mt-1.5 sm:mt-2 flex items-center gap-1.5 sm:gap-2 text-muted-foreground">
|
||||
<Spinner size="sm" className="size-3 sm:size-4" />
|
||||
<span className="text-xs sm:text-sm">
|
||||
Generating video presentation. This may take a few minutes.
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2 sm:mt-3">
|
||||
<div className="h-1 sm:h-1.5 w-full overflow-hidden rounded-full bg-primary/10">
|
||||
<div className="h-full w-1/3 animate-pulse rounded-full bg-primary" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ErrorState({ title, error }: { title: string; error: string }) {
|
||||
return (
|
||||
<div className="my-4 overflow-hidden rounded-xl border border-destructive/20 bg-destructive/5 p-4 sm:p-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4">
|
||||
<div className="flex size-12 sm:size-16 shrink-0 items-center justify-center rounded-full bg-destructive/10">
|
||||
<AlertCircleIcon className="size-6 sm:size-8 text-destructive" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-foreground text-sm sm:text-base leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="mt-1 text-destructive text-xs sm:text-sm">
|
||||
Failed to generate video presentation
|
||||
</p>
|
||||
<p className="mt-1.5 sm:mt-2 text-muted-foreground text-xs sm:text-sm">{error}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CompilationLoadingState({ title }: { title: string }) {
|
||||
return (
|
||||
<div className="my-4 overflow-hidden rounded-xl border bg-muted/30 p-4 sm:p-6">
|
||||
<div className="flex items-center gap-3 sm:gap-4">
|
||||
<div className="flex size-12 sm:size-16 shrink-0 items-center justify-center rounded-full bg-primary/10">
|
||||
<Film className="size-6 sm:size-8 text-primary/50" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="font-semibold text-foreground text-sm sm:text-base leading-tight">
|
||||
{title}
|
||||
</h3>
|
||||
<div className="mt-1.5 sm:mt-2 flex items-center gap-1.5 sm:gap-2 text-muted-foreground">
|
||||
<Spinner size="sm" className="size-3 sm:size-4" />
|
||||
<span className="text-xs sm:text-sm">Compiling scenes...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function VideoPresentationPlayer({
|
||||
presentationId,
|
||||
title,
|
||||
}: {
|
||||
presentationId: number;
|
||||
title: string;
|
||||
}) {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [compiledSlides, setCompiledSlides] = useState<CompiledSlide[]>([]);
|
||||
|
||||
const [isRendering, setIsRendering] = useState(false);
|
||||
const [renderProgress, setRenderProgress] = useState<number | null>(null);
|
||||
const [renderError, setRenderError] = useState<string | null>(null);
|
||||
const [renderFormat, setRenderFormat] = useState<string | null>(null);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
const [isPptxExporting, setIsPptxExporting] = useState(false);
|
||||
const [pptxProgress, setPptxProgress] = useState<string | null>(null);
|
||||
|
||||
const backendUrl = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL ?? "";
|
||||
const audioBlobUrlsRef = useRef<string[]>([]);
|
||||
|
||||
const loadPresentation = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const raw = await baseApiService.get<unknown>(
|
||||
`/api/v1/video-presentations/${presentationId}`,
|
||||
);
|
||||
const data = parseStatusResponse(raw);
|
||||
if (!data) throw new Error("Invalid response");
|
||||
if (data.status !== "ready") throw new Error(`Unexpected status: ${data.status}`);
|
||||
if (!data.slides?.length || !data.scene_codes?.length) {
|
||||
throw new Error("No slides or scene codes in response");
|
||||
}
|
||||
|
||||
const sceneMap = new Map(data.scene_codes.map((sc) => [sc.slide_number, sc]));
|
||||
|
||||
const compiled: CompiledSlide[] = [];
|
||||
for (const slide of data.slides) {
|
||||
const scene = sceneMap.get(slide.slide_number);
|
||||
if (!scene) continue;
|
||||
|
||||
const durationInFrames = slide.duration_in_frames ?? 300;
|
||||
const check = compileCheck(scene.code);
|
||||
if (!check.success) {
|
||||
console.warn(
|
||||
`Slide ${slide.slide_number} failed to compile: ${check.error}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const component = compileToComponent(scene.code, durationInFrames);
|
||||
|
||||
compiled.push({
|
||||
component,
|
||||
title: scene.title ?? slide.title,
|
||||
code: scene.code,
|
||||
durationInFrames,
|
||||
audioUrl: slide.audio_url
|
||||
? `${backendUrl}${slide.audio_url}`
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (compiled.length === 0) {
|
||||
throw new Error("No slides compiled successfully");
|
||||
}
|
||||
|
||||
// Pre-fetch all audio files with auth headers and convert to blob URLs.
|
||||
// Remotion's <Audio> uses a plain <audio> element which can't send auth
|
||||
// headers, so we fetch the audio ourselves and hand it a blob: URL.
|
||||
const withBlobs = await Promise.all(
|
||||
compiled.map(async (slide) => {
|
||||
if (!slide.audioUrl) return slide;
|
||||
try {
|
||||
const resp = await authenticatedFetch(slide.audioUrl, {
|
||||
method: "GET",
|
||||
});
|
||||
if (!resp.ok) {
|
||||
console.warn(
|
||||
`Audio fetch ${resp.status} for slide "${slide.title}"`,
|
||||
);
|
||||
return { ...slide, audioUrl: undefined };
|
||||
}
|
||||
const blob = await resp.blob();
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
audioBlobUrlsRef.current.push(blobUrl);
|
||||
return { ...slide, audioUrl: blobUrl };
|
||||
} catch (err) {
|
||||
console.warn(`Failed to fetch audio for "${slide.title}":`, err);
|
||||
return { ...slide, audioUrl: undefined };
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
setCompiledSlides(withBlobs);
|
||||
} catch (err) {
|
||||
console.error("Error loading video presentation:", err);
|
||||
setError(err instanceof Error ? err.message : "Failed to load presentation");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [presentationId, backendUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPresentation();
|
||||
return () => {
|
||||
for (const url of audioBlobUrlsRef.current) {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
audioBlobUrlsRef.current = [];
|
||||
};
|
||||
}, [loadPresentation]);
|
||||
|
||||
const totalDuration = useMemo(
|
||||
() => compiledSlides.reduce((sum, s) => sum + s.durationInFrames / FPS, 0),
|
||||
[compiledSlides],
|
||||
);
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (isRendering || compiledSlides.length === 0) return;
|
||||
|
||||
setIsRendering(true);
|
||||
setRenderProgress(0);
|
||||
setRenderError(null);
|
||||
setRenderFormat(null);
|
||||
|
||||
const controller = new AbortController();
|
||||
abortControllerRef.current = controller;
|
||||
|
||||
try {
|
||||
const { canRenderMediaOnWeb, renderMediaOnWeb } = await import(
|
||||
"@remotion/web-renderer"
|
||||
);
|
||||
|
||||
const formats = [
|
||||
{ container: "mp4" as const, videoCodec: "h264" as const, ext: "mp4" },
|
||||
{ container: "mp4" as const, videoCodec: "h265" as const, ext: "mp4" },
|
||||
{ container: "webm" as const, videoCodec: "vp8" as const, ext: "webm" },
|
||||
{ container: "webm" as const, videoCodec: "vp9" as const, ext: "webm" },
|
||||
];
|
||||
|
||||
let chosen: (typeof formats)[number] | null = null;
|
||||
for (const fmt of formats) {
|
||||
const { canRender } = await canRenderMediaOnWeb({
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
container: fmt.container,
|
||||
videoCodec: fmt.videoCodec,
|
||||
});
|
||||
if (canRender) {
|
||||
chosen = fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!chosen) {
|
||||
throw new Error(
|
||||
"Your browser does not support video rendering (WebCodecs). Please use Chrome, Edge, or Firefox 130+.",
|
||||
);
|
||||
}
|
||||
|
||||
setRenderFormat(chosen.ext.toUpperCase());
|
||||
|
||||
const totalFrames = compiledSlides.reduce((sum, s) => sum + s.durationInFrames, 0);
|
||||
const CompositionComponent = buildCompositionComponent(compiledSlides);
|
||||
|
||||
const { getBlob } = await renderMediaOnWeb({
|
||||
composition: {
|
||||
component: CompositionComponent,
|
||||
durationInFrames: totalFrames,
|
||||
fps: FPS,
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
id: "combined-video",
|
||||
},
|
||||
container: chosen.container,
|
||||
videoCodec: chosen.videoCodec,
|
||||
videoBitrate: "high",
|
||||
onProgress: ({ progress }) => {
|
||||
setRenderProgress(progress);
|
||||
},
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
const blob = await getBlob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `video.${chosen.ext}`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (err) {
|
||||
if ((err as Error).name === "AbortError") {
|
||||
// User cancelled
|
||||
} else {
|
||||
setRenderError(err instanceof Error ? err.message : "Failed to render video");
|
||||
}
|
||||
} finally {
|
||||
setIsRendering(false);
|
||||
setRenderProgress(null);
|
||||
abortControllerRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelRender = () => {
|
||||
abortControllerRef.current?.abort();
|
||||
};
|
||||
|
||||
const handleDownloadPPTX = async () => {
|
||||
if (isPptxExporting || compiledSlides.length === 0) return;
|
||||
|
||||
setIsPptxExporting(true);
|
||||
setPptxProgress("Preparing...");
|
||||
setRenderError(null);
|
||||
|
||||
try {
|
||||
const { exportToPptx } = await import("dom-to-pptx");
|
||||
const { Thumbnail } = await import("@remotion/player");
|
||||
const { createRoot } = await import("react-dom/client");
|
||||
const { flushSync } = await import("react-dom");
|
||||
|
||||
const offscreen = document.createElement("div");
|
||||
offscreen.style.cssText =
|
||||
"position:fixed;left:-99999px;top:0;overflow:hidden;pointer-events:none;";
|
||||
document.body.appendChild(offscreen);
|
||||
|
||||
const slideElements: HTMLElement[] = [];
|
||||
const roots: ReturnType<typeof createRoot>[] = [];
|
||||
|
||||
for (let i = 0; i < compiledSlides.length; i++) {
|
||||
const slide = compiledSlides[i];
|
||||
setPptxProgress(`Rendering slide ${i + 1}/${compiledSlides.length}...`);
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.style.cssText = "width:1920px;height:1080px;overflow:hidden;";
|
||||
offscreen.appendChild(wrapper);
|
||||
|
||||
const holdFrame = Math.floor(slide.durationInFrames * 0.3);
|
||||
const root = createRoot(wrapper);
|
||||
|
||||
flushSync(() => {
|
||||
root.render(
|
||||
React.createElement(Thumbnail, {
|
||||
component: slide.component,
|
||||
compositionWidth: 1920,
|
||||
compositionHeight: 1080,
|
||||
frameToDisplay: holdFrame,
|
||||
durationInFrames: slide.durationInFrames,
|
||||
fps: FPS,
|
||||
style: { width: 1920, height: 1080 },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
slideElements.push(wrapper);
|
||||
roots.push(root);
|
||||
}
|
||||
|
||||
setPptxProgress("Converting to editable PPTX...");
|
||||
|
||||
await exportToPptx(slideElements, {
|
||||
fileName: "presentation.pptx",
|
||||
});
|
||||
|
||||
roots.forEach((r) => r.unmount());
|
||||
document.body.removeChild(offscreen);
|
||||
} catch (err) {
|
||||
setRenderError(err instanceof Error ? err.message : "Failed to export PPTX");
|
||||
} finally {
|
||||
setIsPptxExporting(false);
|
||||
setPptxProgress(null);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <CompilationLoadingState title={title} />;
|
||||
}
|
||||
|
||||
if (error || compiledSlides.length === 0) {
|
||||
return <ErrorState title={title} error={error || "Failed to compile scenes"} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="my-4 space-y-3">
|
||||
{/* Title bar with actions */}
|
||||
<div className="flex items-center justify-between flex-wrap gap-2">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<div className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||
<Film className="size-4 text-primary" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h3 className="text-sm font-semibold text-foreground truncate">{title}</h3>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{compiledSlides.length} slides · {totalDuration.toFixed(1)}s ·{" "}
|
||||
{FPS}fps
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{isRendering ? (
|
||||
<>
|
||||
<div className="flex items-center gap-2 rounded-lg border bg-card px-3 py-1.5">
|
||||
<Loader2 className="size-3.5 animate-spin text-primary" />
|
||||
<span className="text-xs font-medium">
|
||||
Rendering {renderFormat ?? ""}{" "}
|
||||
{renderProgress !== null
|
||||
? `${Math.round(renderProgress * 100)}%`
|
||||
: "..."}
|
||||
</span>
|
||||
<div className="h-1.5 w-20 overflow-hidden rounded-full bg-secondary">
|
||||
<div
|
||||
className="h-full rounded-full bg-primary transition-all duration-300"
|
||||
style={{ width: `${(renderProgress ?? 0) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleCancelRender}
|
||||
className="rounded-lg border p-1.5 text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
|
||||
title="Cancel render"
|
||||
type="button"
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="inline-flex items-center gap-1.5 rounded-lg border bg-card px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-secondary"
|
||||
type="button"
|
||||
>
|
||||
<Download className="size-3.5" />
|
||||
Download MP4
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDownloadPPTX}
|
||||
disabled={isPptxExporting}
|
||||
className="inline-flex items-center gap-1.5 rounded-lg border bg-card px-3 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-secondary disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
type="button"
|
||||
>
|
||||
{isPptxExporting ? (
|
||||
<>
|
||||
<Loader2 className="size-3.5 animate-spin" />
|
||||
{pptxProgress ?? "Exporting..."}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Presentation className="size-3.5" />
|
||||
Download PPTX
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Render error */}
|
||||
{renderError && (
|
||||
<div className="flex items-start gap-3 rounded-xl border border-destructive/20 bg-destructive/5 p-3">
|
||||
<AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />
|
||||
<div>
|
||||
<p className="text-sm font-medium text-destructive">Download Failed</p>
|
||||
<p className="mt-1 text-xs text-destructive/70 whitespace-pre-wrap">
|
||||
{renderError}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Combined Remotion Player */}
|
||||
<CombinedPlayer slides={compiledSlides} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StatusPoller({
|
||||
presentationId,
|
||||
title,
|
||||
}: {
|
||||
presentationId: number;
|
||||
title: string;
|
||||
}) {
|
||||
const [status, setStatus] = useState<VideoPresentationStatusResponse | null>(null);
|
||||
const pollingRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const poll = async () => {
|
||||
try {
|
||||
const raw = await baseApiService.get<unknown>(
|
||||
`/api/v1/video-presentations/${presentationId}`,
|
||||
);
|
||||
const response = parseStatusResponse(raw);
|
||||
if (response) {
|
||||
setStatus(response);
|
||||
if (response.status === "ready" || response.status === "failed") {
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
pollingRef.current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error polling video presentation status:", err);
|
||||
}
|
||||
};
|
||||
|
||||
poll();
|
||||
pollingRef.current = setInterval(poll, 5000);
|
||||
|
||||
return () => {
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
}
|
||||
};
|
||||
}, [presentationId]);
|
||||
|
||||
if (!status || status.status === "pending" || status.status === "generating") {
|
||||
return <GeneratingState title={title} />;
|
||||
}
|
||||
|
||||
if (status.status === "failed") {
|
||||
return <ErrorState title={title} error="Generation failed" />;
|
||||
}
|
||||
|
||||
if (status.status === "ready") {
|
||||
return (
|
||||
<VideoPresentationPlayer
|
||||
presentationId={status.id}
|
||||
title={status.title || title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <ErrorState title={title} error="Unexpected state" />;
|
||||
}
|
||||
|
||||
export const GenerateVideoPresentationToolUI = makeAssistantToolUI<
|
||||
GenerateVideoPresentationArgs,
|
||||
GenerateVideoPresentationResult
|
||||
>({
|
||||
toolName: "generate_video_presentation",
|
||||
render: function GenerateVideoPresentationUI({ args, result, status }) {
|
||||
const title = args.video_title || "SurfSense Presentation";
|
||||
|
||||
if (status.type === "running" || status.type === "requires-action") {
|
||||
return <GeneratingState title={title} />;
|
||||
}
|
||||
|
||||
if (status.type === "incomplete") {
|
||||
if (status.reason === "cancelled") {
|
||||
return (
|
||||
<div className="my-4 rounded-xl border border-muted p-3 sm:p-4 text-muted-foreground">
|
||||
<p className="flex items-center gap-1.5 sm:gap-2 text-xs sm:text-sm">
|
||||
<Film className="size-3.5 sm:size-4" />
|
||||
<span className="line-through">Presentation generation cancelled</span>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (status.reason === "error") {
|
||||
return (
|
||||
<ErrorState
|
||||
title={title}
|
||||
error={typeof status.error === "string" ? status.error : "An error occurred"}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return <GeneratingState title={title} />;
|
||||
}
|
||||
|
||||
if (result.status === "failed") {
|
||||
return <ErrorState title={title} error={result.error || "Generation failed"} />;
|
||||
}
|
||||
|
||||
if (result.status === "generating") {
|
||||
return (
|
||||
<div className="my-4 overflow-hidden rounded-xl border border-amber-500/20 bg-amber-500/5 p-3 sm:p-4">
|
||||
<div className="flex items-center gap-2.5 sm:gap-3">
|
||||
<div className="flex size-8 sm:size-10 shrink-0 items-center justify-center rounded-full bg-amber-500/20">
|
||||
<Film className="size-4 sm:size-5 text-amber-500" />
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-amber-600 dark:text-amber-400 text-xs sm:text-sm font-medium">
|
||||
Presentation already in progress
|
||||
</p>
|
||||
<p className="text-muted-foreground text-[10px] sm:text-xs mt-0.5">
|
||||
Please wait for the current presentation to complete.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (result.status === "pending" && result.video_presentation_id) {
|
||||
return (
|
||||
<StatusPoller
|
||||
presentationId={result.video_presentation_id}
|
||||
title={result.title || title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (result.status === "ready" && result.video_presentation_id) {
|
||||
return (
|
||||
<VideoPresentationPlayer
|
||||
presentationId={result.video_presentation_id}
|
||||
title={result.title || title}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <ErrorState title={title} error="Missing presentation ID" />;
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { GenerateVideoPresentationToolUI } from "./generate-video-presentation";
|
||||
|
|
@ -3,6 +3,7 @@ import {
|
|||
Brain,
|
||||
Database,
|
||||
FileText,
|
||||
Film,
|
||||
Globe,
|
||||
ImageIcon,
|
||||
Link2,
|
||||
|
|
@ -16,6 +17,7 @@ import {
|
|||
const TOOL_ICONS: Record<string, LucideIcon> = {
|
||||
search_knowledge_base: Database,
|
||||
generate_podcast: Podcast,
|
||||
generate_video_presentation: Film,
|
||||
generate_report: FileText,
|
||||
link_preview: Link2,
|
||||
display_image: ImageIcon,
|
||||
|
|
|
|||
154
surfsense_web/lib/remotion/compile-check.ts
Normal file
154
surfsense_web/lib/remotion/compile-check.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import * as Babel from "@babel/standalone";
|
||||
import React from "react";
|
||||
import {
|
||||
AbsoluteFill,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
spring,
|
||||
interpolate,
|
||||
Sequence,
|
||||
Easing,
|
||||
} from "remotion";
|
||||
import { DURATION_IN_FRAMES } from "./constants";
|
||||
|
||||
export interface CompileResult {
|
||||
success: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
function createStagger(totalFrames: number) {
|
||||
return function stagger(
|
||||
frame: number,
|
||||
fps: number,
|
||||
index: number,
|
||||
total: number,
|
||||
): { opacity: number; transform: string } {
|
||||
const enterPhase = Math.floor(totalFrames * 0.2);
|
||||
const exitStart = Math.floor(totalFrames * 0.8);
|
||||
const gap = Math.max(6, Math.floor(enterPhase / Math.max(total, 1)));
|
||||
const delay = index * gap;
|
||||
|
||||
const s = spring({
|
||||
frame: Math.max(0, frame - delay),
|
||||
fps,
|
||||
config: { damping: 15, stiffness: 120, mass: 0.8 },
|
||||
});
|
||||
|
||||
const exit = interpolate(frame, [exitStart, totalFrames], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
const ambient = s > 0.99 ? Math.sin(frame * 0.05) * 2 : 0;
|
||||
|
||||
const opacity = s * (1 - exit);
|
||||
const translateY =
|
||||
interpolate(s, [0, 1], [40, 0]) +
|
||||
interpolate(exit, [0, 1], [0, -30]) +
|
||||
ambient;
|
||||
const scale = interpolate(s, [0, 1], [0.97, 1]);
|
||||
|
||||
return {
|
||||
opacity,
|
||||
transform: `translateY(${translateY}px) scale(${scale})`,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const defaultStagger = createStagger(DURATION_IN_FRAMES);
|
||||
|
||||
const INJECTED_NAMES = [
|
||||
"React",
|
||||
"AbsoluteFill",
|
||||
"useCurrentFrame",
|
||||
"useVideoConfig",
|
||||
"spring",
|
||||
"interpolate",
|
||||
"Sequence",
|
||||
"Easing",
|
||||
"stagger",
|
||||
] as const;
|
||||
|
||||
const linear = (t: number) => t;
|
||||
|
||||
const SafeEasing = new Proxy(Easing, {
|
||||
get(target, prop) {
|
||||
const val = target[prop as keyof typeof Easing];
|
||||
if (typeof val === "function") return val;
|
||||
return linear;
|
||||
},
|
||||
});
|
||||
|
||||
function buildInjectedValues(staggerFn: ReturnType<typeof createStagger>) {
|
||||
return [
|
||||
React,
|
||||
AbsoluteFill,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
spring,
|
||||
interpolate,
|
||||
Sequence,
|
||||
SafeEasing,
|
||||
staggerFn,
|
||||
];
|
||||
}
|
||||
|
||||
export function prepareSource(code: string): string {
|
||||
const codeWithoutImports = code.replace(/^import\s+.*$/gm, "").trim();
|
||||
|
||||
const match = codeWithoutImports.match(
|
||||
/export\s+(?:const|function)\s+(\w+)\s*(?::\s*React\.FC\s*)?=?\s*\(\s*\)\s*=>\s*\{([\s\S]*)\};?\s*$/,
|
||||
);
|
||||
|
||||
if (match) {
|
||||
return `const DynamicComponent = () => {\n${match[2].trim()}\n};`;
|
||||
}
|
||||
|
||||
const cleanedCode = codeWithoutImports
|
||||
.replace(/export\s+default\s+/, "")
|
||||
.replace(/export\s+/, "");
|
||||
return cleanedCode.replace(/const\s+(\w+)/, "const DynamicComponent");
|
||||
}
|
||||
|
||||
function transpile(code: string): string {
|
||||
const wrappedSource = prepareSource(code);
|
||||
const transpiled = Babel.transform(wrappedSource, {
|
||||
presets: ["react", "typescript"],
|
||||
filename: "dynamic.tsx",
|
||||
});
|
||||
if (!transpiled.code) throw new Error("Transpilation produced no output");
|
||||
return transpiled.code;
|
||||
}
|
||||
|
||||
export function compileCheck(code: string): CompileResult {
|
||||
if (!code?.trim()) {
|
||||
return { success: false, error: "Empty code" };
|
||||
}
|
||||
|
||||
try {
|
||||
const jsCode = transpile(code);
|
||||
new Function(...INJECTED_NAMES, `${jsCode}\nreturn DynamicComponent;`);
|
||||
return { success: true, error: null };
|
||||
} catch (err) {
|
||||
return {
|
||||
success: false,
|
||||
error: err instanceof Error ? err.message : "Unknown compilation error",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function compileToComponent(
|
||||
code: string,
|
||||
durationInFrames?: number,
|
||||
): React.ComponentType {
|
||||
const staggerFn = durationInFrames
|
||||
? createStagger(durationInFrames)
|
||||
: defaultStagger;
|
||||
|
||||
const jsCode = transpile(code);
|
||||
const factory = new Function(
|
||||
...INJECTED_NAMES,
|
||||
`${jsCode}\nreturn DynamicComponent;`,
|
||||
);
|
||||
return factory(...buildInjectedValues(staggerFn)) as React.ComponentType;
|
||||
}
|
||||
2
surfsense_web/lib/remotion/constants.ts
Normal file
2
surfsense_web/lib/remotion/constants.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const FPS = 30;
|
||||
export const DURATION_IN_FRAMES = 300;
|
||||
18
surfsense_web/lib/remotion/dom-to-pptx.d.ts
vendored
Normal file
18
surfsense_web/lib/remotion/dom-to-pptx.d.ts
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
declare module "dom-to-pptx" {
|
||||
interface ExportOptions {
|
||||
fileName?: string;
|
||||
autoEmbedFonts?: boolean;
|
||||
fonts?: Array<{ name: string; url: string }>;
|
||||
skipDownload?: boolean;
|
||||
svgAsVector?: boolean;
|
||||
listConfig?: {
|
||||
color?: string;
|
||||
spacing?: { before?: number; after?: number };
|
||||
};
|
||||
}
|
||||
|
||||
export function exportToPptx(
|
||||
elementOrSelector: string | HTMLElement | Array<string | HTMLElement>,
|
||||
options?: ExportOptions,
|
||||
): Promise<Blob>;
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
"@assistant-ui/react": "^0.11.53",
|
||||
"@assistant-ui/react-ai-sdk": "^1.1.20",
|
||||
"@assistant-ui/react-markdown": "^0.11.9",
|
||||
"@babel/standalone": "^7.29.2",
|
||||
"@electric-sql/client": "^1.4.0",
|
||||
"@electric-sql/pglite": "^0.3.14",
|
||||
"@electric-sql/pglite-sync": "^0.4.0",
|
||||
|
|
@ -72,6 +73,9 @@
|
|||
"@radix-ui/react-toggle-group": "^1.1.10",
|
||||
"@radix-ui/react-toolbar": "^1.1.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@remotion/media": "^4.0.438",
|
||||
"@remotion/player": "^4.0.438",
|
||||
"@remotion/web-renderer": "^4.0.438",
|
||||
"@streamdown/code": "^1.0.2",
|
||||
"@streamdown/math": "^1.0.2",
|
||||
"@tabler/icons-react": "^3.34.1",
|
||||
|
|
@ -88,6 +92,7 @@
|
|||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dom-to-pptx": "^1.1.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"emblor": "^1.4.8",
|
||||
|
|
@ -126,6 +131,7 @@
|
|||
"rehype-sanitize": "^6.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"remark-math": "^6.0.0",
|
||||
"remotion": "^4.0.438",
|
||||
"server-only": "^0.0.1",
|
||||
"sonner": "^2.0.6",
|
||||
"streamdown": "^2.2.0",
|
||||
|
|
@ -143,6 +149,7 @@
|
|||
"@svgr/webpack": "^8.1.0",
|
||||
"@tailwindcss/postcss": "^4.1.11",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/babel__standalone": "^7.1.9",
|
||||
"@types/canvas-confetti": "^1.9.0",
|
||||
"@types/gapi": "^0.0.47",
|
||||
"@types/google.picker": "^0.0.52",
|
||||
|
|
|
|||
384
surfsense_web/pnpm-lock.yaml
generated
384
surfsense_web/pnpm-lock.yaml
generated
|
|
@ -23,6 +23,9 @@ importers:
|
|||
'@assistant-ui/react-markdown':
|
||||
specifier: ^0.11.9
|
||||
version: 0.11.10(@assistant-ui/react@0.11.58(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(immer@10.2.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@babel/standalone':
|
||||
specifier: ^7.29.2
|
||||
version: 7.29.2
|
||||
'@electric-sql/client':
|
||||
specifier: ^1.4.0
|
||||
version: 1.5.7
|
||||
|
|
@ -161,6 +164,15 @@ importers:
|
|||
'@radix-ui/react-tooltip':
|
||||
specifier: ^1.2.7
|
||||
version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@remotion/media':
|
||||
specifier: ^4.0.438
|
||||
version: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@remotion/player':
|
||||
specifier: ^4.0.438
|
||||
version: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@remotion/web-renderer':
|
||||
specifier: ^4.0.438
|
||||
version: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@streamdown/code':
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.3(react@19.2.4)
|
||||
|
|
@ -209,6 +221,9 @@ importers:
|
|||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
dom-to-pptx:
|
||||
specifier: ^1.1.5
|
||||
version: 1.1.5
|
||||
dotenv:
|
||||
specifier: ^17.2.3
|
||||
version: 17.3.1
|
||||
|
|
@ -323,6 +338,9 @@ importers:
|
|||
remark-math:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
remotion:
|
||||
specifier: ^4.0.438
|
||||
version: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
server-only:
|
||||
specifier: ^0.0.1
|
||||
version: 0.0.1
|
||||
|
|
@ -369,6 +387,9 @@ importers:
|
|||
'@tailwindcss/typography':
|
||||
specifier: ^0.5.16
|
||||
version: 0.5.19(tailwindcss@4.2.1)
|
||||
'@types/babel__standalone':
|
||||
specifier: ^7.1.9
|
||||
version: 7.1.9
|
||||
'@types/canvas-confetti':
|
||||
specifier: ^1.9.0
|
||||
version: 1.9.0
|
||||
|
|
@ -1074,6 +1095,10 @@ packages:
|
|||
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/standalone@7.29.2':
|
||||
resolution: {integrity: sha512-VSuvywmVRS8efooKrvJzs6BlVSxRvAdLeGrAKUrWoBx1fFBSeE/oBpUZCQ5BcprLyXy04W8skzz7JT8GqlNRJg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/template@7.28.6':
|
||||
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
|
@ -1892,6 +1917,21 @@ packages:
|
|||
'@mdx-js/mdx@3.1.1':
|
||||
resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==}
|
||||
|
||||
'@mediabunny/aac-encoder@1.39.2':
|
||||
resolution: {integrity: sha512-KD6KADVzAnW7tqhRFGBOX4uaiHbd0Yxvg0lfthj3wJLAEEgEBAvi43w+ZXWeEn54X/jpabrLe4bW/eYFFvlbUA==}
|
||||
peerDependencies:
|
||||
mediabunny: ^1.0.0
|
||||
|
||||
'@mediabunny/flac-encoder@1.39.2':
|
||||
resolution: {integrity: sha512-VwBr3AzZTPEEPvt4aladZiXwOf3W293eq213zDupGQi/taS8WWNqDd3eBdf8FfvlbXATfbRiycXDKyQ0HlOZaQ==}
|
||||
peerDependencies:
|
||||
mediabunny: ^1.0.0
|
||||
|
||||
'@mediabunny/mp3-encoder@1.39.2':
|
||||
resolution: {integrity: sha512-3rrodrGnUpUP8F2d1aRUl8IvjqK3jegkupbOzvOokooSAO5rXk2Lr5jZe7TnPeiVGiXfmnoJ7s9uyUOHlCd8qw==}
|
||||
peerDependencies:
|
||||
mediabunny: ^1.0.0
|
||||
|
||||
'@microsoft/fetch-event-source@2.0.1':
|
||||
resolution: {integrity: sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==}
|
||||
|
||||
|
|
@ -3329,6 +3369,27 @@ packages:
|
|||
'@react-dnd/shallowequal@4.0.2':
|
||||
resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==}
|
||||
|
||||
'@remotion/licensing@4.0.438':
|
||||
resolution: {integrity: sha512-JYg8ebbVkDJDnKt0BZV7OEptAysKkIWTdRPVGdwPeNw6CMcCooPPDuR7gGHjPtm0Odn/A3EKUopCX3kTvyWTPQ==}
|
||||
|
||||
'@remotion/media@4.0.438':
|
||||
resolution: {integrity: sha512-l47r+8Gyrv8KqqumLC9HU0Gq2CWNm8cGaRKkwC1VbdnqZ4bPQUf9SnYJV1U4IsWR8eAhk0i1QGa1Hc4VKYqKVQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@remotion/player@4.0.438':
|
||||
resolution: {integrity: sha512-2OT8r0arsjxUEVEa5dNgain7ChbDG0THZglxh1Bo4U8nTSMnuX+1yyF0MVOlmT56yaESfoiGbZvnnpB6e7Ltew==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@remotion/web-renderer@4.0.438':
|
||||
resolution: {integrity: sha512-cOGtgqRiD+q77Vj65gy/fo+GK1wA3G5ft2xYLPJZzddmrhhrhibyFglljY2Vu7UaXYIUWZTkGoXwdKchC09UZA==}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0'
|
||||
react-dom: '>=18.0.0'
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.59.0':
|
||||
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
|
||||
cpu: [arm]
|
||||
|
|
@ -3798,6 +3859,21 @@ packages:
|
|||
'@tybys/wasm-util@0.10.1':
|
||||
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
|
||||
|
||||
'@types/babel__generator@7.27.0':
|
||||
resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
|
||||
|
||||
'@types/babel__standalone@7.1.9':
|
||||
resolution: {integrity: sha512-IcCNPLqpevUD7UpV8QB0uwQPOyoOKACFf0YtYWRHcmxcakaje4Q7dbG2+jMqxw/I8Zk0NHvEps66WwS7z/UaaA==}
|
||||
|
||||
'@types/babel__template@7.4.4':
|
||||
resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
|
||||
|
||||
'@types/babel__traverse@7.28.0':
|
||||
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
|
||||
|
||||
'@types/canvas-confetti@1.9.0':
|
||||
resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==}
|
||||
|
||||
|
|
@ -3807,6 +3883,12 @@ packages:
|
|||
'@types/diff-match-patch@1.0.36':
|
||||
resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
|
||||
|
||||
'@types/dom-mediacapture-transform@0.1.11':
|
||||
resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==}
|
||||
|
||||
'@types/dom-webcodecs@0.1.13':
|
||||
resolution: {integrity: sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==}
|
||||
|
||||
'@types/estree-jsx@1.0.5':
|
||||
resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
|
||||
|
||||
|
|
@ -3843,6 +3925,9 @@ packages:
|
|||
'@types/ms@2.1.0':
|
||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||
|
||||
'@types/node@18.19.130':
|
||||
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
|
||||
|
||||
'@types/node@20.19.33':
|
||||
resolution: {integrity: sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==}
|
||||
|
||||
|
|
@ -4053,6 +4138,10 @@ packages:
|
|||
resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@xmldom/xmldom@0.8.11':
|
||||
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
acorn-jsx@5.3.2:
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
|
|
@ -4190,6 +4279,10 @@ packages:
|
|||
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||
engines: {node: 18 || 20 || >=22}
|
||||
|
||||
base64-arraybuffer@1.0.2:
|
||||
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
|
||||
engines: {node: '>= 0.6.0'}
|
||||
|
||||
baseline-browser-mapping@2.10.0:
|
||||
resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
|
@ -4346,6 +4439,9 @@ packages:
|
|||
core-js@3.48.0:
|
||||
resolution: {integrity: sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==}
|
||||
|
||||
core-util-is@1.0.3:
|
||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
|
||||
cosmiconfig@8.3.6:
|
||||
resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==}
|
||||
engines: {node: '>=14'}
|
||||
|
|
@ -4364,6 +4460,9 @@ packages:
|
|||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
css-line-break@2.1.0:
|
||||
resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
|
||||
|
||||
css-select@5.2.2:
|
||||
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
|
||||
|
||||
|
|
@ -4481,6 +4580,9 @@ packages:
|
|||
dom-serializer@2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
|
||||
dom-to-pptx@1.1.5:
|
||||
resolution: {integrity: sha512-3uGRnPJH2oOIicClhoslkTUHxLx8GYqAK1kFvFYy2Z2BQ9RFjgenduZsKuYdiDRs2RRVtXiTKtUeZmPyMgn/Ug==}
|
||||
|
||||
domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
|
||||
|
|
@ -4906,6 +5008,9 @@ packages:
|
|||
flatted@3.3.3:
|
||||
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
|
||||
|
||||
fonteditor-core@2.6.3:
|
||||
resolution: {integrity: sha512-YUryIKjkenjZ41E7JvM3V+02Ak4mTHDDTwBWgs9KBzypzHqLZHuua1UDRevZNTKawmnq1dbBAa70Jddl2+F4FQ==}
|
||||
|
||||
for-each@0.3.5:
|
||||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -5208,6 +5313,13 @@ packages:
|
|||
html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
|
||||
html2canvas@1.4.1:
|
||||
resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
https@1.0.0:
|
||||
resolution: {integrity: sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==}
|
||||
|
||||
icu-minify@4.8.3:
|
||||
resolution: {integrity: sha512-65Av7FLosNk7bPbmQx5z5XG2Y3T2GFppcjiXh4z1idHeVgQxlDpAmkGoYI0eFzAvrOnjpWTL5FmPDhsdfRMPEA==}
|
||||
|
||||
|
|
@ -5219,11 +5331,19 @@ packages:
|
|||
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
image-size@1.2.1:
|
||||
resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==}
|
||||
engines: {node: '>=16.x'}
|
||||
hasBin: true
|
||||
|
||||
image-size@2.0.2:
|
||||
resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==}
|
||||
engines: {node: '>=16.x'}
|
||||
hasBin: true
|
||||
|
||||
immediate@3.0.6:
|
||||
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
|
||||
|
||||
immer@10.2.0:
|
||||
resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
|
||||
|
||||
|
|
@ -5235,6 +5355,9 @@ packages:
|
|||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||
engines: {node: '>=0.8.19'}
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
inline-style-parser@0.2.7:
|
||||
resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==}
|
||||
|
||||
|
|
@ -5386,6 +5509,9 @@ packages:
|
|||
resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
isarray@1.0.0:
|
||||
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
|
||||
|
||||
isarray@2.0.5:
|
||||
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
|
||||
|
||||
|
|
@ -5506,6 +5632,9 @@ packages:
|
|||
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
||||
jszip@3.10.1:
|
||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||
|
||||
katex@0.16.22:
|
||||
resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==}
|
||||
hasBin: true
|
||||
|
|
@ -5542,6 +5671,9 @@ packages:
|
|||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
lie@3.3.0:
|
||||
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
|
||||
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
resolution: {integrity: sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
|
@ -5744,6 +5876,9 @@ packages:
|
|||
mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
|
||||
mediabunny@1.39.2:
|
||||
resolution: {integrity: sha512-VcrisGRt+OI7tTPrziucJoCIPYIS/DEWY37TqzQVLWSUUHiyvsiRizEypQ3FOlhfIZ4ytAG/Mw4zxfetCTyKUg==}
|
||||
|
||||
merge2@1.4.1:
|
||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
|
@ -6020,6 +6155,11 @@ packages:
|
|||
oniguruma-to-es@4.3.4:
|
||||
resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==}
|
||||
|
||||
opentype.js@1.3.4:
|
||||
resolution: {integrity: sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
optics-ts@2.4.1:
|
||||
resolution: {integrity: sha512-HaYzMHvC80r7U/LqAd4hQyopDezC60PO2qF5GuIwALut2cl5rK1VWHsqTp0oqoJJWjiv6uXKqsO+Q2OO0C3MmQ==}
|
||||
|
||||
|
|
@ -6039,6 +6179,12 @@ packages:
|
|||
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
pako@1.0.11:
|
||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||
|
||||
pako@2.1.0:
|
||||
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
|
||||
|
||||
parent-module@1.0.1:
|
||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -6178,6 +6324,9 @@ packages:
|
|||
resolution: {integrity: sha512-mdb8TKt+YCRbGQdYar3AKNUPCyEiqcprScF4unYpGALF6HlBaEuO6wPuIqXXpCWkw4VclJYCKbb6lq6pH6bJeA==}
|
||||
engines: {node: ^20.20.0 || >=22.22.0}
|
||||
|
||||
pptxgenjs@3.12.0:
|
||||
resolution: {integrity: sha512-ZozkYKWb1MoPR4ucw3/aFYlHkVIJxo9czikEclcUVnS4Iw/M+r+TEwdlB3fyAWO9JY1USxJDt0Y0/r15IR/RUA==}
|
||||
|
||||
preact@10.28.4:
|
||||
resolution: {integrity: sha512-uKFfOHWuSNpRFVTnljsCluEFq57OKT+0QdOiQo8XWnQ/pSvg7OpX5eNOejELXJMWy+BwM2nobz0FkvzmnpCNsQ==}
|
||||
|
||||
|
|
@ -6193,6 +6342,9 @@ packages:
|
|||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
|
|
@ -6219,6 +6371,9 @@ packages:
|
|||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
queue@6.0.2:
|
||||
resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==}
|
||||
|
||||
radix-ui@1.4.3:
|
||||
resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==}
|
||||
peerDependencies:
|
||||
|
|
@ -6392,6 +6547,9 @@ packages:
|
|||
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
|
||||
|
||||
readdirp@5.0.0:
|
||||
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
|
||||
engines: {node: '>= 20.19.0'}
|
||||
|
|
@ -6490,6 +6648,12 @@ packages:
|
|||
remend@1.2.1:
|
||||
resolution: {integrity: sha512-4wC12bgXsfKAjF1ewwkNIQz5sqewz/z1xgIgjEMb3r1pEytQ37F0Cm6i+OhbTWEvguJD7lhOUJhK5fSasw9f0w==}
|
||||
|
||||
remotion@4.0.438:
|
||||
resolution: {integrity: sha512-keG2GxHh81UFV0zFrwRh+yngXHn6C3z/Nohc+ru49M1TlIcaThG/hD2amJNH9otYzpYJxVjNF1t/i1hqcI8OGw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
resolve-from@4.0.0:
|
||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
@ -6523,6 +6687,9 @@ packages:
|
|||
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
safe-buffer@5.1.2:
|
||||
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -6567,6 +6734,9 @@ packages:
|
|||
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
setimmediate@1.0.5:
|
||||
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||
|
||||
sharp@0.34.5:
|
||||
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
|
|
@ -6666,6 +6836,9 @@ packages:
|
|||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
|
||||
string.prototype.codepointat@0.2.1:
|
||||
resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
|
||||
|
||||
string.prototype.includes@2.0.1:
|
||||
resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -6689,6 +6862,9 @@ packages:
|
|||
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string_decoder@1.1.1:
|
||||
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
|
||||
|
||||
stringify-entities@4.0.4:
|
||||
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
||||
|
||||
|
|
@ -6763,10 +6939,16 @@ packages:
|
|||
resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
text-segmentation@1.0.3:
|
||||
resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
|
||||
|
||||
throttleit@2.1.0:
|
||||
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tiny-inflate@1.0.3:
|
||||
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
|
||||
|
||||
tiny-invariant@1.3.1:
|
||||
resolution: {integrity: sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==}
|
||||
|
||||
|
|
@ -6845,6 +7027,9 @@ packages:
|
|||
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
undici-types@5.26.5:
|
||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
|
|
@ -6986,6 +7171,9 @@ packages:
|
|||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
utrie@1.0.2:
|
||||
resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
|
||||
|
||||
vaul@1.1.2:
|
||||
resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==}
|
||||
peerDependencies:
|
||||
|
|
@ -7960,6 +8148,8 @@ snapshots:
|
|||
|
||||
'@babel/runtime@7.28.6': {}
|
||||
|
||||
'@babel/standalone@7.29.2': {}
|
||||
|
||||
'@babel/template@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.29.0
|
||||
|
|
@ -8565,6 +8755,18 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@mediabunny/aac-encoder@1.39.2(mediabunny@1.39.2)':
|
||||
dependencies:
|
||||
mediabunny: 1.39.2
|
||||
|
||||
'@mediabunny/flac-encoder@1.39.2(mediabunny@1.39.2)':
|
||||
dependencies:
|
||||
mediabunny: 1.39.2
|
||||
|
||||
'@mediabunny/mp3-encoder@1.39.2(mediabunny@1.39.2)':
|
||||
dependencies:
|
||||
mediabunny: 1.39.2
|
||||
|
||||
'@microsoft/fetch-event-source@2.0.1': {}
|
||||
|
||||
'@napi-rs/wasm-runtime@0.2.12':
|
||||
|
|
@ -10078,6 +10280,33 @@ snapshots:
|
|||
|
||||
'@react-dnd/shallowequal@4.0.2': {}
|
||||
|
||||
'@remotion/licensing@4.0.438': {}
|
||||
|
||||
'@remotion/media@4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
mediabunny: 1.39.2
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
remotion: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
zod: 4.3.6
|
||||
|
||||
'@remotion/player@4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
remotion: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
|
||||
'@remotion/web-renderer@4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@mediabunny/aac-encoder': 1.39.2(mediabunny@1.39.2)
|
||||
'@mediabunny/flac-encoder': 1.39.2(mediabunny@1.39.2)
|
||||
'@mediabunny/mp3-encoder': 1.39.2(mediabunny@1.39.2)
|
||||
'@remotion/licensing': 4.0.438
|
||||
mediabunny: 1.39.2
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
remotion: 4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.59.0':
|
||||
optional: true
|
||||
|
||||
|
|
@ -10484,6 +10713,36 @@ snapshots:
|
|||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@types/babel__core@7.20.5':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
'@types/babel__generator': 7.27.0
|
||||
'@types/babel__template': 7.4.4
|
||||
'@types/babel__traverse': 7.28.0
|
||||
|
||||
'@types/babel__generator@7.27.0':
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@types/babel__standalone@7.1.9':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
'@types/babel__core': 7.20.5
|
||||
'@types/babel__generator': 7.27.0
|
||||
'@types/babel__template': 7.4.4
|
||||
'@types/babel__traverse': 7.28.0
|
||||
|
||||
'@types/babel__template@7.4.4':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@types/babel__traverse@7.28.0':
|
||||
dependencies:
|
||||
'@babel/types': 7.29.0
|
||||
|
||||
'@types/canvas-confetti@1.9.0': {}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
|
|
@ -10492,6 +10751,12 @@ snapshots:
|
|||
|
||||
'@types/diff-match-patch@1.0.36': {}
|
||||
|
||||
'@types/dom-mediacapture-transform@0.1.11':
|
||||
dependencies:
|
||||
'@types/dom-webcodecs': 0.1.13
|
||||
|
||||
'@types/dom-webcodecs@0.1.13': {}
|
||||
|
||||
'@types/estree-jsx@1.0.5':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
|
|
@ -10524,6 +10789,10 @@ snapshots:
|
|||
|
||||
'@types/ms@2.1.0': {}
|
||||
|
||||
'@types/node@18.19.130':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/node@20.19.33':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
|
@ -10737,6 +11006,8 @@ snapshots:
|
|||
|
||||
'@vercel/oidc@3.1.0': {}
|
||||
|
||||
'@xmldom/xmldom@0.8.11': {}
|
||||
|
||||
acorn-jsx@5.3.2(acorn@8.16.0):
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
|
|
@ -10911,6 +11182,8 @@ snapshots:
|
|||
|
||||
balanced-match@4.0.4: {}
|
||||
|
||||
base64-arraybuffer@1.0.2: {}
|
||||
|
||||
baseline-browser-mapping@2.10.0: {}
|
||||
|
||||
boolbase@1.0.0: {}
|
||||
|
|
@ -11052,6 +11325,8 @@ snapshots:
|
|||
|
||||
core-js@3.48.0: {}
|
||||
|
||||
core-util-is@1.0.3: {}
|
||||
|
||||
cosmiconfig@8.3.6(typescript@5.9.3):
|
||||
dependencies:
|
||||
import-fresh: 3.3.1
|
||||
|
|
@ -11071,6 +11346,10 @@ snapshots:
|
|||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
css-line-break@2.1.0:
|
||||
dependencies:
|
||||
utrie: 1.0.2
|
||||
|
||||
css-select@5.2.2:
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
|
|
@ -11183,6 +11462,15 @@ snapshots:
|
|||
domhandler: 5.0.3
|
||||
entities: 4.5.0
|
||||
|
||||
dom-to-pptx@1.1.5:
|
||||
dependencies:
|
||||
fonteditor-core: 2.6.3
|
||||
html2canvas: 1.4.1
|
||||
jszip: 3.10.1
|
||||
opentype.js: 1.3.4
|
||||
pako: 2.1.0
|
||||
pptxgenjs: 3.12.0
|
||||
|
||||
domelementtype@2.3.0: {}
|
||||
|
||||
domhandler@5.0.3:
|
||||
|
|
@ -11766,6 +12054,10 @@ snapshots:
|
|||
|
||||
flatted@3.3.3: {}
|
||||
|
||||
fonteditor-core@2.6.3:
|
||||
dependencies:
|
||||
'@xmldom/xmldom': 0.8.11
|
||||
|
||||
for-each@0.3.5:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
|
|
@ -12158,6 +12450,13 @@ snapshots:
|
|||
|
||||
html-void-elements@3.0.0: {}
|
||||
|
||||
html2canvas@1.4.1:
|
||||
dependencies:
|
||||
css-line-break: 2.1.0
|
||||
text-segmentation: 1.0.3
|
||||
|
||||
https@1.0.0: {}
|
||||
|
||||
icu-minify@4.8.3:
|
||||
dependencies:
|
||||
'@formatjs/icu-messageformat-parser': 3.5.1
|
||||
|
|
@ -12166,8 +12465,14 @@ snapshots:
|
|||
|
||||
ignore@7.0.5: {}
|
||||
|
||||
image-size@1.2.1:
|
||||
dependencies:
|
||||
queue: 6.0.2
|
||||
|
||||
image-size@2.0.2: {}
|
||||
|
||||
immediate@3.0.6: {}
|
||||
|
||||
immer@10.2.0: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
|
|
@ -12177,6 +12482,8 @@ snapshots:
|
|||
|
||||
imurmurhash@0.1.4: {}
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
inline-style-parser@0.2.7: {}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
|
|
@ -12334,6 +12641,8 @@ snapshots:
|
|||
call-bound: 1.0.4
|
||||
get-intrinsic: 1.3.0
|
||||
|
||||
isarray@1.0.0: {}
|
||||
|
||||
isarray@2.0.5: {}
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
|
@ -12418,6 +12727,13 @@ snapshots:
|
|||
object.assign: 4.1.7
|
||||
object.values: 1.2.1
|
||||
|
||||
jszip@3.10.1:
|
||||
dependencies:
|
||||
lie: 3.3.0
|
||||
pako: 1.0.11
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
katex@0.16.22:
|
||||
dependencies:
|
||||
commander: 8.3.0
|
||||
|
|
@ -12445,6 +12761,10 @@ snapshots:
|
|||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
|
||||
lie@3.3.0:
|
||||
dependencies:
|
||||
immediate: 3.0.6
|
||||
|
||||
lightningcss-android-arm64@1.31.1:
|
||||
optional: true
|
||||
|
||||
|
|
@ -12736,6 +13056,11 @@ snapshots:
|
|||
|
||||
mdn-data@2.0.30: {}
|
||||
|
||||
mediabunny@1.39.2:
|
||||
dependencies:
|
||||
'@types/dom-mediacapture-transform': 0.1.11
|
||||
'@types/dom-webcodecs': 0.1.13
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
micromark-core-commonmark@2.0.3:
|
||||
|
|
@ -13180,6 +13505,11 @@ snapshots:
|
|||
regex: 6.1.0
|
||||
regex-recursion: 6.0.2
|
||||
|
||||
opentype.js@1.3.4:
|
||||
dependencies:
|
||||
string.prototype.codepointat: 0.2.1
|
||||
tiny-inflate: 1.0.3
|
||||
|
||||
optics-ts@2.4.1: {}
|
||||
|
||||
optionator@0.9.4:
|
||||
|
|
@ -13205,6 +13535,10 @@ snapshots:
|
|||
dependencies:
|
||||
p-limit: 3.1.0
|
||||
|
||||
pako@1.0.11: {}
|
||||
|
||||
pako@2.1.0: {}
|
||||
|
||||
parent-module@1.0.1:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
|
|
@ -13368,6 +13702,13 @@ snapshots:
|
|||
dependencies:
|
||||
'@posthog/core': 1.23.1
|
||||
|
||||
pptxgenjs@3.12.0:
|
||||
dependencies:
|
||||
'@types/node': 18.19.130
|
||||
https: 1.0.0
|
||||
image-size: 1.2.1
|
||||
jszip: 3.10.1
|
||||
|
||||
preact@10.28.4: {}
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
|
@ -13376,6 +13717,8 @@ snapshots:
|
|||
|
||||
prismjs@1.30.0: {}
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
prop-types@15.8.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
|
@ -13411,6 +13754,10 @@ snapshots:
|
|||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
queue@6.0.2:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
|
||||
radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
|
|
@ -13639,6 +13986,16 @@ snapshots:
|
|||
|
||||
react@19.2.4: {}
|
||||
|
||||
readable-stream@2.3.8:
|
||||
dependencies:
|
||||
core-util-is: 1.0.3
|
||||
inherits: 2.0.4
|
||||
isarray: 1.0.0
|
||||
process-nextick-args: 2.0.1
|
||||
safe-buffer: 5.1.2
|
||||
string_decoder: 1.1.1
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
readdirp@5.0.0: {}
|
||||
|
||||
recma-build-jsx@1.0.0:
|
||||
|
|
@ -13825,6 +14182,11 @@ snapshots:
|
|||
|
||||
remend@1.2.1: {}
|
||||
|
||||
remotion@4.0.438(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
|
@ -13889,6 +14251,8 @@ snapshots:
|
|||
has-symbols: 1.1.0
|
||||
isarray: 2.0.5
|
||||
|
||||
safe-buffer@5.1.2: {}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
|
@ -13938,6 +14302,8 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
setimmediate@1.0.5: {}
|
||||
|
||||
sharp@0.34.5:
|
||||
dependencies:
|
||||
'@img/colour': 1.0.0
|
||||
|
|
@ -14102,6 +14468,8 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
string.prototype.codepointat@0.2.1: {}
|
||||
|
||||
string.prototype.includes@2.0.1:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
|
|
@ -14152,6 +14520,10 @@ snapshots:
|
|||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
string_decoder@1.1.1:
|
||||
dependencies:
|
||||
safe-buffer: 5.1.2
|
||||
|
||||
stringify-entities@4.0.4:
|
||||
dependencies:
|
||||
character-entities-html4: 2.1.0
|
||||
|
|
@ -14216,8 +14588,14 @@ snapshots:
|
|||
|
||||
tapable@2.3.0: {}
|
||||
|
||||
text-segmentation@1.0.3:
|
||||
dependencies:
|
||||
utrie: 1.0.2
|
||||
|
||||
throttleit@2.1.0: {}
|
||||
|
||||
tiny-inflate@1.0.3: {}
|
||||
|
||||
tiny-invariant@1.3.1: {}
|
||||
|
||||
tinyexec@1.0.2: {}
|
||||
|
|
@ -14307,6 +14685,8 @@ snapshots:
|
|||
has-symbols: 1.1.0
|
||||
which-boxed-primitive: 1.1.1
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1: {}
|
||||
|
|
@ -14465,6 +14845,10 @@ snapshots:
|
|||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
utrie@1.0.2:
|
||||
dependencies:
|
||||
base64-arraybuffer: 1.0.2
|
||||
|
||||
vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
|
||||
dependencies:
|
||||
'@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue