From edef68bf5c1c06029c9a996bf0a296203319e973 Mon Sep 17 00:00:00 2001 From: Carlos Ricardo Ziegler <38855507+CarlosZiegler@users.noreply.github.com> Date: Thu, 25 Jun 2026 07:52:35 +0200 Subject: [PATCH 1/2] feat: add Tanstack start support --- .changeset/tanstack-start-support.md | 25 + examples/tanstack-start-example/.env.example | 3 + examples/tanstack-start-example/.gitignore | 9 + examples/tanstack-start-example/README.md | 53 + examples/tanstack-start-example/package.json | 27 + examples/tanstack-start-example/src/flags.ts | 62 + .../src/precomputed-flags.ts | 20 + .../tanstack-start-example/src/router.tsx | 16 + .../src/routes/[.]well-known/vercel/flags.ts | 15 + .../src/routes/__root.tsx | 45 + .../src/routes/dashboard.tsx | 35 + .../src/routes/index.tsx | 32 + .../src/routes/marketing.$code.tsx | 42 + .../src/routes/marketing.tsx | 19 + examples/tanstack-start-example/tsconfig.json | 18 + .../tanstack-start-example/vite.config.ts | 7 + packages/flags/README.md | 54 +- packages/flags/package.json | 17 +- packages/flags/src/tanstack-start/env.ts | 14 + .../tanstack-start/get-request-dedupe.test.ts | 42 + .../flags/src/tanstack-start/get-request.ts | 39 + .../flags/src/tanstack-start/index.test.ts | 154 ++ packages/flags/src/tanstack-start/index.ts | 420 +++++ .../flags/src/tanstack-start/precompute.ts | 154 ++ packages/flags/src/tanstack-start/types.ts | 40 + packages/flags/tsup.config.js | 1 + pnpm-lock.yaml | 1444 +++++++++++++---- 27 files changed, 2498 insertions(+), 309 deletions(-) create mode 100644 .changeset/tanstack-start-support.md create mode 100644 examples/tanstack-start-example/.env.example create mode 100644 examples/tanstack-start-example/.gitignore create mode 100644 examples/tanstack-start-example/README.md create mode 100644 examples/tanstack-start-example/package.json create mode 100644 examples/tanstack-start-example/src/flags.ts create mode 100644 examples/tanstack-start-example/src/precomputed-flags.ts create mode 100644 examples/tanstack-start-example/src/router.tsx create mode 100644 examples/tanstack-start-example/src/routes/[.]well-known/vercel/flags.ts create mode 100644 examples/tanstack-start-example/src/routes/__root.tsx create mode 100644 examples/tanstack-start-example/src/routes/dashboard.tsx create mode 100644 examples/tanstack-start-example/src/routes/index.tsx create mode 100644 examples/tanstack-start-example/src/routes/marketing.$code.tsx create mode 100644 examples/tanstack-start-example/src/routes/marketing.tsx create mode 100644 examples/tanstack-start-example/tsconfig.json create mode 100644 examples/tanstack-start-example/vite.config.ts create mode 100644 packages/flags/src/tanstack-start/env.ts create mode 100644 packages/flags/src/tanstack-start/get-request-dedupe.test.ts create mode 100644 packages/flags/src/tanstack-start/get-request.ts create mode 100644 packages/flags/src/tanstack-start/index.test.ts create mode 100644 packages/flags/src/tanstack-start/index.ts create mode 100644 packages/flags/src/tanstack-start/precompute.ts create mode 100644 packages/flags/src/tanstack-start/types.ts diff --git a/.changeset/tanstack-start-support.md b/.changeset/tanstack-start-support.md new file mode 100644 index 00000000..91c292de --- /dev/null +++ b/.changeset/tanstack-start-support.md @@ -0,0 +1,25 @@ +--- +'flags': minor +--- + +Add TanStack Start support via a new `flags/tanstack-start` entrypoint + +The Flags SDK now ships a first-class adapter for [TanStack Start](https://tanstack.com/start/latest), following the same patterns as the Next.js and SvelteKit entrypoints. + +```ts +// src/flags.ts +import { flag } from 'flags/tanstack-start'; + +export const exampleFlag = flag({ + key: 'example-flag', + decide: () => true, +}); +``` + +Flags can be evaluated with no arguments inside a route loader, server function, +or server route — the request is resolved automatically through TanStack Start's +`getRequest()`. You may also pass a `Request` explicitly (e.g. `flag(request)`). + +The entrypoint exports `flag`, `getProviderData`, `createFlagsDiscoveryEndpoint`, +`precompute`, `generatePermutations`, and the `encrypt*`/`decrypt*` helpers, plus +support for Vercel Toolbar overrides via the `vercel-flag-overrides` cookie. diff --git a/examples/tanstack-start-example/.env.example b/examples/tanstack-start-example/.env.example new file mode 100644 index 00000000..494e3c0a --- /dev/null +++ b/examples/tanstack-start-example/.env.example @@ -0,0 +1,3 @@ +# Generate a value with: +# node -e "console.log(crypto.randomBytes(32).toString('base64url'))" +FLAGS_SECRET=RtZ3kUODKCMC0CYDgUNi3nfh1lceNG_pgaUC0R5pdBg diff --git a/examples/tanstack-start-example/.gitignore b/examples/tanstack-start-example/.gitignore new file mode 100644 index 00000000..b4357501 --- /dev/null +++ b/examples/tanstack-start-example/.gitignore @@ -0,0 +1,9 @@ +node_modules +dist +.output +.nitro +.tanstack +.vinxi +# Generated by the TanStack Router plugin +src/routeTree.gen.ts +.env diff --git a/examples/tanstack-start-example/README.md b/examples/tanstack-start-example/README.md new file mode 100644 index 00000000..0da86ce8 --- /dev/null +++ b/examples/tanstack-start-example/README.md @@ -0,0 +1,53 @@ +# Flags SDK + TanStack Start example + +A minimal [TanStack Start](https://tanstack.com/start/latest) app showing how to +use the Flags SDK through the `flags/tanstack-start` entrypoint. + +## What it demonstrates + +- **`src/flags.ts`** — declaring flags with `flag()` from `flags/tanstack-start`, + including a cookie-driven boolean flag and two precomputed A/B flags with an + `identify` function. +- **`src/routes/dashboard.tsx`** — evaluating a flag inside a route loader. Flags + run on the server, so the evaluation is wrapped in a `createServerFn()` server + function (this keeps it working during client-side navigation too). +- **`src/routes/marketing.tsx` + `marketing.$code.tsx`** — precomputing flags into + a short, signed code that is encoded into the URL, then reading the values back + cheaply with `flag(code, marketingFlags)`. +- **`src/routes/[.]well-known/vercel/flags.ts`** — the flags discovery endpoint for + the Vercel Toolbar, built with `createFlagsDiscoveryEndpoint`. + +## Running it + +```sh +pnpm install +pnpm dev +``` + +Then open http://localhost:3000. + +## Setup notes + +A `FLAGS_SECRET` is required. One is provided in `.env` for local development — +generate your own for real deployments: + +```sh +node -e "console.log(crypto.randomBytes(32).toString('base64url'))" +``` + +### Evaluating flags + +Inside a route loader, server function, or server route you can call a flag with +no arguments — the request is resolved automatically via TanStack Start's +`getRequest()`: + +```ts +const value = await showNewDashboard(); +``` + +You can also pass a `Request` explicitly when evaluating outside of a request +context: + +```ts +const value = await showNewDashboard(request); +``` diff --git a/examples/tanstack-start-example/package.json b/examples/tanstack-start-example/package.json new file mode 100644 index 00000000..65ec50a9 --- /dev/null +++ b/examples/tanstack-start-example/package.json @@ -0,0 +1,27 @@ +{ + "name": "tanstack-start-example", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "dev": "vite dev --port 3000", + "build": "vite build", + "start": "node .output/server/index.mjs", + "check": "biome check", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@tanstack/react-router": "^1.170.0", + "@tanstack/react-start": "^1.168.0", + "flags": "workspace:*", + "react": "^19", + "react-dom": "^19" + }, + "devDependencies": { + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "@vitejs/plugin-react": "^5.0.0", + "typescript": "5.6.3", + "vite": "^7.0.0" + } +} diff --git a/examples/tanstack-start-example/src/flags.ts b/examples/tanstack-start-example/src/flags.ts new file mode 100644 index 00000000..f12b8a4f --- /dev/null +++ b/examples/tanstack-start-example/src/flags.ts @@ -0,0 +1,62 @@ +import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags'; +import { flag } from 'flags/tanstack-start'; + +/** + * A simple boolean flag driven by a cookie. + * + * Toggle it by setting a `showNewDashboard=true` cookie (e.g. via the Vercel + * Toolbar overrides, or `document.cookie = 'showNewDashboard=true'`). + */ +export const showNewDashboard = flag({ + key: 'showNewDashboard', + description: 'Show the new dashboard', + options: [{ value: true }, { value: false }], + decide({ cookies }) { + return cookies.get('showNewDashboard')?.value === 'true'; + }, +}); + +interface Entities { + visitorId?: string; +} + +/** + * Establishes the entities the marketing flags decide on. In a real app the + * `visitorId` would be set by middleware; here we fall back to a stable demo id + * so the example works without any extra setup. + */ +function identify({ + cookies, + headers, +}: { + cookies: ReadonlyRequestCookies; + headers: ReadonlyHeaders; +}): Entities { + const visitorId = + cookies.get('visitorId')?.value ?? + headers.get('x-visitor-id') ?? + 'demo-visitor'; + + return { visitorId }; +} + +export const firstMarketingABTest = flag({ + key: 'firstMarketingABTest', + description: 'Example of a precomputed flag', + identify, + decide({ entities }) { + if (!entities?.visitorId) return false; + // Any deterministic function of the visitorId works here. + return /^[a-m0-4]/i.test(entities.visitorId); + }, +}); + +export const secondMarketingABTest = flag({ + key: 'secondMarketingABTest', + description: 'Example of a precomputed flag', + identify, + decide({ entities }) { + if (!entities?.visitorId) return false; + return /[a-m0-4]$/i.test(entities.visitorId); + }, +}); diff --git a/examples/tanstack-start-example/src/precomputed-flags.ts b/examples/tanstack-start-example/src/precomputed-flags.ts new file mode 100644 index 00000000..0f34d466 --- /dev/null +++ b/examples/tanstack-start-example/src/precomputed-flags.ts @@ -0,0 +1,20 @@ +import { precompute } from 'flags/tanstack-start'; +import { firstMarketingABTest, secondMarketingABTest } from './flags'; + +/** + * The flags that are precomputed for the marketing pages. The order matters: + * the same array must be passed to `precompute()` and when reading values back + * with `flag(code, marketingFlags)`. + */ +export const marketingFlags = [ + firstMarketingABTest, + secondMarketingABTest, +] as const; + +/** + * Precompute the marketing flags into a short, signed code that can be used as + * a route parameter (`/marketing/$code`). + */ +export async function precomputeMarketing(request: Request): Promise { + return precompute(marketingFlags, request); +} diff --git a/examples/tanstack-start-example/src/router.tsx b/examples/tanstack-start-example/src/router.tsx new file mode 100644 index 00000000..217fc3c1 --- /dev/null +++ b/examples/tanstack-start-example/src/router.tsx @@ -0,0 +1,16 @@ +import { createRouter as createTanstackRouter } from '@tanstack/react-router'; +import { routeTree } from './routeTree.gen'; + +export function getRouter() { + return createTanstackRouter({ + routeTree, + scrollRestoration: true, + defaultPreload: 'intent', + }); +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType; + } +} diff --git a/examples/tanstack-start-example/src/routes/[.]well-known/vercel/flags.ts b/examples/tanstack-start-example/src/routes/[.]well-known/vercel/flags.ts new file mode 100644 index 00000000..af637329 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/[.]well-known/vercel/flags.ts @@ -0,0 +1,15 @@ +// The `[.]` escapes the leading dot so the directory resolves to +// `/.well-known/vercel/flags` (folders starting with a real dot are ignored by +// the bundler). +import { createFileRoute } from '@tanstack/react-router'; +import { + createFlagsDiscoveryEndpoint, + getProviderData, +} from 'flags/tanstack-start'; +import * as flags from '../../../flags'; + +const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + +export const Route = createFileRoute('/.well-known/vercel/flags')({ + server: { handlers: { GET: handler } }, +}); diff --git a/examples/tanstack-start-example/src/routes/__root.tsx b/examples/tanstack-start-example/src/routes/__root.tsx new file mode 100644 index 00000000..86ff0150 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/__root.tsx @@ -0,0 +1,45 @@ +import { + createRootRoute, + HeadContent, + Link, + Outlet, + Scripts, +} from '@tanstack/react-router'; + +export const Route = createRootRoute({ + head: () => ({ + meta: [ + { charSet: 'utf-8' }, + { name: 'viewport', content: 'width=device-width, initial-scale=1' }, + { title: 'Flags SDK + TanStack Start' }, + ], + }), + component: RootComponent, +}); + +function RootComponent() { + return ( + + + + + + + + + + + ); +} diff --git a/examples/tanstack-start-example/src/routes/dashboard.tsx b/examples/tanstack-start-example/src/routes/dashboard.tsx new file mode 100644 index 00000000..bfa7c605 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/dashboard.tsx @@ -0,0 +1,35 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { showNewDashboard } from '../flags'; + +// Flags are evaluated on the server, so we wrap the evaluation in a server +// function. This keeps it working during client-side navigation too — the +// loader calls the server function instead of evaluating the flag directly. +const getDashboardFlags = createServerFn().handler(async () => { + return { showNewDashboard: await showNewDashboard() }; +}); + +export const Route = createFileRoute('/dashboard')({ + loader: () => getDashboardFlags(), + component: Dashboard, +}); + +function Dashboard() { + const { showNewDashboard } = Route.useLoaderData(); + + return ( +
+

Dashboard

+ {showNewDashboard ? ( +

✨ You are seeing the new dashboard.

+ ) : ( +

You are seeing the old dashboard.

+ )} +

+ Toggle it by setting a cookie, then reload: +
+ document.cookie = 'showNewDashboard=true' +

+
+ ); +} diff --git a/examples/tanstack-start-example/src/routes/index.tsx b/examples/tanstack-start-example/src/routes/index.tsx new file mode 100644 index 00000000..57452a74 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/index.tsx @@ -0,0 +1,32 @@ +import { createFileRoute, Link } from '@tanstack/react-router'; + +export const Route = createFileRoute('/')({ + component: Home, +}); + +function Home() { + return ( +
+

Flags SDK + TanStack Start

+

+ This example shows how to use flags/tanstack-start in a + TanStack Start app. +

+
    +
  • + Dashboard — a boolean flag evaluated in a + route loader via a server function. +
  • +
  • + Marketing A/B — precomputed flags encoded + into the URL. +
  • +
  • + /.well-known/vercel/flags — + the flags discovery endpoint (returns 401 without a valid + Authorization header). +
  • +
+
+ ); +} diff --git a/examples/tanstack-start-example/src/routes/marketing.$code.tsx b/examples/tanstack-start-example/src/routes/marketing.$code.tsx new file mode 100644 index 00000000..f3256250 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/marketing.$code.tsx @@ -0,0 +1,42 @@ +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { firstMarketingABTest, secondMarketingABTest } from '../flags'; +import { marketingFlags } from '../precomputed-flags'; + +// Reading precomputed flags is cheap: `flag(code, marketingFlags)` decodes the +// value from the signed code without re-running `decide`. +const getMarketingFlags = createServerFn() + .validator((code: string) => code) + .handler(async ({ data: code }) => { + return { + first: await firstMarketingABTest(code, marketingFlags), + second: await secondMarketingABTest(code, marketingFlags), + }; + }); + +export const Route = createFileRoute('/marketing/$code')({ + loader: ({ params }) => getMarketingFlags({ data: params.code }), + component: MarketingPage, +}); + +function MarketingPage() { + const { first, second } = Route.useLoaderData(); + const { code } = Route.useParams(); + + return ( +
+

Marketing A/B Test

+

+ Precomputed code: {code} +

+
    +
  • + firstMarketingABTest: {String(first)} +
  • +
  • + secondMarketingABTest: {String(second)} +
  • +
