diff --git a/apps/dispatch-server/routes/aircraft.ts b/apps/dispatch-server/routes/aircraft.ts index c3ff5d44..fa665438 100644 --- a/apps/dispatch-server/routes/aircraft.ts +++ b/apps/dispatch-server/routes/aircraft.ts @@ -2,6 +2,7 @@ import { AdminMessage, getPublicUser, MissionLog, + MissionSdsStatusLog, NotificationPayload, Prisma, prisma, @@ -130,6 +131,44 @@ router.patch("/:id", async (req, res) => { } }); +router.post("/:id/send-sds-message", async (req, res) => { + const { id } = req.params; + const { sdsMessage } = req.body as { sdsMessage: MissionSdsStatusLog }; + + if (!sdsMessage.data.stationId || !id) { + res.status(400).json({ error: "Missing aircraftId or stationId" }); + return; + } + + await prisma.mission.updateMany({ + where: { + state: "running", + missionStationIds: { + has: sdsMessage.data.stationId, + }, + }, + data: { + missionLog: { + push: sdsMessage as unknown as Prisma.InputJsonValue, + }, + }, + }); + + io.to( + sdsMessage.data.direction === "to-lst" ? "dispatchers" : `station:${sdsMessage.data.stationId}`, + ).emit(sdsMessage.data.direction === "to-lst" ? "notification" : "sds-status", { + type: "station-status", + status: sdsMessage.data.status, + message: "SDS Status Message", + data: { + aircraftId: parseInt(id), + stationId: sdsMessage.data.stationId, + }, + } as NotificationPayload); + + res.sendStatus(204); +}); + // Kick a connectedAircraft by ID router.delete("/:id", async (req, res) => { const { id } = req.params; diff --git a/apps/dispatch/Dockerfile b/apps/dispatch/Dockerfile index 315d8d76..1236c9d6 100644 --- a/apps/dispatch/Dockerfile +++ b/apps/dispatch/Dockerfile @@ -1,12 +1,12 @@ FROM node:22-alpine AS base -ARG NEXT_PUBLIC_DISPATCH_URL -ARG NEXT_PUBLIC_DISPATCH_SERVER_URL -ARG NEXT_PUBLIC_HUB_URL -ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID -ARG NEXT_PUBLIC_LIVEKIT_URL -ARG NEXT_PUBLIC_DISCORD_URL -ARG NEXT_PUBLIC_OPENAIP_ACCESS +ARG NEXT_PUBLIC_DISPATCH_URL="http://localhost:3001" +ARG NEXT_PUBLIC_DISPATCH_SERVER_URL="http://localhost:4001" +ARG NEXT_PUBLIC_HUB_URL="http://localhost:3002" +ARG NEXT_PUBLIC_DISPATCH_SERVICE_ID="1" +ARG NEXT_PUBLIC_LIVEKIT_URL="http://localhost:7880" +ARG NEXT_PUBLIC_DISCORD_URL="https://discord.com" +ARG NEXT_PUBLIC_OPENAIP_ACCESS="" ENV NEXT_PUBLIC_DISPATCH_SERVER_URL=$NEXT_PUBLIC_DISPATCH_SERVER_URL ENV NEXT_PUBLIC_DISPATCH_URL=$NEXT_PUBLIC_DISPATCH_URL @@ -16,13 +16,13 @@ ENV NEXT_PUBLIC_LIVEKIT_URL=$NEXT_PUBLIC_LIVEKIT_URL ENV NEXT_PUBLIC_OPENAIP_ACCESS=$NEXT_PUBLIC_OPENAIP_ACCESS ENV NEXT_PUBLIC_DISCORD_URL=$NEXT_PUBLIC_DISCORD_URL +FROM base AS builder + ENV PNPM_HOME="/usr/local/pnpm" ENV PATH="${PNPM_HOME}:${PATH}" RUN corepack enable && corepack prepare pnpm@latest --activate RUN pnpm add -g turbo@^2.5 - -FROM base AS builder RUN apk update RUN apk add --no-cache libc6-compat @@ -31,12 +31,20 @@ WORKDIR /usr/app RUN echo "NEXT_PUBLIC_HUB_URL is: $NEXT_PUBLIC_HUB_URL" RUN echo "NEXT_PUBLIC_DISPATCH_SERVICE_ID is: $NEXT_PUBLIC_DISPATCH_SERVICE_ID" RUN echo "NEXT_PUBLIC_DISPATCH_SERVER_URL is: $NEXT_PUBLIC_DISPATCH_SERVER_URL" +RUN echo "NEXT_PUBLIC_LIVEKIT_URL is: $NEXT_PUBLIC_LIVEKIT_URL" COPY . . RUN turbo prune dispatch --docker FROM base AS installer + +ENV PNPM_HOME="/usr/local/pnpm" +ENV PATH="${PNPM_HOME}:${PATH}" +RUN corepack enable && corepack prepare pnpm@latest --activate + +RUN pnpm add -g turbo@^2.5 + RUN apk update RUN apk add --no-cache libc6-compat @@ -50,19 +58,22 @@ COPY --from=builder /usr/app/out/full/ . RUN turbo run build -FROM base AS runner +FROM node:22-alpine AS runner WORKDIR /usr/app # Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs -USER nextjs # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer --chown=nextjs:nodejs /usr/app/ ./ +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/.next/static ./apps/dispatch/.next/static +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/dispatch/public ./apps/dispatch/public + +USER nextjs # Expose the application port -EXPOSE 3001 +EXPOSE 3000 -CMD ["pnpm", "--dir", "apps/dispatch", "run", "start"] \ No newline at end of file +CMD ["node", "apps/dispatch/server.js"] \ No newline at end of file diff --git a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx index f1450f19..039d7ac2 100644 --- a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx +++ b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx @@ -14,7 +14,7 @@ export const ConnectionBtn = () => { const connection = useDispatchConnectionStore((state) => state); const [form, setForm] = useState({ logoffTime: "", - selectedZone: "LST_01", + selectedZone: "VAR_LST_RD_01", ghostMode: false, }); const changeDispatcherMutation = useMutation({ diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx new file mode 100644 index 00000000..169b7d24 --- /dev/null +++ b/apps/dispatch/app/(app)/pilot/_components/mrt/Base.tsx @@ -0,0 +1,29 @@ +import { useEffect } from "react"; // ...existing code... +import { useMrtStore } from "_store/pilot/MrtStore"; +import Image from "next/image"; +import DAY_BASE_IMG from "./images/Base_NoScreen_Day.png"; +import NIGHT_BASE_IMG from "./images/Base_NoScreen_Night.png"; + +export const MrtBase = () => { + const { nightMode, setNightMode, page } = useMrtStore((state) => state); + + useEffect(() => { + const checkNightMode = () => { + const currentHour = new Date().getHours(); + setNightMode(currentHour >= 22 || currentHour < 8); + }; + + checkNightMode(); // Initial check + const intervalId = setInterval(checkNightMode, 60000); // Check every minute + + return () => clearInterval(intervalId); // Cleanup on unmount + }, [setNightMode]); // ...existing code... + + return ( + + ); +}; diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png deleted file mode 100644 index a9c552b1..00000000 Binary files a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT.png and /dev/null differ diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png b/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png deleted file mode 100644 index a0e80ae6..00000000 Binary files a/apps/dispatch/app/(app)/pilot/_components/mrt/MRT_MESSAGE.png and /dev/null differ diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx index 5d271921..0fda6281 100644 --- a/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx +++ b/apps/dispatch/app/(app)/pilot/_components/mrt/Mrt.tsx @@ -1,22 +1,9 @@ import { CSSProperties } from "react"; -import MrtImage from "./MRT.png"; -import MrtMessageImage from "./MRT_MESSAGE.png"; -import { useButtons } from "./useButtons"; -import { useSounds } from "./useSounds"; import "./mrt.css"; -import Image from "next/image"; -import { useMrtStore } from "_store/pilot/MrtStore"; - -const MRT_BUTTON_STYLES: CSSProperties = { - cursor: "pointer", - zIndex: "9999", - backgroundColor: "transparent", - border: "none", -}; -const MRT_DISPLAYLINE_STYLES: CSSProperties = { - color: "white", - zIndex: 1, -}; +import { MrtBase } from "./Base"; +import { MrtDisplay } from "./MrtDisplay"; +import { MrtButtons } from "./MrtButtons"; +import { MrtPopups } from "./MrtPopups"; export interface DisplayLineProps { lineStyle?: CSSProperties; @@ -27,45 +14,7 @@ export interface DisplayLineProps { textSize: "1" | "2" | "3" | "4"; } -const DisplayLine = ({ - style = {}, - textLeft, - textMid, - textRight, - textSize, - lineStyle, -}: DisplayLineProps) => { - const INNER_TEXT_PARTS: CSSProperties = { - fontFamily: "Melder", - flex: "1", - flexBasis: "auto", - overflowWrap: "break-word", - ...lineStyle, - }; - - return ( -
- {textLeft} - {textMid} - {textRight} -
- ); -}; - export const Mrt = () => { - useSounds(); - const { handleButton } = useButtons(); - const { lines, page } = useMrtStore((state) => state); - return (
{ maxHeight: "100%", maxWidth: "100%", color: "white", - gridTemplateColumns: "21.83% 4.43% 24.42% 18.08% 5.93% 1.98% 6.00% 1.69% 6.00% 9.35%", - gridTemplateRows: "21.58% 11.87% 3.55% 5.00% 6.84% 0.53% 3.03% 11.84% 3.55% 11.84% 20.39%", + gridTemplateColumns: + "9.75% 4.23% 8.59% 7.30% 1.16% 7.30% 1.23% 7.16% 1.09% 7.30% 3.68% 4.23% 5.59% 6.07% 1.91% 6.07% 1.84% 6.21% 9.28%", + gridTemplateRows: + "21.55% 11.83% 3.55% 2.50% 9.46% 2.76% 0.66% 4.99% 6.83% 3.55% 1.97% 9.99% 4.20% 11.04% 5.12%", }} > - {page !== "sds" && ( - MrtImage - )} - {page === "sds" && ( - MrtImage-Message - )} - -
); }; diff --git a/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx b/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx new file mode 100644 index 00000000..a7942466 --- /dev/null +++ b/apps/dispatch/app/(app)/pilot/_components/mrt/MrtButtons.tsx @@ -0,0 +1,150 @@ +import { CSSProperties, useRef } from "react"; +import { useButtons } from "./useButtons"; + +const MRT_BUTTON_STYLES: CSSProperties = { + cursor: "pointer", + zIndex: "9999", + backgroundColor: "transparent", + border: "none", +}; + +interface MrtButtonProps { + onClick: () => void; + onHold?: () => void; + style: CSSProperties; +} + +const MrtButton = ({ onClick, onHold, style }: MrtButtonProps) => { + const timeoutRef = useRef(null); + + const handleMouseDown = () => { + if (!onHold) return; + timeoutRef.current = setTimeout(handleTimeoutExpired, 500); + }; + + const handleTimeoutExpired = () => { + timeoutRef.current = null; + if (onHold) { + onHold(); + } + }; + + const handleMouseUp = () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + onClick(); + } + }; + + return ( + ))} diff --git a/apps/dispatch/app/_components/QueryProvider.tsx b/apps/dispatch/app/_components/QueryProvider.tsx index d5b2799a..345d2fb1 100644 --- a/apps/dispatch/app/_components/QueryProvider.tsx +++ b/apps/dispatch/app/_components/QueryProvider.tsx @@ -63,14 +63,15 @@ export function QueryProvider({ children }: { children: ReactNode }) { }; const handleNotification = (notification: NotificationPayload) => { + console.log("Received notification:", notification); const playNotificationSound = () => { if (notificationSound.current) { - notificationSound.current.currentTime = 0; - notificationSound.current - .play() - .catch((e) => console.error("Notification sound error:", e)); - } - } + notificationSound.current.currentTime = 0; + notificationSound.current + .play() + .catch((e) => console.error("Notification sound error:", e)); + } + }; switch (notification.type) { case "hpg-validation": @@ -90,6 +91,7 @@ export function QueryProvider({ children }: { children: ReactNode }) { }); break; case "station-status": + console.log("station Status", QUICK_RESPONSE[notification.status]); if (!QUICK_RESPONSE[notification.status]) return; toast.custom((e) => , { duration: 60000, @@ -106,7 +108,7 @@ export function QueryProvider({ children }: { children: ReactNode }) { break; case "mission-closed": toast("Dein aktueller Einsatz wurde geschlossen."); - + break; default: toast("unbekanntes Notification-Event"); diff --git a/apps/dispatch/app/_components/customToasts/StationStatusToast.tsx b/apps/dispatch/app/_components/customToasts/StationStatusToast.tsx index 0b163e79..a3d3b64a 100644 --- a/apps/dispatch/app/_components/customToasts/StationStatusToast.tsx +++ b/apps/dispatch/app/_components/customToasts/StationStatusToast.tsx @@ -1,14 +1,16 @@ -import { Prisma, StationStatus } from "@repo/db"; +import { getPublicUser, MissionSdsStatusLog, StationStatus } from "@repo/db"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { BaseNotification } from "_components/customToasts/BaseNotification"; import { FMS_STATUS_COLORS } from "_helpers/fmsStatusColors"; -import { editConnectedAircraftAPI, getConnectedAircraftsAPI } from "_querys/aircrafts"; +import { getConnectedAircraftsAPI } from "_querys/aircrafts"; import { getLivekitRooms } from "_querys/livekit"; +import { sendSdsStatusMessageAPI } from "_querys/missions"; import { getStationsAPI } from "_querys/stations"; import { useAudioStore } from "_store/audioStore"; import { useMapStore } from "_store/mapStore"; import { X } from "lucide-react"; -import { useEffect, useRef, useState } from "react"; +import { useSession } from "next-auth/react"; +import { useEffect, useRef } from "react"; import { Toast, toast } from "react-hot-toast"; export const QUICK_RESPONSE: Record = { @@ -22,6 +24,8 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => const status5Sounds = useRef(null); const status9Sounds = useRef(null); + const session = useSession(); + const { data: livekitRooms } = useQuery({ queryKey: ["livekit-rooms"], queryFn: () => getLivekitRooms(), @@ -46,7 +50,7 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => status9Sounds.current = new Audio("/sounds/status-9.mp3"); } }, []); - const [aircraftDataAcurate, setAircraftDataAccurate] = useState(false); + //const mapStore = useMapStore((s) => s); const { setOpenAircraftMarker, setMap } = useMapStore((store) => store); @@ -65,29 +69,16 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => const station = stations?.find((s) => s.id === event.data?.stationId); const queryClient = useQueryClient(); - const changeAircraftMutation = useMutation({ - mutationFn: async ({ - id, - update, - }: { - id: number; - update: Prisma.ConnectedAircraftUpdateInput; - }) => { - await editConnectedAircraftAPI(id, update); + const sendSdsStatusMutation = useMutation({ + mutationFn: async ({ sdsMessage }: { sdsMessage: MissionSdsStatusLog }) => { + if (!connectedAircraft?.id) throw new Error("No connected aircraft"); + await sendSdsStatusMessageAPI({ sdsMessage, aircraftId: connectedAircraft?.id }); queryClient.invalidateQueries({ - queryKey: ["aircrafts"], + queryKey: ["missions"], }); }, }); - useEffect(() => { - if (event.status !== connectedAircraft?.fmsStatus && aircraftDataAcurate) { - toast.remove(t.id); - } else if (event.status == connectedAircraft?.fmsStatus && !aircraftDataAcurate) { - setAircraftDataAccurate(true); - } - }, [aircraftDataAcurate, connectedAircraft, event.status, t.id]); - useEffect(() => { let soundRef: React.RefObject | null = null; switch (event.status) { @@ -103,7 +94,8 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => default: soundRef = null; } - if (audioRoom !== livekitUser?.roomName) { + + if (audioRoom && livekitUser?.roomName && audioRoom !== livekitUser?.roomName) { toast.remove(t.id); return; } @@ -121,7 +113,8 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => }; }, [event.status, livekitUser?.roomName, audioRoom, t.id]); - if (!connectedAircraft || !station) return null; + console.log(connectedAircraft, station); + if (!connectedAircraft || !station || !session.data) return null; return (
@@ -162,10 +155,18 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) => toast.error("Keine Flugzeug-ID gefunden"); return; } - await changeAircraftMutation.mutateAsync({ - id: event.data?.aircraftId, - update: { - fmsStatus: status, + await sendSdsStatusMutation.mutateAsync({ + sdsMessage: { + type: "sds-status-log", + auto: false, + data: { + direction: "to-aircraft", + stationId: event.data.stationId!, + station: station, + user: getPublicUser(session.data?.user), + status, + }, + timeStamp: new Date().toISOString(), }, }); toast.remove(t.id); diff --git a/apps/dispatch/app/_components/map/AircraftMarker.tsx b/apps/dispatch/app/_components/map/AircraftMarker.tsx index 9c0adaf3..3961690d 100644 --- a/apps/dispatch/app/_components/map/AircraftMarker.tsx +++ b/apps/dispatch/app/_components/map/AircraftMarker.tsx @@ -2,7 +2,7 @@ import { Marker, Polyline, useMap } from "react-leaflet"; import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet"; import { useMapStore } from "_store/mapStore"; import { Fragment, useCallback, useEffect, useRef, useState, useMemo } from "react"; -import { checkSimulatorConnected, cn } from "@repo/shared-components"; +import { cn } from "@repo/shared-components"; import { ChevronsRightLeft, House, MessageSquareText, Minimize2 } from "lucide-react"; import { SmartPopup, calculateAnchor, useSmartPopup } from "_components/SmartPopup"; import FMSStatusHistory, { @@ -396,27 +396,11 @@ const AircraftMarker = ({ aircraft }: { aircraft: ConnectedAircraft & { Station: }; export const AircraftLayer = () => { - const [aircrafts, setAircrafts] = useState<(ConnectedAircraft & { Station: Station })[]>([]); - - useEffect(() => { - const fetchAircrafts = async () => { - try { - const res = await fetch("/api/aircrafts"); - if (!res.ok) { - throw new Error("Failed to fetch aircrafts"); - } - const data: (ConnectedAircraft & { Station: Station })[] = await res.json(); - setAircrafts(data.filter((a) => checkSimulatorConnected(a))); - } catch (error) { - console.error("Failed to fetch aircrafts:", error); - } - }; - - fetchAircrafts(); - const interval = setInterval(fetchAircrafts, 10_000); - - return () => clearInterval(interval); - }, []); + const { data: aircrafts } = useQuery({ + queryKey: ["connected-aircrafts", "map"], + queryFn: () => getConnectedAircraftsAPI(), + refetchInterval: 15000, + }); const { setMap } = useMapStore((state) => state); const map = useMap(); const { diff --git a/apps/dispatch/app/_components/map/_components/AircraftMarkerTabs.tsx b/apps/dispatch/app/_components/map/_components/AircraftMarkerTabs.tsx index 97e529ab..0dae2e20 100644 --- a/apps/dispatch/app/_components/map/_components/AircraftMarkerTabs.tsx +++ b/apps/dispatch/app/_components/map/_components/AircraftMarkerTabs.tsx @@ -9,6 +9,7 @@ import { Mission, MissionLog, MissionSdsLog, + MissionSdsStatusLog, MissionStationLog, Prisma, PublicUser, @@ -40,7 +41,7 @@ import { TextSearch, } from "lucide-react"; import { useSession } from "next-auth/react"; -import { sendSdsMessageAPI } from "_querys/missions"; +import { sendSdsMessageAPI, sendSdsStatusMessageAPI } from "_querys/missions"; import { getLivekitRooms } from "_querys/livekit"; import { findLeitstelleForPosition } from "_helpers/findLeitstelleinPoint"; import { formatDistance } from "date-fns"; @@ -54,9 +55,13 @@ const FMSStatusHistory = ({ mission?: Mission; }) => { const log = ((mission?.missionLog as unknown as MissionLog[]) || []) - .filter((entry) => entry.type === "station-log" && entry.data.stationId === aircraft.Station.id) + .filter( + (entry) => + (entry.type === "station-log" || entry.type == "sds-status-log") && + entry.data.stationId === aircraft.Station.id, + ) .reverse() - .splice(0, 6) as MissionStationLog[]; + .splice(0, 6) as (MissionStationLog | MissionSdsStatusLog)[]; const aircraftUser: PublicUser = typeof aircraft.publicUser === "string" ? JSON.parse(aircraft.publicUser) : aircraft.publicUser; @@ -103,10 +108,13 @@ const FMSStatusHistory = ({ - {entry.data.newFMSstatus} + {entry.type === "sds-status-log" ? entry.data.status : entry.data.newFMSstatus} {new Date(entry.timeStamp).toLocaleTimeString([], { @@ -126,6 +134,7 @@ const FMSStatusSelector = ({ }: { aircraft: ConnectedAircraft & { Station: Station }; }) => { + const session = useSession(); const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected"; const [hoveredStatus, setHoveredStatus] = useState(null); const queryClient = useQueryClient(); @@ -144,6 +153,20 @@ const FMSStatusSelector = ({ }, }); + const sendSdsStatusMutation = useMutation({ + mutationFn: async ({ sdsMessage }: { sdsMessage: MissionSdsStatusLog }) => { + if (!aircraft?.id) throw new Error("No connected aircraft"); + await sendSdsStatusMessageAPI({ sdsMessage, aircraftId: aircraft?.id }); + queryClient.invalidateQueries({ + queryKey: ["missions"], + }); + }, + }); + + if (!session.data?.user) { + return null; + } + return (
@@ -213,12 +236,21 @@ const FMSStatusSelector = ({ onMouseEnter={() => setHoveredStatus(status)} onMouseLeave={() => setHoveredStatus(null)} onClick={async () => { - await changeAircraftMutation.mutateAsync({ - id: aircraft.id, - update: { - fmsStatus: status, + await sendSdsStatusMutation.mutateAsync({ + sdsMessage: { + type: "sds-status-log", + auto: false, + timeStamp: new Date().toISOString(), + data: { + status: status, + direction: "to-aircraft", + stationId: aircraft.Station.id, + station: aircraft.Station, + user: getPublicUser(session.data?.user), + }, }, }); + toast.success(`SDS Status ${status} gesendet`); }} > {status} @@ -378,7 +410,9 @@ const SDSTab = ({ ?.slice() .reverse() .filter( - (entry) => entry.type === "sds-log" && entry.data.stationId === aircraft.Station.id, + (entry) => + (entry.type === "sds-log" || entry.type == "sds-status-log") && + entry.data.stationId === aircraft.Station.id, ) || [], [mission?.missionLog, aircraft.Station.id], ); @@ -471,7 +505,7 @@ const SDSTab = ({ )}
    {log.map((entry, index) => { - const sdsEntry = entry as MissionSdsLog; + const sdsEntry = entry as MissionSdsLog | MissionSdsStatusLog; return (
  • @@ -489,7 +523,9 @@ const SDSTab = ({ {sdsEntry.data.user.firstname?.[0]?.toUpperCase() ?? "?"} {sdsEntry.data.user.lastname?.[0]?.toUpperCase() ?? "?"} - {sdsEntry.data.message} + + {sdsEntry.type == "sds-log" ? sdsEntry.data.message : sdsEntry.data.status} +
  • ); })} diff --git a/apps/dispatch/app/_components/map/_components/MissionMarkerTabs.tsx b/apps/dispatch/app/_components/map/_components/MissionMarkerTabs.tsx index dcb042e1..a02ef87c 100644 --- a/apps/dispatch/app/_components/map/_components/MissionMarkerTabs.tsx +++ b/apps/dispatch/app/_components/map/_components/MissionMarkerTabs.tsx @@ -726,7 +726,11 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => { {entry.data.station.bosCallsign} ); - if (entry.type === "message-log" || entry.type === "sds-log") + if ( + entry.type === "message-log" || + entry.type === "sds-log" || + entry.type === "sds-status-log" + ) return (
  • @@ -741,9 +745,10 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => { color: FMS_STATUS_TEXT_COLORS[6], }} > - {entry.data.user.firstname?.[0]?.toUpperCase() ?? "?"} - {entry.data.user.lastname?.[0]?.toUpperCase() ?? "?"} - {entry.type === "sds-log" && ( + {entry.type == "sds-status-log" && entry.data.direction == "to-lst" + ? entry.data.station.bosCallsignShort + : `${entry.data.user.firstname?.[0]?.toUpperCase() ?? "?"}${entry.data.user.lastname?.[0]?.toUpperCase() ?? "?"}`} + {(entry.type === "sds-log" || entry.type === "sds-status-log") && ( <> { /> - {entry.data.station.bosCallsignShort} + {entry.type == "sds-status-log" && entry.data.direction == "to-aircraft" + ? entry.data.station.bosCallsignShort + : "LST"} )} - {entry.data.message} + + {entry.type === "sds-log" || entry.type === "message-log" + ? entry.data.message + : entry.data.status} +
  • ); if ( diff --git a/apps/dispatch/app/_data/fmsStatusDescription.ts b/apps/dispatch/app/_data/fmsStatusDescription.ts index 3ca69b0c..c83c4551 100644 --- a/apps/dispatch/app/_data/fmsStatusDescription.ts +++ b/apps/dispatch/app/_data/fmsStatusDescription.ts @@ -24,3 +24,30 @@ export const fmsStatusDescription: { [key: string]: string } = { o: "Warten, alle Abfrageplätze belegt", u: "Verstanden", }; + +export const fmsStatusDescriptionShort: { [key: string]: string } = { + NaN: "Keine D.", + "0": "Prio. Sprechen", + "1": "E.-bereit Funk", + "2": "E.-bereit Wache", + "3": "E.-übernahme", + "4": "Einsatzort", + "5": "Sprechwunsch", + "6": "Nicht e.-bereit", + "7": "Einsatzgeb.", + "8": "Bed. Verfügbar", + "9": "F-anmeldung", + E: "Einsatzabbruch", + C: "Melden Sie Einsatzübernahme", + F: "Kommen Sie über Draht", + H: "Fahren Sie Wache an", + J: "Sprechen Sie", + L: "Geben Sie Lagemeldung", + P: "Einsatz mit Polizei", + U: "Ungültige Statusfolge", + c: "Status korrigieren", + d: "Nennen Sie Transportziel", + h: "Zielklinik verständigt", + o: "Warten, alle Abfrageplätze belegt", + u: "Verstanden", +}; diff --git a/apps/dispatch/app/_data/livekitRooms.ts b/apps/dispatch/app/_data/livekitRooms.ts index 1bbb1ae0..f98a61aa 100644 --- a/apps/dispatch/app/_data/livekitRooms.ts +++ b/apps/dispatch/app/_data/livekitRooms.ts @@ -1 +1,7 @@ -export const ROOMS = ["LST_01", "LST_02", "LST_03", "LST_04", "LST_05"]; +export const ROOMS = [ + { name: "VAR_LST_RD_01", id: "2201" }, + { name: "VAR_LST_RD_02", id: "2202" }, + { name: "VAR_LST_RD_03", id: "2203" }, + { name: "VAR_LST_RD_04", id: "2204" }, + { name: "VAR_LST_RD_05", id: "2205" }, +]; diff --git a/apps/dispatch/app/_querys/missions.ts b/apps/dispatch/app/_querys/missions.ts index 240591c1..bab144c4 100644 --- a/apps/dispatch/app/_querys/missions.ts +++ b/apps/dispatch/app/_querys/missions.ts @@ -1,4 +1,4 @@ -import { Mission, MissionSdsLog, Prisma } from "@repo/db"; +import { Mission, MissionSdsLog, MissionSdsStatusLog, Prisma } from "@repo/db"; import axios from "axios"; import { serverApi } from "_helpers/axios"; @@ -29,6 +29,20 @@ export const editMissionAPI = async (id: number, mission: Prisma.MissionUpdateIn const respone = await serverApi.patch(`/mission/${id}`, mission); return respone.data; }; + +export const sendSdsStatusMessageAPI = async ({ + sdsMessage, + aircraftId, +}: { + aircraftId: number; + sdsMessage: MissionSdsStatusLog; +}) => { + const respone = await serverApi.post(`/aircrafts/${aircraftId}/send-sds-message`, { + sdsMessage, + }); + return respone.data; +}; + export const sendSdsMessageAPI = async ({ missionId, sdsMessage, diff --git a/apps/dispatch/app/_store/audioStore.ts b/apps/dispatch/app/_store/audioStore.ts index 7ce25c64..72aabd9f 100644 --- a/apps/dispatch/app/_store/audioStore.ts +++ b/apps/dispatch/app/_store/audioStore.ts @@ -21,12 +21,13 @@ import { useDispatchConnectionStore } from "_store/dispatch/connectionStore"; import { changeDispatcherAPI } from "_querys/dispatcher"; import { getRadioStream } from "_helpers/radioEffect"; import { usePilotConnectionStore } from "_store/pilot/connectionStore"; +import { ROOMS } from "_data/livekitRooms"; let interval: NodeJS.Timeout; type TalkState = { addSpeakingParticipant: (participant: Participant) => void; - connect: (roomName: string, role: string) => void; + connect: (room: (typeof ROOMS)[number] | undefined, role: string) => void; connectionQuality: ConnectionQuality; disconnect: () => void; isTalking: boolean; @@ -44,6 +45,8 @@ type TalkState = { radioVolume: number; dmeVolume: number; }; + selectedRoom?: (typeof ROOMS)[number]; + setSelectedRoom: (room: (typeof ROOMS)[number]) => void; speakingParticipants: Participant[]; state: "connecting" | "connected" | "disconnected" | "error"; toggleTalking: () => void; @@ -72,6 +75,10 @@ export const useAudioStore = create((set, get) => ({ remoteParticipants: 0, connectionQuality: ConnectionQuality.Unknown, room: null, + selectedRoom: ROOMS[0], + setSelectedRoom: (room) => { + set({ selectedRoom: room }); + }, resetSpeakingParticipants: (source: string) => { set({ speakingParticipants: [], @@ -117,11 +124,11 @@ export const useAudioStore = create((set, get) => ({ (oldSettings.micDeviceId !== newSettings.micDeviceId || oldSettings.micVolume !== newSettings.micVolume) ) { - const { room, disconnect, connect } = get(); + const { room, disconnect, connect, selectedRoom } = get(); const role = room?.localParticipant.attributes.role; - if (room?.name || role) { + if (selectedRoom || role) { disconnect(); - connect(room?.name || "", role || "user"); + connect(selectedRoom, role || "user"); } } }, @@ -160,7 +167,7 @@ export const useAudioStore = create((set, get) => ({ set((state) => ({ isTalking: !state.isTalking, transmitBlocked: false })); }, - connect: async (roomName, role) => { + connect: async (_room, role) => { set({ state: "connecting" }); try { @@ -172,13 +179,16 @@ export const useAudioStore = create((set, get) => ({ connectedRoom.removeAllListeners(); } + const { selectedRoom } = get(); + const url = process.env.NEXT_PUBLIC_LIVEKIT_URL; if (!url) return console.error("NEXT_PUBLIC_LIVEKIT_URL not set"); - const token = await getToken(roomName); + const token = await getToken(_room?.name || selectedRoom?.name || "VAR_LST_RD_01"); if (!token) throw new Error("Fehlende Berechtigung"); const room = new Room({}); await room.prepareConnection(url, token); + const roomConnectedSound = new Audio("/sounds/403.wav"); room // Connection events .on(RoomEvent.Connected, async () => { @@ -186,7 +196,7 @@ export const useAudioStore = create((set, get) => ({ if (dispatchState.status === "connected" && dispatchState.connectedDispatcher?.id) { changeDispatcherAPI(dispatchState.connectedDispatcher?.id, { - zone: roomName, + zone: _room?.name || selectedRoom?.name || "VAR_LST_RD_01", ghostMode: dispatchState.ghostMode, }); } @@ -208,7 +218,7 @@ export const useAudioStore = create((set, get) => ({ source: Track.Source.Microphone, }); await publishedTrack.mute(); - + roomConnectedSound.play(); set({ localRadioTrack: publishedTrack }); set({ state: "connected", room, isTalking: false, message: null }); diff --git a/apps/dispatch/app/_store/dispatch/connectionStore.ts b/apps/dispatch/app/_store/dispatch/connectionStore.ts index c7a646aa..9663e473 100644 --- a/apps/dispatch/app/_store/dispatch/connectionStore.ts +++ b/apps/dispatch/app/_store/dispatch/connectionStore.ts @@ -27,7 +27,7 @@ export const useDispatchConnectionStore = create((set) => ({ setHideDraftMissions: (hide) => set({ hideDraftMissions: hide }), connectedDispatcher: null, message: "", - selectedZone: "LST_01", + selectedZone: "VAR_LST_RD_01", logoffTime: "", ghostMode: false, connect: async (uid, selectedZone, logoffTime, ghostMode) => @@ -48,7 +48,7 @@ export const useDispatchConnectionStore = create((set) => ({ dispatchSocket.on("connect", () => { const { logoffTime, selectedZone, ghostMode } = useDispatchConnectionStore.getState(); - useAudioStore.getState().connect("LST_01", selectedZone || "Leitstelle"); + useAudioStore.getState().connect(undefined, selectedZone || "Leitstelle"); dispatchSocket.emit("connect-dispatch", { logoffTime, selectedZone, diff --git a/apps/dispatch/app/_store/pilot/MrtStore.ts b/apps/dispatch/app/_store/pilot/MrtStore.ts index 3678f49a..f8432402 100644 --- a/apps/dispatch/app/_store/pilot/MrtStore.ts +++ b/apps/dispatch/app/_store/pilot/MrtStore.ts @@ -1,173 +1,92 @@ -import { MissionSdsLog, Station } from "@repo/db"; -import { fmsStatusDescription } from "_data/fmsStatusDescription"; -import { DisplayLineProps } from "(app)/pilot/_components/mrt/Mrt"; import { create } from "zustand"; -import { syncTabs } from "zustand-sync-tabs"; -interface SetSdsPageParams { - page: "sds"; - station: Station; - sdsMessage: MissionSdsLog; +interface SetOffPageParams { + page: "off"; +} + +interface SetStartupPageParams { + page: "startup"; } interface SetHomePageParams { page: "home"; - station: Station; - fmsStatus: string; } -interface SetSendingStatusPageParams { - page: "sending-status"; - station: Station; +interface SetVoicecallPageParams { + page: "voice-call"; +} +interface SetSdsReceivedPopupParams { + popup: "sds-received"; } -interface SetNewStatusPageParams { - page: "new-status"; - station: Station; +interface SetGroupSelectionPopupParams { + popup: "group-selection"; } -type SetPageParams = +interface SetStatusSentPopupParams { + popup: "status-sent"; +} + +interface SetLoginPopupParams { + popup: "login"; +} + +interface SetSdsSentPopupParams { + popup: "sds-sent"; +} + +export type SetPageParams = | SetHomePageParams - | SetSendingStatusPageParams - | SetSdsPageParams - | SetNewStatusPageParams; + | SetOffPageParams + | SetStartupPageParams + | SetVoicecallPageParams; + +export type SetPopupParams = + | SetStatusSentPopupParams + | SetSdsSentPopupParams + | SetGroupSelectionPopupParams + | SetSdsReceivedPopupParams + | SetLoginPopupParams; + +interface StringifiedData { + sdsText?: string; + sentSdsText?: string; + + groupSelectionGroupId?: string; + callTextHeader?: string; +} interface MrtStore { page: SetPageParams["page"]; + popup?: SetPopupParams["popup"]; - lines: DisplayLineProps[]; + stringifiedData: StringifiedData; + setStringifiedData: (data: Partial) => void; setPage: (pageData: SetPageParams) => void; - setLines: (lines: MrtStore["lines"]) => void; + setPopup: (popupData: SetPopupParams | null) => void; + + // internal + updateIntervall?: number; + nightMode: boolean; + setNightMode: (nightMode: boolean) => void; } -export const useMrtStore = create( - syncTabs( - (set) => ({ - page: "home", - pageData: { - message: "", - }, - lines: [ - { - textLeft: "VAR.#", - textSize: "2", - }, - { - textLeft: "No Data", - textSize: "3", - }, - ], - setLines: (lines) => set({ lines }), - setPage: (pageData) => { - switch (pageData.page) { - case "home": { - const { station, fmsStatus } = pageData as SetHomePageParams; - set({ - page: "home", - lines: [ - { - textLeft: `${station?.bosCallsign}`, - style: { fontWeight: "bold" }, - textSize: "2", - }, - { textLeft: "ILS VAR#", textSize: "3" }, - { - textLeft: fmsStatus, - style: { fontWeight: "extrabold" }, - textSize: "4", - }, - { - textLeft: fmsStatusDescription[fmsStatus], - textSize: "1", - }, - ], - }); - break; - } - - case "sending-status": { - const { station } = pageData as SetSendingStatusPageParams; - set({ - page: "sending-status", - lines: [ - { - textLeft: `${station?.bosCallsign}`, - style: { fontWeight: "bold" }, - textSize: "2", - }, - { textLeft: "ILS VAR#", textSize: "3" }, - { - textMid: "sending...", - style: { fontWeight: "bold" }, - textSize: "4", - }, - { - textLeft: "Status wird gesendet...", - textSize: "1", - }, - ], - }); - break; - } - case "new-status": { - const { station } = pageData as SetNewStatusPageParams; - set({ - page: "new-status", - lines: [ - { - textLeft: `${station?.bosCallsign}`, - style: { fontWeight: "bold" }, - textSize: "2", - }, - { textLeft: "ILS VAR#", textSize: "3" }, - { - textLeft: "empfangen", - style: { fontWeight: "bold" }, - textSize: "4", - }, - ], - }); - break; - } - case "sds": { - const { sdsMessage } = pageData as SetSdsPageParams; - const msg = sdsMessage.data.message; - set({ - page: "sds", - lines: [ - { - textLeft: `SDS-Nachricht`, - style: { fontWeight: "bold" }, - textSize: "2", - }, - { - textLeft: msg, - style: { - whiteSpace: "normal", - overflowWrap: "break-word", - wordBreak: "break-word", - display: "block", - maxWidth: "100%", - maxHeight: "100%", - overflow: "auto", - textOverflow: "ellipsis", - lineHeight: "1.2em", - }, - textSize: "2", - }, - ], - }); - break; - } - default: - set({ page: "home" }); - break; - } - }, - }), - { - name: "mrt-store", // unique name - }, - ), -); +export const useMrtStore = create((set) => ({ + page: "off", + nightMode: false, + stringifiedData: { + groupSelectionGroupId: "2201", + }, + setNightMode: (nightMode) => set({ nightMode }), + setStringifiedData: (data) => + set((state) => ({ + stringifiedData: { ...state.stringifiedData, ...data }, + })), + setPopup: (popupData) => { + set({ popup: popupData ? popupData.popup : undefined }); + }, + setPage: (pageData) => { + set({ page: pageData.page }); + }, +})); diff --git a/apps/dispatch/app/_store/pilot/connectionStore.ts b/apps/dispatch/app/_store/pilot/connectionStore.ts index e9fc29f8..1ca44645 100644 --- a/apps/dispatch/app/_store/pilot/connectionStore.ts +++ b/apps/dispatch/app/_store/pilot/connectionStore.ts @@ -86,7 +86,7 @@ pilotSocket.on("connect", () => { usePilotConnectionStore.setState({ status: "connected", message: "" }); const { logoffTime, selectedStation, debug } = usePilotConnectionStore.getState(); dispatchSocket.disconnect(); - useAudioStore.getState().connect("LST_01", selectedStation?.bosCallsignShort || "pilot"); + useAudioStore.getState().connect(undefined, selectedStation?.bosCallsignShort || "pilot"); pilotSocket.emit("connect-pilot", { logoffTime, @@ -109,7 +109,7 @@ pilotSocket.on("connect-message", (data) => { }); pilotSocket.on("disconnect", () => { - usePilotConnectionStore.setState({ status: "disconnected" }); + usePilotConnectionStore.setState({ status: "disconnected", connectedAircraft: null }); useAudioStore.getState().disconnect(); }); @@ -142,11 +142,13 @@ pilotSocket.on("mission-alert", (data: Mission & { Stations: Station[] }) => { }); pilotSocket.on("sds-message", (sdsMessage: MissionSdsLog) => { + console.log("Received sds-message via socket:", sdsMessage); const station = usePilotConnectionStore.getState().selectedStation; if (!station) return; - useMrtStore.getState().setPage({ - page: "sds", - station, - sdsMessage, + useMrtStore.getState().setPopup({ + popup: "sds-received", + }); + useMrtStore.getState().setStringifiedData({ + sdsText: sdsMessage.data.message, }); }); diff --git a/apps/dispatch/app/_store/pilot/dmeStore.ts b/apps/dispatch/app/_store/pilot/dmeStore.ts index bf17fb77..19b81b4a 100644 --- a/apps/dispatch/app/_store/pilot/dmeStore.ts +++ b/apps/dispatch/app/_store/pilot/dmeStore.ts @@ -1,7 +1,6 @@ import { Mission, Station, User } from "@repo/db"; import { DisplayLineProps } from "(app)/pilot/_components/dme/Dme"; import { create } from "zustand"; -import { syncTabs } from "zustand-sync-tabs"; interface SetHomePageParams { page: "home"; @@ -45,197 +44,190 @@ interface MrtStore { let interval: NodeJS.Timeout | null = null; -export const useDmeStore = create( - syncTabs( - (set) => ({ - page: "home", - pageData: { - message: "", - }, - lines: [ - { - textLeft: "", - }, - { - textMid: "VAR . DME# No Data", - textSize: "2", - }, - { - textLeft: "", - }, - ], - setLines: (lines) => set({ lines }), - latestMission: null, - setPage: (pageData) => { - if (interval) clearInterval(interval); - switch (pageData.page) { - case "home": { - const setHomePage = () => - set({ - page: "home", - lines: [ - { - textMid: pageData.station.bosCallsign - ? `${pageData.station.bosCallsign}` - : "no Data", - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - { - textMid: new Date().toLocaleDateString("de-DE", { - year: "numeric", - month: "2-digit", - day: "2-digit", - }), - }, - { - textMid: new Date().toLocaleTimeString(), - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - { - textMid: `${pageData.user.lastname} ${pageData.user.firstname}`, - }, - { textMid: "⠀" }, - ], - }); - setHomePage(); - - interval = setInterval(() => { - setHomePage(); - }, 1000); - break; - } - - case "new-mission": { - set({ - page: "new-mission", - lines: [ - { textMid: "⠀" }, - { - textMid: "new mission received", - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - ], - }); - break; - } - case "mission": { - set({ - latestMission: pageData.mission, - page: "mission", - lines: [ - { - textLeft: `${pageData.mission.missionKeywordAbbreviation}`, - textRight: pageData.mission.Stations.map((s) => s.bosCallsignShort).join(","), - style: { fontWeight: "bold" }, - }, - ...(pageData.mission.type == "primär" - ? [ - { - textMid: `${pageData.mission.missionKeywordName}`, - style: { fontWeight: "bold" }, - }, - ] - : []), - - { textLeft: `${pageData.mission.addressStreet}` }, - { - textLeft: `${pageData.mission.addressZip} ${pageData.mission.addressCity}`, - }, - { - textMid: "Weitere Standortinformationen:", - style: { fontWeight: "bold" }, - }, - { - textLeft: pageData.mission.addressAdditionalInfo || "keine Daten", - }, - ...(pageData.mission.type === "sekundär" - ? [ - { - textMid: "Zielort:", - style: { fontWeight: "bold" }, - }, - { - textLeft: pageData.mission.addressMissionDestination || "keine Daten", - }, - ] - : []), - ...(pageData.mission.missionPatientInfo && - pageData.mission.missionPatientInfo.length > 0 - ? [ - { - textMid: "Patienteninfos:", - style: { fontWeight: "bold" }, - }, - { - textLeft: pageData.mission.missionPatientInfo, - }, - ] - : []), - ...(pageData.mission.missionAdditionalInfo && - pageData.mission.missionAdditionalInfo.length > 0 - ? [ - { - textMid: "Weitere Infos:", - style: { fontWeight: "bold" }, - }, - { - textLeft: pageData.mission.missionAdditionalInfo, - }, - ] - : []), - ], - }); - break; - } - case "error": { - set({ - page: "error", - lines: [ - { textMid: "Fehler:" }, - { - textMid: pageData.error, - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - ], - }); - break; - } - case "acknowledge": { - set({ - page: "acknowledge", - lines: [ - { textMid: "⠀" }, - { - textMid: "Einsatz angenommen", - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - ], - }); - break; - } - default: - set({ - page: "error", - lines: [ - { textMid: "Fehler:" }, - { - textMid: `Unbekannte Seite`, - style: { fontWeight: "bold" }, - }, - { textMid: "⠀" }, - ], - }); - break; - } - }, - }), +export const useDmeStore = create((set) => ({ + page: "home", + pageData: { + message: "", + }, + lines: [ { - name: "dme-store", // unique name + textLeft: "", }, - ), -); + { + textMid: "VAR . DME# No Data", + textSize: "2", + }, + { + textLeft: "", + }, + ], + setLines: (lines) => set({ lines }), + latestMission: null, + setPage: (pageData) => { + if (interval) clearInterval(interval); + switch (pageData.page) { + case "home": { + const setHomePage = () => + set({ + page: "home", + lines: [ + { + textMid: pageData.station.bosCallsign + ? `${pageData.station.bosCallsign}` + : "no Data", + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + { + textMid: new Date().toLocaleDateString("de-DE", { + year: "numeric", + month: "2-digit", + day: "2-digit", + }), + }, + { + textMid: new Date().toLocaleTimeString(), + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + { + textMid: `${pageData.user.lastname} ${pageData.user.firstname}`, + }, + { textMid: "⠀" }, + ], + }); + setHomePage(); + + interval = setInterval(() => { + setHomePage(); + }, 1000); + break; + } + + case "new-mission": { + set({ + page: "new-mission", + lines: [ + { textMid: "⠀" }, + { + textMid: "new mission received", + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + ], + }); + break; + } + case "mission": { + set({ + latestMission: pageData.mission, + page: "mission", + lines: [ + { + textLeft: `${pageData.mission.missionKeywordAbbreviation}`, + textRight: pageData.mission.Stations.map((s) => s.bosCallsignShort).join(","), + style: { fontWeight: "bold" }, + }, + ...(pageData.mission.type == "primär" + ? [ + { + textMid: `${pageData.mission.missionKeywordName}`, + style: { fontWeight: "bold" }, + }, + ] + : []), + + { textLeft: `${pageData.mission.addressStreet}` }, + { + textLeft: `${pageData.mission.addressZip} ${pageData.mission.addressCity}`, + }, + { + textMid: "Weitere Standortinformationen:", + style: { fontWeight: "bold" }, + }, + { + textLeft: pageData.mission.addressAdditionalInfo || "keine Daten", + }, + ...(pageData.mission.type === "sekundär" + ? [ + { + textMid: "Zielort:", + style: { fontWeight: "bold" }, + }, + { + textLeft: pageData.mission.addressMissionDestination || "keine Daten", + }, + ] + : []), + ...(pageData.mission.missionPatientInfo && + pageData.mission.missionPatientInfo.length > 0 + ? [ + { + textMid: "Patienteninfos:", + style: { fontWeight: "bold" }, + }, + { + textLeft: pageData.mission.missionPatientInfo, + }, + ] + : []), + ...(pageData.mission.missionAdditionalInfo && + pageData.mission.missionAdditionalInfo.length > 0 + ? [ + { + textMid: "Weitere Infos:", + style: { fontWeight: "bold" }, + }, + { + textLeft: pageData.mission.missionAdditionalInfo, + }, + ] + : []), + ], + }); + break; + } + case "error": { + set({ + page: "error", + lines: [ + { textMid: "Fehler:" }, + { + textMid: pageData.error, + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + ], + }); + break; + } + case "acknowledge": { + set({ + page: "acknowledge", + lines: [ + { textMid: "⠀" }, + { + textMid: "Einsatz angenommen", + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + ], + }); + break; + } + default: + set({ + page: "error", + lines: [ + { textMid: "Fehler:" }, + { + textMid: `Unbekannte Seite`, + style: { fontWeight: "bold" }, + }, + { textMid: "⠀" }, + ], + }); + break; + } + }, +})); diff --git a/apps/dispatch/app/globals.css b/apps/dispatch/app/globals.css index 876c3519..979f4a4d 100644 --- a/apps/dispatch/app/globals.css +++ b/apps/dispatch/app/globals.css @@ -9,6 +9,11 @@ src: url("/fonts/MelderV2.ttf") format("truetype"); /* Chrome 4+, Firefox 3.5, Opera 10+, Safari 3—5 */ } +@font-face { + font-family: "Bahnschrift"; + src: url("/fonts/bahnschrift.ttf") format("truetype"); /* Chrome 4+, Firefox 3.5, Opera 10+, Safari 3—5 */ +} + @theme { --color-rescuetrack: #46b7a3; --color-rescuetrack-highlight: #ff4500; diff --git a/apps/dispatch/next-env.d.ts b/apps/dispatch/next-env.d.ts index 1b3be084..c4b7818f 100644 --- a/apps/dispatch/next-env.d.ts +++ b/apps/dispatch/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/dispatch/next.config.js b/apps/dispatch/next.config.js index 4678774e..eab71bb8 100644 --- a/apps/dispatch/next.config.js +++ b/apps/dispatch/next.config.js @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: "standalone", +}; export default nextConfig; diff --git a/apps/dispatch/package.json b/apps/dispatch/package.json index 914efa9f..ccddbcaa 100644 --- a/apps/dispatch/package.json +++ b/apps/dispatch/package.json @@ -60,7 +60,6 @@ "tailwindcss": "^4.1.11", "typescript": "^5.8.3", "zod": "^3.25.67", - "zustand": "^5.0.6", - "zustand-sync-tabs": "^0.2.2" + "zustand": "^5.0.6" } } diff --git a/apps/dispatch/public/fonts/bahnschrift.ttf b/apps/dispatch/public/fonts/bahnschrift.ttf new file mode 100644 index 00000000..2c121b3d Binary files /dev/null and b/apps/dispatch/public/fonts/bahnschrift.ttf differ diff --git a/apps/dispatch/public/sounds/1504.wav b/apps/dispatch/public/sounds/1504.wav new file mode 100644 index 00000000..edde45b8 Binary files /dev/null and b/apps/dispatch/public/sounds/1504.wav differ diff --git a/apps/dispatch/public/sounds/403.wav b/apps/dispatch/public/sounds/403.wav new file mode 100644 index 00000000..3d855dc6 Binary files /dev/null and b/apps/dispatch/public/sounds/403.wav differ diff --git a/apps/dispatch/public/sounds/775.wav b/apps/dispatch/public/sounds/775.wav new file mode 100644 index 00000000..bb406ab5 Binary files /dev/null and b/apps/dispatch/public/sounds/775.wav differ diff --git a/apps/hub/Dockerfile b/apps/hub/Dockerfile index 6467ccbb..6c5c55af 100644 --- a/apps/hub/Dockerfile +++ b/apps/hub/Dockerfile @@ -1,9 +1,5 @@ FROM node:22-alpine AS base - -ENV PNPM_HOME="/usr/local/pnpm" -ENV PATH="${PNPM_HOME}:${PATH}" - ARG NEXT_PUBLIC_HUB_URL ARG NEXT_PUBLIC_HUB_SERVER_URL ARG NEXT_PUBLIC_DISCORD_URL @@ -16,13 +12,13 @@ ENV NEXT_PUBLIC_DISCORD_URL=${NEXT_PUBLIC_DISCORD_URL} ENV NEXT_PUBLIC_MOODLE_URL=${NEXT_PUBLIC_MOODLE_URL} ENV NEXT_PUBLIC_DISPATCH_URL=${NEXT_PUBLIC_DISPATCH_URL} -RUN corepack enable && corepack prepare pnpm@latest --activate - - -RUN echo "NEXT_PUBLIC_DISCORD_URL=${NEXT_PUBLIC_DISCORD_URL}" -RUN pnpm add -g turbo@^2.5 - FROM base AS builder + +ENV PNPM_HOME="/usr/local/pnpm" +ENV PATH="${PNPM_HOME}:${PATH}" + +RUN corepack enable && corepack prepare pnpm@latest --activate +RUN pnpm add -g turbo@^2.5 RUN apk update RUN apk add --no-cache libc6-compat @@ -33,6 +29,13 @@ COPY . . RUN turbo prune hub --docker FROM base AS installer + +ENV PNPM_HOME="/usr/local/pnpm" +ENV PATH="${PNPM_HOME}:${PATH}" + +RUN corepack enable && corepack prepare pnpm@latest --activate +RUN pnpm add -g turbo@^2.5 + RUN apk update RUN apk add --no-cache libc6-compat @@ -44,21 +47,24 @@ RUN pnpm install # Build the project COPY --from=builder /usr/app/out/full/ . -RUN turbo run build +RUN turbo run build --filter=hub... -FROM base AS runner +FROM node:22-alpine AS runner WORKDIR /usr/app # Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs -USER nextjs # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer --chown=nextjs:nodejs /usr/app/ ./ +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/.next/static ./apps/hub/.next/static +COPY --from=installer --chown=nextjs:nodejs /usr/app/apps/hub/public ./apps/hub/public + +USER nextjs # Expose the application port EXPOSE 3000 -CMD ["pnpm", "--dir", "apps/hub", "run", "start"] \ No newline at end of file +CMD ["node", "apps/hub/server.js"] \ No newline at end of file diff --git a/apps/hub/app/(app)/admin/event/_components/Form.tsx b/apps/hub/app/(app)/admin/event/_components/Form.tsx index 0059d196..f2726311 100644 --- a/apps/hub/app/(app)/admin/event/_components/Form.tsx +++ b/apps/hub/app/(app)/admin/event/_components/Form.tsx @@ -264,6 +264,7 @@ export const Form = ({ event }: { event?: Event }) => { showSearch getFilter={(searchTerm) => ({ + AND: [{ eventId: event?.id }], OR: [ { User: { diff --git a/apps/hub/app/(app)/admin/user/[id]/_components/forms.tsx b/apps/hub/app/(app)/admin/user/[id]/_components/forms.tsx index d04c5309..25789965 100644 --- a/apps/hub/app/(app)/admin/user/[id]/_components/forms.tsx +++ b/apps/hub/app/(app)/admin/user/[id]/_components/forms.tsx @@ -776,13 +776,19 @@ export const AdminForm = ({ {discordAccount && ( - Discord Avatar + {discordAccount.avatar ? ( + Discord Avatar + ) : ( +
    + N/A +
    + )} {discordAccount.username} {discordAccount.discordId} @@ -792,15 +798,20 @@ export const AdminForm = ({ {formerDiscordAccounts.map((account) => ( - {account.DiscordAccount && ( - Discord Avatar - )} + {account.DiscordAccount && + (account.DiscordAccount.avatar ? ( + Discord Avatar + ) : ( +
    + N/A +
    + ))} {account.DiscordAccount?.username || "Unbekannt"} {account.DiscordAccount?.discordId || "Unbekannt"} diff --git a/apps/hub/next.config.ts b/apps/hub/next.config.ts index f681ee94..174231d1 100644 --- a/apps/hub/next.config.ts +++ b/apps/hub/next.config.ts @@ -2,6 +2,7 @@ /* const removeImports = require("next-remove-imports")(); */ /* const nextConfig = removeImports({}); */ const nextConfig = { + output: "standalone", images: { domains: ["cdn.discordapp.com", "nextcloud.virtualairrescue.com"], }, diff --git a/package.json b/package.json index f66adf1d..da08da6d 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "node": ">=18", "pnpm": ">=10" }, - "packageManager": "pnpm@10.13.1", + "packageManager": "pnpm@10.28.0", "workspaces": [ "apps/*", "packages/*" diff --git a/packages/database/prisma/json/MissionVehicleLog.ts b/packages/database/prisma/json/MissionVehicleLog.ts index 7bceda67..c7de840c 100644 --- a/packages/database/prisma/json/MissionVehicleLog.ts +++ b/packages/database/prisma/json/MissionVehicleLog.ts @@ -1,4 +1,5 @@ import { Station } from "../../generated/client"; +import { StationStatus } from "./SocketEvents"; import { PublicUser } from "./User"; export interface MissionVehicleLog { @@ -37,6 +38,19 @@ export interface MissionSdsLog { }; } +export interface MissionSdsStatusLog { + type: "sds-status-log"; + auto: false; + timeStamp: string; + data: { + direction: "to-lst" | "to-aircraft"; + stationId: number; + station: Station; + user: PublicUser; + status: string; + }; +} + export interface MissionMessageLog { type: "message-log"; auto: false; @@ -90,4 +104,5 @@ export type MissionLog = | MissionAlertLogAuto | MissionCompletedLog | MissionVehicleLog - | MissionReopenedLog; + | MissionReopenedLog + | MissionSdsStatusLog; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21252307..9a37750f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,9 +16,12 @@ overrides: next@>=15.0.0 <=15.4.4: '>=15.4.5' next@>=15.0.0-canary.0 <15.4.7: '>=15.4.7' next@>=15.4.0-canary.0 <15.4.8: '>=15.4.8' + next@>=15.4.0-canary.0 <15.4.9: '>=15.4.9' nodemailer@<7.0.7: '>=7.0.7' nodemailer@<=7.0.10: '>=7.0.11' playwright@<1.55.1: '>=1.55.1' + preact@>=10.26.5 <10.26.10: '>=10.26.10' + qs@<6.14.1: '>=6.14.1' importers: @@ -127,7 +130,7 @@ importers: version: 0.5.8(@types/dom-mediacapture-transform@0.1.11)(livekit-client@2.15.3(@types/dom-mediacapture-record@1.0.22)) '@next-auth/prisma-adapter': specifier: ^1.0.7 - version: 1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + version: 1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.1.0) @@ -207,11 +210,11 @@ importers: specifier: ^0.525.0 version: 0.525.0(react@19.1.0) next: - specifier: ^15.4.8 - version: 15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: '>=15.4.9' + version: 16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-auth: specifier: '>=4.24.12' - version: 4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 4.24.13(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) npm: specifier: ^11.4.2 version: 11.4.2 @@ -257,9 +260,6 @@ importers: zustand: specifier: ^5.0.6 version: 5.0.6(@types/react@19.1.8)(react@19.1.0) - zustand-sync-tabs: - specifier: ^0.2.2 - version: 0.2.2(zustand@5.0.6(@types/react@19.1.8)(react@19.1.0)) apps/dispatch-server: dependencies: @@ -365,7 +365,7 @@ importers: version: 5.1.1(react-hook-form@7.60.0(react@19.1.0)) '@next-auth/prisma-adapter': specifier: ^1.0.7 - version: 1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) + version: 1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.1.0) @@ -439,11 +439,11 @@ importers: specifier: ^2.30.1 version: 2.30.1 next: - specifier: ^15.4.8 - version: 15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: '>=15.4.9' + version: 16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-auth: specifier: '>=4.24.12' - version: 4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 4.24.13(next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next-remove-imports: specifier: ^1.0.12 version: 1.0.12(webpack@5.99.9) @@ -791,8 +791,8 @@ packages: '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} - '@emnapi/runtime@1.4.5': - resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} '@emnapi/wasi-threads@1.0.2': resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} @@ -1079,124 +1079,139 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@img/sharp-darwin-arm64@0.34.3': - resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.3': - resolution: {integrity: sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.0': - resolution: {integrity: sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.0': - resolution: {integrity: sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.0': - resolution: {integrity: sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.2.0': - resolution: {integrity: sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.2.0': - resolution: {integrity: sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.0': - resolution: {integrity: sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.2.0': - resolution: {integrity: sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': - resolution: {integrity: sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.2.0': - resolution: {integrity: sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.3': - resolution: {integrity: sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.3': - resolution: {integrity: sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-ppc64@0.34.3': - resolution: {integrity: sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - '@img/sharp-linux-s390x@0.34.3': - resolution: {integrity: sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==} + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.3': - resolution: {integrity: sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.3': - resolution: {integrity: sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.3': - resolution: {integrity: sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.3': - resolution: {integrity: sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.3': - resolution: {integrity: sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.3': - resolution: {integrity: sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.3': - resolution: {integrity: sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1277,56 +1292,56 @@ packages: '@prisma/client': '>=2.26.0 || >=3' next-auth: '>=4.24.12' - '@next/env@15.4.8': - resolution: {integrity: sha512-LydLa2MDI1NMrOFSkO54mTc8iIHSttj6R6dthITky9ylXV2gCGi0bHQjVCtLGRshdRPjyh2kXbxJukDtBWQZtQ==} + '@next/env@16.1.1': + resolution: {integrity: sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==} '@next/eslint-plugin-next@15.4.2': resolution: {integrity: sha512-k0rjdWjXBY6tAOty1ckrMETE6Mx66d85NsgcAIdDp7/cXOsTJ93ywmbg3uUcpxX5TUHFEcCWI5mb8nPhwCe9jg==} - '@next/swc-darwin-arm64@15.4.8': - resolution: {integrity: sha512-Pf6zXp7yyQEn7sqMxur6+kYcywx5up1J849psyET7/8pG2gQTVMjU3NzgIt8SeEP5to3If/SaWmaA6H6ysBr1A==} + '@next/swc-darwin-arm64@16.1.1': + resolution: {integrity: sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.4.8': - resolution: {integrity: sha512-xla6AOfz68a6kq3gRQccWEvFC/VRGJmA/QuSLENSO7CZX5WIEkSz7r1FdXUjtGCQ1c2M+ndUAH7opdfLK1PQbw==} + '@next/swc-darwin-x64@16.1.1': + resolution: {integrity: sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.4.8': - resolution: {integrity: sha512-y3fmp+1Px/SJD+5ntve5QLZnGLycsxsVPkTzAc3zUiXYSOlTPqT8ynfmt6tt4fSo1tAhDPmryXpYKEAcoAPDJw==} + '@next/swc-linux-arm64-gnu@16.1.1': + resolution: {integrity: sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.4.8': - resolution: {integrity: sha512-DX/L8VHzrr1CfwaVjBQr3GWCqNNFgyWJbeQ10Lx/phzbQo3JNAxUok1DZ8JHRGcL6PgMRgj6HylnLNndxn4Z6A==} + '@next/swc-linux-arm64-musl@16.1.1': + resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.4.8': - resolution: {integrity: sha512-9fLAAXKAL3xEIFdKdzG5rUSvSiZTLLTCc6JKq1z04DR4zY7DbAPcRvNm3K1inVhTiQCs19ZRAgUerHiVKMZZIA==} + '@next/swc-linux-x64-gnu@16.1.1': + resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.4.8': - resolution: {integrity: sha512-s45V7nfb5g7dbS7JK6XZDcapicVrMMvX2uYgOHP16QuKH/JA285oy6HcxlKqwUNaFY/UC6EvQ8QZUOo19cBKSA==} + '@next/swc-linux-x64-musl@16.1.1': + resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.4.8': - resolution: {integrity: sha512-KjgeQyOAq7t/HzAJcWPGA8X+4WY03uSCZ2Ekk98S9OgCFsb6lfBE3dbUzUuEQAN2THbwYgFfxX2yFTCMm8Kehw==} + '@next/swc-win32-arm64-msvc@16.1.1': + resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.4.8': - resolution: {integrity: sha512-Exsmf/+42fWVnLMaZHzshukTBxZrSwuuLKFvqhGHJ+mC1AokqieLY/XzAl3jc/CqhXLqLY3RRjkKJ9YnLPcRWg==} + '@next/swc-win32-x64-msvc@16.1.1': + resolution: {integrity: sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2558,6 +2573,10 @@ packages: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} + baseline-browser-mapping@2.9.14: + resolution: {integrity: sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==} + hasBin: true + batch-processor@1.0.0: resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==} @@ -2696,13 +2715,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2883,6 +2895,10 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -3544,9 +3560,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -4174,7 +4187,7 @@ packages: resolution: {integrity: sha512-sgObCfcfL7BzIK76SS5TnQtc3yo2Oifp/yIpfv6fMfeBOiBJkDWF3A2y9+yqnmJ4JKc2C+nMjSjmgDeTwgN1rQ==} peerDependencies: '@auth/core': 0.34.3 - next: '>=15.4.8' + next: '>=15.4.9' nodemailer: '>=7.0.11' react: ^17.0.2 || ^18 || ^19 react-dom: ^17.0.2 || ^18 || ^19 @@ -4187,9 +4200,9 @@ packages: next-remove-imports@1.0.12: resolution: {integrity: sha512-3tdL6VuSykJ/mcUwxfjQ+Fd4OpEmrwWVHtLZ/fhNcSaToWCutUp7nrfIww7/4CURe9I7BDCQE9AWl4fkY3YZOQ==} - next@15.4.8: - resolution: {integrity: sha512-jwOXTz/bo0Pvlf20FSb6VXVeWRssA2vbvq9SdrOPEg9x8E1B27C2rQtvriAn600o9hH61kjrVRexEffv3JybuA==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + next@16.1.1: + resolution: {integrity: sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==} + engines: {node: '>=20.9.0'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -4482,10 +4495,10 @@ packages: preact-render-to-string@5.2.6: resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} peerDependencies: - preact: '>=10' + preact: '>=10.26.10' - preact@10.26.9: - resolution: {integrity: sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==} + preact@10.28.2: + resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -4601,8 +4614,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -4872,6 +4885,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -4898,8 +4916,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.34.3: - resolution: {integrity: sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -4930,9 +4948,6 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-update-notifier@2.0.0: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} @@ -5468,11 +5483,6 @@ packages: zod@3.25.67: resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==} - zustand-sync-tabs@0.2.2: - resolution: {integrity: sha512-i2pQPm5SGBIq50v7tt6XFXZSR/iJNErOslS5HzMKJVd06+xDyBCXioxEap0Ke6u98+a49fU5QRqzypo21wMe9A==} - peerDependencies: - zustand: 3-5 - zustand@5.0.6: resolution: {integrity: sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==} engines: {node: '>=12.20.0'} @@ -5593,7 +5603,7 @@ snapshots: '@babel/parser': 7.27.7 '@babel/template': 7.27.2 '@babel/types': 7.27.7 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -5665,7 +5675,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.5': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true @@ -5824,7 +5834,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -5842,7 +5852,7 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -5910,90 +5920,101 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/sharp-darwin-arm64@0.34.3': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.0 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.34.3': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.0 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.0': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.0': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.0': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.2.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.0': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.0': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.0': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.34.3': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.0 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.34.3': + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.0 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-ppc64@0.34.3': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.0 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.34.3': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.0 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.34.3': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.0 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.3': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.3': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-wasm32@0.34.3': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.8.1 optional: true - '@img/sharp-win32-arm64@0.34.3': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.34.3': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.34.3': + '@img/sharp-win32-x64@0.34.5': optional: true '@interactjs/types@1.10.27': {} @@ -6065,39 +6086,44 @@ snapshots: '@tybys/wasm-util': 0.9.0 optional: true - '@next-auth/prisma-adapter@1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + '@next-auth/prisma-adapter@1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': dependencies: '@prisma/client': 6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3) - next-auth: 4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next-auth: 4.24.13(next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@next/env@15.4.8': {} + '@next-auth/prisma-adapter@1.0.7(@prisma/client@6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3))(next-auth@4.24.13(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))': + dependencies: + '@prisma/client': 6.12.0(prisma@6.12.0(typescript@5.8.3))(typescript@5.8.3) + next-auth: 4.24.13(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + + '@next/env@16.1.1': {} '@next/eslint-plugin-next@15.4.2': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.4.8': + '@next/swc-darwin-arm64@16.1.1': optional: true - '@next/swc-darwin-x64@15.4.8': + '@next/swc-darwin-x64@16.1.1': optional: true - '@next/swc-linux-arm64-gnu@15.4.8': + '@next/swc-linux-arm64-gnu@16.1.1': optional: true - '@next/swc-linux-arm64-musl@15.4.8': + '@next/swc-linux-arm64-musl@16.1.1': optional: true - '@next/swc-linux-x64-gnu@15.4.8': + '@next/swc-linux-x64-gnu@16.1.1': optional: true - '@next/swc-linux-x64-musl@15.4.8': + '@next/swc-linux-x64-musl@16.1.1': optional: true - '@next/swc-win32-arm64-msvc@15.4.8': + '@next/swc-win32-arm64-msvc@16.1.1': optional: true - '@next/swc-win32-x64-msvc@15.4.8': + '@next/swc-win32-x64-msvc@16.1.1': optional: true '@nodelib/fs.scandir@2.1.5': @@ -7723,7 +7749,7 @@ snapshots: '@typescript-eslint/types': 8.37.0 '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.37.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 9.31.0(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: @@ -7733,7 +7759,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.37.0(typescript@5.8.3) '@typescript-eslint/types': 8.37.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -7752,7 +7778,7 @@ snapshots: '@typescript-eslint/types': 8.37.0 '@typescript-eslint/typescript-estree': 8.37.0(typescript@5.8.3) '@typescript-eslint/utils': 8.37.0(eslint@9.31.0(jiti@2.4.2))(typescript@5.8.3) - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 9.31.0(jiti@2.4.2) ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -7767,7 +7793,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.37.0(typescript@5.8.3) '@typescript-eslint/types': 8.37.0 '@typescript-eslint/visitor-keys': 8.37.0 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -8137,6 +8163,8 @@ snapshots: base64id@2.0.0: {} + baseline-browser-mapping@2.9.14: {} + batch-processor@1.0.0: {} bcp-47-match@2.0.3: {} @@ -8157,7 +8185,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.7.0 on-finished: 2.4.1 - qs: 6.14.0 + qs: 6.14.1 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -8274,18 +8302,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -8408,6 +8424,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.1: + dependencies: + ms: 2.1.3 + debug@4.4.1(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -8446,6 +8466,9 @@ snapshots: detect-libc@2.0.4: {} + detect-libc@2.1.2: + optional: true + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -8747,7 +8770,7 @@ snapshots: eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.31.0(jiti@2.4.2)): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.1 eslint: 9.31.0(jiti@2.4.2) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 @@ -8884,7 +8907,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1(supports-color@5.5.0) + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -8955,7 +8978,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.14.1 range-parser: 1.2.1 router: 2.2.0 send: 1.2.0 @@ -9412,9 +9435,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -10186,17 +10206,34 @@ snapshots: neo-async@2.6.2: {} - next-auth@4.24.13(next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next-auth@4.24.13(next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@babel/runtime': 7.27.6 '@panva/hkdf': 1.2.1 cookie: 0.7.2 jose: 4.15.9 - next: 15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) oauth: 0.9.15 openid-client: 5.7.1 - preact: 10.26.9 - preact-render-to-string: 5.2.6(preact@10.26.9) + preact: 10.28.2 + preact-render-to-string: 5.2.6(preact@10.28.2) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + uuid: 8.3.2 + optionalDependencies: + nodemailer: 7.0.11 + + next-auth@4.24.13(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(nodemailer@7.0.11)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@babel/runtime': 7.27.6 + '@panva/hkdf': 1.2.1 + cookie: 0.7.2 + jose: 4.15.9 + next: 16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + oauth: 0.9.15 + openid-client: 5.7.1 + preact: 10.28.2 + preact-render-to-string: 5.2.6(preact@10.28.2) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) uuid: 8.3.2 @@ -10212,27 +10249,54 @@ snapshots: - supports-color - webpack - next@15.4.8(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next@16.1.1(@babel/core@7.27.7)(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - '@next/env': 15.4.8 + '@next/env': 16.1.1 '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.9.14 caniuse-lite: 1.0.30001726 postcss: 8.4.31 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) styled-jsx: 5.1.6(@babel/core@7.27.7)(react@19.1.0) optionalDependencies: - '@next/swc-darwin-arm64': 15.4.8 - '@next/swc-darwin-x64': 15.4.8 - '@next/swc-linux-arm64-gnu': 15.4.8 - '@next/swc-linux-arm64-musl': 15.4.8 - '@next/swc-linux-x64-gnu': 15.4.8 - '@next/swc-linux-x64-musl': 15.4.8 - '@next/swc-win32-arm64-msvc': 15.4.8 - '@next/swc-win32-x64-msvc': 15.4.8 + '@next/swc-darwin-arm64': 16.1.1 + '@next/swc-darwin-x64': 16.1.1 + '@next/swc-linux-arm64-gnu': 16.1.1 + '@next/swc-linux-arm64-musl': 16.1.1 + '@next/swc-linux-x64-gnu': 16.1.1 + '@next/swc-linux-x64-musl': 16.1.1 + '@next/swc-win32-arm64-msvc': 16.1.1 + '@next/swc-win32-x64-msvc': 16.1.1 '@opentelemetry/api': 1.9.0 '@playwright/test': 1.52.0 - sharp: 0.34.3 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@next/env': 16.1.1 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.9.14 + caniuse-lite: 1.0.30001726 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.6(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 16.1.1 + '@next/swc-darwin-x64': 16.1.1 + '@next/swc-linux-arm64-gnu': 16.1.1 + '@next/swc-linux-arm64-musl': 16.1.1 + '@next/swc-linux-x64-gnu': 16.1.1 + '@next/swc-linux-x64-musl': 16.1.1 + '@next/swc-win32-arm64-msvc': 16.1.1 + '@next/swc-win32-x64-msvc': 16.1.1 + '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.52.0 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -10453,12 +10517,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - preact-render-to-string@5.2.6(preact@10.26.9): + preact-render-to-string@5.2.6(preact@10.28.2): dependencies: - preact: 10.26.9 + preact: 10.28.2 pretty-format: 3.8.0 - preact@10.26.9: {} + preact@10.28.2: {} prelude-ls@1.2.1: {} @@ -10513,7 +10577,7 @@ snapshots: punycode@2.3.1: {} - qs@6.14.0: + qs@6.14.1: dependencies: side-channel: 1.1.0 @@ -10893,6 +10957,9 @@ snapshots: semver@7.7.2: {} + semver@7.7.3: + optional: true + send@1.2.0: dependencies: debug: 4.4.1(supports-color@5.5.0) @@ -10946,34 +11013,36 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.34.3: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.2 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.3 - '@img/sharp-darwin-x64': 0.34.3 - '@img/sharp-libvips-darwin-arm64': 1.2.0 - '@img/sharp-libvips-darwin-x64': 1.2.0 - '@img/sharp-libvips-linux-arm': 1.2.0 - '@img/sharp-libvips-linux-arm64': 1.2.0 - '@img/sharp-libvips-linux-ppc64': 1.2.0 - '@img/sharp-libvips-linux-s390x': 1.2.0 - '@img/sharp-libvips-linux-x64': 1.2.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.0 - '@img/sharp-libvips-linuxmusl-x64': 1.2.0 - '@img/sharp-linux-arm': 0.34.3 - '@img/sharp-linux-arm64': 0.34.3 - '@img/sharp-linux-ppc64': 0.34.3 - '@img/sharp-linux-s390x': 0.34.3 - '@img/sharp-linux-x64': 0.34.3 - '@img/sharp-linuxmusl-arm64': 0.34.3 - '@img/sharp-linuxmusl-x64': 0.34.3 - '@img/sharp-wasm32': 0.34.3 - '@img/sharp-win32-arm64': 0.34.3 - '@img/sharp-win32-ia32': 0.34.3 - '@img/sharp-win32-x64': 0.34.3 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -11012,11 +11081,6 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-update-notifier@2.0.0: dependencies: semver: 7.7.2 @@ -11174,6 +11238,11 @@ snapshots: optionalDependencies: '@babel/core': 7.27.7 + styled-jsx@5.1.6(react@19.1.0): + dependencies: + client-only: 0.0.1 + react: 19.1.0 + stylis@4.2.0: {} supports-color@5.5.0: @@ -11643,10 +11712,6 @@ snapshots: zod@3.25.67: {} - zustand-sync-tabs@0.2.2(zustand@5.0.6(@types/react@19.1.8)(react@19.1.0)): - dependencies: - zustand: 5.0.6(@types/react@19.1.8)(react@19.1.0) - zustand@5.0.6(@types/react@19.1.8)(react@19.1.0): optionalDependencies: '@types/react': 19.1.8 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0b5b71e6..bcd69006 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -23,6 +23,9 @@ overrides: next@>=15.0.0 <=15.4.4: '>=15.4.5' next@>=15.0.0-canary.0 <15.4.7: '>=15.4.7' next@>=15.4.0-canary.0 <15.4.8: '>=15.4.8' + next@>=15.4.0-canary.0 <15.4.9: '>=15.4.9' nodemailer@<7.0.7: '>=7.0.7' nodemailer@<=7.0.10: '>=7.0.11' playwright@<1.55.1: '>=1.55.1' + preact@>=10.26.5 <10.26.10: '>=10.26.10' + qs@<6.14.1: '>=6.14.1'