diff --git a/Dockerfile.dev b/Dockerfile.dev index 1642a662..6de18da2 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -38,7 +38,7 @@ RUN pip install docling --extra-index-url https://download.pytorch.org/whl/cpu # Install dependencies for Next.js WORKDIR /node_dependencies COPY servers/nextjs/package.json servers/nextjs/package-lock.json ./ -RUN npm install +RUN npm install --verbose # Install chrome for puppeteer RUN npx puppeteer browsers install chrome@138.0.7204.94 --install-deps diff --git a/servers/fastapi/chroma/chroma.sqlite3 b/servers/fastapi/chroma/chroma.sqlite3 index caf17128..75372bfc 100644 Binary files a/servers/fastapi/chroma/chroma.sqlite3 and b/servers/fastapi/chroma/chroma.sqlite3 differ diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/AnthropicKeyWarning.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/APIKeyWarning.tsx similarity index 66% rename from servers/nextjs/app/(presentation-generator)/custom-layout/components/AnthropicKeyWarning.tsx rename to servers/nextjs/app/(presentation-generator)/custom-layout/components/APIKeyWarning.tsx index 68d8e565..44b2e0d2 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/AnthropicKeyWarning.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/APIKeyWarning.tsx @@ -1,18 +1,15 @@ import React from "react"; import Header from "@/components/Header"; -export const AnthropicKeyWarning: React.FC = () => { +export const APIKeyWarning: React.FC = () => { return (

- Please put Anthropic Key To Process The Layout + Please add "GOOGLE_API_KEY" to enable template creation via AI.

-

- It Only works on Anthropic(Claude-4). -

diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/EditControls.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/EditControls.tsx index 2ad731b7..82f2f111 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/EditControls.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/EditControls.tsx @@ -1,3 +1,5 @@ +'use client' + import React from "react"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/HtmlEditor.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/HtmlEditor.tsx index 6b04f1a1..284e7b4a 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/HtmlEditor.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/HtmlEditor.tsx @@ -1,3 +1,4 @@ +'use client' import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/NewEachSlide.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/NewEachSlide.tsx index 59f7653f..e766cf90 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/NewEachSlide.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/NewEachSlide.tsx @@ -1,5 +1,6 @@ +'use client' + import React from "react"; -import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { useDrawingCanvas } from "../../hooks/useDrawingCanvas"; @@ -155,36 +156,6 @@ const EachSlide: React.FC = ({ onTouchEnd={handleTouchEnd} /> - - {/* Action Buttons */} -
- -
); }; diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideActions.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideActions.tsx index 91d0e8f5..dbb282de 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideActions.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideActions.tsx @@ -1,3 +1,4 @@ +'use client' import React from "react"; import { AlertCircle, CheckCircle, Edit, Loader2, Repeat2, Trash, Code } from "lucide-react"; import ToolTip from "@/components/ToolTip"; diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideContentDisplay.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideContentDisplay.tsx index b934058c..baf501e6 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideContentDisplay.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/EachSlide/SlideContentDisplay.tsx @@ -1,8 +1,11 @@ +'use client' + import React from "react"; import SlideContent from "../SlideContent"; import { SlideContentDisplayProps } from "../../types"; import { Repeat2 } from "lucide-react"; +import Timer from "../Timer"; export const SlideContentDisplay: React.FC = ({ slide, @@ -33,16 +36,15 @@ export const SlideContentDisplay: React.FC = ({ if (slide.processing) { return (
-

- 🔄 Converting to HTML... -

-
-
-
-
-
- +

🔄 Converting to HTML...

+
+
+
+
+
+
+
); } @@ -50,6 +52,12 @@ export const SlideContentDisplay: React.FC = ({ if (slide.processed && slide.html) { return (
+ {slide.convertingToReact && ( +
+

⚙️ Converting HTML to React...

+ +
+ )}
@@ -86,27 +94,21 @@ export const SlideContentDisplay: React.FC = ({ if (slide.error) { return (
-

- ✗ Conversion failed -

+

✗ Conversion failed

{slide.error.includes("image exceeds 5 MB maximum") ? (
-

- Image too large for processing -

-

- This slide's image exceeds the 5MB limit. Try using a - smaller resolution PPTX file. -

+

Image too large for processing

+

This slide's image exceeds the 5MB limit. Try using a smaller resolution PPTX file.

) : ( slide.error )}
- - +
); @@ -114,9 +116,7 @@ export const SlideContentDisplay: React.FC = ({ return (
-

- ⏳ Waiting in queue to process... -

+

⏳ Waiting in queue to process...

diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/FileUploadSection.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/FileUploadSection.tsx index 3e9c405f..a371c9df 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/FileUploadSection.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/FileUploadSection.tsx @@ -10,6 +10,7 @@ import { import { Label } from "@/components/ui/label"; import { Upload, FileText, X, Loader2 } from "lucide-react"; import { ProcessedSlide } from "../types"; +import Timer from "./Timer"; interface FileUploadSectionProps { selectedFile: File | null; @@ -96,7 +97,7 @@ export const FileUploadSection: React.FC = ({
)} -
+
+ {isProcessingPptx && }
diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/SlideContent.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/SlideContent.tsx index 40d63d91..f2c6881b 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/components/SlideContent.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/SlideContent.tsx @@ -1,3 +1,5 @@ +'use client' + import React, { memo } from "react"; const SlideContent = memo(({ slide }: { slide: any }) => { diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/components/Timer.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/components/Timer.tsx new file mode 100644 index 00000000..0a3922c1 --- /dev/null +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/components/Timer.tsx @@ -0,0 +1,103 @@ +'use client' +import React, { useEffect, useRef, useState } from 'react' + +interface TimerProps { + duration: number // seconds +} + +const Timer = ({ duration }: TimerProps) => { + const [progress, setProgress] = useState(0) + const rafIdRef = useRef(null) + const startTimeRef = useRef(null) + + useEffect(() => { + // Guard against invalid durations + const totalMs = Math.max(0, duration * 1000) + + const easeOutCubic = (x: number) => 1 - Math.pow(1 - x, 3) + const easeOutSine = (x: number) => Math.sin((x * Math.PI) / 2) + + const tick = (now: number) => { + if (startTimeRef.current === null) startTimeRef.current = now + const elapsed = now - startTimeRef.current + const t = totalMs === 0 ? 1 : Math.min(elapsed / totalMs, 1) + + // Piecewise progression: + // - Reach ~75% around 60% of the total duration (faster start) + // - Then ease slowly towards 99% for the remainder + let nextProgress: number + if (t <= 0.6) { + nextProgress = 75 * easeOutCubic(t / 0.6) + } else { + nextProgress = 75 + 24 * easeOutSine((t - 0.6) / 0.4) + } + + // Clamp and ensure we never hit 100 + nextProgress = Math.min(99, nextProgress) + + setProgress(prev => (nextProgress < prev ? prev : nextProgress)) + + if (t < 1 && nextProgress < 99) { + rafIdRef.current = requestAnimationFrame(tick) + } else { + // End at 99 and stop + setProgress(99) + if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current) + rafIdRef.current = null + } + } + + // Initialize animation + setProgress(0) + startTimeRef.current = null + rafIdRef.current = requestAnimationFrame(tick) + + return () => { + if (rafIdRef.current) cancelAnimationFrame(rafIdRef.current) + rafIdRef.current = null + startTimeRef.current = null + } + }, [duration]) + + return ( +
+
+ {Math.round(progress)}% +
+
+
+
+
+
+
+ +
+ ) +} + +export default Timer diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAPIKeyCheck.ts b/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAPIKeyCheck.ts new file mode 100644 index 00000000..5164e7df --- /dev/null +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAPIKeyCheck.ts @@ -0,0 +1,17 @@ +import { useState, useEffect } from "react"; + +export const useAPIKeyCheck = () => { + const [hasRequiredKey, setHasAnthropicKey] = useState(false); + const [isRequiredKeyLoading, setIsAnthropicKeyLoading] = useState(true); + + useEffect(() => { + fetch("/api/has-required-key") + .then((res) => res.json()) + .then((data) => { + setHasAnthropicKey(data.hasKey); + setIsAnthropicKeyLoading(false); + }); + }, []); + + return { hasRequiredKey, isRequiredKeyLoading }; +}; \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAnthropicKeyCheck.ts b/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAnthropicKeyCheck.ts deleted file mode 100644 index e6bdd684..00000000 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useAnthropicKeyCheck.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useState, useEffect } from "react"; - -export const useAnthropicKeyCheck = () => { - const [hasAnthropicKey, setHasAnthropicKey] = useState(false); - const [isAnthropicKeyLoading, setIsAnthropicKeyLoading] = useState(true); - - useEffect(() => { - fetch("/api/has-anthropic-key") - .then((res) => res.json()) - .then((data) => { - setHasAnthropicKey(data.hasKey); - setIsAnthropicKeyLoading(false); - }); - }, []); - - return { hasAnthropicKey, isAnthropicKeyLoading }; -}; \ No newline at end of file diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useLayoutSaving.ts b/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useLayoutSaving.ts index c58528e8..8433a86d 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useLayoutSaving.ts +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/hooks/useLayoutSaving.ts @@ -7,7 +7,8 @@ import { ProcessedSlide, UploadedFont } from "../types"; export const useLayoutSaving = ( slides: ProcessedSlide[], UploadedFonts: UploadedFont[], - refetch: () => void + refetch: () => void, + setSlides: React.Dispatch> ) => { const [isSavingLayout, setIsSavingLayout] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); @@ -80,7 +81,7 @@ export const useLayoutSaving = ( try { // Convert each slide HTML to React component - const reactComponents = []; + const reactComponents: any[] = []; const presentationId = uuidv4(); // Get all uploaded font URLs @@ -95,6 +96,9 @@ export const useLayoutSaving = ( continue; } + // Mark current slide as converting to React + setSlides(prev => prev.map((s, idx) => idx === i ? { ...s, convertingToReact: true } : s)); + try { const reactComponent = await convertSlideToReact(slide, presentationId, FontUrls); reactComponents.push(reactComponent); @@ -112,7 +116,9 @@ export const useLayoutSaving = ( : "An unexpected error occurred", }); // Continue with other slides even if one fails - continue; + } finally { + // Clear converting flag for this slide + setSlides(prev => prev.map((s, idx) => idx === i ? { ...s, convertingToReact: false } : s)); } } @@ -169,7 +175,7 @@ export const useLayoutSaving = ( } finally { setIsSavingLayout(false); } - }, [slides, UploadedFonts, refetch, closeSaveModal]); + }, [slides, UploadedFonts, refetch, closeSaveModal, setSlides]); return { isSavingLayout, diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/page.tsx b/servers/nextjs/app/(presentation-generator)/custom-layout/page.tsx index 377175dc..1a6d2415 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/page.tsx +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/page.tsx @@ -9,20 +9,20 @@ import { useFontManagement } from "./hooks/useFontManagement"; import { useFileUpload } from "./hooks/useFileUpload"; import { useSlideProcessing } from "./hooks/useSlideProcessing"; import { useLayoutSaving } from "./hooks/useLayoutSaving"; -import { useAnthropicKeyCheck } from "./hooks/useAnthropicKeyCheck"; import { LoadingSpinner } from "./components/LoadingSpinner"; -import { AnthropicKeyWarning } from "./components/AnthropicKeyWarning"; import { FileUploadSection } from "./components/FileUploadSection"; import { SaveLayoutButton } from "./components/SaveLayoutButton"; import { SaveLayoutModal } from "./components/SaveLayoutModal"; import EachSlide from "./components/EachSlide/NewEachSlide"; +import { APIKeyWarning } from "./components/APIKeyWarning"; +import { useAPIKeyCheck } from "./hooks/useAPIKeyCheck"; const CustomLayoutPage = () => { const { refetch } = useLayout(); // Custom hooks for different concerns - const { hasAnthropicKey, isAnthropicKeyLoading } = useAnthropicKeyCheck(); + const { hasRequiredKey, isRequiredKeyLoading } = useAPIKeyCheck(); const { selectedFile, handleFileSelect, removeFile } = useFileUpload(); const { slides, setSlides, completedSlides } = useCustomLayout(); const { fontsData, UploadedFonts, uploadFont, removeFont, getAllUnsupportedFonts, setFontsData } = useFontManagement(); @@ -35,7 +35,8 @@ const CustomLayoutPage = () => { const { isSavingLayout, isModalOpen, openSaveModal, closeSaveModal, saveLayout } = useLayoutSaving( slides, UploadedFonts, - refetch + refetch, + setSlides ); const handleProcessSlideToHtml = (slide: any) => { @@ -58,13 +59,13 @@ const CustomLayoutPage = () => { }; // Loading state - if (isAnthropicKeyLoading) { - return ; + if (isRequiredKeyLoading) { + return ; } // Anthropic key warning - if (!hasAnthropicKey) { - return ; + if (!hasRequiredKey) { + return ; } return ( diff --git a/servers/nextjs/app/(presentation-generator)/custom-layout/types/index.ts b/servers/nextjs/app/(presentation-generator)/custom-layout/types/index.ts index e82bcca1..64e260ad 100644 --- a/servers/nextjs/app/(presentation-generator)/custom-layout/types/index.ts +++ b/servers/nextjs/app/(presentation-generator)/custom-layout/types/index.ts @@ -18,6 +18,7 @@ export interface ProcessedSlide extends SlideData { processed?: boolean; error?: string; modified?: boolean; + convertingToReact?: boolean; // indicates HTML-to-React conversion in progress } export interface FontData { diff --git a/servers/nextjs/app/(presentation-generator)/layout-preview/[slug]/page.tsx b/servers/nextjs/app/(presentation-generator)/layout-preview/[slug]/page.tsx index 22570da2..8df2e343 100644 --- a/servers/nextjs/app/(presentation-generator)/layout-preview/[slug]/page.tsx +++ b/servers/nextjs/app/(presentation-generator)/layout-preview/[slug]/page.tsx @@ -1,19 +1,54 @@ "use client"; -import React, { useEffect } from "react"; + +import React, { useEffect, useState, useRef } from "react"; import { useParams, useRouter } from "next/navigation"; // import { useGroupLayoutLoader } from '../hooks/useGroupLayoutLoader' import LoadingStates from "../components/LoadingStates"; import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { ArrowLeft, Home, Trash2 } from "lucide-react"; +import { ArrowLeft, Edit, Home, Trash2 } from "lucide-react"; import { useLayout } from "@/app/(presentation-generator)/context/LayoutContext"; +import { useDrawingCanvas } from "../../custom-layout/hooks/useDrawingCanvas"; +import { EditControls } from "../../custom-layout/components/EachSlide/EditControls"; +import html2canvas from "html2canvas"; + const GroupLayoutPreview = () => { const params = useParams(); const router = useRouter(); const slug = params.slug as string; + // const isCustom = slug.includes("custom-"); + const isCustom = true; + // Custom hooks + const { + canvasRef, + slideDisplayRef, + strokeWidth, + strokeColor, + eraserMode, + isDrawing, + canvasDimensions, + setCanvasDimensions, + didYourDraw, + handleMouseDown, + handleMouseMove, + handleMouseUp, + handleTouchStart, + handleTouchMove, + handleTouchEnd, + handleClearCanvas, + handleEraserModeChange, + handleStrokeColorChange, + handleStrokeWidthChange, + } = useDrawingCanvas(); + + const slideContentRef = useRef(null); const { getFullDataByGroup, loading,refetch } = useLayout(); const layoutGroup = getFullDataByGroup(slug); + const [isEditMode, setIsEditMode] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(null); + const [prompt, setPrompt] = useState(""); + const [isUpdating, setIsUpdating] = useState(false); useEffect(() => { const existingScript = document.querySelector( @@ -27,6 +62,17 @@ const GroupLayoutPreview = () => { } }, [slug]); + // Size canvas to content when entering edit mode + useEffect(() => { + if (isEditMode && slideContentRef.current) { + const rect = slideContentRef.current.getBoundingClientRect(); + setCanvasDimensions({ + width: Math.max(rect.width, 800), + height: Math.max(rect.height, 600), + }); + } + }, [isEditMode, setCanvasDimensions]); + // Handle loading state if (loading) { return ; @@ -47,6 +93,130 @@ const GroupLayoutPreview = () => { router.push("/layout-preview"); } } + + const handleSave = async ( + slideDisplayRef: React.RefObject, + didYourDraw: boolean + ) => { + if ( + !slideContentRef.current || + !slideDisplayRef.current + ) + return; + + if (!prompt.trim()) { + alert("Please enter a prompt before saving."); + return; + } + + setIsUpdating(true); + + try { + // Take screenshot of the slide display area (slide only) + const slideOnly = await html2canvas(slideDisplayRef.current, { + backgroundColor: "#ffffff", + scale: 1, + logging: false, + useCORS: true, + ignoreElements: (element) => { + return element.tagName === "CANVAS"; + }, + }); + let slideWithCanvas; + if (didYourDraw) { + // Take screenshot of the entire slide display area including canvas + slideWithCanvas = await html2canvas(slideDisplayRef.current, { + backgroundColor: "#ffffff", + scale: 1, + logging: false, + useCORS: true, + }); + } + + + + const currentUiImageBlob = dataURLToBlob( + slideOnly.toDataURL("image/png") + ); + let sketchImageBlob; + if (didYourDraw && slideWithCanvas) { + sketchImageBlob = dataURLToBlob(slideWithCanvas.toDataURL("image/png")); + } + + // download the images + + const currentUiImageUrl = URL.createObjectURL(currentUiImageBlob); + const sketchImageUrl = didYourDraw ? URL.createObjectURL(sketchImageBlob) : null; + + const a = document.createElement("a"); + a.href = currentUiImageUrl; + a.download = `slide-current.png`; + a.click(); + + if (sketchImageUrl) { + const b = document.createElement("a"); + b.href = sketchImageUrl; + b.download = `slide-sketch.png`; + b.click(); + } + + + // const formData = new FormData(); + // formData.append( + // "current_ui_image", + // currentUiImageBlob, + // `slide--current.png` + // ); + // if (didYourDraw && slideWithCanvas && sketchImageBlob) { + // formData.append( + // "sketch_image", + // sketchImageBlob, + // `slide-sketch.png` + // ); + // } + // formData.append("html", ''); + // formData.append("prompt", prompt); + + // const response = await fetch("/api/v1/ppt/html-edit/", { + // method: "POST", + // body: formData, + // }); + + // if (!response.ok) { + // throw new Error(`API call failed: ${response.statusText}`); + // } + + // const data = await response.json(); + + + // Exit edit mode + setIsEditMode(false); + setPrompt(""); + } catch (error) { + console.error("Error updating slide:", error); + alert( + `Error updating slide: ${ + error instanceof Error ? error.message : "Unknown error" + }` + ); + } finally { + setIsUpdating(false); + } + }; + const dataURLToBlob = (dataURL: string): Blob => { + const parts = dataURL.split(","); + const contentType = parts[0].match(/:(.*?);/)?.[1] || "image/png"; + const raw = window.atob(parts[1]); + const rawLength = raw.length; + const uInt8Array = new Uint8Array(rawLength); + + for (let i = 0; i < rawLength; ++i) { + uInt8Array[i] = raw.charCodeAt(i); + } + + return new Blob([uInt8Array], { type: contentType }); + }; + return (
{/* Header */} @@ -72,7 +242,7 @@ const GroupLayoutPreview = () => { All Groups - {slug.includes('custom-') && }
@@ -90,8 +260,37 @@ const GroupLayoutPreview = () => {
- {/* Layout Grid */} +
+ {/* Edit Controls (no HTML editor) */} + {isCustom && ( + { + setIsUpdating(true); + setTimeout(() => { + setIsUpdating(false); + setIsEditMode(false); + setSelectedIndex(null); + }, 300); + }} + onCancel={() => { + setIsEditMode(false); + setSelectedIndex(null); + handleClearCanvas(); + }} + onStrokeWidthChange={handleStrokeWidthChange} + onStrokeColorChange={handleStrokeColorChange} + onEraserModeChange={handleEraserModeChange} + onClearCanvas={handleClearCanvas} + /> + )}
{layoutGroup.map((layout: any, index: number) => { const { @@ -101,6 +300,8 @@ const GroupLayoutPreview = () => { fileName, } = layout; + const isSelected = isCustom && isEditMode && selectedIndex === index; + return ( {
-
- Layout #{index + 1} -
+ {isCustom && ( + + )}
{/* Layout Content */} -
- +
+
+ + {isSelected && ( + e.preventDefault()} + /> + )} +
); diff --git a/servers/nextjs/app/api/has-anthropic-key/route.ts b/servers/nextjs/app/api/has-required-key/route.ts similarity index 74% rename from servers/nextjs/app/api/has-anthropic-key/route.ts rename to servers/nextjs/app/api/has-required-key/route.ts index 97c8ff0b..9e4a3b40 100644 --- a/servers/nextjs/app/api/has-anthropic-key/route.ts +++ b/servers/nextjs/app/api/has-required-key/route.ts @@ -3,6 +3,6 @@ import { NextResponse } from "next/server"; export const dynamic = "force-dynamic"; export async function GET() { - const hasKey = process.env.ANTHROPIC_API_KEY !== ""; + const hasKey = process.env.GOOGLE_API_KEY !== ""; return NextResponse.json({ hasKey }); } diff --git a/servers/nextjs/next-env.d.ts b/servers/nextjs/next-env.d.ts index 1b3be084..40c3d680 100644 --- a/servers/nextjs/next-env.d.ts +++ b/servers/nextjs/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. diff --git a/servers/nextjs/package-lock.json b/servers/nextjs/package-lock.json index 158baf51..94b61767 100644 --- a/servers/nextjs/package-lock.json +++ b/servers/nextjs/package-lock.json @@ -45,7 +45,7 @@ "lucide-react": "^0.447.0", "marked": "^15.0.11", "mermaid": "^11.9.0", - "next": "15.4.5", + "next": "^14.2.14", "next-themes": "^0.4.6", "prismjs": "^1.30.0", "puppeteer": "^24.13.0", @@ -67,8 +67,8 @@ "@types/node": "^20", "@types/prismjs": "^1.26.5", "@types/puppeteer": "^5.4.7", - "@types/react": "^19", - "@types/react-dom": "^19", + "@types/react": "^18", + "@types/react-dom": "^18", "@types/uuid": "^10.0.0", "@types/ws": "^8.5.13", "cypress": "^14.3.3", @@ -1425,15 +1425,15 @@ } }, "node_modules/@next/env": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.5.tgz", - "integrity": "sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.31.tgz", + "integrity": "sha512-X8VxxYL6VuezrG82h0pUA1V+DuTSJp7Nv15bxq3ivrFqZLjx81rfeHMWOE9T0jm1n3DtHGv8gdn6B0T0kr0D3Q==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.5.tgz", - "integrity": "sha512-84dAN4fkfdC7nX6udDLz9GzQlMUwEMKD7zsseXrl7FTeIItF8vpk1lhLEnsotiiDt+QFu3O1FVWnqwcRD2U3KA==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.31.tgz", + "integrity": "sha512-dTHKfaFO/xMJ3kzhXYgf64VtV6MMwDs2viedDOdP+ezd0zWMOQZkxcwOfdcQeQCpouTr9b+xOqMCUXxgLizl8Q==", "cpu": [ "arm64" ], @@ -1447,9 +1447,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.5.tgz", - "integrity": "sha512-CL6mfGsKuFSyQjx36p2ftwMNSb8PQog8y0HO/ONLdQqDql7x3aJb/wB+LA651r4we2pp/Ck+qoRVUeZZEvSurA==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.31.tgz", + "integrity": "sha512-iSavebQgeMukUAfjfW8Fi2Iz01t95yxRl2w2wCzjD91h5In9la99QIDKcKSYPfqLjCgwz3JpIWxLG6LM/sxL4g==", "cpu": [ "x64" ], @@ -1463,9 +1463,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.5.tgz", - "integrity": "sha512-1hTVd9n6jpM/thnDc5kYHD1OjjWYpUJrJxY4DlEacT7L5SEOXIifIdTye6SQNNn8JDZrcN+n8AWOmeJ8u3KlvQ==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.31.tgz", + "integrity": "sha512-XJb3/LURg1u1SdQoopG6jDL2otxGKChH2UYnUTcby4izjM0il7ylBY5TIA7myhvHj9lG5pn9F2nR2s3i8X9awQ==", "cpu": [ "arm64" ], @@ -1479,9 +1479,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.5.tgz", - "integrity": "sha512-4W+D/nw3RpIwGrqpFi7greZ0hjrCaioGErI7XHgkcTeWdZd146NNu1s4HnaHonLeNTguKnL2Urqvj28UJj6Gqw==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.31.tgz", + "integrity": "sha512-IInDAcchNCu3BzocdqdCv1bKCmUVO/bKJHnBFTeq3svfaWpOPewaLJ2Lu3GL4yV76c/86ZvpBbG/JJ1lVIs5MA==", "cpu": [ "arm64" ], @@ -1495,9 +1495,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.5.tgz", - "integrity": "sha512-N6Mgdxe/Cn2K1yMHge6pclffkxzbSGOydXVKYOjYqQXZYjLCfN/CuFkaYDeDHY2VBwSHyM2fUjYBiQCIlxIKDA==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.31.tgz", + "integrity": "sha512-YTChJL5/9e4NXPKW+OJzsQa42RiWUNbE+k+ReHvA+lwXk+bvzTsVQboNcezWOuCD+p/J+ntxKOB/81o0MenBhw==", "cpu": [ "x64" ], @@ -1511,9 +1511,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.5.tgz", - "integrity": "sha512-YZ3bNDrS8v5KiqgWE0xZQgtXgCTUacgFtnEgI4ccotAASwSvcMPDLua7BWLuTfucoRv6mPidXkITJLd8IdJplQ==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.31.tgz", + "integrity": "sha512-A0JmD1y4q/9ufOGEAhoa60Sof++X10PEoiWOH0gZ2isufWZeV03NnyRlRmJpRQWGIbRkJUmBo9I3Qz5C10vx4w==", "cpu": [ "x64" ], @@ -1527,9 +1527,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.5.tgz", - "integrity": "sha512-9Wr4t9GkZmMNcTVvSloFtjzbH4vtT4a8+UHqDoVnxA5QyfWe6c5flTH1BIWPGNWSUlofc8dVJAE7j84FQgskvQ==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.31.tgz", + "integrity": "sha512-nowJ5GbMeDOMzbTm29YqrdrD6lTM8qn2wnZfGpYMY7SZODYYpaJHH1FJXE1l1zWICHR+WfIMytlTDBHu10jb8A==", "cpu": [ "arm64" ], @@ -1542,10 +1542,26 @@ "node": ">= 10" } }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.31.tgz", + "integrity": "sha512-pk9Bu4K0015anTS1OS9d/SpS0UtRObC+xe93fwnm7Gvqbv/W1ZbzhK4nvc96RURIQOux3P/bBH316xz8wjGSsA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.5.tgz", - "integrity": "sha512-voWk7XtGvlsP+w8VBz7lqp8Y+dYw/MTI4KeS0gTVtfdhdJ5QwhXLmNrndFOin/MDoCvUaLWMkYKATaCoUkt2/A==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.31.tgz", + "integrity": "sha512-LwFZd4JFnMHGceItR9+jtlMm8lGLU/IPkgjBBgYmdYSfalbHCiDpjMYtgDQ2wtwiAOSJOCyFI4m8PikrsDyA6Q==", "cpu": [ "x64" ], @@ -2823,13 +2839,20 @@ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "license": "Apache-2.0", "dependencies": { - "tslib": "^2.8.0" + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" } }, "node_modules/@tailwindcss/typography": { @@ -3593,9 +3616,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz", - "integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==", + "version": "20.19.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.10.tgz", + "integrity": "sha512-iAFpG6DokED3roLSP0K+ybeDdIX6Bc0Vd3mLW5uDqThPWtNos3E+EqOM11mPQHKzfWHqEBuLjIlsBQQ8CsISmQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3609,6 +3632,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@types/puppeteer": { "version": "5.4.7", "resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-5.4.7.tgz", @@ -3620,23 +3650,24 @@ } }, "node_modules/@types/react": { - "version": "19.1.9", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", - "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", + "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "devOptional": true, "license": "MIT", "dependencies": { + "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "19.1.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", - "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^18.0.0" } }, "node_modules/@types/sinonjs__fake-timers": { @@ -3951,9 +3982,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.0.tgz", - "integrity": "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", + "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", "license": "Apache-2.0", "optional": true }, @@ -4152,6 +4183,17 @@ "node": "*" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/cachedir": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", @@ -4212,9 +4254,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001731", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", - "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "version": "1.0.30001733", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001733.tgz", + "integrity": "sha512-e4QKw/O2Kavj2VQTKZWrwzkt3IxOmIlU6ajRb6LP64LHpBo1J67k2Hi4Vu/TgJWsNtynurfS0uK3MaUTCPfu5Q==", "funding": [ { "type": "opencollective", @@ -4679,9 +4721,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "14.5.3", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.5.3.tgz", - "integrity": "sha512-syLwKjDeMg77FRRx68bytLdlqHXDT4yBVh0/PPkcgesChYDjUZbwxLqMXuryYKzAyJsPsQHUDW1YU74/IYEUIA==", + "version": "14.5.4", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-14.5.4.tgz", + "integrity": "sha512-0Dhm4qc9VatOcI1GiFGVt8osgpPdqJLHzRwcAB5MSD/CAAts3oybvPUPawHyvJZUd8osADqZe/xzMsZ8sDTjXw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5346,9 +5388,9 @@ "license": "MIT" }, "node_modules/devtools-protocol": { - "version": "0.0.1464554", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1464554.tgz", - "integrity": "sha512-CAoP3lYfwAGQTaAXYvA6JZR0fjGUb7qec1qf4mToyoH2TZgUFeIqYcjh6f9jNuhHfuZiEdH+PONHYrLhRQX6aw==", + "version": "0.0.1475386", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1475386.tgz", + "integrity": "sha512-RQ809ykTfJ+dgj9bftdeL2vRVxASAuGU+I9LEx9Ij5TXU5HrgAQVmzi72VA+mkzscE12uzlRv5/tWWv9R9J1SA==", "license": "BSD-3-Clause" }, "node_modules/didyoumean": { @@ -6107,7 +6149,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/hachure-fill": { @@ -7143,40 +7184,41 @@ } }, "node_modules/next": { - "version": "15.4.5", - "resolved": "https://registry.npmjs.org/next/-/next-15.4.5.tgz", - "integrity": "sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==", + "version": "14.2.31", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.31.tgz", + "integrity": "sha512-Wyw1m4t8PhqG+or5a1U/Deb888YApC4rAez9bGhHkTsfwAy4SWKVro0GhEx4sox1856IbLhvhce2hAA6o8vkog==", "license": "MIT", "dependencies": { - "@next/env": "15.4.5", - "@swc/helpers": "0.5.15", + "@next/env": "14.2.31", + "@swc/helpers": "0.5.5", + "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.6" + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.4.5", - "@next/swc-darwin-x64": "15.4.5", - "@next/swc-linux-arm64-gnu": "15.4.5", - "@next/swc-linux-arm64-musl": "15.4.5", - "@next/swc-linux-x64-gnu": "15.4.5", - "@next/swc-linux-x64-musl": "15.4.5", - "@next/swc-win32-arm64-msvc": "15.4.5", - "@next/swc-win32-x64-msvc": "15.4.5", - "sharp": "^0.34.3" + "@next/swc-darwin-arm64": "14.2.31", + "@next/swc-darwin-x64": "14.2.31", + "@next/swc-linux-arm64-gnu": "14.2.31", + "@next/swc-linux-arm64-musl": "14.2.31", + "@next/swc-linux-x64-gnu": "14.2.31", + "@next/swc-linux-x64-musl": "14.2.31", + "@next/swc-win32-arm64-msvc": "14.2.31", + "@next/swc-win32-ia32-msvc": "14.2.31", + "@next/swc-win32-x64-msvc": "14.2.31" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "@playwright/test": "^1.41.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { @@ -7186,9 +7228,6 @@ "@playwright/test": { "optional": true }, - "babel-plugin-react-compiler": { - "optional": true - }, "sass": { "optional": true } @@ -7797,9 +7836,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.2.tgz", - "integrity": "sha512-BVypCAJ4SL6jOiTsDffP3Wp6wD69lRhI4zg/iT8JXjp3ccZFiq5WyguxvMKmdKFC3prhaig7wSr8dneDToHE1Q==", + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.3.tgz", + "integrity": "sha512-dY2HdaNXlARknJbrManZ1WyUtos+AP97AmvqdOQtWtrrC5g4mohVX5DTi9rXNFSk09eczLq9GuNTtq3EfMeMGA==", "license": "MIT", "dependencies": { "orderedmap": "^2.0.0" @@ -7948,17 +7987,17 @@ } }, "node_modules/puppeteer": { - "version": "24.15.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.15.0.tgz", - "integrity": "sha512-HPSOTw+DFsU/5s2TUUWEum9WjFbyjmvFDuGHtj2X4YUz2AzOzvKMkT3+A3FR+E+ZefiX/h3kyLyXzWJWx/eMLQ==", + "version": "24.16.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.16.0.tgz", + "integrity": "sha512-5qxFGOpdAzYexoPwKPEF4L/IYKYOFE1MxWsqcp7K33HySM8N8S/yZwSQCaV0rzmJsTLX5LxU4zt65+ceNiVDgQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.2.0", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1464554", - "puppeteer-core": "24.15.0", + "devtools-protocol": "0.0.1475386", + "puppeteer-core": "24.16.0", "typed-query-selector": "^2.12.0" }, "bin": { @@ -7969,15 +8008,15 @@ } }, "node_modules/puppeteer-core": { - "version": "24.15.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.15.0.tgz", - "integrity": "sha512-2iy0iBeWbNyhgiCGd/wvGrDSo73emNFjSxYOcyAqYiagkYt5q4cPfVXaVDKBsukgc2fIIfLAalBZlaxldxdDYg==", + "version": "24.16.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.16.0.tgz", + "integrity": "sha512-tZ0tJiOYaDGTRzzr2giDpf8O/55JsoqkrafS1Xu4H6S8oP4eeL6RbZzY9OzjShSf5EQvx/zAc55QKpDqzXos/Q==", "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.2.0", "debug": "^4.4.1", - "devtools-protocol": "0.0.1464554", + "devtools-protocol": "0.0.1475386", "typed-query-selector": "^2.12.0", "ws": "^8.18.3" }, @@ -8747,6 +8786,14 @@ "dev": true, "license": "MIT" }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/streamx": { "version": "2.22.1", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", @@ -8825,9 +8872,9 @@ } }, "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -8836,7 +8883,7 @@ "node": ">= 12.0.0" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" }, "peerDependenciesMeta": { "@babel/core": { @@ -9207,9 +9254,9 @@ "license": "MIT" }, "node_modules/tmp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", - "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { @@ -9669,9 +9716,9 @@ } }, "node_modules/zod": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.0.15.tgz", - "integrity": "sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.0.16.tgz", + "integrity": "sha512-Djo/cM339grjI7/HmN+ixYO2FzEMcWr/On50UlQ/RjrWK1I/hPpWhpC76heCptnRFpH0LMwrEbUY50HDc0V8wg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/servers/nextjs/package.json b/servers/nextjs/package.json index 7554780c..8fdd24c3 100644 --- a/servers/nextjs/package.json +++ b/servers/nextjs/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev ", "build": "next build", "start": "next start", "lint": "next lint" @@ -47,7 +47,7 @@ "lucide-react": "^0.447.0", "marked": "^15.0.11", "mermaid": "^11.9.0", - "next": "15.4.5", + "next": "^14.2.14", "next-themes": "^0.4.6", "prismjs": "^1.30.0", "puppeteer": "^24.13.0", @@ -69,8 +69,8 @@ "@types/node": "^20", "@types/prismjs": "^1.26.5", "@types/puppeteer": "^5.4.7", - "@types/react": "^19", - "@types/react-dom": "^19", + "@types/react": "^18", + "@types/react-dom": "^18", "@types/uuid": "^10.0.0", "@types/ws": "^8.5.13", "cypress": "^14.3.3",