+
+ ); +} diff --git a/examples/tanstack-start-example/src/routes/marketing.tsx b/examples/tanstack-start-example/src/routes/marketing.tsx new file mode 100644 index 00000000..5ba875f1 --- /dev/null +++ b/examples/tanstack-start-example/src/routes/marketing.tsx @@ -0,0 +1,19 @@ +import { createFileRoute, redirect } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { getRequest } from '@tanstack/react-start/server'; +import { precomputeMarketing } from '../precomputed-flags'; + +// Precompute the marketing flags into a signed code, then redirect to the +// precomputed route. The same code can be cached/served statically. +const getMarketingCode = createServerFn().handler(async () => { + const request = getRequest(); + return precomputeMarketing(request); +}); + +export const Route = createFileRoute('/marketing')({ + loader: async () => { + const code = await getMarketingCode(); + throw redirect({ to: '/marketing/$code', params: { code } }); + }, + component: () => null, +}); diff --git a/examples/tanstack-start-example/tsconfig.json b/examples/tanstack-start-example/tsconfig.json new file mode 100644 index 00000000..19ee6b7b --- /dev/null +++ b/examples/tanstack-start-example/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "jsx": "react-jsx", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "isolatedModules": true, + "resolveJsonModule": true, + "types": ["vite/client"] + }, + "include": ["src", "vite.config.ts"] +} diff --git a/examples/tanstack-start-example/vite.config.ts b/examples/tanstack-start-example/vite.config.ts new file mode 100644 index 00000000..1a32c096 --- /dev/null +++ b/examples/tanstack-start-example/vite.config.ts @@ -0,0 +1,7 @@ +import { tanstackStart } from '@tanstack/react-start/plugin/vite'; +import viteReact from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [tanstackStart(), viteReact()], +}); diff --git a/packages/flags/README.md b/packages/flags/README.md index 3eee48be..118f1dc5 100644 --- a/packages/flags/README.md +++ b/packages/flags/README.md @@ -2,9 +2,9 @@ # Flags SDK -The feature flags toolkit for Next.js and SvelteKit. +The feature flags toolkit for Next.js, SvelteKit and TanStack Start. -From the creators of Next.js, the Flags SDK is a free open-source library that gives you the tools you need to use feature flags in Next.js and SvelteKit applications. +From the creators of Next.js, the Flags SDK is a free open-source library that gives you the tools you need to use feature flags in Next.js, SvelteKit and TanStack Start applications. - Works with any flag provider, custom setups or no flag provider at all - Compatible with App Router, Pages Router, and Routing Middleware @@ -72,6 +72,56 @@ export default async function Page() { Feature Flags can also be called in Routing Middleware and API Routes. +### TanStack Start + +Import `flag` from `flags/tanstack-start` and evaluate flags inside a route +loader, server function, or server route — the request is resolved automatically: + +```ts +// src/flags.ts +import { flag } from "flags/tanstack-start"; + +export const exampleFlag = flag({ + key: "example-flag", + decide: () => true, +}); +``` + +```tsx +// src/routes/index.tsx +import { createFileRoute } from "@tanstack/react-router"; +import { exampleFlag } from "../flags"; + +export const Route = createFileRoute("/")({ + loader: async () => ({ example: await exampleFlag() }), + component: Home, +}); + +function Home() { + const { example } = Route.useLoaderData(); + return
{example ? "Flag is on" : "Flag is off"}
; +} +``` + +You can expose the flags discovery endpoint for the Vercel Toolbar with a server +route: + +```ts +// src/routes/.well-known/vercel/flags.ts +import { createFileRoute } from "@tanstack/react-router"; +import { + createFlagsDiscoveryEndpoint, + getProviderData, +} from "flags/tanstack-start"; +import * as flags from "../../../flags"; + +const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + +export const Route = createFileRoute("/.well-known/vercel/flags/")({ + server: { handlers: { GET: handler } }, +}); +``` + ## Adapters The Flags SDK has adapters for popular feature flag providers including LaunchDarkly, Optimizely, and Statsig. diff --git a/packages/flags/package.json b/packages/flags/package.json index 274d523d..e1377e87 100644 --- a/packages/flags/package.json +++ b/packages/flags/package.json @@ -1,14 +1,15 @@ { "name": "flags", "version": "4.2.0", - "description": "Flags SDK by Vercel - The feature flags toolkit for Next.js and SvelteKit", + "description": "Flags SDK by Vercel - The feature flags toolkit for Next.js, SvelteKit and TanStack Start", "keywords": [ "feature flags", "Next.js", "react", "toolbar", "overrides", - "SvelteKit" + "SvelteKit", + "TanStack Start" ], "author": "Dominik Ferber ", "homepage": "https://flags-sdk.dev", @@ -43,6 +44,10 @@ "svelte": "./dist/sveltekit.js", "import": "./dist/sveltekit.js", "require": "./dist/sveltekit.cjs" + }, + "./tanstack-start": { + "import": "./dist/tanstack-start.js", + "require": "./dist/tanstack-start.cjs" } }, "typesVersions": { @@ -62,6 +67,10 @@ "sveltekit": [ "dist/sveltekit.d.ts", "dist/sveltekit.d.cts" + ], + "tanstack-start": [ + "dist/tanstack-start.d.ts", + "dist/tanstack-start.d.cts" ] } }, @@ -98,6 +107,7 @@ "peerDependencies": { "@opentelemetry/api": "^1.7.0", "@sveltejs/kit": "*", + "@tanstack/react-start": "*", "next": "*", "react": "*", "react-dom": "*" @@ -109,6 +119,9 @@ "@sveltejs/kit": { "optional": true }, + "@tanstack/react-start": { + "optional": true + }, "next": { "optional": true }, diff --git a/packages/flags/src/tanstack-start/env.ts b/packages/flags/src/tanstack-start/env.ts new file mode 100644 index 00000000..dd5c175c --- /dev/null +++ b/packages/flags/src/tanstack-start/env.ts @@ -0,0 +1,14 @@ +// TanStack Start runs on the server through Nitro/Vite, so the secret is +// available via `process.env`. We keep this in its own module to mirror the +// other framework adapters and to make it easy to swap out later. +export async function tryGetSecret(secret?: string): Promise { + secret = secret || process.env.FLAGS_SECRET; + + if (!secret) { + throw new Error( + 'flags: No secret provided. Set an environment variable FLAGS_SECRET or provide a secret to the function.', + ); + } + + return secret; +} diff --git a/packages/flags/src/tanstack-start/get-request-dedupe.test.ts b/packages/flags/src/tanstack-start/get-request-dedupe.test.ts new file mode 100644 index 00000000..31da4719 --- /dev/null +++ b/packages/flags/src/tanstack-start/get-request-dedupe.test.ts @@ -0,0 +1,42 @@ +import { beforeAll, describe, expect, it, vi } from 'vitest'; + +// Issue #3: when a flag is evaluated with no argument, it resolves the request +// through `getStartRequest()`. The per-request dedupe is keyed on that Request +// instance, so it only works if `getStartRequest()` returns a STABLE instance +// within a single request. Here we mock it to return one shared Request and +// assert that two no-arg evaluations share a single `decide` call. +// +// NOTE: this proves the adapter dedupes correctly given a stable request. In +// production, confirm TanStack Start's `getRequest()` returns the same Request +// instance across calls within a request (it should, via the server request +// context); if it ever returns a fresh wrapper, switch the context keying to an +// AsyncLocalStorage-based store instead of the Request instance. +const sharedRequest = new Request('http://localhost/shared'); +vi.mock('./get-request', () => ({ + getStartRequest: async () => sharedRequest, +})); + +import { flag } from '.'; + +beforeAll(() => { + process.env.FLAGS_SECRET = 'a'.repeat(43); +}); + +describe('getStartRequest dedupe', () => { + it('deduplicates decide across no-arg calls sharing one request', async () => { + let calls = 0; + const f = flag({ key: 'gr-dedupe', decide: () => ++calls }); + const [a, b] = await Promise.all([f(), f()]); + expect(a).toBe(b); + expect(calls).toBe(1); + }); + + it('reuses the cached value on a later no-arg call too', async () => { + let calls = 0; + const f = flag({ key: 'gr-dedupe-2', decide: () => ++calls }); + const first = await f(); + const second = await f(); + expect(first).toBe(second); + expect(calls).toBe(1); + }); +}); diff --git a/packages/flags/src/tanstack-start/get-request.ts b/packages/flags/src/tanstack-start/get-request.ts new file mode 100644 index 00000000..a8c450cb --- /dev/null +++ b/packages/flags/src/tanstack-start/get-request.ts @@ -0,0 +1,39 @@ +/** + * Resolves the incoming request using TanStack Start's server utilities. + * + * The import is done dynamically so that this entrypoint doesn't hard-depend on + * `@tanstack/react-start` being resolvable in environments that only use the + * precompute or crypto helpers (e.g. when running inside Routing Middleware). + */ +export async function getStartRequest(): Promise { + let getRequest: (() => Request | undefined) | undefined; + + try { + const mod = (await import('@tanstack/react-start/server')) as Record< + string, + unknown + >; + // `getRequest` is the current API; `getWebRequest` is kept as a fallback for + // older TanStack Start versions. + getRequest = (mod.getRequest ?? mod.getWebRequest) as + | (() => Request | undefined) + | undefined; + } catch { + // ignore, handled below + } + + if (typeof getRequest !== 'function') { + throw new Error( + 'flags: Could not load "@tanstack/react-start/server". Make sure TanStack Start is installed, or call the flag with an explicit `Request`, e.g. `flag(request)`.', + ); + } + + const request = getRequest(); + if (!request) { + throw new Error( + 'flags: No request found. Feature flags can only be evaluated on the server, inside a route loader, server function, or server route. You may also pass a `Request` explicitly, e.g. `flag(request)`.', + ); + } + + return request; +} diff --git a/packages/flags/src/tanstack-start/index.test.ts b/packages/flags/src/tanstack-start/index.test.ts new file mode 100644 index 00000000..244d835d --- /dev/null +++ b/packages/flags/src/tanstack-start/index.test.ts @@ -0,0 +1,154 @@ +import { beforeAll, describe, expect, it } from 'vitest'; +import { encryptOverrides } from '..'; +import { + createFlagsDiscoveryEndpoint, + flag, + generatePermutations, + getProviderData, + precompute, +} from '.'; + +const secret = 'a'.repeat(43); + +beforeAll(() => { + process.env.FLAGS_SECRET = secret; +}); + +describe('getProviderData', () => { + it('is a function', () => { + expect(typeof getProviderData).toBe('function'); + }); + + it('returns definitions for the passed flags', () => { + const first = flag({ key: 'first-flag', decide: () => false }); + const data = getProviderData({ first }); + expect(data.definitions).toHaveProperty('first-flag'); + }); +}); + +describe('flag', () => { + it('defines a key', () => { + const f = flag({ key: 'first-flag', decide: () => false }); + expect(f).toHaveProperty('key', 'first-flag'); + }); + + it('evaluates using an explicitly passed request', async () => { + const f = flag({ key: 'explicit-request', decide: () => true }); + const request = new Request('http://localhost/'); + await expect(f(request)).resolves.toBe(true); + }); + + it('passes headers and cookies to decide', async () => { + const f = flag({ + key: 'reads-cookie', + decide: ({ cookies }) => cookies.get('country')?.value ?? 'unknown', + }); + const request = new Request('http://localhost/', { + headers: { cookie: 'country=US' }, + }); + await expect(f(request)).resolves.toBe('US'); + }); + + it('deduplicates decide calls within the same request', async () => { + let calls = 0; + const f = flag({ + key: 'dedupe', + decide: () => ++calls, + }); + const request = new Request('http://localhost/'); + const [a, b] = await Promise.all([f(request), f(request)]); + expect(a).toBe(b); + expect(calls).toBe(1); + }); + + it('respects overrides from the vercel-flag-overrides cookie', async () => { + const f = flag({ key: 'overridable', decide: () => false }); + const override = await encryptOverrides({ overridable: true }, secret); + const request = new Request('http://localhost/', { + headers: { cookie: `vercel-flag-overrides=${override}` }, + }); + await expect(f(request)).resolves.toBe(true); + }); + + // Fix #1: defaultValue fallback when decide/adapter returns undefined. + it('falls back to defaultValue when decide returns undefined', async () => { + const f = flag({ + key: 'undefined-decide', + defaultValue: true, + decide: () => undefined as unknown as boolean, + }); + await expect(f(new Request('http://localhost/'))).resolves.toBe(true); + }); + + it('falls back to defaultValue when the adapter decide returns undefined', async () => { + const f = flag({ + key: 'undefined-adapter-decide', + defaultValue: true, + adapter: () => ({ decide: () => undefined as unknown as boolean }), + }); + await expect(f(new Request('http://localhost/'))).resolves.toBe(true); + }); + + // Fix #2: a plain decide flag must evaluate without FLAGS_SECRET; the secret + // is only required to decrypt an overrides cookie. + it('evaluates a plain decide flag without FLAGS_SECRET', async () => { + const saved = process.env.FLAGS_SECRET; + delete process.env.FLAGS_SECRET; + try { + const f = flag({ key: 'no-secret-needed', decide: () => true }); + await expect(f(new Request('http://localhost/'))).resolves.toBe(true); + } finally { + process.env.FLAGS_SECRET = saved; + } + }); + + it('throws a clear error for an overrides cookie when no secret is set', async () => { + const saved = process.env.FLAGS_SECRET; + delete process.env.FLAGS_SECRET; + try { + const f = flag({ key: 'needs-secret', decide: () => false }); + const request = new Request('http://localhost/', { + headers: { cookie: 'vercel-flag-overrides=anything' }, + }); + await expect(f(request)).rejects.toThrow(/No secret provided/); + } finally { + process.env.FLAGS_SECRET = saved; + } + }); +}); + +describe('precompute', () => { + it('serializes and reads back precomputed values', async () => { + const flagA = flag({ key: 'a', decide: () => true }); + const flagB = flag({ key: 'b', decide: () => false }); + const flags = [flagA, flagB] as const; + const request = new Request('http://localhost/'); + + const code = await precompute(flags, request); + + await expect(flagA(code, flags)).resolves.toBe(true); + await expect(flagB(code, flags)).resolves.toBe(false); + }); +}); + +describe('generatePermutations', () => { + it('generates one code per boolean permutation', async () => { + const flagA = flag({ key: 'a', decide: () => false }); + const flagB = flag({ key: 'b', decide: () => false }); + const permutations = await generatePermutations([flagA, flagB]); + expect(permutations).toHaveLength(4); + }); +}); + +describe('createFlagsDiscoveryEndpoint', () => { + it('returns 401 when the request is not authorized', async () => { + const handler = createFlagsDiscoveryEndpoint(() => ({ + definitions: {}, + hints: [], + })); + const response = await handler({ + request: new Request('http://localhost/.well-known/vercel/flags'), + }); + expect(response.status).toBe(401); + }); +}); diff --git a/packages/flags/src/tanstack-start/index.ts b/packages/flags/src/tanstack-start/index.ts new file mode 100644 index 00000000..281e9cc4 --- /dev/null +++ b/packages/flags/src/tanstack-start/index.ts @@ -0,0 +1,420 @@ +import { RequestCookies } from '@edge-runtime/cookies'; +import { + decryptFlagDefinitions as _decryptFlagDefinitions, + decryptFlagValues as _decryptFlagValues, + decryptOverrides as _decryptOverrides, + encryptFlagDefinitions as _encryptFlagDefinitions, + encryptFlagValues as _encryptFlagValues, + encryptOverrides as _encryptOverrides, + type ApiData, + type FlagDefinitionsType, + type JsonValue, + reportValue, + verifyAccess, + version, +} from '..'; +import { normalizeOptions } from '../lib/normalize-options'; +import { + HeadersAdapter, + type ReadonlyHeaders, +} from '../spec-extension/adapters/headers'; +import { + type ReadonlyRequestCookies, + RequestCookiesAdapter, +} from '../spec-extension/adapters/request-cookies'; +import type { + Decide, + FlagDeclaration, + FlagOverridesType, + FlagValuesType, + Identify, + ResolvedFlagDeclaration, +} from '../types'; +import { tryGetSecret } from './env'; +import { getStartRequest } from './get-request'; +import { + generatePermutations as _generatePermutations, + precompute as _precompute, + getPrecomputed, +} from './precompute'; +import type { Flag, FlagsArray } from './types'; + +export type { Flag, FlagsArray } from './types'; + +// biome-ignore lint/suspicious/noShadowRestrictedNames: for type safety +function hasOwnProperty( + obj: X, + prop: Y, +): obj is X & Record { + return Object.hasOwn(obj, prop); +} + +const headersMap = new WeakMap(); +const cookiesMap = new WeakMap(); + +function sealHeaders(headers: Headers): ReadonlyHeaders { + const cached = headersMap.get(headers); + if (cached !== undefined) return cached; + + const sealed = HeadersAdapter.seal(headers); + headersMap.set(headers, sealed); + return sealed; +} + +function sealCookies(headers: Headers): ReadonlyRequestCookies { + const cached = cookiesMap.get(headers); + if (cached !== undefined) return cached; + + const sealed = RequestCookiesAdapter.seal(new RequestCookies(headers)); + cookiesMap.set(headers, sealed); + return sealed; +} + +function getDecide( + definition: ResolvedFlagDeclaration, +): Decide { + return function decide(params) { + if (typeof definition.decide === 'function') { + return definition.decide(params); + } + if (typeof definition.adapter?.decide === 'function') { + return definition.adapter.decide({ key: definition.key, ...params }); + } + throw new Error(`flags: No decide function provided for ${definition.key}`); + }; +} + +function getIdentify( + definition: ResolvedFlagDeclaration, +): Identify | undefined { + if (typeof definition.identify === 'function') { + return definition.identify; + } + if (typeof definition.adapter?.identify === 'function') { + return definition.adapter.identify; + } +} + +interface RequestContext { + /** + * A secret passed explicitly to the flag, if any. The secret is only needed + * to decrypt Vercel Toolbar overrides, so it is resolved lazily (see the + * override branch in `flagImpl`) rather than required up front. + */ + secretOverride?: string; + usedFlags: Record>; + identifiers: Map, ReturnType>>; +} + +/** + * Per-request context, keyed off the request instance returned by TanStack + * Start's `getRequest()` (or the request passed explicitly to a flag). This + * deduplicates `decide`/`identify` calls and override decryption within a + * single request. + */ +const contextMap = new WeakMap(); + +// Resolving the context must stay synchronous so that, for a request passed +// explicitly, concurrent flag evaluations share a single `decide` call (the +// `usedFlags` entry is written before the first `await`). +// +// The secret is NOT required here: a plain `decide` flag (no overrides cookie, +// no precompute) must evaluate without FLAGS_SECRET. The secret is resolved +// lazily, and only when an overrides cookie is actually present. +function getContext(request: Request, secret?: string): RequestContext { + const existing = contextMap.get(request); + if (existing) { + // Capture an explicitly-passed secret if an earlier call didn't have one. + if (secret && !existing.secretOverride) existing.secretOverride = secret; + return existing; + } + + const context: RequestContext = { + secretOverride: secret, + usedFlags: {}, + identifiers: new Map(), + }; + contextMap.set(request, context); + return context; +} + +/** + * Declares a feature flag. + * + * The returned function can be called with no arguments inside a route loader, + * server function, or server route — the request is resolved automatically + * through TanStack Start's `getRequest()`. You may also pass a `Request` + * explicitly when evaluating outside of a request context. + * + * If an override set by Vercel Toolbar is present (the `vercel-flag-overrides` + * cookie) then the `decide` function will not be called and the value of the + * override will be returned instead. + * + * @example + * ```ts + * import { flag } from 'flags/tanstack-start'; + * + * export const showBanner = flag({ + * key: 'show-banner', + * decide: () => false, + * }); + * + * // inside a route loader / server function + * const value = await showBanner(); + * ``` + */ +export function flag< + ValueType extends JsonValue = boolean | string | number, + EntitiesType = any, +>(definition: FlagDeclaration): Flag { + // Allow passing the adapter factory directly (`adapter: vercelAdapter`) as a + // shorthand for calling it (`adapter: vercelAdapter()`). Resolve it once here. + const adapter = + typeof definition.adapter === 'function' + ? definition.adapter() + : definition.adapter; + const resolvedDefinition = { + ...definition, + adapter, + } as ResolvedFlagDeclaration; + + const decide = getDecide(resolvedDefinition); + const identify = getIdentify(resolvedDefinition); + + const flagImpl = async function flagImpl( + requestOrCode?: string | Request, + flagsArrayOrSecret?: string | Flag[], + maybeSecret?: string, + ): Promise { + // Precomputed mode: `flag(code, flagsArray, secret?)` + if ( + typeof requestOrCode === 'string' && + Array.isArray(flagsArrayOrSecret) + ) { + return getPrecomputed( + definition.key, + flagsArrayOrSecret, + requestOrCode, + await tryGetSecret(maybeSecret), + ); + } + + const request = + requestOrCode instanceof Request + ? requestOrCode + : await getStartRequest(); + + const secret = + typeof flagsArrayOrSecret === 'string' ? flagsArrayOrSecret : undefined; + + const store = getContext(request, secret); + + if (hasOwnProperty(store.usedFlags, definition.key)) { + const valuePromise = store.usedFlags[definition.key]; + if (typeof valuePromise !== 'undefined') { + return valuePromise as Promise; + } + } + + const headers = sealHeaders(request.headers); + const cookies = sealCookies(request.headers); + + const overridesCookie = cookies.get('vercel-flag-overrides')?.value; + if (overridesCookie) { + // The secret is only needed to decrypt overrides — resolve it here. + const secret = store.secretOverride ?? process.env.FLAGS_SECRET; + if (!secret) { + throw new Error( + 'flags: No secret provided. Set an environment variable FLAGS_SECRET or provide a secret to the function.', + ); + } + const overrides = await _decryptOverrides(overridesCookie, secret); + if (overrides && hasOwnProperty(overrides, definition.key)) { + const value = overrides[definition.key]; + if (typeof value !== 'undefined') { + reportValue(definition.key, value); + store.usedFlags[definition.key] = Promise.resolve(value as JsonValue); + return value as ValueType; + } + } + } + + let entities: EntitiesType | undefined; + if (identify) { + // Deduplicate calls to identify, key being the function itself + if (!store.identifiers.has(identify)) { + const entitiesPromise = identify({ + headers, + cookies, + }); + store.identifiers.set(identify, entitiesPromise); + } + + entities = (await store.identifiers.get(identify)) as EntitiesType; + } + + // Fall back to the declared `defaultValue` when `decide` (or the adapter) + // returns `undefined`. The wrapped promise is stored synchronously so + // concurrent evaluations dedupe to the same (defaulted) value. + const valuePromise = Promise.resolve( + decide({ headers, cookies, entities }), + ).then((decided) => + decided === undefined ? (definition.defaultValue as ValueType) : decided, + ); + store.usedFlags[definition.key] = valuePromise as Promise; + + const value = await valuePromise; + reportValue(definition.key, value); + return value; + }; + + flagImpl.key = definition.key; + flagImpl.defaultValue = definition.defaultValue; + flagImpl.origin = definition.origin; + flagImpl.description = definition.description; + flagImpl.options = normalizeOptions(definition.options); + flagImpl.decide = decide; + flagImpl.identify = identify; + + return flagImpl as Flag; +} + +export function getProviderData(flags: Record>): ApiData { + const definitions = Object.values(flags).reduce( + (acc, d) => { + acc[d.key] = { + options: normalizeOptions(d.options), + origin: d.origin, + description: d.description, + }; + return acc; + }, + {}, + ); + + return { definitions, hints: [] }; +} + +export async function encryptFlagValues( + value: FlagValuesType, + secret?: string, +) { + return _encryptFlagValues(value, await tryGetSecret(secret)); +} + +export async function decryptFlagValues( + encryptedData: string, + secret?: string, +) { + return _decryptFlagValues(encryptedData, await tryGetSecret(secret)); +} + +export async function encryptOverrides( + overrides: FlagOverridesType, + secret?: string, +) { + return _encryptOverrides(overrides, await tryGetSecret(secret)); +} + +export async function decryptOverrides(encryptedData: string, secret?: string) { + return _decryptOverrides(encryptedData, await tryGetSecret(secret)); +} + +export async function encryptFlagDefinitions( + value: FlagDefinitionsType, + secret?: string, +) { + return _encryptFlagDefinitions(value, await tryGetSecret(secret)); +} + +export async function decryptFlagDefinitions( + encryptedData: string, + secret?: string, +) { + return _decryptFlagDefinitions(encryptedData, await tryGetSecret(secret)); +} + +/** + * Evaluate a list of feature flags and generate a signed string representing their values. + * + * This convenience function call combines `evaluate` and `serialize`. + * + * @param flags - list of flags + * @returns - a string representing evaluated flags + */ +export async function precompute( + flags: T, + request: Request, + secret?: string, +): Promise { + return _precompute(flags, request, await tryGetSecret(secret)); +} + +/** + * Generates all permutations given a list of feature flags based on the options declared on each flag. + * @param flags - The list of feature flags + * @param filter - An optional filter function which gets called with each permutation. + * @param secret - The secret sign the generated permutation with + * @returns An array of strings representing each permutation + */ +export async function generatePermutations( + flags: FlagsArray, + filter: ((permutation: Record) => boolean) | null = null, + secret?: string, +): Promise { + return _generatePermutations(flags, filter, await tryGetSecret(secret)); +} + +/** + * The handler context provided by a TanStack Start server route handler. + * Typed loosely so this package doesn't need to depend on TanStack types. + */ +interface ServerRouteHandlerContext { + request: Request; +} + +/** + * Creates a handler for the `/.well-known/vercel/flags` discovery endpoint. + * + * Wire it up in a server route, e.g. `src/routes/.well-known/vercel/flags.ts`: + * + * @example + * ```ts + * import { createFileRoute } from '@tanstack/react-router'; + * import { createFlagsDiscoveryEndpoint, getProviderData } from 'flags/tanstack-start'; + * import * as flags from '../../flags'; + * + * const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + * + * export const Route = createFileRoute('/.well-known/vercel/flags/')({ + * server: { handlers: { GET: handler } }, + * }); + * ``` + * + * @param getApiData a function returning the API data + * @param options accepts a secret + * @returns a server route handler returning a `Response` + */ +export function createFlagsDiscoveryEndpoint( + getApiData: ( + context: ServerRouteHandlerContext, + ) => Promise | ApiData, + options?: { + secret?: string | undefined; + }, +) { + return async function handler( + context: ServerRouteHandlerContext, + ): Promise { + const access = await verifyAccess( + context.request.headers.get('Authorization'), + options?.secret, + ); + if (!access) return new Response(null, { status: 401 }); + + const apiData = await getApiData(context); + return Response.json(apiData, { + headers: { 'x-flags-sdk-version': version }, + }); + }; +} diff --git a/packages/flags/src/tanstack-start/precompute.ts b/packages/flags/src/tanstack-start/precompute.ts new file mode 100644 index 00000000..e5b27aa1 --- /dev/null +++ b/packages/flags/src/tanstack-start/precompute.ts @@ -0,0 +1,154 @@ +import type { JsonValue } from '..'; +import * as s from '../lib/serialization'; +import type { Flag, FlagsArray } from './types'; + +type ValuesArray = readonly any[]; + +/** + * Resolves a list of flags + * @param flags - list of flags + * @returns - an array of evaluated flag values with one entry per flag + */ +async function evaluate( + flags: T, + request: Request, +): Promise<{ [K in keyof T]: Awaited> }> { + return Promise.all(flags.map((flag) => flag(request))) as Promise<{ + [K in keyof T]: Awaited>; + }>; +} + +/** + * Evaluate a list of feature flags and generate a signed string representing their values. + * + * This convenience function call combines `evaluate` and `serialize`. + * + * @param flags - list of flags + * @returns - a string representing evaluated flags + */ +export async function precompute( + flags: T, + request: Request, + secret: string, +): Promise { + const values = await evaluate(flags, request); + return serialize(flags, values, secret); +} + +/** + * Combines flag declarations with values. + * @param flags - flag declarations + * @param values - flag values + * @returns - A record where the keys are flag keys and the values are flag values. + */ +function combine(flags: FlagsArray, values: ValuesArray) { + return Object.fromEntries(flags.map((flag, i) => [flag.key, values[i]])); +} + +/** + * Takes a list of feature flag declarations and their values and turns them into a short, signed string. + * + * The returned string is signed to avoid enumeration attacks. + * + * When a feature flag's `options` contains the value the flag resolved to, then the encoding will store it's index only, leading to better compression. Boolean values and null are compressed even when the options are not declared on the flag. + * + * @param flags - A list of feature flags + * @param values - A list of the values of the flags declared in ´flags` + * @param secret - The secret to use for signing the result + * @returns - A short string representing the values. + */ +async function serialize( + flags: FlagsArray, + values: ValuesArray, + secret: string, +) { + if (flags.length === 0) return '__no_flags__'; + return s.serialize(combine(flags, values), flags, secret); +} + +/** + * Decodes all flags given the list of flags used to encode. Returns an object consisting of each flag's key and its resolved value. + * @param flags - Flags used when `code` was generated by `precompute` or `serialize`. + * @param code - The code returned from `serialize` + * @param secret - The secret to use for signing the result + * @returns - An object consisting of each flag's key and its resolved value. + */ +async function deserialize(flags: FlagsArray, code: string, secret: string) { + if (code === '__no_flags__') return {}; + return s.deserialize(code, flags, secret); +} + +/** + * Decodes the value of one or multiple flags given the list of flags used to encode and the code. + * + * @param flagKey - Flag or list of flags to decode + * @param precomputeFlags - Flags used when `code` was generated by `serialize` + * @param code - The code returned from `serialize` + * @param secret - The secret to use for verifying the signature + */ +export async function getPrecomputed( + flagKey: Flag['key'], + precomputeFlags: FlagsArray, + code: string, + secret: string, +): Promise { + if (code === '__no_flags__') { + console.warn( + `flags: getPrecomputed was called with a code generated from an empty flags array. The flag "${flagKey}" can not be resolved. Make sure to include it in the array passed to serialize/precompute.`, + ); + } + + const flagSet = await deserialize(precomputeFlags, code, secret); + + if (!Object.hasOwn(flagSet, flagKey)) { + console.warn( + `flags: Tried to read precomputed value for flag "${flagKey}" which is not part of the precomputed flags. Make sure to include it in the array passed to serialize/precompute.`, + ); + } + + return flagSet[flagKey]; +} + +// see https://stackoverflow.com/a/44344803 +function* cartesianIterator(items: T[][]): Generator { + const remainder = items.length > 1 ? cartesianIterator(items.slice(1)) : [[]]; + for (const r of remainder) for (const h of items.at(0)!) yield [h, ...r]; +} + +/** + * Generates all permutations given a list of feature flags based on the options declared on each flag. + * @param flags - The list of feature flags + * @param filter - An optional filter function which gets called with each permutation. + * @param secret - The secret sign the generated permutation with + * @returns An array of strings representing each permutation + */ +export async function generatePermutations( + flags: FlagsArray, + filter: ((permutation: Record) => boolean) | null = null, + secret: string, +): Promise { + if (flags.length === 0) return ['__no_flags__']; + + const options = flags.map((flag) => { + // infer boolean permutations if you don't declare any options. + // + // to explicitly opt out you need to use "filter" + if (!flag.options) return [false, true]; + return flag.options.map((option) => option.value); + }); + + const list: Record[] = []; + + for (const permutation of cartesianIterator(options)) { + const permObject = permutation.reduce>( + (acc, value, index) => { + acc[(flags[index] as Flag).key] = value; + return acc; + }, + {}, + ); + if (!filter || filter(permObject)) list.push(permObject); + } + + return Promise.all(list.map((values) => s.serialize(values, flags, secret))); +} diff --git a/packages/flags/src/tanstack-start/types.ts b/packages/flags/src/tanstack-start/types.ts new file mode 100644 index 00000000..54afc799 --- /dev/null +++ b/packages/flags/src/tanstack-start/types.ts @@ -0,0 +1,40 @@ +import type { FlagOption } from '../types'; + +type FlagsMeta = { + key: string; + description?: string; + origin?: string | Record; + options?: FlagOption[]; +}; + +type RegularFlag = { + (): ReturnValue | Promise; + ( + /** + * Only provide this if you're retrieving the flag value outside of a request + * context where `getRequest()` is available (e.g. when calling it from code + * that runs before TanStack Start established the request). In a route + * loader, server function, or server route you can call the flag without any + * arguments. + */ + request?: Request, + secret?: string, + ): ReturnValue | Promise; +} & FlagsMeta; + +type PrecomputedFlag = { + (): never; + ( + /** The route parameter that contains the precomputed flag values */ + code: string, + /** The flags which were used to create the code (i.e. the same array you passed to `precompute(...)`) */ + flagsArray: FlagsArray, + secret?: string, + ): ReturnValue | Promise; +} & FlagsMeta; + +export type Flag = + | RegularFlag + | PrecomputedFlag; + +export type FlagsArray = readonly Flag[]; diff --git a/packages/flags/tsup.config.js b/packages/flags/tsup.config.js index ae4466c1..1d9eb928 100644 --- a/packages/flags/tsup.config.js +++ b/packages/flags/tsup.config.js @@ -16,6 +16,7 @@ export default defineConfig({ index: 'src/index.ts', next: 'src/next/index.ts', sveltekit: 'src/sveltekit/index.ts', + 'tanstack-start': 'src/tanstack-start/index.ts', react: 'src/react/index.tsx', analytics: 'src/analytics.ts', }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 369f15bc..a6391291 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,22 +58,22 @@ importers: version: 5.9.3 typescript-eslint: specifier: 8.46.1 - version: 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) apps/docs: dependencies: '@vercel/analytics': specifier: ^1.6.1 - version: 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + version: 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) '@vercel/geistdocs': specifier: 1.8.0 - version: 1.8.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(unified@11.0.5)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + version: 1.8.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) '@vercel/speed-insights': specifier: ^1.3.1 - version: 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + version: 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) '@vercel/toolbar': specifier: 0.1.36 - version: 0.1.36(46e20062f085152cc5929d2c51b95350) + version: 0.1.36(d61f01146c2ef5fb24ca3153124e8775) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -88,13 +88,13 @@ importers: version: link:../../packages/flags fumadocs-core: specifier: 16.2.2 - version: 16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + version: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) fumadocs-mdx: specifier: 14.0.4 - version: 14.0.4(fumadocs-core@16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + version: 14.0.4(fumadocs-core@16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) fumadocs-ui: specifier: 16.2.2 - version: 16.2.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18) + version: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18) lucide-react: specifier: ^0.555.0 version: 0.555.0(react@19.2.4) @@ -183,10 +183,10 @@ importers: version: 19.2.3(@types/react@19.2.14) eslint: specifier: ^9 - version: 9.38.0(jiti@2.6.1) + version: 9.38.0(jiti@2.7.0) eslint-config-next: specifier: 16.2.0 - version: 16.2.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + version: 16.2.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) tailwindcss: specifier: ^4 version: 4.1.18 @@ -250,7 +250,7 @@ importers: version: 0.5.16(tailwindcss@4.0.15) '@vercel/analytics': specifier: 1.5.0 - version: 1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) + version: 1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) '@vercel/edge': specifier: 1.2.1 version: 1.2.1 @@ -259,7 +259,7 @@ importers: version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@vercel/toolbar': specifier: 0.1.36 - version: 0.1.36(e11d9f19b9b209cd13851100642dec20) + version: 0.1.36(5e695e95bd856e4a5cccdd7b48e1248c) clsx: specifier: 2.1.1 version: 2.1.1 @@ -326,7 +326,7 @@ importers: version: 1.4.3(@opentelemetry/api@1.9.0)(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1)) '@vercel/toolbar': specifier: 0.1.36 - version: 0.1.36(0f6bdcb16ca33fd4d4a7a6778377aac0) + version: 0.1.36(6c18ec6ca37694d8fda4040b542538f4) class-variance-authority: specifier: 0.7.1 version: 0.7.1 @@ -390,13 +390,13 @@ importers: version: 0.5.16(tailwindcss@4.0.15) '@tailwindcss/vite': specifier: 4.0.15 - version: 4.0.15(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + version: 4.0.15(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) '@vercel/edge': specifier: ^1.2.1 version: 1.2.1 '@vercel/toolbar': specifier: 0.1.36 - version: 0.1.36(8fe6223b567b6ad42eaed06500731368) + version: 0.1.36(ddbcaeb0e7cf10b922b48b60c0a982eb) cookie: specifier: ^0.7.0 version: 0.7.2 @@ -409,13 +409,13 @@ importers: devDependencies: '@sveltejs/adapter-vercel': specifier: ^5.6.0 - version: 5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(rollup@4.59.0) + version: 5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(rollup@4.59.0) '@sveltejs/kit': specifier: ^2.50.2 - version: 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + version: 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) '@sveltejs/vite-plugin-svelte': specifier: ^4.0.0 - version: 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + version: 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) svelte: specifier: ^5.0.0 version: 5.41.3 @@ -427,7 +427,41 @@ importers: version: 5.8.2 vite: specifier: ^5.4.4 - version: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + version: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) + + examples/tanstack-start-example: + dependencies: + '@tanstack/react-router': + specifier: ^1.170.0 + version: 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start': + specifier: ^1.168.0 + version: 1.168.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + flags: + specifier: workspace:* + version: link:../../packages/flags + react: + specifier: ^19 + version: 19.2.4 + react-dom: + specifier: ^19 + version: 19.2.4(react@19.2.4) + devDependencies: + '@types/react': + specifier: 'catalog:' + version: 19.2.14 + '@types/react-dom': + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.2.0(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + typescript: + specifier: 5.6.3 + version: 5.6.3 + vite: + specifier: ^7.0.0 + version: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) packages/adapter-edge-config: dependencies: @@ -446,16 +480,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-flagsmith: dependencies: @@ -477,16 +511,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-growthbook: dependencies: @@ -514,16 +548,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-hypertune: dependencies: @@ -548,16 +582,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-launchdarkly: dependencies: @@ -582,16 +616,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-openfeature: devDependencies: @@ -612,16 +646,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-optimizely: devDependencies: @@ -639,16 +673,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-posthog: dependencies: @@ -673,16 +707,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.8.2)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.8.2)(yaml@2.8.1) typescript: specifier: 5.8.2 version: 5.8.2 vite: specifier: 6.4.1 - version: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + version: 6.4.1(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@22.14.0)(lightningcss@1.30.2) + version: 1.6.1(@types/node@22.14.0)(lightningcss@1.32.0) packages/adapter-reflag: dependencies: @@ -704,16 +738,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-split: devDependencies: @@ -731,16 +765,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-statsig: dependencies: @@ -771,16 +805,16 @@ importers: version: 6.1.2 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/adapter-vercel: dependencies: @@ -802,16 +836,16 @@ importers: version: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413) tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 6.4.1 - version: 6.4.1(@types/node@20.11.17)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + version: 6.4.1(@types/node@20.11.17)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) vitest: specifier: 2.1.9 - version: 2.1.9(@types/node@20.11.17)(lightningcss@1.30.2)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) + version: 2.1.9(@types/node@20.11.17)(lightningcss@1.32.0)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) packages/flags: dependencies: @@ -823,7 +857,10 @@ importers: version: 1.9.0 '@sveltejs/kit': specifier: '*' - version: 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.6.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + version: 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.6.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + '@tanstack/react-start': + specifier: '*' + version: 1.168.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) jose: specifier: ^5.10.0 version: 5.10.0 @@ -848,7 +885,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: 4.2.1 - version: 4.2.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + version: 4.2.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) msw: specifier: 2.6.4 version: 2.6.4(@types/node@20.11.17)(typescript@5.6.3) @@ -857,16 +894,16 @@ importers: version: 16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 5.4.21 - version: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + version: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) vitest: specifier: 1.6.1 - version: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + version: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) packages/prepare-flags-definitions: devDependencies: @@ -875,16 +912,16 @@ importers: version: 20.11.17 tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 6.4.1 - version: 6.4.1(@types/node@20.11.17)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + version: 6.4.1(@types/node@20.11.17)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) vitest: specifier: 2.1.9 - version: 2.1.9(@types/node@20.11.17)(lightningcss@1.30.2)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) + version: 2.1.9(@types/node@20.11.17)(lightningcss@1.32.0)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) packages/vercel-flags-core: dependencies: @@ -915,16 +952,16 @@ importers: version: 16.2.0(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.3.0-canary-fef12a01-20260413))(react@19.3.0-canary-fef12a01-20260413) tsup: specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) + version: 8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1) typescript: specifier: 5.6.3 version: 5.6.3 vite: specifier: 6.4.1 - version: 6.4.1(@types/node@20.11.17)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + version: 6.4.1(@types/node@20.11.17)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) vitest: specifier: 2.1.9 - version: 2.1.9(@types/node@20.11.17)(lightningcss@1.30.2)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) + version: 2.1.9(@types/node@20.11.17)(lightningcss@1.32.0)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)) tests/next-15: dependencies: @@ -1004,7 +1041,7 @@ importers: dependencies: '@vercel/toolbar': specifier: 0.1.36 - version: 0.1.36(8fe6223b567b6ad42eaed06500731368) + version: 0.1.36(ddbcaeb0e7cf10b922b48b60c0a982eb) flags: specifier: workspace:* version: link:../../packages/flags @@ -1014,13 +1051,13 @@ importers: version: 1.58.1 '@sveltejs/adapter-vercel': specifier: ^5.6.0 - version: 5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(rollup@4.59.0) + version: 5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(rollup@4.59.0) '@sveltejs/kit': specifier: ^2.50.2 - version: 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + version: 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) '@sveltejs/vite-plugin-svelte': specifier: ^4.0.0 - version: 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + version: 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) svelte: specifier: ^5.0.0 version: 5.41.3 @@ -1032,7 +1069,7 @@ importers: version: 5.8.2 vite: specifier: ^5.4.4 - version: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + version: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) packages: @@ -1077,6 +1114,10 @@ packages: resolution: {integrity: sha512-GiwTmBFOU1/+UVNqqCGzFJYfBXEytUkiI+iRZ6Qx7KmUVtLm00sYySkfe203C9QtPG11yOz1ZaMek8dT/xnlgg==} engines: {node: '>=20'} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -2739,6 +2780,22 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} + '@oozcitak/dom@2.0.2': + resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} + engines: {node: '>=20.0'} + + '@oozcitak/infra@2.0.2': + resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} + engines: {node: '>=20.0'} + + '@oozcitak/url@3.0.0': + resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} + engines: {node: '>=20.0'} + + '@oozcitak/util@10.0.0': + resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} + engines: {node: '>=20.0'} + '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -4146,6 +4203,9 @@ packages: '@reflag/node-sdk@1.0.1': resolution: {integrity: sha512-UUmxjspx3hExHDzmtBrZux9fDP44SQok9sQawM+OV0zvJzPyR9b6g3UuK/vNnr+RPMgKoaBvlPeU4kEB70Gt1A==} + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -4777,15 +4837,148 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 + '@tanstack/history@1.162.0': + resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} + engines: {node: '>=20.19'} + + '@tanstack/react-router@1.170.16': + resolution: {integrity: sha512-w6eq1IJklujs1tESazaK/FxH0+H2l8vm/QPuu1cD3oRW/ubgKneQpd7b64ti/8gUyEimzimJQZDmJr6YHfP5+g==} + engines: {node: '>=20.19'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-client@1.168.14': + resolution: {integrity: sha512-oaz43fdOhBWfOPsdLkp3IejwYEXRyeaZ4CYexOPZx3eVXzm4LLozvNkkkBE9aje1sM5MVC2Yo6+cyv2HdVzkHQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start-rsc@0.1.25': + resolution: {integrity: sha512-Rwm6cjcS148y2XAebr8jyrwU0SqsRSkW4/CuXesoHg+G3IOnVRHV0HOylJfnznUTVuH1nVhfQRPI5uWPJaw2TA==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rspack/core': '>=2.0.0-0' + '@vitejs/plugin-rsc': '>=0.5.20' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + react-server-dom-rspack: '>=0.0.2' + peerDependenciesMeta: + '@rspack/core': + optional: true + '@vitejs/plugin-rsc': + optional: true + react-server-dom-rspack: + optional: true + + '@tanstack/react-start-server@1.167.20': + resolution: {integrity: sha512-hg9xVI6yNDu+6NCalKz1h3Ea18HZEUu35i/ZMJz1WadwqcArLMp41nM1GNhOAtGIdpycrp9tT7ccqc9zuRMRpQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-start@1.168.26': + resolution: {integrity: sha512-ZzNecqKWC0p2643/kIcFUdsMrXZ8A4dXm4Yfe9zV/Y0u14MtSkh/Sk76RQYIU5S84VyDyKhHo0Ffh8HQbLdvFw==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rsbuild/core': ^2.0.0 + '@vitejs/plugin-rsc': '*' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + vite: '>=7.0.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@vitejs/plugin-rsc': + optional: true + vite: + optional: true + + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/react-virtual@3.13.12': resolution: {integrity: sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + '@tanstack/router-core@1.171.13': + resolution: {integrity: sha512-+NOwEj1kO/6IGmpHRIZHasYxYWpyBQGNIZAST9aNrk9Q3YlU9SgqVnl1pbLa9qAKfeNdXQIRve0RQb/0kyDeDA==} + engines: {node: '>=20.19'} + + '@tanstack/router-generator@1.167.17': + resolution: {integrity: sha512-xtB9tB2Ws0tWR6Pi7nc3Qk9IYgoh1mQCKWjHqIl9tf6BNUpKoqniJoPAQ4+LGrK8FeZYU0o0p/qlZEyj9FAulA==} + engines: {node: '>=20.19'} + + '@tanstack/router-plugin@1.168.18': + resolution: {integrity: sha512-MofS28/axfnfnhOD2RSgJEaU882aX5RsAzhGz5Vc4XhAmvCjy919u9JrNs4QsTWFbTD1P7IJ8WFlFVsrg0pStg==} + engines: {node: '>=20.19'} + peerDependencies: + '@rsbuild/core': '>=1.0.2 || ^2.0.0' + '@tanstack/react-router': ^1.170.15 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' + vite-plugin-solid: ^2.11.10 || ^3.0.0-0 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.162.2': + resolution: {integrity: sha512-hTWqJtqIFFdvuCl8WXNyrodp2L9zo2G37xKRrcVmVRWpAB2h+U1LuRAfS4tsFTiWOIoE/B+WDVFB8JpoEdw6jQ==} + engines: {node: '>=20.19'} + + '@tanstack/start-client-core@1.170.12': + resolution: {integrity: sha512-gwtZRMPUIAxmDV2AIQUhC0kSW262SV7BkHXEgy5B1woHQdrdsELuGOdJwdweLxrjyefORxk+9MYGqDY0Cxn0bw==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-fn-stubs@1.162.0': + resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-plugin-core@1.171.18': + resolution: {integrity: sha512-weuOOjRD03BiKcF9NYKL5QADEQOp3yGHb0qIsOX42ENz5XUE4in2fXcVYHjSwwpzs+XGhWIFLp5J385pOVPuZQ==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@rsbuild/core': ^2.0.0 + vite: '>=7.0.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + vite: + optional: true + + '@tanstack/start-server-core@1.169.15': + resolution: {integrity: sha512-V8ie2G2Ecb3Nklk8/QuKzulxb+tDUqgz6rjJe8Isdp4iKVXZu/TscItkUP/4Q5Bu7W4gUy3P25O6soC1oW1SXQ==} + engines: {node: '>=22.12.0'} + + '@tanstack/start-storage-context@1.167.15': + resolution: {integrity: sha512-Jy0q4vdG6pv76N92+X+ag3fuOV2zINQagYyMN1/es7tPI1vzpKECIU8AqHqzI6ahkwaph7XDvmfUkiLJ3i4LOA==} + engines: {node: '>=22.12.0'} + + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} + '@tanstack/virtual-core@3.13.12': resolution: {integrity: sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==} + '@tanstack/virtual-file-routes@1.162.0': + resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} + engines: {node: '>=20.19'} + '@tinyhttp/accepts@1.3.0': resolution: {integrity: sha512-YaJ4EMgVUI6JHzWO14lr6vn/BLJEoFN4Sqd20l0/oBcLLENkP8gnPtX1jB7OhIu0AE40VCweAqvSP+0/pgzB1g==} engines: {node: '>=12.4.0'} @@ -5404,6 +5597,12 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + '@vitest/expect@1.6.1': resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} @@ -5520,6 +5719,10 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + ansis@4.3.1: + resolution: {integrity: sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==} + engines: {node: '>=14'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -5619,6 +5822,9 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -5908,6 +6114,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie@0.4.0: resolution: {integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==} engines: {node: '>= 0.6'} @@ -6233,6 +6442,10 @@ packages: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -6573,6 +6786,9 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exsolve@1.1.0: + resolution: {integrity: sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -6619,6 +6835,9 @@ packages: resolution: {integrity: sha512-hgH6CCb+7+0c8PBlakI2KubG6R+Rb1MhpNcdvqUXZTBwBHf32piwY255diAkAmkGZ6AWlywOU88AkOgP9q8Rdw==} engines: {node: '>=20', pnpm: '>=10'} + fetchdts@0.1.7: + resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -6910,6 +7129,16 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} + h3@2.0.1-rc.20: + resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==} + engines: {node: '>=20.11.1'} + hasBin: true + peerDependencies: + crossws: ^0.4.1 + peerDependenciesMeta: + crossws: + optional: true + hachure-fill@0.5.2: resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} @@ -7246,6 +7475,10 @@ packages: isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isbot@5.1.43: + resolution: {integrity: sha512-drJhFmibra4LO6Wd7D3Oi6UICRK9244vSZkmxzhlZP0TTdwCA2ueK4PEkUkzPYeuqug9+cqqdWPgihjk5+83Cg==} + engines: {node: '>=18'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -7268,6 +7501,10 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} @@ -7396,6 +7633,12 @@ packages: cpu: [arm64] os: [android] + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.29.2: resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} engines: {node: '>= 12.0.0'} @@ -7408,6 +7651,12 @@ packages: cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.29.2: resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} engines: {node: '>= 12.0.0'} @@ -7420,6 +7669,12 @@ packages: cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.29.2: resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} engines: {node: '>= 12.0.0'} @@ -7432,6 +7687,12 @@ packages: cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.29.2: resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} engines: {node: '>= 12.0.0'} @@ -7444,6 +7705,12 @@ packages: cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.29.2: resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} engines: {node: '>= 12.0.0'} @@ -7458,6 +7725,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-musl@1.29.2: resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} engines: {node: '>= 12.0.0'} @@ -7472,6 +7746,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-gnu@1.29.2: resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} engines: {node: '>= 12.0.0'} @@ -7486,6 +7767,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-musl@1.29.2: resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} engines: {node: '>= 12.0.0'} @@ -7500,6 +7788,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-win32-arm64-msvc@1.29.2: resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} engines: {node: '>= 12.0.0'} @@ -7512,6 +7807,12 @@ packages: cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.29.2: resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} engines: {node: '>= 12.0.0'} @@ -7524,6 +7825,12 @@ packages: cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.29.2: resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} engines: {node: '>= 12.0.0'} @@ -7532,6 +7839,10 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + lilconfig@3.0.0: resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} engines: {node: '>=14'} @@ -8502,6 +8813,11 @@ packages: engines: {node: '>=10.13.0'} hasBin: true + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} + engines: {node: '>=14'} + hasBin: true + pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8597,6 +8913,10 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -8833,6 +9153,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rou3@0.8.1: + resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} + roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} @@ -8898,6 +9221,16 @@ packages: engines: {node: '>=10'} hasBin: true + seroval-plugins@1.5.4: + resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.5.4: + resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} + engines: {node: '>=10'} + set-cookie-parser@3.0.1: resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} @@ -9012,6 +9345,11 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + srvx@0.11.17: + resolution: {integrity: sha512-43yM4luKfCJamyCMhrUeHUPOrf8TdZe7kN8s5zayZCH5OeprYqi49Aso5ZvHXR4aB+DHaRNO/diNFgZSMNG8Xw==} + engines: {node: '>=20.16.0'} + hasBin: true + stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} @@ -9497,6 +9835,10 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} @@ -9657,6 +9999,46 @@ packages: yaml: optional: true + vite@7.3.5: + resolution: {integrity: sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.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 + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitefu@1.1.1: resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} peerDependencies: @@ -9745,6 +10127,9 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -9801,6 +10186,10 @@ packages: resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} hasBin: true + xmlbuilder2@4.0.3: + resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} + engines: {node: '>=20.0'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -9867,6 +10256,9 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -9930,6 +10322,12 @@ snapshots: typescript: 5.6.1-rc validate-npm-package-name: 5.0.1 + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -10684,9 +11082,9 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@9.38.0(jiti@2.7.0))': dependencies: - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} @@ -11273,6 +11671,23 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} + '@oozcitak/dom@2.0.2': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/url': 3.0.0 + '@oozcitak/util': 10.0.0 + + '@oozcitak/infra@2.0.2': + dependencies: + '@oozcitak/util': 10.0.0 + + '@oozcitak/url@3.0.0': + dependencies: + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + + '@oozcitak/util@10.0.0': {} + '@open-draft/deferred-promise@2.2.0': {} '@open-draft/logger@0.3.0': @@ -12823,6 +13238,8 @@ snapshots: dependencies: '@reflag/flag-evaluation': 1.0.0 + '@rolldown/pluginutils@1.0.0-rc.3': {} + '@rollup/pluginutils@5.3.0(rollup@4.59.0)': dependencies: '@types/estree': 1.0.8 @@ -13015,9 +13432,9 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-vercel@5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(rollup@4.59.0)': + '@sveltejs/adapter-vercel@5.10.3(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(rollup@4.59.0)': dependencies: - '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) '@vercel/nft': 0.30.3(rollup@4.59.0) esbuild: 0.25.11 transitivePeerDependencies: @@ -13025,11 +13442,11 @@ snapshots: - rollup - supports-color - '@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2))': + '@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.6(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 @@ -13042,16 +13459,16 @@ snapshots: set-cookie-parser: 3.0.1 sirv: 3.0.2 svelte: 5.41.3 - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.8.2 - '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.6.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2))': + '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.6.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -13063,16 +13480,16 @@ snapshots: set-cookie-parser: 3.0.1 sirv: 3.0.2 svelte: 5.41.3 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.6.3 - '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -13084,17 +13501,17 @@ snapshots: set-cookie-parser: 3.0.1 sirv: 3.0.2 svelte: 5.41.3 - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.8.2 optional: true - '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -13106,17 +13523,17 @@ snapshots: set-cookie-parser: 3.0.1 sirv: 3.0.2 svelte: 5.41.3 - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.8.2 optional: true - '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -13128,124 +13545,124 @@ snapshots: set-cookie-parser: 3.0.1 sirv: 3.0.2 svelte: 5.41.3 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) optionalDependencies: '@opentelemetry/api': 1.9.0 typescript: 5.9.3 optional: true - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)))(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)))(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) debug: 4.4.3 svelte: 5.41.3 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) debug: 4.4.3 svelte: 5.41.3 - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.41.3 - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color optional: true - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.41.3 - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color optional: true - '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte-inspector@3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte': 4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 svelte: 5.41.3 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color optional: true - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)))(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)))(svelte@5.41.3)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.41.3 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) - vitefu: 1.1.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + vitefu: 1.1.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.41.3 - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) - vitefu: 1.1.1(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) + vitefu: 1.1.1(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.41.3 - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) transitivePeerDependencies: - supports-color optional: true - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.41.3 - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) transitivePeerDependencies: - supports-color optional: true - '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/vite-plugin-svelte-inspector': 3.0.1(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.21 svelte: 5.41.3 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) + vitefu: 1.1.1(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) transitivePeerDependencies: - supports-color optional: true @@ -13516,13 +13933,137 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.0.15 - '@tailwindcss/vite@4.0.15(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2))': + '@tailwindcss/vite@4.0.15(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0))': dependencies: '@tailwindcss/node': 4.0.15 '@tailwindcss/oxide': 4.0.15 lightningcss: 1.29.2 tailwindcss: 4.0.15 - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) + + '@tanstack/history@1.162.0': {} + + '@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.162.0 + '@tanstack/react-store': 0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + isbot: 5.1.43 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/react-start-client@1.168.14(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/start-client-core': 1.170.12 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@tanstack/react-start-rsc@0.1.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-storage-context': 1.167.15 + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@rsbuild/core' + - crossws + - supports-color + - vite + - vite-plugin-solid + - webpack + + '@tanstack/react-start-rsc@0.1.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@tanstack/start-server-core': 1.169.15 + '@tanstack/start-storage-context': 1.167.15 + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - '@rsbuild/core' + - crossws + - supports-color + - vite + - vite-plugin-solid + - webpack + + '@tanstack/react-start-server@1.167.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.171.13 + '@tanstack/start-server-core': 1.169.15 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - crossws + + '@tanstack/react-start@1.168.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.168.14(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-rsc': 0.1.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + '@tanstack/react-start-server': 1.167.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + '@tanstack/start-server-core': 1.169.15 + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + transitivePeerDependencies: + - '@rspack/core' + - crossws + - react-server-dom-rspack + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/react-start@1.168.26(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': + dependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-client': 1.168.14(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-start-rsc': 0.1.25(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@tanstack/react-start-server': 1.167.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-plugin-core': 1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@tanstack/start-server-core': 1.169.15 + pathe: 2.0.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) + transitivePeerDependencies: + - '@rspack/core' + - crossws + - react-server-dom-rspack + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/react-store@0.9.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.9.3 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) '@tanstack/react-virtual@3.13.12(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: @@ -13530,8 +14071,166 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + '@tanstack/router-core@1.171.13': + dependencies: + '@tanstack/history': 1.162.0 + cookie-es: 3.1.1 + seroval: 1.5.4 + seroval-plugins: 1.5.4(seroval@1.5.4) + + '@tanstack/router-generator@1.167.17': + dependencies: + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-utils': 1.162.2 + '@tanstack/virtual-file-routes': 1.162.0 + jiti: 2.7.0 + magic-string: 0.30.21 + prettier: 3.8.4 + zod: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-utils': 1.162.2 + chokidar: 5.0.0 + unplugin: 3.0.0 + zod: 4.4.3 + optionalDependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-utils': 1.162.2 + chokidar: 5.0.0 + unplugin: 3.0.0 + zod: 4.4.3 + optionalDependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.162.2': + dependencies: + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + ansis: 4.3.1 + babel-dead-code-elimination: 1.0.12 + diff: 8.0.4 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + + '@tanstack/start-client-core@1.170.12': + dependencies: + '@tanstack/router-core': 1.171.13 + '@tanstack/start-fn-stubs': 1.162.0 + '@tanstack/start-storage-context': 1.167.15 + seroval: 1.5.4 + + '@tanstack/start-fn-stubs@1.162.0': {} + + '@tanstack/start-plugin-core@1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-plugin': 1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-server-core': 1.169.15 + exsolve: 1.1.0 + lightningcss: 1.32.0 + pathe: 2.0.3 + picomatch: 4.0.3 + seroval: 1.5.4 + source-map: 0.7.6 + srvx: 0.11.17 + tinyglobby: 0.2.15 + ufo: 1.6.3 + vitefu: 1.1.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) + xmlbuilder2: 4.0.3 + zod: 4.4.3 + optionalDependencies: + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + transitivePeerDependencies: + - '@tanstack/react-router' + - crossws + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/start-plugin-core@1.171.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/core': 7.29.0 + '@babel/types': 7.29.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/router-generator': 1.167.17 + '@tanstack/router-plugin': 1.168.18(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@tanstack/router-utils': 1.162.2 + '@tanstack/start-server-core': 1.169.15 + exsolve: 1.1.0 + lightningcss: 1.32.0 + pathe: 2.0.3 + picomatch: 4.0.3 + seroval: 1.5.4 + source-map: 0.7.6 + srvx: 0.11.17 + tinyglobby: 0.2.15 + ufo: 1.6.3 + vitefu: 1.1.1(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + xmlbuilder2: 4.0.3 + zod: 4.4.3 + optionalDependencies: + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) + transitivePeerDependencies: + - '@tanstack/react-router' + - crossws + - supports-color + - vite-plugin-solid + - webpack + + '@tanstack/start-server-core@1.169.15': + dependencies: + '@tanstack/history': 1.162.0 + '@tanstack/router-core': 1.171.13 + '@tanstack/start-client-core': 1.170.12 + '@tanstack/start-storage-context': 1.167.15 + fetchdts: 0.1.7 + h3-v2: h3@2.0.1-rc.20 + seroval: 1.5.4 + transitivePeerDependencies: + - crossws + + '@tanstack/start-storage-context@1.167.15': + dependencies: + '@tanstack/router-core': 1.171.13 + + '@tanstack/store@0.9.3': {} + '@tanstack/virtual-core@3.13.12': {} + '@tanstack/virtual-file-routes@1.162.0': {} + '@tinyhttp/accepts@1.3.0': dependencies: es-mime-types: 0.0.16 @@ -13827,15 +14526,15 @@ snapshots: '@types/unist@3.0.3': {} - '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/type-utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.1 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -13844,14 +14543,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.1 '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.1 debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -13874,13 +14573,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -13904,13 +14603,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) '@typescript-eslint/scope-manager': 8.46.1 '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -13989,32 +14688,32 @@ snapshots: optionalDependencies: next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@vercel/analytics@1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3)': + '@vercel/analytics@1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 svelte: 5.41.3 - '@vercel/analytics@1.6.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': + '@vercel/analytics@1.6.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 svelte: 5.41.3 optional: true - '@vercel/analytics@1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3)': + '@vercel/analytics@1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) react: 19.0.0-rc.1 svelte: 5.41.3 optional: true - '@vercel/analytics@1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': + '@vercel/analytics@1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 svelte: 5.41.3 @@ -14050,7 +14749,7 @@ snapshots: dependencies: '@vercel/oidc': 3.2.0 - '@vercel/geistdocs@1.8.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(unified@11.0.5)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1))': + '@vercel/geistdocs@1.8.0(@svta/cml-cta@1.0.1(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1))(@svta/cml-structured-field-values@1.0.1(@svta/cml-utils@1.0.1))(@svta/cml-utils@1.0.1)(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/mdast@4.0.4)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(micromark-util-types@2.0.2)(micromark@4.0.2)(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18)(unified@11.0.5)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': dependencies: '@ai-sdk/react': 3.0.208(react@19.2.4)(zod@4.3.6) '@clack/prompts': 0.11.0 @@ -14065,9 +14764,9 @@ snapshots: commander: 14.0.3 dexie: 4.3.0 dexie-react-hooks: 4.2.0(@types/react@19.2.14)(dexie@4.3.0)(react@19.2.4) - fumadocs-core: 16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - fumadocs-mdx: 14.0.4(fumadocs-core@16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) - fumadocs-ui: 16.2.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18) + fumadocs-core: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fumadocs-mdx: 14.0.4(fumadocs-core@16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + fumadocs-ui: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18) glob: 11.1.0 lucide-react: 0.555.0(react@19.2.4) mermaid: 11.12.2 @@ -14108,7 +14807,7 @@ snapshots: - vite - waku - '@vercel/microfrontends@1.1.0(0f6bdcb16ca33fd4d4a7a6778377aac0)': + '@vercel/microfrontends@1.1.0(5e695e95bd856e4a5cccdd7b48e1248c)': dependencies: ajv: 8.17.1 commander: 12.1.0 @@ -14119,17 +14818,17 @@ snapshots: nanoid: 3.3.11 path-to-regexp: 6.2.1 optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) - '@vercel/analytics': 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3) - '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3) - next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) - react: 19.0.0-rc.1 - react-dom: 19.0.0-rc.1(react@19.0.0-rc.1) - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@vercel/analytics': 1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) + '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) + next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - debug - '@vercel/microfrontends@1.1.0(46e20062f085152cc5929d2c51b95350)': + '@vercel/microfrontends@1.1.0(6c18ec6ca37694d8fda4040b542538f4)': dependencies: ajv: 8.17.1 commander: 12.1.0 @@ -14140,17 +14839,17 @@ snapshots: nanoid: 3.3.11 path-to-regexp: 6.2.1 optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) - '@vercel/analytics': 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) - '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) - next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) + '@vercel/analytics': 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3) + '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3) + next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) + react: 19.0.0-rc.1 + react-dom: 19.0.0-rc.1(react@19.0.0-rc.1) + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - debug - '@vercel/microfrontends@1.1.0(8fe6223b567b6ad42eaed06500731368)': + '@vercel/microfrontends@1.1.0(d61f01146c2ef5fb24ca3153124e8775)': dependencies: ajv: 8.17.1 commander: 12.1.0 @@ -14161,17 +14860,17 @@ snapshots: nanoid: 3.3.11 path-to-regexp: 6.2.1 optionalDependencies: - '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) - '@vercel/analytics': 1.6.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) - '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) + '@vercel/analytics': 1.6.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - debug - '@vercel/microfrontends@1.1.0(e11d9f19b9b209cd13851100642dec20)': + '@vercel/microfrontends@1.1.0(ddbcaeb0e7cf10b922b48b60c0a982eb)': dependencies: ajv: 8.17.1 commander: 12.1.0 @@ -14182,13 +14881,13 @@ snapshots: nanoid: 3.3.11 path-to-regexp: 6.2.1 optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) - '@vercel/analytics': 1.5.0(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) - '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3) - next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) + '@vercel/analytics': 1.6.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + '@vercel/speed-insights': 1.3.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3) + next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) transitivePeerDependencies: - debug @@ -14215,41 +14914,41 @@ snapshots: '@vercel/oidc@3.5.0': {} - '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': + '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)) + '@sveltejs/kit': 2.50.2(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)))(svelte@5.41.3)(typescript@5.8.2)(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 svelte: 5.41.3 optional: true - '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3)': + '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1))(react@19.0.0-rc.1)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) react: 19.0.0-rc.1 svelte: 5.41.3 optional: true - '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3)': + '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.8.2)(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 svelte: 5.41.3 optional: true - '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': + '@vercel/speed-insights@1.3.1(@sveltejs/kit@2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(svelte@5.41.3)': optionalDependencies: - '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)) + '@sveltejs/kit': 2.53.4(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@4.0.4(svelte@5.41.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)))(svelte@5.41.3)(typescript@5.9.3)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 svelte: 5.41.3 - '@vercel/toolbar@0.1.36(0f6bdcb16ca33fd4d4a7a6778377aac0)': + '@vercel/toolbar@0.1.36(5e695e95bd856e4a5cccdd7b48e1248c)': dependencies: '@tinyhttp/app': 1.3.0 - '@vercel/microfrontends': 1.1.0(0f6bdcb16ca33fd4d4a7a6778377aac0) + '@vercel/microfrontends': 1.1.0(5e695e95bd856e4a5cccdd7b48e1248c) chokidar: 3.6.0 execa: 5.1.1 fast-glob: 3.3.3 @@ -14258,9 +14957,9 @@ snapshots: jsonc-parser: 3.3.1 strip-ansi: 6.0.1 optionalDependencies: - next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) - react: 19.0.0-rc.1 - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) + next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - '@sveltejs/kit' - '@vercel/analytics' @@ -14268,10 +14967,10 @@ snapshots: - debug - react-dom - '@vercel/toolbar@0.1.36(46e20062f085152cc5929d2c51b95350)': + '@vercel/toolbar@0.1.36(6c18ec6ca37694d8fda4040b542538f4)': dependencies: '@tinyhttp/app': 1.3.0 - '@vercel/microfrontends': 1.1.0(46e20062f085152cc5929d2c51b95350) + '@vercel/microfrontends': 1.1.0(6c18ec6ca37694d8fda4040b542538f4) chokidar: 3.6.0 execa: 5.1.1 fast-glob: 3.3.3 @@ -14280,9 +14979,9 @@ snapshots: jsonc-parser: 3.3.1 strip-ansi: 6.0.1 optionalDependencies: - next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.0.0-rc.1(react@19.0.0-rc.1))(react@19.0.0-rc.1) + react: 19.0.0-rc.1 + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - '@sveltejs/kit' - '@vercel/analytics' @@ -14290,10 +14989,10 @@ snapshots: - debug - react-dom - '@vercel/toolbar@0.1.36(8fe6223b567b6ad42eaed06500731368)': + '@vercel/toolbar@0.1.36(d61f01146c2ef5fb24ca3153124e8775)': dependencies: '@tinyhttp/app': 1.3.0 - '@vercel/microfrontends': 1.1.0(8fe6223b567b6ad42eaed06500731368) + '@vercel/microfrontends': 1.1.0(d61f01146c2ef5fb24ca3153124e8775) chokidar: 3.6.0 execa: 5.1.1 fast-glob: 3.3.3 @@ -14304,7 +15003,7 @@ snapshots: optionalDependencies: next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - '@sveltejs/kit' - '@vercel/analytics' @@ -14312,10 +15011,10 @@ snapshots: - debug - react-dom - '@vercel/toolbar@0.1.36(e11d9f19b9b209cd13851100642dec20)': + '@vercel/toolbar@0.1.36(ddbcaeb0e7cf10b922b48b60c0a982eb)': dependencies: '@tinyhttp/app': 1.3.0 - '@vercel/microfrontends': 1.1.0(e11d9f19b9b209cd13851100642dec20) + '@vercel/microfrontends': 1.1.0(ddbcaeb0e7cf10b922b48b60c0a982eb) chokidar: 3.6.0 execa: 5.1.1 fast-glob: 3.3.3 @@ -14324,9 +15023,9 @@ snapshots: jsonc-parser: 3.3.1 strip-ansi: 6.0.1 optionalDependencies: - next: 16.1.5(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) transitivePeerDependencies: - '@sveltejs/kit' - '@vercel/analytics' @@ -14339,14 +15038,26 @@ snapshots: native-promise-only: 0.8.1 weakmap-polyfill: 2.0.4 - '@vitejs/plugin-react@4.2.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2))': + '@vitejs/plugin-react@4.2.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-react@5.2.0(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -14363,14 +15074,14 @@ snapshots: chai: 5.3.3 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.9(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2))': + '@vitest/mocker@2.1.9(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.6.4(@types/node@20.11.17)(typescript@5.6.3) - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) '@vitest/pretty-format@2.1.9': dependencies: @@ -14480,6 +15191,8 @@ snapshots: ansi-styles@6.2.3: {} + ansis@4.3.1: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -14600,6 +15313,15 @@ snapshots: axobject-query@4.1.0: {} + babel-dead-code-elimination@1.0.12: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -14875,6 +15597,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-es@3.1.1: {} + cookie@0.4.0: {} cookie@0.6.0: {} @@ -15224,6 +15948,8 @@ snapshots: diff-sequences@29.6.3: {} + diff@8.0.4: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -15556,18 +16282,18 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.2.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@16.2.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.2.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.38.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 7.0.1(eslint@9.38.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.38.0(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.38.0(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.0.1(eslint@9.38.0(jiti@2.7.0)) globals: 16.4.0 - typescript-eslint: 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + typescript-eslint: 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -15584,33 +16310,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0(jiti@2.7.0)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) get-tsconfig: 4.13.6 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.7.0)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.38.0(jiti@2.7.0) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.38.0(jiti@2.7.0)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.7.0)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -15619,9 +16345,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@2.7.0)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -15633,13 +16359,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.38.0(jiti@2.7.0)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -15649,7 +16375,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -15658,18 +16384,18 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@7.0.1(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-react-hooks@7.0.1(eslint@9.38.0(jiti@2.7.0)): dependencies: '@babel/core': 7.29.0 '@babel/parser': 7.29.0 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) hermes-parser: 0.25.1 zod: 4.3.6 zod-validation-error: 4.0.2(zod@4.3.6) transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@9.38.0(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.38.0(jiti@2.7.0)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -15677,7 +16403,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.3.1 - eslint: 9.38.0(jiti@2.6.1) + eslint: 9.38.0(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -15700,9 +16426,9 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.38.0(jiti@2.6.1): + eslint@9.38.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.38.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.2 '@eslint/config-helpers': 0.4.2 @@ -15737,7 +16463,7 @@ snapshots: natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color @@ -15838,6 +16564,8 @@ snapshots: expect-type@1.3.0: {} + exsolve@1.1.0: {} + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -15882,6 +16610,8 @@ snapshots: dependencies: xml-js: 1.6.11 + fetchdts@0.1.7: {} + fflate@0.8.2: {} file-entry-cache@8.0.0: @@ -15976,7 +16706,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + fumadocs-core@16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: '@formatjs/intl-localematcher': 0.6.2 '@orama/orama': 3.1.18 @@ -15997,6 +16727,7 @@ snapshots: shiki: 3.22.0 unist-util-visit: 5.0.0 optionalDependencies: + '@tanstack/react-router': 1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@types/react': 19.2.14 lucide-react: 0.555.0(react@19.2.4) next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -16005,14 +16736,14 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@14.0.4(fumadocs-core@16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)): + fumadocs-mdx@14.0.4(fumadocs-core@16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.0.0 chokidar: 5.0.0 esbuild: 0.27.2 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fumadocs-core: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) js-yaml: 4.1.1 lru-cache: 11.2.2 mdast-util-to-markdown: 2.1.2 @@ -16029,11 +16760,11 @@ snapshots: optionalDependencies: next: 16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) react: 19.2.4 - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - fumadocs-ui@16.2.2(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18): + fumadocs-ui@16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tailwindcss@4.1.18): dependencies: '@radix-ui/react-accordion': 1.2.12(@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) '@radix-ui/react-collapsible': 1.1.12(@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) @@ -16046,7 +16777,7 @@ snapshots: '@radix-ui/react-slot': 1.2.4(@types/react@19.2.14)(react@19.2.4) '@radix-ui/react-tabs': 1.1.13(@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) class-variance-authority: 0.7.1 - fumadocs-core: 16.2.2(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + fumadocs-core: 16.2.2(@tanstack/react-router@1.170.16(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.14)(lucide-react@0.555.0(react@19.2.4))(next@16.2.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) lodash.merge: 4.6.2 next-themes: 0.4.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4) postcss-selector-parser: 7.1.1 @@ -16196,6 +16927,11 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 + h3@2.0.1-rc.20: + dependencies: + rou3: 0.8.1 + srvx: 0.11.17 + hachure-fill@0.5.2: {} has-bigints@1.1.0: {} @@ -16598,6 +17334,8 @@ snapshots: isarray@2.0.5: {} + isbot@5.1.43: {} + isexe@2.0.0: {} iterator.prototype@1.1.5: @@ -16623,6 +17361,8 @@ snapshots: jiti@2.6.1: {} + jiti@2.7.0: {} + jose@5.10.0: {} jose@5.2.1: {} @@ -16733,66 +17473,99 @@ snapshots: lightningcss-android-arm64@1.30.2: optional: true + lightningcss-android-arm64@1.32.0: + optional: true + lightningcss-darwin-arm64@1.29.2: optional: true lightningcss-darwin-arm64@1.30.2: optional: true + lightningcss-darwin-arm64@1.32.0: + optional: true + lightningcss-darwin-x64@1.29.2: optional: true lightningcss-darwin-x64@1.30.2: optional: true + lightningcss-darwin-x64@1.32.0: + optional: true + lightningcss-freebsd-x64@1.29.2: optional: true lightningcss-freebsd-x64@1.30.2: optional: true + lightningcss-freebsd-x64@1.32.0: + optional: true + lightningcss-linux-arm-gnueabihf@1.29.2: optional: true lightningcss-linux-arm-gnueabihf@1.30.2: optional: true + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + lightningcss-linux-arm64-gnu@1.29.2: optional: true lightningcss-linux-arm64-gnu@1.30.2: optional: true + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + lightningcss-linux-arm64-musl@1.29.2: optional: true lightningcss-linux-arm64-musl@1.30.2: optional: true + lightningcss-linux-arm64-musl@1.32.0: + optional: true + lightningcss-linux-x64-gnu@1.29.2: optional: true lightningcss-linux-x64-gnu@1.30.2: optional: true + lightningcss-linux-x64-gnu@1.32.0: + optional: true + lightningcss-linux-x64-musl@1.29.2: optional: true lightningcss-linux-x64-musl@1.30.2: optional: true + lightningcss-linux-x64-musl@1.32.0: + optional: true + lightningcss-win32-arm64-msvc@1.29.2: optional: true lightningcss-win32-arm64-msvc@1.30.2: optional: true + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + lightningcss-win32-x64-msvc@1.29.2: optional: true lightningcss-win32-x64-msvc@1.30.2: optional: true + lightningcss-win32-x64-msvc@1.32.0: + optional: true + lightningcss@1.29.2: dependencies: detect-libc: 2.1.2 @@ -16824,6 +17597,22 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + lilconfig@3.0.0: {} lilconfig@3.1.3: {} @@ -18157,11 +18946,11 @@ snapshots: postcss: 8.5.8 yaml: 2.8.1 - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.1): + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.8)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 postcss: 8.5.8 yaml: 2.8.1 @@ -18215,6 +19004,8 @@ snapshots: prettier@2.8.8: {} + prettier@3.8.4: {} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 @@ -18372,6 +19163,8 @@ snapshots: react-refresh@0.14.2: {} + react-refresh@0.18.0: {} + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.0.0-rc.1): dependencies: react: 19.0.0-rc.1 @@ -18708,6 +19501,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + rou3@0.8.1: {} + roughjs@4.6.6: dependencies: hachure-fill: 0.5.2 @@ -18773,6 +19568,12 @@ snapshots: semver@7.7.4: {} + seroval-plugins@1.5.4(seroval@1.5.4): + dependencies: + seroval: 1.5.4 + + seroval@1.5.4: {} + set-cookie-parser@3.0.1: {} set-function-length@1.2.2: @@ -18938,6 +19739,8 @@ snapshots: sprintf-js@1.0.3: {} + srvx@0.11.17: {} + stable-hash@0.0.5: {} stackback@0.0.2: {} @@ -19331,7 +20134,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1): + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.6.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -19342,7 +20145,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.8)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -19359,7 +20162,7 @@ snapshots: - tsx - yaml - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.8)(typescript@5.8.2)(yaml@2.8.1): + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.8)(typescript@5.8.2)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.27.3) cac: 6.7.14 @@ -19370,7 +20173,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.8)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.8)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.59.0 source-map: 0.7.6 @@ -19459,13 +20262,13 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3))(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.38.0(jiti@2.6.1) + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.38.0(jiti@2.7.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -19551,6 +20354,12 @@ snapshots: universalify@0.2.0: {} + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -19668,13 +20477,13 @@ snapshots: dependencies: '@vimeo/player': 2.29.0 - vite-node@1.6.1(@types/node@20.11.17)(lightningcss@1.30.2): + vite-node@1.6.1(@types/node@20.11.17)(lightningcss@1.32.0): dependencies: cac: 6.7.14 debug: 4.4.3 pathe: 1.1.2 picocolors: 1.1.1 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - less @@ -19686,13 +20495,13 @@ snapshots: - supports-color - terser - vite-node@1.6.1(@types/node@22.14.0)(lightningcss@1.30.2): + vite-node@1.6.1(@types/node@22.14.0)(lightningcss@1.32.0): dependencies: cac: 6.7.14 debug: 4.4.3 pathe: 1.1.2 picocolors: 1.1.1 - vite: 5.4.21(@types/node@22.14.0)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@22.14.0)(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - less @@ -19704,13 +20513,13 @@ snapshots: - supports-color - terser - vite-node@2.1.9(@types/node@20.11.17)(lightningcss@1.30.2): + vite-node@2.1.9(@types/node@20.11.17)(lightningcss@1.32.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 1.1.2 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) transitivePeerDependencies: - '@types/node' - less @@ -19722,7 +20531,7 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2): + vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0): dependencies: esbuild: 0.21.5 postcss: 8.5.8 @@ -19730,9 +20539,9 @@ snapshots: optionalDependencies: '@types/node': 20.11.17 fsevents: 2.3.3 - lightningcss: 1.30.2 + lightningcss: 1.32.0 - vite@5.4.21(@types/node@22.14.0)(lightningcss@1.30.2): + vite@5.4.21(@types/node@22.14.0)(lightningcss@1.32.0): dependencies: esbuild: 0.21.5 postcss: 8.5.8 @@ -19740,9 +20549,9 @@ snapshots: optionalDependencies: '@types/node': 22.14.0 fsevents: 2.3.3 - lightningcss: 1.30.2 + lightningcss: 1.32.0 - vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2): + vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0): dependencies: esbuild: 0.21.5 postcss: 8.5.8 @@ -19750,9 +20559,9 @@ snapshots: optionalDependencies: '@types/node': 24.10.13 fsevents: 2.3.3 - lightningcss: 1.30.2 + lightningcss: 1.32.0 - vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1): + vite@6.4.1(@types/node@20.11.17)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -19763,12 +20572,11 @@ snapshots: optionalDependencies: '@types/node': 20.11.17 fsevents: 2.3.3 - jiti: 1.21.7 - lightningcss: 1.30.2 + jiti: 2.7.0 + lightningcss: 1.32.0 yaml: 2.8.1 - optional: true - vite@6.4.1(@types/node@20.11.17)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1): + vite@6.4.1(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -19776,16 +20584,32 @@ snapshots: postcss: 8.5.8 rollup: 4.59.0 tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.14.0 + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + yaml: 2.8.1 + + vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.8 + rollup: 4.59.0 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 20.11.17 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + jiti: 1.21.7 + lightningcss: 1.32.0 yaml: 2.8.1 + optional: true - vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1): + vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 @@ -19794,13 +20618,14 @@ snapshots: optionalDependencies: '@types/node': 22.14.0 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + jiti: 2.7.0 + lightningcss: 1.32.0 yaml: 2.8.1 + optional: true - vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1): + vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 @@ -19809,35 +20634,33 @@ snapshots: optionalDependencies: '@types/node': 24.10.13 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + jiti: 2.7.0 + lightningcss: 1.32.0 yaml: 2.8.1 - optional: true - vitefu@1.1.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)): + vitefu@1.1.1(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)): optionalDependencies: - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) - vitefu@1.1.1(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.30.2)): + vitefu@1.1.1(vite@5.4.21(@types/node@24.10.13)(lightningcss@1.32.0)): optionalDependencies: - vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@24.10.13)(lightningcss@1.32.0) - vitefu@1.1.1(vite@6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1)): + vitefu@1.1.1(vite@7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1)): optionalDependencies: - vite: 6.4.1(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@20.11.17)(jiti@1.21.7)(lightningcss@1.32.0)(yaml@2.8.1) optional: true - vitefu@1.1.1(vite@6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)): + vitefu@1.1.1(vite@7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)): optionalDependencies: - vite: 6.4.1(@types/node@22.14.0)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) + vite: 7.3.5(@types/node@22.14.0)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) optional: true - vitefu@1.1.1(vite@6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1)): + vitefu@1.1.1(vite@7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1)): optionalDependencies: - vite: 6.4.1(@types/node@24.10.13)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.1) - optional: true + vite: 7.3.5(@types/node@24.10.13)(jiti@2.7.0)(lightningcss@1.32.0)(yaml@2.8.1) - vitest@1.6.1(@types/node@20.11.17)(lightningcss@1.30.2): + vitest@1.6.1(@types/node@20.11.17)(lightningcss@1.32.0): dependencies: '@vitest/expect': 1.6.1 '@vitest/runner': 1.6.1 @@ -19856,8 +20679,8 @@ snapshots: strip-literal: 2.1.1 tinybench: 2.9.0 tinypool: 0.8.4 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) - vite-node: 1.6.1(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + vite-node: 1.6.1(@types/node@20.11.17)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.11.17 @@ -19871,7 +20694,7 @@ snapshots: - supports-color - terser - vitest@1.6.1(@types/node@22.14.0)(lightningcss@1.30.2): + vitest@1.6.1(@types/node@22.14.0)(lightningcss@1.32.0): dependencies: '@vitest/expect': 1.6.1 '@vitest/runner': 1.6.1 @@ -19890,8 +20713,8 @@ snapshots: strip-literal: 2.1.1 tinybench: 2.9.0 tinypool: 0.8.4 - vite: 5.4.21(@types/node@22.14.0)(lightningcss@1.30.2) - vite-node: 1.6.1(@types/node@22.14.0)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@22.14.0)(lightningcss@1.32.0) + vite-node: 1.6.1(@types/node@22.14.0)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.14.0 @@ -19905,10 +20728,10 @@ snapshots: - supports-color - terser - vitest@2.1.9(@types/node@20.11.17)(lightningcss@1.30.2)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)): + vitest@2.1.9(@types/node@20.11.17)(lightningcss@1.32.0)(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3)): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.30.2)) + '@vitest/mocker': 2.1.9(msw@2.6.4(@types/node@20.11.17)(typescript@5.6.3))(vite@5.4.21(@types/node@20.11.17)(lightningcss@1.32.0)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -19924,8 +20747,8 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.30.2) - vite-node: 2.1.9(@types/node@20.11.17)(lightningcss@1.30.2) + vite: 5.4.21(@types/node@20.11.17)(lightningcss@1.32.0) + vite-node: 2.1.9(@types/node@20.11.17)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.11.17 @@ -19963,6 +20786,8 @@ snapshots: webidl-conversions@3.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -20052,6 +20877,13 @@ snapshots: dependencies: sax: 1.4.4 + xmlbuilder2@4.0.3: + dependencies: + '@oozcitak/dom': 2.0.2 + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 + js-yaml: 4.1.1 + y18n@5.0.8: {} yallist@3.1.1: {} @@ -20105,4 +20937,6 @@ snapshots: zod@4.3.6: {} + zod@4.4.3: {} + zwitch@2.0.4: {} From 718c213736aba78076235d2d72193f0e80769b1f Mon Sep 17 00:00:00 2001 From: Carlos Ricardo Ziegler <38855507+CarlosZiegler@users.noreply.github.com> Date: Thu, 25 Jun 2026 08:11:45 +0200 Subject: [PATCH 2/2] docs: add doc about tanstack start usage --- .../frameworks/tanstack-start.mdx | 124 +++++++ .../tanstack-start/evaluation-context.mdx | 136 +++++++ .../tanstack-start/guides/dashboard-pages.mdx | 77 ++++ .../tanstack-start/guides/marketing-pages.mdx | 145 ++++++++ .../tanstack-start/guides/meta.json | 3 + .../docs/frameworks/tanstack-start/index.mdx | 216 +++++++++++ .../docs/frameworks/tanstack-start/meta.json | 14 + .../frameworks/tanstack-start/precompute.mdx | 152 ++++++++ apps/docs/content/docs/meta.json | 1 + apps/docs/geistdocs.tsx | 4 +- skills/flags-sdk/SKILL.md | 29 +- skills/flags-sdk/references/tanstack-start.md | 341 ++++++++++++++++++ 12 files changed, 1236 insertions(+), 6 deletions(-) create mode 100644 apps/docs/content/docs/api-reference/frameworks/tanstack-start.mdx create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/evaluation-context.mdx create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/guides/dashboard-pages.mdx create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/guides/marketing-pages.mdx create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/guides/meta.json create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/index.mdx create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/meta.json create mode 100644 apps/docs/content/docs/frameworks/tanstack-start/precompute.mdx create mode 100644 skills/flags-sdk/references/tanstack-start.md diff --git a/apps/docs/content/docs/api-reference/frameworks/tanstack-start.mdx b/apps/docs/content/docs/api-reference/frameworks/tanstack-start.mdx new file mode 100644 index 00000000..55f5c78f --- /dev/null +++ b/apps/docs/content/docs/api-reference/frameworks/tanstack-start.mdx @@ -0,0 +1,124 @@ +--- +title: 'flags/tanstack-start' +description: APIs for working with feature flags in TanStack Start. +--- + +### `flag` + +**Description**: Declares a feature flag. + +A feature flag declared this way will automatically respect overrides set by Vercel Toolbar and integrate with Runtime Logs, Web Analytics, and more. + +| Parameter | Type | Description | +| ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------- | +| `key` | `string` | Key of the feature flag. | +| `decide` | `function` | Resolves the value of the feature flag. | +| `description` (Optional) | `string` | Description of the feature flag. | +| `origin` (Optional) | `string` | The URL where this feature flag can be managed. | +| `options` (Optional) | `{ label?: string, value: any }[]` | Possible values a feature flag can resolve to, which are displayed in Vercel Toolbar. | +| `identify` (Optional) | `function` | Provide an evaluation context which will be passed to `decide`. | +| `defaultValue` (Optional)| `any` | Returned when `decide` (or the adapter) resolves to `undefined`. | +| `adapter` (Optional) | `Adapter` | A provider adapter implementing `decide` and `origin`. | + +The `key`, `description`, `origin`, and `options` appear in Vercel Toolbar. + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const showSummerSale = flag({ + key: 'summer-sale', + async decide() { + return false; + }, + origin: 'https://example.com/flags/summer-sale/', + description: 'Show Summer Holiday Sale Banner, 20% off', + options: [ + // options are not necessary for boolean flags, but we customize their labels here + { value: false, label: 'Hide' }, + { value: true, label: 'Show' }, + ], +}); +``` + +#### Calling the flag + +The function returned by `flag` can be called in two ways: + +| Call signature | Description | +| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `flag()` | Evaluates the flag. The request is resolved automatically via TanStack Start's `getRequest()`. Use inside a loader, server function, or server route. | +| `flag(request, secret?)` | Evaluates the flag against an explicit `Request`. Use when evaluating outside of a request context. | +| `flag(code, flagsArray, secret?)` | Reads a precomputed value out of `code` instead of running `decide`. See [`precompute`](#precompute). | + +`decide` and `identify` are deduplicated per request, so calling the same flag multiple times within one request only evaluates it once. + +### `getProviderData` + +**Description**: Turns flags declared using `flag` into Vercel Toolbar compatible definitions. + +| Parameter | Type | Description | +| --------- | ---------------------- | ------------------------------------------------------------------- | +| `flags` | `Record` | A record where the values are feature flags. The keys are not used. | + +### `createFlagsDiscoveryEndpoint` + +**Description**: Creates a handler for the `/.well-known/vercel/flags` discovery endpoint. It verifies the Vercel Toolbar's authenticated request and responds with the provided API data. Wire it up as a TanStack Start server route. + +| Parameter | Type | Description | +| ------------------- | ---------------------------------------------------------- | -------------------------------------------------------- | +| `getApiData` | `(context) => ApiData \| Promise` | Returns the API data, typically via `getProviderData`. | +| `options` (Optional)| `{ secret?: string }` | The `FLAGS_SECRET` used to verify access. Defaults to the `FLAGS_SECRET` environment variable. | + +```ts title="src/routes/[.]well-known/vercel/flags.ts" +import { createFileRoute } from '@tanstack/react-router'; +import { + createFlagsDiscoveryEndpoint, + getProviderData, +} from 'flags/tanstack-start'; +import * as flags from '../../../flags'; + +const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + +export const Route = createFileRoute('/.well-known/vercel/flags')({ + server: { handlers: { GET: handler } }, +}); +``` + +## Precomputation + +These APIs are relevant for [precomputing feature flags](/principles/precompute). See the [marketing pages guide](/frameworks/tanstack-start/guides/marketing-pages) to learn how to use them in TanStack Start. + +### `precompute` + +**Description**: Evaluates multiple feature flags. Returns their values encoded into a single signed string. + +| Parameter | Type | Description | +| ------------------- | ------------ | ---------------------------------------------------------------------------------------- | +| `flags` | `function[]` | The flags to precompute. | +| `request` | `Request` | The incoming request used to evaluate the flags. | +| `secret` (Optional) | `string` | The secret used to sign the generated code. Defaults to the `FLAGS_SECRET` env variable. | + +Read the encoded values back by calling a flag with the generated code and the same flags array: `await myFlag(code, flags)`. + +### `generatePermutations` + +**Description**: Calculates all precomputations of the options of the provided flags. Useful when you want to prerender or statically cache every variant of a page. + +| Parameter | Type | Description | +| ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------- | +| `flags` | `function[]` | The flags. | +| `filter` (Optional) | `function` | Called with every possible permutation of the flags' options. Return `true` to keep the permutation. | +| `secret` (Optional) | `string` | The secret used to sign the generated codes. Defaults to the `FLAGS_SECRET` env variable. | + +## Encryption + +These functions keep flag data confidential (used by the Flags Explorer). All of them default to the `FLAGS_SECRET` environment variable when no secret is passed. + +| Function | Description | +| ------------------------- | ------------------------------------ | +| `encryptFlagValues` | Encrypt resolved flag values. | +| `decryptFlagValues` | Decrypt flag values. | +| `encryptFlagDefinitions` | Encrypt flag definitions/metadata. | +| `decryptFlagDefinitions` | Decrypt flag definitions. | +| `encryptOverrides` | Encrypt toolbar overrides. | +| `decryptOverrides` | Decrypt toolbar overrides. | diff --git a/apps/docs/content/docs/frameworks/tanstack-start/evaluation-context.mdx b/apps/docs/content/docs/frameworks/tanstack-start/evaluation-context.mdx new file mode 100644 index 00000000..95fa84df --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/evaluation-context.mdx @@ -0,0 +1,136 @@ +--- +title: Evaluation Context +description: Segment by any criteria, using an evaluation context +--- + +It is common for features to be on for some users, but off for others. +For example team members working on a new setting might need to see and +use the setting, while the rest of the team need the setting to be +hidden. + +The `flag` declaration accepts an `identify` +function. The entities returned from the `identify` function +are passed as an argument to the `decide` function. + +## Example + +A trivial case to illustrate the concept: + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const exampleFlag = flag({ + key: 'identify-example-flag', + identify() { + return { user: { id: 'user1' } }; + }, + decide({ entities }) { + return entities?.user?.id === 'user1'; + }, +}); +``` + +Having first-class support for an evaluation context allows decoupling +the identifying step from the decision making step. + +## Type safety + +The entities can be typed using the `flag` function. + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +interface Entities { + user?: { id: string }; +} + +export const exampleFlag = flag({ + key: 'identify-example-flag', + identify() { + return { user: { id: 'user1' } }; + }, + decide({ entities }) { + return entities?.user?.id === 'user1'; + }, +}); +``` + +## Headers and Cookies + +The `identify` function is called with `headers`{" "} +and `cookies` arguments, which is useful when dealing with +anonymous or authenticated users. + +The arguments are normalized to a common format, so the same flag can be +used in Routing Middleware and within TanStack Start server contexts (route +loaders, server functions, server routes) without having to worry about the +differences in how `headers` and `cookies` are represented there. + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const exampleFlag = flag({ + // ... + identify({ headers, cookies }) { + // access to normalized headers and cookies here + headers.get('auth'); + cookies.get('auth')?.value; + // ... + }, + // ... +}); +``` + +## Deduplication + +Calls to `identify` are deduped based on the object identity of the passed function. That means, in order to ensure that an `identify` function is only called once per request, +make sure to extract it to a named function and reuse it across your flags. + +```ts title="src/flags.ts" +import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags'; +import { flag } from 'flags/tanstack-start'; + +interface Entities { + visitorId?: string; +} + +function identify({ + cookies, + headers, +}: { + cookies: ReadonlyRequestCookies; + headers: ReadonlyHeaders; +}): Entities { + const visitorId = + cookies.get('visitorId')?.value ?? headers.get('x-visitor-id'); + + return { visitorId }; +} + +export const exampleFlag1 = flag({ + key: 'exampleFlag1', + identify, + decide({ entities }) { + // ... + }, +}); + +export const exampleFlag2 = flag({ + key: 'exampleFlag2', + identify, + decide({ entities }) { + // ... + }, +}); +``` + +## Precomputing and targeting + +The [Marketing Pages](/frameworks/tanstack-start/guides/marketing-pages) example shows how to identify and target users using cookies when +precomputing pages. + +### Full example + + + See the Marketing Pages example + diff --git a/apps/docs/content/docs/frameworks/tanstack-start/guides/dashboard-pages.mdx b/apps/docs/content/docs/frameworks/tanstack-start/guides/dashboard-pages.mdx new file mode 100644 index 00000000..28fc98ed --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/guides/dashboard-pages.mdx @@ -0,0 +1,77 @@ +--- +title: Dashboard Pages +description: Use feature flags on dynamic pages. +--- + +Dashboard pages are rendered at request time, and may require authenticated +users. + +The example below shows how to use feature flags to show a feature to +specific users on a dashboard page. They are flagged in based on a specific cookie. + +## Definition + +The example works by first defining a feature flag that reads from a cookie. + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const showNewDashboard = flag({ + key: 'showNewDashboard', + decide({ cookies }) { + return cookies.get('showNewDashboard')?.value === 'true'; + }, +}); +``` + +The example reads the value directly from the cookie. In a real +dashboard you would likely read a signed JWT instead. + +## Usage + +Flags are evaluated on the server. Wrap the evaluation in a `createServerFn()` +server function and call it from the route loader — this keeps the flag working +during client-side navigation as well as on the initial server render. + +```tsx title="src/routes/dashboard.tsx" +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { showNewDashboard } from '../flags'; + +const getDashboardFlags = createServerFn().handler(async () => { + return { showNewDashboard: await showNewDashboard() }; +}); + +export const Route = createFileRoute('/dashboard')({ + loader: () => getDashboardFlags(), + component: Dashboard, +}); + +function Dashboard() { + const { showNewDashboard } = Route.useLoaderData(); + + return ( +
+

