diff --git a/app/api/auth/change-password/route.ts b/app/api/auth/change-password/route.ts index 4bf1712..e01c3e5 100644 --- a/app/api/auth/change-password/route.ts +++ b/app/api/auth/change-password/route.ts @@ -1,6 +1,7 @@ import { AUTH_COOKIE_NAME, BE_BASE_URL } from "@/app/services/constants"; import { NextResponse } from "next/server"; import { decodeJwt } from "jose"; +import { JWTPayload } from "@/app/utils/auth"; export async function POST(request: Request) { try { @@ -21,15 +22,8 @@ export async function POST(request: Request) { // Check MustChangePassword flag from current token let mustChangePassword = false; try { - const payload = decodeJwt(token); - const mustChangeClaim = payload.MustChangePassword; - if (typeof mustChangeClaim === "boolean") { - mustChangePassword = mustChangeClaim; - } else if (typeof mustChangeClaim === "string") { - mustChangePassword = mustChangeClaim.toLowerCase() === "true"; - } else { - mustChangePassword = false; - } + const payload = decodeJwt(token); + mustChangePassword = payload.MustChangePassword; } catch (err) { console.error("❌ Failed to decode current JWT:", err); } @@ -89,7 +83,7 @@ export async function POST(request: Request) { // Derive maxAge from JWT exp if available; fallback to 12h let maxAge = 60 * 60 * 12; try { - const payload = decodeJwt(newToken); + const payload = decodeJwt(newToken); if (payload?.exp) { const secondsLeft = payload.exp - Math.floor(Date.now() / 1000); if (secondsLeft > 0) maxAge = secondsLeft; diff --git a/app/api/auth/login/route.tsx b/app/api/auth/login/route.tsx index 3615eed..2e9f623 100644 --- a/app/api/auth/login/route.tsx +++ b/app/api/auth/login/route.tsx @@ -1,7 +1,8 @@ -import { AUTH_COOKIE_NAME, BE_BASE_URL } from "@/app/services/constants"; import { NextResponse } from "next/server"; import { cookies } from "next/headers"; import { decodeJwt } from "jose"; +import { AUTH_COOKIE_NAME, BE_BASE_URL } from "@/app/services/constants"; +import { JWTPayload } from "@/app/utils/auth"; export async function POST(request: Request) { try { @@ -14,8 +15,6 @@ export async function POST(request: Request) { body: JSON.stringify({ email, password }), }); - console.log("[LOGIN] resp", resp); - if (!resp.ok) { const errJson = await safeJson(resp); return NextResponse.json( @@ -39,7 +38,7 @@ export async function POST(request: Request) { let maxAge = 60 * 60 * 12; // fallback to 12h try { - const payload = decodeJwt(token); + const payload = decodeJwt(token); // Extract exp if present if (payload?.exp) { diff --git a/app/dashboard/admin/matcher/MatcherBoard/DraggableItem.tsx b/app/dashboard/admin/matcher/MatcherBoard/DraggableItem.tsx new file mode 100644 index 0000000..2b7fcac --- /dev/null +++ b/app/dashboard/admin/matcher/MatcherBoard/DraggableItem.tsx @@ -0,0 +1,55 @@ +"use client"; + +import React from "react"; +import { useDraggable } from "@dnd-kit/core"; +import { CSS } from "@dnd-kit/utilities"; +import { Card, CardContent, Typography } from "@mui/material"; +import { DraggableItemProps } from "../types"; + +export function DraggableItem({ item, isDragging }: DraggableItemProps) { + const { + attributes, + listeners, + setNodeRef, + transform, + isDragging: isItemDragging, + } = useDraggable({ + id: item.id, + }); + + const style = { + transform: CSS.Translate.toString(transform), + opacity: isItemDragging || isDragging ? 0.5 : 1, + }; + + return ( + + + + {item.name} + + {item.id && ( + + ID: {item.id} + + )} + + + ); +} diff --git a/app/dashboard/admin/matcher/MatcherBoard/DroppableColumn.tsx b/app/dashboard/admin/matcher/MatcherBoard/DroppableColumn.tsx new file mode 100644 index 0000000..fd1b3e6 --- /dev/null +++ b/app/dashboard/admin/matcher/MatcherBoard/DroppableColumn.tsx @@ -0,0 +1,80 @@ +"use client"; + +import React from "react"; +import { useDroppable } from "@dnd-kit/core"; +import { Box, Typography, Chip } from "@mui/material"; +import { DroppableColumnProps } from "../types"; +import { DraggableItem } from "./DraggableItem"; + +export function DroppableColumn({ + id, + title, + items, + activeId, +}: DroppableColumnProps) { + const { setNodeRef, isOver } = useDroppable({ + id, + }); + + return ( + + + {title} + + + {items.map(item => ( + + ))} + {items.length === 0 && ( + + + Drop items here + + + )} + + + + ); +} diff --git a/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.scss b/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.scss new file mode 100644 index 0000000..435295f --- /dev/null +++ b/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.scss @@ -0,0 +1,36 @@ +.matcher-board { + &__column { + display: flex; + flex-direction: column; + } + + &__column-content { + &::-webkit-scrollbar { + width: 8px; + } + + &::-webkit-scrollbar-track { + background: #f1f1f1; + border-radius: 4px; + } + + &::-webkit-scrollbar-thumb { + background: #888; + border-radius: 4px; + + &:hover { + background: #555; + } + } + } + + &__item { + transition: + transform 0.2s ease, + box-shadow 0.2s ease; + + &:hover { + transform: translateY(-2px); + } + } +} diff --git a/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.tsx b/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.tsx new file mode 100644 index 0000000..301d9e9 --- /dev/null +++ b/app/dashboard/admin/matcher/MatcherBoard/MatcherBoard.tsx @@ -0,0 +1,125 @@ +"use client"; + +import React, { useState } from "react"; +import { + DndContext, + DragEndEvent, + DragOverlay, + DragStartEvent, + PointerSensor, + useSensor, + useSensors, + closestCenter, +} from "@dnd-kit/core"; +import { Box, Card, CardContent, Typography } from "@mui/material"; +import { MatcherBoardProps } from "../types"; +import { DroppableColumn } from "./DroppableColumn"; +import { findActiveItem, isItemInSource, addItemIfNotPresent } from "../utils"; +import "./MatcherBoard.scss"; + +export default function MatcherBoard({ + sourceItems: initialSourceItems, + targetItems: initialTargetItems, + config, + onMatch, +}: MatcherBoardProps) { + const [sourceItems, setSourceItems] = useState(initialSourceItems); + const [targetItems, setTargetItems] = useState(initialTargetItems); + const [activeId, setActiveId] = useState(null); + + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { + distance: 8, + }, + }) + ); + + const handleDragStart = (event: DragStartEvent) => { + setActiveId(String(event.active.id)); + }; + + const handleDragEnd = (event: DragEndEvent) => { + const { active, over } = event; + setActiveId(null); + + if (!over) return; + + const activeId = String(active.id); + const overId = String(over.id); + + const activeItem = findActiveItem(sourceItems, targetItems, activeId); + if (!activeItem) return; + + const activeIsSource = isItemInSource(sourceItems, activeId); + const droppedOnSource = overId === "source"; + const droppedOnTarget = overId === "target"; + + // If dragging from source to target column + if (activeIsSource && droppedOnTarget) { + setSourceItems(prev => prev.filter(item => item.id !== activeId)); + setTargetItems(prev => addItemIfNotPresent(prev, activeItem)); + + if (onMatch) { + onMatch(activeId, "target"); + } + } else if (!activeIsSource && droppedOnSource) { + setTargetItems(prev => prev.filter(item => item.id !== activeId)); + setSourceItems(prev => addItemIfNotPresent(prev, activeItem)); + } + }; + + const activeItem = activeId + ? findActiveItem(sourceItems, targetItems, activeId) + : null; + + return ( + + + + + + + {activeItem ? ( + + + + {activeItem.name} + + + + ) : null} + + + ); +} diff --git a/app/dashboard/admin/matcher/MatcherPageClient.tsx b/app/dashboard/admin/matcher/MatcherPageClient.tsx new file mode 100644 index 0000000..6485371 --- /dev/null +++ b/app/dashboard/admin/matcher/MatcherPageClient.tsx @@ -0,0 +1,109 @@ +"use client"; + +import React, { useState, useCallback } from "react"; +import { useRouter } from "next/navigation"; +import { + Box, + Typography, + Select, + MenuItem, + FormControl, + InputLabel, + Alert, +} from "@mui/material"; +import MatcherBoard from "./MatcherBoard/MatcherBoard"; +import { MATCH_CONFIGS } from "./constants"; +import { MatchableEntity, MatchConfig } from "./types"; +import toast from "react-hot-toast"; + +interface MatcherPageClientProps { + initialSourceItems: MatchableEntity[]; + initialTargetItems: MatchableEntity[]; + initialMatchType: string; + config: MatchConfig; +} + +export default function MatcherPageClient({ + initialSourceItems, + initialTargetItems, + initialMatchType, + config: initialConfig, +}: MatcherPageClientProps) { + const router = useRouter(); + const [matchType, setMatchType] = useState(initialMatchType); + const [sourceItems, setSourceItems] = useState(initialSourceItems); + const [targetItems, setTargetItems] = useState(initialTargetItems); + + const currentConfig = MATCH_CONFIGS[matchType] || initialConfig; + + const handleMatchTypeChange = (newType: string) => { + setMatchType(newType); + // Update URL and reload page to fetch new data via SSR + router.push(`/dashboard/admin/matcher?type=${newType}`); + router.refresh(); + }; + + const handleMatch = useCallback( + async (sourceId: string, targetId: string) => { + try { + // TODO: Call API endpoint to save the match + // For now, just show a toast + toast.success( + `Matched ${currentConfig.sourceLabel} to ${currentConfig.targetLabel}` + ); + console.log("Match:", { + sourceId, + targetId, + matchType, + }); + } catch (error) { + toast.error("Failed to save match"); + console.error("Error saving match:", error); + } + }, + [currentConfig, matchType] + ); + + return ( + + + + Entity Matcher + + + Match Type + + + + + + Drag items from the left column to the right column to create matches. + You can also drag items back to remove matches. + + + + + ); +} diff --git a/app/dashboard/admin/matcher/constants.ts b/app/dashboard/admin/matcher/constants.ts new file mode 100644 index 0000000..0b37cf6 --- /dev/null +++ b/app/dashboard/admin/matcher/constants.ts @@ -0,0 +1,48 @@ +import { MatchConfig } from "./types"; + +export const MATCH_CONFIGS: Record = { + "permissions-to-groups": { + type: "permissions-to-groups", + sourceLabel: "Permissions", + targetLabel: "Groups", + sourceEndpoint: "/api/dashboard/admin/permissions", + targetEndpoint: "/api/dashboard/admin/groups", + sourceCollectionKeys: ["permissions", "data", "items"], + targetCollectionKeys: ["groups", "data", "items"], + sourcePrimaryKey: "name", + targetPrimaryKey: "name", + }, + "methods-to-psp": { + type: "methods-to-psp", + sourceLabel: "Methods", + targetLabel: "PSPs", + sourceEndpoint: "/api/dashboard/admin/methods", + targetEndpoint: "/api/dashboard/admin/psps", + sourceCollectionKeys: ["methods", "data", "items"], + targetCollectionKeys: ["psps", "data", "items"], + sourcePrimaryKey: "name", + targetPrimaryKey: "name", + }, + "psp-to-merchant": { + type: "psp-to-merchant", + sourceLabel: "PSPs", + targetLabel: "Merchants", + sourceEndpoint: "/api/dashboard/admin/psps", + targetEndpoint: "/api/dashboard/admin/merchants", + sourceCollectionKeys: ["psps", "data", "items"], + targetCollectionKeys: ["merchants", "data", "items"], + sourcePrimaryKey: "name", + targetPrimaryKey: "name", + }, + "groups-to-users": { + type: "groups-to-users", + sourceLabel: "Groups", + targetLabel: "Users", + sourceEndpoint: "/api/dashboard/admin/groups", + targetEndpoint: "/api/dashboard/admin/users", + sourceCollectionKeys: ["groups", "data", "items"], + targetCollectionKeys: ["users", "data", "items"], + sourcePrimaryKey: "name", + targetPrimaryKey: "email", + }, +}; diff --git a/app/dashboard/admin/matcher/page.tsx b/app/dashboard/admin/matcher/page.tsx new file mode 100644 index 0000000..e97e375 --- /dev/null +++ b/app/dashboard/admin/matcher/page.tsx @@ -0,0 +1,42 @@ +import { cookies } from "next/headers"; +import MatcherPageClient from "./MatcherPageClient"; +import { MATCH_CONFIGS } from "./constants"; +import { getMatcherData } from "@/app/services/matcher"; +import { getBaseUrl } from "@/app/services/constants"; + +export default async function MatcherPage({ + searchParams, +}: { + searchParams: Promise>; +}) { + const params = await searchParams; + const matchType = + (params.type as string) || Object.keys(MATCH_CONFIGS)[0] || ""; + + const baseUrl = getBaseUrl(); + + // Forward cookies for auth when calling the internal API route + const cookieStore = await cookies(); + const cookieHeader = cookieStore + .getAll() + .map((c: { name: string; value: string }) => `${c.name}=${c.value}`) + .join("; "); + + const { sourceItems, targetItems } = await getMatcherData( + matchType, + cookieHeader, + baseUrl + ); + + const config = + MATCH_CONFIGS[matchType] || MATCH_CONFIGS[Object.keys(MATCH_CONFIGS)[0]]; + + return ( + + ); +} diff --git a/app/dashboard/admin/matcher/types.ts b/app/dashboard/admin/matcher/types.ts new file mode 100644 index 0000000..5087723 --- /dev/null +++ b/app/dashboard/admin/matcher/types.ts @@ -0,0 +1,58 @@ +type MatchType = + | "permissions-to-groups" + | "methods-to-psp" + | "psp-to-merchant" + | "groups-to-users"; + +interface MatchableEntity { + id: string | number; + name: string; + [key: string]: unknown; +} + +interface MatchColumn { + id: string; + title: string; + items: MatchableEntity[]; +} + +interface MatchConfig { + type: MatchType; + sourceLabel: string; + targetLabel: string; + sourceEndpoint: string; + targetEndpoint: string; + sourceCollectionKeys?: string[]; + targetCollectionKeys?: string[]; + sourcePrimaryKey?: string; + targetPrimaryKey?: string; +} + +interface MatcherBoardProps { + sourceItems: MatchableEntity[]; + targetItems: MatchableEntity[]; + config: MatchConfig; + onMatch?: (sourceId: string, targetId: string) => void; +} + +interface DraggableItemProps { + item: MatchableEntity; + isDragging?: boolean; +} + +interface DroppableColumnProps { + id: string; + title: string; + items: MatchableEntity[]; + activeId: string | null; +} + +export type { + MatchType, + MatchableEntity, + MatchColumn, + MatchConfig, + MatcherBoardProps, + DraggableItemProps, + DroppableColumnProps, +}; diff --git a/app/dashboard/admin/matcher/utils.ts b/app/dashboard/admin/matcher/utils.ts new file mode 100644 index 0000000..9b38e43 --- /dev/null +++ b/app/dashboard/admin/matcher/utils.ts @@ -0,0 +1,72 @@ +import { MatchableEntity } from "./types"; + +const DEFAULT_COLLECTION_KEYS = ["data", "items"]; + +export function resolveCollection( + payload: unknown, + preferredKeys: string[] = [] +): Record[] { + if (typeof payload !== "object" || payload === null) { + return []; + } + + const obj = payload as Record; + + for (const key of [...preferredKeys, ...DEFAULT_COLLECTION_KEYS]) { + const maybeCollection = obj?.[key]; + if (Array.isArray(maybeCollection)) { + return maybeCollection as Record[]; + } + } + + if (Array.isArray(payload)) { + return payload as Record[]; + } + + return []; +} + +export function normalizeEntity( + item: Record, + primaryKey: string = "name", + fallbackId: number +): MatchableEntity { + const id = item.id ?? item._id ?? fallbackId; + const name = + (item[primaryKey] as string) || + (item.name as string) || + (item.title as string) || + (item.email as string) || + `Item ${id}`; + + return { + id: String(id), + name: String(name), + ...item, + }; +} + +export function findActiveItem( + sourceItems: MatchableEntity[], + targetItems: MatchableEntity[], + activeId: string +): MatchableEntity | undefined { + return [...sourceItems, ...targetItems].find(item => item.id === activeId); +} + +export function isItemInSource( + sourceItems: MatchableEntity[], + activeId: string +): boolean { + return sourceItems.some(item => item.id === activeId); +} + +export function addItemIfNotPresent( + items: MatchableEntity[], + item: MatchableEntity +): MatchableEntity[] { + if (items.some(existingItem => existingItem.id === item.id)) { + return items; + } + return [...items, item]; +} diff --git a/app/dashboard/admin/users/page.tsx b/app/dashboard/admin/users/page.tsx index ed1e353..4cb8b83 100644 --- a/app/dashboard/admin/users/page.tsx +++ b/app/dashboard/admin/users/page.tsx @@ -1,5 +1,6 @@ import Users from "@/app/features/Pages/Admin/Users/users"; import { cookies } from "next/headers"; +import { getBaseUrl } from "@/app/services/constants"; export default async function BackOfficeUsersPage({ searchParams, @@ -11,14 +12,7 @@ export default async function BackOfficeUsersPage({ const limit = params.limit || "10"; const page = params.page || "1"; - // Build absolute URL for server-side fetch - // In server components, fetch requires absolute URLs - const port = process.env.PORT || "3000"; - const baseUrl = - process.env.NEXT_PUBLIC_BASE_URL || - (process.env.VERCEL_URL - ? `https://${process.env.VERCEL_URL}` - : `http://localhost:${port}`); + const baseUrl = getBaseUrl(); const url = new URL(`${baseUrl}/api/dashboard/admin/users`); url.searchParams.set("limit", typeof limit === "string" ? limit : limit[0]); diff --git a/app/dashboard/audits/AuditTableClient.tsx b/app/dashboard/audits/AuditTableClient.tsx index 6bc3c73..5c9b2ff 100644 --- a/app/dashboard/audits/AuditTableClient.tsx +++ b/app/dashboard/audits/AuditTableClient.tsx @@ -1,6 +1,12 @@ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { + useCallback, + useEffect, + useMemo, + useState, + useTransition, +} from "react"; import { DataGrid, GridColDef, @@ -9,13 +15,16 @@ import { } from "@mui/x-data-grid"; import TextField from "@mui/material/TextField"; import { Box, debounce } from "@mui/material"; -import useSWR from "swr"; -import { getAudits } from "@/app/services/audits"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; + +import { AuditRow } from "./auditTransforms"; +import { PAGE_SIZE_OPTIONS } from "./auditConstants"; import { - AuditQueryResult, - AuditRow, - DEFAULT_PAGE_SIZE, -} from "./auditTransforms"; + buildSortParam, + deriveColumns, + parseSortModel, + toTitle, +} from "./utils"; const FALLBACK_COLUMNS: GridColDef[] = [ { @@ -27,103 +36,55 @@ const FALLBACK_COLUMNS: GridColDef[] = [ }, ]; -const toTitle = (field: string) => - field - .replace(/_/g, " ") - .replace(/-/g, " ") - .replace(/([a-z])([A-Z])/g, "$1 $2") - .replace(/\s+/g, " ") - .trim() - .replace(/^\w/g, char => char.toUpperCase()); - -const deriveColumns = (rows: AuditRow[]): GridColDef[] => { - if (!rows.length) return []; - - return Object.keys(rows[0]).map(field => ({ - field, - headerName: toTitle(field), - flex: field === "id" ? 0 : 1, - minWidth: field === "id" ? 140 : 200, - sortable: true, - })); -}; - interface AuditTableClientProps { - initialData: AuditQueryResult; + rows: AuditRow[]; + total: number; + pageIndex: number; + pageSize: number; + sortParam?: string; + entityQuery?: string; } -const ENTITY_PREFIX = "LIKE/"; - -const buildSortParam = (sortModel: GridSortModel) => - sortModel.length && sortModel[0].field && sortModel[0].sort - ? `${sortModel[0].field}:${sortModel[0].sort}` - : undefined; - -const buildEntityParam = (entitySearch: string) => - entitySearch.trim() ? `${ENTITY_PREFIX}${entitySearch.trim()}` : undefined; - export default function AuditTableClient({ - initialData, + rows, + total, + pageIndex, + pageSize, + sortParam, + entityQuery = "", }: AuditTableClientProps) { - const [paginationModel, setPaginationModel] = useState({ - page: initialData.pageIndex ?? 0, - pageSize: DEFAULT_PAGE_SIZE, - }); - const [sortModel, setSortModel] = useState([]); - const [entitySearch, setEntitySearch] = useState(""); - const [entitySearchInput, setEntitySearchInput] = useState(""); + const router = useRouter(); + const pathname = usePathname(); + const searchParams = useSearchParams(); + const searchParamsString = searchParams.toString(); + const [isNavigating, startTransition] = useTransition(); - const [columns, setColumns] = useState( - initialData.rows.length ? deriveColumns(initialData.rows) : FALLBACK_COLUMNS + // Derive values directly from props + const paginationModel = useMemo( + () => ({ + page: pageIndex, + pageSize, + }), + [pageIndex, pageSize] ); - const debouncedSetEntitySearch = useMemo( - () => - debounce((value: string) => { - setEntitySearch(value); - setPaginationModel(prev => ({ ...prev, page: 0 })); - }, 500), - [] + const sortModel = useMemo(() => parseSortModel(sortParam), [sortParam]); + const columns = useMemo( + () => (rows.length ? deriveColumns(rows) : FALLBACK_COLUMNS), + [rows] ); + // Only entitySearchInput needs state since it's a controlled input + const normalizedEntityQuery = entityQuery.trim(); + const [entitySearchInput, setEntitySearchInput] = useState( + normalizedEntityQuery + ); + + // Sync entity input when query prop changes (e.g., from URL navigation) useEffect(() => { - return () => { - debouncedSetEntitySearch.clear(); - }; - }, [debouncedSetEntitySearch]); + setEntitySearchInput(normalizedEntityQuery); + }, [normalizedEntityQuery]); - const sortParam = useMemo(() => buildSortParam(sortModel), [sortModel]); - const entityParam = useMemo( - () => buildEntityParam(entitySearch), - [entitySearch] - ); - - const { data, error, isLoading, isValidating } = useSWR( - [ - "audits", - paginationModel.page, - paginationModel.pageSize, - sortParam ?? "", - entityParam ?? "", - ], - () => - getAudits({ - limit: paginationModel.pageSize, - page: paginationModel.page + 1, - sort: sortParam, - entity: entityParam, - }), - { - keepPreviousData: true, - revalidateOnFocus: true, - revalidateOnReconnect: true, - fallbackData: initialData, - } - ); - - const rows = data?.rows ?? initialData.rows; - const rowCount = data?.total ?? initialData.total ?? rows.length; - const loading = isLoading || (isValidating && !rows.length); const pageTitle = useMemo( () => sortModel.length && sortModel[0].field @@ -132,32 +93,65 @@ export default function AuditTableClient({ [sortModel] ); + const navigateWithParams = useCallback( + (updates: Record) => { + const params = new URLSearchParams(searchParamsString); + + Object.entries(updates).forEach(([key, value]) => { + if (!value) { + params.delete(key); + } else { + params.set(key, value); + } + }); + + startTransition(() => { + const queryString = params.toString(); + router.push(queryString ? `${pathname}?${queryString}` : pathname); + }); + }, + [pathname, router, searchParamsString, startTransition] + ); + + const debouncedEntityNavigate = useMemo( + () => + debounce((value: string) => { + navigateWithParams({ + page: "1", + entity: value.trim() ? value.trim() : null, + }); + }, 500), + [navigateWithParams] + ); + useEffect(() => { - setColumns(prev => - rows.length ? deriveColumns(rows) : prev.length ? prev : FALLBACK_COLUMNS - ); - }, [rows]); + return () => { + debouncedEntityNavigate.clear(); + }; + }, [debouncedEntityNavigate]); const handlePaginationChange = (model: GridPaginationModel) => { - setPaginationModel(model); + navigateWithParams({ + page: String(model.page + 1), + limit: String(model.pageSize), + }); }; const handleSortModelChange = (model: GridSortModel) => { - setSortModel(model); - setPaginationModel(prev => ({ ...prev, page: 0 })); + navigateWithParams({ + page: "1", + sort: buildSortParam(model) ?? null, + }); }; const handleEntitySearchChange = (value: string) => { setEntitySearchInput(value); - debouncedSetEntitySearch(value); + debouncedEntityNavigate(value); }; - const errorMessage = - error instanceof Error - ? error.message - : error - ? "Failed to load audits" - : null; + const loading = isNavigating; + + console.log("LOADING", loading); return (
@@ -172,11 +166,6 @@ export default function AuditTableClient({ />

{pageTitle}

- {errorMessage && ( -
- {errorMessage} -
- )}
+

Loading audit logs...

+
+ ); +} diff --git a/app/dashboard/audits/page.tsx b/app/dashboard/audits/page.tsx index b672cca..edc1de2 100644 --- a/app/dashboard/audits/page.tsx +++ b/app/dashboard/audits/page.tsx @@ -1,70 +1,55 @@ import "./page.scss"; import AuditTableClient from "./AuditTableClient"; +import { DEFAULT_PAGE_SIZE } from "./auditTransforms"; +import { fetchAudits } from "@/app/services/audits"; import { - AuditApiResponse, - AuditQueryResult, - DEFAULT_PAGE_SIZE, - extractArray, - normalizeRows, - resolveTotal, -} from "./auditTransforms"; -import { cookies } from "next/headers"; -import { - AUDIT_CACHE_TAG, - AUTH_COOKIE_NAME, - BE_BASE_URL, - REVALIDATE_SECONDS, -} from "@/app/services/constants"; + ENTITY_PREFIX, + PAGE_SIZE_OPTIONS, +} from "@/app/dashboard/audits/auditConstants"; -async function fetchInitialAudits(): Promise { - const cookieStore = await cookies(); - const token = cookieStore.get(AUTH_COOKIE_NAME)?.value; +type AuditPageProps = { + searchParams?: Record; +}; - if (!token) { - throw new Error("Missing auth token"); - } +const toSingleValue = (value?: string | string[]): string | undefined => { + if (Array.isArray(value)) return value[0]; + return value; +}; - const params = new URLSearchParams(); - params.set("limit", DEFAULT_PAGE_SIZE.toString()); - params.set("page", "1"); +const clampNumber = (value: number, min: number, max?: number) => { + if (Number.isNaN(value)) return min; + if (value < min) return min; + if (typeof max === "number" && value > max) return max; + return value; +}; - const backendUrl = `${BE_BASE_URL}/api/v1/audit${ - params.size ? `?${params.toString()}` : "" - }`; +export default async function AuditPage({ searchParams = {} }: AuditPageProps) { + const pageParam = toSingleValue(searchParams.page); + const limitParam = toSingleValue(searchParams.limit); + const sortParam = toSingleValue(searchParams.sort) || undefined; + const entityQuery = toSingleValue(searchParams.entity)?.trim() || ""; - const response = await fetch(backendUrl, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - next: { - revalidate: REVALIDATE_SECONDS, - tags: [AUDIT_CACHE_TAG], - }, + const page = clampNumber(parseInt(pageParam || "1", 10), 1); + const parsedLimit = parseInt(limitParam || String(DEFAULT_PAGE_SIZE), 10); + const limit = + PAGE_SIZE_OPTIONS.find(size => size === parsedLimit) ?? DEFAULT_PAGE_SIZE; + + const data = await fetchAudits({ + limit, + page, + sort: sortParam, + entity: entityQuery ? `${ENTITY_PREFIX}${entityQuery}` : undefined, }); - if (!response.ok) { - const errorData = await response - .json() - .catch(() => ({ message: "Failed to fetch audits" })); - throw new Error(errorData?.message || "Failed to fetch audits"); - } - - const payload = (await response.json()) as AuditApiResponse; - const rows = normalizeRows(extractArray(payload), 0); - const total = resolveTotal(payload, rows.length); - - return { - rows, - total, - payload, - pageIndex: 0, - }; -} - -export default async function AuditPage() { - const initialData = await fetchInitialAudits(); - return ; + return ( + + ); } diff --git a/app/dashboard/audits/utils.ts b/app/dashboard/audits/utils.ts new file mode 100644 index 0000000..6fe4f1f --- /dev/null +++ b/app/dashboard/audits/utils.ts @@ -0,0 +1,38 @@ +import { GridColDef, GridSortModel } from "@mui/x-data-grid"; +import { AuditRow } from "./auditTransforms"; + +export const buildSortParam = (sortModel: GridSortModel) => + sortModel.length && sortModel[0].field && sortModel[0].sort + ? `${sortModel[0].field}:${sortModel[0].sort}` + : undefined; + +export const parseSortModel = (sortParam?: string): GridSortModel => { + if (!sortParam) return []; + const [field, direction] = sortParam.split(":"); + if (!field || (direction !== "asc" && direction !== "desc")) { + return []; + } + + return [{ field, sort: direction }]; +}; + +export const toTitle = (field: string) => + field + .replace(/_/g, " ") + .replace(/-/g, " ") + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replace(/\s+/g, " ") + .trim() + .replace(/^\w/g, char => char.toUpperCase()); + +export const deriveColumns = (rows: AuditRow[]): GridColDef[] => { + if (!rows.length) return []; + + return Object.keys(rows[0]).map(field => ({ + field, + headerName: toTitle(field), + flex: field === "id" ? 0 : 1, + minWidth: field === "id" ? 140 : 200, + sortable: true, + })); +}; diff --git a/app/dashboard/settings/page.tsx b/app/dashboard/settings/page.tsx index 9ccc2ab..767ad41 100644 --- a/app/dashboard/settings/page.tsx +++ b/app/dashboard/settings/page.tsx @@ -1,19 +1,5 @@ import SettingsPageClient from "@/app/features/Pages/Settings/SettingsPageClient"; -// We can enable this if we want to fetch the user from the database by the id but it's not necessary since we already have the user in the redux store -// async function getUser() { -// const token = (await cookies()).get("auth_token")?.value; -// const payload = token ? await validateToken(token) : null; -// const userId = payload?.id; // requires JWT to include id -// if (!userId) throw new Error("No user id in token"); -// const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/dashboard/admin/users/${userId}`, { -// headers: { Authorization: `Bearer ${token}` }, -// cache: "no-store", -// }); -// if (!res.ok) throw new Error("Failed to fetch user"); -// return res.json(); -// } - export default async function SettingsPage() { // const user = await getUser(); diff --git a/app/features/dashboard/header/Header.scss b/app/features/dashboard/header/Header.scss index 2b46c6c..48944a6 100644 --- a/app/features/dashboard/header/Header.scss +++ b/app/features/dashboard/header/Header.scss @@ -1,4 +1,6 @@ .header { + backdrop-filter: blur(10px); + background: rgba(255, 255, 255, 0.5); .header__toolbar { display: flex; align-items: center; diff --git a/app/services/audits.ts b/app/services/audits.ts index 0e9da52..eb170b0 100644 --- a/app/services/audits.ts +++ b/app/services/audits.ts @@ -1,3 +1,5 @@ +import { cookies } from "next/headers"; + import { AuditApiResponse, AuditQueryResult, @@ -6,43 +8,64 @@ import { normalizeRows, resolveTotal, } from "@/app/dashboard/audits/auditTransforms"; -import { IGetAuditsParams } from "./types"; -import { AUDIT_CACHE_TAG, REVALIDATE_SECONDS } from "./constants"; +import { + AUDIT_CACHE_TAG, + AUTH_COOKIE_NAME, + BE_BASE_URL, + REVALIDATE_SECONDS, +} from "./constants"; -export async function getAudits({ +interface FetchAuditsParams { + limit?: number; + page?: number; + sort?: string; + filter?: string; + entity?: string; +} + +export async function fetchAudits({ limit = DEFAULT_PAGE_SIZE, page = 1, sort, filter, entity, - signal, -}: IGetAuditsParams = {}): Promise { +}: FetchAuditsParams = {}): Promise { + const cookieStore = await cookies(); + const token = cookieStore.get(AUTH_COOKIE_NAME)?.value; + + if (!token) { + throw new Error("Missing auth token"); + } + const params = new URLSearchParams(); - if (limit) params.set("limit", String(limit)); - if (page) params.set("page", String(page)); + params.set("limit", String(limit)); + params.set("page", String(page)); if (sort) params.set("sort", sort); if (filter) params.set("filter", filter); if (entity) params.set("Entity", entity); - const queryString = params.toString(); - const response = await fetch( - `/api/dashboard/audits${queryString ? `?${queryString}` : ""}`, - { - method: "GET", - signal, - next: { - revalidate: REVALIDATE_SECONDS, - tags: [AUDIT_CACHE_TAG], - }, - } - ); + const backendUrl = `${BE_BASE_URL}/api/v1/audit${ + params.size ? `?${params.toString()}` : "" + }`; + + const response = await fetch(backendUrl, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + next: { + revalidate: REVALIDATE_SECONDS, + tags: [AUDIT_CACHE_TAG], + }, + }); if (!response.ok) { const errorData = await response .json() - .catch(() => ({ message: "Unknown error" })); - throw new Error(errorData.message || "Failed to fetch audits"); + .catch(() => ({ message: "Failed to fetch audits" })); + throw new Error(errorData?.message || "Failed to fetch audits"); } const payload = (await response.json()) as AuditApiResponse; diff --git a/app/services/constants copy.ts b/app/services/constants copy.ts deleted file mode 100644 index e69de29..0000000 diff --git a/app/services/constants.ts b/app/services/constants.ts index 4ce47d7..ac19427 100644 --- a/app/services/constants.ts +++ b/app/services/constants.ts @@ -3,3 +3,13 @@ export const REVALIDATE_SECONDS = 60; export const BE_BASE_URL = process.env.BE_BASE_URL || ""; export const AUTH_COOKIE_NAME = "auth_token"; + +export function getBaseUrl(): string { + const port = process.env.PORT || "3000"; + return ( + process.env.NEXT_PUBLIC_BASE_URL || + (process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : `http://localhost:${port}`) + ); +} diff --git a/app/services/matcher.ts b/app/services/matcher.ts new file mode 100644 index 0000000..b2b9063 --- /dev/null +++ b/app/services/matcher.ts @@ -0,0 +1,83 @@ +import { MATCH_CONFIGS } from "../dashboard/admin/matcher/constants"; +import { MatchableEntity, MatchConfig } from "../dashboard/admin/matcher/types"; +import { + normalizeEntity, + resolveCollection, +} from "../dashboard/admin/matcher/utils"; + +export async function getMatcherData( + matchType: string, + cookieHeader: string, + baseUrl: string +): Promise<{ + sourceItems: MatchableEntity[]; + targetItems: MatchableEntity[]; +}> { + const config = MATCH_CONFIGS[matchType]; + if (!config) { + return { sourceItems: [], targetItems: [] }; + } + + try { + const [sourceItems, targetItems] = await Promise.all([ + fetchEntities(config.sourceEndpoint, config, cookieHeader, baseUrl, true), + fetchEntities( + config.targetEndpoint, + config, + cookieHeader, + baseUrl, + false + ), + ]); + + return { sourceItems, targetItems }; + } catch (error) { + console.error("Error fetching matcher data:", error); + return { sourceItems: [], targetItems: [] }; + } +} + +export async function fetchEntities( + endpoint: string, + config: MatchConfig, + cookieHeader: string, + baseUrl: string, + isSource: boolean +): Promise { + const url = new URL(`${baseUrl}${endpoint}`); + + // For now, fetch all items (no pagination limit) + // In production, you might want to add pagination + const response = await fetch(url.toString(), { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: cookieHeader, + }, + body: JSON.stringify({ + filters: {}, + pagination: { page: 1, limit: 1000 }, + sort: {}, + }), + cache: "no-store", + }); + + if (!response.ok) { + console.error(`Failed to fetch from ${endpoint}:`, response.status); + return []; + } + + const data = await response.json(); + console.log("[fetchEntities] data:", data, url.toString()); + const collectionKeys = isSource + ? config.sourceCollectionKeys + : config.targetCollectionKeys; + const primaryKey = isSource + ? config.sourcePrimaryKey + : config.targetPrimaryKey; + + const collection = resolveCollection(data, collectionKeys); + return collection.map((item, index) => + normalizeEntity(item, primaryKey || "name", index + 1) + ); +} diff --git a/app/services/types.ts b/app/services/types.ts deleted file mode 100644 index 43aab8a..0000000 --- a/app/services/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface IGetAuditsParams { - limit?: number; - page?: number; - sort?: string; - filter?: string; - entity?: string; - signal?: AbortSignal; -} diff --git a/app/utils/auth.ts b/app/utils/auth.ts index 452582a..1456bfb 100644 --- a/app/utils/auth.ts +++ b/app/utils/auth.ts @@ -9,6 +9,8 @@ export interface JWTPayload { role: string; iat: number; exp: number; + MustChangePassword: boolean; + Groups: string[]; } /** diff --git a/package.json b/package.json index e97f2b4..aebfab8 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,9 @@ "prepare": "husky" }, "dependencies": { + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.0", "@mui/icons-material": "^7.1.1", diff --git a/yarn.lock b/yarn.lock index f93dd46..a6bb054 100644 --- a/yarn.lock +++ b/yarn.lock @@ -104,6 +104,59 @@ "@types/tough-cookie" "^4.0.5" tough-cookie "^4.1.4" +"@dnd-kit/accessibility@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz#3b4202bd6bb370a0730f6734867785919beac6af" + integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@^6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.3.1.tgz#4c36406a62c7baac499726f899935f93f0e6d003" + integrity sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ== + dependencies: + "@dnd-kit/accessibility" "^3.1.1" + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/sortable@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-10.0.0.tgz#1f9382b90d835cd5c65d92824fa9dafb78c4c3e8" + integrity sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg== + dependencies: + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b" + integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg== + dependencies: + tslib "^2.0.0" + +"@emnapi/core@^1.4.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4" + integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791" + integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + "@emotion/babel-plugin@^11.13.5": version "11.13.5" resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz" @@ -149,7 +202,7 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== -"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.14.0", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0", "@emotion/react@^11.9.0": +"@emotion/react@^11.14.0": version "11.14.0" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz" integrity sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA== @@ -179,7 +232,7 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== -"@emotion/styled@^11.14.0", "@emotion/styled@^11.3.0", "@emotion/styled@^11.8.1": +"@emotion/styled@^11.14.0": version "11.14.0" resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz" integrity sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA== @@ -317,6 +370,124 @@ resolved "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz" integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== +"@img/sharp-darwin-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz#65049ef7c6be7857da742cd028f97602ce209635" + integrity sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.1.0" + +"@img/sharp-darwin-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz#d37ff7c75c46d5a68a3756e3f1924ef7ca7b285e" + integrity sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.1.0" + +"@img/sharp-libvips-darwin-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz#843f7c09c7245dc0d3cfec2b3c83bb08799a704f" + integrity sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA== + +"@img/sharp-libvips-darwin-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz#1239c24426c06a8e833815562f78047a3bfbaaf8" + integrity sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ== + +"@img/sharp-libvips-linux-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz#20d276cefd903ee483f0441ba35961679c286315" + integrity sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew== + +"@img/sharp-libvips-linux-arm@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz#067c0b566eae8063738cf1b1db8f8a8573b5465c" + integrity sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA== + +"@img/sharp-libvips-linux-ppc64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802" + integrity sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ== + +"@img/sharp-libvips-linux-s390x@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz#82fcd68444b3666384235279c145c2b28d8ee302" + integrity sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA== + +"@img/sharp-libvips-linux-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz#65b2b908bf47156b0724fde9095676c83a18cf5a" + integrity sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q== + +"@img/sharp-libvips-linuxmusl-arm64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz#72accf924e80b081c8db83b900b444a67c203f01" + integrity sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w== + +"@img/sharp-libvips-linuxmusl-x64@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz#1fa052737e203f46bf44192acd01f9faf11522d7" + integrity sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A== + +"@img/sharp-linux-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz#c9690fac5f3137eaab3f7ad6065390d10f66f1fa" + integrity sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.1.0" + +"@img/sharp-linux-arm@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz#771dd2ec645f85f98441359bfc118afaf38cbd8b" + integrity sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.1.0" + +"@img/sharp-linux-s390x@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz#82132d158abff57bd90b53574f2865f72f94e6c8" + integrity sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.1.0" + +"@img/sharp-linux-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz#d815fb87899d462b28b62a9252ad127f02fe0740" + integrity sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.1.0" + +"@img/sharp-linuxmusl-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz#cfac45b2abbc04628f676e123bfe3aeb300266c7" + integrity sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.1.0" + +"@img/sharp-linuxmusl-x64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz#b876c23ff51d0fb6d9f3b0a07e2f4d1436c203ad" + integrity sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.1.0" + +"@img/sharp-wasm32@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz#b1dd0bab547dccf517586eb1fa5852160bba3b82" + integrity sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ== + dependencies: + "@emnapi/runtime" "^1.4.3" + +"@img/sharp-win32-arm64@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz#f37bee0f60c167f825a09d2b8de6849b823e8b30" + integrity sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ== + +"@img/sharp-win32-ia32@0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz#8fc30b6655bc6ff8910344a2020d334aa6361672" + integrity sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw== + "@img/sharp-win32-x64@0.34.2": version "0.34.2" resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz" @@ -410,7 +581,7 @@ dependencies: "@babel/runtime" "^7.27.1" -"@mui/material@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/material@^7.1.2": +"@mui/material@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@mui/material/-/material-7.1.2.tgz" integrity sha512-Z5PYKkA6Kd8vS04zKxJNpwuvt6IoMwqpbidV7RCrRQQKwczIwcNcS8L6GnN4pzFYfEs+N9v6co27DmG07rcnoA== @@ -449,7 +620,7 @@ csstype "^3.1.3" prop-types "^15.8.1" -"@mui/system@^5.15.14 || ^6.0.0 || ^7.0.0", "@mui/system@^7.1.1": +"@mui/system@^7.1.1": version "7.1.1" resolved "https://registry.npmjs.org/@mui/system/-/system-7.1.1.tgz" integrity sha512-Kj1uhiqnj4Zo7PDjAOghtXJtNABunWvhcRU0O7RQJ7WOxeynoH6wXPcilphV8QTFtkKaip8EiNJRiCD+B3eROA== @@ -516,6 +687,15 @@ "@mui/utils" "^7.1.1" reselect "^5.1.1" +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + "@next/env@15.3.3": version "15.3.3" resolved "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz" @@ -528,6 +708,41 @@ dependencies: fast-glob "3.3.1" +"@next/swc-darwin-arm64@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz#994de8515cdfb74d337bdad645c33605de44c68b" + integrity sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg== + +"@next/swc-darwin-x64@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz#71588bad245180ffd1af1e1f894477287e739eb0" + integrity sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw== + +"@next/swc-linux-arm64-gnu@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz#66a15f749c14f04a89f8c7e21c7a8d343fc34e6e" + integrity sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw== + +"@next/swc-linux-arm64-musl@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz#14bd66213f7f33d6909574750bcb05037221a2ac" + integrity sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA== + +"@next/swc-linux-x64-gnu@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz#4a19434545e5e752d9a3ed71f9b34982725f6293" + integrity sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw== + +"@next/swc-linux-x64-musl@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz#41ab140dd0a04ab7291adbec5836c1ce251a588c" + integrity sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw== + +"@next/swc-win32-arm64-msvc@15.3.3": + version "15.3.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz#fcd1d7e0007b7b73d1acdbf0ad6d91f7aa2deb15" + integrity sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ== + "@next/swc-win32-x64-msvc@15.3.3": version "15.3.3" resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz" @@ -541,7 +756,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -577,6 +792,66 @@ resolved "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + +"@parcel/watcher-darwin-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" + integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== + +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + "@parcel/watcher-win32-x64@2.5.1": version "2.5.1" resolved "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz" @@ -655,6 +930,13 @@ dependencies: tslib "^2.8.0" +"@tybys/wasm-util@^0.10.0": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + "@types/cookie@^0.6.0": version "0.6.0" resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz" @@ -738,7 +1020,7 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== -"@types/node@^20", "@types/node@>=18": +"@types/node@^20": version "20.19.1" resolved "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz" integrity sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA== @@ -783,7 +1065,7 @@ resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz" integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w== -"@types/react@*", "@types/react@^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react@^18.2.25 || ^19", "@types/react@^19", "@types/react@^19.0.0": +"@types/react@*", "@types/react@^19": version "19.1.8" resolved "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz" integrity sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g== @@ -827,7 +1109,7 @@ natural-compare "^1.4.0" ts-api-utils "^2.1.0" -"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/parser@^8.34.1": +"@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": version "8.34.1" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz" integrity sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA== @@ -855,7 +1137,7 @@ "@typescript-eslint/types" "8.34.1" "@typescript-eslint/visitor-keys" "8.34.1" -"@typescript-eslint/tsconfig-utils@^8.34.1", "@typescript-eslint/tsconfig-utils@8.34.1": +"@typescript-eslint/tsconfig-utils@8.34.1", "@typescript-eslint/tsconfig-utils@^8.34.1": version "8.34.1" resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz" integrity sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg== @@ -870,7 +1152,7 @@ debug "^4.3.4" ts-api-utils "^2.1.0" -"@typescript-eslint/types@^8.34.1", "@typescript-eslint/types@8.34.1": +"@typescript-eslint/types@8.34.1", "@typescript-eslint/types@^8.34.1": version "8.34.1" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz" integrity sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA== @@ -909,6 +1191,98 @@ "@typescript-eslint/types" "8.34.1" eslint-visitor-keys "^4.2.1" +"@unrs/resolver-binding-android-arm-eabi@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.0.tgz#e91317973356eb845c9186db5f9ec43e8d0002eb" + integrity sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg== + +"@unrs/resolver-binding-android-arm64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.0.tgz#fbdd79b2a8e478e02e1c0751dfbc100017522161" + integrity sha512-sG1NHtgXtX8owEkJ11yn34vt0Xqzi3k9TJ8zppDmyG8GZV4kVWw44FHwKwHeEFl07uKPeC4ZoyuQaGh5ruJYPA== + +"@unrs/resolver-binding-darwin-arm64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.9.0.tgz#24bb42710227ae2f4fea191151f3acc6a75b50d6" + integrity sha512-nJ9z47kfFnCxN1z/oYZS7HSNsFh43y2asePzTEZpEvK7kGyuShSl3RRXnm/1QaqFL+iP+BjMwuB+DYUymOkA5A== + +"@unrs/resolver-binding-darwin-x64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.0.tgz#4a205940ec311ac8396c3f25043644b78cc98a20" + integrity sha512-TK+UA1TTa0qS53rjWn7cVlEKVGz2B6JYe0C++TdQjvWYIyx83ruwh0wd4LRxYBM5HeuAzXcylA9BH2trARXJTw== + +"@unrs/resolver-binding-freebsd-x64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.0.tgz#ed82e000f7248011696ecc8894f574caa197b0be" + integrity sha512-6uZwzMRFcD7CcCd0vz3Hp+9qIL2jseE/bx3ZjaLwn8t714nYGwiE84WpaMCYjU+IQET8Vu/+BNAGtYD7BG/0yA== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.0.tgz#534a8b32118590f7fb9edd21c6576243a89a8aad" + integrity sha512-bPUBksQfrgcfv2+mm+AZinaKq8LCFvt5PThYqRotqSuuZK1TVKkhbVMS/jvSRfYl7jr3AoZLYbDkItxgqMKRkg== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.0.tgz#b31718752e77cecbbcf7ba1e01dea97c1a5ee7e0" + integrity sha512-uT6E7UBIrTdCsFQ+y0tQd3g5oudmrS/hds5pbU3h4s2t/1vsGWbbSKhBSCD9mcqaqkBwoqlECpUrRJCmldl8PA== + +"@unrs/resolver-binding-linux-arm64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.0.tgz#0f11ba195020cfa869533fb74733d68162349d14" + integrity sha512-vdqBh911wc5awE2bX2zx3eflbyv8U9xbE/jVKAm425eRoOVv/VseGZsqi3A3SykckSpF4wSROkbQPvbQFn8EsA== + +"@unrs/resolver-binding-linux-arm64-musl@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.0.tgz#8b6bc086cf9efaa22e8f2fef381786d6636b8e19" + integrity sha512-/8JFZ/SnuDr1lLEVsxsuVwrsGquTvT51RZGvyDB/dOK3oYK2UqeXzgeyq6Otp8FZXQcEYqJwxb9v+gtdXn03eQ== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.0.tgz#5cd15899af31c2bbf90bfca5f798f64a16770e23" + integrity sha512-FkJjybtrl+rajTw4loI3L6YqSOpeZfDls4SstL/5lsP2bka9TiHUjgMBjygeZEis1oC8LfJTS8FSgpKPaQx2tQ== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.0.tgz#4f2c75af52437eb10b48ea5b72750fb65fb174be" + integrity sha512-w/NZfHNeDusbqSZ8r/hp8iL4S39h4+vQMc9/vvzuIKMWKppyUGKm3IST0Qv0aOZ1rzIbl9SrDeIqK86ZpUK37w== + +"@unrs/resolver-binding-linux-riscv64-musl@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.0.tgz#6a87e82e0dd39d34ff37ddba6accf73cdb396e86" + integrity sha512-bEPBosut8/8KQbUixPry8zg/fOzVOWyvwzOfz0C0Rw6dp+wIBseyiHKjkcSyZKv/98edrbMknBaMNJfA/UEdqw== + +"@unrs/resolver-binding-linux-s390x-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.0.tgz#6524cc3c01309022de86c4a7317fe7d9f9fb855c" + integrity sha512-LDtMT7moE3gK753gG4pc31AAqGUC86j3AplaFusc717EUGF9ZFJ356sdQzzZzkBk1XzMdxFyZ4f/i35NKM/lFA== + +"@unrs/resolver-binding-linux-x64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.0.tgz#85fb8a45dccf3823cd73ea4b61b2c3f2e8ab6653" + integrity sha512-WmFd5KINHIXj8o1mPaT8QRjA9HgSXhN1gl9Da4IZihARihEnOylu4co7i/yeaIpcfsI6sYs33cNZKyHYDh0lrA== + +"@unrs/resolver-binding-linux-x64-musl@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.0.tgz#235e539da5872df51c03e0e050a1c715e25044ca" + integrity sha512-CYuXbANW+WgzVRIl8/QvZmDaZxrqvOldOwlbUjIM4pQ46FJ0W5cinJ/Ghwa/Ng1ZPMJMk1VFdsD/XwmCGIXBWg== + +"@unrs/resolver-binding-wasm32-wasi@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.0.tgz#1bc614ce2ba61330c16bffa1e50f41d95d25c0a6" + integrity sha512-6Rp2WH0OoitMYR57Z6VE8Y6corX8C6QEMWLgOV6qXiJIeZ1F9WGXY/yQ8yDC4iTraotyLOeJ2Asea0urWj2fKQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.0.tgz#0d8704275a9f2634d81b35d8a00a2f4bd8dec7fa" + integrity sha512-rknkrTRuvujprrbPmGeHi8wYWxmNVlBoNW8+4XF2hXUnASOjmuC9FNF1tGbDiRQWn264q9U/oGtixyO3BT8adQ== + +"@unrs/resolver-binding-win32-ia32-msvc@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.0.tgz#46909cbeb9a38b3f31a64833fe03aa1aebb8da2b" + integrity sha512-Ceymm+iBl+bgAICtgiHyMLz6hjxmLJKqBim8tDzpX61wpZOx2bPK6Gjuor7I2RiUynVjvvkoRIkrPyMwzBzF3A== + "@unrs/resolver-binding-win32-x64-msvc@1.9.0": version "1.9.0" resolved "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.0.tgz" @@ -919,7 +1293,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0: +acorn@^8.15.0: version "8.15.0" resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== @@ -1298,12 +1672,12 @@ cross-spawn@^7.0.6: shebang-command "^2.0.0" which "^2.0.1" -csstype@^3.0.10, csstype@^3.0.2, csstype@^3.1.3: +csstype@^3.0.2, csstype@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -d3-array@^3.1.6, "d3-array@2 - 3", "d3-array@2.10.0 - 3": +"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: version "3.2.4" resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz" integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== @@ -1325,7 +1699,7 @@ d3-ease@^3.0.1: resolved "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz" integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== -d3-interpolate@^3.0.1, "d3-interpolate@1.2.0 - 3": +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz" integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== @@ -1362,7 +1736,7 @@ d3-shape@^3.1.0: dependencies: d3-time "1 - 3" -d3-time@^3.0.0, "d3-time@1 - 3", "d3-time@2.1.1 - 3": +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz" integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== @@ -1413,12 +1787,12 @@ date-fns@^2.16.1: dependencies: "@babel/runtime" "^7.21.0" -"date-fns@^2.25.0 || ^3.2.0 || ^4.0.0", date-fns@^4.1.0, "date-fns@3.0.6 || >=3.0.0": +date-fns@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz" integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg== -dayjs@^1.10.7, dayjs@^1.11.13: +dayjs@^1.11.13: version "1.11.13" resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== @@ -1701,7 +2075,7 @@ eslint-module-utils@^2.12.0: dependencies: debug "^3.2.7" -eslint-plugin-import@*, eslint-plugin-import@^2.31.0: +eslint-plugin-import@^2.31.0: version "2.31.0" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz" integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== @@ -1794,7 +2168,7 @@ eslint-visitor-keys@^4.2.1: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz" integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== -eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.23.0 || ^8.0.0 || ^9.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9: +eslint@^9: version "9.29.0" resolved "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz" integrity sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ== @@ -1883,17 +2257,6 @@ fast-equals@^5.0.1: resolved "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz" integrity sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw== -fast-glob@^3.3.2: - version "3.3.3" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz" - integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.8" - fast-glob@3.3.1: version "3.3.1" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz" @@ -1905,6 +2268,17 @@ fast-glob@3.3.1: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" @@ -2828,7 +3202,7 @@ picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -"picomatch@^3 || ^4", picomatch@^4.0.2: +picomatch@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== @@ -2898,7 +3272,7 @@ react-date-range@^2.0.1: react-list "^0.8.13" shallow-equal "^1.2.1" -"react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react-dom@^19.0.0, react-dom@>=16, react-dom@>=16.6.0: +react-dom@^19.0.0: version "19.1.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz" integrity sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g== @@ -2933,7 +3307,7 @@ react-list@^0.8.13: resolved "https://registry.npmjs.org/react-list/-/react-list-0.8.18.tgz" integrity sha512-1OSdDvzuKuwDJvQNuhXxxL+jTmmdtKg1i6KtYgxI9XR98kbOql1FcSGP+Lcvo91fk3cYng+Z6YkC6X9HRJwxfw== -"react-redux@^7.2.1 || ^8.1.3 || ^9.0.0", react-redux@^9.2.0: +react-redux@^9.2.0: version "9.2.0" resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz" integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g== @@ -2960,7 +3334,7 @@ react-transition-group@^4.4.5: loose-envify "^1.4.0" prop-types "^15.6.2" -"react@^0.14 || ^15.0.0-rc || >=15.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^17.0.0 || ^18.0.0 || ^19.0.0", "react@^18.0 || ^19", "react@^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", react@^19.0.0, react@^19.1.0, "react@>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0", react@>=16, react@>=16.6.0, react@>=16.8.0, "react@0.14 || 15 - 19": +react@^19.0.0: version "19.1.0" resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz" integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg== @@ -3013,7 +3387,7 @@ redux@^4.0.0: dependencies: "@babel/runtime" "^7.9.2" -redux@^5.0.0, redux@^5.0.1, "redux@>=5 <6", redux@>4.0.0: +redux@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz" integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== @@ -3099,7 +3473,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.8.2, "rxjs@>=7 <8": +rxjs@^7.8.2: version "7.8.2" resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz" integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== @@ -3134,7 +3508,7 @@ safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -sass@^1.3.0, sass@^1.89.2: +sass@^1.89.2: version "1.90.0" resolved "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz" integrity sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q== @@ -3291,7 +3665,7 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -source-map-js@^1.0.2, "source-map-js@>=0.6.2 <2.0.0": +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.2.1" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -3507,7 +3881,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -3574,7 +3948,7 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@^5, "typescript@>= 4.8.x", typescript@>=3.3.1, typescript@>=4.8.4, "typescript@>=4.8.4 <5.9.0": +typescript@^5: version "5.8.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==