diff --git a/apps/web/app/components/CopyCitationButton.test.tsx b/apps/web/app/components/CopyCitationButton.test.tsx new file mode 100644 index 000000000..59d99076f --- /dev/null +++ b/apps/web/app/components/CopyCitationButton.test.tsx @@ -0,0 +1,108 @@ +// @vitest-environment jsdom +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { render, screen, fireEvent, cleanup, waitFor } from '@testing-library/react'; +import { CopyCitationButton } from './CopyCitationButton'; + +const originalClipboard = navigator.clipboard; +const originalExecCommand = document.execCommand; + +afterEach(() => { + cleanup(); + vi.restoreAllMocks(); + vi.useRealTimers(); + Object.assign(navigator, { clipboard: originalClipboard }); + Object.assign(document, { execCommand: originalExecCommand }); +}); + +describe('CopyCitationButton', () => { + it('shows the copied state after a successful Clipboard API write', async () => { + const writeText = vi.fn().mockResolvedValue(undefined); + Object.assign(navigator, { clipboard: { writeText } }); + + render(); + fireEvent.click(screen.getByRole('button')); + + await waitFor(() => expect(writeText).toHaveBeenCalledWith('hello')); + await screen.findByText('Копирано!'); + expect(screen.getByRole('button').className).toContain('is-copied'); + }); + + it('falls back to execCommand when navigator.clipboard is unavailable', async () => { + Object.assign(navigator, { clipboard: undefined }); + const execCommand = vi.fn().mockReturnValue(true); + Object.assign(document, { execCommand }); + + render(); + fireEvent.click(screen.getByRole('button')); + + await screen.findByText('Копирано!'); + expect(execCommand).toHaveBeenCalledWith('copy'); + expect(screen.getByRole('button').className).toContain('is-copied'); + }); + + it('shows the failed state when both the Clipboard API and execCommand fail', async () => { + const writeText = vi.fn().mockRejectedValue(new Error('denied')); + Object.assign(navigator, { clipboard: { writeText } }); + const execCommand = vi.fn().mockReturnValue(false); + Object.assign(document, { execCommand }); + vi.spyOn(console, 'error').mockImplementation(() => {}); + + render(); + fireEvent.click(screen.getByRole('button')); + + await screen.findByText('Неуспешно копиране'); + expect(screen.getByRole('button').className).not.toContain('is-copied'); + expect(screen.getByRole('button').getAttribute('aria-label')).toBe('Копирането не бе успешно'); + }); + + it('reports failed when execCommand throws while navigator.clipboard is unavailable', async () => { + Object.assign(navigator, { clipboard: undefined }); + Object.assign(document, { + execCommand: vi.fn(() => { + throw new Error('unsupported'); + }), + }); + + render(); + fireEvent.click(screen.getByRole('button')); + + await screen.findByText('Неуспешно копиране'); + }); + + it('clears the pending reset timeout on unmount', async () => { + const writeText = vi.fn().mockResolvedValue(undefined); + Object.assign(navigator, { clipboard: { writeText } }); + const clearTimeoutSpy = vi.spyOn(window, 'clearTimeout'); + + const { unmount } = render(); + fireEvent.click(screen.getByRole('button')); + await screen.findByText('Копирано!'); + + clearTimeoutSpy.mockClear(); + unmount(); + + expect(clearTimeoutSpy).toHaveBeenCalled(); + }); + + it('does not update state after unmount when the clipboard write resolves late', async () => { + let resolveWrite: () => void = () => {}; + const writeText = vi.fn( + () => + new Promise((resolve) => { + resolveWrite = resolve; + }), + ); + Object.assign(navigator, { clipboard: { writeText } }); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + const { unmount } = render(); + fireEvent.click(screen.getByRole('button')); + await waitFor(() => expect(writeText).toHaveBeenCalled()); + + unmount(); + resolveWrite(); + await Promise.resolve(); + + expect(errorSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/web/app/components/CopyCitationButton.tsx b/apps/web/app/components/CopyCitationButton.tsx new file mode 100644 index 000000000..7759f9d8e --- /dev/null +++ b/apps/web/app/components/CopyCitationButton.tsx @@ -0,0 +1,121 @@ +import { useState, useCallback, useEffect, useRef } from 'react'; + +function copyWithExecCommand(text: string): boolean { + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.style.position = 'fixed'; + textarea.style.opacity = '0'; + textarea.setAttribute('aria-hidden', 'true'); + textarea.tabIndex = -1; + document.body.appendChild(textarea); + textarea.focus(); + textarea.select(); + let ok = false; + try { + ok = document.execCommand('copy'); + } catch { + ok = false; + } + document.body.removeChild(textarea); + return ok; +} + +export function CopyCitationButton({ textToCopy }: { textToCopy: string }) { + const [status, setStatus] = useState<'idle' | 'copied' | 'failed'>('idle'); + const timeoutRef = useRef(null); + const mountedRef = useRef(true); + + useEffect(() => { + mountedRef.current = true; + return () => { + mountedRef.current = false; + if (timeoutRef.current !== null) { + window.clearTimeout(timeoutRef.current); + } + }; + }, []); + + const resetAfterDelay = useCallback(() => { + if (timeoutRef.current !== null) { + window.clearTimeout(timeoutRef.current); + } + timeoutRef.current = window.setTimeout(() => setStatus('idle'), 2000); + }, []); + + const handleCopy = useCallback(() => { + if (typeof navigator !== 'undefined' && navigator.clipboard) { + navigator.clipboard + .writeText(textToCopy) + .then(() => { + if (!mountedRef.current) return; + setStatus('copied'); + resetAfterDelay(); + }) + .catch((err) => { + console.error('Failed to copy text:', err); + if (!mountedRef.current) return; + // execCommand('copy') here runs after an awaited promise rejection, so in some + // browsers the original click's user-gesture context may already be gone by this + // point, which can make execCommand return false even though a synchronous-first + // attempt would have succeeded. We still degrade correctly to the 'failed' UI state + // in that case, and writeText (tried first, above) is the modern/preferred path that + // succeeds in the overwhelming majority of real browsers — so this ordering is kept + // rather than reversing the priority to chase a rarer edge case. + setStatus(copyWithExecCommand(textToCopy) ? 'copied' : 'failed'); + resetAfterDelay(); + }); + return; + } + setStatus(copyWithExecCommand(textToCopy) ? 'copied' : 'failed'); + resetAfterDelay(); + }, [textToCopy, resetAfterDelay]); + + const copied = status === 'copied'; + const failed = status === 'failed'; + + return ( + + ); +} diff --git a/apps/web/app/lib/citation.test.ts b/apps/web/app/lib/citation.test.ts new file mode 100644 index 000000000..6f97f04f8 --- /dev/null +++ b/apps/web/app/lib/citation.test.ts @@ -0,0 +1,149 @@ +import { describe, it, expect } from 'vitest'; +import { buildContractCitation, buildCompanyCitation, buildAuthorityCitation } from './citation'; + +describe('citation builders', () => { + it('builds a contract citation', () => { + const c = { + subject: 'Доставка на компютри', + authority: { name: 'Община Пловдив' }, + bidder: { displayName: 'Техно ООД' }, + value: { currentEur: 125000.5 }, + id: 'abc-123', + }; + + const citation = buildContractCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Договор: Доставка на компютри', + 'Възложител: Община Пловдив', + 'Изпълнител: Техно ООД', + 'Стойност: 125 хил. €', + 'Връзка: https://sigma.test/contracts/abc-123', + ].join('\n'), + ); + }); + + it('handles contract with null value', () => { + const c = { + subject: 'Одит', + authority: { name: 'Община Пловдив' }, + bidder: { displayName: 'Техно ООД' }, + value: { currentEur: null }, + id: 'abc-123', + }; + + const citation = buildContractCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Договор: Одит', + 'Възложител: Община Пловдив', + 'Изпълнител: Техно ООД', + 'Стойност: —', + 'Връзка: https://sigma.test/contracts/abc-123', + ].join('\n'), + ); + }); + + it('builds a company citation with EIK', () => { + const c = { + displayName: 'Техно ООД', + eik: '123456789', + wonEur: 5000000, + contracts: 42, + slug: 'techno-ood', + }; + + const citation = buildCompanyCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Компания: Техно ООД', + 'ЕИК: 123456789', + 'Общо спечелено: 5 млн. €', + 'Брой договори: 42', + 'Връзка: https://sigma.test/companies/techno-ood', + ].join('\n'), + ); + }); + + it('handles contract with no awarded bidder', () => { + const c = { + subject: 'Прекратена процедура', + authority: { name: 'Община Пловдив' }, + bidder: null, + value: { currentEur: null }, + id: 'abc-123', + }; + + const citation = buildContractCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Договор: Прекратена процедура', + 'Възложител: Община Пловдив', + 'Изпълнител: —', + 'Стойност: —', + 'Връзка: https://sigma.test/contracts/abc-123', + ].join('\n'), + ); + }); + + it('builds a company citation without EIK', () => { + const c = { + displayName: 'Чуждестранна фирма', + eik: null, + wonEur: 0, + contracts: 1, + slug: 'foreign-corp', + }; + + const citation = buildCompanyCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Компания: Чуждестранна фирма', + 'ЕИК: Няма', + 'Общо спечелено: 0 €', + 'Брой договори: 1', + 'Връзка: https://sigma.test/companies/foreign-corp', + ].join('\n'), + ); + }); + + it('shows "Няма" for an empty-string EIK, not a blank line', () => { + const c = { + displayName: 'Празен ЕИК ЕООД', + eik: '', + wonEur: 250000, + contracts: 3, + slug: 'prazen-eik-eood', + }; + + const citation = buildCompanyCitation(c, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Компания: Празен ЕИК ЕООД', + 'ЕИК: Няма', + 'Общо спечелено: 250 хил. €', + 'Брой договори: 3', + 'Връзка: https://sigma.test/companies/prazen-eik-eood', + ].join('\n'), + ); + }); + + it('builds an authority citation', () => { + const a = { + name: 'Община Варна', + spentEur: 1000000, + contracts: 5, + slug: 'obshtina-varna', + }; + + const citation = buildAuthorityCitation(a, 'https://sigma.test'); + expect(citation).toBe( + [ + 'Институция: Община Варна', + 'Общо похарчено: 1 млн. €', + 'Брой договори: 5', + 'Връзка: https://sigma.test/authorities/obshtina-varna', + ].join('\n'), + ); + }); +}); diff --git a/apps/web/app/lib/citation.ts b/apps/web/app/lib/citation.ts new file mode 100644 index 000000000..e0138a5aa --- /dev/null +++ b/apps/web/app/lib/citation.ts @@ -0,0 +1,58 @@ +import { money, count } from '@sigma/shared'; + +export function buildContractCitation( + c: { + subject: string; + authority: { name: string }; + bidder: { displayName: string } | null; + value: { currentEur: number | null }; + id: string; + }, + origin: string, +): string { + return [ + `Договор: ${c.subject}`, + `Възложител: ${c.authority.name}`, + `Изпълнител: ${c.bidder ? c.bidder.displayName : '—'}`, + `Стойност: ${money(c.value.currentEur)}`, + // `c.id` is already the percent-encoded slug (contractSlug output, see + // routes/contract.tsx), so the path-safe URL below needs no `slug` field of its own. + `Връзка: ${origin}/contracts/${c.id}`, + ].join('\n'); +} + +export function buildCompanyCitation( + c: { + displayName: string; + eik: string | null; + wonEur: number; + contracts: number; + slug: string; + }, + origin: string, +): string { + return [ + `Компания: ${c.displayName}`, + `ЕИК: ${c.eik || 'Няма'}`, + `Общо спечелено: ${money(c.wonEur)}`, + `Брой договори: ${count(c.contracts)}`, + `Връзка: ${origin}/companies/${c.slug}`, + ].join('\n'); +} + +export function buildAuthorityCitation( + a: { + name: string; + spentEur: number; + contracts: number; + slug: string; + }, + origin: string, +): string { + return [ + `Институция: ${a.name}`, + `Общо похарчено: ${money(a.spentEur)}`, + `Брой договори: ${count(a.contracts)}`, + `Връзка: ${origin}/authorities/${a.slug}`, + ].join('\n'); +} diff --git a/apps/web/app/lib/meta.ts b/apps/web/app/lib/meta.ts index cd7cfd5ad..23a1fa814 100644 --- a/apps/web/app/lib/meta.ts +++ b/apps/web/app/lib/meta.ts @@ -7,6 +7,10 @@ type MetaMatches = ReadonlyArray<{ id?: string; data?: unknown } | undefined> | undefined; +// Used as the origin for absolute URLs (citations, canonical links) when the root loader's +// origin isn't available (e.g. during error boundaries or before it has run). +export const FALLBACK_ORIGIN = 'https://sigma.midt.bg'; + export function getRootOrigin(matches: MetaMatches): string | undefined { const data = matches?.find((m) => m?.id === 'root')?.data as { origin?: string } | undefined; return data?.origin || undefined; diff --git a/apps/web/app/routes/authority.tsx b/apps/web/app/routes/authority.tsx index e2266254d..e66a13f09 100644 --- a/apps/web/app/routes/authority.tsx +++ b/apps/web/app/routes/authority.tsx @@ -1,4 +1,4 @@ -import { Link } from 'react-router'; +import { Link, useMatches } from 'react-router'; import { EU_SCOREBOARD, type IndicatorRating, rateLowerIsBetter } from '@sigma/config'; import { count, money, moneyBare, pct, periodRange, plural } from '@sigma/shared'; import { @@ -13,6 +13,7 @@ import { import type { Route } from './+types/authority'; import { Breadcrumbs } from '../components/Breadcrumbs'; import { PageHeader } from '../components/PageHeader'; +import { CopyCitationButton } from '../components/CopyCitationButton'; import { FactsList } from '../components/FactsList'; import { StackedBar } from '../components/StackedBar'; import { DataTable } from '../components/DataTable'; @@ -25,7 +26,8 @@ import { publicCache } from '../lib/cache'; import { coverageRange, getCoverageMeta } from '../lib/coverage'; import { networkColumns, networkRows, trendYearColumns } from '../lib/entity-tables'; import { withDbRetry } from '../lib/retry'; -import { seoMeta } from '../lib/meta'; +import { buildAuthorityCitation } from '../lib/citation'; +import { seoMeta, getRootOrigin, FALLBACK_ORIGIN } from '../lib/meta'; export function meta({ data, params, matches }: Route.MetaArgs) { const name = data?.authority.name ?? 'Институция'; @@ -69,6 +71,8 @@ const RATING_LABEL: Record = { }; export default function Authority({ loaderData }: Route.ComponentProps) { + const matches = useMatches(); + const origin = getRootOrigin(matches) ?? FALLBACK_ORIGIN; const a = loaderData.authority; const { trend, network, competition, procedure } = loaderData; const ct = competition; @@ -107,7 +111,11 @@ export default function Authority({ loaderData }: Route.ComponentProps) { } title={a.name} lede={`Колко публични средства е похарчила институцията за обществени поръчки през ${range} г. Зад всяко число по-долу стоят конкретните договори, които го формират.`} - /> + > +
+ +
+ + > +
+ +
+ } > - {c.eopTenderId && ( - // Deep-link to the procedure's page on the public ЦАИС ЕОП portal, where the official - // documents are published and downloadable. The portal keys this page on the numeric EOP - // tenderId (preserved on the parent tender as `eop_tender_id`), NOT the noticeId/document - // number. The portal is a client-rendered SPA, so this is a clickable deep link, not a - // scrapeable file list. - - - Виж документите в ЦАИС ЕОП - - - )} + + Виж документите в ЦАИС ЕОП + + + )} +
` shows the resolved version and # what pulls it in. +# ── react-router 7.18.0 — GHSA-qwww-vcr4-c8h2 (High, CVSS 7.1), fixed in 8.3.0 ────────── +# WHY IGNORED: this CVE is a CSRF flaw in react-router's UNSTABLE RSC (React Server +# Components) code paths only — "this only affects your application if you are using the +# unstable RSC APIs" per the advisory. Verified via `git grep` across this repo for RSC +# usage (unstable_.*RSC, react-server, unstable_RSCPayload, unstable_routeRSCServerRequest): +# zero hits. This app does not use RSC. No fix exists in the 7.x line (introduced in 7.12.0, +# only patched in 8.3.0) — upgrading to react-router 8.x is a major, breaking version bump +# out of scope for a security patch to a code path this app never exercises. +# REMOVE WHEN: this app adopts react-router's RSC APIs (re-evaluate applicability first), or +# a deliberate, separately-planned major-version upgrade to react-router 8.x lands. +[[IgnoredVulns]] +id = "GHSA-qwww-vcr4-c8h2" +ignoreUntil = 2026-10-01T00:00:00Z +reason = "CSRF in react-router's unstable RSC code paths only (GHSA-qwww-vcr4-c8h2) - this app does not use RSC (verified via repo-wide grep for RSC APIs). No fix in the 7.x line; upgrading to 8.x is a major breaking change out of scope for a security patch to an unused code path." + # ── sharp 0.34.5 — GHSA-f88m-g3jw-g9cj (High, CVSS 7.0), fixed in 0.35.0 ────────────────── # WHY IGNORED: sharp is a DEV-ONLY, TRANSITIVE dependency pulled in only by `miniflare` # (Cloudflare's local Workers simulator, used by `wrangler dev` and the test suite). diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 150a51d18..895f6b4cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,11 @@ overrides: vite@8: ^8.0.16 undici: ^7.28.0 '@babel/core': ^7.29.6 + sharp: ^0.35.0 + postcss: ^8.5.18 + valibot: ^1.4.2 + react-router: ^7.18.0 + '@react-router/dev': ^7.18.0 importers: @@ -36,7 +41,7 @@ importers: version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(jsdom@29.1.1)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.1)(jiti@2.7.0)) wrangler: specifier: ^4.93.1 - version: 4.93.1(@cloudflare/workers-types@4.20260521.1) + version: 4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@25.9.1) apps/etl: dependencies: @@ -77,18 +82,21 @@ importers: specifier: ^19.2.6 version: 19.2.6(react@19.2.6) react-router: - specifier: 7.18.0 - version: 7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + specifier: ^7.18.0 + version: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) devDependencies: '@cloudflare/vite-plugin': specifier: ^1.29.1 - version: 1.37.3(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(workerd@1.20260520.1)(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)) + version: 1.37.3(@types/node@22.19.19)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(workerd@1.20260520.1)(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19)) '@react-router/dev': - specifier: 7.18.0 - version: 7.18.0(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)) + specifier: ^7.18.0 + version: 7.18.1(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19)) '@tailwindcss/vite': specifier: ^4.2.2 version: 4.3.0(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@types/node': specifier: ^22 version: 22.19.19 @@ -112,7 +120,7 @@ importers: version: 8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0) wrangler: specifier: ^4.75.0 - version: 4.93.1(@cloudflare/workers-types@4.20260521.1) + version: 4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19) packages/api-contract: dependencies: @@ -298,6 +306,10 @@ packages: peerDependencies: '@babel/core': ^7.29.6 + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} @@ -412,6 +424,9 @@ packages: '@emnapi/runtime@1.10.0': resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} @@ -584,152 +599,161 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} 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} + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@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} + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} cpu: [x64] os: [linux] libc: [musl] - '@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} + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@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} + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@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} + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@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} + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@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} + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -777,12 +801,12 @@ packages: '@poppinss/exception@1.2.3': resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} - '@react-router/dev@7.18.0': - resolution: {integrity: sha512-GVTFvul0xlZHZyVXyRpiJv54Xfyj4eDOAlGYrzi7kDmN7n40rsrUqX+hvU0fy/41SCDMtckht59R3iGR94703g==} + '@react-router/dev@7.18.1': + resolution: {integrity: sha512-1Yu5272BI8g5sl1jwmhM3aFeajXQwNbWP4qrdMYfC+ayT2khxV6KPCitLNJl+jT6DMGEKb/hmwcmKd0lFIBjxQ==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@react-router/serve': ^7.18.0 + '@react-router/serve': ^7.18.1 '@vitejs/plugin-rsc': ~0.5.21 react-router: ^7.18.0 react-server-dom-webpack: ^19.2.3 @@ -801,11 +825,11 @@ packages: wrangler: optional: true - '@react-router/node@7.18.0': - resolution: {integrity: sha512-pRXJahLrdVfuVbaTpWsZ89mBuGiYH3Z4y+y1UidwxmJFKk6NjMyUvkJl3FjDWdD+nSlgFPSESUZS0hF560MUUQ==} + '@react-router/node@7.18.1': + resolution: {integrity: sha512-2GhAwa90z/+GMFM8Q5HsgwzakYogbQcZpqpNonhN4YWDRjWkSz+t5jgwNAFvG8ENR8fKGEVEsOHIaNVDfW9Ouw==} engines: {node: '>=20.0.0'} peerDependencies: - react-router: 7.18.0 + react-router: ^7.18.0 typescript: ^5.1.0 || ^6.0.0 peerDependenciesMeta: typescript: @@ -1154,6 +1178,25 @@ packages: peerDependencies: vite: ^7.3.5 + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@turbo/darwin-64@2.9.14': resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} cpu: [x64] @@ -1187,6 +1230,9 @@ packages: '@tybys/wasm-util@0.10.2': resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -1255,9 +1301,20 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1341,10 +1398,17 @@ packages: babel-plugin-macros: optional: true + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + electron-to-chromium@1.5.360: resolution: {integrity: sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==} @@ -1541,6 +1605,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1555,8 +1623,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -1597,8 +1665,8 @@ packages: pkg-types@2.3.1: resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} prettier@3.8.3: @@ -1606,6 +1674,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1615,12 +1687,15 @@ packages: peerDependencies: react: ^19.2.6 + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-router@7.18.0: - resolution: {integrity: sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==} + react-router@7.18.1: + resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -1662,17 +1737,22 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1771,8 +1851,8 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - valibot@1.4.0: - resolution: {integrity: sha512-iC/x7fVcSyOwlm/VSt7RlHnzNGLGvR9GnxdifUeWoCJo0q4ZZvrVkIHC6faTlkxG47I2Y4UrFquPuVHCrOnrLg==} + valibot@1.4.2: + resolution: {integrity: sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -2184,6 +2264,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/runtime@7.29.7': {} + '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 @@ -2219,15 +2301,16 @@ snapshots: optionalDependencies: workerd: 1.20260520.1 - '@cloudflare/vite-plugin@1.37.3(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(workerd@1.20260520.1)(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1))': + '@cloudflare/vite-plugin@1.37.3(@types/node@22.19.19)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(workerd@1.20260520.1)(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19))': dependencies: '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260520.1) - miniflare: 4.20260520.0 + miniflare: 4.20260520.0(@types/node@22.19.19) unenv: 2.0.0-rc.24 vite: 8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0) - wrangler: 4.93.1(@cloudflare/workers-types@4.20260521.1) + wrangler: 4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19) ws: 8.21.0 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate - workerd @@ -2288,6 +2371,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.11.2': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.2.1': dependencies: tslib: 2.8.1 @@ -2375,98 +2463,108 @@ snapshots: '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.2 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.2 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.2': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.2': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.2': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.2': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.2': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.2': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.2 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.2 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.2 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.2 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.2 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.2 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.3': dependencies: - '@emnapi/runtime': 1.10.0 + '@emnapi/runtime': 1.11.2 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-win32-arm64@0.35.3': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.3': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.3': optional: true '@jridgewell/gen-mapping@0.3.13': @@ -2518,7 +2616,7 @@ snapshots: '@poppinss/exception@1.2.3': {} - '@react-router/dev@7.18.0(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1))': + '@react-router/dev@7.18.1(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)(vite@8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))(wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19))': dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 @@ -2527,7 +2625,7 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.29.7) '@babel/traverse': 7.29.7 '@babel/types': 7.29.7 - '@react-router/node': 7.18.0(react-router@7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) + '@react-router/node': 7.18.1(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3) '@remix-run/node-fetch-server': 0.13.3 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 @@ -2544,15 +2642,15 @@ snapshots: pkg-types: 2.3.1 prettier: 3.8.3 react-refresh: 0.14.2 - react-router: 7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - semver: 7.8.0 + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + semver: 7.8.5 tinyglobby: 0.2.17 - valibot: 1.4.0(typescript@5.9.3) + valibot: 1.4.2(typescript@5.9.3) vite: 8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0) vite-node: 3.2.4(@types/node@22.19.19)(jiti@2.7.0)(lightningcss@1.32.0) optionalDependencies: typescript: 5.9.3 - wrangler: 4.93.1(@cloudflare/workers-types@4.20260521.1) + wrangler: 4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -2568,10 +2666,10 @@ snapshots: - tsx - yaml - '@react-router/node@7.18.0(react-router@7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': + '@react-router/node@7.18.1(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 5.9.3 @@ -2777,6 +2875,27 @@ snapshots: tailwindcss: 4.3.0 vite: 8.0.16(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0) + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.7 + '@testing-library/dom': 10.4.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 19.2.15 + '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@turbo/darwin-64@2.9.14': optional: true @@ -2800,6 +2919,8 @@ snapshots: tslib: 2.8.1 optional: true + '@types/aria-query@5.0.4': {} + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -2880,8 +3001,16 @@ snapshots: '@opentelemetry/api': 1.9.1 zod: 4.4.3 + ansi-regex@5.0.1: {} + + ansi-styles@5.2.0: {} + arg@5.0.2: {} + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + assertion-error@2.0.1: {} babel-dead-code-elimination@1.0.12: @@ -2949,8 +3078,12 @@ snapshots: dedent@1.7.2: {} + dequal@2.0.3: {} + detect-libc@2.1.2: {} + dom-accessibility-api@0.5.16: {} + electron-to-chromium@1.5.360: {} enhanced-resolve@5.21.6: @@ -3125,27 +3258,43 @@ snapshots: dependencies: yallist: 3.1.1 + lz-string@1.5.0: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 mdn-data@2.27.1: {} - miniflare@4.20260520.0: + miniflare@4.20260520.0(@types/node@22.19.19): dependencies: '@cspotcode/source-map-support': 0.8.1 - sharp: 0.34.5 + sharp: 0.35.3(@types/node@22.19.19) undici: 7.28.0 workerd: 1.20260520.1 ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + miniflare@4.20260520.0(@types/node@25.9.1): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.35.3(@types/node@25.9.1) + undici: 7.28.0 + workerd: 1.20260520.1 + ws: 8.21.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate ms@2.1.3: {} - nanoid@3.3.12: {} + nanoid@3.3.16: {} node-releases@2.0.45: {} @@ -3178,14 +3327,20 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - postcss@8.5.15: + postcss@8.5.23: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 prettier@3.8.3: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + punycode@2.3.1: {} react-dom@19.2.6(react@19.2.6): @@ -3193,9 +3348,11 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 + react-is@17.0.2: {} + react-refresh@0.14.2: {} - react-router@7.18.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 react: 19.2.6 @@ -3269,40 +3426,75 @@ snapshots: semver@6.3.1: {} - semver@7.8.0: {} + semver@7.8.5: {} set-cookie-parser@2.7.2: {} - sharp@0.34.5: + sharp@0.35.3(@types/node@22.19.19): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.0 + semver: 7.8.5 optionalDependencies: - '@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 + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 22.19.19 + + sharp@0.35.3(@types/node@25.9.1): + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 25.9.1 siginfo@2.0.0: {} @@ -3382,7 +3574,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - valibot@1.4.0(typescript@5.9.3): + valibot@1.4.2(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 @@ -3412,7 +3604,7 @@ snapshots: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rollup: 4.60.4 tinyglobby: 0.2.17 optionalDependencies: @@ -3425,7 +3617,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -3438,7 +3630,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: @@ -3505,13 +3697,31 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260520.1 '@cloudflare/workerd-windows-64': 1.20260520.1 - wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1): + wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@22.19.19): + dependencies: + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260520.1) + blake3-wasm: 2.1.5 + esbuild: 0.28.1 + miniflare: 4.20260520.0(@types/node@22.19.19) + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260520.1 + optionalDependencies: + '@cloudflare/workers-types': 4.20260521.1 + fsevents: 2.3.3 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - utf-8-validate + + wrangler@4.93.1(@cloudflare/workers-types@4.20260521.1)(@types/node@25.9.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260520.1) blake3-wasm: 2.1.5 esbuild: 0.28.1 - miniflare: 4.20260520.0 + miniflare: 4.20260520.0(@types/node@25.9.1) path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 workerd: 1.20260520.1 @@ -3519,6 +3729,7 @@ snapshots: '@cloudflare/workers-types': 4.20260521.1 fsevents: 2.3.3 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 96815ceab..08f1cfce9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -24,6 +24,24 @@ overrides: # @babel/core <7.29.6 — arbitrary file read via sourceMappingURL (GHSA-4x5r-pxfx-6jf8); # dev/build-time only (via @react-router/dev), never ships to the Worker. '@babel/core': '^7.29.6' + # sharp <0.35.0 — HIGH severity (CVSS 7.0) advisory GHSA-f88m-g3jw-g9cj, via + # wrangler→miniflare. Dev/build-time only; never ships to the Worker. + sharp: '^0.35.0' + # postcss <8.5.18 — path traversal via sourceMappingURL auto-load + # (GHSA-r28c-9q8g-f849); patch-level fix. + # valibot <1.4.2 — flatten() crashes on inherited-property keys + # (GHSA-5qjj-4xww-7phc); patch-level fix. + postcss: '^8.5.18' + valibot: '^1.4.2' + # react-router <7.18.0 — 4 advisories fixed within the 7.x line (no major bump needed): + # SSR hydration constructor injection (GHSA-337j-9hxr-rhxg), unauthenticated + # DoS via inefficient route matching (GHSA-chx6-hx7r-mcp5), RSCErrorHandler + # missing protocol validation / XSS (GHSA-h8fp-f39c-q6mh), open redirect via + # backslash in Link/useNavigate (GHSA-wrjc-x8rr-h8h6). The separate + # GHSA-qwww-vcr4-c8h2 (RSC-only CSRF, needs 8.x) is NOT fixed by this pin — + # see osv-scanner.toml for why that one is suppressed instead of bumped. + 'react-router': '^7.18.0' + '@react-router/dev': '^7.18.0' onlyBuiltDependencies: - esbuild