Dashboard

+ {showNewDashboard ? ( +

You are seeing the new dashboard.

+ ) : ( +

You are seeing the old dashboard.

+ )} +
+ ); +} +``` + +Inside the server function the flag is called with no arguments — the request is +resolved automatically through TanStack Start's `getRequest()`. Since dashboard +pages are typically dynamic anyhow, the async call to evaluate the feature flag +fits right in. + +## Evaluation Context + +Feature flags used on dashboards will usually run in the Serverless +Function Region, close to the database. This means it is acceptable for +a feature flag's `decide` function to read the database +when establishing the evaluation context. However, ideally, it would +only read from the JWT as this leads to lower overall latency. diff --git a/apps/docs/content/docs/frameworks/tanstack-start/guides/marketing-pages.mdx b/apps/docs/content/docs/frameworks/tanstack-start/guides/marketing-pages.mdx new file mode 100644 index 00000000..6712574d --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/guides/marketing-pages.mdx @@ -0,0 +1,145 @@ +--- +title: Marketing Pages +description: Use feature flags on static pages. +--- + +This example shows how to use feature flags for marketing pages. +Marketing pages are typically static, and served from a CDN at the edge. + +When A/B testing on marketing pages it's important to avoid layout +shift and jank, and to keep the pages static. At first glance this seems +at odds with the dynamic nature of feature flags. This example shows +how to keep a page static and serveable from the CDN even when running +multiple A/B tests on the page. + +## Precomputing + +The approach used to keep pages static even when using feature flags on them is described in more detail in the Precompute section. +At a high level you evaluate the flags once on the server, encode their values into a short signed code, and route to a dynamic `/marketing/$code` segment that reads those values back cheaply. +Because the code is deterministic for a given set of flag values, the `/marketing/$code` page can be cached and served statically. + + + Learn more about `precompute` + + +## Identifying + +This example uses a stable visitor id to target users. The `identify` function +reads it from a cookie (falling back to a header, which is useful when the +visitor id is generated in middleware before the cookie has been set). By making +`identify` a shared, named function its call is deduplicated between flags — +`identify` runs only once per request. + +```ts title="src/flags.ts" +import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags'; +import { flag } from 'flags/tanstack-start'; + +interface Entities { + visitorId?: string; +} + +function identify({ + cookies, + headers, +}: { + cookies: ReadonlyRequestCookies; + headers: ReadonlyHeaders; +}): Entities { + const visitorId = + cookies.get('visitorId')?.value ?? + headers.get('x-visitor-id') ?? + 'demo-visitor'; + + return { visitorId }; +} + +export const firstMarketingABTest = flag({ + key: 'firstMarketingABTest', + description: 'Example of a precomputed flag', + identify, + decide({ entities }) { + if (!entities?.visitorId) return false; + // Any deterministic function of the visitorId works here. + return /^[a-m0-4]/i.test(entities.visitorId); + }, +}); + +export const secondMarketingABTest = flag({ + key: 'secondMarketingABTest', + description: 'Example of a precomputed flag', + identify, + decide({ entities }) { + if (!entities?.visitorId) return false; + return /[a-m0-4]$/i.test(entities.visitorId); + }, +}); +``` + + + Learn more about `identify` + + +## Precompute and read the values + +Group the flags into an array and precompute them into a signed code, then read +the values back from the dynamic `$code` route. + +```ts title="src/precomputed-flags.ts" +import { precompute } from 'flags/tanstack-start'; +import { firstMarketingABTest, secondMarketingABTest } from './flags'; + +export const marketingFlags = [ + firstMarketingABTest, + secondMarketingABTest, +] as const; + +export async function precomputeMarketing(request: Request): Promise { + return precompute(marketingFlags, request); +} +``` + +```tsx title="src/routes/marketing.$code.tsx" +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { firstMarketingABTest, secondMarketingABTest } from '../flags'; +import { marketingFlags } from '../precomputed-flags'; + +const getMarketingFlags = createServerFn() + .validator((code: string) => code) + .handler(async ({ data: code }) => { + return { + first: await firstMarketingABTest(code, marketingFlags), + second: await secondMarketingABTest(code, marketingFlags), + }; + }); + +export const Route = createFileRoute('/marketing/$code')({ + loader: ({ params }) => getMarketingFlags({ data: params.code }), + component: MarketingPage, +}); + +function MarketingPage() { + const { first, second } = Route.useLoaderData(); + return ( +
    +
  • firstMarketingABTest: {String(first)}
  • +
  • secondMarketingABTest: {String(second)}
  • +
