From 657256eb0af4f32da899200346ebabf206a73a9e Mon Sep 17 00:00:00 2001 From: Ben Vinegar <2153+benvinegar@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:02:09 -0500 Subject: [PATCH] Upgrade latest Remix and enable all future flags (#130) --- app/__tests__/root.test.tsx | 9 +- app/root.tsx | 10 +- app/routes.ts | 3 + app/routes/__tests__/dashboard.test.tsx | 112 +++--- .../__tests__/resources.browser.test.tsx | 5 +- .../__tests__/resources.country.test.tsx | 5 +- .../__tests__/resources.device.test.tsx | 5 +- app/routes/__tests__/resources.paths.test.tsx | 3 +- .../__tests__/resources.referrer.test.tsx | 3 +- app/routes/__tests__/resources.stats.test.tsx | 6 +- .../__tests__/resources.timeseries.test.tsx | 2 +- app/routes/dashboard.tsx | 6 +- app/routes/resources.browser.tsx | 5 +- app/routes/resources.country.tsx | 5 +- app/routes/resources.device.tsx | 5 +- app/routes/resources.paths.tsx | 5 +- app/routes/resources.referrer.tsx | 5 +- app/routes/resources.stats.tsx | 5 +- app/routes/resources.timeseries.tsx | 5 +- package-lock.json | 335 +++++++++++------- package.json | 10 +- vite.config.ts | 3 + 22 files changed, 315 insertions(+), 237 deletions(-) create mode 100644 app/routes.ts diff --git a/app/__tests__/root.test.tsx b/app/__tests__/root.test.tsx index 157bba48..ef43606e 100644 --- a/app/__tests__/root.test.tsx +++ b/app/__tests__/root.test.tsx @@ -1,5 +1,4 @@ // @vitest-environment jsdom -import { json } from "@remix-run/node"; import { beforeAll, afterEach, describe, expect, test, vitest } from "vitest"; import "vitest-dom/extend-expect"; import { render, waitFor, screen, cleanup } from "@testing-library/react"; @@ -17,11 +16,11 @@ describe("Root", () => { test("renders without crashing", async () => { function loader() { - return json({ + return { version: "ABC123", origin: "http://example.com", url: "http://example.com/path", - }); + }; } const RemixStub = createRemixStub([ @@ -75,11 +74,11 @@ describe("Layout", () => { test("renders with provided route data", async () => { function loader() { - return json({ + return { version: "v1.2.3", origin: "test.counterscale.dev", url: "https://test.counterscale.dev/", - }); + }; } const RemixStub = createRemixStub([ diff --git a/app/root.tsx b/app/root.tsx index 3356dc44..fe91eff6 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,10 +1,6 @@ /// import styles from "./globals.css?url"; -import { - json, - LoaderFunctionArgs, - type LinksFunction, -} from "@remix-run/cloudflare"; +import { LoaderFunctionArgs, type LinksFunction } from "@remix-run/cloudflare"; import { Links, @@ -19,11 +15,11 @@ export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }]; export const loader = ({ context, request }: LoaderFunctionArgs) => { const url = new URL(request.url); - return json({ + return { version: context.cloudflare?.env?.CF_PAGES_COMMIT_SHA, origin: url.origin, url: request.url, - }); + }; }; export const Layout = ({ children = [] }: { children: React.ReactNode }) => { diff --git a/app/routes.ts b/app/routes.ts new file mode 100644 index 00000000..83892841 --- /dev/null +++ b/app/routes.ts @@ -0,0 +1,3 @@ +import { flatRoutes } from "@remix-run/fs-routes"; + +export default flatRoutes(); diff --git a/app/routes/__tests__/dashboard.test.tsx b/app/routes/__tests__/dashboard.test.tsx index 238ffd1b..fec9c803 100644 --- a/app/routes/__tests__/dashboard.test.tsx +++ b/app/routes/__tests__/dashboard.test.tsx @@ -1,5 +1,5 @@ // @vitest-environment jsdom -import { json, LoaderFunctionArgs } from "@remix-run/node"; +import { LoaderFunctionArgs } from "@remix-run/node"; import { vi, test, @@ -97,19 +97,24 @@ describe("Dashboard route", () => { }), ); - const response = await loader({ - ...getDefaultContext(), - // @ts-expect-error we don't need to provide all the properties of the request object - request: { - url: "http://localhost:3000/dashboard", // no site query param - }, - }); + try { + await loader({ + ...getDefaultContext(), + // @ts-expect-error we don't need to provide all the properties of the request object + request: { + url: "http://localhost:3000/dashboard", // no site query param + }, + }); + } catch (error) { + expect(error).toBeInstanceOf(Response); + const response = error as Response; - // expect redirect - expect(response.status).toBe(302); - expect(response.headers.get("Location")).toBe( - "http://localhost:3000/dashboard?site=test-siteid", - ); + // expect redirect + expect(response.status).toBe(302); + expect(response.headers.get("Location")).toBe( + "http://localhost:3000/dashboard?site=test-siteid", + ); + } }); test("redirects to ?site= if no siteId is provided via query string / no site data", async () => { @@ -120,19 +125,24 @@ describe("Dashboard route", () => { }), ); - const response = await loader({ - ...getDefaultContext(), - // @ts-expect-error we don't need to provide all the properties of the request object - request: { - url: "http://localhost:3000/dashboard", // no site query param - }, - }); + try { + await loader({ + ...getDefaultContext(), + // @ts-expect-error we don't need to provide all the properties of the request object + request: { + url: "http://localhost:3000/dashboard", // no site query param + }, + }); + } catch (error) { + expect(error).toBeInstanceOf(Response); + const response = error as Response; - // expect redirect - expect(response.status).toBe(302); - expect(response.headers.get("Location")).toBe( - "http://localhost:3000/dashboard?site=", - ); + // expect redirect + expect(response.status).toBe(302); + expect(response.headers.get("Location")).toBe( + "http://localhost:3000/dashboard?site=", + ); + } }); test("assembles data returned from CF API", async () => { @@ -153,7 +163,7 @@ describe("Dashboard route", () => { }, }); - const json = await response.json(); + const json = await response; expect(json).toEqual({ filters: {}, @@ -179,7 +189,7 @@ describe("Dashboard route", () => { }, }); - const json = await response.json(); + const json = await response; expect(json).toEqual({ filters: {}, @@ -193,11 +203,11 @@ describe("Dashboard route", () => { test("renders when no data", async () => { function loader() { - return json({ + return { siteId: "@unknown", sites: [], intervalType: "day", - }); + }; } const RemixStub = createRemixStub([ @@ -209,46 +219,46 @@ describe("Dashboard route", () => { { path: "/resources/timeseries", loader: () => { - return json({ chartData: [] }); + return { chartData: [] }; }, }, { path: "/resources/stats", loader: () => { - return json({ + return { views: 0, visitors: 0, - }); + }; }, }, { path: "/resources/paths", loader: () => { - return json({ countsByProperty: [] }); + return { countsByProperty: [] }; }, }, { path: "/resources/referrer", loader: () => { - return json({ countsByProperty: [] }); + return { countsByProperty: [] }; }, }, { path: "/resources/browser", loader: () => { - return json({ countsByProperty: [] }); + return { countsByProperty: [] }; }, }, { path: "/resources/country", loader: () => { - return json({ countsByProperty: [] }); + return { countsByProperty: [] }; }, }, { path: "/resources/device", loader: () => { - return json({ countsByProperty: [] }); + return { countsByProperty: [] }; }, }, ], @@ -288,7 +298,7 @@ describe("Dashboard route", () => { test("renders with valid data", async () => { function loader() { - return json({ ...defaultMockedLoaderJson }); + return { ...defaultMockedLoaderJson }; } const RemixStub = createRemixStub([ @@ -300,76 +310,76 @@ describe("Dashboard route", () => { { path: "/resources/stats", loader: () => { - return json({ + return { views: 2133, visitors: 33, - }); + }; }, }, { path: "/resources/timeseries", loader: () => { - return json({}); + return {}; }, }, { path: "/resources/paths", loader: () => { - return json({ + return { countsByProperty: [ ["/", 100], ["/about", 80], ["/contact", 60], ], - }); + }; }, }, { path: "/resources/referrer", loader: () => { - return json({ + return { countsByProperty: [ ["google.com", 100], ["facebook.com", 80], ["twitter.com", 60], ], - }); + }; }, }, { path: "/resources/browser", loader: () => { - return json({ + return { countsByProperty: [ ["Chrome", 100], ["Safari", 80], ["Firefox", 60], ], - }); + }; }, }, { path: "/resources/country", loader: () => { - return json({ + return { countsByProperty: [ ["United States", 100], ["Canada", 80], ["United Kingdom", 60], ], - }); + }; }, }, { path: "/resources/device", loader: () => { - return json({ + return { countsByProperty: [ ["Desktop", 100], ["Mobile", 80], ["Tablet", 60], ], - }); + }; }, }, ], diff --git a/app/routes/__tests__/resources.browser.test.tsx b/app/routes/__tests__/resources.browser.test.tsx index b15f570d..536ad4f3 100644 --- a/app/routes/__tests__/resources.browser.test.tsx +++ b/app/routes/__tests__/resources.browser.test.tsx @@ -43,10 +43,7 @@ describe("Resources/Browser route", () => { }, }); - // expect redirect - expect(response.status).toBe(200); - - const json = await response.json(); + const json = await response; expect(json).toEqual({ countsByProperty: [ ["Chrome", 5], diff --git a/app/routes/__tests__/resources.country.test.tsx b/app/routes/__tests__/resources.country.test.tsx index 064aa8d3..fb524be2 100644 --- a/app/routes/__tests__/resources.country.test.tsx +++ b/app/routes/__tests__/resources.country.test.tsx @@ -43,10 +43,7 @@ describe("Resources/Country route", () => { }, }); - // expect redirect - expect(response.status).toBe(200); - - const json = await response.json(); + const json = await response; expect(json).toEqual({ countsByProperty: [ [["CA", "Canada"], 5], diff --git a/app/routes/__tests__/resources.device.test.tsx b/app/routes/__tests__/resources.device.test.tsx index 5421b68d..b513db9e 100644 --- a/app/routes/__tests__/resources.device.test.tsx +++ b/app/routes/__tests__/resources.device.test.tsx @@ -43,10 +43,7 @@ describe("Resources/Device route", () => { }, }); - // expect redirect - expect(response.status).toBe(200); - - const json = await response.json(); + const json = await response; expect(json).toEqual({ countsByProperty: [ ["Android", 5], diff --git a/app/routes/__tests__/resources.paths.test.tsx b/app/routes/__tests__/resources.paths.test.tsx index f1d1a698..69b879d5 100644 --- a/app/routes/__tests__/resources.paths.test.tsx +++ b/app/routes/__tests__/resources.paths.test.tsx @@ -61,10 +61,9 @@ describe("Resources/Paths route", () => { }); // expect redirect - expect(response.status).toBe(200); expect(fetch).toHaveBeenCalledTimes(2); - const json = await response.json(); + const json = await response; expect(json).toEqual({ countsByProperty: [ diff --git a/app/routes/__tests__/resources.referrer.test.tsx b/app/routes/__tests__/resources.referrer.test.tsx index 0dc6bcd6..2892453f 100644 --- a/app/routes/__tests__/resources.referrer.test.tsx +++ b/app/routes/__tests__/resources.referrer.test.tsx @@ -62,10 +62,9 @@ describe("Resources/Referrer route", () => { }); // expect redirect - expect(response.status).toBe(200); expect(fetch).toHaveBeenCalledTimes(2); - const json = await response.json(); + const json = await response; expect(json).toEqual({ countsByProperty: [ ["/", 1, 6], diff --git a/app/routes/__tests__/resources.stats.test.tsx b/app/routes/__tests__/resources.stats.test.tsx index f0629e3e..6dfbc815 100644 --- a/app/routes/__tests__/resources.stats.test.tsx +++ b/app/routes/__tests__/resources.stats.test.tsx @@ -36,7 +36,7 @@ describe("resources.stats loader", () => { ); const response = await loader({ context, request } as any); - const data = await response.json(); + const data = await response; expect(mockGetCounts).toHaveBeenCalledWith( "test-site", @@ -75,7 +75,7 @@ describe("resources.stats loader", () => { ); const response = await loader({ context, request } as any); - const data = await response.json(); + const data = await response; expect(data).toEqual({ views: 1000, @@ -107,7 +107,7 @@ describe("resources.stats loader", () => { ); const response = await loader({ context, request } as any); - const data = await response.json(); + const data = await response; expect(data).toEqual({ views: 1000, diff --git a/app/routes/__tests__/resources.timeseries.test.tsx b/app/routes/__tests__/resources.timeseries.test.tsx index 2f91c410..9d0c7e84 100644 --- a/app/routes/__tests__/resources.timeseries.test.tsx +++ b/app/routes/__tests__/resources.timeseries.test.tsx @@ -58,7 +58,7 @@ describe("resources.timeseries loader", () => { request, }); - const data = await result.json(); + const data = await result; expect(data.chartData).toEqual([ { date: "2024-01-15T00:00:00Z", diff --git a/app/routes/dashboard.tsx b/app/routes/dashboard.tsx index c3f21eae..f9954105 100644 --- a/app/routes/dashboard.tsx +++ b/app/routes/dashboard.tsx @@ -7,7 +7,7 @@ import { } from "~/components/ui/select"; import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/cloudflare"; -import { json, redirect } from "@remix-run/cloudflare"; +import { redirect } from "@remix-run/cloudflare"; import { isRouteErrorResponse, useLoaderData, @@ -74,7 +74,7 @@ export const loader = async ({ context, request }: LoaderFunctionArgs) => { const redirectSite = sitesByHits[0]?.[0] || ""; const redirectUrl = new URL(request.url); redirectUrl.searchParams.set("site", redirectSite); - return redirect(redirectUrl.toString()); + throw redirect(redirectUrl.toString()); } const siteId = url.searchParams.get("site") || ""; @@ -111,7 +111,7 @@ export const loader = async ({ context, request }: LoaderFunctionArgs) => { throw new Error("Failed to fetch data from Analytics Engine"); } - return json(out); + return out; }; export default function Dashboard() { diff --git a/app/routes/resources.browser.tsx b/app/routes/resources.browser.tsx index b14be7bd..99911a7b 100644 --- a/app/routes/resources.browser.tsx +++ b/app/routes/resources.browser.tsx @@ -1,7 +1,6 @@ import { useFetcher } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getFiltersFromSearchParams, paramsFromUrl } from "~/lib/utils"; import PaginatedTableCard from "~/components/PaginatedTableCard"; @@ -15,7 +14,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const tz = url.searchParams.get("timezone") || "UTC"; const filters = getFiltersFromSearchParams(url.searchParams); - return json({ + return { countsByProperty: await analyticsEngine.getCountByBrowser( site, interval, @@ -24,7 +23,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { Number(page), ), page: Number(page), - }); + }; } export const BrowserCard = ({ diff --git a/app/routes/resources.country.tsx b/app/routes/resources.country.tsx index 94306361..985fc08a 100644 --- a/app/routes/resources.country.tsx +++ b/app/routes/resources.country.tsx @@ -1,6 +1,5 @@ import { useFetcher } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getFiltersFromSearchParams, paramsFromUrl } from "~/lib/utils"; import PaginatedTableCard from "~/components/PaginatedTableCard"; import { SearchFilters } from "~/lib/types"; @@ -45,10 +44,10 @@ export async function loader({ context, request }: LoaderFunctionArgs) { // in different browsers (see https://github.com/benvinegar/counterscale/issues/72) const countsByProperty = convertCountryCodesToNames(countsByCountry); - return json({ + return { countsByProperty, page: Number(page), - }); + }; } export const CountryCard = ({ diff --git a/app/routes/resources.device.tsx b/app/routes/resources.device.tsx index 21267b2a..86cc1747 100644 --- a/app/routes/resources.device.tsx +++ b/app/routes/resources.device.tsx @@ -1,7 +1,6 @@ import { useFetcher } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getFiltersFromSearchParams, paramsFromUrl } from "~/lib/utils"; import PaginatedTableCard from "~/components/PaginatedTableCard"; @@ -16,7 +15,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const tz = url.searchParams.get("timezone") || "UTC"; const filters = getFiltersFromSearchParams(url.searchParams); - return json({ + return { countsByProperty: await analyticsEngine.getCountByDevice( site, interval, @@ -25,7 +24,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { Number(page), ), page: Number(page), - }); + }; } export const DeviceCard = ({ diff --git a/app/routes/resources.paths.tsx b/app/routes/resources.paths.tsx index d6d1bacd..2a1bf009 100644 --- a/app/routes/resources.paths.tsx +++ b/app/routes/resources.paths.tsx @@ -1,7 +1,6 @@ import { useFetcher } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getFiltersFromSearchParams as getFiltersFromSearchParams, @@ -19,7 +18,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const tz = url.searchParams.get("timezone") || "UTC"; const filters = getFiltersFromSearchParams(url.searchParams); - return json({ + return { countsByProperty: await analyticsEngine.getCountByPath( site, interval, @@ -28,7 +27,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { Number(page), ), page: Number(page), - }); + }; } export const PathsCard = ({ diff --git a/app/routes/resources.referrer.tsx b/app/routes/resources.referrer.tsx index 950f97f5..6337718e 100644 --- a/app/routes/resources.referrer.tsx +++ b/app/routes/resources.referrer.tsx @@ -1,7 +1,6 @@ import { useFetcher } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import PaginatedTableCard from "~/components/PaginatedTableCard"; @@ -17,7 +16,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const tz = url.searchParams.get("timezone") || "UTC"; const filters = getFiltersFromSearchParams(url.searchParams); - return json({ + return { countsByProperty: await analyticsEngine.getCountByReferrer( site, interval, @@ -26,7 +25,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { Number(page), ), page: Number(page), - }); + }; } export const ReferrerCard = ({ diff --git a/app/routes/resources.stats.tsx b/app/routes/resources.stats.tsx index b24494a6..09794e5e 100644 --- a/app/routes/resources.stats.tsx +++ b/app/routes/resources.stats.tsx @@ -1,5 +1,4 @@ import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getDateTimeRange, getFiltersFromSearchParams, @@ -45,12 +44,12 @@ export async function loader({ context, request }: LoaderFunctionArgs) { const bounceRate = counts.visitors > 0 ? counts.bounces / counts.visitors : undefined; - return json({ + return { views: counts.views, visitors: counts.visitors, bounceRate: bounceRate, hasSufficientBounceData, - }); + }; } export const StatsCard = ({ diff --git a/app/routes/resources.timeseries.tsx b/app/routes/resources.timeseries.tsx index 8084982d..24de0aa7 100644 --- a/app/routes/resources.timeseries.tsx +++ b/app/routes/resources.timeseries.tsx @@ -1,5 +1,4 @@ import type { LoaderFunctionArgs } from "@remix-run/cloudflare"; -import { json } from "@remix-run/cloudflare"; import { getFiltersFromSearchParams, paramsFromUrl, @@ -51,10 +50,10 @@ export async function loader({ context, request }: LoaderFunctionArgs) { }); }); - return json({ + return { chartData: chartData, intervalType: intervalType, - }); + }; } export const TimeSeriesCard = ({ diff --git a/package-lock.json b/package-lock.json index ac0208c3..a9abc1ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "@cloudflare/kv-asset-handler": "^0.3.3", "@radix-ui/react-select": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", - "@remix-run/cloudflare": "^2.9.2", - "@remix-run/cloudflare-pages": "^2.9.2", - "@remix-run/react": "^2.9.2", + "@remix-run/cloudflare": "^2.15.1", + "@remix-run/cloudflare-pages": "^2.15.1", + "@remix-run/react": "^2.15.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "dayjs": "^1.11.11", @@ -30,7 +30,9 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20240620.0", "@remix-run/dev": "^2.9.2", - "@remix-run/testing": "^2.9.2", + "@remix-run/fs-routes": "^2.15.1", + "@remix-run/route-config": "^2.15.1", + "@remix-run/testing": "^2.15.1", "@testing-library/react": "^14.3.1", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", @@ -2056,13 +2058,12 @@ "license": "MIT" }, "node_modules/@remix-run/cloudflare": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/cloudflare/-/cloudflare-2.9.2.tgz", - "integrity": "sha512-gTITKNS4kEx3svcyXsobC5ODTZJ09P1+NMymr1fi6wLkLpUmLa1jLdPBrfo60b5acAmxPWRTtTtL+UJPHnjHYQ==", - "license": "MIT", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/cloudflare/-/cloudflare-2.15.1.tgz", + "integrity": "sha512-QQOyleNnI4bHjyxL75RBNmgIFTdMN7QgYWx6YhbSPCdopAw6PvuUwqKPExa8TZJQ/N4DuaiHUodTEYzdmETXkg==", "dependencies": { "@cloudflare/kv-asset-handler": "^0.1.3", - "@remix-run/server-runtime": "2.9.2" + "@remix-run/server-runtime": "2.15.1" }, "engines": { "node": ">=18.0.0" @@ -2078,12 +2079,11 @@ } }, "node_modules/@remix-run/cloudflare-pages": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/cloudflare-pages/-/cloudflare-pages-2.9.2.tgz", - "integrity": "sha512-ese5MIsSCfSsv4fnEaFWwDlxpVFfz4WU77egRmDdQVMcFoYXUIBTZ8BUQwxYmSthdwzutQJ9bwoXLqDYVXdW2A==", - "license": "MIT", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/cloudflare-pages/-/cloudflare-pages-2.15.1.tgz", + "integrity": "sha512-LP6pdeQ2UI1FPZccOdIFbbijMi3w5PnpE1ESrEpgD5QXZ8Y+S9aqixf7Acul8O9yuqQHMpCnSxqTYwtIIit+NQ==", "dependencies": { - "@remix-run/cloudflare": "2.9.2" + "@remix-run/cloudflare": "2.15.1" }, "engines": { "node": ">=18.0.0" @@ -2120,11 +2120,10 @@ } }, "node_modules/@remix-run/dev": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.9.2.tgz", - "integrity": "sha512-70dr9HH/mCHP5+uPoQXyS9+r73IL//IDPaFruIhK8kmmLPGAg5bGyFRz/xX6LTa98gPdAwZXxBy7frudeh2Z0Q==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.15.1.tgz", + "integrity": "sha512-vuAVNCW0TsjdoLrpXRFTDJzWut+cfOYw6HVrwdin3J/isfZ2ZyRUNo4kdK4TkmEXoRtTWLk1MG6LbeTAJlg11g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.21.8", "@babel/generator": "^7.21.5", @@ -2136,9 +2135,9 @@ "@babel/types": "^7.22.5", "@mdx-js/mdx": "^2.3.0", "@npmcli/package-json": "^4.0.1", - "@remix-run/node": "2.9.2", - "@remix-run/router": "1.16.1", - "@remix-run/server-runtime": "2.9.2", + "@remix-run/node": "2.15.1", + "@remix-run/router": "1.21.0", + "@remix-run/server-runtime": "2.15.1", "@types/mdx": "^2.0.5", "@vanilla-extract/integration": "^6.2.0", "arg": "^5.0.1", @@ -2152,7 +2151,7 @@ "esbuild-plugins-node-modules-polyfill": "^1.6.0", "execa": "5.1.1", "exit-hook": "2.2.1", - "express": "^4.17.1", + "express": "^4.20.0", "fs-extra": "^10.0.0", "get-port": "^5.1.1", "gunzip-maybe": "^1.4.2", @@ -2178,7 +2177,9 @@ "set-cookie-parser": "^2.6.0", "tar-fs": "^2.1.1", "tsconfig-paths": "^4.0.0", - "ws": "^7.4.5" + "valibot": "^0.41.0", + "vite-node": "^1.6.0", + "ws": "^7.5.10" }, "bin": { "remix": "dist/cli.js" @@ -2187,8 +2188,8 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@remix-run/react": "^2.9.2", - "@remix-run/serve": "^2.9.2", + "@remix-run/react": "^2.15.1", + "@remix-run/serve": "^2.15.1", "typescript": "^5.1.0", "vite": "^5.1.0", "wrangler": "^3.28.2" @@ -2223,20 +2224,60 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/@remix-run/dev/node_modules/vite-node": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "pathe": "^1.1.1", + "picocolors": "^1.0.0", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@remix-run/fs-routes": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/fs-routes/-/fs-routes-2.15.1.tgz", + "integrity": "sha512-LIbuAusCKzmVejif4vHQ0EFCLD7kLnPOm/BeOTFpuPPe7Ei8pbS3ByNP+adInCEx5dYWVYiFklP2H3hb4N+pxg==", + "dev": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@remix-run/dev": "^2.15.1", + "@remix-run/route-config": "^2.15.1", + "typescript": "^5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@remix-run/node": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.9.2.tgz", - "integrity": "sha512-2Mt2107pfelz4T+ziDBef3P4A7kgPqCDshnEYCVGxInivJ3HHwAKUcb7MhGa8uMMMA6LMWxbAPYNHPzC3iKv2A==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.15.1.tgz", + "integrity": "sha512-23xWN3/yOohNUr27KS7hEcDMbtufMkniXfXkcLx8Dz2wUVNfJYGpICjeV48Ue/INtpiUCCzOYwkL9VRjIMEJbA==", "dev": true, - "license": "MIT", "dependencies": { - "@remix-run/server-runtime": "2.9.2", + "@remix-run/server-runtime": "2.15.1", "@remix-run/web-fetch": "^4.4.2", "@web3-storage/multipart-parser": "^1.0.0", "cookie-signature": "^1.1.0", "source-map-support": "^0.5.21", "stream-slice": "^0.1.2", - "undici": "^6.10.1" + "undici": "^6.11.1" }, "engines": { "node": ">=18.0.0" @@ -2251,26 +2292,24 @@ } }, "node_modules/@remix-run/node/node_modules/undici": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.2.tgz", - "integrity": "sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", "dev": true, - "license": "MIT", "engines": { "node": ">=18.17" } }, "node_modules/@remix-run/react": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.9.2.tgz", - "integrity": "sha512-DcZDzm68MBxGn8hjf/VsuUpjxDYZ8VOOH79P1zWu4hb3hBr90WV1Sa/gIAFUEGpOCcSQ0EG/ci8MaFxcAaPz2Q==", - "license": "MIT", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/react/-/react-2.15.1.tgz", + "integrity": "sha512-h0BVUeg87vt3FKbYfoF7Ln56MM3O8rvGLDKYOuPY0OgNlJVaQKQzWVX+mnlmzysX4hF7WnOPMw1q38Ow7N9wKg==", "dependencies": { - "@remix-run/router": "1.16.1", - "@remix-run/server-runtime": "2.9.2", - "react-router": "6.23.1", - "react-router-dom": "6.23.1", - "turbo-stream": "^2.0.0" + "@remix-run/router": "1.21.0", + "@remix-run/server-runtime": "2.15.1", + "react-router": "6.28.0", + "react-router-dom": "6.28.0", + "turbo-stream": "2.4.0" }, "engines": { "node": ">=18.0.0" @@ -2286,28 +2325,47 @@ } } }, + "node_modules/@remix-run/route-config": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/route-config/-/route-config-2.15.1.tgz", + "integrity": "sha512-xO4XLj9leghzg8zj3UqLd/Hl4Wo8P/Jrp2TapNNRKpWul9sZiTJWSnK8DX6Dv8cd0AEfDCiLCvLNCRBwLBcDlQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@remix-run/dev": "^2.15.1", + "typescript": "^5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@remix-run/router": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", - "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", - "license": "MIT", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", + "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", "engines": { "node": ">=14.0.0" } }, "node_modules/@remix-run/server-runtime": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.9.2.tgz", - "integrity": "sha512-dX37FEeMVVg7KUbpRhX4hD0nUY0Sscz/qAjU4lYCdd6IzwJGariTmz+bQTXKCjploZuXj09OQZHSOS/ydkUVDA==", - "license": "MIT", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.15.1.tgz", + "integrity": "sha512-TDM3rzax//N2F5uNMV5pNTWAop8cYul6hteDu+Xmfwys/eRGlbzEf7YJzyRj6Kcsg2TFVHI7+xEPItGAVm1hHA==", "dependencies": { - "@remix-run/router": "1.16.1", + "@remix-run/router": "1.21.0", "@types/cookie": "^0.6.0", "@web3-storage/multipart-parser": "^1.0.0", "cookie": "^0.6.0", "set-cookie-parser": "^2.4.8", "source-map": "^0.7.3", - "turbo-stream": "^2.0.0" + "turbo-stream": "2.4.0" }, "engines": { "node": ">=18.0.0" @@ -2325,22 +2383,20 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/@remix-run/testing": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/@remix-run/testing/-/testing-2.9.2.tgz", - "integrity": "sha512-zJz/D1zCMnPr7EVTRqOqUR9DkJXRBOgsyniJu+zM5yO3r2rULaYy+D7d9AlxMuUDxprpgRfk734BlZh4lFEdrQ==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/@remix-run/testing/-/testing-2.15.1.tgz", + "integrity": "sha512-93snHVXbS3zhl/k76SlBfzxb3BxLjKolNHnS6/Gn7SU9lP6ur2m5FA91cT/VTvNa2NmJrIfB4rO5pe+NuBdLcA==", "dev": true, - "license": "MIT", "dependencies": { - "@remix-run/node": "2.9.2", - "@remix-run/react": "2.9.2", - "@remix-run/router": "1.16.1", - "react-router-dom": "6.23.1" + "@remix-run/node": "2.15.1", + "@remix-run/react": "2.15.1", + "@remix-run/router": "1.21.0", + "react-router-dom": "6.28.0" }, "engines": { "node": ">=18.0.0" @@ -4461,9 +4517,9 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -4474,7 +4530,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -5656,9 +5712,9 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" @@ -6696,37 +6752,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -6735,12 +6791,16 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "engines": { "node": ">= 0.6" @@ -6860,13 +6920,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -9005,10 +9065,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -10587,9 +10650,9 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "node_modules/path-type": { @@ -11077,12 +11140,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -11227,12 +11290,11 @@ } }, "node_modules/react-router": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", - "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", - "license": "MIT", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", + "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", "dependencies": { - "@remix-run/router": "1.16.1" + "@remix-run/router": "1.21.0" }, "engines": { "node": ">=14.0.0" @@ -11242,13 +11304,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.23.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", - "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", - "license": "MIT", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", + "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", "dependencies": { - "@remix-run/router": "1.16.1", - "react-router": "6.23.1" + "@remix-run/router": "1.21.0", + "react-router": "6.28.0" }, "engines": { "node": ">=14.0.0" @@ -11942,9 +12003,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -11980,6 +12041,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -11993,15 +12063,15 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -13038,10 +13108,9 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/turbo-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.2.0.tgz", - "integrity": "sha512-FKFg7A0To1VU4CH9YmSMON5QphK0BXjSoiC7D9yMh+mEEbXLUP9qJ4hEt1qcjKtzncs1OpcnjZO8NgrlVbZH+g==", - "license": "ISC" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==" }, "node_modules/type-check": { "version": "0.4.0", @@ -13567,6 +13636,20 @@ "node": ">=8" } }, + "node_modules/valibot": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.41.0.tgz", + "integrity": "sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng==", + "dev": true, + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -15532,9 +15615,9 @@ "dev": true }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "engines": { "node": ">=8.3.0" diff --git a/package.json b/package.json index d92eb49d..62f08adb 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "@cloudflare/kv-asset-handler": "^0.3.3", "@radix-ui/react-select": "^2.1.0", "@radix-ui/react-slot": "^1.1.0", - "@remix-run/cloudflare": "^2.9.2", - "@remix-run/cloudflare-pages": "^2.9.2", - "@remix-run/react": "^2.9.2", + "@remix-run/cloudflare": "^2.15.1", + "@remix-run/cloudflare-pages": "^2.15.1", + "@remix-run/react": "^2.15.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "dayjs": "^1.11.11", @@ -42,7 +42,9 @@ "devDependencies": { "@cloudflare/workers-types": "^4.20240620.0", "@remix-run/dev": "^2.9.2", - "@remix-run/testing": "^2.9.2", + "@remix-run/fs-routes": "^2.15.1", + "@remix-run/route-config": "^2.15.1", + "@remix-run/testing": "^2.15.1", "@testing-library/react": "^14.3.1", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", diff --git a/vite.config.ts b/vite.config.ts index 70982d49..b7246ed4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -21,6 +21,9 @@ export default defineConfig({ v3_fetcherPersist: true, v3_relativeSplatPath: true, v3_throwAbortReason: true, + v3_routeConfig: true, + v3_lazyRouteDiscovery: true, + v3_singleFetch: true, }, }), tsconfigPaths(),