From 18e68bb17641a2b944dc52b3070da37978d1aa30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Tue, 7 Apr 2026 13:49:52 +0200 Subject: [PATCH 001/642] Add public changelog with Atom feed and What's New indicator - Changelog entries authored as markdown files in apps/journal/changelog/ with YAML frontmatter, loaded via Vite import.meta.glob at build time - /changelog list page with date, title, and preview - /changelog/:slug detail page with full markdown rendering (react-markdown) and Open Graph meta tags for social sharing - /changelog/feed.xml Atom feed with auto-discovery tags - "What's New" dot on nav bar using localStorage timestamp tracking - Notification toggle: users can permanently disable/re-enable the indicator - i18n strings for en and de - Initial changelog entry covering the Phase 1 launch Co-Authored-By: Claude Opus 4.6 (1M context) --- .../app/components/ChangelogIndicator.tsx | 78 ++ apps/journal/app/lib/changelog.server.ts | 73 ++ apps/journal/app/root.tsx | 9 +- apps/journal/app/routes.ts | 3 + apps/journal/app/routes/changelog.$slug.tsx | 50 ++ apps/journal/app/routes/changelog._index.tsx | 58 ++ .../app/routes/changelog.feed[.xml].ts | 51 ++ apps/journal/changelog/2026-03-25.md | 34 + openspec/changes/changelog/design.md | 21 +- openspec/changes/changelog/proposal.md | 6 +- .../changes/changelog/specs/changelog/spec.md | 21 + openspec/changes/changelog/tasks.md | 48 +- package.json | 1 + packages/i18n/src/locales/de.ts | 7 + packages/i18n/src/locales/en.ts | 7 + pnpm-lock.yaml | 667 ++++++++++++++++++ 16 files changed, 1109 insertions(+), 25 deletions(-) create mode 100644 apps/journal/app/components/ChangelogIndicator.tsx create mode 100644 apps/journal/app/lib/changelog.server.ts create mode 100644 apps/journal/app/routes/changelog.$slug.tsx create mode 100644 apps/journal/app/routes/changelog._index.tsx create mode 100644 apps/journal/app/routes/changelog.feed[.xml].ts create mode 100644 apps/journal/changelog/2026-03-25.md diff --git a/apps/journal/app/components/ChangelogIndicator.tsx b/apps/journal/app/components/ChangelogIndicator.tsx new file mode 100644 index 0000000..c0ac4f4 --- /dev/null +++ b/apps/journal/app/components/ChangelogIndicator.tsx @@ -0,0 +1,78 @@ +import { useEffect, useState } from "react"; +import { Link, useLocation } from "react-router"; +import { useTranslation } from "react-i18next"; + +const LAST_SEEN_KEY = "changelog:lastSeen"; +const DISABLED_KEY = "changelog:disabled"; + +export function ChangelogLink({ + newestDate, + className, +}: { + newestDate: string | null; + className: (active: boolean) => string; +}) { + const { t } = useTranslation("journal"); + const location = useLocation(); + const [showDot, setShowDot] = useState(false); + const isActive = + location.pathname === "/changelog" || + location.pathname.startsWith("/changelog/"); + + useEffect(() => { + if (!newestDate) return; + const disabled = localStorage.getItem(DISABLED_KEY); + if (disabled === "true") return; + const lastSeen = localStorage.getItem(LAST_SEEN_KEY); + if (!lastSeen || newestDate > lastSeen) { + setShowDot(true); + } + }, [newestDate]); + + useEffect(() => { + if (isActive && newestDate) { + localStorage.setItem(LAST_SEEN_KEY, newestDate); + setShowDot(false); + } + }, [isActive, newestDate]); + + return ( + + {t("nav.changelog")} + {showDot && ( + + )} + + ); +} + +export function ChangelogNotificationToggle() { + const { t } = useTranslation("journal"); + const [disabled, setDisabled] = useState(false); + + useEffect(() => { + setDisabled(localStorage.getItem(DISABLED_KEY) === "true"); + }, []); + + function toggle() { + if (disabled) { + localStorage.removeItem(DISABLED_KEY); + setDisabled(false); + } else { + localStorage.setItem(DISABLED_KEY, "true"); + setDisabled(true); + } + } + + return ( + + ); +} diff --git a/apps/journal/app/lib/changelog.server.ts b/apps/journal/app/lib/changelog.server.ts new file mode 100644 index 0000000..885dc2e --- /dev/null +++ b/apps/journal/app/lib/changelog.server.ts @@ -0,0 +1,73 @@ +const modules = import.meta.glob("/changelog/*.md", { + query: "?raw", + import: "default", + eager: true, +}) as Record; + +export interface ChangelogEntry { + slug: string; + title: string; + date: string; + preview: string; + content: string; +} + +function parseFrontmatter(raw: string): { + attrs: Record; + body: string; +} { + const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); + if (!match) return { attrs: {}, body: raw }; + const attrs: Record = {}; + for (const line of match[1]!.split("\n")) { + const idx = line.indexOf(":"); + if (idx === -1) continue; + const key = line.slice(0, idx).trim(); + const value = line.slice(idx + 1).trim().replace(/^["']|["']$/g, ""); + attrs[key] = value; + } + return { attrs, body: match[2]! }; +} + +function firstParagraph(md: string): string { + const trimmed = md.trim(); + const lines: string[] = []; + for (const line of trimmed.split("\n")) { + if (line.startsWith("#")) continue; + if (lines.length > 0 && line.trim() === "") break; + if (line.trim() !== "") lines.push(line); + } + return lines.join(" ").slice(0, 200); +} + +function parseEntry(path: string, raw: string): ChangelogEntry { + const slug = path.replace(/^\/changelog\//, "").replace(/\.md$/, ""); + const { attrs, body } = parseFrontmatter(raw); + return { + slug, + title: attrs.title ?? slug, + date: attrs.date ?? slug, + preview: firstParagraph(body), + content: body, + }; +} + +let cachedEntries: ChangelogEntry[] | null = null; + +export function getAllEntries(): ChangelogEntry[] { + if (!cachedEntries) { + cachedEntries = Object.entries(modules) + .map(([path, raw]) => parseEntry(path, raw)) + .sort((a, b) => b.date.localeCompare(a.date)); + } + return cachedEntries; +} + +export function getEntry(slug: string): ChangelogEntry | undefined { + return getAllEntries().find((e) => e.slug === slug); +} + +export function getNewestDate(): string | null { + const entries = getAllEntries(); + return entries.length > 0 ? entries[0]!.date : null; +} diff --git a/apps/journal/app/root.tsx b/apps/journal/app/root.tsx index be4a5f4..a51ea58 100644 --- a/apps/journal/app/root.tsx +++ b/apps/journal/app/root.tsx @@ -1,5 +1,6 @@ import { useEffect } from "react"; import { Links, Meta, Outlet, Scripts, ScrollRestoration, isRouteErrorResponse, useLocation, Form, Link } from "react-router"; +import { ChangelogLink } from "~/components/ChangelogIndicator"; import type { LinksFunction } from "react-router"; import type { Route } from "./+types/root"; import * as Sentry from "@sentry/react"; @@ -34,12 +35,13 @@ export function Layout({ children }: { children: React.ReactNode }) { } export async function loader({ request }: Route.LoaderArgs) { + const { getNewestDate } = await import("~/lib/changelog.server"); const user = await getSessionUser(request); const locale = detectLocale(request); - return { user: user ? { id: user.id, username: user.username } : null, locale }; + return { user: user ? { id: user.id, username: user.username } : null, locale, newestChangelogDate: getNewestDate() }; } -function NavBar({ user }: { user: { id: string; username: string } | null }) { +function NavBar({ user, newestChangelogDate }: { user: { id: string; username: string } | null; newestChangelogDate: string | null }) { const { t } = useTranslation("journal"); const location = useLocation(); @@ -60,6 +62,7 @@ function NavBar({ user }: { user: { id: string; username: string } | null }) { {t("title")} + linkClass("/changelog")} /> {user && ( <> @@ -124,7 +127,7 @@ export default function App({ loaderData }: Route.ComponentProps) { return ( - + ); diff --git a/apps/journal/app/routes.ts b/apps/journal/app/routes.ts index 60e9952..3fa8016 100644 --- a/apps/journal/app/routes.ts +++ b/apps/journal/app/routes.ts @@ -30,4 +30,7 @@ export default [ route("api/sync/disconnect/:provider", "routes/api.sync.disconnect.$provider.ts"), route("api/sync/webhook/:provider", "routes/api.sync.webhook.$provider.ts"), route("privacy", "routes/privacy.tsx"), + route("changelog", "routes/changelog._index.tsx"), + route("changelog/feed.xml", "routes/changelog.feed[.xml].ts"), + route("changelog/:slug", "routes/changelog.$slug.tsx"), ] satisfies RouteConfig; diff --git a/apps/journal/app/routes/changelog.$slug.tsx b/apps/journal/app/routes/changelog.$slug.tsx new file mode 100644 index 0000000..c13e5c8 --- /dev/null +++ b/apps/journal/app/routes/changelog.$slug.tsx @@ -0,0 +1,50 @@ +import { data } from "react-router"; +import { useTranslation } from "react-i18next"; +import Markdown from "react-markdown"; +import type { Route } from "./+types/changelog.$slug"; +import { getEntry } from "~/lib/changelog.server"; +import { ClientDate } from "~/components/ClientDate"; + +export function meta({ data: entry }: Route.MetaArgs) { + if (!entry) return [{ title: "Not Found — trails.cool" }]; + return [ + { title: `${entry.title} — Changelog — trails.cool` }, + { name: "description", content: entry.preview }, + { property: "og:title", content: entry.title }, + { property: "og:description", content: entry.preview }, + { property: "og:url", content: `https://trails.cool/changelog/${entry.slug}` }, + ]; +} + +export function links() { + return [ + { rel: "alternate", type: "application/atom+xml", title: "trails.cool Changelog", href: "/changelog/feed.xml" }, + ]; +} + +export async function loader({ params }: Route.LoaderArgs) { + const entry = getEntry(params.slug); + if (!entry) throw data(null, { status: 404 }); + return entry; +} + +export default function ChangelogEntryPage({ loaderData: entry }: Route.ComponentProps) { + const { t } = useTranslation("journal"); + + return ( +
+ + {t("changelog.backToList")} + +
+ +

{entry.title}

+
+ {entry.content} +
+
+
+ ); +} diff --git a/apps/journal/app/routes/changelog._index.tsx b/apps/journal/app/routes/changelog._index.tsx new file mode 100644 index 0000000..11076e7 --- /dev/null +++ b/apps/journal/app/routes/changelog._index.tsx @@ -0,0 +1,58 @@ +import { Link } from "react-router"; +import { useTranslation } from "react-i18next"; +import type { Route } from "./+types/changelog._index"; +import { getAllEntries, getNewestDate } from "~/lib/changelog.server"; +import { ClientDate } from "~/components/ClientDate"; +import { ChangelogNotificationToggle } from "~/components/ChangelogIndicator"; + +export function meta() { + return [ + { title: "Changelog — trails.cool" }, + { name: "description", content: "What's new on trails.cool" }, + { property: "og:title", content: "Changelog — trails.cool" }, + { property: "og:description", content: "What's new on trails.cool" }, + ]; +} + +export function links() { + return [ + { rel: "alternate", type: "application/atom+xml", title: "trails.cool Changelog", href: "/changelog/feed.xml" }, + ]; +} + +export async function loader() { + return { entries: getAllEntries(), newestDate: getNewestDate() }; +} + +export default function ChangelogListPage({ loaderData }: Route.ComponentProps) { + const { entries } = loaderData; + const { t } = useTranslation("journal"); + + return ( +
+
+
+

{t("changelog.title")}

+

{t("changelog.subtitle")}

+
+ +
+ +
+ {entries.map((entry) => ( + + +

{entry.title}

+

{entry.preview}

+ + ))} +
+
+ ); +} diff --git a/apps/journal/app/routes/changelog.feed[.xml].ts b/apps/journal/app/routes/changelog.feed[.xml].ts new file mode 100644 index 0000000..939d7dd --- /dev/null +++ b/apps/journal/app/routes/changelog.feed[.xml].ts @@ -0,0 +1,51 @@ +import { getAllEntries } from "~/lib/changelog.server"; +import Markdown from "react-markdown"; +import { renderToStaticMarkup } from "react-dom/server"; +import { createElement } from "react"; + +function renderMarkdown(md: string): string { + return renderToStaticMarkup(createElement(Markdown, null, md)); +} + +function escapeXml(str: string): string { + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +export async function loader() { + const entries = getAllEntries(); + const domain = process.env.DOMAIN ?? "trails.cool"; + const baseUrl = `https://${domain}`; + const updated = entries[0]?.date ?? new Date().toISOString().slice(0, 10); + + const atomEntries = entries.map((entry) => { + const html = renderMarkdown(entry.content); + return ` + ${escapeXml(entry.title)} + + ${baseUrl}/changelog/${entry.slug} + ${entry.date}T00:00:00Z + ${escapeXml(html)} + `; + }); + + const feed = ` + + trails.cool Changelog + + + ${baseUrl}/changelog + ${updated}T00:00:00Z +${atomEntries.join("\n")} +`; + + return new Response(feed, { + headers: { + "Content-Type": "application/atom+xml; charset=utf-8", + "Cache-Control": "public, max-age=3600", + }, + }); +} diff --git a/apps/journal/changelog/2026-03-25.md b/apps/journal/changelog/2026-03-25.md new file mode 100644 index 0000000..ff88492 --- /dev/null +++ b/apps/journal/changelog/2026-03-25.md @@ -0,0 +1,34 @@ +--- +title: "trails.cool is live" +date: 2026-03-25 +--- + +We're excited to launch trails.cool — a federated, self-hostable platform for outdoor enthusiasts. + +## Planner: Collaborative Route Planning + +Plan hiking, cycling, and driving routes together in real-time. No account needed — just share a link and start editing. + +- **Real-time collaboration** via Yjs — changes sync instantly across all participants +- **Smart routing** powered by BRouter with profiles for hiking, fast cycling, safe cycling, shortest path, and car +- **Elevation profiles** with total ascent and descent statistics +- **Route coloring** by elevation gradient or surface type +- **No-go areas** — draw polygons on the map to avoid specific regions +- **GPX import and export** — bring routes from other apps or export for your GPS device +- **Session notes** — shared text area for trip planning details +- **Crash recovery** — unsaved work is preserved if your browser crashes + +## Journal: Your Activity Hub + +Track your routes and outdoor activities with a personal journal. + +- **Route management** with GPX import/export and sequential versioning +- **Activity tracking** — log activities with GPS traces, distances, and durations +- **Wahoo integration** — automatic sync of workouts via webhook, plus manual import +- **Map previews** on route and activity list pages +- **Passkey authentication** — passwordless login, no passwords to remember +- **Magic link fallback** for devices without passkey support + +## Self-Hostable and Privacy-First + +trails.cool is designed for data ownership. Host your own instance, keep your data, export everything as GPX or JSON. We collect zero analytics, zero tracking — your routes are yours. diff --git a/openspec/changes/changelog/design.md b/openspec/changes/changelog/design.md index d88d976..09b7e15 100644 --- a/openspec/changes/changelog/design.md +++ b/openspec/changes/changelog/design.md @@ -16,7 +16,7 @@ produces shareable social links. **Non-Goals:** - CMS or admin interface for writing entries -- RSS feed (future, not now) +- RSS/Atom feed for subscribing to updates - Email notifications for new entries - Per-entry images or rich media (just markdown text) - Bilingual entries (English only for now) @@ -50,11 +50,30 @@ Store `changelog:lastSeen` timestamp in localStorage. If the newest entry's date is after this timestamp, show a dot on the nav "Changelog" link. Clicking the changelog page updates the timestamp. No server state needed. +Users can permanently disable the "What's New" indicator by setting +`changelog:disabled` in localStorage. A "Don't show again" option is available +on the changelog page. When disabled, the dot never appears regardless of new +entries. The setting can be re-enabled from the changelog page itself via a +"Show new entry notifications" toggle. All client-side, no auth required. + ### D4: Open Graph meta for social sharing Each `/changelog/:date` page sets `og:title`, `og:description` (first paragraph), and `og:url`. No og:image for now — text previews are fine. +### D5: RSS/Atom feed at `/changelog/feed.xml` + +A standard Atom feed at `/changelog/feed.xml` so users and tools can subscribe. +Generated server-side from the same changelog entries used by the HTML pages. +Each `` includes the title, date, full markdown content rendered as HTML, +and a link to the individual changelog page. + +The feed URL is advertised via a `` +tag in the `` of the changelog pages, so feed readers auto-discover it. + +Atom over RSS 2.0 because Atom has a proper spec (RFC 4287), required dates, +and better content handling. All major feed readers support both. + ## Risks / Trade-offs - **Build-time loading means deploy to publish** → Acceptable. We deploy on diff --git a/openspec/changes/changelog/proposal.md b/openspec/changes/changelog/proposal.md index 2a47bfe..eda814a 100644 --- a/openspec/changes/changelog/proposal.md +++ b/openspec/changes/changelog/proposal.md @@ -22,7 +22,7 @@ project is alive and improving), and social followers (shareable updates). ### New Capabilities -- `changelog`: Public changelog with dated entries, shareable individual pages with OG tags, "what's new" indicator +- `changelog`: Public changelog with dated entries, shareable individual pages with OG tags, "what's new" indicator, RSS/Atom feed ### Modified Capabilities @@ -30,8 +30,8 @@ project is alive and improving), and social followers (shareable updates). ## Impact -- **Files**: New routes (`/changelog`, `/changelog/:slug`), markdown entry files - in `docs/changelog/` or `apps/journal/changelog/`, nav bar update +- **Files**: New routes (`/changelog`, `/changelog/:slug`, `/changelog/feed.xml`), + markdown entry files in `apps/journal/changelog/`, nav bar update - **Dependencies**: A markdown renderer (could reuse `react-markdown` or render at build time) - **i18n**: Changelog entries written in English (primary audience), German diff --git a/openspec/changes/changelog/specs/changelog/spec.md b/openspec/changes/changelog/specs/changelog/spec.md index 6d99060..27f4bed 100644 --- a/openspec/changes/changelog/specs/changelog/spec.md +++ b/openspec/changes/changelog/specs/changelog/spec.md @@ -35,3 +35,24 @@ The system SHALL show a visual indicator when there are changelog entries the us #### Scenario: Indicator dismissed - **WHEN** a user visits the /changelog page - **THEN** the indicator is dismissed (localStorage timestamp updated) + +#### Scenario: Permanently disable indicator +- **WHEN** a user clicks "Don't show again" on the changelog page +- **THEN** `changelog:disabled` is set in localStorage +- **AND** the "What's New" dot no longer appears for any future entries + +#### Scenario: Re-enable indicator +- **WHEN** a user toggles "Show new entry notifications" on the changelog page +- **THEN** `changelog:disabled` is removed from localStorage +- **AND** the indicator resumes normal behavior + +### Requirement: RSS/Atom feed +The system SHALL provide an Atom feed at `/changelog/feed.xml` for subscribing to changelog updates. + +#### Scenario: Subscribe to feed +- **WHEN** a feed reader requests `/changelog/feed.xml` +- **THEN** it receives a valid Atom feed with all changelog entries including title, date, content, and link + +#### Scenario: Feed auto-discovery +- **WHEN** a browser or feed reader visits any `/changelog` page +- **THEN** a `` tag in the page head points to the feed URL diff --git a/openspec/changes/changelog/tasks.md b/openspec/changes/changelog/tasks.md index 276e3b4..f7a9f99 100644 --- a/openspec/changes/changelog/tasks.md +++ b/openspec/changes/changelog/tasks.md @@ -1,29 +1,41 @@ ## 1. Changelog Data Layer -- [ ] 1.1 Create `apps/journal/changelog/` directory with a sample entry (`2026-03-25.md`) covering the initial launch -- [ ] 1.2 Set up Vite `import.meta.glob` to load all `.md` files from the changelog directory with frontmatter parsing -- [ ] 1.3 Create `apps/journal/app/lib/changelog.server.ts` with functions: getAllEntries(), getEntry(date) returning parsed markdown + frontmatter +- [x] 1.1 Create `apps/journal/changelog/` directory with a sample entry (`2026-03-25.md`) covering the initial launch +- [x] 1.2 Set up Vite `import.meta.glob` to load all `.md` files from the changelog directory with frontmatter parsing +- [x] 1.3 Create `apps/journal/app/lib/changelog.server.ts` with functions: getAllEntries(), getEntry(date) returning parsed markdown + frontmatter ## 2. Routes -- [ ] 2.1 Add `/changelog` route showing all entries (date, title, preview) newest-first -- [ ] 2.2 Add `/changelog/:date` route rendering full markdown entry -- [ ] 2.3 Add Open Graph meta tags on entry pages (og:title, og:description, og:url) -- [ ] 2.4 Add both routes to `routes.ts` +- [x] 2.1 Add `/changelog` route showing all entries (date, title, preview) newest-first +- [x] 2.2 Add `/changelog/:date` route rendering full markdown entry +- [x] 2.3 Add Open Graph meta tags on entry pages (og:title, og:description, og:url) +- [x] 2.4 Add both routes to `routes.ts` -## 3. What's New Indicator +## 3. RSS/Atom Feed -- [ ] 3.1 Add "Changelog" link to Journal nav bar -- [ ] 3.2 Track `changelog:lastSeen` in localStorage, show dot when newest entry is newer -- [ ] 3.3 Clear indicator when user visits /changelog +- [x] 3.1 Add `/changelog/feed.xml` route that returns an Atom feed (application/atom+xml) with all entries +- [x] 3.2 Add `` to changelog page heads for feed auto-discovery -## 4. Content +## 4. What's New Indicator -- [ ] 4.1 Write initial changelog entry for the launch (features shipped in Phase 1) -- [ ] 4.2 Add markdown rendering (react-markdown or built-in) for entry content +- [x] 4.1 Add "Changelog" link to Journal nav bar +- [x] 4.2 Track `changelog:lastSeen` in localStorage, show dot when newest entry is newer +- [x] 4.3 Clear indicator when user visits /changelog +- [x] 4.4 Add "Don't show again" option on changelog page that sets `changelog:disabled` in localStorage +- [x] 4.5 Add "Show new entry notifications" toggle on changelog page to re-enable the indicator +- [x] 4.6 Skip indicator check when `changelog:disabled` is set -## 5. Verify +## 5. Content -- [ ] 5.1 Verify /changelog lists entries correctly -- [ ] 5.2 Verify /changelog/:date renders full entry with OG tags -- [ ] 5.3 Verify "What's New" dot appears and dismisses +- [x] 5.1 Write initial changelog entry for the launch (features shipped in Phase 1) +- [x] 5.2 Add markdown rendering (react-markdown or built-in) for entry content + +## 6. Verify + +- [x] 6.1 Verify /changelog lists entries correctly +- [x] 6.2 Verify /changelog/:date renders full entry with OG tags +- [x] 6.3 Verify "What's New" dot appears and dismisses +- [x] 6.6 Verify "Don't show again" disables indicator permanently +- [x] 6.7 Verify re-enabling notifications restores indicator behavior +- [x] 6.4 Verify /changelog/feed.xml returns valid Atom feed +- [x] 6.5 Verify feed auto-discovery link is present in page source diff --git a/package.json b/package.json index 0a2fe43..4f0780a 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "react-dom": "^19.2.4", "react-i18next": "^17.0.2", "react-leaflet": "^5.0.0", + "react-markdown": "^10.1.0", "react-router": "catalog:", "tailwindcss": "^4.2.2", "turbo": "^2.9.3", diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index 51f0a30..eb6fff1 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -192,9 +192,16 @@ export default { previous: "Zurück", next: "Weiter", }, + changelog: { + title: "Änderungsprotokoll", + subtitle: "Was gibt es Neues auf trails.cool", + backToList: "Zurück zum Änderungsprotokoll", + showNotifications: "Über neue Einträge benachrichtigen", + }, nav: { routes: "Routen", activities: "Aktivitäten", + changelog: "Änderungen", login: "Anmelden", register: "Registrieren", profile: "Profil", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index 31490a8..702d3a5 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -192,9 +192,16 @@ export default { previous: "Previous", next: "Next", }, + changelog: { + title: "Changelog", + subtitle: "What's new on trails.cool", + backToList: "Back to Changelog", + showNotifications: "Notify me of new entries", + }, nav: { routes: "Routes", activities: "Activities", + changelog: "Changelog", login: "Sign In", register: "Register", profile: "Profile", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 994c1ab..5a9a5e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,9 @@ importers: react-leaflet: specifier: ^5.0.0 version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.14)(react@19.2.4) react-router: specifier: 'catalog:' version: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -1957,24 +1960,39 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/leaflet@1.9.21': resolution: {integrity: sha512-TbAd9DaPGSnzp6QvtYngntMZgcRk+igFELwR2N99XZn7RXUdKgsXMR+28bUO0rPsWp8MIu/f47luLIQuSLYv/w==} + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mysql@2.15.27': resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} @@ -2001,6 +2019,12 @@ packages: '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -2063,6 +2087,9 @@ packages: resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vitejs/plugin-basic-ssl@2.3.0': resolution: {integrity: sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2160,6 +2187,9 @@ packages: babel-dead-code-elimination@1.0.12: resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} @@ -2226,10 +2256,25 @@ packages: caniuse-lite@1.0.30001781: resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@6.2.2: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2240,6 +2285,9 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -2324,6 +2372,9 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + dedent@1.7.2: resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: @@ -2351,6 +2402,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -2594,6 +2648,9 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -2620,6 +2677,9 @@ packages: exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-copy@4.0.2: resolution: {integrity: sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==} @@ -2732,6 +2792,12 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + help-me@5.0.0: resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} @@ -2745,6 +2811,9 @@ packages: html-parse-stringify@3.0.1: resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -2800,10 +2869,22 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2812,6 +2893,13 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -2968,6 +3056,9 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + lru-cache@11.2.7: resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} engines: {node: 20 || >=22} @@ -2986,6 +3077,30 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} @@ -3000,6 +3115,69 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -3122,6 +3300,9 @@ packages: resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} engines: {node: '>=18'} + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse5@8.0.0: resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} @@ -3249,6 +3430,9 @@ packages: resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==} engines: {node: ^16 || ^18 || >=20} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -3322,6 +3506,12 @@ packages: react: ^19.0.0 react-dom: ^19.0.0 + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -3355,6 +3545,12 @@ packages: reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} @@ -3461,6 +3657,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + splaytree-ts@1.0.2: resolution: {integrity: sha512-0kGecIZNIReCSiznK3uheYB8sbstLjCZLiwcQwbmLhgHJj2gz6OnSPkVzJQCMnmEz1BQ4gPK59ylhBoEWOhGNA==} @@ -3478,6 +3677,9 @@ packages: std-env@4.0.0: resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -3486,6 +3688,12 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + sweepline-intersections@1.5.0: resolution: {integrity: sha512-AoVmx72QHpKtItPu72TzFL+kcYjd67BPLDoR0LarIk+xyaRg+pDTMFXndIEvZf9xEKnJv6JdhgRMnocoG0D3AQ==} @@ -3546,6 +3754,12 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -3601,6 +3815,24 @@ packages: resolution: {integrity: sha512-3IWdCpjgxp15CbJnsi/Y9TCDE7HWVN19j1hmzVhoAkY/+CJx449tVxT5wZc1Gwg8J+P0LWvzlBzxYRnHJ+1i7Q==} engines: {node: '>=20.18.1'} + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -3635,6 +3867,12 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -3807,6 +4045,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + snapshots: '@adobe/css-tools@4.4.4': {} @@ -5342,20 +5583,38 @@ snapshots: dependencies: '@types/node': 25.5.2 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} '@types/esrecurse@4.3.1': {} + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + '@types/estree@1.0.8': {} '@types/geojson@7946.0.16': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/leaflet@1.9.21': dependencies: '@types/geojson': 7946.0.16 + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + '@types/mysql@2.15.27': dependencies: '@types/node': 25.5.2 @@ -5390,6 +5649,10 @@ snapshots: dependencies: '@types/node': 25.5.2 + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + '@types/ws@8.18.1': dependencies: '@types/node': 25.5.2 @@ -5485,6 +5748,8 @@ snapshots: '@typescript-eslint/types': 8.58.0 eslint-visitor-keys: 5.0.1 + '@ungap/structured-clone@1.3.0': {} + '@vitejs/plugin-basic-ssl@2.3.0(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': dependencies: vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) @@ -5591,6 +5856,8 @@ snapshots: transitivePeerDependencies: - supports-color + bail@2.0.2: {} + balanced-match@4.0.4: {} base64-js@1.5.1: {} @@ -5663,8 +5930,18 @@ snapshots: caniuse-lite@1.0.30001781: {} + ccount@2.0.1: {} + chai@6.2.2: {} + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -5673,6 +5950,8 @@ snapshots: colorette@2.0.20: {} + comma-separated-tokens@2.0.3: {} + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -5751,6 +6030,10 @@ snapshots: decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + dedent@1.7.2: {} deep-is@0.1.4: {} @@ -5763,6 +6046,10 @@ snapshots: detect-libc@2.1.2: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + dom-accessibility-api@0.5.16: {} dom-accessibility-api@0.6.3: {} @@ -6000,6 +6287,8 @@ snapshots: estraverse@5.3.0: {} + estree-util-is-identifier-name@3.0.0: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -6050,6 +6339,8 @@ snapshots: exsolve@1.0.8: {} + extend@3.0.2: {} + fast-copy@4.0.2: {} fast-deep-equal@3.1.3: {} @@ -6156,6 +6447,30 @@ snapshots: dependencies: function-bind: 1.1.2 + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + help-me@5.0.0: {} html-encoding-sniffer@6.0.0: @@ -6170,6 +6485,8 @@ snapshots: dependencies: void-elements: 3.1.0 + html-url-attributes@3.0.1: {} + htmlparser2@10.1.0: dependencies: domelementtype: 2.3.0 @@ -6232,14 +6549,29 @@ snapshots: inherits@2.0.4: {} + inline-style-parser@0.2.7: {} + ipaddr.js@1.9.1: {} + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + is-extglob@2.1.1: {} is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + is-potential-custom-element-name@1.0.1: {} isbot@5.1.37: {} @@ -6370,6 +6702,8 @@ snapshots: lodash@4.18.1: {} + longest-streak@3.1.0: {} + lru-cache@11.2.7: {} lru-cache@5.1.1: @@ -6384,6 +6718,95 @@ snapshots: math-intrinsics@1.1.0: {} + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdn-data@2.27.1: {} media-typer@0.3.0: {} @@ -6392,6 +6815,139 @@ snapshots: methods@1.1.2: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -6487,6 +7043,16 @@ snapshots: p-map@7.0.4: {} + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + parse5@8.0.0: dependencies: entities: 6.0.1 @@ -6620,6 +7186,8 @@ snapshots: '@opentelemetry/api': 1.9.1 tdigest: 0.1.2 + property-information@7.1.0: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -6686,6 +7254,24 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + react-markdown@10.1.0(@types/react@19.2.14)(react@19.2.4): + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/react': 19.2.14 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.4 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + react-refresh@0.14.2: {} react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): @@ -6709,6 +7295,23 @@ snapshots: reflect-metadata@0.2.2: {} + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + require-from-string@2.0.2: {} require-in-the-middle@8.0.1: @@ -6853,6 +7456,8 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + splaytree-ts@1.0.2: {} split2@4.2.0: {} @@ -6863,12 +7468,25 @@ snapshots: std-env@4.0.0: {} + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 strip-json-comments@5.0.3: {} + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + sweepline-intersections@1.5.0: dependencies: tinyqueue: 2.0.3 @@ -6918,6 +7536,10 @@ snapshots: dependencies: punycode: 2.3.1 + trim-lines@3.0.1: {} + + trough@2.2.0: {} + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -6974,6 +7596,39 @@ snapshots: undici@7.24.5: {} + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + unpipe@1.0.0: {} update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -6998,6 +7653,16 @@ snapshots: vary@1.1.2: {} + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + vite-node@3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0): dependencies: cac: 6.7.14 @@ -7131,3 +7796,5 @@ snapshots: lib0: 0.2.117 yocto-queue@0.1.0: {} + + zwitch@2.0.4: {} From 3b49aa7a5b372da3d8781b71cf61b60b5d9a680e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 19:01:58 +0000 Subject: [PATCH 002/642] Bump nodemailer from 8.0.4 to 8.0.5 Bumps [nodemailer](https://github.com/nodemailer/nodemailer) from 8.0.4 to 8.0.5. - [Release notes](https://github.com/nodemailer/nodemailer/releases) - [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodemailer/nodemailer/compare/v8.0.4...v8.0.5) --- updated-dependencies: - dependency-name: nodemailer dependency-version: 8.0.5 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- apps/journal/package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/journal/package.json b/apps/journal/package.json index 9969ff3..9d3ac4b 100644 --- a/apps/journal/package.json +++ b/apps/journal/package.json @@ -26,7 +26,7 @@ "drizzle-orm": "catalog:", "isbot": "^5.1.37", "jose": "^6.2.2", - "nodemailer": "^8.0.4", + "nodemailer": "^8.0.5", "pino": "^10.3.1", "prom-client": "^15.1.3", "react": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 994c1ab..f21b4a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -219,8 +219,8 @@ importers: specifier: ^6.2.2 version: 6.2.2 nodemailer: - specifier: ^8.0.4 - version: 8.0.4 + specifier: ^8.0.5 + version: 8.0.5 pino: specifier: ^10.3.1 version: 10.3.1 @@ -3073,8 +3073,8 @@ packages: node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - nodemailer@8.0.4: - resolution: {integrity: sha512-k+jf6N8PfQJ0Fe8ZhJlgqU5qJU44Lpvp2yvidH3vp1lPnVQMgi4yEEMPXg5eJS1gFIJTVq1NHBk7Ia9ARdSBdQ==} + nodemailer@8.0.5: + resolution: {integrity: sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==} engines: {node: '>=6.0.0'} nth-check@2.1.1: @@ -6442,7 +6442,7 @@ snapshots: node-releases@2.0.36: {} - nodemailer@8.0.4: {} + nodemailer@8.0.5: {} nth-check@2.1.1: dependencies: From f7f9bef2ba8ff0fbf4e964faffe0ec4f03445a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 22:44:03 +0200 Subject: [PATCH 003/642] Expand multi-day-routes spec to include Journal integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The spec was Planner-only — day structure would be lost when saving to the Journal. Added GPX roundtrip (D9), Journal storage (D10), route detail day breakdown (D11), and shared computeDays in @trails-cool/gpx (D12). Co-Authored-By: Claude Opus 4.6 (1M context) --- openspec/changes/multi-day-routes/design.md | 88 +++++++++++++++++++ openspec/changes/multi-day-routes/proposal.md | 19 +++- openspec/changes/multi-day-routes/tasks.md | 35 +++++--- 3 files changed, 126 insertions(+), 16 deletions(-) diff --git a/openspec/changes/multi-day-routes/design.md b/openspec/changes/multi-day-routes/design.md index 2ad3e7b..48aad3b 100644 --- a/openspec/changes/multi-day-routes/design.md +++ b/openspec/changes/multi-day-routes/design.md @@ -192,6 +192,94 @@ Visual feedback follows visual-redesign tokens: - The "OVERNIGHT" badge uses `--stop` text on `--stop-bg` background with `--stop-border` border +### D9: GPX parse recognizes overnight waypoints + +The `parseWaypoints` function in `packages/gpx/src/parse.ts` is extended to +check for `overnight` inside `` elements. When found, the +returned `Waypoint` has `isDayBreak: true`. + +```typescript +function parseWaypoints(doc: Document): Waypoint[] { + const wpts = doc.querySelectorAll("wpt"); + return Array.from(wpts).map((wpt) => { + const lat = parseFloat(wpt.getAttribute("lat") ?? "0"); + const lon = parseFloat(wpt.getAttribute("lon") ?? "0"); + const name = wpt.querySelector("name")?.textContent ?? undefined; + const type = wpt.querySelector("type")?.textContent ?? undefined; + const isDayBreak = type === "overnight" ? true : undefined; + return { lat, lon, name, isDayBreak }; + }); +} +``` + +This makes GPX round-tripping work: Planner exports overnight waypoints with +`overnight` (D7), and any consumer — the Journal's `updateRoute`, +the Planner's GPX import, or a future mobile app — gets `isDayBreak` back. + +### D10: Journal stores dayBreaks on route save + +The `dayBreaks` jsonb column on `journal.routes` already exists. When +`updateRoute` receives GPX and calls `parseGpxAsync`, it extracts the indices +of waypoints where `isDayBreak === true` and writes them to `dayBreaks`: + +```typescript +const parsed = await parseGpxAsync(gpx); +const dayBreaks = parsed.waypoints + .map((w, i) => (w.isDayBreak ? i : -1)) + .filter((i) => i >= 0); +``` + +This is computed on write, not on read — the Journal doesn't need to re-parse +GPX to know day structure. If the GPX has no overnight waypoints, `dayBreaks` +is an empty array (single-day route). + +### D11: Journal route detail day breakdown + +When a route has non-empty `dayBreaks`, the route detail page shows a day +breakdown section below the stats grid. Per-day stats (distance, ascent, +descent) are computed from the stored GPX by splitting at day-break waypoints +— reusing the same `computeDays` logic from D2, extracted into +`@trails-cool/gpx` so both Planner and Journal can use it. + +``` +DAY 1: Berlin → Dessau 120 km ↑340m ↓180m +DAY 2: Dessau → Erfurt 223 km ↑528m ↓490m +``` + +The map also colors each day segment differently (alternating two colors from +the design tokens) so users can visually see where each day starts and ends. + +For single-day routes (no `dayBreaks`), nothing changes — the page renders +exactly as it does today. + +### D12: computeDays as a shared package function + +The `computeDays` pure function (D2) is placed in `@trails-cool/gpx` rather +than in the Planner app, since both the Planner (from Yjs + EnrichedRoute) and +the Journal (from parsed GPX) need day computation. The function signature +works with the `GpxData` tracks and waypoints returned by `parseGpx`: + +```typescript +interface DayStage { + dayNumber: number; + startWaypointIndex: number; + endWaypointIndex: number; + startName?: string; + endName?: string; + distance: number; // meters + ascent: number; // meters + descent: number; // meters +} + +function computeDays( + waypoints: Waypoint[], + tracks: TrackPoint[][], +): DayStage[]; +``` + +The Planner's `useDays()` hook maps its Yjs waypoints + EnrichedRoute into +this same shape before calling `computeDays`. + ## Risks / Trade-offs - **Segment boundary alignment**: The day computation relies on diff --git a/openspec/changes/multi-day-routes/proposal.md b/openspec/changes/multi-day-routes/proposal.md index bb8cbbe..e09b6b3 100644 --- a/openspec/changes/multi-day-routes/proposal.md +++ b/openspec/changes/multi-day-routes/proposal.md @@ -44,6 +44,9 @@ the data model, computation logic, and integration wiring. - `planner-session`: Waypoints gain an `overnight` property in Yjs state - `map-display`: Day boundary labels on route, overnight marker styling - `gpx-export`: Day-break metadata in exported GPX waypoints +- `gpx-import`: Parse `overnight` waypoints to restore day breaks +- `route-management`: Populate `dayBreaks` column on save, expose per-day stats +- `journal-route-detail`: Day breakdown display with per-day stats and map segments ## Non-Goals @@ -52,8 +55,9 @@ the data model, computation logic, and integration wiring. - **Accommodation search**: No POI lookup for campsites or hotels. Out of scope. - **Per-day routing profiles**: All days use the same BRouter profile. Supporting different profiles per day would require rearchitecting the routing pipeline. -- **Journal integration**: Saving multi-day routes to the Journal is a separate - concern (route-features change). This spec is Planner-only. +- **Per-day activity tracking**: Linking individual activities to specific days + of a multi-day route (e.g. "Day 2 activity"). Activities remain linked to the + full route. Per-day activity chaining is a future concern. ## Impact @@ -67,6 +71,13 @@ the data model, computation logic, and integration wiring. sections and overnight toggle buttons - **ElevationChart**: Canvas drawing extended with vertical day dividers - **Map**: New day-label layer and overnight marker variant -- **GPX**: `generateGpx` extended to emit `overnight` on day-break - waypoints +- **GPX generate**: `generateGpx` extended to emit `overnight` on + day-break waypoints +- **GPX parse**: `parseGpx` extended to recognize `overnight` and + set `isDayBreak: true` on parsed waypoints +- **Journal route storage**: `updateRoute` populates `dayBreaks` column from + parsed waypoint indices when saving GPX +- **Journal route detail**: Day breakdown section with per-day stats (distance, + ascent, descent) when `dayBreaks` is non-empty - **i18n**: New keys for day labels, overnight toggle, per-day stats (en + de) + in both planner and journal namespaces diff --git a/openspec/changes/multi-day-routes/tasks.md b/openspec/changes/multi-day-routes/tasks.md index d6f984d..717fbcd 100644 --- a/openspec/changes/multi-day-routes/tasks.md +++ b/openspec/changes/multi-day-routes/tasks.md @@ -1,8 +1,8 @@ ## 1. Data Model & Computation - [ ] 1.1 Add `overnight` property support to Yjs waypoint Y.Maps: helper functions `setOvernight(yjs, index, value)` and `isOvernight(yMap)` in a new `apps/planner/app/lib/overnight.ts` -- [ ] 1.2 Create `apps/planner/app/lib/compute-days.ts` with `computeDays()` pure function: takes waypoints array + `EnrichedRoute`, returns `DayStage[]` (day number, waypoint range, coord range, distance, ascent, descent, estimated time) -- [ ] 1.3 Create `useDays()` hook in `apps/planner/app/lib/use-days.ts`: observes Yjs waypoints + routeData, calls `computeDays()`, returns reactive `DayStage[]` +- [ ] 1.2 Create `computeDays()` pure function in `packages/gpx/src/compute-days.ts`: takes `Waypoint[]` + `TrackPoint[][]`, returns `DayStage[]` (day number, waypoint range, distance, ascent, descent). Export from package index. +- [ ] 1.3 Create `useDays()` hook in `apps/planner/app/lib/use-days.ts`: maps Yjs waypoints + EnrichedRoute into `computeDays()` input, returns reactive `DayStage[]` ## 2. Sidebar Day Breakdown @@ -22,19 +22,30 @@ - [ ] 4.1 Add day divider rendering to `ElevationChart`: dashed vertical lines at overnight waypoint distances with "Day N" labels at top - [ ] 4.2 Show per-day distance ranges on x-axis labels (e.g. "120 km" at each day boundary) -## 5. GPX Export +## 5. GPX Roundtrip - [ ] 5.1 Extend `generateGpx` in `@trails-cool/gpx` to emit `overnight` for waypoints with `isDayBreak: true` -- [ ] 5.2 Add multi-track export option: split track into one `` per day, each named "Day N: Start - End" +- [ ] 5.2 Extend `parseGpx` in `@trails-cool/gpx` to recognize `overnight` and set `isDayBreak: true` on parsed waypoints +- [ ] 5.3 Add multi-track export option: split track into one `` per day, each named "Day N: Start - End" -## 6. i18n +## 6. Journal Integration -- [ ] 6.1 Add translation keys for en + de: day labels ("Day 1", "Tag 1"), overnight toggle ("Mark as overnight stop" / "Als Ubernachtung markieren"), per-day stats, route summary +- [ ] 6.1 Update `updateRoute` in `apps/journal/app/lib/routes.server.ts` to extract `dayBreaks` indices from parsed GPX waypoints and write to `dayBreaks` column +- [ ] 6.2 Expose `dayBreaks` and per-day stats in route detail loader (`routes.$id.tsx`) +- [ ] 6.3 Add day breakdown section to route detail page: per-day distance, ascent, descent, start/end names — shown only when dayBreaks is non-empty +- [ ] 6.4 Color route map segments per day (alternating colors) on the route detail map when dayBreaks exist -## 7. Testing +## 7. i18n -- [ ] 7.1 Unit tests for `computeDays()`: single day (no overnight), two days, three days, empty route, single waypoint, overnight on first/last waypoint edge cases -- [ ] 7.2 Unit tests for `overnight.ts` helpers: set/clear/check overnight on Y.Map -- [ ] 7.3 Unit tests for GPX export with overnight waypoints: verify `overnight` output, multi-track splitting -- [ ] 7.4 E2E test: add waypoints, toggle overnight on one, verify sidebar shows day breakdown with correct stats -- [ ] 7.5 E2E test: export GPX with day breaks, verify downloaded file contains overnight metadata +- [ ] 7.1 Add Planner translation keys for en + de: day labels ("Day 1", "Tag 1"), overnight toggle ("Mark as overnight stop" / "Als Übernachtung markieren"), per-day stats, route summary +- [ ] 7.2 Add Journal translation keys for en + de: day breakdown header, per-day stats labels + +## 8. Testing + +- [ ] 8.1 Unit tests for `computeDays()`: single day (no overnight), two days, three days, empty route, single waypoint, overnight on first/last waypoint edge cases +- [ ] 8.2 Unit tests for `overnight.ts` helpers: set/clear/check overnight on Y.Map +- [ ] 8.3 Unit tests for GPX roundtrip: generate with `isDayBreak`, parse back, verify `isDayBreak` preserved +- [ ] 8.4 Unit tests for `dayBreaks` extraction in route update logic +- [ ] 8.5 E2E test: add waypoints, toggle overnight on one, verify sidebar shows day breakdown with correct stats +- [ ] 8.6 E2E test: export GPX with day breaks, verify downloaded file contains overnight metadata +- [ ] 8.7 E2E test: save multi-day route to Journal, verify day breakdown displays on route detail page From 06949fc7b5015ebdd00a022f76cec0eba3cf81dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 22:52:43 +0200 Subject: [PATCH 004/642] Upgrade Vite from 6.4.2 to 8.0.8 Vite 8 ships Rolldown as its Rust-based bundler, replacing esbuild+Rollup. Removed the esbuild override from pnpm-workspace.yaml since Vite 8 no longer uses esbuild for bundling. All plugins (@react-router/dev, @tailwindcss/vite, @sentry/vite-plugin, @vitejs/plugin-basic-ssl) support Vite 8. Co-Authored-By: Claude Opus 4.6 (1M context) --- pnpm-lock.yaml | 325 ++++++++++++++++++++++++++++++++++++++++---- pnpm-workspace.yaml | 5 +- 2 files changed, 302 insertions(+), 28 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f21b4a3..01719c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ catalogs: specifier: ^5.8.3 version: 5.9.3 vite: - specifier: ^6.4.2 - version: 6.4.2 + specifier: ^8.0.8 + version: 8.0.8 overrides: picomatch@>=4.0.0 <4.0.4: 4.0.4 @@ -67,7 +67,7 @@ importers: version: 1.59.1 '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@react-router/node': specifier: 'catalog:' version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) @@ -79,7 +79,7 @@ importers: version: 5.1.1(rollup@4.60.0) '@tailwindcss/vite': specifier: ^4.2.2 - version: 4.2.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -166,10 +166,10 @@ importers: version: 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) vite: specifier: 'catalog:' - version: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) vitest: specifier: ^4.1.2 - version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) apps/journal: dependencies: @@ -239,13 +239,13 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@types/nodemailer': specifier: ^8.0.0 version: 8.0.0 @@ -257,7 +257,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-basic-ssl': specifier: ^2.3.0 - version: 2.3.0(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 2.3.0(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) pino-pretty: specifier: ^13.1.3 version: 13.1.3 @@ -269,7 +269,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) apps/planner: dependencies: @@ -345,10 +345,10 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@tailwindcss/vite': specifier: 'catalog:' - version: 4.2.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@types/react': specifier: 'catalog:' version: 19.2.14 @@ -369,7 +369,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) packages/db: dependencies: @@ -609,6 +609,15 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -1161,6 +1170,12 @@ packages: '@mjackson/node-fetch-server@0.2.0': resolution: {integrity: sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==} + '@napi-rs/wasm-runtime@1.1.3': + resolution: {integrity: sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@opentelemetry/api-logs@0.207.0': resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} engines: {node: '>=8.0.0'} @@ -1365,6 +1380,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 + '@oxc-project/types@0.124.0': + resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@peculiar/asn1-android@2.6.0': resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} @@ -1477,6 +1495,98 @@ packages: '@remix-run/node-fetch-server@0.13.0': resolution: {integrity: sha512-1EsNo0ZpgXu/90AWoRZf/oE3RVTUS80tiTUpt+hv5pjtAkw7icN4WskDwz/KdAw5ARbJLMhZBrO1NqThmy/McA==} + '@rolldown/binding-android-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.15': + resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-rc.15': + resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} + '@rollup/rollup-android-arm-eabi@4.60.0': resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} cpu: [arm] @@ -1948,6 +2058,9 @@ packages: '@turf/truncate@7.3.4': resolution: {integrity: sha512-VPXdae9+RLLM19FMrJgt7QANBikm7DxPbfp/dXgzE4Ca7v+mJ4T1fYc7gCZDaqOrWMccHKbvv4iSuW7YZWdIIA==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -3369,6 +3482,11 @@ packages: robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} + rolldown@1.0.0-rc.15: + resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.60.0: resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -3680,6 +3798,49 @@ packages: yaml: optional: true + vite@8.0.8: + resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@4.1.2: resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -4047,6 +4208,22 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -4371,6 +4548,13 @@ snapshots: '@mjackson/node-fetch-server@0.2.0': {} + '@napi-rs/wasm-runtime@1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + '@opentelemetry/api-logs@0.207.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -4634,6 +4818,8 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@oxc-project/types@0.124.0': {} + '@peculiar/asn1-android@2.6.0': dependencies: '@peculiar/asn1-schema': 2.6.0 @@ -4749,7 +4935,7 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@react-router/dev@7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': + '@react-router/dev@7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -4779,7 +4965,7 @@ snapshots: semver: 7.7.4 tinyglobby: 0.2.15 valibot: 1.3.1(typescript@5.9.3) - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) vite-node: 3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) optionalDependencies: '@react-router/serve': 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) @@ -4831,6 +5017,57 @@ snapshots: '@remix-run/node-fetch-server@0.13.0': {} + '@rolldown/binding-android-arm64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.3(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + optional: true + + '@rolldown/pluginutils@1.0.0-rc.15': {} + '@rollup/rollup-android-arm-eabi@4.60.0': optional: true @@ -5159,12 +5396,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - '@tailwindcss/vite@4.2.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': + '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 tailwindcss: 4.2.2 - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) '@testing-library/dom@10.4.1': dependencies: @@ -5331,6 +5568,11 @@ snapshots: '@types/geojson': 7946.0.16 tslib: 2.8.1 + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@types/aria-query@5.0.4': {} '@types/chai@5.2.3': @@ -5485,9 +5727,9 @@ snapshots: '@typescript-eslint/types': 8.58.0 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-basic-ssl@2.3.0(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': + '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) '@vitest/expect@4.1.2': dependencies: @@ -5498,13 +5740,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0))': + '@vitest/mocker@4.1.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.2 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) '@vitest/pretty-format@4.1.2': dependencies: @@ -6722,6 +6964,27 @@ snapshots: robust-predicates@3.0.3: {} + rolldown@1.0.0-rc.15: + dependencies: + '@oxc-project/types': 0.124.0 + '@rolldown/pluginutils': 1.0.0-rc.15 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 + '@rolldown/binding-darwin-x64': 1.0.0-rc.15 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 + rollup@4.60.0: dependencies: '@types/estree': 1.0.8 @@ -7034,10 +7297,24 @@ snapshots: lightningcss: 1.32.0 tsx: 4.21.0 - vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)): + vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.8 + rolldown: 1.0.0-rc.15 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.5.2 + esbuild: 0.27.4 + fsevents: 2.3.3 + jiti: 2.6.1 + tsx: 4.21.0 + + vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0)) + '@vitest/mocker': 4.1.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.2 '@vitest/runner': 4.1.2 '@vitest/snapshot': 4.1.2 @@ -7054,7 +7331,7 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 6.4.2(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cb04669..1a6a7e8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -14,11 +14,8 @@ catalog: tailwindcss: ^4.1.7 "@tailwindcss/vite": ^4.1.7 typescript: ^5.8.3 - vite: ^6.4.2 + vite: ^8.0.8 drizzle-orm: ^0.45.2 drizzle-kit: ^0.31.0 drizzle-postgis: ^1.1.0 postgres: ^3.4.9 - -overrides: - esbuild: ">=0.25.0" From 760818c8434f6e7c1bab01355e65231f12ed7d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 23:04:34 +0200 Subject: [PATCH 005/642] Deduplicate dependency versions via pnpm catalog Root package.json had hardcoded versions for react, react-dom, @types/react, @types/react-dom, tailwindcss, @tailwindcss/vite, drizzle-orm, drizzle-kit, and drizzle-postgis that drifted from catalog entries. Switched them all to catalog: and bumped catalog versions to match. Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 18 +++++++++--------- pnpm-lock.yaml | 36 +++++++++++++++++++++--------------- pnpm-workspace.yaml | 16 ++++++++-------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 0a2fe43..e9a12dc 100644 --- a/package.json +++ b/package.json @@ -41,16 +41,16 @@ "@react-router/node": "catalog:", "@react-router/serve": "catalog:", "@sentry/vite-plugin": "^5.1.1", - "@tailwindcss/vite": "^4.2.2", + "@tailwindcss/vite": "catalog:", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@types/geojson": "^7946.0.16", "@types/leaflet": "^1.9.21", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "drizzle-kit": "^0.31.10", - "drizzle-orm": "^0.45.2", - "drizzle-postgis": "^1.1.1", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "drizzle-kit": "catalog:", + "drizzle-orm": "catalog:", + "drizzle-postgis": "catalog:", "eslint": "^10.2.0", "eslint-config-prettier": "^10.1.8", "fit-file-parser": "^2.3.3", @@ -62,12 +62,12 @@ "playwright": "^1.59.1", "postgres": "catalog:", "prettier": "^3.8.1", - "react": "^19.2.4", - "react-dom": "^19.2.4", + "react": "catalog:", + "react-dom": "catalog:", "react-i18next": "^17.0.2", "react-leaflet": "^5.0.0", "react-router": "catalog:", - "tailwindcss": "^4.2.2", + "tailwindcss": "catalog:", "turbo": "^2.9.3", "typescript-eslint": "^8.58.0", "vite": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01719c6..f5a8894 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,31 +16,37 @@ catalogs: specifier: ^7.14.0 version: 7.14.0 '@tailwindcss/vite': - specifier: ^4.1.7 + specifier: ^4.2.2 version: 4.2.2 '@types/react': - specifier: ^19.1.4 + specifier: ^19.2.14 version: 19.2.14 '@types/react-dom': - specifier: ^19.1.5 + specifier: ^19.2.3 version: 19.2.3 + drizzle-kit: + specifier: ^0.31.10 + version: 0.31.10 drizzle-orm: specifier: ^0.45.2 version: 0.45.2 + drizzle-postgis: + specifier: ^1.1.1 + version: 1.1.1 postgres: specifier: ^3.4.9 version: 3.4.9 react: - specifier: ^19.1.0 + specifier: ^19.2.4 version: 19.2.4 react-dom: - specifier: ^19.1.0 + specifier: ^19.2.4 version: 19.2.4 react-router: specifier: ^7.14.0 version: 7.14.0 tailwindcss: - specifier: ^4.1.7 + specifier: ^4.2.2 version: 4.2.2 typescript: specifier: ^5.8.3 @@ -78,7 +84,7 @@ importers: specifier: ^5.1.1 version: 5.1.1(rollup@4.60.0) '@tailwindcss/vite': - specifier: ^4.2.2 + specifier: 'catalog:' version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@testing-library/jest-dom': specifier: ^6.9.1 @@ -93,19 +99,19 @@ importers: specifier: ^1.9.21 version: 1.9.21 '@types/react': - specifier: ^19.2.14 + specifier: 'catalog:' version: 19.2.14 '@types/react-dom': - specifier: ^19.2.3 + specifier: 'catalog:' version: 19.2.3(@types/react@19.2.14) drizzle-kit: - specifier: ^0.31.10 + specifier: 'catalog:' version: 0.31.10 drizzle-orm: - specifier: ^0.45.2 + specifier: 'catalog:' version: 0.45.2(@opentelemetry/api@1.9.1)(@types/pg@8.15.6)(postgres@3.4.9) drizzle-postgis: - specifier: ^1.1.1 + specifier: 'catalog:' version: 1.1.1 eslint: specifier: ^10.2.0 @@ -141,10 +147,10 @@ importers: specifier: ^3.8.1 version: 3.8.1 react: - specifier: ^19.2.4 + specifier: 'catalog:' version: 19.2.4 react-dom: - specifier: ^19.2.4 + specifier: 'catalog:' version: 19.2.4(react@19.2.4) react-i18next: specifier: ^17.0.2 @@ -156,7 +162,7 @@ importers: specifier: 'catalog:' version: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tailwindcss: - specifier: ^4.2.2 + specifier: 'catalog:' version: 4.2.2 turbo: specifier: ^2.9.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1a6a7e8..54c4586 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,19 +3,19 @@ packages: - "packages/*" catalog: - react: ^19.1.0 - react-dom: ^19.1.0 + react: ^19.2.4 + react-dom: ^19.2.4 react-router: ^7.14.0 "@react-router/dev": ^7.14.0 "@react-router/node": ^7.14.0 "@react-router/serve": ^7.14.0 - "@types/react": ^19.1.4 - "@types/react-dom": ^19.1.5 - tailwindcss: ^4.1.7 - "@tailwindcss/vite": ^4.1.7 + "@types/react": ^19.2.14 + "@types/react-dom": ^19.2.3 + tailwindcss: ^4.2.2 + "@tailwindcss/vite": ^4.2.2 typescript: ^5.8.3 vite: ^8.0.8 drizzle-orm: ^0.45.2 - drizzle-kit: ^0.31.0 - drizzle-postgis: ^1.1.0 + drizzle-kit: ^0.31.10 + drizzle-postgis: ^1.1.1 postgres: ^3.4.9 From 04efe791cdbf46c56d2ca0dd4be1f3938bd81cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 23:10:06 +0200 Subject: [PATCH 006/642] Update dependencies and move Sentry to pnpm catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dependency bumps: - react, react-dom: 19.2.4 → 19.2.5 (catalog) - @sentry/node, @sentry/react: 10.47.0 → 10.48.0 - @sentry/vite-plugin: 5.1.1 → 5.2.0 - @geoman-io/leaflet-geoman-free: 2.19.2 → 2.19.3 - jsdom: 29.0.1 → 29.0.2 - prettier: 3.8.1 → 3.8.2 - turbo: 2.9.3 → 2.9.6 - typescript-eslint: 8.58.0 → 8.58.1 - vitest: 4.1.2 → 4.1.4 Catalog cleanup: - Move @sentry/node and @sentry/react to pnpm catalog (used by both apps) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/journal/package.json | 4 +- apps/planner/package.json | 6 +- package.json | 12 +- pnpm-lock.yaml | 662 +++++++++++++++++++------------------- pnpm-workspace.yaml | 6 +- 5 files changed, 345 insertions(+), 345 deletions(-) diff --git a/apps/journal/package.json b/apps/journal/package.json index 9d3ac4b..da0e393 100644 --- a/apps/journal/package.json +++ b/apps/journal/package.json @@ -13,8 +13,8 @@ "dependencies": { "@react-router/node": "catalog:", "@react-router/serve": "catalog:", - "@sentry/node": "^10.47.0", - "@sentry/react": "^10.47.0", + "@sentry/node": "catalog:", + "@sentry/react": "catalog:", "@simplewebauthn/browser": "^13.3.0", "@simplewebauthn/server": "^13.3.0", "@trails-cool/db": "workspace:*", diff --git a/apps/planner/package.json b/apps/planner/package.json index 3c5edfd..cb08be8 100644 --- a/apps/planner/package.json +++ b/apps/planner/package.json @@ -11,11 +11,11 @@ "lint": "eslint ." }, "dependencies": { - "@geoman-io/leaflet-geoman-free": "^2.19.2", + "@geoman-io/leaflet-geoman-free": "^2.19.3", "@react-router/node": "catalog:", "@react-router/serve": "catalog:", - "@sentry/node": "^10.47.0", - "@sentry/react": "^10.47.0", + "@sentry/node": "catalog:", + "@sentry/react": "catalog:", "@trails-cool/db": "workspace:*", "@trails-cool/gpx": "workspace:*", "@trails-cool/i18n": "workspace:*", diff --git a/package.json b/package.json index e9a12dc..7d5df87 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@react-router/dev": "catalog:", "@react-router/node": "catalog:", "@react-router/serve": "catalog:", - "@sentry/vite-plugin": "^5.1.1", + "@sentry/vite-plugin": "^5.2.0", "@tailwindcss/vite": "catalog:", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", @@ -56,21 +56,21 @@ "fit-file-parser": "^2.3.3", "i18next": "^26.0.3", "i18next-browser-languagedetector": "^8.2.1", - "jsdom": "^29.0.1", + "jsdom": "^29.0.2", "leaflet": "^1.9.4", "linkedom": "^0.18.12", "playwright": "^1.59.1", "postgres": "catalog:", - "prettier": "^3.8.1", + "prettier": "^3.8.2", "react": "catalog:", "react-dom": "catalog:", "react-i18next": "^17.0.2", "react-leaflet": "^5.0.0", "react-router": "catalog:", "tailwindcss": "catalog:", - "turbo": "^2.9.3", - "typescript-eslint": "^8.58.0", + "turbo": "^2.9.6", + "typescript-eslint": "^8.58.1", "vite": "catalog:", - "vitest": "^4.1.2" + "vitest": "^4.1.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f5a8894..aad64aa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,12 @@ catalogs: '@react-router/serve': specifier: ^7.14.0 version: 7.14.0 + '@sentry/node': + specifier: ^10.48.0 + version: 10.48.0 + '@sentry/react': + specifier: ^10.48.0 + version: 10.48.0 '@tailwindcss/vite': specifier: ^4.2.2 version: 4.2.2 @@ -37,11 +43,11 @@ catalogs: specifier: ^3.4.9 version: 3.4.9 react: - specifier: ^19.2.4 - version: 19.2.4 + specifier: ^19.2.5 + version: 19.2.5 react-dom: - specifier: ^19.2.4 - version: 19.2.4 + specifier: ^19.2.5 + version: 19.2.5 react-router: specifier: ^7.14.0 version: 7.14.0 @@ -73,16 +79,16 @@ importers: version: 1.59.1 '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/vite-plugin': - specifier: ^5.1.1 - version: 5.1.1(rollup@4.60.0) + specifier: ^5.2.0 + version: 5.2.0(rollup@4.60.0) '@tailwindcss/vite': specifier: 'catalog:' version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) @@ -91,7 +97,7 @@ importers: version: 6.9.1 '@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.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@types/geojson': specifier: ^7946.0.16 version: 7946.0.16 @@ -124,13 +130,13 @@ importers: version: 2.3.3 i18next: specifier: ^26.0.3 - version: 26.0.3(typescript@5.9.3) + version: 26.0.4(typescript@5.9.3) i18next-browser-languagedetector: specifier: ^8.2.1 version: 8.2.1 jsdom: - specifier: ^29.0.1 - version: 29.0.1 + specifier: ^29.0.2 + version: 29.0.2 leaflet: specifier: ^1.9.4 version: 1.9.4 @@ -144,53 +150,53 @@ importers: specifier: 'catalog:' version: 3.4.9 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.2 + version: 3.8.2 react: specifier: 'catalog:' - version: 19.2.4 + version: 19.2.5 react-dom: specifier: 'catalog:' - version: 19.2.4(react@19.2.4) + version: 19.2.5(react@19.2.5) react-i18next: specifier: ^17.0.2 - version: 17.0.2(i18next@26.0.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) react-leaflet: specifier: ^5.0.0 - version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: specifier: 'catalog:' version: 4.2.2 turbo: - specifier: ^2.9.3 - version: 2.9.3 + specifier: ^2.9.6 + version: 2.9.6 typescript-eslint: - specifier: ^8.58.0 - version: 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.58.1 + version: 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) vite: specifier: 'catalog:' version: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) vitest: - specifier: ^4.1.2 - version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) + specifier: ^4.1.4 + version: 4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) apps/journal: dependencies: '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': - specifier: ^10.47.0 - version: 10.47.0 + specifier: 'catalog:' + version: 10.48.0 '@sentry/react': - specifier: ^10.47.0 - version: 10.47.0(react@19.2.4) + specifier: 'catalog:' + version: 10.48.0(react@19.2.5) '@simplewebauthn/browser': specifier: ^13.3.0 version: 13.3.0 @@ -235,17 +241,17 @@ importers: version: 15.1.3 react: specifier: 'catalog:' - version: 19.2.4 + version: 19.2.5 react-dom: specifier: 'catalog:' - version: 19.2.4(react@19.2.4) + version: 19.2.5(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@simplewebauthn/types': specifier: ^12.0.0 version: 12.0.0 @@ -280,20 +286,20 @@ importers: apps/planner: dependencies: '@geoman-io/leaflet-geoman-free': - specifier: ^2.19.2 - version: 2.19.2(leaflet@1.9.4) + specifier: ^2.19.3 + version: 2.19.3(leaflet@1.9.4) '@react-router/node': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@react-router/serve': specifier: 'catalog:' - version: 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@sentry/node': - specifier: ^10.47.0 - version: 10.47.0 + specifier: 'catalog:' + version: 10.48.0 '@sentry/react': - specifier: ^10.47.0 - version: 10.47.0(react@19.2.4) + specifier: 'catalog:' + version: 10.48.0(react@19.2.5) '@trails-cool/db': specifier: workspace:* version: link:../../packages/db @@ -329,13 +335,13 @@ importers: version: 15.1.3 react: specifier: 'catalog:' - version: 19.2.4 + version: 19.2.5 react-dom: specifier: 'catalog:' - version: 19.2.4(react@19.2.4) + version: 19.2.5(react@19.2.5) react-router: specifier: 'catalog:' - version: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ws: specifier: ^8.20.0 version: 8.20.0 @@ -351,7 +357,7 @@ importers: devDependencies: '@react-router/dev': specifier: 'catalog:' - version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) + version: 7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) '@tailwindcss/vite': specifier: 'catalog:' version: 4.2.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) @@ -396,13 +402,13 @@ importers: dependencies: i18next: specifier: '>=26' - version: 26.0.3(typescript@5.9.3) + version: 26.0.4(typescript@5.9.3) react: specifier: '>=18' - version: 19.2.4 + version: 19.2.5 react-i18next: specifier: '>=17' - version: 17.0.2(i18next@26.0.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) + version: 17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) packages/map: dependencies: @@ -411,13 +417,13 @@ importers: version: 1.9.4 react: specifier: '>=18' - version: 19.2.4 + version: 19.2.5 react-dom: specifier: '>=18' - version: 19.2.4(react@19.2.4) + version: 19.2.5(react@19.2.5) react-leaflet: specifier: '>=5' - version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) packages/types: {} @@ -428,12 +434,12 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - '@asamuzakjp/css-color@5.0.1': - resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==} + '@asamuzakjp/css-color@5.1.9': + resolution: {integrity: sha512-zd9c/Wdso6v1U7v6w3i/hbAr4K7NaSHImdpvmLt+Y9ea5BhilnIGNkfhOJ7FEIuPipAnE9tZeDOll05WDT0kgg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@asamuzakjp/dom-selector@7.0.4': - resolution: {integrity: sha512-jXR6x4AcT3eIrS2fSNAwJpwirOkGcd+E7F7CP3zjdTqz9B/2huHOL8YJZBgekKwLML+u7qB/6P1LXQuMScsx0w==} + '@asamuzakjp/dom-selector@7.0.9': + resolution: {integrity: sha512-r3ElRr7y8ucyN2KdICwGsmj19RoN13CLCa/pvGydghWK6ZzeKQ+TcDjVdtEZz2ElpndM5jXw//B9CEee0mWnVg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} '@asamuzakjp/nwsapi@2.3.9': @@ -1129,8 +1135,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.9.0 - '@geoman-io/leaflet-geoman-free@2.19.2': - resolution: {integrity: sha512-FYqLCFjCWLc1c5vel83i2ON77zPugH9qfxzLxTt+SiFiMgHjO1dSS59qz23aLLQ0hRWTQdycnxXGNmT+4OC9sg==} + '@geoman-io/leaflet-geoman-free@2.19.3': + resolution: {integrity: sha512-HjbEpfAEUs0NyI1Dhvz3SMVG6m0pAN/1Eo0tRKsz9cpaROTrFtmJGY22swEir1Uj/8IeGF1NJId38C5Fu+nZGQ==} engines: {node: '>=18.0.0'} peerDependencies: leaflet: ^1.2.0 @@ -1228,12 +1234,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-express@0.62.0': - resolution: {integrity: sha512-Tvx+vgAZKEQxU3Rx+xWLiR0mLxHwmk69/8ya04+VsV9WYh8w6Lhx5hm5yAMvo1wy0KqWgFKBLwSeo3sHCwdOww==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-fs@0.33.0': resolution: {integrity: sha512-sCZWXGalQ01wr3tAhSR9ucqFJ0phidpAle6/17HVjD6gN8FLmZMK/8sKxdXYHy3PbnlV1P4zeiSVFNKpbFMNLA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -1718,32 +1718,32 @@ packages: cpu: [x64] os: [win32] - '@sentry-internal/browser-utils@10.47.0': - resolution: {integrity: sha512-bVFRAeJWMBcBCvJKIFCMJ1/yQToL4vPGqfmlnDZeypcxkqUDKQ/Y3ziLHXoDL2sx0lagcgU2vH1QhCQ67Aujjw==} + '@sentry-internal/browser-utils@10.48.0': + resolution: {integrity: sha512-SCiTLBXzugFKxev6NoKYBIhQoDk0gUh0AVVVepCBqfCJiWBG01Zvv0R5tCVohr4cWRllkQ8mlBdNQd/I7s9tdA==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.47.0': - resolution: {integrity: sha512-pdvMmi4dQpX5S/vAAzrhHPIw3T3HjUgDNgUiCBrlp7N9/6zGO2gNPhUnNekP+CjgI/z0rvf49RLqlDenpNrMOg==} + '@sentry-internal/feedback@10.48.0': + resolution: {integrity: sha512-tGkEyOM1HDS9qebDphUMEnyk3qq/50AnuTBiFmMJyjNzowylVGmRRk0sr3xkmbVHCDXQCiYnDmSVlJ2x4SDMrQ==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.47.0': - resolution: {integrity: sha512-A5OY8friSe6g8WAK4L8IeOPiEd9D3Ps40DzRH5j2f6SUja0t90mKMvHRcRf8zq0d4BkdB+JM7tjOkwxpuv8heA==} + '@sentry-internal/replay-canvas@10.48.0': + resolution: {integrity: sha512-9nWuN2z4O+iwbTfuYV5ZmngBgJU/ZxfOo47A5RJP3Nu/kl59aJ1lUhILYOKyeNOIC/JyeERmpIcTxnlPXQzZ3Q==} engines: {node: '>=18'} - '@sentry-internal/replay@10.47.0': - resolution: {integrity: sha512-ScdovxP7hJxgMt70+7hFvwT02GIaIUAxdEM/YPsayZBeCoAukPW8WiwztJfoKtsfPyKJ5A6f0H3PIxTPcA9Row==} + '@sentry-internal/replay@10.48.0': + resolution: {integrity: sha512-sevRTePfuk4PNuz9KAKpmTZEomAU0aLXyIhOwA0OnUDdxPhkY8kq5lwDbuxTHv6DQUjUX3YgFbY45VH1JEqHKA==} engines: {node: '>=18'} - '@sentry/babel-plugin-component-annotate@5.1.1': - resolution: {integrity: sha512-x2wEpBHwsTyTF2rWsLKJlzrRF1TTIGOfX+ngdE+Yd5DBkoS58HwQv824QOviPGQRla4/ypISqAXzjdDPL/zalg==} + '@sentry/babel-plugin-component-annotate@5.2.0': + resolution: {integrity: sha512-8LbOI5Kzb5F0+7LVQPi2+zGz1iPiRRFhM+7uZ/ZQ33L9BmDOYNIy3xWxCfMw2JCuMXXaxF47XCjGmR22/B0WPg==} engines: {node: '>= 18'} - '@sentry/browser@10.47.0': - resolution: {integrity: sha512-rC0agZdxKA5XWfL4VwPOr/rJMogXDqZgnVzr93YWpFn9DMZT/7LzxSJVPIJwRUjx3bFEby3PcTa3YaX7pxm1AA==} + '@sentry/browser@10.48.0': + resolution: {integrity: sha512-4jt2zX2ExgFcNe2x+W+/k81fmDUsOrquGtt028CiGuDuma6kEsWBI4JbooT1jhj2T+eeUxe3YGbM23Zhh7Ghhw==} engines: {node: '>=18'} - '@sentry/bundler-plugin-core@5.1.1': - resolution: {integrity: sha512-F+itpwR9DyQR7gEkrXd2tigREPTvtF5lC8qu6e4anxXYRTui1+dVR0fXNwjpyAZMhIesLfXRN7WY7ggdj7hi0Q==} + '@sentry/bundler-plugin-core@5.2.0': + resolution: {integrity: sha512-+C0x4gEIJRgoMwyRFGx+TFiJ1Po2BZlT1v61+PnouiaprKL5qtZG8n5PXx/5LPLDsVjSIcXjnDrTz9aSm8SJ3w==} engines: {node: '>= 18'} '@sentry/cli-darwin@2.58.5': @@ -1798,12 +1798,12 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@10.47.0': - resolution: {integrity: sha512-nsYRAx3EWezDut+Zl+UwwP07thh9uY7CfSAi2whTdcJl5hu1nSp2z8bba7Vq/MGbNLnazkd3A+GITBEML924JA==} + '@sentry/core@10.48.0': + resolution: {integrity: sha512-h8F+fXVwYC9ro5ZaO8V+v3vqc0awlXHGblEAuVxSGgh4IV/oFX+QVzXeDTTrFOFS6v/Vn5vAyu240eJrJAS6/g==} engines: {node: '>=18'} - '@sentry/node-core@10.47.0': - resolution: {integrity: sha512-qv6LsqHbkQmd0aQEUox/svRSz26J+l4gGjFOUNEay2armZu9XLD+Ct89jpFgZD5oIPNAj2jraodTRqydXiwS5w==} + '@sentry/node-core@10.48.0': + resolution: {integrity: sha512-D1TnPhN6vhrRqJ+bN+rdXDM+INibI6lNBm0eGx45zz7DBx9ouq2e9gm/DPx+y/hAkYYq0qTd6x84cGxtVZbKLw==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -1832,12 +1832,12 @@ packages: '@opentelemetry/semantic-conventions': optional: true - '@sentry/node@10.47.0': - resolution: {integrity: sha512-R+btqPepv88o635G6HtVewLjqCLUedBg5HBs7Nq1qbbKvyti01uArUF2f+3DsLenk5B9LUNiRlE+frZA44Ahmw==} + '@sentry/node@10.48.0': + resolution: {integrity: sha512-MzyLJyYmr0Qg60K6NJ2EdwJUX1OuAYXs9tyYxnqVO3nJ8MyYwIcuN4FCYEnXkG6Jiy/4q7OuZgXWnfdQJVcaqw==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.47.0': - resolution: {integrity: sha512-f6Hw2lrpCjlOksiosP0Z2jK/+l+21SIdoNglVeG/sttMyx8C8ywONKh0Ha50sFsvB1VaB8n94RKzzf3hkh9V3g==} + '@sentry/opentelemetry@10.48.0': + resolution: {integrity: sha512-Tn6Y0PZjRJ7OW8loK1ntK7wnJnIINnCfSpnwuqow0FMblaDmu5jDVOYq0U1SJBoBcMD5j9aSqrwyj6zqKwjc0A==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -1846,20 +1846,23 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 - '@sentry/react@10.47.0': - resolution: {integrity: sha512-ZtJV6xxF8jUVE9e3YQUG3Do0XapG1GjniyLyqMPgN6cNvs/HaRJODf7m60By+VGqcl5XArEjEPTvx8CdPUXDfA==} + '@sentry/react@10.48.0': + resolution: {integrity: sha512-uc93vKjmu6gNns+JAX4qquuxWpAMit0uGPA1TYlMjct9NG1uX3TkDPJAr9Pgd1lOXx8mKqCmj5fK33QeExMpPw==} engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - '@sentry/rollup-plugin@5.1.1': - resolution: {integrity: sha512-1d5NkdRR6aKWBP7czkY8sFFWiKnfmfRpQOj+m9bJTsyTjbMiEQJst6315w5pCVlRItPhBqpAraqAhutZFgvyVg==} + '@sentry/rollup-plugin@5.2.0': + resolution: {integrity: sha512-a8LfpvcYMFtFSroro5MpCcOoS528LeLfUHzxWURnpofOnY+Aso9Si4y4dFlna+RKqxCXjmFbn6CLnfI+YrHysQ==} engines: {node: '>= 18'} peerDependencies: rollup: '>=3.2.0' + peerDependenciesMeta: + rollup: + optional: true - '@sentry/vite-plugin@5.1.1': - resolution: {integrity: sha512-i6NWUDi2SDikfSUeMJvJTRdwEKYSfTd+mvBO2Ja51S1YK+hnickBuDfD+RvPerIXLuyRu3GamgNPbNqgCGUg/Q==} + '@sentry/vite-plugin@5.2.0': + resolution: {integrity: sha512-4Jo3ixBspso5HY81PDvZdRXkH9wYGVmcw/0a2IX9ejbyKBdHqkYg4IhAtNqGUAyGuHwwRS9Y1S+sCMvrXv6htw==} engines: {node: '>= 18'} '@simplewebauthn/browser@13.3.0': @@ -1989,33 +1992,33 @@ packages: '@types/react-dom': optional: true - '@turbo/darwin-64@2.9.3': - resolution: {integrity: sha512-P8foouaP+y/p+hhEGBoZpzMbpVvUMwPjDpcy6wN7EYfvvyISD1USuV27qWkczecihwuPJzQ1lDBuL8ERcavTyg==} + '@turbo/darwin-64@2.9.6': + resolution: {integrity: sha512-X/56SnVXIQZBLKwniGTwEQTGmtE5brSACnKMBWpY3YafuxVYefrC2acamfjgxP7BG5w3I+6jf0UrLoSzgPcSJg==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.3': - resolution: {integrity: sha512-SIzEkvtNdzdI50FJDaIQ6kQGqgSSdFPcdn0wqmmONN6iGKjy6hsT+EH99GP65FsfV7DLZTh2NmtTIRl2kdoz5Q==} + '@turbo/darwin-arm64@2.9.6': + resolution: {integrity: sha512-aalBeSl4agT/QtYGDyf/XLajedWzUC9Vg/pm/YO6QQ93vkQ91Vz5uK1ta5RbVRDozQSz4njxUNqRNmOXDzW+qw==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.3': - resolution: {integrity: sha512-pLRwFmcHHNBvsCySLS6OFabr/07kDT2pxEt/k6eBf/3asiVQZKJ7Rk88AafQx2aYA641qek4RsXvYO3JYpiBug==} + '@turbo/linux-64@2.9.6': + resolution: {integrity: sha512-YKi05jnNHaD7vevgYwahpzGwbsNNTwzU2c7VZdmdFm7+cGDP4oREUWSsainiMfRqjRuolQxBwRn8wf1jmu+YZA==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.3': - resolution: {integrity: sha512-gy6ApUroC2Nzv+qjGtE/uPNkhHAFU4c8God+zd5Aiv9L9uBgHlxVJpHT3XWl5xwlJZ2KWuMrlHTaS5kmNB+q1Q==} + '@turbo/linux-arm64@2.9.6': + resolution: {integrity: sha512-02o/ZS69cOYEDczXvOB2xmyrtzjQ2hVFtWZK1iqxXUfzMmTjZK4UumrfNnjckSg+gqeBfnPRHa0NstA173Ik3g==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.3': - resolution: {integrity: sha512-d0YelTX6hAsB7kIEtGB3PzIzSfAg3yDoUlHwuwJc3adBXUsyUIs0YLG+1NNtuhcDOUGnWQeKUoJ2pGWvbpRj7w==} + '@turbo/windows-64@2.9.6': + resolution: {integrity: sha512-wVdQjvnBI15wB6JrA+43CtUtagjIMmX6XYO758oZHAsCNSxqRlJtdyujih0D8OCnwCRWiGWGI63zAxR0hO6s9g==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.3': - resolution: {integrity: sha512-/08CwpKJl3oRY8nOlh2YgilZVJDHsr60XTNxRhuDeuFXONpUZ5X+Nv65izbG/xBew9qxcJFbDX9/sAmAX+ITcQ==} + '@turbo/windows-arm64@2.9.6': + resolution: {integrity: sha512-1XUUyWW0W6FTSqGEhU8RHVqb2wP1SPkr7hIvBlMEwH9jr+sJQK5kqeosLJ/QaUv4ecSAd1ZhIrLoW7qslAzT4A==} cpu: [arm64] os: [win32] @@ -2123,63 +2126,63 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@typescript-eslint/eslint-plugin@8.58.0': - resolution: {integrity: sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==} + '@typescript-eslint/eslint-plugin@8.58.1': + resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.0 + '@typescript-eslint/parser': ^8.58.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.0': - resolution: {integrity: sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==} + '@typescript-eslint/parser@8.58.1': + resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.0': - resolution: {integrity: sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==} + '@typescript-eslint/project-service@8.58.1': + resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.0': - resolution: {integrity: sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==} + '@typescript-eslint/scope-manager@8.58.1': + resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.0': - resolution: {integrity: sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==} + '@typescript-eslint/tsconfig-utils@8.58.1': + resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.0': - resolution: {integrity: sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==} + '@typescript-eslint/type-utils@8.58.1': + resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.0': - resolution: {integrity: sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==} + '@typescript-eslint/types@8.58.1': + resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.0': - resolution: {integrity: sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==} + '@typescript-eslint/typescript-estree@8.58.1': + resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.0': - resolution: {integrity: sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==} + '@typescript-eslint/utils@8.58.1': + resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.0': - resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==} + '@typescript-eslint/visitor-keys@8.58.1': + resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vitejs/plugin-basic-ssl@2.3.0': @@ -2188,11 +2191,11 @@ packages: peerDependencies: vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@vitest/expect@4.1.2': - resolution: {integrity: sha512-gbu+7B0YgUJ2nkdsRJrFFW6X7NTP44WlhiclHniUhxADQJH5Szt9mZ9hWnJPJ8YwOK5zUOSSlSvyzRf0u1DSBQ==} + '@vitest/expect@4.1.4': + resolution: {integrity: sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==} - '@vitest/mocker@4.1.2': - resolution: {integrity: sha512-Ize4iQtEALHDttPRCmN+FKqOl2vxTiNUhzobQFFt/BM1lRUTG7zRCLOykG/6Vo4E4hnUdfVLo5/eqKPukcWW7Q==} + '@vitest/mocker@4.1.4': + resolution: {integrity: sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2202,20 +2205,20 @@ packages: vite: optional: true - '@vitest/pretty-format@4.1.2': - resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} + '@vitest/pretty-format@4.1.4': + resolution: {integrity: sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==} - '@vitest/runner@4.1.2': - resolution: {integrity: sha512-Gr+FQan34CdiYAwpGJmQG8PgkyFVmARK8/xSijia3eTFgVfpcpztWLuP6FttGNfPLJhaZVP/euvujeNYar36OQ==} + '@vitest/runner@4.1.4': + resolution: {integrity: sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==} - '@vitest/snapshot@4.1.2': - resolution: {integrity: sha512-g7yfUmxYS4mNxk31qbOYsSt2F4m1E02LFqO53Xpzg3zKMhLAPZAjjfyl9e6z7HrW6LvUdTwAQR3HHfLjpko16A==} + '@vitest/snapshot@4.1.4': + resolution: {integrity: sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==} - '@vitest/spy@4.1.2': - resolution: {integrity: sha512-DU4fBnbVCJGNBwVA6xSToNXrkZNSiw59H8tcuUspVMsBDBST4nfvsPsEHDHGtWRRnqBERBQu7TrTKskmjqTXKA==} + '@vitest/spy@4.1.4': + resolution: {integrity: sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==} - '@vitest/utils@4.1.2': - resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} + '@vitest/utils@4.1.4': + resolution: {integrity: sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==} accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -2878,8 +2881,8 @@ packages: i18next-browser-languagedetector@8.2.1: resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} - i18next@26.0.3: - resolution: {integrity: sha512-1571kXINxHKY7LksWp8wP+zP0YqHSSpl/OW0Y0owFEf2H3s8gCAffWaZivcz14rMkOvn3R/psiQxVsR9t2Nafg==} + i18next@26.0.4: + resolution: {integrity: sha512-gXF7U9bfioXPLv7mw8Qt2nfO7vij5MyINvPgVv99pX3fL1Y01pw2mKBFrlYpRxRCl2wz3ISenj6VsMJT2isfuA==} peerDependencies: typescript: ^5 || ^6 peerDependenciesMeta: @@ -2958,8 +2961,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - jsdom@29.0.1: - resolution: {integrity: sha512-z6JOK5gRO7aMybVq/y/MlIpKh8JIi68FBKMUtKkK2KH/wMSRlCxQ682d08LB9fYXplyY/UXG8P4XXTScmdjApg==} + jsdom@29.0.2: + resolution: {integrity: sha512-9VnGEBosc/ZpwyOsJBCQ/3I5p7Q5ngOY14a9bf5btenAORmZfDse1ZEheMiWcJ3h81+Fv7HmJFdS0szo/waF2w==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} peerDependencies: canvas: ^3.0.0 @@ -3348,8 +3351,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.2: + resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} engines: {node: '>=14'} hasBin: true @@ -3410,10 +3413,10 @@ packages: rbush@3.0.1: resolution: {integrity: sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==} - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-i18next@17.0.2: resolution: {integrity: sha512-shBftH2vaTWK2Bsp7FiL+cevx3xFJlvFxmsDFQSrJc+6twHkP0tv/bGa01VVWzpreUVVwU+3Hev5iFqRg65RwA==} @@ -3455,8 +3458,8 @@ packages: react-dom: optional: true - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} readdirp@4.1.2: @@ -3691,8 +3694,8 @@ packages: resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} engines: {node: '>= 6.0.0'} - turbo@2.9.3: - resolution: {integrity: sha512-J/VUvsGRykPb9R8Kh8dHVBOqioDexLk9BhLCU/ZybRR+HN9UR3cURdazFvNgMDt9zPP8TF6K73Z+tplfmi0PqQ==} + turbo@2.9.6: + resolution: {integrity: sha512-+v2QJey7ZUeUiuigkU+uFfklvNUyPI2VO2vBpMYJA+a1hKFLFiKtUYlRHdb3P9CrAvMzi0upbjI4WT+zKtqkBg==} hasBin: true type-check@0.4.0: @@ -3703,8 +3706,8 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript-eslint@8.58.0: - resolution: {integrity: sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==} + typescript-eslint@8.58.1: + resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -3847,18 +3850,20 @@ packages: yaml: optional: true - vitest@4.1.2: - resolution: {integrity: sha512-xjR1dMTVHlFLh98JE3i/f/WePqJsah4A0FK9cc8Ehp9Udk0AZk6ccpIZhh1qJ/yxVWRZ+Q54ocnD8TXmkhspGg==} + vitest@4.1.4: + resolution: {integrity: sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.2 - '@vitest/browser-preview': 4.1.2 - '@vitest/browser-webdriverio': 4.1.2 - '@vitest/ui': 4.1.2 + '@vitest/browser-playwright': 4.1.4 + '@vitest/browser-preview': 4.1.4 + '@vitest/browser-webdriverio': 4.1.4 + '@vitest/coverage-istanbul': 4.1.4 + '@vitest/coverage-v8': 4.1.4 + '@vitest/ui': 4.1.4 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3875,6 +3880,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -3978,21 +3987,19 @@ snapshots: '@adobe/css-tools@4.4.4': {} - '@asamuzakjp/css-color@5.0.1': + '@asamuzakjp/css-color@5.1.9': dependencies: '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.7 - '@asamuzakjp/dom-selector@7.0.4': + '@asamuzakjp/dom-selector@7.0.9': dependencies: '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.7 '@asamuzakjp/nwsapi@2.3.9': {} @@ -4508,7 +4515,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@geoman-io/leaflet-geoman-free@2.19.2(leaflet@1.9.4)': + '@geoman-io/leaflet-geoman-free@2.19.3(leaflet@1.9.4)': dependencies: '@turf/boolean-contains': 7.3.4 '@turf/kinks': 7.3.4 @@ -4610,15 +4617,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-express@0.62.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - '@opentelemetry/instrumentation-fs@0.33.0(@opentelemetry/api@1.9.1)': dependencies: '@opentelemetry/api': 1.9.1 @@ -4935,13 +4933,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@react-leaflet/core@3.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: leaflet: 1.9.4 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) - '@react-router/dev@7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': + '@react-router/dev@7.14.0(@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3))(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -4950,7 +4948,7 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) '@babel/traverse': 7.29.0 '@babel/types': 7.29.0 - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) '@remix-run/node-fetch-server': 0.13.0 arg: 5.0.2 babel-dead-code-elimination: 1.0.12 @@ -4965,16 +4963,16 @@ snapshots: pathe: 1.1.2 picocolors: 1.1.1 pkg-types: 2.3.0 - prettier: 3.8.1 + prettier: 3.8.2 react-refresh: 0.14.2 - react-router: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) semver: 7.7.4 tinyglobby: 0.2.15 valibot: 1.3.1(typescript@5.9.3) vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) vite-node: 3.2.4(@types/node@25.5.2)(jiti@2.6.1)(lightningcss@1.32.0)(tsx@4.21.0) optionalDependencies: - '@react-router/serve': 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@react-router/serve': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - '@types/node' @@ -4991,31 +4989,31 @@ snapshots: - tsx - yaml - '@react-router/express@7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + '@react-router/express@7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) express: 4.22.1 - react-router: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/node@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + '@react-router/node@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) optionalDependencies: typescript: 5.9.3 - '@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3)': + '@react-router/serve@7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - '@react-router/express': 7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) - '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + '@react-router/express': 7.14.0(express@4.22.1)(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) + '@react-router/node': 7.14.0(react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(typescript@5.9.3) compression: 1.8.1 express: 4.22.1 get-port: 5.1.1 morgan: 1.10.1 - react-router: 7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-router: 7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color @@ -5149,38 +5147,38 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.60.0': optional: true - '@sentry-internal/browser-utils@10.47.0': + '@sentry-internal/browser-utils@10.48.0': dependencies: - '@sentry/core': 10.47.0 + '@sentry/core': 10.48.0 - '@sentry-internal/feedback@10.47.0': + '@sentry-internal/feedback@10.48.0': dependencies: - '@sentry/core': 10.47.0 + '@sentry/core': 10.48.0 - '@sentry-internal/replay-canvas@10.47.0': + '@sentry-internal/replay-canvas@10.48.0': dependencies: - '@sentry-internal/replay': 10.47.0 - '@sentry/core': 10.47.0 + '@sentry-internal/replay': 10.48.0 + '@sentry/core': 10.48.0 - '@sentry-internal/replay@10.47.0': + '@sentry-internal/replay@10.48.0': dependencies: - '@sentry-internal/browser-utils': 10.47.0 - '@sentry/core': 10.47.0 + '@sentry-internal/browser-utils': 10.48.0 + '@sentry/core': 10.48.0 - '@sentry/babel-plugin-component-annotate@5.1.1': {} + '@sentry/babel-plugin-component-annotate@5.2.0': {} - '@sentry/browser@10.47.0': + '@sentry/browser@10.48.0': dependencies: - '@sentry-internal/browser-utils': 10.47.0 - '@sentry-internal/feedback': 10.47.0 - '@sentry-internal/replay': 10.47.0 - '@sentry-internal/replay-canvas': 10.47.0 - '@sentry/core': 10.47.0 + '@sentry-internal/browser-utils': 10.48.0 + '@sentry-internal/feedback': 10.48.0 + '@sentry-internal/replay': 10.48.0 + '@sentry-internal/replay-canvas': 10.48.0 + '@sentry/core': 10.48.0 - '@sentry/bundler-plugin-core@5.1.1': + '@sentry/bundler-plugin-core@5.2.0': dependencies: '@babel/core': 7.29.0 - '@sentry/babel-plugin-component-annotate': 5.1.1 + '@sentry/babel-plugin-component-annotate': 5.2.0 '@sentry/cli': 2.58.5 dotenv: 16.6.1 find-up: 5.0.0 @@ -5234,12 +5232,12 @@ snapshots: - encoding - supports-color - '@sentry/core@10.47.0': {} + '@sentry/core@10.48.0': {} - '@sentry/node-core@10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/node-core@10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: - '@sentry/core': 10.47.0 - '@sentry/opentelemetry': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/core': 10.48.0 + '@sentry/opentelemetry': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 3.0.0 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -5250,7 +5248,7 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/node@10.47.0': + '@sentry/node@10.48.0': dependencies: '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) '@opentelemetry/api': 1.9.1 @@ -5260,7 +5258,6 @@ snapshots: '@opentelemetry/instrumentation-amqplib': 0.61.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-connect': 0.57.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-dataloader': 0.31.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-express': 0.62.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-fs': 0.33.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-generic-pool': 0.57.0(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) @@ -5283,42 +5280,43 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) - '@sentry/core': 10.47.0 - '@sentry/node-core': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/opentelemetry': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/core': 10.48.0 + '@sentry/node-core': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/resources@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) + '@sentry/opentelemetry': 10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) import-in-the-middle: 3.0.0 transitivePeerDependencies: - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/opentelemetry@10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': + '@sentry/opentelemetry@10.48.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/context-async-hooks': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/core': 10.47.0 + '@sentry/core': 10.48.0 - '@sentry/react@10.47.0(react@19.2.4)': + '@sentry/react@10.48.0(react@19.2.5)': dependencies: - '@sentry/browser': 10.47.0 - '@sentry/core': 10.47.0 - react: 19.2.4 + '@sentry/browser': 10.48.0 + '@sentry/core': 10.48.0 + react: 19.2.5 - '@sentry/rollup-plugin@5.1.1(rollup@4.60.0)': + '@sentry/rollup-plugin@5.2.0(rollup@4.60.0)': dependencies: - '@sentry/bundler-plugin-core': 5.1.1 + '@sentry/bundler-plugin-core': 5.2.0 magic-string: 0.30.21 + optionalDependencies: rollup: 4.60.0 transitivePeerDependencies: - encoding - supports-color - '@sentry/vite-plugin@5.1.1(rollup@4.60.0)': + '@sentry/vite-plugin@5.2.0(rollup@4.60.0)': dependencies: - '@sentry/bundler-plugin-core': 5.1.1 - '@sentry/rollup-plugin': 5.1.1(rollup@4.60.0) + '@sentry/bundler-plugin-core': 5.2.0 + '@sentry/rollup-plugin': 5.2.0(rollup@4.60.0) transitivePeerDependencies: - encoding - rollup @@ -5429,32 +5427,32 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: '@babel/runtime': 7.29.2 '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@turbo/darwin-64@2.9.3': + '@turbo/darwin-64@2.9.6': optional: true - '@turbo/darwin-arm64@2.9.3': + '@turbo/darwin-arm64@2.9.6': optional: true - '@turbo/linux-64@2.9.3': + '@turbo/linux-64@2.9.6': optional: true - '@turbo/linux-arm64@2.9.3': + '@turbo/linux-arm64@2.9.6': optional: true - '@turbo/windows-64@2.9.3': + '@turbo/windows-64@2.9.6': optional: true - '@turbo/windows-arm64@2.9.3': + '@turbo/windows-arm64@2.9.6': optional: true '@turf/bbox@7.3.4': @@ -5642,14 +5640,14 @@ snapshots: dependencies: '@types/node': 25.5.2 - '@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/type-utils': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.0 + '@typescript-eslint/parser': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.1 eslint: 10.2.0(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 @@ -5658,41 +5656,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.58.0 + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.58.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) - '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) + '@typescript-eslint/types': 8.58.1 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.0': + '@typescript-eslint/scope-manager@8.58.1': dependencies: - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/visitor-keys': 8.58.0 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/visitor-keys': 8.58.1 - '@typescript-eslint/tsconfig-utils@8.58.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.58.1(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 eslint: 10.2.0(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) @@ -5700,14 +5698,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.0': {} + '@typescript-eslint/types@8.58.1': {} - '@typescript-eslint/typescript-estree@8.58.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.58.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.58.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/visitor-keys': 8.58.0 + '@typescript-eslint/project-service': 8.58.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@5.9.3) + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/visitor-keys': 8.58.1 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.4 @@ -5717,64 +5715,64 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.0 - '@typescript-eslint/types': 8.58.0 - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.58.1 + '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.0': + '@typescript-eslint/visitor-keys@8.58.1': dependencies: - '@typescript-eslint/types': 8.58.0 + '@typescript-eslint/types': 8.58.1 eslint-visitor-keys: 5.0.1 '@vitejs/plugin-basic-ssl@2.3.0(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) - '@vitest/expect@4.1.2': + '@vitest/expect@4.1.4': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': + '@vitest/mocker@4.1.4(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0))': dependencies: - '@vitest/spy': 4.1.2 + '@vitest/spy': 4.1.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: vite: 8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0) - '@vitest/pretty-format@4.1.2': + '@vitest/pretty-format@4.1.4': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.2': + '@vitest/runner@4.1.4': dependencies: - '@vitest/utils': 4.1.2 + '@vitest/utils': 4.1.4 pathe: 2.0.3 - '@vitest/snapshot@4.1.2': + '@vitest/snapshot@4.1.4': dependencies: - '@vitest/pretty-format': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/pretty-format': 4.1.4 + '@vitest/utils': 4.1.4 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.2': {} + '@vitest/spy@4.1.4': {} - '@vitest/utils@4.1.2': + '@vitest/utils@4.1.4': dependencies: - '@vitest/pretty-format': 4.1.2 + '@vitest/pretty-format': 4.1.4 convert-source-map: 2.0.0 tinyrainbow: 3.1.0 @@ -6444,7 +6442,7 @@ snapshots: dependencies: '@babel/runtime': 7.29.2 - i18next@26.0.3(typescript@5.9.3): + i18next@26.0.4(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 optionalDependencies: @@ -6504,10 +6502,10 @@ snapshots: js-tokens@4.0.0: {} - jsdom@29.0.1: + jsdom@29.0.2: dependencies: - '@asamuzakjp/css-color': 5.0.1 - '@asamuzakjp/dom-selector': 7.0.4 + '@asamuzakjp/css-color': 5.1.9 + '@asamuzakjp/dom-selector': 7.0.9 '@bramus/specificity': 2.4.2 '@csstools/css-syntax-patches-for-csstree': 1.1.1(css-tree@3.2.1) '@exodus/bytes': 1.15.0 @@ -6851,7 +6849,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.8.1: {} + prettier@3.8.2: {} pretty-format@27.5.1: dependencies: @@ -6909,42 +6907,42 @@ snapshots: dependencies: quickselect: 2.0.0 - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 - react-i18next@17.0.2(i18next@26.0.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + react-i18next@17.0.2(i18next@26.0.4(typescript@5.9.3))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 - i18next: 26.0.3(typescript@5.9.3) - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + i18next: 26.0.4(typescript@5.9.3) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) typescript: 5.9.3 react-is@17.0.2: {} - react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-leaflet@5.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@react-leaflet/core': 3.0.0(leaflet@1.9.4)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) leaflet: 1.9.4 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) react-refresh@0.14.2: {} - react-router@7.14.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + react-router@7.14.0(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: cookie: 1.1.1 - react: 19.2.4 + react: 19.2.5 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) - react@19.2.4: {} + react@19.2.5: {} readdirp@4.1.2: {} @@ -7206,14 +7204,14 @@ snapshots: dependencies: tslib: 1.14.1 - turbo@2.9.3: + turbo@2.9.6: optionalDependencies: - '@turbo/darwin-64': 2.9.3 - '@turbo/darwin-arm64': 2.9.3 - '@turbo/linux-64': 2.9.3 - '@turbo/linux-arm64': 2.9.3 - '@turbo/windows-64': 2.9.3 - '@turbo/windows-arm64': 2.9.3 + '@turbo/darwin-64': 2.9.6 + '@turbo/darwin-arm64': 2.9.6 + '@turbo/linux-64': 2.9.6 + '@turbo/linux-arm64': 2.9.6 + '@turbo/windows-64': 2.9.6 + '@turbo/windows-arm64': 2.9.6 type-check@0.4.0: dependencies: @@ -7224,12 +7222,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript-eslint@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.58.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.58.0(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3))(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.58.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.58.1(eslint@10.2.0(jiti@2.6.1))(typescript@5.9.3) eslint: 10.2.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -7255,9 +7253,9 @@ snapshots: dependencies: punycode: 2.3.1 - use-sync-external-store@1.6.0(react@19.2.4): + use-sync-external-store@1.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 utils-merge@1.0.1: {} @@ -7317,15 +7315,15 @@ snapshots: jiti: 2.6.1 tsx: 4.21.0 - vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.1)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)): + vitest@4.1.4(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(jsdom@29.0.2)(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)): dependencies: - '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) - '@vitest/pretty-format': 4.1.2 - '@vitest/runner': 4.1.2 - '@vitest/snapshot': 4.1.2 - '@vitest/spy': 4.1.2 - '@vitest/utils': 4.1.2 + '@vitest/expect': 4.1.4 + '@vitest/mocker': 4.1.4(vite@8.0.8(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.6.1)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.4 + '@vitest/runner': 4.1.4 + '@vitest/snapshot': 4.1.4 + '@vitest/spy': 4.1.4 + '@vitest/utils': 4.1.4 es-module-lexer: 2.0.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -7342,7 +7340,7 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.5.2 - jsdom: 29.0.1 + jsdom: 29.0.2 transitivePeerDependencies: - msw diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 54c4586..29b41bb 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,8 +3,8 @@ packages: - "packages/*" catalog: - react: ^19.2.4 - react-dom: ^19.2.4 + react: ^19.2.5 + react-dom: ^19.2.5 react-router: ^7.14.0 "@react-router/dev": ^7.14.0 "@react-router/node": ^7.14.0 @@ -18,4 +18,6 @@ catalog: drizzle-orm: ^0.45.2 drizzle-kit: ^0.31.10 drizzle-postgis: ^1.1.1 + "@sentry/node": ^10.48.0 + "@sentry/react": ^10.48.0 postgres: ^3.4.9 From efdb3c19737f8efeb07e9c047d47f43a77115c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 23:51:31 +0200 Subject: [PATCH 007/642] Add multi-day data model, computeDays, and GPX roundtrip - overnight.ts: Yjs helpers to set/clear/check overnight flag on waypoints - compute-days.ts: Pure function splitting routes into DayStage[] at day breaks - use-days.ts: Reactive hook mapping Yjs state into computeDays() input - GPX generate: emit overnight for isDayBreak waypoints - GPX parse: recognize overnight and set isDayBreak on waypoints Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/planner/app/lib/overnight.ts | 24 ++++ apps/planner/app/lib/use-days.ts | 68 ++++++++++++ openspec/changes/multi-day-routes/tasks.md | 10 +- packages/gpx/src/compute-days.ts | 121 +++++++++++++++++++++ packages/gpx/src/generate.ts | 3 + packages/gpx/src/index.ts | 2 + packages/gpx/src/parse.ts | 4 +- 7 files changed, 226 insertions(+), 6 deletions(-) create mode 100644 apps/planner/app/lib/overnight.ts create mode 100644 apps/planner/app/lib/use-days.ts create mode 100644 packages/gpx/src/compute-days.ts diff --git a/apps/planner/app/lib/overnight.ts b/apps/planner/app/lib/overnight.ts new file mode 100644 index 0000000..eecfabc --- /dev/null +++ b/apps/planner/app/lib/overnight.ts @@ -0,0 +1,24 @@ +import * as Y from "yjs"; +import type { YjsState } from "./use-yjs.ts"; + +/** + * Set or clear the overnight flag on a waypoint. + */ +export function setOvernight(yjs: YjsState, index: number, value: boolean): void { + const waypointMap = yjs.waypoints.get(index); + if (!waypointMap) return; + yjs.doc.transact(() => { + if (value) { + waypointMap.set("overnight", true); + } else { + waypointMap.delete("overnight"); + } + }, "local"); +} + +/** + * Check if a waypoint Y.Map has the overnight flag set. + */ +export function isOvernight(yMap: Y.Map): boolean { + return yMap.get("overnight") === true; +} diff --git a/apps/planner/app/lib/use-days.ts b/apps/planner/app/lib/use-days.ts new file mode 100644 index 0000000..f56326a --- /dev/null +++ b/apps/planner/app/lib/use-days.ts @@ -0,0 +1,68 @@ +import { useEffect, useState } from "react"; +import * as Y from "yjs"; +import { computeDays, type DayStage } from "@trails-cool/gpx"; +import type { Waypoint } from "@trails-cool/types"; +import type { TrackPoint } from "@trails-cool/gpx"; +import type { YjsState } from "./use-yjs.ts"; +import { isOvernight } from "./overnight.ts"; + +/** + * Reactive hook that computes day stages from Yjs waypoints and route data. + * Returns an empty array for single-day routes (no overnight waypoints). + */ +export function useDays(yjs: YjsState | null): DayStage[] { + const [days, setDays] = useState([]); + + useEffect(() => { + if (!yjs) return; + + const recompute = () => { + // Extract waypoints with isDayBreak from Yjs + const waypoints: Waypoint[] = yjs.waypoints.toArray().map((yMap: Y.Map) => ({ + lat: yMap.get("lat") as number, + lon: yMap.get("lon") as number, + name: yMap.get("name") as string | undefined, + isDayBreak: isOvernight(yMap) || undefined, + })); + + // Check if any waypoint has isDayBreak + const hasBreaks = waypoints.some((w) => w.isDayBreak); + if (!hasBreaks) { + setDays([]); + return; + } + + // Extract track points from route coordinates stored in Yjs + const coordsStr = yjs.routeData.get("coordinates") as string | undefined; + if (!coordsStr) { + setDays([]); + return; + } + + try { + // coordinates are stored as [[lon, lat, ele], ...] (GeoJSON format) + const coords: number[][] = JSON.parse(coordsStr); + const trackPoints: TrackPoint[] = coords.map((c) => ({ + lat: c[1]!, + lon: c[0]!, + ele: c[2], + })); + + setDays(computeDays(waypoints, [trackPoints])); + } catch { + setDays([]); + } + }; + + yjs.waypoints.observeDeep(recompute); + yjs.routeData.observe(recompute); + recompute(); + + return () => { + yjs.waypoints.unobserveDeep(recompute); + yjs.routeData.unobserve(recompute); + }; + }, [yjs]); + + return days; +} diff --git a/openspec/changes/multi-day-routes/tasks.md b/openspec/changes/multi-day-routes/tasks.md index 717fbcd..120db05 100644 --- a/openspec/changes/multi-day-routes/tasks.md +++ b/openspec/changes/multi-day-routes/tasks.md @@ -1,8 +1,8 @@ ## 1. Data Model & Computation -- [ ] 1.1 Add `overnight` property support to Yjs waypoint Y.Maps: helper functions `setOvernight(yjs, index, value)` and `isOvernight(yMap)` in a new `apps/planner/app/lib/overnight.ts` -- [ ] 1.2 Create `computeDays()` pure function in `packages/gpx/src/compute-days.ts`: takes `Waypoint[]` + `TrackPoint[][]`, returns `DayStage[]` (day number, waypoint range, distance, ascent, descent). Export from package index. -- [ ] 1.3 Create `useDays()` hook in `apps/planner/app/lib/use-days.ts`: maps Yjs waypoints + EnrichedRoute into `computeDays()` input, returns reactive `DayStage[]` +- [x] 1.1 Add `overnight` property support to Yjs waypoint Y.Maps: helper functions `setOvernight(yjs, index, value)` and `isOvernight(yMap)` in a new `apps/planner/app/lib/overnight.ts` +- [x] 1.2 Create `computeDays()` pure function in `packages/gpx/src/compute-days.ts`: takes `Waypoint[]` + `TrackPoint[][]`, returns `DayStage[]` (day number, waypoint range, distance, ascent, descent). Export from package index. +- [x] 1.3 Create `useDays()` hook in `apps/planner/app/lib/use-days.ts`: maps Yjs waypoints + EnrichedRoute into `computeDays()` input, returns reactive `DayStage[]` ## 2. Sidebar Day Breakdown @@ -24,8 +24,8 @@ ## 5. GPX Roundtrip -- [ ] 5.1 Extend `generateGpx` in `@trails-cool/gpx` to emit `overnight` for waypoints with `isDayBreak: true` -- [ ] 5.2 Extend `parseGpx` in `@trails-cool/gpx` to recognize `overnight` and set `isDayBreak: true` on parsed waypoints +- [x] 5.1 Extend `generateGpx` in `@trails-cool/gpx` to emit `overnight` for waypoints with `isDayBreak: true` +- [x] 5.2 Extend `parseGpx` in `@trails-cool/gpx` to recognize `overnight` and set `isDayBreak: true` on parsed waypoints - [ ] 5.3 Add multi-track export option: split track into one `` per day, each named "Day N: Start - End" ## 6. Journal Integration diff --git a/packages/gpx/src/compute-days.ts b/packages/gpx/src/compute-days.ts new file mode 100644 index 0000000..f5211cc --- /dev/null +++ b/packages/gpx/src/compute-days.ts @@ -0,0 +1,121 @@ +import type { Waypoint } from "@trails-cool/types"; +import type { TrackPoint } from "./types.ts"; + +export interface DayStage { + dayNumber: number; + startWaypointIndex: number; + endWaypointIndex: number; + startName?: string; + endName?: string; + /** Distance in meters */ + distance: number; + /** Ascent in meters */ + ascent: number; + /** Descent in meters */ + descent: number; +} + +/** + * Split a route into day stages based on waypoints with isDayBreak. + * + * Day boundaries are defined by waypoints where isDayBreak is true. + * The first waypoint is the implicit start of Day 1, the last waypoint + * is the implicit end of the final day, and each isDayBreak waypoint + * marks the end of one day and the start of the next. + * + * If no waypoints have isDayBreak, returns a single day covering the + * entire route. + */ +export function computeDays( + waypoints: Waypoint[], + tracks: TrackPoint[][], +): DayStage[] { + if (waypoints.length === 0 || tracks.length === 0) return []; + + // Flatten all tracks into a single point array + const allPoints: TrackPoint[] = tracks.flat(); + if (allPoints.length === 0) return []; + + // Find waypoint indices that are day breaks + const breakIndices: number[] = []; + for (let i = 0; i < waypoints.length; i++) { + if (waypoints[i]!.isDayBreak) { + breakIndices.push(i); + } + } + + // Build day boundaries: [0, break1, break2, ..., lastWaypointIndex] + const boundaries = [0, ...breakIndices]; + if (boundaries[boundaries.length - 1] !== waypoints.length - 1) { + boundaries.push(waypoints.length - 1); + } + + // For each waypoint, find the closest point in the track + const waypointTrackIndices = waypoints.map((wp) => { + let bestIdx = 0; + let bestDist = Infinity; + for (let i = 0; i < allPoints.length; i++) { + const dx = allPoints[i]!.lat - wp.lat; + const dy = allPoints[i]!.lon - wp.lon; + const d = dx * dx + dy * dy; + if (d < bestDist) { + bestDist = d; + bestIdx = i; + } + } + return bestIdx; + }); + + // Precompute cumulative distances and elevation changes + const cumDist: number[] = [0]; + const cumAscent: number[] = [0]; + const cumDescent: number[] = [0]; + + for (let i = 1; i < allPoints.length; i++) { + const prev = allPoints[i - 1]!; + const curr = allPoints[i]!; + cumDist.push(cumDist[i - 1]! + haversine(prev.lat, prev.lon, curr.lat, curr.lon)); + + if (prev.ele !== undefined && curr.ele !== undefined) { + const diff = curr.ele - prev.ele; + cumAscent.push(cumAscent[i - 1]! + (diff > 0 ? diff : 0)); + cumDescent.push(cumDescent[i - 1]! + (diff < 0 ? -diff : 0)); + } else { + cumAscent.push(cumAscent[i - 1]!); + cumDescent.push(cumDescent[i - 1]!); + } + } + + // Build day stages + const days: DayStage[] = []; + for (let d = 0; d < boundaries.length - 1; d++) { + const startWpIdx = boundaries[d]!; + const endWpIdx = boundaries[d + 1]!; + const startTrackIdx = waypointTrackIndices[startWpIdx]!; + const endTrackIdx = waypointTrackIndices[endWpIdx]!; + + days.push({ + dayNumber: d + 1, + startWaypointIndex: startWpIdx, + endWaypointIndex: endWpIdx, + startName: waypoints[startWpIdx]!.name, + endName: waypoints[endWpIdx]!.name, + distance: Math.round(cumDist[endTrackIdx]! - cumDist[startTrackIdx]!), + ascent: Math.round(cumAscent[endTrackIdx]! - cumAscent[startTrackIdx]!), + descent: Math.round(cumDescent[endTrackIdx]! - cumDescent[startTrackIdx]!), + }); + } + + return days; +} + +function haversine(lat1: number, lon1: number, lat2: number, lon2: number): number { + const R = 6371000; + const toRad = (d: number) => (d * Math.PI) / 180; + const dLat = toRad(lat2 - lat1); + const dLon = toRad(lon2 - lon1); + const a = + Math.sin(dLat / 2) ** 2 + + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; + return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +} diff --git a/packages/gpx/src/generate.ts b/packages/gpx/src/generate.ts index 1be51f2..f52de43 100644 --- a/packages/gpx/src/generate.ts +++ b/packages/gpx/src/generate.ts @@ -33,6 +33,9 @@ export function generateGpx(options: { if (wpt.name) { lines.push(` ${escapeXml(wpt.name)}`); } + if (wpt.isDayBreak) { + lines.push(" overnight"); + } lines.push(" "); } } diff --git a/packages/gpx/src/index.ts b/packages/gpx/src/index.ts index 6830ada..f958032 100644 --- a/packages/gpx/src/index.ts +++ b/packages/gpx/src/index.ts @@ -1,4 +1,6 @@ export { parseGpxAsync } from "./parse.ts"; export { generateGpx } from "./generate.ts"; export { extractWaypoints } from "./waypoints.ts"; +export { computeDays } from "./compute-days.ts"; +export type { DayStage } from "./compute-days.ts"; export type { GpxData, TrackPoint, ElevationProfile, NoGoArea } from "./types.ts"; diff --git a/packages/gpx/src/parse.ts b/packages/gpx/src/parse.ts index e43d249..114aad9 100644 --- a/packages/gpx/src/parse.ts +++ b/packages/gpx/src/parse.ts @@ -58,7 +58,9 @@ function parseWaypoints(doc: Document): Waypoint[] { const lat = parseFloat(wpt.getAttribute("lat") ?? "0"); const lon = parseFloat(wpt.getAttribute("lon") ?? "0"); const name = wpt.querySelector("name")?.textContent ?? undefined; - return { lat, lon, name }; + const type = wpt.querySelector("type")?.textContent ?? undefined; + const isDayBreak = type === "overnight" ? true : undefined; + return { lat, lon, name, isDayBreak }; }); } From 94016fd4c4c938d19f097715c36c02aa803bc971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 10 Apr 2026 23:53:43 +0200 Subject: [PATCH 008/642] Add sidebar day breakdown and overnight toggle UI - DayBreakdown: Collapsible day sections with per-day stats - WaypointSidebar: Overnight toggle button (moon icon), day-grouped view when any waypoint is marked overnight, route summary in header - SessionView: Wire useDays() hook into sidebar via SidebarTabs - i18n: Add multiDay keys for en + de (day labels, overnight, stats) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/planner/app/components/DayBreakdown.tsx | 54 +++++++ apps/planner/app/components/SessionView.tsx | 4 +- .../app/components/WaypointSidebar.tsx | 152 ++++++++++++------ openspec/changes/multi-day-routes/tasks.md | 10 +- packages/i18n/src/locales/de.ts | 11 ++ packages/i18n/src/locales/en.ts | 11 ++ 6 files changed, 190 insertions(+), 52 deletions(-) create mode 100644 apps/planner/app/components/DayBreakdown.tsx diff --git a/apps/planner/app/components/DayBreakdown.tsx b/apps/planner/app/components/DayBreakdown.tsx new file mode 100644 index 0000000..9632531 --- /dev/null +++ b/apps/planner/app/components/DayBreakdown.tsx @@ -0,0 +1,54 @@ +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import type { DayStage } from "@trails-cool/gpx"; + +interface DayBreakdownProps { + days: DayStage[]; + children: (dayStage: DayStage, waypointIndices: { start: number; end: number }) => React.ReactNode; +} + +export function DayBreakdown({ days, children }: DayBreakdownProps) { + const { t } = useTranslation(); + const [expandedDay, setExpandedDay] = useState(1); + + return ( +
+ {days.map((day) => { + const isExpanded = expandedDay === day.dayNumber; + return ( +
+ + + {isExpanded && ( + <> +
+ ↑ {day.ascent} m + ↓ {day.descent} m +
+ {children(day, { start: day.startWaypointIndex, end: day.endWaypointIndex })} + + )} +
+ ); + })} +
+ ); +} diff --git a/apps/planner/app/components/SessionView.tsx b/apps/planner/app/components/SessionView.tsx index 6cea400..614934f 100644 --- a/apps/planner/app/components/SessionView.tsx +++ b/apps/planner/app/components/SessionView.tsx @@ -5,6 +5,7 @@ import type { TFunction } from "i18next"; import * as Sentry from "@sentry/react"; import { useYjs, type YjsState } from "~/lib/use-yjs"; import { useRouting, type RouteError } from "~/lib/use-routing"; +import { useDays } from "~/lib/use-days"; import { useUndo, useUndoShortcuts } from "~/lib/use-undo"; import { ProfileSelector } from "~/components/ProfileSelector"; import { ExportButton } from "~/components/ExportButton"; @@ -144,6 +145,7 @@ function ColorModeToggle({ yjs }: { yjs: YjsState }) { function SidebarTabs({ yjs, routeStats }: { yjs: YjsState; routeStats: ReturnType["routeStats"] }) { const { t } = useTranslation("planner"); const [tab, setTab] = useState<"waypoints" | "notes">("waypoints"); + const days = useDays(yjs); return (