+ ); +} +``` + +## Ensuring the generated id is always available + +When a user visits the page for the first time they will not have the +`visitorId` cookie yet. If you generate the id in Routing Middleware, the page +will not see the freshly generated cookie because cookies are only supplied with +the *next* request. To solve this, set an `x-visitor-id` request header from the +middleware in addition to the cookie. The `identify` function above reads from +both, so it always sees the id — whether from the cookie or the header. + +## Full example + + + See the TanStack Start example app + diff --git a/apps/docs/content/docs/frameworks/tanstack-start/guides/meta.json b/apps/docs/content/docs/frameworks/tanstack-start/guides/meta.json new file mode 100644 index 00000000..49b33cc2 --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/guides/meta.json @@ -0,0 +1,3 @@ +{ + "defaultOpen": true +} diff --git a/apps/docs/content/docs/frameworks/tanstack-start/index.mdx b/apps/docs/content/docs/frameworks/tanstack-start/index.mdx new file mode 100644 index 00000000..c3944c59 --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/index.mdx @@ -0,0 +1,216 @@ +--- +title: Quickstart +description: Using the Flags SDK in TanStack Start +--- + +[TanStack Start](https://tanstack.com/start/latest) is a full-stack React framework powered by TanStack Router and Vite. The Flags SDK supports TanStack Start out of the box through the `flags/tanstack-start` entrypoint. + + + Add Flags SDK to my existing TanStack Start app. Configure `FLAGS_SECRET`, install and wire the Vercel Toolbar for local development, create a typed flag in `src/flags.ts` using `flags/tanstack-start`, add the Flags Explorer discovery endpoint as a server route, evaluate the flag inside a route loader through a server function, and run the relevant type checks or build when finished. + + +A minimal feature flag declaration for TanStack Start looks like this: + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const exampleFlag = flag({ + key: 'example-flag', + decide() { + return false; + }, +}); +``` + +## Installation + +Install the Vercel CLI using the following command: + +```sh title="Terminal" +npm i -g vercel@latest +``` + +## Set up TanStack Start application + +1. Create a TanStack Start application by following the [official guide](https://tanstack.com/start/latest/docs/framework/react/quick-start), or start from the [Flags SDK example](https://github.com/vercel/flags/tree/main/examples/tanstack-start-example). +2. At this stage the project only exists locally and not on Vercel. Use the following command to link it to a project on Vercel: + ```sh title="Terminal" + vc link + ``` +3. Add the `FLAGS_SECRET` environment variable. Use a separate value for each environment (Development, Preview, and Production), and mark the Preview and Production values as Sensitive. + + Run this command once per environment to generate distinct secrets: + ```sh title="Terminal" + node -e "console.log(crypto.randomBytes(32).toString('base64url'))" + ``` + Then store each secret as the `FLAGS_SECRET` environment variable for the matching environment: + ```sh title="Terminal" + vercel env add FLAGS_SECRET production --sensitive --value + vercel env add FLAGS_SECRET preview --sensitive --value + vercel env add FLAGS_SECRET development --value + ``` +4. Finally, pull any env vars from your project on Vercel locally + ```sh title="Terminal" + vc env pull + ``` + +## Add the toolbar locally + +1. Install the `@vercel/toolbar` package: + ```sh + npm i @vercel/toolbar + ``` +2. In your `vite.config.ts` file add the toolbar plugin for Vite: + + ```ts title="vite.config.ts" + import { defineConfig } from 'vite'; + import { tanstackStart } from '@tanstack/react-start/plugin/vite'; + import viteReact from '@vitejs/plugin-react'; + import { vercelToolbar } from '@vercel/toolbar/plugins/vite'; + + export default defineConfig({ + plugins: [tanstackStart(), viteReact(), vercelToolbar()], + }); + ``` + +3. Next render the toolbar in your root route so that it's visible for your visitors. This renders the toolbar for all visitors. In production you may want to [render it for team members only](https://vercel.com/docs/workflow-collaboration/vercel-toolbar/in-production-and-localhost/add-to-production): + + ```tsx title="src/routes/__root.tsx" + import { useEffect } from 'react'; + import { mountVercelToolbar } from '@vercel/toolbar/vite'; + + function RootComponent() { + useEffect(() => mountVercelToolbar(), []); + + // ...render your app + } + ``` + +## Set up `flags` + +1. Install the `flags` package: + + ```sh + npm i flags + ``` + + If you use an AI coding assistant, we recommend installing the Flags SDK agent skill: + + ```sh + npx skills add vercel/flags --skill flags-sdk + ``` + +2. Create your first feature flag by importing the `flag` method from `flags/tanstack-start`: + + ```ts title="src/flags.ts" + import { flag } from 'flags/tanstack-start'; + + export const showDashboard = flag({ + key: 'showDashboard', + description: 'Show the dashboard', // optional + origin: 'https://example.com/#showdashboard', // optional + options: [{ value: true }, { value: false }], // optional + // can be async and has access to headers, cookies, and entities + decide() { + return false; + }, + }); + ``` + +3. Next set up the Flags Explorer discovery endpoint. This is a one-time setup step which makes the toolbar aware of your application's feature flags. Add it as a server route at `/.well-known/vercel/flags`: + + ```ts title="src/routes/[.]well-known/vercel/flags.ts" + // The `[.]` escapes the leading dot so the directory resolves to + // `/.well-known/vercel/flags` (folders starting with a real dot are + // ignored by the bundler). + import { createFileRoute } from '@tanstack/react-router'; + import { + createFlagsDiscoveryEndpoint, + getProviderData, + } from 'flags/tanstack-start'; + import * as flags from '../../../flags'; + + const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + + export const Route = createFileRoute('/.well-known/vercel/flags')({ + server: { handlers: { GET: handler } }, + }); + ``` + +4. You can now use this flag in code. Flags are evaluated on the server, so wrap the evaluation in a `createServerFn()` server function and call it from a route loader. This keeps it working during client-side navigation too: + + ```tsx title="src/routes/dashboard.tsx" + import { createFileRoute } from '@tanstack/react-router'; + import { createServerFn } from '@tanstack/react-start'; + import { showDashboard } from '../flags'; + + const getDashboardFlags = createServerFn().handler(async () => { + return { showDashboard: await showDashboard() }; + }); + + export const Route = createFileRoute('/dashboard')({ + loader: () => getDashboardFlags(), + component: Dashboard, + }); + + function Dashboard() { + const { showDashboard } = Route.useLoaderData(); + return

{showDashboard ? 'New Dashboard' : 'Old Dashboard'}

; + } + ``` + + Inside a route loader, server function, or server route you can call a flag with no arguments — the request is resolved automatically through TanStack Start's `getRequest()`. You may also pass a `Request` explicitly when evaluating outside of a request context: + + ```ts + const value = await showDashboard(request); + ``` + + + See the Dashboard Pages guide for more info + + +## Flags Explorer + +Open the Flags Explorer locally to see the feature flag. + + + Learn more about the Flags Explorer + + +### Available flags + +Notice how the toolbar knows about the flag's name, description and the link to where the flag can be managed. All of these are communicated through the `/.well-known/vercel/flags` endpoint, which is set up by the `createFlagsDiscoveryEndpoint` server route we added above. + +This endpoint responds with the application's feature flags when it sees the authenticated request made by Vercel Toolbar to load your application's feature flags. + +### Overrides + +When you set an override using Vercel Toolbar it will automatically be respected by the feature flags defined through `flags/tanstack-start`. The override is read from the `vercel-flag-overrides` cookie, and when present the flag's `decide` function is skipped in favor of the override value. + +## Next steps + +### Precomputed flags + +Precomputing flags allows experimentation on static pages, while avoiding layout shift. The Flags SDK for TanStack Start supports precomputing flags. + + + Learn how to precompute values + + +### Evaluation Contexts + +Evaluation Contexts allow targeting flags to specific users. The Flags SDK for TanStack Start supports the Evaluation Context by passing an `identify` function to the flag declaration. + + + Learn how to identify users with the evaluation context + + +### API Reference + + + APIs for working with feature flags in TanStack Start + diff --git a/apps/docs/content/docs/frameworks/tanstack-start/meta.json b/apps/docs/content/docs/frameworks/tanstack-start/meta.json new file mode 100644 index 00000000..9e0d289b --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/meta.json @@ -0,0 +1,14 @@ +{ + "title": "TanStack Start", + "defaultOpen": false, + "root": true, + "pages": [ + "index", + "------", + "---Concepts---", + "precompute", + "evaluation-context", + "---Guides---", + "...guides" + ] +} diff --git a/apps/docs/content/docs/frameworks/tanstack-start/precompute.mdx b/apps/docs/content/docs/frameworks/tanstack-start/precompute.mdx new file mode 100644 index 00000000..45c135e1 --- /dev/null +++ b/apps/docs/content/docs/frameworks/tanstack-start/precompute.mdx @@ -0,0 +1,152 @@ +--- +title: Precompute +description: Using the precompute pattern in TanStack Start +--- + +This page shows how to implement the precompute pattern in TanStack Start to keep pages static, even when multiple feature flags are used on a single page, or even when feature flags are used across multiple pages. +Ensure you've read about the general precompute concept to understand the pattern and benefits: + + + Implement precomputed feature flags in my TanStack Start app. Add `FLAGS_SECRET`, group the relevant `flags/tanstack-start` declarations into an array, precompute them server-side into a signed code, expose a dynamic `$code` route that reads the precomputed values with `flag(code, flags)`, and run the relevant checks when finished. + + + +
Read the introduction to precompute
+
+ +The following assumes you've already set up the Flags SDK for TanStack Start as described in the [Quickstart guide](/frameworks/tanstack-start). + +## How it works + +The precompute pattern keeps a page static even when feature flags are used on it. Instead of evaluating the flags inside the page itself, you: + +1. Evaluate all flags used on the page once, on the server, and encode their values into a short, signed code with `precompute`. +2. Route the request to a dynamic segment (e.g. `/marketing/$code`) that contains that code. +3. Read the values back from the code with `flag(code, flags)` — this decodes the value without re-running `decide`. + +Because the code is deterministic for a given set of flag values, the resulting `/marketing/$code` page can be cached and served statically. + +## 1. Create flags to be precomputed + +Create one or multiple flags. + +```ts title="src/flags.ts" +import { flag } from 'flags/tanstack-start'; + +export const firstMarketingABTest = flag({ + key: 'firstMarketingABTest', + decide: () => false, +}); + +export const secondMarketingABTest = flag({ + key: 'secondMarketingABTest', + decide: () => false, +}); +``` + +Export them as an array to be precomputed. Put them into a separate file so you can colocate other precompute-related logic. The order matters: the same array must be passed to `precompute()` and when reading values back with `flag(code, marketingFlags)`. + +```ts title="src/precomputed-flags.ts" +import { precompute } from 'flags/tanstack-start'; +import { firstMarketingABTest, secondMarketingABTest } from './flags'; + +export const marketingFlags = [ + firstMarketingABTest, + secondMarketingABTest, +] as const; + +export async function precomputeMarketing(request: Request): Promise { + return precompute(marketingFlags, request); +} +``` + +## 2. Precompute the code and route to it + +Use a server function to precompute the flags into a signed code, then redirect to the dynamic route that carries it. `precompute` invokes each flag, reads its value, and encodes the result so the user-visible `/marketing` URL is internally served as e.g. `/marketing/abc-123`. + +```tsx title="src/routes/marketing.tsx" +import { createFileRoute, redirect } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { getRequest } from '@tanstack/react-start/server'; +import { precomputeMarketing } from '../precomputed-flags'; + +const getMarketingCode = createServerFn().handler(async () => { + const request = getRequest(); + return precomputeMarketing(request); +}); + +export const Route = createFileRoute('/marketing')({ + loader: async () => { + const code = await getMarketingCode(); + throw redirect({ to: '/marketing/$code', params: { code } }); + }, + component: () => null, +}); +``` + +## 3. Read the precomputation result from the page + +Read the precomputed values by calling each flag with the code from the URL and the same `marketingFlags` array used during precomputation. + +When a flag is called this way it reads the result from the precomputation and does **not** invoke the flag's `decide` function again: + +```tsx title="src/routes/marketing.$code.tsx" +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { firstMarketingABTest, secondMarketingABTest } from '../flags'; +import { marketingFlags } from '../precomputed-flags'; + +const getMarketingFlags = createServerFn() + .validator((code: string) => code) + .handler(async ({ data: code }) => { + return { + first: await firstMarketingABTest(code, marketingFlags), + second: await secondMarketingABTest(code, marketingFlags), + }; + }); + +export const Route = createFileRoute('/marketing/$code')({ + loader: ({ params }) => getMarketingFlags({ data: params.code }), + component: MarketingPage, +}); + +function MarketingPage() { + const { first, second } = Route.useLoaderData(); + return ( +
    +
  • firstMarketingABTest: {String(first)}
  • +
  • secondMarketingABTest: {String(second)}
  • +
+ ); +} +``` + +## Generating permutations + +When you want to prerender or statically cache every variant of a page, use `generatePermutations` to enumerate all possible codes from the flags' options. You can then build a static page per code. + +```ts title="src/precomputed-flags.ts" +import { generatePermutations } from 'flags/tanstack-start'; +import { marketingFlags } from './precomputed-flags'; + +// returns one signed code per combination of flag values +const codes = await generatePermutations(marketingFlags); +``` + + + See the API reference for `precompute` and `generatePermutations` + + +## Routing Middleware (optional) + +The server-function approach above runs inside the TanStack Start runtime. If you want to rewrite the request to the precomputed variant *before* the CDN is hit — for example to keep a marketing page fully static at the edge — you can additionally run `precompute` inside Vercel [Routing Middleware](https://vercel.com/docs/routing-middleware) and `rewrite` to `/marketing/${code}`. Because `precompute` only needs a `Request`, the same `precomputeMarketing` helper can be reused there. + +## Next steps + +You now know how to use the precompute pattern within TanStack Start. +The above example didn't get into details about how to use e.g. cookies to determine the value of the flag. +This and more is covered in the Marketing Pages guide. + + + See the Marketing Pages example which implements this pattern + diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json index 80308aed..285d8ba5 100644 --- a/apps/docs/content/docs/meta.json +++ b/apps/docs/content/docs/meta.json @@ -2,6 +2,7 @@ "pages": [ "frameworks/next", "frameworks/sveltekit", + "frameworks/tanstack-start", "principles", "providers", "api-reference" diff --git a/apps/docs/geistdocs.tsx b/apps/docs/geistdocs.tsx index 02757cd3..bfb6730b 100644 --- a/apps/docs/geistdocs.tsx +++ b/apps/docs/geistdocs.tsx @@ -39,13 +39,13 @@ export const suggestions = [ export const title = "Flags SDK Documentation"; export const prompt = - "You are a helpful assistant specializing in answering questions about Flags SDK, a free, open-source library for using feature flags in Next.js and SvelteKit."; + "You are a helpful assistant specializing in answering questions about Flags SDK, a free, open-source library for using feature flags in Next.js, SvelteKit, and TanStack Start."; export const agent = { product: { name: "Flags SDK", description: - "Flags SDK is a free, open-source library for using feature flags in Next.js and SvelteKit.", + "Flags SDK is a free, open-source library for using feature flags in Next.js, SvelteKit, and TanStack Start.", category: "Feature Flags", audience: ["Application developers", "Framework teams"], useCases: [ diff --git a/skills/flags-sdk/SKILL.md b/skills/flags-sdk/SKILL.md index 3feb8ad7..79cbff61 100644 --- a/skills/flags-sdk/SKILL.md +++ b/skills/flags-sdk/SKILL.md @@ -8,17 +8,17 @@ description: > Edge Config, OpenFeature, Split, Flagsmith, Reflag, Optimizely, or custom adapters), implementing precompute patterns for static pages, setting up `identify`/`dedupe`, integrating Flags Explorer/Toolbar, - working with flags in Next.js (App Router, Pages Router, Middleware) or SvelteKit, + working with flags in Next.js (App Router, Pages Router, Middleware), SvelteKit, or TanStack Start, writing custom adapters, or encrypting/decrypting flag values. Triggers: feature flags, A/B testing, experimentation, flags SDK, flag adapters, precompute, Flags Explorer, feature gates, flag overrides, Vercel Flags, vercel flags CLI, vercel flags add, vercel flags list, vercel flags enable, vercel flags disable, - `flags/next`, `flags/sveltekit`, `flags/react`, `@flags-sdk/*`. + `flags/next`, `flags/sveltekit`, `flags/tanstack-start`, `flags/react`, `@flags-sdk/*`. --- # Flags SDK -The Flags SDK (`flags` npm package) is a feature flags toolkit for Next.js and SvelteKit. It turns each feature flag into a callable function, works with any flag provider via adapters, and keeps pages static using the precompute pattern. Vercel Flags is the first-party provider, letting you manage flags from the Vercel dashboard or the `vercel flags` CLI. +The Flags SDK (`flags` npm package) is a feature flags toolkit for Next.js, SvelteKit, and TanStack Start. It turns each feature flag into a callable function, works with any flag provider via adapters, and keeps pages static using the precompute pattern. Vercel Flags is the first-party provider, letting you manage flags from the Vercel dashboard or the `vercel flags` CLI. - Docs: https://flags-sdk.dev - Repo: https://github.com/vercel/flags @@ -133,7 +133,7 @@ When using Vercel Flags, declare flags with `vercelAdapter()` as shown in the [A ### Basic flag ```ts -import { flag } from 'flags/next'; // or 'flags/sveltekit' +import { flag } from 'flags/next'; // or 'flags/sveltekit', 'flags/tanstack-start' export const showBanner = flag({ key: 'show-banner', @@ -250,6 +250,26 @@ import * as flags from '$lib/flags'; export const handle = createHandle({ secret: FLAGS_SECRET, flags }); ``` +### TanStack Start + +There is no server hook — wire up a server route at `/.well-known/vercel/flags`: + +```ts +// src/routes/[.]well-known/vercel/flags.ts +import { createFileRoute } from '@tanstack/react-router'; +import { + createFlagsDiscoveryEndpoint, + getProviderData, +} from 'flags/tanstack-start'; +import * as flags from '../../../flags'; + +const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + +export const Route = createFileRoute('/.well-known/vercel/flags')({ + server: { handlers: { GET: handler } }, +}); +``` + ## FLAGS_SECRET Required for precompute and Flags Explorer. Must be 32 random bytes, base64-encoded: @@ -281,6 +301,7 @@ High-level flow: For full implementation details, see framework-specific references: - **Next.js**: See [references/nextjs.md](references/nextjs.md) — covers proxy middleware, precompute setup, ISR, generatePermutations, multiple groups - **SvelteKit**: See [references/sveltekit.md](references/sveltekit.md) — covers reroute hook, middleware, precompute setup, ISR, prerendering +- **TanStack Start**: See [references/tanstack-start.md](references/tanstack-start.md) — covers server-function precompute, the `$code` route, generatePermutations, optional Routing Middleware ## Custom adapters diff --git a/skills/flags-sdk/references/tanstack-start.md b/skills/flags-sdk/references/tanstack-start.md new file mode 100644 index 00000000..afd6d546 --- /dev/null +++ b/skills/flags-sdk/references/tanstack-start.md @@ -0,0 +1,341 @@ +# TanStack Start Integration + +## Table of Contents + +- [Quickstart](#quickstart) +- [Toolbar Setup](#toolbar-setup) +- [Flags Explorer Setup](#flags-explorer-setup) +- [Flag Declaration](#flag-declaration) +- [Evaluation Context](#evaluation-context) +- [Precompute](#precompute) +- [Dashboard Pages](#dashboard-pages) +- [Marketing Pages](#marketing-pages) + +The `flags/tanstack-start` entrypoint mirrors the other adapters. Key differences from SvelteKit: + +- There is **no** `createHandle`/server hook. The Flags Explorer is wired up as a TanStack Start **server route** at `/.well-known/vercel/flags` using `createFlagsDiscoveryEndpoint`. +- Flags evaluate on the server. The request is resolved automatically via TanStack Start's `getRequest()` inside a route loader, server function, or server route. You may also pass a `Request` explicitly: `flag(request)`. +- Wrap evaluation in `createServerFn()` so it works during client-side navigation too. + +## Quickstart + +### Installation + +```sh +pnpm i flags @vercel/toolbar +``` + +### Create a flag + +```ts +// src/flags.ts +import { flag } from 'flags/tanstack-start'; + +export const showDashboard = flag({ + key: 'showDashboard', + description: 'Show the dashboard', + origin: 'https://example.com/#showdashboard', + options: [{ value: true }, { value: false }], + decide() { + return false; + }, +}); +``` + +### Use the flag + +Flags are evaluated on the server, so wrap evaluation in a server function and call it from a route loader. + +```tsx +// src/routes/dashboard.tsx +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { showDashboard } from '../flags'; + +const getDashboardFlags = createServerFn().handler(async () => { + return { showDashboard: await showDashboard() }; +}); + +export const Route = createFileRoute('/dashboard')({ + loader: () => getDashboardFlags(), + component: Dashboard, +}); + +function Dashboard() { + const { showDashboard } = Route.useLoaderData(); + return

{showDashboard ? 'New Dashboard' : 'Old Dashboard'}

; +} +``` + +## Toolbar Setup + +1. Install `@vercel/toolbar` +2. Add the Vite plugin: + +```ts +// vite.config.ts +import { defineConfig } from 'vite'; +import { tanstackStart } from '@tanstack/react-start/plugin/vite'; +import viteReact from '@vitejs/plugin-react'; +import { vercelToolbar } from '@vercel/toolbar/plugins/vite'; + +export default defineConfig({ + plugins: [tanstackStart(), viteReact(), vercelToolbar()], +}); +``` + +3. Mount the toolbar in the root route: + +```tsx +// src/routes/__root.tsx +import { useEffect } from 'react'; +import { mountVercelToolbar } from '@vercel/toolbar/vite'; + +function RootComponent() { + useEffect(() => mountVercelToolbar(), []); + // ...render your app +} +``` + +## Flags Explorer Setup + +Wire up the discovery endpoint as a server route. The `[.]` escapes the leading dot so the directory resolves to `/.well-known/vercel/flags`. + +```ts +// src/routes/[.]well-known/vercel/flags.ts +import { createFileRoute } from '@tanstack/react-router'; +import { + createFlagsDiscoveryEndpoint, + getProviderData, +} from 'flags/tanstack-start'; +import * as flags from '../../../flags'; + +const handler = createFlagsDiscoveryEndpoint(() => getProviderData(flags)); + +export const Route = createFileRoute('/.well-known/vercel/flags')({ + server: { handlers: { GET: handler } }, +}); +``` + +Overrides set by Vercel Toolbar (the `vercel-flag-overrides` cookie) are respected automatically — when present the flag's `decide` is skipped. + +## Flag Declaration + +```ts +import { flag } from 'flags/tanstack-start'; + +export const showSummerSale = flag({ + key: 'summer-sale', + async decide() { return false; }, + origin: 'https://example.com/flags/summer-sale/', + description: 'Show Summer Holiday Sale Banner, 20% off', + options: [ + { value: false, label: 'Hide' }, + { value: true, label: 'Show' }, + ], +}); +``` + +## Evaluation Context + +Use `identify` to segment users. Headers and cookies are normalized: + +```ts +import { flag } from 'flags/tanstack-start'; + +interface Entities { + user?: { id: string }; +} + +export const exampleFlag = flag({ + key: 'identify-example-flag', + identify({ headers, cookies }) { + const userId = cookies.get('user-id')?.value; + return { user: userId ? { id: userId } : undefined }; + }, + decide({ entities }) { + return entities?.user?.id === 'user1'; + }, +}); +``` + +### Deduplication + +Extract `identify` as a named function and reuse it across flags. Calls are deduped by function identity within a request: + +```ts +import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags'; +import { flag } from 'flags/tanstack-start'; + +interface Entities { + visitorId?: string; +} + +function identify({ + cookies, + headers, +}: { + cookies: ReadonlyRequestCookies; + headers: ReadonlyHeaders; +}): Entities { + const visitorId = + cookies.get('visitorId')?.value ?? headers.get('x-visitor-id'); + return { visitorId }; +} + +export const flag1 = flag({ + key: 'flag1', + identify, + decide({ entities }) { /* ... */ }, +}); + +export const flag2 = flag({ + key: 'flag2', + identify, + decide({ entities }) { /* ... */ }, +}); +``` + +## Precompute + +Precompute keeps pages static by evaluating flags once, encoding their values into a signed code, and routing to a dynamic `$code` segment that reads them back. + +### Step 1: Create flag group + +```ts +// src/precomputed-flags.ts +import { precompute } from 'flags/tanstack-start'; +import { firstMarketingABTest, secondMarketingABTest } from './flags'; + +export const marketingFlags = [ + firstMarketingABTest, + secondMarketingABTest, +] as const; + +export async function precomputeMarketing(request: Request): Promise { + return precompute(marketingFlags, request); +} +``` + +### Step 2: Precompute and route to the code + +```tsx +// src/routes/marketing.tsx +import { createFileRoute, redirect } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { getRequest } from '@tanstack/react-start/server'; +import { precomputeMarketing } from '../precomputed-flags'; + +const getMarketingCode = createServerFn().handler(async () => { + return precomputeMarketing(getRequest()); +}); + +export const Route = createFileRoute('/marketing')({ + loader: async () => { + const code = await getMarketingCode(); + throw redirect({ to: '/marketing/$code', params: { code } }); + }, + component: () => null, +}); +``` + +### Step 3: Read precomputed values + +Calling `flag(code, marketingFlags)` decodes the value without re-running `decide`. The same array must be passed to `precompute` and when reading back. + +```tsx +// src/routes/marketing.$code.tsx +import { createFileRoute } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { firstMarketingABTest, secondMarketingABTest } from '../flags'; +import { marketingFlags } from '../precomputed-flags'; + +const getMarketingFlags = createServerFn() + .validator((code: string) => code) + .handler(async ({ data: code }) => ({ + first: await firstMarketingABTest(code, marketingFlags), + second: await secondMarketingABTest(code, marketingFlags), + })); + +export const Route = createFileRoute('/marketing/$code')({ + loader: ({ params }) => getMarketingFlags({ data: params.code }), + component: MarketingPage, +}); +``` + +### Generate permutations + +```ts +import { generatePermutations } from 'flags/tanstack-start'; +import { marketingFlags } from './precomputed-flags'; + +const codes = await generatePermutations(marketingFlags); +``` + +### Routing Middleware (optional) + +To rewrite to the precomputed variant before the CDN is hit, run `precompute` inside Vercel Routing Middleware and `rewrite` to `/marketing/${code}`. `precompute` only needs a `Request`, so the same helper is reusable. + +## Dashboard Pages + +```ts +// src/flags.ts +import { flag } from 'flags/tanstack-start'; + +export const showNewDashboard = flag({ + key: 'showNewDashboard', + decide({ cookies }) { + return cookies.get('showNewDashboard')?.value === 'true'; + }, +}); +``` + +```tsx +// src/routes/dashboard.tsx +import { createServerFn } from '@tanstack/react-start'; +import { showNewDashboard } from '../flags'; + +const getDashboardFlags = createServerFn().handler(async () => { + return { showNewDashboard: await showNewDashboard() }; +}); +``` + +## Marketing Pages + +Combine precompute with a stable visitor id for A/B tests on static pages. The +`identify` function reads the id from a cookie, falling back to an +`x-visitor-id` header (useful when the id is generated in middleware before the +cookie is set): + +```ts +// src/flags.ts +import type { ReadonlyHeaders, ReadonlyRequestCookies } from 'flags'; +import { flag } from 'flags/tanstack-start'; + +interface Entities { + visitorId?: string; +} + +function identify({ + cookies, + headers, +}: { + cookies: ReadonlyRequestCookies; + headers: ReadonlyHeaders; +}): Entities { + const visitorId = + cookies.get('visitorId')?.value ?? headers.get('x-visitor-id'); + return { visitorId }; +} + +export const firstMarketingABTest = flag({ + key: 'firstMarketingABTest', + identify, + decide({ entities }) { + if (!entities?.visitorId) return false; + return /^[a-m0-4]/i.test(entities.visitorId); + }, +}); +``` + +See the full example at `examples/tanstack-start-example`.