diff --git a/.github/labeler.yml b/.github/labeler.yml index 650e4e34d1..65e3cde23b 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -22,20 +22,14 @@ - 'packages/start-api-routes/**/*' 'package: react-start-client': - 'packages/react-start-client/**/*' -'package: react-start-config': - - 'packages/react-start-config/**/*' 'package: react-start-plugin': - 'packages/react-start-plugin/**/*' -'package: react-start-router-manifest': - - 'packages/react-start-router-manifest/**/*' 'package: react-start-server': - 'packages/react-start-server/**/*' 'package: start-server-functions-client': - 'packages/start-server-functions-client/**/*' 'package: start-server-functions-fetcher': - 'packages/start-server-functions-fetcher/**/*' -'package: start-server-functions-handler': - - 'packages/start-server-functions-handler/**/*' 'package: start-server-functions-ssr': - 'packages/start-server-functions-ssr/**/*' 'package: router-cli': @@ -74,8 +68,6 @@ - 'packages/solid-start-server/**/*' 'package: start': - 'packages/start/**/*' -'package: start-config': - - 'packages/start-config/**/*' 'package: start-server-functions-server': - 'packages/start-server-functions-server/**/*' 'package: valibot-adapter': diff --git a/.gitignore b/.gitignore index 5cc3e94113..36785455d3 100644 --- a/.gitignore +++ b/.gitignore @@ -61,12 +61,14 @@ nx-cloud.env gpt/db.json app.config.timestamp-* +vite.config.timestamp-* vite.config.js.timestamp-* vite.config.ts.timestamp-* app.config.js.timestamp-* app.config.ts.timestamp-* app.config.timestamp_* +vite.config.timestamp_* vite.config.js.timestamp_* vite.config.ts.timestamp_* app.config.js.timestamp_* diff --git a/.npmrc b/.npmrc index 84aee8d998..ad30a6c4d2 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,3 @@ link-workspace-packages=true prefer-workspace-packages=true -provenance=true +provenance=false diff --git a/.prettierignore b/.prettierignore index d285f8937d..25c93015ed 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,7 +7,6 @@ pnpm-lock.yaml **/snapshots **/.vercel -**/.vinxi **/.output **/node_modules node_modules diff --git a/docs/router/eslint/create-route-property-order.md b/docs/router/eslint/create-route-property-order.md index 3ce5102013..c0fee218d2 100644 --- a/docs/router/eslint/create-route-property-order.md +++ b/docs/router/eslint/create-route-property-order.md @@ -29,7 +29,7 @@ Examples of **incorrect** code for this rule: /* eslint "@tanstack/router/create-route-property-order": "warn" */ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/foo/bar/$id')({ +export const Route = createFileRoute({ loader: async ({context}) => { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)), }, @@ -43,7 +43,7 @@ Examples of **correct** code for this rule: /* eslint "@tanstack/router/create-route-property-order": "warn" */ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/foo/bar/$id')({ +export const Route = createFileRoute({ beforeLoad: () => ({hello: 'world'}), loader: async ({context}) => { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)), diff --git a/docs/router/framework/react/api/router/createFileRouteFunction.md b/docs/router/framework/react/api/router/createFileRouteFunction.md index 945e713075..0986d6ccff 100644 --- a/docs/router/framework/react/api/router/createFileRouteFunction.md +++ b/docs/router/framework/react/api/router/createFileRouteFunction.md @@ -26,7 +26,7 @@ A new function that accepts a single argument of type [`RouteOptions`](./RouteOp ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ loader: () => { return 'Hello World' }, diff --git a/docs/router/framework/react/api/router/retainSearchParamsFunction.md b/docs/router/framework/react/api/router/retainSearchParamsFunction.md index 97e411b29c..d4bc185203 100644 --- a/docs/router/framework/react/api/router/retainSearchParamsFunction.md +++ b/docs/router/framework/react/api/router/retainSearchParamsFunction.md @@ -39,7 +39,7 @@ const searchSchema = z.object({ two: z.string().optional(), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { middlewares: [retainSearchParams(true)], diff --git a/docs/router/framework/react/api/router/stripSearchParamsFunction.md b/docs/router/framework/react/api/router/stripSearchParamsFunction.md index 05b9b02e7f..439a1796d2 100644 --- a/docs/router/framework/react/api/router/stripSearchParamsFunction.md +++ b/docs/router/framework/react/api/router/stripSearchParamsFunction.md @@ -30,7 +30,7 @@ const searchSchema = z.object({ two: z.string().default(defaultValues.two), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { // strip default values @@ -68,7 +68,7 @@ const searchSchema = z.object({ two: z.string().default('xyz'), }) -export const Route = createFileRoute('/hello')({ +export const Route = createFileRoute({ validateSearch: zodValidator(searchSchema), search: { // remove all search params diff --git a/docs/router/framework/react/decisions-on-dx.md b/docs/router/framework/react/decisions-on-dx.md index 405db4c6eb..a38716f624 100644 --- a/docs/router/framework/react/decisions-on-dx.md +++ b/docs/router/framework/react/decisions-on-dx.md @@ -225,7 +225,7 @@ Let's take a look at how the route configuration for the previous example would // src/routes/posts/index.ts import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: () => 'Posts index component goes here!!!', }) ``` diff --git a/docs/router/framework/react/guide/external-data-loading.md b/docs/router/framework/react/guide/external-data-loading.md index e2d0e1eb53..2b1ebf78f1 100644 --- a/docs/router/framework/react/guide/external-data-loading.md +++ b/docs/router/framework/react/guide/external-data-loading.md @@ -48,7 +48,7 @@ Here is a naive illustration (don't do this) of using a Route's `loader` option // src/routes/posts.tsx let postsCache = [] -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => { postsCache = await fetchPosts() }, @@ -80,7 +80,7 @@ const postsQueryOptions = queryOptions({ queryFn: () => fetchPosts(), }) -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ // Use the `loader` option to ensure that the data is loaded loader: () => queryClient.ensureQueryData(postsQueryOptions), component: () => { @@ -105,7 +105,7 @@ export const Route = createFileRoute('/posts')({ When an error occurs while using `suspense` with `Tanstack Query`, you'll need to let queries know that you want to try again when re-rendering. This can be done by using the `reset` function provided by the `useQueryErrorResetBoundary` hook. We can invoke this function in an effect as soon as the error component mounts. This will make sure that the query is reset and will try to fetch data again when the route component is rendered again. This will also cover cases where users navigate away from our route instead of clicking the `retry` button. ```tsx -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: () => queryClient.ensureQueryData(postsQueryOptions), errorComponent: ({ error, reset }) => { const router = useRouter() diff --git a/docs/router/framework/react/guide/router-context.md b/docs/router/framework/react/guide/router-context.md index 561b1e2f00..f54e7a7b23 100644 --- a/docs/router/framework/react/guide/router-context.md +++ b/docs/router/framework/react/guide/router-context.md @@ -92,7 +92,7 @@ Once you have defined the router context type, you can use it in your route defi ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: ({ context }) => fetchTodosByUserId(context.user.id), }) @@ -122,7 +122,7 @@ Then, in your route: ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: ({ context }) => context.fetchTodosByUserId(context.userId), }) @@ -158,7 +158,7 @@ Then, in your route: ```tsx // src/routes/todos.tsx -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, loader: async ({ context }) => { await context.queryClient.ensureQueryData({ @@ -234,7 +234,7 @@ So, now in our route's `loader` function, we can access the `networkStrength` ho ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: Posts, loader: ({ context }) => { if (context.networkStrength === 'STRONG') { @@ -282,7 +282,7 @@ const router = createRouter({ ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/todos')({ +export const Route = createFileRoute({ component: Todos, beforeLoad: () => { return { diff --git a/docs/router/framework/react/guide/tanstack-start.md b/docs/router/framework/react/guide/tanstack-start.md index 9704d721c4..a56a204e28 100644 --- a/docs/router/framework/react/guide/tanstack-start.md +++ b/docs/router/framework/react/guide/tanstack-start.md @@ -47,15 +47,12 @@ TanStack Start is powered by the following packages and need to be installed as - [@tanstack/start](https://github.com/tanstack/start) - [@tanstack/react-router](https://tanstack.com/router) -- [Vinxi](https://vinxi.vercel.app/) - -> [!NOTE] -> Vinxi is a temporary dependency that will be replaced by a simple vite plugin or a dedicated Start CLI. +- [Vite](https://vite.dev/) To install them, run: ```shell -npm i @tanstack/react-start @tanstack/react-router vinxi +npm i @tanstack/react-start @tanstack/react-router vite ``` You'll also need React and the Vite React plugin, so install their dependencies as well: @@ -72,16 +69,16 @@ npm i -D typescript @types/react @types/react-dom # Update Configuration Files -We'll then update our `package.json` to use Vinxi's CLI and set `"type": "module"`: +We'll then update our `package.json` to use Vite's CLI and set `"type": "module"`: ```jsonc { // ... "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", }, } ``` @@ -97,12 +94,10 @@ export default defineConfig({}) # Add the Basic Templating -There are four required files for TanStack Start usage: +There are 2 required files for TanStack Start usage: 1. The router configuration -2. The server entry point -3. The client entry point -4. The root of your application +2. The root of your application Once configuration is done, we'll have a file tree that looks like the following: @@ -111,10 +106,8 @@ Once configuration is done, we'll have a file tree that looks like the following ├── app/ │ ├── routes/ │ │ └── `__root.tsx` -│ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` -│ └── `ssr.tsx` ├── `.gitignore` ├── `app.config.ts` ├── `package.json` @@ -123,7 +116,7 @@ Once configuration is done, we'll have a file tree that looks like the following ## The Router Configuration -This is the file that will dictate the behavior of TanStack Router used within Start. Here, you can configure everything +This is the file that will dictate the behavior of TanStack Router used within Start for both the server and the client. Here, you can configure everything from the default [preloading functionality](./preloading.md) to [caching staleness](./data-loading.md). ```tsx @@ -149,52 +142,9 @@ declare module '@tanstack/react-router' { > `routeTree.gen.ts` is not a file you're expected to have at this point. > It will be generated when you run TanStack Start (via `npm run dev` or `npm run start`) for the first time. -## The Server Entry Point - -As TanStack Start is an [SSR](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg) framework, we need to pipe this router -information to our server entry point: - -```tsx -// app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This allows us to know what routes and loaders we need to execute when the user hits a given route. - -## The Client Entry Point - -Now we need a way to hydrate our client-side JavaScript once the route resolves to the client. We do this by piping the same -router information to our client entry point: - -```tsx -// app/client.tsx -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter({ - scrollRestoration: true, -}) - -hydrateRoot(document!, ) -``` - -This enables us to kick off client-side routing once the user's initial server request has fulfilled. - ## The Root of Your Application -Finally, we need to create the root of our application. This is the entry point for all other routes. The code in this file will wrap all other routes in the application. +Finally, we need to create the root of our application. This is the entry point for all application routes. The code in this file will wrap all other routes in the application. ```tsx // app/routes/__root.tsx diff --git a/docs/router/framework/react/migrate-from-react-location.md b/docs/router/framework/react/migrate-from-react-location.md index 100d614cae..fc04391c61 100644 --- a/docs/router/framework/react/migrate-from-react-location.md +++ b/docs/router/framework/react/migrate-from-react-location.md @@ -112,7 +112,7 @@ export const Route = createRootRoute({ // src/routes/index.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Index, }) ``` @@ -125,7 +125,7 @@ export const Route = createFileRoute('/')({ // src/routes/posts.tsx import { createFileRoute, Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: Posts, loader: async () => { const posts = await fetchPosts() @@ -164,7 +164,7 @@ function Posts() { // src/routes/posts.index.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndex, }) ``` @@ -177,7 +177,7 @@ export const Route = createFileRoute('/posts/')({ // src/routes/posts.$postId.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ component: PostsId, loader: async ({ params: { postId } }) => { const post = await fetchPost(postId) diff --git a/docs/router/framework/react/overview.md b/docs/router/framework/react/overview.md index be83513a79..9e064cf0a1 100644 --- a/docs/router/framework/react/overview.md +++ b/docs/router/framework/react/overview.md @@ -42,7 +42,7 @@ It's probably no surprise at this point that picking a router is so important th **Does this mean that TanStack Router is a framework?** -TanStack Router itself is not a "framework" in the traditional sense, since it doesn't address a few other common full-stack concerns. However TanStack Router has been designed to be upgradable to a full-stack framework when used in conjunction with other tools that address bundling, deployments, and server-side-specific functionality. This is why we are currently developing [TanStack Start](https://tanstack.com/start), a full-stack framework that is built on top of TanStack Router and tools like Nitro, and Vite. +TanStack Router itself is not a "framework" in the traditional sense, since it doesn't address a few other common full-stack concerns. However TanStack Router has been designed to be upgradable to a full-stack framework when used in conjunction with other tools that address bundling, deployments, and server-side-specific functionality. This is why we are currently developing [TanStack Start](https://tanstack.com/start), a full-stack framework that is built on top of TanStack Router and Vite. For a deeper dive on the history of TanStack Router, feel free to read [TanStack Router's History](./decisions-on-dx.md#tanstack-routers-origin-story). diff --git a/docs/router/framework/react/routing/routing-concepts.md b/docs/router/framework/react/routing/routing-concepts.md index f07bb65868..c6a21c3c92 100644 --- a/docs/router/framework/react/routing/routing-concepts.md +++ b/docs/router/framework/react/routing/routing-concepts.md @@ -13,7 +13,7 @@ All other routes, other than the [Root Route](#the-root-route), are configured u ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ component: PostsComponent, }) ``` @@ -71,7 +71,7 @@ Let's take a look at an `/about` route: // about.tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/about')({ +export const Route = createFileRoute({ component: AboutComponent, }) @@ -93,7 +93,7 @@ Let's take a look at an index route for a `/posts` URL: import { createFileRoute } from '@tanstack/react-router' // Note the trailing slash, which is used to target index routes -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) @@ -113,7 +113,7 @@ These params are then usable in your route's configuration and components! Let's ```tsx import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ // In a loader loader: ({ params }) => fetchPost(params.postId), // Or in a component @@ -172,7 +172,7 @@ This tree structure is used to wrap the child routes with a layout component: ```tsx import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/app')({ +export const Route = createFileRoute({ component: AppLayoutComponent, }) @@ -243,7 +243,7 @@ The `_pathlessLayout.tsx` route is used to wrap the child routes with a Pathless ```tsx import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: PathlessLayoutComponent, }) diff --git a/docs/start/config.json b/docs/start/config.json index 5aa7af5324..50cf495a70 100644 --- a/docs/start/config.json +++ b/docs/start/config.json @@ -46,8 +46,8 @@ "to": "framework/react/middleware" }, { - "label": "API Routes", - "to": "framework/react/api-routes" + "label": "Server Routes", + "to": "framework/react/server-routes" }, { "label": "SSR", diff --git a/docs/start/framework/react/api-routes.md b/docs/start/framework/react/api-routes.md deleted file mode 100644 index a1d1dd6d4c..0000000000 --- a/docs/start/framework/react/api-routes.md +++ /dev/null @@ -1,292 +0,0 @@ ---- -id: api-routes -title: API Routes ---- - -API Routes are a powerful feature of TanStack Start that allow you to create server-side endpoints in your application without the need for a separate server. API Routes are useful for handling form submissions, user authentication, and more. - -By default, API Routes are defined in your `./app/routes/api` directory of your project and are automatically handled by the TanStack Start server. - -> 🧠 This means that by default, your API Routes will be prefixed with `/api` and will be served from the same server as your application. You can customize this base path by changing the `server.apiBaseURL` in your TanStack Start config. - -## File Route Conventions - -API Routes in TanStack Start, follow the same file-based routing conventions as TanStack Router. This means that each file in your `routes` directory that is prefixed with `api` (which can be configured) will be treated as an API route. Here are a few examples: - -- `routes/api.users.ts` will create an API route at `/api/users` -- `routes/api/users.ts` will **also** create an API route at `/api/users` -- `routes/api/users.index.ts` will **also** create an API route at `/api/users` -- `routes/api/users/$id.ts` will create an API route at `/api/users/$id` -- `routes/api/users/$id/posts.ts` will create an API route at `/api/users/$id/posts` -- `routes/api.users.$id.posts.ts` will **also** create an API route at `/api/users/$id/posts` -- `routes/api/file/$.ts` will create an API route at `/api/file/$` - -Your route files that are prefixed with `api`, can be thought of as the handlers for the given API route path. - -It's important to remember that each route can only have a single handler file associated with it. So, if you have a file named `routes/api/users.ts` which'd equal the request path of `/api/users`, you cannot have other files that'd also resolve to the same route, like: - -- `routes/api/users.index.ts` -- `routes/api.users.ts`. -- `routes/api.users.index.ts`. - -❗ One more thing, API Routes do not have the concept of pathless layout routes or parallel routes. So, a file named: - -- `routes/api/_pathlessLayout/users.ts` would resolve to `/api/_pathlessLayout/users` and **NOT** `/api/users`. - -## Nested Directories vs File-names - -In the examples above, you may have noticed that the file naming conventions are flexible and allow you to mix and match directories and file names. This is intentional and allows you to organize your API Routes in a way that makes sense for your application. You can read more about this in the [TanStack Router File-based Routing Guide](/router/latest/docs/framework/react/routing/file-based-routing#s-or-s). - -## Setting up the entry handler - -Before you can create your API routes, you need to set up the entry handler for your TanStack Start project. This entry handler, similar to `client` and `ssr`, handles the API incoming requests and routes them to the appropriate API route handler. The API entry handler is defined in the `app/api.ts` file in your project. - -Here's an example implementation: - -```ts -// app/api.ts -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) -``` - -This file is responsible for creating the API handler that will be used to route incoming requests to the appropriate API route handler. The `defaultAPIFileRouteHandler` is a helper function that will automatically load and execute the appropriate API route handler based on the incoming request. - -## Defining an API Route - -API Routes export an APIRoute instance by calling the `createAPIFileRoute` function. Similar to other file-based routes in TanStack Router, the first argument to this function is the path of the route. The function returned is called again with an object that defines the route handlers for each HTTP method. - -> [!TIP] -> If you've already got the dev server running, when you create a new API route, it'll automatically have the initial handler set up for you. From there on, you can customize the handler as needed. - -> [!NOTE] -> The export variable must be named `APIRoute` or the resulting response will be a `404 not found`. - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response('Hello, World! from ' + request.url) - }, -}) -``` - -Each HTTP method handler receives an object with the following properties: - -- `request`: The incoming request object. You can read more about the `Request` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Request). -- `params`: An object containing the dynamic path parameters of the route. For example, if the route path is `/users/$id`, and the request is made to `/users/123`, then `params` will be `{ id: '123' }`. We'll cover dynamic path parameters and wildcard parameters later in this guide. - -Once you've processed the request, you need to return a `Response` object or `Promise`. This can be done by creating a new `Response` object and returning it from the handler. You can read more about the `Response` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Response). - -## Dynamic Path Params - -API Routes support dynamic path parameters, which are denoted by a `$` followed by the parameter name. For example, a file named `routes/api/users/$id.ts` will create an API route at `/api/users/$id` that accepts a dynamic `id` parameter. - -```ts -// routes/api/users/$id.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ params }) => { - const { id } = params - return new Response(`User ID: ${id}`) - }, -}) - -// Visit /api/users/123 to see the response -// User ID: 123 -``` - -You can also have multiple dynamic path parameters in a single route. For example, a file named `routes/api/users/$id/posts/$postId.ts` will create an API route at `/api/users/$id/posts/$postId` that accepts two dynamic parameters. - -```ts -// routes/api/users/$id/posts/$postId.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/users/$id/posts/$postId')({ - GET: async ({ params }) => { - const { id, postId } = params - return new Response(`User ID: ${id}, Post ID: ${postId}`) - }, -}) - -// Visit /api/users/123/posts/456 to see the response -// User ID: 123, Post ID: 456 -``` - -## Wildcard/Splat Param - -API Routes also support wildcard parameters at the end of the path, which are denoted by a `$` followed by nothing. For example, a file named `routes/api/file/$.ts` will create an API route at `/api/file/$` that accepts a wildcard parameter. - -```ts -// routes/api/file/$.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/file/$')({ - GET: async ({ params }) => { - const { _splat } = params - return new Response(`File: ${_splat}`) - }, -}) - -// Visit /api/file/hello.txt to see the response -// File: hello.txt -``` - -## Handling requests with a body - -To handle POST requests,you can add a `POST` handler to the route object. The handler will receive the request object as the first argument, and you can access the request body using the `request.json()` method. - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - POST: async ({ request }) => { - const body = await request.json() - return new Response(`Hello, ${body.name}!`) - }, -}) - -// Send a POST request to /api/hello with a JSON body like { "name": "Tanner" } -// Hello, Tanner! -``` - -This also applies to other HTTP methods like `PUT`, `PATCH`, and `DELETE`. You can add handlers for these methods in the route object and access the request body using the appropriate method. - -It's important to remember that the `request.json()` method returns a `Promise` that resolves to the parsed JSON body of the request. You need to `await` the result to access the body. - -This is a common pattern for handling POST requests in API Routes. You can also use other methods like `request.text()` or `request.formData()` to access the body of the request. - -## Responding with JSON - -When returning JSON using a Response object, this is a common pattern: - -```ts -// routes/api/hello.ts -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response(JSON.stringify({ message: 'Hello, World!' }), { - headers: { - 'Content-Type': 'application/json', - }, - }) - }, -}) - -// Visit /api/hello to see the response -// {"message":"Hello, World!"} -``` - -## Using the `json` helper function - -Or you can use the `json` helper function to automatically set the `Content-Type` header to `application/json` and serialize the JSON object for you. - -```ts -// routes/api/hello.ts -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' - -export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return json({ message: 'Hello, World!' }) - }, -}) - -// Visit /api/hello to see the response -// {"message":"Hello, World!"} -``` - -## Responding with a status code - -You can set the status code of the response by either: - -- Passing it as a property of the second argument to the `Response` constructor - - ```ts - // routes/api/hello.ts - import { json } from '@tanstack/react-start' - import { createAPIFileRoute } from '@tanstack/react-start/api' - - export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ request, params }) => { - const user = await findUser(params.id) - if (!user) { - return new Response('User not found', { - status: 404, - }) - } - return json(user) - }, - }) - ``` - -- Using the `setResponseStatus` helper function from `@tanstack/react-start/server` - - ```ts - // routes/api/hello.ts - import { json } from '@tanstack/react-start' - import { createAPIFileRoute } from '@tanstack/react-start/api' - import { setResponseStatus } from '@tanstack/react-start/server' - - export const APIRoute = createAPIFileRoute('/users/$id')({ - GET: async ({ request, params }) => { - const user = await findUser(params.id) - if (!user) { - setResponseStatus(404) - return new Response('User not found') - } - return json(user) - }, - }) - ``` - -In this example, we're returning a `404` status code if the user is not found. You can set any valid HTTP status code using this method. - -## Setting headers in the response - -Sometimes you may need to set headers in the response. You can do this by either: - -- Passing an object as the second argument to the `Response` constructor. - - ```ts - // routes/api/hello.ts - import { createAPIFileRoute } from '@tanstack/react-start/api' - - export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - return new Response('Hello, World!', { - headers: { - 'Content-Type': 'text/plain', - }, - }) - }, - }) - - // Visit /api/hello to see the response - // Hello, World! - ``` - -- Or using the `setHeaders` helper function from `@tanstack/react-start/server`. - - ```ts - // routes/api/hello.ts - import { createAPIFileRoute } from '@tanstack/react-start/api' - import { setHeaders } from '@tanstack/react-start/server' - - export const APIRoute = createAPIFileRoute('/api/hello')({ - GET: async ({ request }) => { - setHeaders({ - 'Content-Type': 'text/plain', - }) - return new Response('Hello, World!') - }, - }) - ``` diff --git a/docs/start/framework/react/build-from-scratch.md b/docs/start/framework/react/build-from-scratch.md index 5cb2e8e483..114ade8273 100644 --- a/docs/start/framework/react/build-from-scratch.md +++ b/docs/start/framework/react/build-from-scratch.md @@ -47,14 +47,12 @@ We highly recommend using TypeScript with TanStack Start. Create a `tsconfig.jso ## Install Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. - -> [!NOTE] > \*Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin or dedicated TanStack Start CLI. +TanStack Start is (currently\*) powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router) and requires them as dependencies. To install them, run: ```shell -npm i @tanstack/react-start @tanstack/react-router vinxi +npm i @tanstack/react-start @tanstack/react-router vite ``` You'll also need React and the Vite React plugin, so install them too: @@ -72,16 +70,16 @@ npm i -D typescript @types/react @types/react-dom ## Update Configuration Files -We'll then update our `package.json` to use Vinxi's CLI and set `"type": "module"`: +We'll then update our `package.json` to set `"type": "module"`: ```json { // ... "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" } } ``` @@ -106,12 +104,10 @@ export default defineConfig({ ## Add the Basic Templating -There are four required files for TanStack Start usage: +There are 2 required files for TanStack Start usage: 1. The router configuration -2. The server entry point -3. The client entry point -4. The root of your application +2. The root of your application Once configuration is done, we'll have a file tree that looks like the following: @@ -120,10 +116,8 @@ Once configuration is done, we'll have a file tree that looks like the following ├── app/ │ ├── routes/ │ │ └── `__root.tsx` -│ ├── `client.tsx` │ ├── `router.tsx` │ ├── `routeTree.gen.ts` -│ └── `ssr.tsx` ├── `.gitignore` ├── `app.config.ts` ├── `package.json` @@ -159,48 +153,6 @@ declare module '@tanstack/react-router' { } ``` -## The Server Entry Point - -As TanStack Start is an [SSR](https://unicorn-utterances.com/posts/what-is-ssr-and-ssg) framework, we need to pipe this router -information to our server entry point: - -```tsx -// app/ssr.tsx -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) -``` - -This allows us to know what routes and loaders we need to execute when the user hits a given route. - -## The Client Entry Point - -Now we need a way to hydrate our client-side JavaScript once the route resolves to the client. We do this by piping the same -router information to our client entry point: - -```tsx -// app/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) -``` - -This enables us to kick off client-side routing once the user's initial server request has fulfilled. - ## The Root of Your Application Finally, we need to create the root of our application. This is the entry point for all other routes. The code in this file will wrap all other routes in the application. diff --git a/docs/start/framework/react/hosting.md b/docs/start/framework/react/hosting.md index c7ef0d3485..d5dfeff318 100644 --- a/docs/start/framework/react/hosting.md +++ b/docs/start/framework/react/hosting.md @@ -3,7 +3,7 @@ id: hosting title: Hosting --- -Hosting is the process of deploying your application to the internet so that users can access it. This is a critical part of any web development project, ensuring your application is available to the world. TanStack Start is built on [Nitro](https://nitro.unjs.io/), a powerful server toolkit for deploying web applications anywhere. Nitro allows TanStack Start to provide a unified API for SSR, streaming, and hydration on any hosting provider. +Hosting is the process of deploying your application to the internet so that users can access it. This is a critical part of any web development project, ensuring your application is available to the world. TanStack Start is built on Vite, a powerful dev/build platform that allows us to make it possible to deploy your application to any hosting provider. ## What should I use? diff --git a/docs/start/framework/react/learn-the-basics.md b/docs/start/framework/react/learn-the-basics.md index 4703259c5a..fa8a6451be 100644 --- a/docs/start/framework/react/learn-the-basics.md +++ b/docs/start/framework/react/learn-the-basics.md @@ -7,13 +7,10 @@ This guide will help you learn the basics behind how TanStack Start works, regar ## Dependencies -TanStack Start is (currently\*) powered by [Vinxi](https://vinxi.vercel.app/), [Nitro](https://nitro.unjs.io/) and [TanStack Router](https://tanstack.com/router). +TanStack Start is powered by [Vite](https://vite.dev/) and [TanStack Router](https://tanstack.com/router). - **TanStack Router**: A router for building web applications. -- **Nitro**: A framework for building server applications. -- **Vinxi**: A server framework for building web applications. - -> [!NOTE] Vinxi will be removed before version 1.0.0 is released and TanStack will rely only on Vite and Nitro. The commands and APIs that use Vinxi will likely be replaced with a Vite plugin. +- **Vite**: A build tool for bundling your application. ## It all "Starts" with the Router @@ -47,14 +44,15 @@ declare module '@tanstack/react-router' { The `routeTree.gen.ts` file is generated when you run TanStack Start (via `npm run dev` or `npm run start`) for the first time. This file contains the generated route tree and a handful of TS utilities that make TanStack Start fully type-safe. -## The Server Entry Point +## The Server Entry Point (Optional) -Although TanStack Start is designed with client-first APIs, it is by and large, a full-stack framework. This means that all use cases, including both dynamic and static rely on a server or build-time entry to render our application's initial HTML payload. +> [!NOTE] +> The server entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the server entry point for you using the below as a default. -This is done via the `app/ssr.tsx` file: +This is done via the `src/server.tsx` file: ```tsx -// app/ssr.tsx +// src/server.tsx import { createStartHandler, defaultStreamHandler, @@ -69,13 +67,16 @@ export default createStartHandler({ })(defaultStreamHandler) ``` -Whether we are statically generating our app or serving it dynamically, the `ssr.tsx` file is the entry point for doing all SSR-related work. +Whether we are statically generating our app or serving it dynamically, the `server.tsx` file is the entry point for doing all SSR-related work. - It's important that a new router is created for each request. This ensures that any data handled by the router is unique to the request. - The `getRouterManifest` function is used to generate the router manifest, which is used to determine many aspects of asset management and preloading for our application. - The `defaultStreamHandler` function is used to render our application to a stream, allowing us to take advantage of streaming HTML to the client. (This is the default handler, but you can also use other handlers like `defaultRenderHandler`, or even build your own) -## The Client Entry Point +## The Client Entry Point (Optional) + +> [!NOTE] +> The client entry point is **optional** out of the box. If not provided, TanStack Start will automatically handle the client entry point for you using the below as a default. Getting our html to the client is only half the battle. Once there, we need to hydrate our client-side JavaScript once the route resolves to the client. We do this by hydrating the root of our application with the `StartClient` component: @@ -94,7 +95,7 @@ This enables us to kick off client-side routing once the user's initial server r ## The Root of Your Application -Other than the client entry point, the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. +Other than the client entry point (which is optional by default), the `__root` route of your application is the entry point for your application. The code in this file will wrap all other routes in the app, including your home page. It behaves like a pathless layout route for your whole application. Because it is **always rendered**, it is the perfect place to construct your application shell and take care of any global logic. diff --git a/docs/start/framework/react/overview.md b/docs/start/framework/react/overview.md index 84e036c7b3..b656127b06 100644 --- a/docs/start/framework/react/overview.md +++ b/docs/start/framework/react/overview.md @@ -3,7 +3,7 @@ id: overview title: TanStack Start Overview --- -TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more using tools like [Nitro](https://nitro.unjs.io/) and [Vite](https://vitejs.dev/). It is ready to deploy to your favorite hosting provider! +TanStack Start is a full-stack React framework powered by TanStack Router. It provides a full-document SSR, streaming, server functions, bundling, and more. Thanks to [Vite](https://vite.dev/), it's ready to develop and deploy to any hosting provider or runtime you want! ## Router or Start? @@ -39,7 +39,7 @@ What you get with TanStack Start: ## How does it work? -TanStack Start uses [Nitro](https://nitro.unjs.io/) and [Vite](https://vitejs.dev/) to bundle and deploy your application. In fact, these are the same tools that power Solid Start! With these tools, we can do a few things we couldn't do before: +TanStack Start uses [Vite](https://vitejs.dev/) to bundle and deploy your application and empowers amazing features like: - Provide a unified API for SSR, streaming, and hydration - Extract server-only code from your client-side code (e.g. server functions) diff --git a/docs/start/framework/react/server-routes.md b/docs/start/framework/react/server-routes.md new file mode 100644 index 0000000000..44ba76293b --- /dev/null +++ b/docs/start/framework/react/server-routes.md @@ -0,0 +1,387 @@ +--- +id: server-routes +title: Server Routes +--- + +// TODO: Add redirect from api-routes to server-routes + +Server routes are a powerful feature of TanStack Start that allow you to create server-side endpoints in your application and are useful for handling raw HTTP requests, form submissions, user authentication, and much more. + +Server routes can be defined in your `./app/routes` directory of your project **right alongside your TanStack Router routes** and are automatically handled by the TanStack Start server. + +Here's what a simple server route looks like: + +```ts +// routes/hello.ts + +export const ServerRoute = createServerRoute({ + GET: async ({ request }) => { + return new Response('Hello, World!') + }, +}) +``` + +## Server Routes and App Routes + +Because server routes can be defined in the same directory as your app routes, you can even use the same file for both! + +```tsx +// routes/hello.ts + +export const ServerRoute = createServerRoute().methods({ + POST: async ({ request }) => { + const body = await request.json() + return new Response(JSON.stringify({ message: `Hello, ${body.name}!` })) + }, +}) + +export const Route = createFileRoute({ + component: HelloComponent, +}) + +function HelloComponent() { + const [reply, setReply] = useState('') + + return ( +
+ +
+ ) +} +``` + +## File Route Conventions + +Server routes in TanStack Start, follow the same file-based routing conventions as TanStack Router. This means that each file in your `routes` directory with a `ServerRoute` export will be treated as an API route. Here are a few examples: + +- `/routes/users.ts` will create an API route at `/users` +- `/routes/users.index.ts` will **also** create an API route at `/users` (but will error if duplicate methods are defined) +- `/routes/users/$id.ts` will create an API route at `/users/$id` +- `/routes/users/$id/posts.ts` will create an API route at `/users/$id/posts` +- `/routes/users.$id.posts.ts` will create an API route at `/users/$id/posts` +- `/routes/file/$.ts` will create an API route at `/api/file/$` +- `/routes/my-script[.]js.ts` will create an API route at `/my-script.js` + +## Unique Route Paths + +Each route can only have a single handler file associated with it. So, if you have a file named `routes/users.ts` which'd equal the request path of `/api/users`, you cannot have other files that'd also resolve to the same route. For example, the following files would all resolve to the same route and would error: + +- `/routes/users.index.ts` +- `/routes/users.ts` +- `/routes/users.index.ts` + +## Escaped Matching + +Just as with normal routes, server routes can match on escaped characters. For example, a file named `routes/users[.]ts` will create an API route at `/api/users[.]`. + +## Pathless Layout Routes and Break-out Routes + +Because of the unified routing system, pathless layout routes and break-out routes are supported for similar functionality around server route middleware. + +- Pathless layout routes can be used to add middleware to a group of routes +- Break-out routes can be used to "break out" of parent middleware + +## Nested Directories vs File-names + +In the examples above, you may have noticed that the file naming conventions are flexible and allow you to mix and match directories and file names. This is intentional and allows you to organize your Server routes in a way that makes sense for your application. You can read more about this in the [TanStack Router File-based Routing Guide](/router/latest/docs/framework/react/routing/file-based-routing#s-or-s). + +## Handling Server Route Requests + +Server route requests are handled by Start's `createStartHandler` in your `server.ts` entry file. + +```tsx +// server.ts +import { createStartHandler } from '@tanstack/react-start/server' + +export default createStartHandler({ + createRouter, + getRouterManifest, +})(defaultStreamHandler) +``` + +The start handler is responsible for matching an incoming request to a server route and executing the appropriate middleware, validators and handler. + +Remember, if you need to customize the server handler, you can do so by creating a custom handler and then passing the event to the start handler: + +```tsx +// server.ts +import { createStartHandler } from '@tanstack/react-start/server' + +export default defineHandler((event) => { + const startHandler = createStartHandler({ + createRouter, + getRouterManifest, + })(defaultStreamHandler) + + return startHandler(event) +}) +``` + +## Defining an Server Route + +Server routes are created by exporting a `ServerRoute` from a route file. The `ServerRoute` export should be created by calling the `createServerFileRoute` function. The resulting builder object can then be used to: + +- Add route-level middleware +- Define handlers for each HTTP method +- Add middleware and validators to specific HTTP methods + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }, +}) +``` + +## Defining a Server Route Handler + +There are two ways to define a handler for a server route. + +- Provide a handler function directly to the method +- By calling the `handler` method on the method builder object for more advanced use cases + +### Providing a handler function directly to the method + +For simple use cases, you can provide a handler function directly to the method. + +```ts +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }, +}) +``` + +### Providing a handler function via the method builder object + +For more complex use cases, you can provide a handler function via the method builder object. This allows you to: + +- Add middleware to the method +- Add a validator to the method + +```tsx +// routes/hello.ts +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: api + .middleware([loggerMiddleware]) + .validator(z.object({ name: z.string() })) + .handler(async ({ request }) => { + return new Response('Hello, World! from ' + request.url) + }), +})) +``` + +## Handler Context + +Each HTTP method handler receives an object with the following properties: + +- `request`: The incoming request object. You can read more about the `Request` object in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Request). +- `params`: An object containing the dynamic path parameters of the route. For example, if the route path is `/users/$id`, and the request is made to `/users/123`, then `params` will be `{ id: '123' }`. We'll cover dynamic path parameters and wildcard parameters later in this guide. +- `context`: An object containing the context of the request. This is useful for passing data between middleware. + +Once you've processed the request, you can return a `Response` object or `Promise` or even use any of the helpers from `@tanstack/react-start` to manipulate the response. + +## Dynamic Path Params + +Server routes support dynamic path parameters in the same way as TanStack Router. For example, a file named `routes/users/$id.ts` will create an API route at `/users/$id` that accepts a dynamic `id` parameter. + +```ts +// routes/users/$id.ts +export const APIRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { id } = params + return new Response(`User ID: ${id}`) + }, +}) + +// Visit /api/users/123 to see the response +// User ID: 123 +``` + +You can also have multiple dynamic path parameters in a single route. For example, a file named `routes/users/$id/posts/$postId.ts` will create an API route at `/api/users/$id/posts/$postId` that accepts two dynamic parameters. + +```ts +// routes/users/$id/posts/$postId.ts +export const APIRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { id, postId } = params + return new Response(`User ID: ${id}, Post ID: ${postId}`) + }, +}) + +// Visit /api/users/123/posts/456 to see the response +// User ID: 123, Post ID: 456 +``` + +## Wildcard/Splat Param + +Server routes also support wildcard parameters at the end of the path, which are denoted by a `$` followed by nothing. For example, a file named `routes/file/$.ts` will create an API route at `/api/file/$` that accepts a wildcard parameter. + +```ts +// routes/file/$.ts +export const APIRoute = createServerFileRoute().methods({ + GET: async ({ params }) => { + const { _splat } = params + return new Response(`File: ${_splat}`) + }, +}) + +// Visit /api/file/hello.txt to see the response +// File: hello.txt +``` + +## Handling requests with a body + +To handle POST requests,you can add a `POST` handler to the route object. The handler will receive the request object as the first argument, and you can access the request body using the `request.json()` method. + +```ts +// routes/hello.ts +export const APIRoute = createServerFileRoute().methods({ + POST: async ({ request }) => { + const body = await request.json() + return new Response(`Hello, ${body.name}!`) + }, +}) + +// Send a POST request to /api/hello with a JSON body like { "name": "Tanner" } +// Hello, Tanner! +``` + +This also applies to other HTTP methods like `PUT`, `PATCH`, and `DELETE`. You can add handlers for these methods in the route object and access the request body using the appropriate method. + +It's important to remember that the `request.json()` method returns a `Promise` that resolves to the parsed JSON body of the request. You need to `await` the result to access the body. + +This is a common pattern for handling POST requests in Server routes/ You can also use other methods like `request.text()` or `request.formData()` to access the body of the request. + +## Responding with JSON + +When returning JSON using a Response object, this is a common pattern: + +```ts +// routes/hello.ts +export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response(JSON.stringify({ message: 'Hello, World!' }), { + headers: { + 'Content-Type': 'application/json', + }, + }) + }, +}) + +// Visit /api/hello to see the response +// {"message":"Hello, World!"} +``` + +## Using the `json` helper function + +Or you can use the `json` helper function to automatically set the `Content-Type` header to `application/json` and serialize the JSON object for you. + +```ts +// routes/hello.ts +import { json } from '@tanstack/react-start' + +export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return json({ message: 'Hello, World!' }) + }, +}) + +// Visit /api/hello to see the response +// {"message":"Hello, World!"} +``` + +## Responding with a status code + +You can set the status code of the response by either: + +- Passing it as a property of the second argument to the `Response` constructor + + ```ts + // routes/hello.ts + import { json } from '@tanstack/react-start' + + export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request, params }) => { + const user = await findUser(params.id) + if (!user) { + return new Response('User not found', { + status: 404, + }) + } + return json(user) + }, + }) + ``` + +- Using the `setResponseStatus` helper function from `@tanstack/react-start/server` + + ```ts + // routes/hello.ts + import { json } from '@tanstack/react-start' + import { setResponseStatus } from '@tanstack/react-start/server' + + export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request, params }) => { + const user = await findUser(params.id) + if (!user) { + setResponseStatus(404) + return new Response('User not found') + } + return json(user) + }, + }) + ``` + +In this example, we're returning a `404` status code if the user is not found. You can set any valid HTTP status code using this method. + +## Setting headers in the response + +Sometimes you may need to set headers in the response. You can do this by either: + +- Passing an object as the second argument to the `Response` constructor. + + ```ts + // routes/hello.ts + export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + return new Response('Hello, World!', { + headers: { + 'Content-Type': 'text/plain', + }, + }) + }, + }) + + // Visit /api/hello to see the response + // Hello, World! + ``` + +- Or using the `setHeaders` helper function from `@tanstack/react-start/server`. + + ```ts + // routes/hello.ts + import { setHeaders } from '@tanstack/react-start/server' + + export const APIRoute = createServerFileRoute().methods({ + GET: async ({ request }) => { + setHeaders({ + 'Content-Type': 'text/plain', + }) + return new Response('Hello, World!') + }, + }) + ``` diff --git a/docs/start/framework/react/ssr.md b/docs/start/framework/react/ssr.md index f509d47f72..b932548555 100644 --- a/docs/start/framework/react/ssr.md +++ b/docs/start/framework/react/ssr.md @@ -7,10 +7,10 @@ Server-side rendering (SSR) is the process of rendering your application on the ## SSR Basics -TanStack Start supports server-side rendering out of the box. To enable server-side rendering, create an `app/ssr.tsx` file in your project: +TanStack Start supports server-side rendering out of the box. To enable server-side rendering, create an `src/server.tsx` file in your project: ```tsx -// app/ssr.tsx +// src/server.tsx import { createStartHandler, diff --git a/docs/start/framework/react/static-prerendering.md b/docs/start/framework/react/static-prerendering.md index 768e11d539..30111f24fb 100644 --- a/docs/start/framework/react/static-prerendering.md +++ b/docs/start/framework/react/static-prerendering.md @@ -3,13 +3,11 @@ id: static-prerendering title: Static Prerendering --- -> Static Prerendering is a feature of Nitro, and while it is available in TanStack Start, we are still exploring the best practices for using it. Tread lightly! - Static prerendering is the process of generating static HTML files for your application. This can be useful for either improving the performance of your application, as it allows you to serve pre-rendered HTML files to users without having to generate them on the fly or for deploying static sites to platforms that do not support server-side rendering. -## Prerendering, powered by Nitro +## Prerendering -TanStack Start is built on Nitro, which means we can take advantage of Nitro's prerendering capabilities. Nitro can prerender your application to static HTML files, which can then be served to users without having to generate them on the fly. To prerender your application, you can add the `server.prerender` option to your `app.config.js` file: +TanStack Start can prerender your application to static HTML files, which can then be served to users without having to generate them on the fly. To prerender your application, you can add the `server.prerender` option to your `app.config.js` file: ```js // app.config.js @@ -25,39 +23,3 @@ export default defineConfig({ }, }) ``` - -Many of the options available for prerendering are documented in the [Nitro config prerender documentation](https://nitro.unjs.io/config#prerender). - -## Prerendering dynamic routes with Nitro - -Nitro ships with some prebuilt hooks that let you customize the prerendering process among other things. One of these hooks is the `prerender:routes` hook. This hook allows you to fetch async data and add routes to a `Set` of routes to be prerendered. - -For this example, let's pretend we have a blog with a list of posts. We want to prerender each post page. Our post route looks like `/posts/$postId`. We can use the `prerender:routes` hook to fetch the all of our posts and add each post path to the routes set. - -```ts -// app.config.ts -import { defineConfig } from '@tanstack/react-start/config' - -export default defineConfig({ - server: { - hooks: { - 'prerender:routes': async (routes) => { - // fetch the pages you want to render - const posts = await fetch('https://api.example.com/posts') - const postsData = await posts.json() - - // add each post path to the routes set - postsData.forEach((post) => { - routes.add(`/posts/${post.id}`) - }) - }, - }, - prerender: { - routes: ['/'], - crawlLinks: true, - }, - }, -}) -``` - -As of writing, the [Nitro hooks documentation](https://nitro.build/config#hooks) does not include any information on the provided hooks. diff --git a/e2e/create-start/utils/setup.ts b/e2e/create-start/utils/setup.ts index bfb4c1fd53..5f0af79fee 100644 --- a/e2e/create-start/utils/setup.ts +++ b/e2e/create-start/utils/setup.ts @@ -15,7 +15,7 @@ async function _setup( const ADDR = `http://localhost:${port}` const childProcess = exec( - `VITE_SERVER_PORT=${port} pnpm vinxi dev --port ${port}`, + `VITE_SERVER_PORT=${port} pnpm vite dev --port ${port}`, { cwd: projectPath, }, diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts index 0cc7397492..e15a1921e5 100644 --- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts +++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts @@ -432,6 +432,152 @@ declare module '@tanstack/react-router' { } } +declare module './routes/index' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/'> + > +} +declare module './routes/_layout' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/_layout'> + > +} +declare module './routes/anchor' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/anchor'> + > +} +declare module './routes/editing-a' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/editing-a'> + > +} +declare module './routes/editing-b' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/editing-b'> + > +} +declare module './routes/posts' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/posts'> + > +} +declare module './routes/(another-group)/onlyrouteinside' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(another-group)/onlyrouteinside'> + > +} +declare module './routes/(group)' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)'> + > +} +declare module './routes/(group)/_layout' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)/_layout'> + > +} +declare module './routes/(group)/inside' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)/inside'> + > +} +declare module './routes/(group)/lazyinside' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)/lazyinside'> + > +} +declare module './routes/_layout/_layout-2' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/_layout/_layout-2'> + > +} +declare module './routes/posts.$postId' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/posts/$postId'> + > +} +declare module './routes/redirect/$target' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/$target'> + > +} +declare module './routes/structural-sharing.$enabled' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/structural-sharing/$enabled'> + > +} +declare module './routes/posts.index' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/posts/'> + > +} +declare module './routes/redirect/index' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/'> + > +} +declare module './routes/(group)/_layout.insidelayout' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)/_layout/insidelayout'> + > +} +declare module './routes/(group)/subfolder/inside' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/(group)/subfolder/inside'> + > +} +declare module './routes/_layout/_layout-2/layout-a' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/_layout/_layout-2/layout-a'> + > +} +declare module './routes/_layout/_layout-2/layout-b' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/_layout/_layout-2/layout-b'> + > +} +declare module './routes/params.single.$value' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/params/single/$value'> + > +} +declare module './routes/posts_.$postId.edit' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/posts_/$postId/edit'> + > +} +declare module './routes/redirect/$target/via-beforeLoad' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/$target/via-beforeLoad'> + > +} +declare module './routes/redirect/$target/via-loader' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/$target/via-loader'> + > +} +declare module './routes/redirect/preload/first' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/preload/first'> + > +} +declare module './routes/redirect/preload/second' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/preload/second'> + > +} +declare module './routes/redirect/preload/third' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/preload/third'> + > +} +declare module './routes/redirect/$target/index' { + const createFileRoute: ReturnType< + typeof import('@tanstack/react-router').createFileRouteImpl<'/redirect/$target/'> + > +} + // Create and export the route tree interface LayoutLayout2RouteChildren { diff --git a/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx b/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx index bbd1eedb6f..bcc87859bb 100644 --- a/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(another-group)/onlyrouteinside.tsx @@ -4,7 +4,7 @@ import { zodValidator } from '@tanstack/zod-adapter' const routeApi = getRouteApi('/(another-group)/onlyrouteinside') -export const Route = createFileRoute('/(another-group)/onlyrouteinside')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ hello: z.string().optional() })), component: () => { const searchViaHook = useSearch({ diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx index 2975baedc9..4e1ddc648c 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.insidelayout.tsx @@ -4,7 +4,7 @@ import { zodValidator } from '@tanstack/zod-adapter' const routeApi = getRouteApi('/(group)/_layout/insidelayout') -export const Route = createFileRoute('/(group)/_layout/insidelayout')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ hello: z.string().optional() })), component: () => { const searchViaHook = useSearch({ from: '/(group)/_layout/insidelayout' }) diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx index 4b755791c0..31f57f0fb5 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/_layout.tsx @@ -1,6 +1,6 @@ import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/(group)/_layout')({ +export const Route = createFileRoute({ component: () => ( <>
/(group)/_layout!
diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx index 356ff96003..dd95cde83e 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/inside.tsx @@ -4,7 +4,7 @@ import { zodValidator } from '@tanstack/zod-adapter' const routeApi = getRouteApi('/(group)/inside') -export const Route = createFileRoute('/(group)/inside')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ hello: z.string().optional() })), component: () => { const searchViaHook = useSearch({ from: '/(group)/inside' }) diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx index 527be4f520..1597742495 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.lazy.tsx @@ -6,7 +6,7 @@ import { const routeApi = getRouteApi('/(group)/lazyinside') -export const Route = createLazyFileRoute('/(group)/lazyinside')({ +export const Route = createLazyFileRoute({ component: () => { const searchViaHook = useSearch({ from: '/(group)/lazyinside' }) const searchViaRouteHook = Route.useSearch() diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx index 0f52a40d98..7cb5fe027b 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/lazyinside.tsx @@ -2,6 +2,6 @@ import { createFileRoute } from '@tanstack/react-router' import { z } from 'zod' import { zodValidator } from '@tanstack/zod-adapter' -export const Route = createFileRoute('/(group)/lazyinside')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ hello: z.string().optional() })), }) diff --git a/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx b/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx index 3a4a051e8a..b148a408ae 100644 --- a/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx +++ b/e2e/react-router/basic-file-based/src/routes/(group)/subfolder/inside.tsx @@ -4,7 +4,7 @@ import { zodValidator } from '@tanstack/zod-adapter' const routeApi = getRouteApi('/(group)/subfolder/inside') -export const Route = createFileRoute('/(group)/subfolder/inside')({ +export const Route = createFileRoute({ validateSearch: zodValidator(z.object({ hello: z.string().optional() })), component: () => { const searchViaHook = useSearch({ from: '/(group)/subfolder/inside' }) diff --git a/e2e/react-router/basic-file-based/src/routes/_layout.tsx b/e2e/react-router/basic-file-based/src/routes/_layout.tsx index 02ddbb1cd9..582cfef366 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout.tsx @@ -1,6 +1,6 @@ import { Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx index 3b7dbf2903..c4b1085ae0 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2.tsx @@ -1,6 +1,6 @@ import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx index 61e19b4d9f..0eef1bea7d 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-a.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2/layout-a')({ +export const Route = createFileRoute({ component: LayoutAComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx index cceed1fb9a..35e70a9a98 100644 --- a/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx +++ b/e2e/react-router/basic-file-based/src/routes/_layout/_layout-2/layout-b.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_layout/_layout-2/layout-b')({ +export const Route = createFileRoute({ component: LayoutBComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/anchor.tsx b/e2e/react-router/basic-file-based/src/routes/anchor.tsx index 93975ba621..d3ca808330 100644 --- a/e2e/react-router/basic-file-based/src/routes/anchor.tsx +++ b/e2e/react-router/basic-file-based/src/routes/anchor.tsx @@ -6,7 +6,7 @@ import { useNavigate, } from '@tanstack/react-router' -export const Route = createFileRoute('/anchor')({ +export const Route = createFileRoute({ component: AnchorComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/editing-a.tsx b/e2e/react-router/basic-file-based/src/routes/editing-a.tsx index cecd0dfed1..0f65f8bf72 100644 --- a/e2e/react-router/basic-file-based/src/routes/editing-a.tsx +++ b/e2e/react-router/basic-file-based/src/routes/editing-a.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createFileRoute, useBlocker } from '@tanstack/react-router' -export const Route = createFileRoute('/editing-a')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/editing-b.tsx b/e2e/react-router/basic-file-based/src/routes/editing-b.tsx index 1a85e72e26..ec883811f4 100644 --- a/e2e/react-router/basic-file-based/src/routes/editing-b.tsx +++ b/e2e/react-router/basic-file-based/src/routes/editing-b.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createFileRoute, useBlocker } from '@tanstack/react-router' -export const Route = createFileRoute('/editing-b')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/index.tsx b/e2e/react-router/basic-file-based/src/routes/index.tsx index eac82a9174..b23956ae17 100644 --- a/e2e/react-router/basic-file-based/src/routes/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: Home, }) diff --git a/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx b/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx index b5761e839e..a2cd180ce8 100644 --- a/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx +++ b/e2e/react-router/basic-file-based/src/routes/params.single.$value.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { Link, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/params/single/$value')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx b/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx index df51873ddf..8401ba1e0f 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.$postId.tsx @@ -3,7 +3,7 @@ import { ErrorComponent, createFileRoute } from '@tanstack/react-router' import { fetchPost } from '../posts' import type { ErrorComponentProps } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost(postId), errorComponent: PostErrorComponent, notFoundComponent: () => { diff --git a/e2e/react-router/basic-file-based/src/routes/posts.index.tsx b/e2e/react-router/basic-file-based/src/routes/posts.index.tsx index ab89fb5a62..8de87f515a 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/posts.tsx b/e2e/react-router/basic-file-based/src/routes/posts.tsx index 9eabdd5b33..f8825e4c3e 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import { Link, Outlet, createFileRoute } from '@tanstack/react-router' import { fetchPosts } from '../posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute()({ head: () => ({ meta: [ { diff --git a/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx b/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx index 44a62b0004..b05da729bf 100644 --- a/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx +++ b/e2e/react-router/basic-file-based/src/routes/posts_.$postId.edit.tsx @@ -1,6 +1,6 @@ import { createFileRoute, getRouteApi, useParams } from '@tanstack/react-router' -export const Route = createFileRoute('/posts_/$postId/edit')({ +export const Route = createFileRoute({ component: PostEditPage, }) diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx index 686f1c7056..c7c9b80108 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target.tsx @@ -1,7 +1,7 @@ import { createFileRoute, retainSearchParams } from '@tanstack/react-router' import z from 'zod' -export const Route = createFileRoute('/redirect/$target')({ +export const Route = createFileRoute({ params: { parse: (p) => z diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx index 57760cec88..4069e261b1 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/index.tsx @@ -1,6 +1,6 @@ import { Link, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/')({ +export const Route = createFileRoute({ component: () => { const preload = Route.useSearch({ select: (s) => s.preload }) return ( diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx index 14a2492331..8ab3dff8e5 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-beforeLoad.tsx @@ -1,6 +1,6 @@ import { createFileRoute, redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/via-beforeLoad')({ +export const Route = createFileRoute({ beforeLoad: ({ params: { target }, search: { reloadDocument, externalHost }, diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx index 9e6a3fc9db..0269dc1fa7 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/$target/via-loader.tsx @@ -1,6 +1,6 @@ import { createFileRoute, redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/$target/via-loader')({ +export const Route = createFileRoute({ loaderDeps: ({ search: { reloadDocument, externalHost } }) => ({ reloadDocument, externalHost, diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx index c0b26a1df4..a420a4ea61 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/index.tsx @@ -1,6 +1,6 @@ import { Link, createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/')({ +export const Route = createFileRoute({ component: () => (
{ await new Promise((r) => setTimeout(r, 1000)) throw redirect({ from: Route.fullPath, to: '../third' }) diff --git a/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx b/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx index e882d29e69..4de62f9e03 100644 --- a/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx +++ b/e2e/react-router/basic-file-based/src/routes/redirect/preload/third.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect/preload/third')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx b/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx index 4a477f7ccd..8649bc38c1 100644 --- a/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx +++ b/e2e/react-router/basic-file-based/src/routes/structural-sharing.$enabled.tsx @@ -17,7 +17,7 @@ const enabledSchema = { }, z.boolean()), } -export const Route = createFileRoute('/structural-sharing/$enabled')({ +export const Route = createFileRoute({ component: RouteComponent, params: { parse: (p) => z.object(enabledSchema).parse(p), diff --git a/e2e/react-start/basic-auth/.gitignore b/e2e/react-start/basic-auth/.gitignore index b15fed94e2..75a469e80c 100644 --- a/e2e/react-start/basic-auth/.gitignore +++ b/e2e/react-start/basic-auth/.gitignore @@ -7,13 +7,11 @@ yarn.lock .cache .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/react-start/basic-auth/package.json b/e2e/react-start/basic-auth/package.json index bb04401e02..f0223cf4a1 100644 --- a/e2e/react-start/basic-auth/package.json +++ b/e2e/react-start/basic-auth/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build", + "start": "vite start", "prisma-generate": "prisma generate", "test:e2e": "exit 0; pnpm run prisma-generate && playwright test --project=chromium" }, @@ -20,8 +20,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@playwright/test": "^1.50.1", diff --git a/e2e/react-start/basic-auth/src/client.tsx b/e2e/react-start/basic-auth/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/basic-auth/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-react-query/.gitignore b/e2e/react-start/basic-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/basic-react-query/.gitignore +++ b/e2e/react-start/basic-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/basic-react-query/package.json b/e2e/react-start/basic-react-query/package.json index 4cc7162526..c7d7424af0 100644 --- a/e2e/react-start/basic-react-query/package.json +++ b/e2e/react-start/basic-react-query/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -20,8 +20,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@playwright/test": "^1.50.1", diff --git a/e2e/react-start/basic-react-query/src/client.tsx b/e2e/react-start/basic-react-query/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/basic-react-query/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/basic-rsc/.gitignore b/e2e/react-start/basic-rsc/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/e2e/react-start/basic-rsc/.gitignore +++ b/e2e/react-start/basic-rsc/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/e2e/react-start/basic-rsc/package.json b/e2e/react-start/basic-rsc/package.json index c93361fa88..fc2369d466 100644 --- a/e2e/react-start/basic-rsc/package.json +++ b/e2e/react-start/basic-rsc/package.json @@ -4,9 +4,9 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@babel/plugin-syntax-typescript": "^7.25.9", @@ -16,8 +16,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/e2e/react-start/basic-rsc/src/client.tsx b/e2e/react-start/basic-rsc/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/basic-rsc/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/basic-tsr-config/.gitignore b/e2e/react-start/basic-tsr-config/.gitignore index 2b76174be5..08eba9e706 100644 --- a/e2e/react-start/basic-tsr-config/.gitignore +++ b/e2e/react-start/basic-tsr-config/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/basic-tsr-config/package.json b/e2e/react-start/basic-tsr-config/package.json index cd697d2bfb..78fa63c5fc 100644 --- a/e2e/react-start/basic-tsr-config/package.json +++ b/e2e/react-start/basic-tsr-config/package.json @@ -4,18 +4,17 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "rimraf ./count.txt && vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "rimraf ./count.txt && vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { "@tanstack/react-router": "workspace:^", "@tanstack/react-start": "workspace:^", "react": "^19.0.0", - "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@tanstack/router-e2e-utils": "workspace:^", diff --git a/e2e/react-start/basic-tsr-config/src/app/client.tsx b/e2e/react-start/basic-tsr-config/src/app/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/basic-tsr-config/src/app/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic/.gitignore b/e2e/react-start/basic/.gitignore index be342025da..a79d5cf129 100644 --- a/e2e/react-start/basic/.gitignore +++ b/e2e/react-start/basic/.gitignore @@ -7,13 +7,11 @@ yarn.lock .env .vercel .output -.vinxi /build/ /api/ /server/build /public/build -.vinxi # Sentry Config File .env.sentry-build-plugin /test-results/ diff --git a/e2e/react-start/basic/package.json b/e2e/react-start/basic/package.json index 2046e82f17..8f0fd1fb2f 100644 --- a/e2e/react-start/basic/package.json +++ b/e2e/react-start/basic/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -18,7 +18,6 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/basic/src/client.tsx b/e2e/react-start/basic/src/client.tsx deleted file mode 100644 index b14d8aac68..0000000000 --- a/e2e/react-start/basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic/src/ssr.tsx b/e2e/react-start/basic/src/ssr.tsx deleted file mode 100644 index 62572579ac..0000000000 --- a/e2e/react-start/basic/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/start/server' -import { getRouterManifest } from '@tanstack/start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/react-start/clerk-basic/.gitignore b/e2e/react-start/clerk-basic/.gitignore index b15fed94e2..2818549158 100644 --- a/e2e/react-start/clerk-basic/.gitignore +++ b/e2e/react-start/clerk-basic/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/clerk-basic/package.json b/e2e/react-start/clerk-basic/package.json index c2c2bb13fe..d258ae2303 100644 --- a/e2e/react-start/clerk-basic/package.json +++ b/e2e/react-start/clerk-basic/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build", + "start": "vite start", "test:e2e": "exit 0; playwright test --project=chromium" }, "dependencies": { @@ -18,8 +18,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@playwright/test": "^1.50.1", diff --git a/e2e/react-start/clerk-basic/src/client.tsx b/e2e/react-start/clerk-basic/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/clerk-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/clerk-basic/src/server.tsx b/e2e/react-start/clerk-basic/src/server.tsx new file mode 100644 index 0000000000..3283a1ba85 --- /dev/null +++ b/e2e/react-start/clerk-basic/src/server.tsx @@ -0,0 +1,18 @@ +import { + createStartHandler, + defaultStreamHandler, + defineEventHandler, +} from '@tanstack/react-start/server' +import { createClerkHandler } from '@clerk/tanstack-start/server' +import { createRouter } from './router' + +export default defineEventHandler((event) => { + const startHandler = createStartHandler({ + createRouter, + }) + + const withClerkHandler = + createClerkHandler(startHandler)(defaultStreamHandler) + + return withClerkHandler(event) +}) diff --git a/e2e/react-start/scroll-restoration/.gitignore b/e2e/react-start/scroll-restoration/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/scroll-restoration/.gitignore +++ b/e2e/react-start/scroll-restoration/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/scroll-restoration/package.json b/e2e/react-start/scroll-restoration/package.json index 73a72f7300..de9d765fad 100644 --- a/e2e/react-start/scroll-restoration/package.json +++ b/e2e/react-start/scroll-restoration/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -19,7 +19,6 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/scroll-restoration/src/client.tsx b/e2e/react-start/scroll-restoration/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/scroll-restoration/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/scroll-restoration/src/routes/__root.tsx b/e2e/react-start/scroll-restoration/src/routes/__root.tsx index bf315e98ae..07037679f0 100644 --- a/e2e/react-start/scroll-restoration/src/routes/__root.tsx +++ b/e2e/react-start/scroll-restoration/src/routes/__root.tsx @@ -7,6 +7,7 @@ import { HeadContent, Scripts, } from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' @@ -66,6 +67,7 @@ function RootComponent() { return ( + ) } diff --git a/e2e/react-start/server-functions/.gitignore b/e2e/react-start/server-functions/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/server-functions/.gitignore +++ b/e2e/react-start/server-functions/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/server-functions/package.json b/e2e/react-start/server-functions/package.json index 2107818357..4d48b8f7da 100644 --- a/e2e/react-start/server-functions/package.json +++ b/e2e/react-start/server-functions/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -19,7 +19,6 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/server-functions/src/client.tsx b/e2e/react-start/server-functions/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/e2e/react-start/server-functions/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/website/.gitignore b/e2e/react-start/website/.gitignore index be342025da..ca63f49885 100644 --- a/e2e/react-start/website/.gitignore +++ b/e2e/react-start/website/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/e2e/react-start/website/package.json b/e2e/react-start/website/package.json index e69c2b3ffa..980aa9ca51 100644 --- a/e2e/react-start/website/package.json +++ b/e2e/react-start/website/package.json @@ -4,10 +4,10 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev --port 3000", - "dev:e2e": "vinxi dev", - "build": "vinxi build && tsc --noEmit", - "start": "vinxi start", + "dev": "vite dev --port 3000", + "dev:e2e": "vite dev", + "build": "vite build && tsc --noEmit", + "start": "vite start", "test:e2e": "playwright test --project=chromium" }, "dependencies": { @@ -18,7 +18,6 @@ "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/e2e/react-start/website/src/client.tsx b/e2e/react-start/website/src/client.tsx deleted file mode 100644 index 31385f57f1..0000000000 --- a/e2e/react-start/website/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document!, ) diff --git a/e2e/react-start/website/src/ssr.tsx b/e2e/react-start/website/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/e2e/react-start/website/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx index aae7611b51..3f0d097d14 100644 --- a/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx +++ b/e2e/solid-start/scroll-restoration/src/routes/(tests)/with-loader.tsx @@ -1,6 +1,6 @@ import { createFileRoute } from '@tanstack/solid-router' +import { sleep } from 'src/utils/posts' import { ScrollBlock } from '../-components/scroll-block' -import { sleep } from '~/utils/posts' export const Route = createFileRoute('/(tests)/with-loader')({ loader: async () => { diff --git a/e2e/solid-start/website/src/routes/__root.tsx b/e2e/solid-start/website/src/routes/__root.tsx index d33148818f..514d187924 100644 --- a/e2e/solid-start/website/src/routes/__root.tsx +++ b/e2e/solid-start/website/src/routes/__root.tsx @@ -1,8 +1,8 @@ import { Outlet, createRootRoute } from '@tanstack/solid-router' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' -import { seo } from '~/utils/seo' import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' +import { seo } from '~/utils/seo' export const Route = createRootRoute({ head: () => ({ diff --git a/examples/react/authenticated-routes-firebase/package.json b/examples/react/authenticated-routes-firebase/package.json index 13e29af9fa..ec1faa0dee 100644 --- a/examples/react/authenticated-routes-firebase/package.json +++ b/examples/react/authenticated-routes-firebase/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "autoprefixer": "^10.4.20", "firebase": "^11.4.0", "postcss": "^8.5.1", diff --git a/examples/react/authenticated-routes/package.json b/examples/react/authenticated-routes/package.json index fce450e1f7..f247c8f614 100644 --- a/examples/react/authenticated-routes/package.json +++ b/examples/react/authenticated-routes/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-default-search-params/package.json b/examples/react/basic-default-search-params/package.json index 9b0cf7c675..962aed096b 100644 --- a/examples/react/basic-default-search-params/package.json +++ b/examples/react/basic-default-search-params/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-devtools-panel/package.json b/examples/react/basic-devtools-panel/package.json index 09c1da7dd4..4a6b823d07 100644 --- a/examples/react/basic-devtools-panel/package.json +++ b/examples/react/basic-devtools-panel/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "@tanstack/react-query-devtools": "^5.67.2", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/basic-file-based/package.json b/examples/react/basic-file-based/package.json index 80806bcf64..a3c83918ba 100644 --- a/examples/react/basic-file-based/package.json +++ b/examples/react/basic-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-non-nested-devtools/package.json b/examples/react/basic-non-nested-devtools/package.json index 0cf74deaf9..33020a3889 100644 --- a/examples/react/basic-non-nested-devtools/package.json +++ b/examples/react/basic-non-nested-devtools/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-react-query-file-based/package.json b/examples/react/basic-react-query-file-based/package.json index 53d74e2439..396737ac0a 100644 --- a/examples/react/basic-react-query-file-based/package.json +++ b/examples/react/basic-react-query-file-based/package.json @@ -11,9 +11,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-react-query/package.json b/examples/react/basic-react-query/package.json index 5de861a6a0..5a7f29e37b 100644 --- a/examples/react/basic-react-query/package.json +++ b/examples/react/basic-react-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/basic-ssr-file-based/package.json b/examples/react/basic-ssr-file-based/package.json index 303c306a12..b4ea49aaf3 100644 --- a/examples/react/basic-ssr-file-based/package.json +++ b/examples/react/basic-ssr-file-based/package.json @@ -11,10 +11,10 @@ "debug": "node --inspect-brk server" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "get-port": "^7.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/basic-ssr-streaming-file-based/package.json b/examples/react/basic-ssr-streaming-file-based/package.json index 3e01c0d887..ec7f556279 100644 --- a/examples/react/basic-ssr-streaming-file-based/package.json +++ b/examples/react/basic-ssr-streaming-file-based/package.json @@ -11,10 +11,10 @@ "debug": "node --inspect-brk server" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "get-port": "^7.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/basic-virtual-file-based/package.json b/examples/react/basic-virtual-file-based/package.json index 10f6236c7e..3bcacf9883 100644 --- a/examples/react/basic-virtual-file-based/package.json +++ b/examples/react/basic-virtual-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "@tanstack/virtual-file-routes": "^1.115.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/basic-virtual-inside-file-based/package.json b/examples/react/basic-virtual-inside-file-based/package.json index 5d18292572..7d2cebed20 100644 --- a/examples/react/basic-virtual-inside-file-based/package.json +++ b/examples/react/basic-virtual-inside-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "@tanstack/virtual-file-routes": "^1.115.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json index 7f9babace7..a00f9d49cd 100644 --- a/examples/react/basic/package.json +++ b/examples/react/basic/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/deferred-data/package.json b/examples/react/deferred-data/package.json index e0750be78b..392aa79914 100644 --- a/examples/react/deferred-data/package.json +++ b/examples/react/deferred-data/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/kitchen-sink-file-based/package.json b/examples/react/kitchen-sink-file-based/package.json index 2c3f5090f8..970cb88813 100644 --- a/examples/react/kitchen-sink-file-based/package.json +++ b/examples/react/kitchen-sink-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/kitchen-sink-react-query-file-based/package.json b/examples/react/kitchen-sink-react-query-file-based/package.json index 6151c94bfc..f74a232a45 100644 --- a/examples/react/kitchen-sink-react-query-file-based/package.json +++ b/examples/react/kitchen-sink-react-query-file-based/package.json @@ -11,9 +11,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/kitchen-sink-react-query/package.json b/examples/react/kitchen-sink-react-query/package.json index d75715ba8f..c6a940fd2b 100644 --- a/examples/react/kitchen-sink-react-query/package.json +++ b/examples/react/kitchen-sink-react-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json index 345b43d83e..54cd956ace 100644 --- a/examples/react/kitchen-sink/package.json +++ b/examples/react/kitchen-sink/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "immer": "^10.1.1", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/large-file-based/package.json b/examples/react/large-file-based/package.json index b1e6984816..1b4e39e272 100644 --- a/examples/react/large-file-based/package.json +++ b/examples/react/large-file-based/package.json @@ -12,9 +12,9 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/location-masking/package.json b/examples/react/location-masking/package.json index 23889f308b..4f85c1c348 100644 --- a/examples/react/location-masking/package.json +++ b/examples/react/location-masking/package.json @@ -11,8 +11,8 @@ "dependencies": { "@radix-ui/react-dialog": "^1.1.6", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/navigation-blocking/package.json b/examples/react/navigation-blocking/package.json index 65bf8a380a..0b95f82bcb 100644 --- a/examples/react/navigation-blocking/package.json +++ b/examples/react/navigation-blocking/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/quickstart-esbuild-file-based/package.json b/examples/react/quickstart-esbuild-file-based/package.json index 5f01e26da0..9e8f629c97 100644 --- a/examples/react/quickstart-esbuild-file-based/package.json +++ b/examples/react/quickstart-esbuild-file-based/package.json @@ -9,9 +9,9 @@ "start": "dev" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/quickstart-file-based/package.json b/examples/react/quickstart-file-based/package.json index 0b2753fcf9..419c23072c 100644 --- a/examples/react/quickstart-file-based/package.json +++ b/examples/react/quickstart-file-based/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/quickstart-rspack-file-based/package.json b/examples/react/quickstart-rspack-file-based/package.json index 7a33f52889..1896d135a9 100644 --- a/examples/react/quickstart-rspack-file-based/package.json +++ b/examples/react/quickstart-rspack-file-based/package.json @@ -8,8 +8,8 @@ "preview": "rsbuild preview" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", @@ -19,7 +19,7 @@ "devDependencies": { "@rsbuild/core": "1.2.4", "@rsbuild/plugin-react": "1.1.0", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "typescript": "^5.6.2" diff --git a/examples/react/quickstart-webpack-file-based/package.json b/examples/react/quickstart-webpack-file-based/package.json index b069626942..70606de724 100644 --- a/examples/react/quickstart-webpack-file-based/package.json +++ b/examples/react/quickstart-webpack-file-based/package.json @@ -7,14 +7,14 @@ "build": "webpack build && tsc --noEmit" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, "devDependencies": { "@swc/core": "^1.10.15", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "html-webpack-plugin": "^5.6.3", diff --git a/examples/react/quickstart/package.json b/examples/react/quickstart/package.json index 7ad5f715e0..fe786d26b5 100644 --- a/examples/react/quickstart/package.json +++ b/examples/react/quickstart/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", diff --git a/examples/react/router-monorepo-react-query/package.json b/examples/react/router-monorepo-react-query/package.json index 56b4830118..4ecfe39f31 100644 --- a/examples/react/router-monorepo-react-query/package.json +++ b/examples/react/router-monorepo-react-query/package.json @@ -12,9 +12,9 @@ "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" diff --git a/examples/react/router-monorepo-react-query/packages/app/package.json b/examples/react/router-monorepo-react-query/packages/app/package.json index 8dd55376a7..1df369cc48 100644 --- a/examples/react/router-monorepo-react-query/packages/app/package.json +++ b/examples/react/router-monorepo-react-query/packages/app/package.json @@ -20,7 +20,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router-devtools": "^1.116.0", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", diff --git a/examples/react/router-monorepo-react-query/packages/router/package.json b/examples/react/router-monorepo-react-query/packages/router/package.json index 6fab2c6a5c..070fe31e70 100644 --- a/examples/react/router-monorepo-react-query/packages/router/package.json +++ b/examples/react/router-monorepo-react-query/packages/router/package.json @@ -10,8 +10,8 @@ "dependencies": { "@tanstack/history": "^1.115.0", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "@router-mono-react-query/post-query": "workspace:*", "redaxios": "^0.5.1", "zod": "^3.24.2", diff --git a/examples/react/router-monorepo-simple-lazy/package.json b/examples/react/router-monorepo-simple-lazy/package.json index 8e75f4b0f9..d242f29580 100644 --- a/examples/react/router-monorepo-simple-lazy/package.json +++ b/examples/react/router-monorepo-simple-lazy/package.json @@ -8,9 +8,9 @@ "dev": "pnpm router build && pnpm post-feature build && pnpm app dev" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" diff --git a/examples/react/router-monorepo-simple-lazy/packages/app/package.json b/examples/react/router-monorepo-simple-lazy/packages/app/package.json index d8d7d9b5a2..539db44bd5 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/app/package.json +++ b/examples/react/router-monorepo-simple-lazy/packages/app/package.json @@ -19,7 +19,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router-devtools": "^1.116.0", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", diff --git a/examples/react/router-monorepo-simple-lazy/packages/router/package.json b/examples/react/router-monorepo-simple-lazy/packages/router/package.json index d8ae72819d..61438244a8 100644 --- a/examples/react/router-monorepo-simple-lazy/packages/router/package.json +++ b/examples/react/router-monorepo-simple-lazy/packages/router/package.json @@ -9,8 +9,8 @@ "types": "./dist/index.d.ts", "dependencies": { "@tanstack/history": "^1.115.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "redaxios": "^0.5.1", "zod": "^3.24.2", "react": "^19.0.0", diff --git a/examples/react/router-monorepo-simple/package.json b/examples/react/router-monorepo-simple/package.json index fb7ab93ffc..91299b90b6 100644 --- a/examples/react/router-monorepo-simple/package.json +++ b/examples/react/router-monorepo-simple/package.json @@ -8,9 +8,9 @@ "dev": "pnpm router build && pnpm post-feature build && pnpm app dev" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1" diff --git a/examples/react/router-monorepo-simple/packages/app/package.json b/examples/react/router-monorepo-simple/packages/app/package.json index 5be02d2013..b95da79f9d 100644 --- a/examples/react/router-monorepo-simple/packages/app/package.json +++ b/examples/react/router-monorepo-simple/packages/app/package.json @@ -19,7 +19,7 @@ "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", "typescript": "^5.7.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router-devtools": "^1.116.0", "vite": "^6.1.0", "postcss": "^8.5.1", "autoprefixer": "^10.4.20", diff --git a/examples/react/router-monorepo-simple/packages/router/package.json b/examples/react/router-monorepo-simple/packages/router/package.json index 99a666ac7c..585abc4155 100644 --- a/examples/react/router-monorepo-simple/packages/router/package.json +++ b/examples/react/router-monorepo-simple/packages/router/package.json @@ -9,8 +9,8 @@ "types": "./dist/index.d.ts", "dependencies": { "@tanstack/history": "^1.115.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "redaxios": "^0.5.1", "zod": "^3.24.2", "react": "^19.0.0", diff --git a/examples/react/scroll-restoration/package.json b/examples/react/scroll-restoration/package.json index d03cdef9d5..7fa7a1c4b9 100644 --- a/examples/react/scroll-restoration/package.json +++ b/examples/react/scroll-restoration/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", + "@tanstack/react-router": "^1.116.0", "@tanstack/react-virtual": "^3.13.0", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "postcss": "^8.5.1", diff --git a/examples/react/search-validator-adapters/package.json b/examples/react/search-validator-adapters/package.json index 830d9b6125..bab2603b95 100644 --- a/examples/react/search-validator-adapters/package.json +++ b/examples/react/search-validator-adapters/package.json @@ -10,13 +10,13 @@ "test:unit": "vitest" }, "dependencies": { - "@tanstack/arktype-adapter": "^1.115.2", + "@tanstack/arktype-adapter": "^1.116.0", "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", - "@tanstack/valibot-adapter": "^1.115.2", - "@tanstack/zod-adapter": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", + "@tanstack/valibot-adapter": "^1.116.0", + "@tanstack/zod-adapter": "^1.116.0", "arktype": "^2.1.7", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/start-bare/package.json b/examples/react/start-bare/package.json index 44e5008631..9f96f66fa6 100644 --- a/examples/react/start-bare/package.json +++ b/examples/react/start-bare/package.json @@ -4,17 +4,16 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-bare/src/client.tsx b/examples/react/start-bare/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-bare/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-auth/.gitignore b/examples/react/start-basic-auth/.gitignore index b15fed94e2..2818549158 100644 --- a/examples/react/start-basic-auth/.gitignore +++ b/examples/react/start-basic-auth/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-auth/package.json b/examples/react/start-basic-auth/package.json index 271747da32..f3787c7be1 100644 --- a/examples/react/start-basic-auth/package.json +++ b/examples/react/start-basic-auth/package.json @@ -4,22 +4,21 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", "prisma-generate": "prisma generate" }, "dependencies": { "@prisma/client": "5.22.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "prisma": "^5.22.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-auth/src/client.tsx b/examples/react/start-basic-auth/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-auth/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-bare/src/ssr.tsx b/examples/react/start-basic-auth/src/server.ts similarity index 100% rename from examples/react/start-bare/src/ssr.tsx rename to examples/react/start-basic-auth/src/server.ts diff --git a/examples/react/start-basic-auth/src/ssr.tsx b/examples/react/start-basic-auth/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-auth/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-react-query/.gitignore b/examples/react/start-basic-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/start-basic-react-query/.gitignore +++ b/examples/react/start-basic-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-react-query/package.json b/examples/react/start-basic-react-query/package.json index e29d63a960..7a73a46b89 100644 --- a/examples/react/start-basic-react-query/package.json +++ b/examples/react/start-basic-react-query/package.json @@ -4,22 +4,21 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-with-query": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-with-query": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-react-query/src/client.tsx b/examples/react/start-basic-react-query/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-react-query/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/server-functions/src/ssr.tsx b/examples/react/start-basic-react-query/src/server.ts similarity index 100% rename from e2e/react-start/server-functions/src/ssr.tsx rename to examples/react/start-basic-react-query/src/server.ts diff --git a/examples/react/start-basic-rsc/.gitignore b/examples/react/start-basic-rsc/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/examples/react/start-basic-rsc/.gitignore +++ b/examples/react/start-basic-rsc/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/examples/react/start-basic-rsc/package.json b/examples/react/start-basic-rsc/package.json index a94b9bae13..553f367dec 100644 --- a/examples/react/start-basic-rsc/package.json +++ b/examples/react/start-basic-rsc/package.json @@ -4,20 +4,19 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@babel/plugin-syntax-typescript": "^7.25.9", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-basic-rsc/src/client.tsx b/examples/react/start-basic-rsc/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-rsc/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/scroll-restoration/src/ssr.tsx b/examples/react/start-basic-rsc/src/server.ts similarity index 100% rename from e2e/react-start/scroll-restoration/src/ssr.tsx rename to examples/react/start-basic-rsc/src/server.ts diff --git a/examples/react/start-basic-rsc/src/ssr.tsx b/examples/react/start-basic-rsc/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-rsc/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic-static/.gitignore b/examples/react/start-basic-static/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/start-basic-static/.gitignore +++ b/examples/react/start-basic-static/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic-static/package.json b/examples/react/start-basic-static/package.json index 505a80eec3..0b70df265b 100644 --- a/examples/react/start-basic-static/package.json +++ b/examples/react/start-basic-static/package.json @@ -4,19 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.5.5", - "vinxi": "0.5.1" + "tailwind-merge": "^2.5.5" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-basic-static/src/client.tsx b/examples/react/start-basic-static/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic-static/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-rsc/src/ssr.tsx b/examples/react/start-basic-static/src/server.ts similarity index 100% rename from e2e/react-start/basic-rsc/src/ssr.tsx rename to examples/react/start-basic-static/src/server.ts diff --git a/examples/react/start-basic-static/src/ssr.tsx b/examples/react/start-basic-static/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic-static/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic/.gitignore b/examples/react/start-basic/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/start-basic/.gitignore +++ b/examples/react/start-basic/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-basic/app.config.ts b/examples/react/start-basic/app.config.ts deleted file mode 100644 index 90c7c8cba8..0000000000 --- a/examples/react/start-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/react/start-basic/package.json b/examples/react/start-basic/package.json index 6ea80e4657..e548e7f73b 100644 --- a/examples/react/start-basic/package.json +++ b/examples/react/start-basic/package.json @@ -4,26 +4,26 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "vite": "6.1.5" }, "devDependencies": { "@types/node": "^22.5.4", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", - "postcss": "^8.5.1", "autoprefixer": "^10.4.20", + "postcss": "^8.5.1", "tailwindcss": "^3.4.17", "typescript": "^5.7.2", "vite-tsconfig-paths": "^5.1.4" diff --git a/examples/react/start-basic/src/api.ts b/examples/react/start-basic/src/api.ts deleted file mode 100644 index 8b9fef1667..0000000000 --- a/examples/react/start-basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/react-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/examples/react/start-basic/src/client.tsx b/examples/react/start-basic/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic/src/global-middleware.ts b/examples/react/start-basic/src/global-middleware.ts deleted file mode 100644 index c7e7af599f..0000000000 --- a/examples/react/start-basic/src/global-middleware.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { registerGlobalMiddleware } from '@tanstack/react-start' -import { logMiddleware } from './utils/loggingMiddleware' - -registerGlobalMiddleware({ - middleware: [logMiddleware], -}) diff --git a/examples/react/start-basic/src/routeTree.gen.ts b/examples/react/start-basic/src/routeTree.gen.ts index 4dca20ee9c..e55d4140d5 100644 --- a/examples/react/start-basic/src/routeTree.gen.ts +++ b/examples/react/start-basic/src/routeTree.gen.ts @@ -10,105 +10,133 @@ // Import Routes +import type { FileRoutesByPath, CreateFileRoute } from '@tanstack/react-router' +import { serverOnly } from '@tanstack/react-start' +import type { CreateServerFileRoute } from '@tanstack/react-start' import { Route as rootRoute } from './routes/__root' -import { Route as RedirectImport } from './routes/redirect' -import { Route as DeferredImport } from './routes/deferred' -import { Route as PathlessLayoutImport } from './routes/_pathlessLayout' -import { Route as UsersRouteImport } from './routes/users.route' -import { Route as PostsRouteImport } from './routes/posts.route' -import { Route as IndexImport } from './routes/index' -import { Route as UsersIndexImport } from './routes/users.index' -import { Route as PostsIndexImport } from './routes/posts.index' -import { Route as UsersUserIdImport } from './routes/users.$userId' -import { Route as PostsPostIdImport } from './routes/posts.$postId' -import { Route as PathlessLayoutNestedLayoutImport } from './routes/_pathlessLayout/_nested-layout' -import { Route as PostsPostIdDeepImport } from './routes/posts_.$postId.deep' -import { Route as PathlessLayoutNestedLayoutRouteBImport } from './routes/_pathlessLayout/_nested-layout/route-b' -import { Route as PathlessLayoutNestedLayoutRouteAImport } from './routes/_pathlessLayout/_nested-layout/route-a' +import { + Route as UsersRouteImport, + ServerRoute as UsersServerRouteImport, +} from './routes/users' +import { Route as RedirectRouteImport } from './routes/redirect' +import { Route as PostsRouteImport } from './routes/posts' +import { Route as DeferredRouteImport } from './routes/deferred' +import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout' +import { Route as IndexRouteImport } from './routes/index' +import { Route as UsersIndexRouteImport } from './routes/users.index' +import { Route as PostsIndexRouteImport } from './routes/posts.index' +import { + Route as UsersUserIdRouteImport, + ServerRoute as UsersUserIdServerRouteImport, +} from './routes/users.$userId' +import { Route as PostsPostIdRouteImport } from './routes/posts.$postId' +import { Route as PathlessLayoutNestedLayoutRouteImport } from './routes/_pathlessLayout/_nested-layout' +import { Route as PostsPostIdDeepRouteImport } from './routes/posts_.$postId.deep' +import { Route as PathlessLayoutNestedLayoutRouteBRouteImport } from './routes/_pathlessLayout/_nested-layout/route-b' +import { Route as PathlessLayoutNestedLayoutRouteARouteImport } from './routes/_pathlessLayout/_nested-layout/route-a' // Create/Update Routes -const RedirectRoute = RedirectImport.update({ - id: '/redirect', - path: '/redirect', +const UsersRoute = UsersRouteImport.update({ + id: '/users', + path: '/users', getParentRoute: () => rootRoute, + staticData: createIsomorphicFn() + .server(() => ({ + ...rootRoute.staticData, + serverRoute: UsersServerRouteImport, + })) + .client(() => rootRoute.staticData)(), } as any) -const DeferredRoute = DeferredImport.update({ - id: '/deferred', - path: '/deferred', +Object.assign(UsersServerRouteImport.options, { + pathname: '/users', +}) + +const RedirectRoute = RedirectRouteImport.update({ + id: '/redirect', + path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ - id: '/_pathlessLayout', +const PostsRoute = PostsRouteImport.update({ + id: '/posts', + path: '/posts', getParentRoute: () => rootRoute, } as any) -const UsersRouteRoute = UsersRouteImport.update({ - id: '/users', - path: '/users', +const DeferredRoute = DeferredRouteImport.update({ + id: '/deferred', + path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PostsRouteRoute = PostsRouteImport.update({ - id: '/posts', - path: '/posts', +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ + id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', - getParentRoute: () => UsersRouteRoute, + getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', - getParentRoute: () => PostsRouteRoute, + getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', - getParentRoute: () => UsersRouteRoute, + getParentRoute: () => UsersRoute, + staticData: createIsomorphicFn() + .server(() => ({ + ...UsersRoute.staticData, + serverRoute: UsersUserIdServerRouteImport, + })) + .client(() => UsersRoute.staticData)(), } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +Object.assign(UsersUserIdServerRouteImport.options, { + pathname: '/users/$userId', +}) + +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', - getParentRoute: () => PostsRouteRoute, + getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,132 +150,333 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport - parentRoute: typeof rootRoute - } - '/posts': { - id: '/posts' - path: '/posts' - fullPath: '/posts' - preLoaderRoute: typeof PostsRouteImport - parentRoute: typeof rootRoute - } - '/users': { - id: '/users' - path: '/users' - fullPath: '/users' - preLoaderRoute: typeof UsersRouteImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport + parentRoute: typeof rootRoute + } + '/posts': { + id: '/posts' + path: '/posts' + fullPath: '/posts' + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } + '/users': { + id: '/users' + path: '/users' + fullPath: '/users' + preLoaderRoute: typeof UsersRouteImport + parentRoute: typeof rootRoute + serverRoute: typeof UsersServerRouteImport + } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport + preLoaderRoute: typeof PostsPostIdRouteImport parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport + preLoaderRoute: typeof UsersUserIdRouteImport parentRoute: typeof UsersRouteImport + serverRoute: typeof UsersUserIdServerRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport + preLoaderRoute: typeof PostsIndexRouteImport parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport + preLoaderRoute: typeof UsersIndexRouteImport parentRoute: typeof UsersRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } -// Create and export the route tree - -interface PostsRouteRouteChildren { - PostsPostIdRoute: typeof PostsPostIdRoute - PostsIndexRoute: typeof PostsIndexRoute +// Add type-safety to the createFileRoute & createServerFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/', + unknown, + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > } - -const PostsRouteRouteChildren: PostsRouteRouteChildren = { - PostsPostIdRoute: PostsPostIdRoute, - PostsIndexRoute: PostsIndexRoute, +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout', + unknown, + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > } - -const PostsRouteRouteWithChildren = PostsRouteRoute._addFileChildren( - PostsRouteRouteChildren, -) - -interface UsersRouteRouteChildren { - UsersUserIdRoute: typeof UsersUserIdRoute - UsersIndexRoute: typeof UsersIndexRoute +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/deferred', + unknown, + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > } - -const UsersRouteRouteChildren: UsersRouteRouteChildren = { - UsersUserIdRoute: UsersUserIdRoute, - UsersIndexRoute: UsersIndexRoute, +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts', + unknown, + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/redirect', + unknown, + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users', + unknown, + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout', + unknown, + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts/$postId', + unknown, + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users/$userId', + typeof UsersServerRouteImport, + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts/', + unknown, + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users/', + typeof UsersServerRouteImport, + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + unknown, + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + unknown, + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts_/$postId/deep', + unknown, + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > } -const UsersRouteRouteWithChildren = UsersRouteRoute._addFileChildren( - UsersRouteRouteChildren, -) +// Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { PathlessLayoutNestedLayoutRouteARoute: typeof PathlessLayoutNestedLayoutRouteARoute @@ -279,13 +508,37 @@ const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren( PathlessLayoutRouteChildren, ) +interface PostsRouteChildren { + PostsPostIdRoute: typeof PostsPostIdRoute + PostsIndexRoute: typeof PostsIndexRoute +} + +const PostsRouteChildren: PostsRouteChildren = { + PostsPostIdRoute: PostsPostIdRoute, + PostsIndexRoute: PostsIndexRoute, +} + +const PostsRouteWithChildren = PostsRoute._addFileChildren(PostsRouteChildren) + +interface UsersRouteChildren { + UsersUserIdRoute: typeof UsersUserIdRoute + UsersIndexRoute: typeof UsersIndexRoute +} + +const UsersRouteChildren: UsersRouteChildren = { + UsersUserIdRoute: UsersUserIdRoute, + UsersIndexRoute: UsersIndexRoute, +} + +const UsersRouteWithChildren = UsersRoute._addFileChildren(UsersRouteChildren) + export interface FileRoutesByFullPath { '/': typeof IndexRoute - '/posts': typeof PostsRouteRouteWithChildren - '/users': typeof UsersRouteRouteWithChildren '': typeof PathlessLayoutNestedLayoutRouteWithChildren '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute '/posts/': typeof PostsIndexRoute @@ -295,6 +548,11 @@ export interface FileRoutesByFullPath { '/posts/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesByFullPath { + '/users': typeof UsersServerRouteWithChildren + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRoutesByTo { '/': typeof IndexRoute '': typeof PathlessLayoutNestedLayoutRouteWithChildren @@ -309,14 +567,18 @@ export interface FileRoutesByTo { '/posts/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesByTo { + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute - '/posts': typeof PostsRouteRouteWithChildren - '/users': typeof UsersRouteRouteWithChildren '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren '/deferred': typeof DeferredRoute + '/posts': typeof PostsRouteWithChildren '/redirect': typeof RedirectRoute + '/users': typeof UsersRouteWithChildren '/_pathlessLayout/_nested-layout': typeof PathlessLayoutNestedLayoutRouteWithChildren '/posts/$postId': typeof PostsPostIdRoute '/users/$userId': typeof UsersUserIdRoute @@ -327,15 +589,20 @@ export interface FileRoutesById { '/posts_/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesById { + '/users': typeof UsersServerRouteWithChildren + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: | '/' - | '/posts' - | '/users' | '' | '/deferred' + | '/posts' | '/redirect' + | '/users' | '/posts/$postId' | '/users/$userId' | '/posts/' @@ -359,11 +626,11 @@ export interface FileRouteTypes { id: | '__root__' | '/' - | '/posts' - | '/users' | '/_pathlessLayout' | '/deferred' + | '/posts' | '/redirect' + | '/users' | '/_pathlessLayout/_nested-layout' | '/posts/$postId' | '/users/$userId' @@ -373,25 +640,26 @@ export interface FileRouteTypes { | '/_pathlessLayout/_nested-layout/route-b' | '/posts_/$postId/deep' fileRoutesById: FileRoutesById + serverFileRoutesById: ServerFileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute - PostsRouteRoute: typeof PostsRouteRouteWithChildren - UsersRouteRoute: typeof UsersRouteRouteWithChildren PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren DeferredRoute: typeof DeferredRoute + PostsRoute: typeof PostsRouteWithChildren RedirectRoute: typeof RedirectRoute + UsersRoute: typeof UsersRouteWithChildren PostsPostIdDeepRoute: typeof PostsPostIdDeepRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, - PostsRouteRoute: PostsRouteRouteWithChildren, - UsersRouteRoute: UsersRouteRouteWithChildren, PathlessLayoutRoute: PathlessLayoutRouteWithChildren, DeferredRoute: DeferredRoute, + PostsRoute: PostsRouteWithChildren, RedirectRoute: RedirectRoute, + UsersRoute: UsersRouteWithChildren, PostsPostIdDeepRoute: PostsPostIdDeepRoute, } @@ -406,31 +674,17 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", - "/posts", - "/users", "/_pathlessLayout", "/deferred", + "/posts", "/redirect", + "/users", "/posts_/$postId/deep" ] }, "/": { "filePath": "index.tsx" }, - "/posts": { - "filePath": "posts.route.tsx", - "children": [ - "/posts/$postId", - "/posts/" - ] - }, - "/users": { - "filePath": "users.route.tsx", - "children": [ - "/users/$userId", - "/users/" - ] - }, "/_pathlessLayout": { "filePath": "_pathlessLayout.tsx", "children": [ @@ -440,9 +694,23 @@ export const routeTree = rootRoute "/deferred": { "filePath": "deferred.tsx" }, + "/posts": { + "filePath": "posts.tsx", + "children": [ + "/posts/$postId", + "/posts/" + ] + }, "/redirect": { "filePath": "redirect.tsx" }, + "/users": { + "filePath": "users.tsx", + "children": [ + "/users/$userId", + "/users/" + ] + }, "/_pathlessLayout/_nested-layout": { "filePath": "_pathlessLayout/_nested-layout.tsx", "parent": "/_pathlessLayout", diff --git a/examples/react/start-basic/src/routes/_pathlessLayout.tsx b/examples/react/start-basic/src/routes/_pathlessLayout.tsx index c3b12442b8..5c4a461d8d 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/react-router' +import { Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx index 9a48b73a46..1e1400f5a7 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index 426a8fe486..843209d78b 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( + +export const Route = createFileRoute( { component: LayoutAComponent, }, diff --git a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 20facf2daf..97fa3753b3 100644 --- a/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/react/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( + +export const Route = createFileRoute( { component: LayoutBComponent, }, diff --git a/examples/react/start-basic/src/routes/api/users.$id.ts b/examples/react/start-basic/src/routes/api/users.$id.ts deleted file mode 100644 index b1797e7917..0000000000 --- a/examples/react/start-basic/src/routes/api/users.$id.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' - -export const APIRoute = createAPIFileRoute('/api/users/$id')({ - GET: async ({ request, params }) => { - console.info(`Fetching users by id=${params.id}... @`, request.url) - try { - const res = await axios.get( - 'https://jsonplaceholder.typicode.com/users/' + params.id, - ) - - return json({ - id: res.data.id, - name: res.data.name, - email: res.data.email, - }) - } catch (e) { - console.error(e) - return json({ error: 'User not found' }, { status: 404 }) - } - }, -}) diff --git a/examples/react/start-basic/src/routes/api/users.ts b/examples/react/start-basic/src/routes/api/users.ts deleted file mode 100644 index 679eb9e8ab..0000000000 --- a/examples/react/start-basic/src/routes/api/users.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { json } from '@tanstack/react-start' -import { createAPIFileRoute } from '@tanstack/react-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' - -export const APIRoute = createAPIFileRoute('/api/users')({ - GET: async ({ request }) => { - console.info('Fetching users... @', request.url) - const res = await axios.get>( - 'https://jsonplaceholder.typicode.com/users', - ) - - const list = res.data.slice(0, 10) - - return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) - }, -}) diff --git a/examples/react/start-basic/src/routes/deferred.tsx b/examples/react/start-basic/src/routes/deferred.tsx index f3e09d1d4e..da895081df 100644 --- a/examples/react/start-basic/src/routes/deferred.tsx +++ b/examples/react/start-basic/src/routes/deferred.tsx @@ -1,4 +1,4 @@ -import { Await, createFileRoute } from '@tanstack/react-router' +import { Await } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { Suspense, useState } from 'react' @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/examples/react/start-basic/src/routes/index.tsx b/examples/react/start-basic/src/routes/index.tsx index 09a907cb18..d5fdaf7e38 100644 --- a/examples/react/start-basic/src/routes/index.tsx +++ b/examples/react/start-basic/src/routes/index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ + +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-basic/src/routes/posts.$postId.tsx b/examples/react/start-basic/src/routes/posts.$postId.tsx index d6de7c9dc3..d409f1d056 100644 --- a/examples/react/start-basic/src/routes/posts.$postId.tsx +++ b/examples/react/start-basic/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { NotFound } from '~/components/NotFound' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/react/start-basic/src/routes/posts.index.tsx b/examples/react/start-basic/src/routes/posts.index.tsx index 5b5f08f95b..d0d3b4f2f2 100644 --- a/examples/react/start-basic/src/routes/posts.index.tsx +++ b/examples/react/start-basic/src/routes/posts.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/posts/')({ + +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/react/start-basic/src/routes/posts.route.tsx b/examples/react/start-basic/src/routes/posts.tsx similarity index 82% rename from examples/react/start-basic/src/routes/posts.route.tsx rename to examples/react/start-basic/src/routes/posts.tsx index f29619363e..5bcd320911 100644 --- a/examples/react/start-basic/src/routes/posts.route.tsx +++ b/examples/react/start-basic/src/routes/posts.tsx @@ -1,12 +1,12 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' +import { Link, Outlet } from '@tanstack/react-router' import { fetchPosts } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => fetchPosts(), - component: PostsLayoutComponent, + component: PostsComponent, }) -function PostsLayoutComponent() { +function PostsComponent() { const posts = Route.useLoaderData() return ( diff --git a/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx b/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx index 29e6c39b5a..624b76a6c1 100644 --- a/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx +++ b/examples/react/start-basic/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId, diff --git a/examples/react/start-basic/src/routes/redirect.tsx b/examples/react/start-basic/src/routes/redirect.tsx index c9286de13d..4c665e6c56 100644 --- a/examples/react/start-basic/src/routes/redirect.tsx +++ b/examples/react/start-basic/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' +import { redirect } from '@tanstack/react-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/react/start-basic/src/routes/users.$userId.tsx b/examples/react/start-basic/src/routes/users.$userId.tsx index 623698bd35..1ce5c2e259 100644 --- a/examples/react/start-basic/src/routes/users.$userId.tsx +++ b/examples/react/start-basic/src/routes/users.$userId.tsx @@ -1,15 +1,38 @@ -import { createFileRoute } from '@tanstack/react-router' import axios from 'redaxios' -import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' -import { NotFound } from '~/components/NotFound' -import { UserErrorComponent } from '~/components/UserError' +import { NotFound } from 'src/components/NotFound' +import { UserErrorComponent } from 'src/components/UserError' +import { json } from '@tanstack/react-start' +import type { User } from 'src/utils/users' -export const Route = createFileRoute('/users/$userId')({ +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params, request }) => { + console.info(`Fetching users by id=${params.userId}... @`, request.url) + try { + const res = await axios.get( + 'https://jsonplaceholder.typicode.com/users/' + params.userId, + ) + + return json({ + id: res.data.id, + name: res.data.name, + email: res.data.email, + }) + } catch (e) { + console.error(e) + return json({ error: 'User not found' }, { status: 404 }) + } + }, +}) + +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { - return await axios - .get(DEPLOY_URL + '/api/users/' + userId) - .then((r) => r.data) + return (await axios.get)( + '/api/users/' + userId, + ) + .then((r) => { + if ('error' in r.data) throw new Error() + return r.data + }) .catch(() => { throw new Error('Failed to fetch user') }) diff --git a/examples/react/start-basic/src/routes/users.index.tsx b/examples/react/start-basic/src/routes/users.index.tsx index b6b0ee67fb..0e79fc2e7a 100644 --- a/examples/react/start-basic/src/routes/users.index.tsx +++ b/examples/react/start-basic/src/routes/users.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/users/')({ + +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/examples/react/start-basic/src/routes/users.route.tsx b/examples/react/start-basic/src/routes/users.route.tsx deleted file mode 100644 index 76cf588f6a..0000000000 --- a/examples/react/start-basic/src/routes/users.route.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/react-router' -import axios from 'redaxios' -import { DEPLOY_URL } from '../utils/users' -import type { User } from '../utils/users' - -export const Route = createFileRoute('/users')({ - loader: async () => { - return await axios - .get>(DEPLOY_URL + '/api/users') - .then((r) => r.data) - .catch(() => { - throw new Error('Failed to fetch users') - }) - }, - component: UsersLayoutComponent, -}) - -function UsersLayoutComponent() { - const users = Route.useLoaderData() - - return ( -
-
    - {[ - ...users, - { id: 'i-do-not-exist', name: 'Non-existent User', email: '' }, - ].map((user) => { - return ( -
  • - -
    {user.name}
    - -
  • - ) - })} -
-
- -
- ) -} diff --git a/examples/react/start-basic/src/routes/users.tsx b/examples/react/start-basic/src/routes/users.tsx new file mode 100644 index 0000000000..9fe0b4f0c8 --- /dev/null +++ b/examples/react/start-basic/src/routes/users.tsx @@ -0,0 +1,80 @@ +import { Link, Outlet } from '@tanstack/react-router' +import axios from 'redaxios' +import { json } from '@tanstack/react-start' +import type { User } from '../utils/users' + +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await axios.get>( + 'https://jsonplaceholder.typicode.com/users', + ) + + const list = res.data.slice(0, 10) + + return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) + }, + POST: api + .validator((input: { body: { name: string; email: string } }) => input) + .handler(async ({ data }) => { + console.info('Creating user...', data) + return json({ id: '1', name: data.body.name, email: data.body.email }) + }), +})) + +export const Route = createFileRoute({ + loader: () => { + return ServerRoute.client.get() + }, + component: UsersComponent, +}) + +function UsersComponent() { + const users = Route.useLoaderData() + + const addUser = ( + + ) + + return ( +
+
    + {[ + ...users, + { id: 'i-do-not-exist', name: 'Non-existent User', email: '' }, + ].map((user) => { + return ( +
  • + +
    {user.name}
    + +
  • + ) + })} +
+
+ +
+ ) +} diff --git a/examples/react/start-basic/src/ssr.tsx b/examples/react/start-basic/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-basic/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-basic/src/utils/loggingMiddleware.tsx b/examples/react/start-basic/src/utils/loggingMiddleware.tsx index 3944490725..d743ba5340 100644 --- a/examples/react/start-basic/src/utils/loggingMiddleware.tsx +++ b/examples/react/start-basic/src/utils/loggingMiddleware.tsx @@ -32,7 +32,7 @@ export const logMiddleware = createMiddleware() const now = new Date() console.log('Client Req/Res:', { - duration: res.context.clientTime.getTime() - now.getTime(), + duration: now.getTime() - res.context.clientTime.getTime(), durationToServer: res.context.durationToServer, durationFromServer: now.getTime() - res.context.serverTime.getTime(), }) diff --git a/examples/react/start-basic/src/utils/posts.tsx b/examples/react/start-basic/src/utils/posts.tsx index 5a2ff0232b..952249fdcb 100644 --- a/examples/react/start-basic/src/utils/posts.tsx +++ b/examples/react/start-basic/src/utils/posts.tsx @@ -8,7 +8,7 @@ export type PostType = { body: string } -export const fetchPost = createServerFn({ method: 'GET' }) +export const fetchPost = createServerFn({ method: 'GET', type: 'static' }) .validator((d: string) => d) .handler(async ({ data }) => { console.info(`Fetching post with id ${data}...`) @@ -26,11 +26,12 @@ export const fetchPost = createServerFn({ method: 'GET' }) return post }) -export const fetchPosts = createServerFn({ method: 'GET' }).handler( - async () => { - console.info('Fetching posts...') - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) - }, -) +export const fetchPosts = createServerFn({ + method: 'GET', + type: 'static', +}).handler(async () => { + console.info('Fetching posts...') + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) +}) diff --git a/examples/react/start-basic/src/utils/users.tsx b/examples/react/start-basic/src/utils/users.tsx index b810f455fe..7ba645b383 100644 --- a/examples/react/start-basic/src/utils/users.tsx +++ b/examples/react/start-basic/src/utils/users.tsx @@ -3,5 +3,3 @@ export type User = { name: string email: string } - -export const DEPLOY_URL = 'http://localhost:3000' diff --git a/examples/react/start-basic/vite.config.ts b/examples/react/start-basic/vite.config.ts new file mode 100644 index 0000000000..0262ff7f77 --- /dev/null +++ b/examples/react/start-basic/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { TanStackStartVitePlugin } from '@tanstack/react-start/plugin' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + TanStackStartVitePlugin({ + // prerender: { + // enabled: true, + // }, + }), + ], +}) diff --git a/examples/react/start-clerk-basic/.gitignore b/examples/react/start-clerk-basic/.gitignore index b15fed94e2..2818549158 100644 --- a/examples/react/start-clerk-basic/.gitignore +++ b/examples/react/start-clerk-basic/.gitignore @@ -7,14 +7,10 @@ yarn.lock .cache .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-clerk-basic/package.json b/examples/react/start-clerk-basic/package.json index 579d7c1513..50634be144 100644 --- a/examples/react/start-clerk-basic/package.json +++ b/examples/react/start-clerk-basic/package.json @@ -4,20 +4,19 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@clerk/tanstack-react-start": "0.12.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", - "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3" + "tailwind-merge": "^2.6.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-clerk-basic/src/client.tsx b/examples/react/start-clerk-basic/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-clerk-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/clerk-basic/src/ssr.tsx b/examples/react/start-clerk-basic/src/server.ts similarity index 100% rename from e2e/react-start/clerk-basic/src/ssr.tsx rename to examples/react/start-clerk-basic/src/server.ts diff --git a/examples/react/start-clerk-basic/src/ssr.tsx b/examples/react/start-clerk-basic/src/ssr.tsx deleted file mode 100644 index 060cd4816b..0000000000 --- a/examples/react/start-clerk-basic/src/ssr.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' -import { createClerkHandler } from '@clerk/tanstack-react-start/server' -import { createRouter } from './router' - -const handler = createStartHandler({ - createRouter, - getRouterManifest, -}) - -const clerkHandler = createClerkHandler(handler) - -export default clerkHandler(defaultStreamHandler) diff --git a/examples/react/start-convex-trellaux/.gitignore b/examples/react/start-convex-trellaux/.gitignore index 30518e7416..ba7dbddfbe 100644 --- a/examples/react/start-convex-trellaux/.gitignore +++ b/examples/react/start-convex-trellaux/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin .env.local diff --git a/examples/react/start-convex-trellaux/.stackblitzrc b/examples/react/start-convex-trellaux/.stackblitzrc index 2f76846e62..e616ee3a78 100644 --- a/examples/react/start-convex-trellaux/.stackblitzrc +++ b/examples/react/start-convex-trellaux/.stackblitzrc @@ -1,3 +1,3 @@ { - "startCommand": "cp .env.local.example .env.local && npx vinxi dev" + "startCommand": "cp .env.local.example .env.local && npx vite dev" } diff --git a/examples/react/start-convex-trellaux/package.json b/examples/react/start-convex-trellaux/package.json index 00b6ac505d..b6985c28f3 100644 --- a/examples/react/start-convex-trellaux/package.json +++ b/examples/react/start-convex-trellaux/package.json @@ -5,19 +5,19 @@ "type": "module", "scripts": { "dev": "npx convex dev --once && concurrently -r npm:dev:web npm:dev:db", - "dev:web": "vinxi dev", + "dev:web": "vite dev", "dev:db": "convex dev --run board:seed", - "build": "vinxi build", - "start": "vinxi start" + "build": "vite build", + "start": "vite start" }, "dependencies": { "@convex-dev/react-query": "0.0.0-alpha.8", "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-with-query": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-with-query": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "concurrently": "^8.2.2", "convex": "^1.19.0", "ky": "^1.7.4", @@ -28,7 +28,6 @@ "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-convex-trellaux/src/client.tsx b/examples/react/start-convex-trellaux/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-convex-trellaux/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-react-query/src/ssr.tsx b/examples/react/start-convex-trellaux/src/server.ts similarity index 100% rename from e2e/react-start/basic-react-query/src/ssr.tsx rename to examples/react/start-convex-trellaux/src/server.ts diff --git a/examples/react/start-convex-trellaux/src/ssr.tsx b/examples/react/start-convex-trellaux/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-convex-trellaux/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-counter/.gitignore b/examples/react/start-counter/.gitignore index 2b76174be5..08eba9e706 100644 --- a/examples/react/start-counter/.gitignore +++ b/examples/react/start-counter/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-counter/package.json b/examples/react/start-counter/package.json index 9d65a5ff90..dc49465594 100644 --- a/examples/react/start-counter/package.json +++ b/examples/react/start-counter/package.json @@ -4,17 +4,16 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", - "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-counter/src/client.tsx b/examples/react/start-counter/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-counter/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-auth/src/ssr.tsx b/examples/react/start-counter/src/server.ts similarity index 100% rename from e2e/react-start/basic-auth/src/ssr.tsx rename to examples/react/start-counter/src/server.ts diff --git a/examples/react/start-counter/src/ssr.tsx b/examples/react/start-counter/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-counter/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-large/.gitignore b/examples/react/start-large/.gitignore index cb9991202d..ca4ef70bc0 100644 --- a/examples/react/start-large/.gitignore +++ b/examples/react/start-large/.gitignore @@ -13,10 +13,7 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi \ No newline at end of file +/public/build \ No newline at end of file diff --git a/examples/react/start-large/package.json b/examples/react/start-large/package.json index 9dd173ce26..2175cf3f49 100644 --- a/examples/react/start-large/package.json +++ b/examples/react/start-large/package.json @@ -4,23 +4,22 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start", + "dev": "vite dev", + "build": "vite build", + "start": "vite start", "gen": "node ./src/createRoutes.mjs", "test:types": "tsc --extendedDiagnostics" }, "dependencies": { "@tanstack/react-query": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "valibot": "^1.0.0-beta.15", - "vinxi": "0.5.3" + "valibot": "^1.0.0-beta.15" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/react/start-large/src/client.tsx b/examples/react/start-large/src/client.tsx deleted file mode 100644 index 4d4c49a500..0000000000 --- a/examples/react/start-large/src/client.tsx +++ /dev/null @@ -1,9 +0,0 @@ -// src/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-large/src/routeTree.gen.ts b/examples/react/start-large/src/routeTree.gen.ts index e4f3a85ab1..c7ceaf8236 100644 --- a/examples/react/start-large/src/routeTree.gen.ts +++ b/examples/react/start-large/src/routeTree.gen.ts @@ -10,61 +10,64 @@ // Import Routes +import type { FileRoutesByPath, CreateFileRoute } from '@tanstack/react-router' +import { serverOnly } from '@tanstack/react-start' +import type { CreateServerFileRoute } from '@tanstack/react-start' import { Route as rootRoute } from './routes/__root' -import { Route as RelativeImport } from './routes/relative' -import { Route as LinkPropsImport } from './routes/linkProps' -import { Route as AbsoluteImport } from './routes/absolute' -import { Route as SearchRouteImport } from './routes/search/route' -import { Route as ParamsRouteImport } from './routes/params/route' -import { Route as IndexImport } from './routes/index' -import { Route as SearchSearchPlaceholderImport } from './routes/search/searchPlaceholder' -import { Route as ParamsParamsPlaceholderImport } from './routes/params/$paramsPlaceholder' +import { Route as RelativeRouteImport } from './routes/relative' +import { Route as LinkPropsRouteImport } from './routes/linkProps' +import { Route as AbsoluteRouteImport } from './routes/absolute' +import { Route as SearchRouteRouteImport } from './routes/search/route' +import { Route as ParamsRouteRouteImport } from './routes/params/route' +import { Route as IndexRouteImport } from './routes/index' +import { Route as SearchSearchPlaceholderRouteImport } from './routes/search/searchPlaceholder' +import { Route as ParamsParamsPlaceholderRouteImport } from './routes/params/$paramsPlaceholder' // Create/Update Routes -const RelativeRoute = RelativeImport.update({ +const RelativeRoute = RelativeRouteImport.update({ id: '/relative', path: '/relative', getParentRoute: () => rootRoute, } as any) -const LinkPropsRoute = LinkPropsImport.update({ +const LinkPropsRoute = LinkPropsRouteImport.update({ id: '/linkProps', path: '/linkProps', getParentRoute: () => rootRoute, } as any) -const AbsoluteRoute = AbsoluteImport.update({ +const AbsoluteRoute = AbsoluteRouteImport.update({ id: '/absolute', path: '/absolute', getParentRoute: () => rootRoute, } as any) -const SearchRouteRoute = SearchRouteImport.update({ +const SearchRouteRoute = SearchRouteRouteImport.update({ id: '/search', path: '/search', getParentRoute: () => rootRoute, } as any) -const ParamsRouteRoute = ParamsRouteImport.update({ +const ParamsRouteRoute = ParamsRouteRouteImport.update({ id: '/params', path: '/params', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const SearchSearchPlaceholderRoute = SearchSearchPlaceholderImport.update({ +const SearchSearchPlaceholderRoute = SearchSearchPlaceholderRouteImport.update({ id: '/searchPlaceholder', path: '/searchPlaceholder', getParentRoute: () => SearchRouteRoute, } as any) -const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderImport.update({ +const ParamsParamsPlaceholderRoute = ParamsParamsPlaceholderRouteImport.update({ id: '/$paramsPlaceholder', path: '/$paramsPlaceholder', getParentRoute: () => ParamsRouteRoute, @@ -78,61 +81,192 @@ declare module '@tanstack/react-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/params': { id: '/params' path: '/params' fullPath: '/params' - preLoaderRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsRouteRouteImport parentRoute: typeof rootRoute } '/search': { id: '/search' path: '/search' fullPath: '/search' - preLoaderRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchRouteRouteImport parentRoute: typeof rootRoute } '/absolute': { id: '/absolute' path: '/absolute' fullPath: '/absolute' - preLoaderRoute: typeof AbsoluteImport + preLoaderRoute: typeof AbsoluteRouteImport parentRoute: typeof rootRoute } '/linkProps': { id: '/linkProps' path: '/linkProps' fullPath: '/linkProps' - preLoaderRoute: typeof LinkPropsImport + preLoaderRoute: typeof LinkPropsRouteImport parentRoute: typeof rootRoute } '/relative': { id: '/relative' path: '/relative' fullPath: '/relative' - preLoaderRoute: typeof RelativeImport + preLoaderRoute: typeof RelativeRouteImport parentRoute: typeof rootRoute } '/params/$paramsPlaceholder': { id: '/params/$paramsPlaceholder' path: '/$paramsPlaceholder' fullPath: '/params/$paramsPlaceholder' - preLoaderRoute: typeof ParamsParamsPlaceholderImport - parentRoute: typeof ParamsRouteImport + preLoaderRoute: typeof ParamsParamsPlaceholderRouteImport + parentRoute: typeof ParamsRouteRouteImport } '/search/searchPlaceholder': { id: '/search/searchPlaceholder' path: '/searchPlaceholder' fullPath: '/search/searchPlaceholder' - preLoaderRoute: typeof SearchSearchPlaceholderImport - parentRoute: typeof SearchRouteImport + preLoaderRoute: typeof SearchSearchPlaceholderRouteImport + parentRoute: typeof SearchRouteRouteImport } } } +// Add type-safety to the createFileRoute & createServerFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/', + unknown, + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/params/route' { + const createFileRoute: CreateFileRoute< + '/params', + FileRoutesByPath['/params']['parentRoute'], + FileRoutesByPath['/params']['id'], + FileRoutesByPath['/params']['path'], + FileRoutesByPath['/params']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/params', + unknown, + FileRoutesByPath['/params']['id'], + FileRoutesByPath['/params']['path'], + FileRoutesByPath['/params']['fullPath'] + > +} +declare module './routes/search/route' { + const createFileRoute: CreateFileRoute< + '/search', + FileRoutesByPath['/search']['parentRoute'], + FileRoutesByPath['/search']['id'], + FileRoutesByPath['/search']['path'], + FileRoutesByPath['/search']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/search', + unknown, + FileRoutesByPath['/search']['id'], + FileRoutesByPath['/search']['path'], + FileRoutesByPath['/search']['fullPath'] + > +} +declare module './routes/absolute' { + const createFileRoute: CreateFileRoute< + '/absolute', + FileRoutesByPath['/absolute']['parentRoute'], + FileRoutesByPath['/absolute']['id'], + FileRoutesByPath['/absolute']['path'], + FileRoutesByPath['/absolute']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/absolute', + unknown, + FileRoutesByPath['/absolute']['id'], + FileRoutesByPath['/absolute']['path'], + FileRoutesByPath['/absolute']['fullPath'] + > +} +declare module './routes/linkProps' { + const createFileRoute: CreateFileRoute< + '/linkProps', + FileRoutesByPath['/linkProps']['parentRoute'], + FileRoutesByPath['/linkProps']['id'], + FileRoutesByPath['/linkProps']['path'], + FileRoutesByPath['/linkProps']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/linkProps', + unknown, + FileRoutesByPath['/linkProps']['id'], + FileRoutesByPath['/linkProps']['path'], + FileRoutesByPath['/linkProps']['fullPath'] + > +} +declare module './routes/relative' { + const createFileRoute: CreateFileRoute< + '/relative', + FileRoutesByPath['/relative']['parentRoute'], + FileRoutesByPath['/relative']['id'], + FileRoutesByPath['/relative']['path'], + FileRoutesByPath['/relative']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/relative', + unknown, + FileRoutesByPath['/relative']['id'], + FileRoutesByPath['/relative']['path'], + FileRoutesByPath['/relative']['fullPath'] + > +} +declare module './routes/params/$paramsPlaceholder' { + const createFileRoute: CreateFileRoute< + '/params/$paramsPlaceholder', + FileRoutesByPath['/params/$paramsPlaceholder']['parentRoute'], + FileRoutesByPath['/params/$paramsPlaceholder']['id'], + FileRoutesByPath['/params/$paramsPlaceholder']['path'], + FileRoutesByPath['/params/$paramsPlaceholder']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/params/$paramsPlaceholder', + unknown, + FileRoutesByPath['/params/$paramsPlaceholder']['id'], + FileRoutesByPath['/params/$paramsPlaceholder']['path'], + FileRoutesByPath['/params/$paramsPlaceholder']['fullPath'] + > +} +declare module './routes/search/searchPlaceholder' { + const createFileRoute: CreateFileRoute< + '/search/searchPlaceholder', + FileRoutesByPath['/search/searchPlaceholder']['parentRoute'], + FileRoutesByPath['/search/searchPlaceholder']['id'], + FileRoutesByPath['/search/searchPlaceholder']['path'], + FileRoutesByPath['/search/searchPlaceholder']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/search/searchPlaceholder', + unknown, + FileRoutesByPath['/search/searchPlaceholder']['id'], + FileRoutesByPath['/search/searchPlaceholder']['path'], + FileRoutesByPath['/search/searchPlaceholder']['fullPath'] + > +} + // Create and export the route tree interface ParamsRouteRouteChildren { @@ -170,6 +304,8 @@ export interface FileRoutesByFullPath { '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute } +export interface ServerFileRoutesByFullPath {} + export interface FileRoutesByTo { '/': typeof IndexRoute '/params': typeof ParamsRouteRouteWithChildren @@ -181,6 +317,8 @@ export interface FileRoutesByTo { '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute } +export interface ServerFileRoutesByTo {} + export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute @@ -193,6 +331,8 @@ export interface FileRoutesById { '/search/searchPlaceholder': typeof SearchSearchPlaceholderRoute } +export interface ServerFileRoutesById {} + export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: diff --git a/examples/react/start-large/src/routes/__root.tsx b/examples/react/start-large/src/routes/__root.tsx index 789c85c351..b52ca36ae8 100644 --- a/examples/react/start-large/src/routes/__root.tsx +++ b/examples/react/start-large/src/routes/__root.tsx @@ -7,7 +7,6 @@ import { } from '@tanstack/react-router' import type { QueryClient } from '@tanstack/react-query' import type { ReactNode } from 'react' -import appCss from '~/styles.css?url' import { TanStackRouterDevtools } from '@tanstack/react-router-devtools' export interface Context { queryClient: QueryClient @@ -15,7 +14,7 @@ export interface Context { export const Route = createRootRouteWithContext()({ head: () => ({ - links: [{ rel: 'stylesheet', href: appCss }], + links: [{ rel: 'stylesheet' }], meta: [ { charSet: 'utf-8', diff --git a/examples/react/start-large/src/routes/absolute.tsx b/examples/react/start-large/src/routes/absolute.tsx index ba1f875050..857515fa10 100644 --- a/examples/react/start-large/src/routes/absolute.tsx +++ b/examples/react/start-large/src/routes/absolute.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/absolute')({ +export const Route = createFileRoute({ component: AbsoluteComponent, }) diff --git a/examples/react/start-large/src/routes/index.tsx b/examples/react/start-large/src/routes/index.tsx index eac82a9174..607fbf2506 100644 --- a/examples/react/start-large/src/routes/index.tsx +++ b/examples/react/start-large/src/routes/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ + +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/react/start-large/src/routes/linkProps.tsx b/examples/react/start-large/src/routes/linkProps.tsx index 4804161ccf..89ef1c2a36 100644 --- a/examples/react/start-large/src/routes/linkProps.tsx +++ b/examples/react/start-large/src/routes/linkProps.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, createFileRoute, linkOptions } from '@tanstack/react-router' +import { Link, linkOptions } from '@tanstack/react-router' import { customRedirect, ListItems, @@ -7,7 +7,7 @@ import { useCustomNavigate, } from '~/typePrimitives' -export const Route = createFileRoute('/linkProps')({ +export const Route = createFileRoute({ component: LinkPropsPage, loader: () => { throw customRedirect({ diff --git a/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx b/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx index 45c00d1837..2b68e4cf50 100644 --- a/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx +++ b/examples/react/start-large/src/routes/params/$paramsPlaceholder.tsx @@ -1,5 +1,5 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import * as v from 'valibot' import { queryOptions } from '@tanstack/react-query' import { createMiddleware, createServerFn } from '@tanstack/react-start' @@ -44,7 +44,7 @@ const paramsQueryOptions = queryOptions({ }, }) -export const Route = createFileRoute('/params/$paramsPlaceholder')({ +export const Route = createFileRoute({ component: ParamsComponent, context: () => ({ paramsQueryOptions: queryOptions({ diff --git a/examples/react/start-large/src/routes/params/route.tsx b/examples/react/start-large/src/routes/params/route.tsx index 32f2b82024..5d39cf1d8d 100644 --- a/examples/react/start-large/src/routes/params/route.tsx +++ b/examples/react/start-large/src/routes/params/route.tsx @@ -1,6 +1,6 @@ import * as React from 'react' -import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/params')({ + +export const Route = createFileRoute({ component: () =>
Hello /params!
, }) diff --git a/examples/react/start-large/src/routes/relative.tsx b/examples/react/start-large/src/routes/relative.tsx index 6f6e581efd..cf25ec6f9f 100644 --- a/examples/react/start-large/src/routes/relative.tsx +++ b/examples/react/start-large/src/routes/relative.tsx @@ -1,7 +1,7 @@ import * as React from 'react' -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' -export const Route = createFileRoute('/relative')({ +export const Route = createFileRoute({ component: RelativeComponent, }) diff --git a/examples/react/start-large/src/routes/search/route.tsx b/examples/react/start-large/src/routes/search/route.tsx index 3bcbe420e1..9fd088aa4e 100644 --- a/examples/react/start-large/src/routes/search/route.tsx +++ b/examples/react/start-large/src/routes/search/route.tsx @@ -1,11 +1,11 @@ -import { createFileRoute } from '@tanstack/react-router' + import * as v from 'valibot' const search = v.object({ rootSearch: v.number(), }) -export const Route = createFileRoute('/search')({ +export const Route = createFileRoute({ component: () =>
Hello /search!
, validateSearch: search, }) diff --git a/examples/react/start-large/src/routes/search/searchPlaceholder.tsx b/examples/react/start-large/src/routes/search/searchPlaceholder.tsx index 56dc0a2931..1957b019de 100644 --- a/examples/react/start-large/src/routes/search/searchPlaceholder.tsx +++ b/examples/react/start-large/src/routes/search/searchPlaceholder.tsx @@ -1,4 +1,4 @@ -import { Link, createFileRoute } from '@tanstack/react-router' +import { Link } from '@tanstack/react-router' import * as v from 'valibot' import { queryOptions } from '@tanstack/react-query' @@ -42,7 +42,19 @@ const fn = createServerFn() return result }) -export const Route = createFileRoute('/search/searchPlaceholder')({ +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: api + .validator( + v.object({ + search: v.object({ searchPlaceholder: v.literal('searchPlaceholder') }), + }), + ) + .handler((ctx) => { + return ctx.data + }), +})) + +export const Route = createFileRoute({ component: SearchComponent, validateSearch: search, loaderDeps: ({ search }) => ({ search }), @@ -51,9 +63,24 @@ export const Route = createFileRoute('/search/searchPlaceholder')({ queryKey: ['searchPlaceholder'], queryFn: () => fn({ data: ctx.deps.search }), }), + externalSearchQueryOptions: queryOptions({ + queryKey: ['searchPlaceholder', 'external'], + queryFn: () => ServerRoute.client.get({ search: ctx.deps.search }), + }), }), - loader: (opts) => - opts.context.queryClient.ensureQueryData(opts.context.searchQueryOptions), + loader: async (opts) => { + const search = await opts.context.queryClient.ensureQueryData( + opts.context.searchQueryOptions, + ) + const external = await opts.context.queryClient.ensureQueryData( + opts.context.externalSearchQueryOptions, + ) + + return { + search, + external, + } + }, }) function SearchComponent() { diff --git a/examples/react/start-large/src/ssr.tsx b/examples/react/start-large/src/ssr.tsx deleted file mode 100644 index a24fb32843..0000000000 --- a/examples/react/start-large/src/ssr.tsx +++ /dev/null @@ -1,14 +0,0 @@ -// src/ssr.tsx -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-large/vite.config.ts b/examples/react/start-large/vite.config.ts new file mode 100644 index 0000000000..0262ff7f77 --- /dev/null +++ b/examples/react/start-large/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { TanStackStartVitePlugin } from '@tanstack/react-start/plugin' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + TanStackStartVitePlugin({ + // prerender: { + // enabled: true, + // }, + }), + ], +}) diff --git a/examples/react/start-material-ui/package.json b/examples/react/start-material-ui/package.json index 288be99328..2808bd09bf 100644 --- a/examples/react/start-material-ui/package.json +++ b/examples/react/start-material-ui/package.json @@ -14,9 +14,9 @@ "@emotion/styled": "11.14.0", "@fontsource-variable/roboto": "5.2.5", "@mui/material": "6.4.7", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-start": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-start": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "vinxi": "0.5.3", diff --git a/examples/react/start-supabase-basic/.gitignore b/examples/react/start-supabase-basic/.gitignore index 5578fb7487..8293849e8d 100644 --- a/examples/react/start-supabase-basic/.gitignore +++ b/examples/react/start-supabase-basic/.gitignore @@ -9,14 +9,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/start-supabase-basic/package.json b/examples/react/start-supabase-basic/package.json index abb87c6b56..a59f993086 100644 --- a/examples/react/start-supabase-basic/package.json +++ b/examples/react/start-supabase-basic/package.json @@ -5,9 +5,9 @@ "main": "index.js", "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "keywords": [], "author": "", @@ -15,12 +15,11 @@ "dependencies": { "@supabase/ssr": "^0.5.2", "@supabase/supabase-js": "^2.48.1", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "react": "^19.0.0", - "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "react-dom": "^19.0.0" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-supabase-basic/src/client.tsx b/examples/react/start-supabase-basic/src/client.tsx deleted file mode 100644 index 4d4c49a500..0000000000 --- a/examples/react/start-supabase-basic/src/client.tsx +++ /dev/null @@ -1,9 +0,0 @@ -// src/client.tsx -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/e2e/react-start/basic-tsr-config/src/app/ssr.tsx b/examples/react/start-supabase-basic/src/server.ts similarity index 87% rename from e2e/react-start/basic-tsr-config/src/app/ssr.tsx rename to examples/react/start-supabase-basic/src/server.ts index 8981a9a338..cb5ab731aa 100644 --- a/e2e/react-start/basic-tsr-config/src/app/ssr.tsx +++ b/examples/react/start-supabase-basic/src/server.ts @@ -1,4 +1,5 @@ -/// +// src/server.tsx + import { createStartHandler, defaultStreamHandler, diff --git a/examples/react/start-supabase-basic/src/ssr.tsx b/examples/react/start-supabase-basic/src/ssr.tsx deleted file mode 100644 index a24fb32843..0000000000 --- a/examples/react/start-supabase-basic/src/ssr.tsx +++ /dev/null @@ -1,14 +0,0 @@ -// src/ssr.tsx -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-trellaux/.gitignore b/examples/react/start-trellaux/.gitignore index d3387e00cd..3c8e6870b3 100644 --- a/examples/react/start-trellaux/.gitignore +++ b/examples/react/start-trellaux/.gitignore @@ -7,12 +7,8 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin diff --git a/examples/react/start-trellaux/package.json b/examples/react/start-trellaux/package.json index 224a46f7a2..c4b1ad0dd7 100644 --- a/examples/react/start-trellaux/package.json +++ b/examples/react/start-trellaux/package.json @@ -4,17 +4,17 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-with-query": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-with-query": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "ky": "^1.7.4", "msw": "^2.7.0", "react": "^19.0.0", @@ -23,7 +23,6 @@ "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/start-trellaux/src/client.tsx b/examples/react/start-trellaux/src/client.tsx deleted file mode 100644 index 1593d1b3c7..0000000000 --- a/examples/react/start-trellaux/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrateRoot } from 'react-dom/client' -import { StartClient } from '@tanstack/react-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrateRoot(document, ) diff --git a/examples/react/start-basic-react-query/src/ssr.tsx b/examples/react/start-trellaux/src/server.ts similarity index 87% rename from examples/react/start-basic-react-query/src/ssr.tsx rename to examples/react/start-trellaux/src/server.ts index 8981a9a338..65a580f25e 100644 --- a/examples/react/start-basic-react-query/src/ssr.tsx +++ b/examples/react/start-trellaux/src/server.ts @@ -1,4 +1,3 @@ -/// import { createStartHandler, defaultStreamHandler, diff --git a/examples/react/start-trellaux/src/ssr.tsx b/examples/react/start-trellaux/src/ssr.tsx deleted file mode 100644 index 8981a9a338..0000000000 --- a/examples/react/start-trellaux/src/ssr.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/react/start-workos/app.config.ts b/examples/react/start-workos/app.config.ts deleted file mode 100644 index 3096b30089..0000000000 --- a/examples/react/start-workos/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/react-start/config'; -import tsConfigPaths from 'vite-tsconfig-paths'; - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}); diff --git a/examples/react/start-workos/package.json b/examples/react/start-workos/package.json index 4d3d02d86a..6d08c7f376 100644 --- a/examples/react/start-workos/package.json +++ b/examples/react/start-workos/package.json @@ -5,24 +5,24 @@ "main": "index.js", "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "keywords": [], "author": "", - "license": "ISC", + "license": "MIT", "dependencies": { "@radix-ui/themes": "^3.2.1", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "@workos-inc/node": "^7.45.0", "iron-session": "^8.0.4", "jose": "^6.0.10", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.3" + "vite": "6.1.5" }, "devDependencies": { "@types/react": "^19.0.8", diff --git a/examples/react/start-workos/vite.config.ts b/examples/react/start-workos/vite.config.ts new file mode 100644 index 0000000000..94ce863f6e --- /dev/null +++ b/examples/react/start-workos/vite.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite'; +import tsConfigPaths from 'vite-tsconfig-paths'; +import { TanStackStartVitePlugin } from '@tanstack/react-start/plugin'; + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + TanStackStartVitePlugin(), + ], +}); diff --git a/examples/react/view-transitions/package.json b/examples/react/view-transitions/package.json index b80d6da3c2..fb37c8ebd5 100644 --- a/examples/react/view-transitions/package.json +++ b/examples/react/view-transitions/package.json @@ -9,9 +9,9 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", "react": "^19.0.0", "react-dom": "^19.0.0", "redaxios": "^0.5.1", diff --git a/examples/react/with-framer-motion/package.json b/examples/react/with-framer-motion/package.json index 92dad29442..68201e2682 100644 --- a/examples/react/with-framer-motion/package.json +++ b/examples/react/with-framer-motion/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", "framer-motion": "^11.18.2", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/examples/react/with-trpc-react-query/.gitignore b/examples/react/with-trpc-react-query/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/with-trpc-react-query/.gitignore +++ b/examples/react/with-trpc-react-query/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/with-trpc-react-query/app.config.js b/examples/react/with-trpc-react-query/app.config.js index ef4eb87c7b..0f15246c33 100644 --- a/examples/react/with-trpc-react-query/app.config.js +++ b/examples/react/with-trpc-react-query/app.config.js @@ -1,8 +1,10 @@ -import { createApp } from 'vinxi' +import { defineConfig } from 'vite' import reactRefresh from '@vitejs/plugin-react' import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -export default createApp({ +// TODO: Need to migrate this to vite and the new TanStack Start plugin + +export default defineConfig({ server: { preset: 'node-server', // change to 'netlify' or 'bun' or anyof the supported presets for nitro (nitro.unjs.io) experimental: { diff --git a/examples/react/with-trpc-react-query/package.json b/examples/react/with-trpc-react-query/package.json index 58ef04aaa6..6bac1bb05d 100644 --- a/examples/react/with-trpc-react-query/package.json +++ b/examples/react/with-trpc-react-query/package.json @@ -3,17 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { "@tanstack/react-query": "^5.66.0", "@tanstack/react-query-devtools": "^5.66.0", - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "@trpc/client": "11.0.0-rc.772", "@trpc/server": "11.0.0-rc.772", "@trpc/tanstack-react-query": "11.0.0-rc.772", @@ -23,7 +23,6 @@ "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/with-trpc-react-query/src/main.tsx b/examples/react/with-trpc-react-query/src/main.tsx index 4cc69baaac..bda5f47256 100644 --- a/examples/react/with-trpc-react-query/src/main.tsx +++ b/examples/react/with-trpc-react-query/src/main.tsx @@ -1,5 +1,3 @@ -/// - import React from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider } from '@tanstack/react-router' diff --git a/examples/react/with-trpc-react-query/src/router.tsx b/examples/react/with-trpc-react-query/src/router.tsx index 1dfd9c4131..0d9dd5c4e4 100644 --- a/examples/react/with-trpc-react-query/src/router.tsx +++ b/examples/react/with-trpc-react-query/src/router.tsx @@ -15,7 +15,7 @@ export const trpc = createTRPCOptionsProxy({ client: createTRPCClient({ links: [ httpBatchLink({ - // since we are using Vinxi, the server is running on the same port, + // since we are using Vite, the server is running on the same port, // this means in dev the url is `http://localhost:3000/trpc` // and since its from the same origin, we don't need to explicitly set the full URL url: '/trpc', diff --git a/examples/react/with-trpc/.gitignore b/examples/react/with-trpc/.gitignore index be342025da..ca63f49885 100644 --- a/examples/react/with-trpc/.gitignore +++ b/examples/react/with-trpc/.gitignore @@ -7,14 +7,10 @@ yarn.lock .env .vercel .output -.vinxi - /build/ /api/ /server/build -/public/build -.vinxi -# Sentry Config File +/public/build# Sentry Config File .env.sentry-build-plugin /test-results/ /playwright-report/ diff --git a/examples/react/with-trpc/app.config.js b/examples/react/with-trpc/app.config.js index ef4eb87c7b..0f15246c33 100644 --- a/examples/react/with-trpc/app.config.js +++ b/examples/react/with-trpc/app.config.js @@ -1,8 +1,10 @@ -import { createApp } from 'vinxi' +import { defineConfig } from 'vite' import reactRefresh from '@vitejs/plugin-react' import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -export default createApp({ +// TODO: Need to migrate this to vite and the new TanStack Start plugin + +export default defineConfig({ server: { preset: 'node-server', // change to 'netlify' or 'bun' or anyof the supported presets for nitro (nitro.unjs.io) experimental: { diff --git a/examples/react/with-trpc/package.json b/examples/react/with-trpc/package.json index 537e90ec3d..c629e24552 100644 --- a/examples/react/with-trpc/package.json +++ b/examples/react/with-trpc/package.json @@ -3,15 +3,15 @@ "private": true, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/react-router": "^1.115.2", - "@tanstack/react-router-devtools": "^1.115.2", - "@tanstack/router-plugin": "^1.115.2", - "@tanstack/react-start": "^1.115.2", + "@tanstack/react-router": "^1.116.0", + "@tanstack/react-router-devtools": "^1.116.0", + "@tanstack/router-plugin": "^1.116.0", + "@tanstack/react-start": "^1.116.0", "@trpc/client": "11.0.0-rc.772", "@trpc/server": "11.0.0-rc.772", "react": "^19.0.0", @@ -20,7 +20,6 @@ "postcss": "^8.5.1", "autoprefixer": "^10.4.20", "tailwindcss": "^3.4.17", - "vinxi": "0.5.3", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/react/with-trpc/src/main.tsx b/examples/react/with-trpc/src/main.tsx index 3cff783e4b..ff5d7de693 100644 --- a/examples/react/with-trpc/src/main.tsx +++ b/examples/react/with-trpc/src/main.tsx @@ -1,5 +1,3 @@ -/// - import React from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider, createRouter } from '@tanstack/react-router' diff --git a/examples/react/with-trpc/src/trpc.ts b/examples/react/with-trpc/src/trpc.ts index 243e4a6f5e..2320dcdfb6 100644 --- a/examples/react/with-trpc/src/trpc.ts +++ b/examples/react/with-trpc/src/trpc.ts @@ -4,7 +4,7 @@ import type { AppRouter } from '../trpc-server.handler' export const trpc = createTRPCClient({ links: [ httpBatchLink({ - // since we are using Vinxi, the server is running on the same port, + // since we are using Vite, the server is running on the same port, // this means in dev the url is `http://localhost:3000/trpc` // and since its from the same origin, we don't need to explicitly set the full URL url: '/trpc', diff --git a/examples/solid/basic-devtools-panel/package.json b/examples/solid/basic-devtools-panel/package.json index 29e4de0b7a..573590a39e 100644 --- a/examples/solid/basic-devtools-panel/package.json +++ b/examples/solid/basic-devtools-panel/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", diff --git a/examples/solid/basic-file-based/package.json b/examples/solid/basic-file-based/package.json index 2623a3ccd8..5b558c268e 100644 --- a/examples/solid/basic-file-based/package.json +++ b/examples/solid/basic-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "autoprefixer": "^10.4.20", "postcss": "^8.5.1", "redaxios": "^0.5.1", @@ -19,7 +19,7 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "typescript": "^5.7.2", "vite": "^6.1.0", "vite-plugin-solid": "^2.11.2" diff --git a/examples/solid/basic-non-nested-devtools/package.json b/examples/solid/basic-non-nested-devtools/package.json index 9d714b3c41..b1696e1e6d 100644 --- a/examples/solid/basic-non-nested-devtools/package.json +++ b/examples/solid/basic-non-nested-devtools/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "redaxios": "^0.5.1", "postcss": "^8.5.1", "solid-js": "^1.9.5", diff --git a/examples/solid/basic-solid-query-file-based/package.json b/examples/solid/basic-solid-query-file-based/package.json index 73c2287191..fb34e7a391 100644 --- a/examples/solid/basic-solid-query-file-based/package.json +++ b/examples/solid/basic-solid-query-file-based/package.json @@ -12,8 +12,8 @@ "dependencies": { "@tanstack/solid-query": "^5.71.9", "@tanstack/solid-query-devtools": "^5.71.9", - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", @@ -22,7 +22,7 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "typescript": "^5.7.2", "vite": "^6.1.0", "vite-plugin-solid": "^2.11.2" diff --git a/examples/solid/basic-solid-query/package.json b/examples/solid/basic-solid-query/package.json index 7aab951c8f..882c8ec95d 100644 --- a/examples/solid/basic-solid-query/package.json +++ b/examples/solid/basic-solid-query/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/solid-query": "^5.71.9", "@tanstack/solid-query-devtools": "^5.71.9", - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "postcss": "^8.5.1", @@ -20,7 +20,7 @@ "tailwindcss": "^3.4.17" }, "devDependencies": { - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "typescript": "^5.7.2", "vite": "^6.1.0", "vite-plugin-solid": "^2.11.2" diff --git a/examples/solid/basic/package.json b/examples/solid/basic/package.json index 2c81c2414c..5fb59f2673 100644 --- a/examples/solid/basic/package.json +++ b/examples/solid/basic/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "redaxios": "^0.5.1", "postcss": "^8.5.1", "solid-js": "^1.9.5", diff --git a/examples/solid/kitchen-sink-file-based/package.json b/examples/solid/kitchen-sink-file-based/package.json index 9b8ddcab67..15899f4fe9 100644 --- a/examples/solid/kitchen-sink-file-based/package.json +++ b/examples/solid/kitchen-sink-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "immer": "^10.1.1", "solid-js": "^1.9.5", "redaxios": "^0.5.1", @@ -20,7 +20,7 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "typescript": "^5.7.2", "vite": "^6.1.0", "vite-plugin-solid": "^2.11.2" diff --git a/examples/solid/quickstart-file-based/package.json b/examples/solid/quickstart-file-based/package.json index f05733c878..abb4193682 100644 --- a/examples/solid/quickstart-file-based/package.json +++ b/examples/solid/quickstart-file-based/package.json @@ -9,8 +9,8 @@ "start": "vite" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", "autoprefixer": "^10.4.20", "postcss": "^8.5.1", "redaxios": "^0.5.1", @@ -19,7 +19,7 @@ "zod": "^3.24.2" }, "devDependencies": { - "@tanstack/router-plugin": "^1.115.2", + "@tanstack/router-plugin": "^1.116.0", "typescript": "^5.7.2", "vite": "^6.1.0", "vite-plugin-solid": "^2.11.2" diff --git a/examples/solid/start-bare/app.config.ts b/examples/solid/start-bare/app.config.ts deleted file mode 100644 index 19c03a0458..0000000000 --- a/examples/solid/start-bare/app.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - tailwindcss(), - ], - }, -}) diff --git a/examples/solid/start-bare/package.json b/examples/solid/start-bare/package.json index ed70bea57f..94f27bda20 100644 --- a/examples/solid/start-bare/package.json +++ b/examples/solid/start-bare/package.json @@ -4,18 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", - "@tanstack/solid-start": "^1.115.2", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", + "@tanstack/solid-start": "^1.116.0", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vinxi": "0.5.3", + "vite": "6.1.5", "zod": "^3.24.2" }, "devDependencies": { diff --git a/examples/solid/start-bare/src/client.tsx b/examples/solid/start-bare/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/examples/solid/start-bare/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/examples/solid/start-bare/src/routeTree.gen.ts b/examples/solid/start-bare/src/routeTree.gen.ts index cb367c516c..345a058687 100644 --- a/examples/solid/start-bare/src/routeTree.gen.ts +++ b/examples/solid/start-bare/src/routeTree.gen.ts @@ -10,6 +10,7 @@ // Import Routes +import type { FileRoutesByPath, CreateFileRoute } from '@tanstack/solid-router' import { Route as rootRoute } from './routes/__root' import { Route as AboutImport } from './routes/about' import { Route as IndexImport } from './routes/index' @@ -49,6 +50,39 @@ declare module '@tanstack/solid-router' { } } +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/', + ServerFileRoutesByPath['/']['parentRoute'], + ServerFileRoutesByPath['/']['id'], + ServerFileRoutesByPath['/']['path'], + ServerFileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/about' { + const createFileRoute: CreateFileRoute< + '/about', + FileRoutesByPath['/about']['parentRoute'], + FileRoutesByPath['/about']['id'], + FileRoutesByPath['/about']['path'], + FileRoutesByPath['/about']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/about', + ServerFileRoutesByPath['/about']['parentRoute'], + ServerFileRoutesByPath['/about']['id'], + ServerFileRoutesByPath['/about']['path'], + ServerFileRoutesByPath['/about']['fullPath'] + > +} + // Create and export the route tree export interface FileRoutesByFullPath { diff --git a/examples/solid/start-bare/src/routes/about.tsx b/examples/solid/start-bare/src/routes/about.tsx index d66c7db828..6cbbbe1871 100644 --- a/examples/solid/start-bare/src/routes/about.tsx +++ b/examples/solid/start-bare/src/routes/about.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/about')({ + +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/solid/start-bare/src/routes/index.tsx b/examples/solid/start-bare/src/routes/index.tsx index 6a91bd1999..ca1710450e 100644 --- a/examples/solid/start-bare/src/routes/index.tsx +++ b/examples/solid/start-bare/src/routes/index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' + import Counter from '~/components/Counter' -export const Route = createFileRoute('/')({ +export const Route = createFileRoute({ component: RouteComponent, }) diff --git a/examples/solid/start-bare/src/ssr.tsx b/examples/solid/start-bare/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/examples/solid/start-bare/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/solid/start-bare/vite.config.ts b/examples/solid/start-bare/vite.config.ts new file mode 100644 index 0000000000..2b67ddeb0c --- /dev/null +++ b/examples/solid/start-bare/vite.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { TanStackStartVitePlugin } from '@tanstack/solid-start/plugin' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + TanStackStartVitePlugin({ + + }), + tailwindcss(), + ], +}) diff --git a/examples/solid/start-basic/app.config.ts b/examples/solid/start-basic/app.config.ts deleted file mode 100644 index 2a06e3d3f0..0000000000 --- a/examples/solid/start-basic/app.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from '@tanstack/solid-start/config' -import tsConfigPaths from 'vite-tsconfig-paths' - -export default defineConfig({ - tsr: { - appDirectory: 'src', - }, - vite: { - plugins: [ - tsConfigPaths({ - projects: ['./tsconfig.json'], - }), - ], - }, -}) diff --git a/examples/solid/start-basic/package.json b/examples/solid/start-basic/package.json index d9007acf0a..2b1c09a2d1 100644 --- a/examples/solid/start-basic/package.json +++ b/examples/solid/start-basic/package.json @@ -4,19 +4,18 @@ "sideEffects": false, "type": "module", "scripts": { - "dev": "vinxi dev", - "build": "vinxi build", - "start": "vinxi start" + "dev": "vite dev", + "build": "vite build", + "start": "vite start" }, "dependencies": { - "@tanstack/solid-router": "^1.115.0", - "@tanstack/solid-router-devtools": "^1.115.0", - "@tanstack/solid-start": "^1.115.2", + "@tanstack/solid-router": "^1.116.0", + "@tanstack/solid-router-devtools": "^1.116.0", + "@tanstack/solid-start": "^1.116.0", "solid-js": "^1.9.5", "redaxios": "^0.5.1", "tailwind-merge": "^2.6.0", - "vite": "6.1.4", - "vinxi": "0.5.3" + "vite": "6.1.4" }, "devDependencies": { "@types/node": "^22.5.4", diff --git a/examples/solid/start-basic/src/api.ts b/examples/solid/start-basic/src/api.ts deleted file mode 100644 index ed511bcd26..0000000000 --- a/examples/solid/start-basic/src/api.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { - createStartAPIHandler, - defaultAPIFileRouteHandler, -} from '@tanstack/solid-start/api' - -export default createStartAPIHandler(defaultAPIFileRouteHandler) diff --git a/examples/solid/start-basic/src/client.tsx b/examples/solid/start-basic/src/client.tsx deleted file mode 100644 index ba0f02fac0..0000000000 --- a/examples/solid/start-basic/src/client.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/// -import { hydrate } from 'solid-js/web' -import { StartClient } from '@tanstack/solid-start' -import { createRouter } from './router' - -const router = createRouter() - -hydrate(() => , document.body) diff --git a/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx b/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx index 0dff3919fd..bf759681a4 100644 --- a/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx +++ b/examples/solid/start-basic/src/components/DefaultCatchBoundary.tsx @@ -28,7 +28,7 @@ export function DefaultCatchBoundary({ error }: ErrorComponentProps) { > Try Again - {isRoot() ? ( + {isRoot ? ( rootRoute, + staticData: createIsomorphicFn() + .server(() => ({ + ...rootRoute.staticData, + serverRoute: UsersServerRouteImport, + })) + .client(() => rootRoute.staticData)(), } as any) -const RedirectRoute = RedirectImport.update({ +Object.assign(UsersServerRouteImport.options, { + pathname: '/users', +}) + +const RedirectRoute = RedirectRouteImport.update({ id: '/redirect', path: '/redirect', getParentRoute: () => rootRoute, } as any) -const PostsRoute = PostsImport.update({ +const PostsRoute = PostsRouteImport.update({ id: '/posts', path: '/posts', getParentRoute: () => rootRoute, } as any) -const DeferredRoute = DeferredImport.update({ +const DeferredRoute = DeferredRouteImport.update({ id: '/deferred', path: '/deferred', getParentRoute: () => rootRoute, } as any) -const PathlessLayoutRoute = PathlessLayoutImport.update({ +const PathlessLayoutRoute = PathlessLayoutRouteImport.update({ id: '/_pathlessLayout', getParentRoute: () => rootRoute, } as any) -const IndexRoute = IndexImport.update({ +const IndexRoute = IndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => rootRoute, } as any) -const UsersIndexRoute = UsersIndexImport.update({ +const UsersIndexRoute = UsersIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => UsersRoute, } as any) -const PostsIndexRoute = PostsIndexImport.update({ +const PostsIndexRoute = PostsIndexRouteImport.update({ id: '/', path: '/', getParentRoute: () => PostsRoute, } as any) -const UsersUserIdRoute = UsersUserIdImport.update({ +const UsersUserIdRoute = UsersUserIdRouteImport.update({ id: '/$userId', path: '/$userId', getParentRoute: () => UsersRoute, + staticData: createIsomorphicFn() + .server(() => ({ + ...UsersRoute.staticData, + serverRoute: UsersUserIdServerRouteImport, + })) + .client(() => UsersRoute.staticData)(), } as any) -const PostsPostIdRoute = PostsPostIdImport.update({ +Object.assign(UsersUserIdServerRouteImport.options, { + pathname: '/users/$userId', +}) + +const PostsPostIdRoute = PostsPostIdRouteImport.update({ id: '/$postId', path: '/$postId', getParentRoute: () => PostsRoute, } as any) -const PathlessLayoutNestedLayoutRoute = PathlessLayoutNestedLayoutImport.update( - { +const PathlessLayoutNestedLayoutRoute = + PathlessLayoutNestedLayoutRouteImport.update({ id: '/_nested-layout', getParentRoute: () => PathlessLayoutRoute, - } as any, -) + } as any) -const PostsPostIdDeepRoute = PostsPostIdDeepImport.update({ +const PostsPostIdDeepRoute = PostsPostIdDeepRouteImport.update({ id: '/posts_/$postId/deep', path: '/posts/$postId/deep', getParentRoute: () => rootRoute, } as any) const PathlessLayoutNestedLayoutRouteBRoute = - PathlessLayoutNestedLayoutRouteBImport.update({ + PathlessLayoutNestedLayoutRouteBRouteImport.update({ id: '/route-b', path: '/route-b', getParentRoute: () => PathlessLayoutNestedLayoutRoute, } as any) const PathlessLayoutNestedLayoutRouteARoute = - PathlessLayoutNestedLayoutRouteAImport.update({ + PathlessLayoutNestedLayoutRouteARouteImport.update({ id: '/route-a', path: '/route-a', getParentRoute: () => PathlessLayoutNestedLayoutRoute, @@ -122,103 +150,334 @@ declare module '@tanstack/solid-router' { id: '/' path: '/' fullPath: '/' - preLoaderRoute: typeof IndexImport + preLoaderRoute: typeof IndexRouteImport parentRoute: typeof rootRoute } '/_pathlessLayout': { id: '/_pathlessLayout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutRouteImport parentRoute: typeof rootRoute } '/deferred': { id: '/deferred' path: '/deferred' fullPath: '/deferred' - preLoaderRoute: typeof DeferredImport + preLoaderRoute: typeof DeferredRouteImport parentRoute: typeof rootRoute } '/posts': { id: '/posts' path: '/posts' fullPath: '/posts' - preLoaderRoute: typeof PostsImport + preLoaderRoute: typeof PostsRouteImport parentRoute: typeof rootRoute } '/redirect': { id: '/redirect' path: '/redirect' fullPath: '/redirect' - preLoaderRoute: typeof RedirectImport + preLoaderRoute: typeof RedirectRouteImport parentRoute: typeof rootRoute } '/users': { id: '/users' path: '/users' fullPath: '/users' - preLoaderRoute: typeof UsersImport + preLoaderRoute: typeof UsersRouteImport parentRoute: typeof rootRoute + serverParentRoute: unknown + serverRoute: typeof UsersServerRouteImport } '/_pathlessLayout/_nested-layout': { id: '/_pathlessLayout/_nested-layout' path: '' fullPath: '' - preLoaderRoute: typeof PathlessLayoutNestedLayoutImport - parentRoute: typeof PathlessLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteImport + parentRoute: typeof PathlessLayoutRouteImport } '/posts/$postId': { id: '/posts/$postId' path: '/$postId' fullPath: '/posts/$postId' - preLoaderRoute: typeof PostsPostIdImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsPostIdRouteImport + parentRoute: typeof PostsRouteImport } '/users/$userId': { id: '/users/$userId' path: '/$userId' fullPath: '/users/$userId' - preLoaderRoute: typeof UsersUserIdImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersUserIdRouteImport + parentRoute: typeof UsersRouteImport + serverParentRoute: typeof UsersServerRouteImport + serverRoute: typeof UsersUserIdServerRouteImport } '/posts/': { id: '/posts/' path: '/' fullPath: '/posts/' - preLoaderRoute: typeof PostsIndexImport - parentRoute: typeof PostsImport + preLoaderRoute: typeof PostsIndexRouteImport + parentRoute: typeof PostsRouteImport } '/users/': { id: '/users/' path: '/' fullPath: '/users/' - preLoaderRoute: typeof UsersIndexImport - parentRoute: typeof UsersImport + preLoaderRoute: typeof UsersIndexRouteImport + parentRoute: typeof UsersRouteImport } '/_pathlessLayout/_nested-layout/route-a': { id: '/_pathlessLayout/_nested-layout/route-a' path: '/route-a' fullPath: '/route-a' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteAImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteARouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/_pathlessLayout/_nested-layout/route-b': { id: '/_pathlessLayout/_nested-layout/route-b' path: '/route-b' fullPath: '/route-b' - preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBImport - parentRoute: typeof PathlessLayoutNestedLayoutImport + preLoaderRoute: typeof PathlessLayoutNestedLayoutRouteBRouteImport + parentRoute: typeof PathlessLayoutNestedLayoutRouteImport } '/posts_/$postId/deep': { id: '/posts_/$postId/deep' path: '/posts/$postId/deep' fullPath: '/posts/$postId/deep' - preLoaderRoute: typeof PostsPostIdDeepImport + preLoaderRoute: typeof PostsPostIdDeepRouteImport parentRoute: typeof rootRoute } } } +// Add type-safety to the createFileRoute & createServerFileRoute function across the route tree + +declare module './routes/index' { + const createFileRoute: CreateFileRoute< + '/', + FileRoutesByPath['/']['parentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/', + FileRoutesByPath['/']['serverParentRoute'], + FileRoutesByPath['/']['id'], + FileRoutesByPath['/']['path'], + FileRoutesByPath['/']['fullPath'] + > +} +declare module './routes/_pathlessLayout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout', + FileRoutesByPath['/_pathlessLayout']['serverParentRoute'], + FileRoutesByPath['/_pathlessLayout']['id'], + FileRoutesByPath['/_pathlessLayout']['path'], + FileRoutesByPath['/_pathlessLayout']['fullPath'] + > +} +declare module './routes/deferred' { + const createFileRoute: CreateFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['parentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/deferred', + FileRoutesByPath['/deferred']['serverParentRoute'], + FileRoutesByPath['/deferred']['id'], + FileRoutesByPath['/deferred']['path'], + FileRoutesByPath['/deferred']['fullPath'] + > +} +declare module './routes/posts' { + const createFileRoute: CreateFileRoute< + '/posts', + FileRoutesByPath['/posts']['parentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts', + FileRoutesByPath['/posts']['serverParentRoute'], + FileRoutesByPath['/posts']['id'], + FileRoutesByPath['/posts']['path'], + FileRoutesByPath['/posts']['fullPath'] + > +} +declare module './routes/redirect' { + const createFileRoute: CreateFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['parentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/redirect', + FileRoutesByPath['/redirect']['serverParentRoute'], + FileRoutesByPath['/redirect']['id'], + FileRoutesByPath['/redirect']['path'], + FileRoutesByPath['/redirect']['fullPath'] + > +} +declare module './routes/users' { + const createFileRoute: CreateFileRoute< + '/users', + FileRoutesByPath['/users']['parentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users', + FileRoutesByPath['/users']['serverParentRoute'], + FileRoutesByPath['/users']['id'], + FileRoutesByPath['/users']['path'], + FileRoutesByPath['/users']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout', + FileRoutesByPath['/_pathlessLayout/_nested-layout']['serverParentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout']['fullPath'] + > +} +declare module './routes/posts.$postId' { + const createFileRoute: CreateFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['parentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts/$postId', + FileRoutesByPath['/posts/$postId']['serverParentRoute'], + FileRoutesByPath['/posts/$postId']['id'], + FileRoutesByPath['/posts/$postId']['path'], + FileRoutesByPath['/posts/$postId']['fullPath'] + > +} +declare module './routes/users.$userId' { + const createFileRoute: CreateFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['parentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users/$userId', + FileRoutesByPath['/users/$userId']['serverParentRoute'], + FileRoutesByPath['/users/$userId']['id'], + FileRoutesByPath['/users/$userId']['path'], + FileRoutesByPath['/users/$userId']['fullPath'] + > +} +declare module './routes/posts.index' { + const createFileRoute: CreateFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['parentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts/', + FileRoutesByPath['/posts/']['serverParentRoute'], + FileRoutesByPath['/posts/']['id'], + FileRoutesByPath['/posts/']['path'], + FileRoutesByPath['/posts/']['fullPath'] + > +} +declare module './routes/users.index' { + const createFileRoute: CreateFileRoute< + '/users/', + FileRoutesByPath['/users/']['parentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/users/', + FileRoutesByPath['/users/']['serverParentRoute'], + FileRoutesByPath['/users/']['id'], + FileRoutesByPath['/users/']['path'], + FileRoutesByPath['/users/']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-a' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout/route-a', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['serverParentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-a']['fullPath'] + > +} +declare module './routes/_pathlessLayout/_nested-layout/route-b' { + const createFileRoute: CreateFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['parentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/_pathlessLayout/_nested-layout/route-b', + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['serverParentRoute'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['id'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['path'], + FileRoutesByPath['/_pathlessLayout/_nested-layout/route-b']['fullPath'] + > +} +declare module './routes/posts_.$postId.deep' { + const createFileRoute: CreateFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['parentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > + const createServerFileRoute: CreateServerFileRoute< + '/posts_/$postId/deep', + FileRoutesByPath['/posts_/$postId/deep']['serverParentRoute'], + FileRoutesByPath['/posts_/$postId/deep']['id'], + FileRoutesByPath['/posts_/$postId/deep']['path'], + FileRoutesByPath['/posts_/$postId/deep']['fullPath'] + > +} + // Create and export the route tree interface PathlessLayoutNestedLayoutRouteChildren { @@ -291,6 +550,11 @@ export interface FileRoutesByFullPath { '/posts/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesByFullPath { + '/users': typeof UsersServerRouteWithChildren + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRoutesByTo { '/': typeof IndexRoute '': typeof PathlessLayoutNestedLayoutRouteWithChildren @@ -305,6 +569,10 @@ export interface FileRoutesByTo { '/posts/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesByTo { + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute @@ -323,6 +591,11 @@ export interface FileRoutesById { '/posts_/$postId/deep': typeof PostsPostIdDeepRoute } +export interface ServerFileRoutesById { + '/users': typeof UsersServerRouteWithChildren + '/users/$userId': typeof UsersUserIdServerRouteImport +} + export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath fullPaths: diff --git a/examples/solid/start-basic/src/routes/__root.tsx b/examples/solid/start-basic/src/routes/__root.tsx index a9380d3209..3ab4e62b4c 100644 --- a/examples/solid/start-basic/src/routes/__root.tsx +++ b/examples/solid/start-basic/src/routes/__root.tsx @@ -1,6 +1,13 @@ -import { Link, Outlet, createRootRoute } from '@tanstack/solid-router' - -import { TanStackRouterDevtoolsInProd } from '@tanstack/solid-router-devtools' +import { + HeadContent, + Link, + Outlet, + Scripts, + createRootRoute, +} from '@tanstack/solid-router' +import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools' +import * as Solid from 'solid-js' +import { DefaultCatchBoundary } from '~/components/DefaultCatchBoundary' import { NotFound } from '~/components/NotFound' import appCss from '~/styles/app.css?url' import { seo } from '~/utils/seo' @@ -8,6 +15,9 @@ import { seo } from '~/utils/seo' export const Route = createRootRoute({ head: () => ({ meta: [ + { + charset: 'utf-8', + }, { name: 'viewport', content: 'width=device-width, initial-scale=1', @@ -41,14 +51,29 @@ export const Route = createRootRoute({ { rel: 'icon', href: '/favicon.ico' }, ], }), - errorComponent: (props) =>

{props.error.stack}

, + errorComponent: (props) => { + return ( + + + + ) + }, notFoundComponent: () => , component: RootComponent, }) function RootComponent() { + return ( + + + + ) +} + +function RootDocument({ children }: { children: Solid.JSX.Element }) { return ( <> +
{' '} - Deferred + Pathless Layout {' '} - redirect + Deferred {' '}
- - +
+ {children} + + ) } diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout.tsx index af197bc038..c549175638 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout.tsx @@ -1,6 +1,6 @@ -import { Outlet, createFileRoute } from '@tanstack/solid-router' +import { Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx index 24e4b2545b..03bcac9d47 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout.tsx @@ -1,6 +1,6 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout')({ +export const Route = createFileRoute({ component: LayoutComponent, }) diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx index a22902a271..843209d78b 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-a.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-a')( + +export const Route = createFileRoute( { component: LayoutAComponent, }, diff --git a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx index 36231d2153..97fa3753b3 100644 --- a/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx +++ b/examples/solid/start-basic/src/routes/_pathlessLayout/_nested-layout/route-b.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/_pathlessLayout/_nested-layout/route-b')( + +export const Route = createFileRoute( { component: LayoutBComponent, }, diff --git a/examples/solid/start-basic/src/routes/api/users.$id.ts b/examples/solid/start-basic/src/routes/api/users.$id.ts deleted file mode 100644 index b1786f6a30..0000000000 --- a/examples/solid/start-basic/src/routes/api/users.$id.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' - -export const APIRoute = createAPIFileRoute('/api/users/$id')({ - GET: async ({ request, params }) => { - console.info(`Fetching users by id=${params.id}... @`, request.url) - try { - const res = await axios.get( - 'https://jsonplaceholder.typicode.com/users/' + params.id, - ) - - return json({ - id: res.data.id, - name: res.data.name, - email: res.data.email, - }) - } catch (e) { - console.error(e) - return json({ error: 'User not found' }, { status: 404 }) - } - }, -}) diff --git a/examples/solid/start-basic/src/routes/api/users.ts b/examples/solid/start-basic/src/routes/api/users.ts deleted file mode 100644 index c10bcfc94a..0000000000 --- a/examples/solid/start-basic/src/routes/api/users.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { json } from '@tanstack/solid-start' -import { createAPIFileRoute } from '@tanstack/solid-start/api' -import axios from 'redaxios' -import type { User } from '../../utils/users' - -export const APIRoute = createAPIFileRoute('/api/users')({ - GET: async ({ request }) => { - console.info('Fetching users... @', request.url) - const res = await axios.get>( - 'https://jsonplaceholder.typicode.com/users', - ) - - const list = res.data.slice(0, 10) - - return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) - }, -}) diff --git a/examples/solid/start-basic/src/routes/deferred.tsx b/examples/solid/start-basic/src/routes/deferred.tsx index 1860f3af9a..c510571e5d 100644 --- a/examples/solid/start-basic/src/routes/deferred.tsx +++ b/examples/solid/start-basic/src/routes/deferred.tsx @@ -1,6 +1,6 @@ -import { Await, createFileRoute } from '@tanstack/solid-router' +import { Await } from '@tanstack/solid-router' import { createServerFn } from '@tanstack/solid-start' -import { createSignal, Suspense } from 'solid-js' +import { Suspense, createSignal } from 'solid-js' const personServerFn = createServerFn({ method: 'GET' }) .validator((d: string) => d) @@ -15,7 +15,7 @@ const slowServerFn = createServerFn({ method: 'GET' }) return { name, randomNumber: Math.floor(Math.random() * 100) } }) -export const Route = createFileRoute('/deferred')({ +export const Route = createFileRoute({ loader: async () => { return { deferredStuff: new Promise((r) => diff --git a/examples/solid/start-basic/src/routes/index.tsx b/examples/solid/start-basic/src/routes/index.tsx index a128aeca0e..aa79ef4545 100644 --- a/examples/solid/start-basic/src/routes/index.tsx +++ b/examples/solid/start-basic/src/routes/index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/')({ + +export const Route = createFileRoute({ component: Home, }) diff --git a/examples/solid/start-basic/src/routes/posts.$postId.tsx b/examples/solid/start-basic/src/routes/posts.$postId.tsx index d13735a4db..7d06791adb 100644 --- a/examples/solid/start-basic/src/routes/posts.$postId.tsx +++ b/examples/solid/start-basic/src/routes/posts.$postId.tsx @@ -1,9 +1,9 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { fetchPost } from '../utils/posts' import { NotFound } from '~/components/NotFound' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts/$postId')({ +export const Route = createFileRoute({ loader: ({ params: { postId } }) => fetchPost({ data: postId }), errorComponent: PostErrorComponent, component: PostComponent, diff --git a/examples/solid/start-basic/src/routes/posts.index.tsx b/examples/solid/start-basic/src/routes/posts.index.tsx index 33d0386c19..d0d3b4f2f2 100644 --- a/examples/solid/start-basic/src/routes/posts.index.tsx +++ b/examples/solid/start-basic/src/routes/posts.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/posts/')({ + +export const Route = createFileRoute({ component: PostsIndexComponent, }) diff --git a/examples/solid/start-basic/src/routes/posts.tsx b/examples/solid/start-basic/src/routes/posts.tsx index 326372478f..4f0b47fa08 100644 --- a/examples/solid/start-basic/src/routes/posts.tsx +++ b/examples/solid/start-basic/src/routes/posts.tsx @@ -1,7 +1,7 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import { fetchPosts } from '../utils/posts' -export const Route = createFileRoute('/posts')({ +export const Route = createFileRoute({ loader: async () => fetchPosts(), component: PostsComponent, }) diff --git a/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx b/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx index 7c52bc19eb..87eeade3b3 100644 --- a/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx +++ b/examples/solid/start-basic/src/routes/posts_.$postId.deep.tsx @@ -1,8 +1,8 @@ -import { Link, createFileRoute } from '@tanstack/solid-router' +import { Link } from '@tanstack/solid-router' import { fetchPost } from '../utils/posts' import { PostErrorComponent } from '~/components/PostError' -export const Route = createFileRoute('/posts_/$postId/deep')({ +export const Route = createFileRoute({ loader: async ({ params: { postId } }) => fetchPost({ data: postId, @@ -16,7 +16,10 @@ function PostDeepComponent() { return (
- + ← All Posts

{post().title}

diff --git a/examples/solid/start-basic/src/routes/redirect.tsx b/examples/solid/start-basic/src/routes/redirect.tsx index ca017f0635..7e98edeb77 100644 --- a/examples/solid/start-basic/src/routes/redirect.tsx +++ b/examples/solid/start-basic/src/routes/redirect.tsx @@ -1,6 +1,6 @@ -import { createFileRoute, redirect } from '@tanstack/solid-router' +import { redirect } from '@tanstack/solid-router' -export const Route = createFileRoute('/redirect')({ +export const Route = createFileRoute({ beforeLoad: async () => { throw redirect({ to: '/posts', diff --git a/examples/solid/start-basic/src/routes/users.$userId.tsx b/examples/solid/start-basic/src/routes/users.$userId.tsx index a2d99fbf6b..4e3b3f659d 100644 --- a/examples/solid/start-basic/src/routes/users.$userId.tsx +++ b/examples/solid/start-basic/src/routes/users.$userId.tsx @@ -1,15 +1,38 @@ -import { createFileRoute } from '@tanstack/solid-router' import axios from 'redaxios' -import type { User } from '~/utils/users' -import { DEPLOY_URL } from '~/utils/users' -import { NotFound } from '~/components/NotFound' -import { UserErrorComponent } from '~/components/UserError' +import { NotFound } from 'src/components/NotFound' +import { UserErrorComponent } from 'src/components/UserError' +import { json } from '@tanstack/solid-start' +import type { User } from 'src/utils/users' -export const Route = createFileRoute('/users/$userId')({ +export const ServerRoute = createServerFileRoute().methods({ + GET: async ({ params, request }) => { + console.info(`Fetching users by id=${params.userId}... @`, request.url) + try { + const res = await axios.get( + 'https://jsonplaceholder.typicode.com/users/' + params.userId, + ) + + return json({ + id: res.data.id, + name: res.data.name, + email: res.data.email, + }) + } catch (e) { + console.error(e) + return json({ error: 'User not found' }, { status: 404 }) + } + }, +}) + +export const Route = createFileRoute({ loader: async ({ params: { userId } }) => { - return await axios - .get(DEPLOY_URL + '/api/users/' + userId) - .then((r) => r.data) + return (await axios.get)( + '/api/users/' + userId, + ) + .then((r) => { + if ('error' in r.data) throw new Error() + return r.data + }) .catch(() => { throw new Error('Failed to fetch user') }) @@ -26,8 +49,8 @@ function UserComponent() { return (
-

{user().name}

-
{user().email}
+

{user.name}

+
{user.email}
) } diff --git a/examples/solid/start-basic/src/routes/users.index.tsx b/examples/solid/start-basic/src/routes/users.index.tsx index bbc96801a9..0e79fc2e7a 100644 --- a/examples/solid/start-basic/src/routes/users.index.tsx +++ b/examples/solid/start-basic/src/routes/users.index.tsx @@ -1,6 +1,6 @@ -import { createFileRoute } from '@tanstack/solid-router' -export const Route = createFileRoute('/users/')({ + +export const Route = createFileRoute({ component: UsersIndexComponent, }) diff --git a/examples/solid/start-basic/src/routes/users.tsx b/examples/solid/start-basic/src/routes/users.tsx index 2caca046e0..e8a5f080fb 100644 --- a/examples/solid/start-basic/src/routes/users.tsx +++ b/examples/solid/start-basic/src/routes/users.tsx @@ -1,16 +1,32 @@ -import { Link, Outlet, createFileRoute } from '@tanstack/solid-router' +import { Link, Outlet } from '@tanstack/solid-router' import axios from 'redaxios' -import { DEPLOY_URL } from '../utils/users' +import { json } from '@tanstack/solid-start' import type { User } from '../utils/users' -export const Route = createFileRoute('/users')({ - loader: async () => { - return await axios - .get>(DEPLOY_URL + '/api/users') - .then((r) => r.data) - .catch(() => { - throw new Error('Failed to fetch users') - }) +export const ServerRoute = createServerFileRoute().methods((api) => ({ + GET: async ({ request }) => { + console.info('Fetching users... @', request.url) + const res = await axios.get>( + 'https://jsonplaceholder.typicode.com/users', + ) + + const list = res.data.slice(0, 10) + + return json(list.map((u) => ({ id: u.id, name: u.name, email: u.email }))) + }, + POST: api + .validator((input: { body: { name: string; email: string } }) => input) + .handler(async ({ data }) => { + console.info('Creating user...', data) + return json({ id: '1', name: data.body.name, email: data.body.email }) + }), +})) + +export const Route = createFileRoute({ + loader: () => { + return ServerRoute.client.get().catch(() => { + throw new Error('Failed to fetch users') + }) }, component: UsersComponent, }) @@ -18,6 +34,24 @@ export const Route = createFileRoute('/users')({ function UsersComponent() { const users = Route.useLoaderData() + const addUser = ( + + ) + return (
    diff --git a/examples/solid/start-basic/src/ssr.tsx b/examples/solid/start-basic/src/ssr.tsx deleted file mode 100644 index 6d10bea05f..0000000000 --- a/examples/solid/start-basic/src/ssr.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/solid-start/server' -import { getRouterManifest } from '@tanstack/solid-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/examples/solid/start-basic/src/utils/posts.tsx b/examples/solid/start-basic/src/utils/posts.tsx index 96eaa78afc..e29706d38c 100644 --- a/examples/solid/start-basic/src/utils/posts.tsx +++ b/examples/solid/start-basic/src/utils/posts.tsx @@ -8,7 +8,7 @@ export type PostType = { body: string } -export const fetchPost = createServerFn({ method: 'GET' }) +export const fetchPost = createServerFn({ method: 'GET', type: 'static' }) .validator((d: string) => d) .handler(async ({ data }) => { console.info(`Fetching post with id ${data}...`) @@ -26,11 +26,12 @@ export const fetchPost = createServerFn({ method: 'GET' }) return post }) -export const fetchPosts = createServerFn({ method: 'GET' }).handler( - async () => { - console.info('Fetching posts...') - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) - }, -) +export const fetchPosts = createServerFn({ + method: 'GET', + type: 'static', +}).handler(async () => { + console.info('Fetching posts...') + return axios + .get>('https://jsonplaceholder.typicode.com/posts') + .then((r) => r.data.slice(0, 10)) +}) diff --git a/examples/solid/start-basic/src/utils/users.tsx b/examples/solid/start-basic/src/utils/users.tsx index b810f455fe..7ba645b383 100644 --- a/examples/solid/start-basic/src/utils/users.tsx +++ b/examples/solid/start-basic/src/utils/users.tsx @@ -3,5 +3,3 @@ export type User = { name: string email: string } - -export const DEPLOY_URL = 'http://localhost:3000' diff --git a/examples/solid/start-basic/vite.config.ts b/examples/solid/start-basic/vite.config.ts new file mode 100644 index 0000000000..7d905553ec --- /dev/null +++ b/examples/solid/start-basic/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite' +import tsConfigPaths from 'vite-tsconfig-paths' +import { TanStackStartVitePlugin } from '@tanstack/solid-start/plugin' + +export default defineConfig({ + server: { + port: 3000, + }, + plugins: [ + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + TanStackStartVitePlugin({ + + }), + ], +}) diff --git a/package.json b/package.json index 2e7f0fc7bf..89ae56e1d0 100644 --- a/package.json +++ b/package.json @@ -108,10 +108,10 @@ "@tanstack/solid-start-server": "workspace:*", "@tanstack/start-api-routes": "workspace:*", "@tanstack/start-server-functions-fetcher": "workspace:*", - "@tanstack/start-server-functions-handler": "workspace:*", "@tanstack/start-server-functions-client": "workspace:*", "@tanstack/start-server-functions-ssr": "workspace:*", "@tanstack/start-server-functions-server": "workspace:*", + "@tanstack/start-plugin-core": "workspace:*", "@tanstack/start-client-core": "workspace:*", "@tanstack/start-server-core": "workspace:*", "@tanstack/eslint-plugin-router": "workspace:*", diff --git a/packages/arktype-adapter/package.json b/packages/arktype-adapter/package.json index 939347e193..eea658c155 100644 --- a/packages/arktype-adapter/package.json +++ b/packages/arktype-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/arktype-adapter", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch --typecheck", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/create-router/package.json b/packages/create-router/package.json index c7fb58e1ed..161d477f56 100644 --- a/packages/create-router/package.json +++ b/packages/create-router/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/create-router", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -17,12 +17,7 @@ "bin": { "create-router": "index.js" }, - "scripts": { - "dev": "unbuild --stub", - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "build": "unbuild" - }, + "scripts": {}, "type": "module", "files": [ "index.js", diff --git a/packages/create-router/templates/core/_dot_gitignore b/packages/create-router/templates/core/_dot_gitignore index ed335a7bdc..bfcf92b4fd 100644 --- a/packages/create-router/templates/core/_dot_gitignore +++ b/packages/create-router/templates/core/_dot_gitignore @@ -5,9 +5,7 @@ # Dist node_modules -dist/ -.vinxi -.output +dist/.output .vercel .netlify .wrangler diff --git a/packages/create-start/package.json b/packages/create-start/package.json index 7fba8666f2..b2715c0642 100644 --- a/packages/create-start/package.json +++ b/packages/create-start/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/create-start", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tim O'Connell", "license": "MIT", @@ -17,16 +17,7 @@ "bin": { "create-start": "index.js" }, - "scripts": { - "dev": "BUILD_ENV=development unbuild --stub --watch", - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "generate-templates": "node ./dist/generate-templates/index.mjs", - "build": "BUILD_ENV=production unbuild && node ./copyTemplates.mjs", - "test": "vitest run", - "test:watch": "vitest watch", - "test:coverage": "vitest run --coverage" - }, + "scripts": {}, "type": "module", "files": [ "index.js", @@ -70,7 +61,6 @@ "@types/react-dom": "^19.0.3", "react": "^19.0.0", "react-dom": "^19.0.0", - "vinxi": "0.5.1", "vite": "^6.0.3" }, "peerDependenciesMeta": { @@ -98,9 +88,6 @@ "react-dom": { "optional": true }, - "vinxi": { - "optional": true - }, "vite": { "optional": true } diff --git a/packages/create-start/src/modules/core/index.ts b/packages/create-start/src/modules/core/index.ts index 79aaf2e8b1..effeb1d66a 100644 --- a/packages/create-start/src/modules/core/index.ts +++ b/packages/create-start/src/modules/core/index.ts @@ -68,21 +68,21 @@ export const coreModule = createModule( '@tanstack/react-start', 'react', 'react-dom', - 'vinxi', + 'vite', ]), devDependencies: await deps(['@types/react', '@types/react']), scripts: [ { name: 'dev', - script: 'vinxi dev', + script: 'vite dev', }, { name: 'build', - script: 'vinxi build', + script: 'vite build', }, { name: 'start', - script: 'vinxi start', + script: 'vite start', }, ], ...vals.packageJson, diff --git a/packages/create-start/src/modules/core/template/app/ssr.tsx b/packages/create-start/src/modules/core/template/app/ssr.tsx deleted file mode 100644 index 4ab0e48d6f..0000000000 --- a/packages/create-start/src/modules/core/template/app/ssr.tsx +++ /dev/null @@ -1,15 +0,0 @@ -// @ts-nocheck - -/// -import { - createStartHandler, - defaultStreamHandler, -} from '@tanstack/react-start/server' -import { getRouterManifest } from '@tanstack/react-start/router-manifest' - -import { createRouter } from './router' - -export default createStartHandler({ - createRouter, - getRouterManifest, -})(defaultStreamHandler) diff --git a/packages/create-start/src/modules/core/template/app/client.tsx b/packages/create-start/src/modules/core/template/src/client.tsx similarity index 84% rename from packages/create-start/src/modules/core/template/app/client.tsx rename to packages/create-start/src/modules/core/template/src/client.tsx index 64f18c113f..f675b9c39d 100644 --- a/packages/create-start/src/modules/core/template/app/client.tsx +++ b/packages/create-start/src/modules/core/template/src/client.tsx @@ -1,6 +1,5 @@ // @ts-nocheck -/// import { hydrateRoot } from 'react-dom/client' import { StartClient } from '@tanstack/react-start' import { createRouter } from './router' diff --git a/packages/create-start/src/modules/core/template/app/router.tsx b/packages/create-start/src/modules/core/template/src/router.tsx similarity index 100% rename from packages/create-start/src/modules/core/template/app/router.tsx rename to packages/create-start/src/modules/core/template/src/router.tsx diff --git a/packages/create-start/src/modules/core/template/app/routes/__root.tsx b/packages/create-start/src/modules/core/template/src/routes/__root.tsx similarity index 100% rename from packages/create-start/src/modules/core/template/app/routes/__root.tsx rename to packages/create-start/src/modules/core/template/src/routes/__root.tsx diff --git a/packages/create-start/tests/e2e/templates/barebones.test.ts b/packages/create-start/tests/e2e/templates/barebones.test.ts index f509937d32..35107d3069 100644 --- a/packages/create-start/tests/e2e/templates/barebones.test.ts +++ b/packages/create-start/tests/e2e/templates/barebones.test.ts @@ -65,15 +65,15 @@ describe('barebones template e2e', () => { expect(pkgJson.dependencies['@tanstack/react-start']).toBeDefined() expect(pkgJson.dependencies['react']).toBeDefined() expect(pkgJson.dependencies['react-dom']).toBeDefined() - expect(pkgJson.dependencies['vinxi']).toBeDefined() + expect(pkgJson.dependencies['vite']).toBeDefined() expect(pkgJson.devDependencies).toBeDefined() expect(pkgJson.devDependencies['@types/react']).toBeDefined() expect(pkgJson.scripts).toBeDefined() - expect(pkgJson.scripts.dev).toBe('vinxi dev') - expect(pkgJson.scripts.build).toBe('vinxi build') - expect(pkgJson.scripts.start).toBe('vinxi start') + expect(pkgJson.scripts.dev).toBe('vite dev') + expect(pkgJson.scripts.build).toBe('vite build') + expect(pkgJson.scripts.start).toBe('vite start') }) }) }) diff --git a/packages/directive-functions-plugin/package.json b/packages/directive-functions-plugin/package.json index 8f0cee2cd5..d10cd0e633 100644 --- a/packages/directive-functions-plugin/package.json +++ b/packages/directive-functions-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/directive-functions-plugin", - "version": "1.115.0", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,22 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", - "test:unit:dev": "vitest --watch", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/directive-functions-plugin/src/compilers.ts b/packages/directive-functions-plugin/src/compilers.ts index da0fe941bc..332a40b415 100644 --- a/packages/directive-functions-plugin/src/compilers.ts +++ b/packages/directive-functions-plugin/src/compilers.ts @@ -40,6 +40,8 @@ export type CompileDirectivesOpts = ParseAstOptions & { }) => string replacer: ReplacerFn // devSplitImporter: string + filename: string + root: string } function buildDirectiveSplitParam(opts: CompileDirectivesOpts) { @@ -230,6 +232,8 @@ export function findDirectives( directiveLabel: string replacer?: ReplacerFn directiveSplitParam: string + filename: string + root: string }, ): Record { const directiveFnsById: Record = {} diff --git a/packages/directive-functions-plugin/src/index.ts b/packages/directive-functions-plugin/src/index.ts index 25ed1df746..d0fd8aee06 100644 --- a/packages/directive-functions-plugin/src/index.ts +++ b/packages/directive-functions-plugin/src/index.ts @@ -15,23 +15,28 @@ export type { ReplacerFn, } from './compilers' -export type DirectiveFunctionsViteOptions = Pick< +export type DirectiveFunctionsViteEnvOptions = Pick< CompileDirectivesOpts, - 'directive' | 'directiveLabel' | 'getRuntimeCode' | 'replacer' - // | 'devSplitImporter' + 'getRuntimeCode' | 'replacer' > & { envLabel: string } +export type DirectiveFunctionsViteOptions = Pick< + CompileDirectivesOpts, + 'directive' | 'directiveLabel' +> & + DirectiveFunctionsViteEnvOptions & { + onDirectiveFnsById?: (directiveFnsById: Record) => void + } + const createDirectiveRx = (directive: string) => new RegExp(`"${directive}"|'${directive}'`, 'gm') export function TanStackDirectiveFunctionsPlugin( - opts: DirectiveFunctionsViteOptions & { - onDirectiveFnsById?: (directiveFnsById: Record) => void - }, + opts: DirectiveFunctionsViteOptions, ): Plugin { - let ROOT: string = process.cwd() + let root: string = process.cwd() const directiveRx = createDirectiveRx(opts.directive) @@ -39,36 +44,123 @@ export function TanStackDirectiveFunctionsPlugin( name: 'tanstack-start-directive-vite-plugin', enforce: 'pre', configResolved: (config) => { - ROOT = config.root + root = config.root }, transform(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - id = fileURLToPath(url).replace(/\\/g, '/') + return transformCode({ ...opts, code, id, directiveRx, root }) + }, + } +} - if (!code.match(directiveRx)) { - return null - } +export type DirectiveFunctionsVitePluginEnvOptions = Pick< + CompileDirectivesOpts, + 'directive' | 'directiveLabel' +> & { + environments: { + client: DirectiveFunctionsViteEnvOptions & { envName?: string } + server: DirectiveFunctionsViteEnvOptions & { envName?: string } + } + onDirectiveFnsById?: (directiveFnsById: Record) => void +} - if (debug) console.info(`${opts.envLabel}: Compiling Directives: `, id) +export function TanStackDirectiveFunctionsPluginEnv( + opts: DirectiveFunctionsVitePluginEnvOptions, +): Plugin { + opts = { + ...opts, + environments: { + client: { + envName: 'client', + ...opts.environments.client, + }, + server: { + envName: 'server', + ...opts.environments.server, + }, + }, + } - const { compiledResult, directiveFnsById } = compileDirectives({ + let root: string = process.cwd() + + const directiveRx = createDirectiveRx(opts.directive) + + return { + name: 'tanstack-start-directive-vite-plugin', + enforce: 'pre', + buildStart() { + root = this.environment.config.root + }, + // applyToEnvironment(env) { + // return [ + // opts.environments.client.envName, + // opts.environments.server.envName, + // ].includes(env.name) + // }, + transform(code, id) { + const envOptions = [ + opts.environments.client, + opts.environments.server, + ].find((e) => e.envName === this.environment.name) + + if (!envOptions) { + throw new Error(`Environment ${this.environment.name} not found`) + } + + return transformCode({ ...opts, + ...envOptions, code, - root: ROOT, - filename: id, - // globalThis.app currently refers to Vinxi's app instance. In the future, it can just be the - // vite dev server instance we get from Nitro. + id, + directiveRx, + root, }) + }, + } +} - opts.onDirectiveFnsById?.(directiveFnsById) +function transformCode({ + code, + id, + directiveRx, + envLabel, + directive, + directiveLabel, + getRuntimeCode, + replacer, + onDirectiveFnsById, + root, +}: DirectiveFunctionsViteOptions & { + code: string + id: string + directiveRx: RegExp + root: string +}) { + const url = pathToFileURL(id) + url.searchParams.delete('v') + id = fileURLToPath(url).replace(/\\/g, '/') - if (debug) { - logDiff(code, compiledResult.code) - console.log('Output:\n', compiledResult.code + '\n\n') - } + if (!code.match(directiveRx)) { + return null + } - return compiledResult - }, + if (debug) console.info(`${envLabel}: Compiling Directives: `, id) + + const { compiledResult, directiveFnsById } = compileDirectives({ + directive, + directiveLabel, + getRuntimeCode, + replacer, + code, + root, + filename: id, + }) + + onDirectiveFnsById?.(directiveFnsById) + + if (debug) { + logDiff(code, compiledResult.code) + console.log('Output:\n', compiledResult.code + '\n\n') } + + return compiledResult } diff --git a/packages/directive-functions-plugin/tests/compiler.test.ts b/packages/directive-functions-plugin/tests/compiler.test.ts index a7ff05be97..e88114a8ef 100644 --- a/packages/directive-functions-plugin/tests/compiler.test.ts +++ b/packages/directive-functions-plugin/tests/compiler.test.ts @@ -697,8 +697,6 @@ describe('server function compilation', () => { .extractedFilename, }) - console.log(ssr.directiveFnsById) - expect(client.compiledResult.code).toMatchInlineSnapshot(` "'use server'; diff --git a/packages/react-router-devtools/package.json b/packages/react-router-devtools/package.json index 08cbb7a424..cae43452d9 100644 --- a/packages/react-router-devtools/package.json +++ b/packages/react-router-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router-devtools", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,19 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "./dist/esm/index.d.ts", "main": "./dist/cjs/index.cjs", diff --git a/packages/react-router-with-query/package.json b/packages/react-router-with-query/package.json index a5bebbf72f..f6d20832b2 100644 --- a/packages/react-router-with-query/package.json +++ b/packages/react-router-with-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router-with-query", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/react-router/package.json b/packages/react-router/package.json index c07ed116be..027c4e5539 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-router", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,23 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js -p tsconfig.legacy.json", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js -p tsconfig.legacy.json", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js -p tsconfig.legacy.json", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js -p tsconfig.legacy.json", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js -p tsconfig.legacy.json", - "test:types:ts58": "tsc -p tsconfig.legacy.json", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch --hideSkippedTests", - "test:perf": "vitest bench", - "test:perf:dev": "pnpm run test:perf --watch --hideSkippedTests", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/react-router/src/HeadContent.tsx b/packages/react-router/src/HeadContent.tsx index 638dee8acc..b0856e5d49 100644 --- a/packages/react-router/src/HeadContent.tsx +++ b/packages/react-router/src/HeadContent.tsx @@ -58,8 +58,8 @@ export const useTags = () => { }, [routeMeta]) const links = useRouterState({ - select: (state) => - state.matches + select: (state) => { + const constructed = state.matches .map((match) => match.links!) .filter(Boolean) .flat(1) @@ -68,7 +68,30 @@ export const useTags = () => { attrs: { ...link, }, - })) as Array, + })) satisfies Array + + const manifest = router.ssr?.manifest + + // These are the assets extracted from the ViteManifest + // using the `startManifestPlugin` + const assets = state.matches + .map((match) => manifest?.routes[match.routeId]?.assets ?? []) + .filter(Boolean) + .flat(1) + .filter((asset) => asset.tag === 'link') + .map( + (asset) => + ({ + tag: 'link', + attrs: { + ...asset.attrs, + suppressHydrationWarning: true, + }, + }) satisfies RouterManagedTag, + ) + + return [...constructed, ...assets] + }, structuralSharing: true as any, }) diff --git a/packages/react-router/src/fileRoute.ts b/packages/react-router/src/fileRoute.ts index d645cc840d..31234f50fc 100644 --- a/packages/react-router/src/fileRoute.ts +++ b/packages/react-router/src/fileRoute.ts @@ -41,8 +41,13 @@ export function createFileRoute< TFullPath extends RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'], >( - path: TFilePath, + path?: TFilePath, ): FileRoute['createRoute'] { + if (typeof path === 'object') { + return new FileRoute(path, { + silent: true, + }).createRoute(path) as any + } return new FileRoute(path, { silent: true, }).createRoute @@ -63,7 +68,7 @@ export class FileRoute< silent?: boolean constructor( - public path: TFilePath, + public path?: TFilePath, _opts?: { silent: boolean }, ) { this.silent = _opts?.silent diff --git a/packages/react-router/src/index.tsx b/packages/react-router/src/index.tsx index a4bf0da92d..1dafac3797 100644 --- a/packages/react-router/src/index.tsx +++ b/packages/react-router/src/index.tsx @@ -126,6 +126,7 @@ export type { RouteById, RootRouteOptions, SerializerExtensions, + CreateFileRoute, } from '@tanstack/router-core' export type * from './serializer' @@ -362,6 +363,11 @@ export type { ValidateUseParamsResult, } from '@tanstack/router-core' +export { + __internal_devHtmlUtils, + type ExtractedHtmlTagInfo, +} from '@tanstack/router-core' + export { ScriptOnce } from './ScriptOnce' export { Asset } from './Asset' export { HeadContent } from './HeadContent' diff --git a/packages/react-router/src/router.ts b/packages/react-router/src/router.ts index 16b25cdcc9..1cfd74c757 100644 --- a/packages/react-router/src/router.ts +++ b/packages/react-router/src/router.ts @@ -1,4 +1,5 @@ import { RouterCore } from '@tanstack/router-core' +import { createFileRoute } from './fileRoute' import type { RouterHistory } from '@tanstack/history' import type { AnyRoute, @@ -105,3 +106,9 @@ export class Router< super(options) } } + +if (typeof globalThis !== 'undefined') { + ;(globalThis as any).createFileRoute = createFileRoute +} else if (typeof window !== 'undefined') { + ;(window as any).createFileRoute = createFileRoute +} diff --git a/packages/react-router/vite.config.ts b/packages/react-router/vite.config.ts index b53262bcf2..4fe28b540a 100644 --- a/packages/react-router/vite.config.ts +++ b/packages/react-router/vite.config.ts @@ -21,5 +21,14 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.tsx', srcDir: './src', + beforeWriteDeclarationFile: (filePath, content) => { + if (filePath.includes('index.d.ts')) { + return content.replace( + `createFileRouteImpl as createFileRoute`, + `createFileRouteGlobal as createFileRoute`, + ) + } + return content + }, }), ) diff --git a/packages/react-start-client/package.json b/packages/react-start-client/package.json index 35d39f4814..d86ef93d66 100644 --- a/packages/react-start-client/package.json +++ b/packages/react-start-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-client", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,22 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:deps && pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", - "test:unit:dev": "vitest --watch", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { @@ -69,8 +54,7 @@ "cookie-es": "^1.2.2", "jsesc": "^3.1.0", "tiny-invariant": "^1.3.3", - "tiny-warning": "^1.0.3", - "vinxi": "^0.5.3" + "tiny-warning": "^1.0.3" }, "devDependencies": { "@testing-library/react": "^16.2.0", diff --git a/packages/react-start-client/src/index.tsx b/packages/react-start-client/src/index.tsx index 6b9c30ee8f..f58d46d8d1 100644 --- a/packages/react-start-client/src/index.tsx +++ b/packages/react-start-client/src/index.tsx @@ -1,6 +1,17 @@ -/// -export { mergeHeaders } from '@tanstack/start-client-core' -export { startSerializer } from '@tanstack/start-client-core' +export { + mergeHeaders, + startSerializer, + createIsomorphicFn, + createServerFn, + createMiddleware, + registerGlobalMiddleware, + globalMiddleware, + serverOnly, + clientOnly, + createServerFileRoute, + getServerFileRouteApi, + json, +} from '@tanstack/start-client-core' export { type DehydratedRouter, type ClientExtractedBaseEntry, @@ -10,16 +21,10 @@ export { type ClientExtractedPromise, type ClientExtractedStream, type ResolvePromiseState, -} from '@tanstack/start-client-core' -export { - createIsomorphicFn, type IsomorphicFn, type ServerOnlyFn, type ClientOnlyFn, type IsomorphicFnBase, -} from '@tanstack/start-client-core' -export { createServerFn } from '@tanstack/start-client-core' -export { type ServerFn as FetchFn, type ServerFnCtx as FetchFnCtx, type CompiledFetcherFnOptions, @@ -31,10 +36,7 @@ export { type ServerFn, type ServerFnCtx, type ServerFnResponseType, -} from '@tanstack/start-client-core' -export { type JsonResponse } from '@tanstack/start-client-core' -export { - createMiddleware, + type JsonResponse, type IntersectAllValidatorInputs, type IntersectAllValidatorOutputs, type MiddlewareServerFn, @@ -44,7 +46,6 @@ export { type MiddlewareValidator, type MiddlewareServer, type MiddlewareAfterClient, - type MiddlewareAfterMiddleware, type MiddlewareAfterServer, type Middleware, type MiddlewareClientFnOptions, @@ -61,13 +62,8 @@ export { type MiddlewareServerFnOptions, type MiddlewareServerNextFn, type ServerResultWithContext, + type CreateServerFileRoute, } from '@tanstack/start-client-core' -export { - registerGlobalMiddleware, - globalMiddleware, -} from '@tanstack/start-client-core' -export { serverOnly, clientOnly } from '@tanstack/start-client-core' -export { json } from '@tanstack/start-client-core' export { Meta } from './Meta' export { Scripts } from './Scripts' export { StartClient } from './StartClient' diff --git a/packages/react-start-client/src/renderRSC.tsx b/packages/react-start-client/src/renderRSC.tsx index 6201bfa476..4832f074b6 100644 --- a/packages/react-start-client/src/renderRSC.tsx +++ b/packages/react-start-client/src/renderRSC.tsx @@ -1,6 +1,4 @@ // TODO: RSCs -// // @ts-expect-error -// import * as reactDom from '@vinxi/react-server-dom/client' import { isValidElement } from 'react' import invariant from 'tiny-invariant' import type React from 'react' diff --git a/packages/react-start-config/README.md b/packages/react-start-config/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/react-start-config/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/react-start-config/eslint.config.js b/packages/react-start-config/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/react-start-config/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/react-start-config/package.json b/packages/react-start-config/package.json deleted file mode 100644 index 482b5bea32..0000000000 --- a/packages/react-start-config/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/react-start-config", - "version": "1.115.2", - "description": "Modern and scalable routing for React applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/react-start-config" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "react", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "build": "tsc", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0;vitest", - "test:eslint": "eslint ./src", - "test:types": "exit 0; vitest" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "@tanstack/router-generator": "workspace:^", - "@tanstack/router-plugin": "workspace:^", - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/react-start-plugin": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@vitejs/plugin-react": "^4.3.4", - "import-meta-resolve": "^4.1.0", - "nitropack": "^2.10.4", - "ofetch": "^1.4.1", - "vite": "^6.1.0", - "vinxi": "0.5.3", - "zod": "^3.24.2" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "vite": "^6.0.0" - } -} diff --git a/packages/react-start-config/src/index.ts b/packages/react-start-config/src/index.ts deleted file mode 100644 index 7d8c8475df..0000000000 --- a/packages/react-start-config/src/index.ts +++ /dev/null @@ -1,665 +0,0 @@ -import path from 'node:path' -import { existsSync, readFileSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { fileURLToPath } from 'node:url' -import viteReact from '@vitejs/plugin-react' -import { resolve } from 'import-meta-resolve' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import { getConfig } from '@tanstack/router-generator' -import { createApp } from 'vinxi' -import { config } from 'vinxi/plugins/config' -// // @ts-expect-error -// import { serverComponents } from '@vinxi/server-components/plugin' -import { createTanStackServerFnPlugin } from '@tanstack/server-functions-plugin' -import { createTanStackStartPlugin } from '@tanstack/react-start-plugin' -import { createFetch } from 'ofetch' -import { createNitro } from 'nitropack' -import { tanstackStartVinxiFileRouter } from './vinxi-file-router.js' -import { - checkDeploymentPresetInput, - getUserViteConfig, - inlineConfigSchema, - serverSchema, -} from './schema.js' -import type { configSchema } from '@tanstack/router-generator' -import type { z } from 'zod' -import type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' -import type { App as VinxiApp } from 'vinxi' -import type { Manifest } from '@tanstack/router-core' -import type * as vite from 'vite' - -export type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' - -function setTsrDefaults(config: TanStackStartOutputConfig['tsr']) { - // Normally these are `./src/___`, but we're using `./app/___` for Start stuff - const appDirectory = config?.appDirectory ?? './app' - return { - ...config, - appDirectory: config?.appDirectory ?? appDirectory, - routesDirectory: - config?.routesDirectory ?? path.join(appDirectory, 'routes'), - generatedRouteTree: - config?.generatedRouteTree ?? path.join(appDirectory, 'routeTree.gen.ts'), - } -} - -function mergeSsrOptions(options: Array) { - let ssrOptions: vite.SSROptions = {} - let noExternal: vite.SSROptions['noExternal'] = [] - for (const option of options) { - if (!option) { - continue - } - - if (option.noExternal) { - if (option.noExternal === true) { - noExternal = true - } else if (noExternal !== true) { - if (Array.isArray(option.noExternal)) { - noExternal.push(...option.noExternal) - } else { - noExternal.push(option.noExternal) - } - } - } - - ssrOptions = { - ...ssrOptions, - ...option, - noExternal, - } - } - - return ssrOptions -} - -export async function defineConfig( - inlineConfig: TanStackStartInputConfig = {}, -): Promise { - const opts = inlineConfigSchema.parse(inlineConfig) - - const { preset: configDeploymentPreset, ...serverOptions } = - serverSchema.parse(opts.server || {}) - - const deploymentPreset = checkDeploymentPresetInput( - configDeploymentPreset || 'node-server', - ) - const tsr = setTsrDefaults(opts.tsr) - const tsrConfig = getConfig(tsr) - - const appDirectory = tsr.appDirectory - const publicDir = opts.routers?.public?.dir || './public' - - const publicBase = opts.routers?.public?.base || '/' - const clientBase = opts.routers?.client?.base || '/_build' - const apiBase = opts.tsr?.apiBase || '/api' - const serverBase = opts.routers?.server?.base || '/_server' - - const apiMiddleware = opts.routers?.api?.middleware || undefined - const serverMiddleware = opts.routers?.server?.middleware || undefined - const ssrMiddleware = opts.routers?.ssr?.middleware || undefined - - const clientEntry = - opts.routers?.client?.entry || path.join(appDirectory, 'client.tsx') - const ssrEntry = - opts.routers?.ssr?.entry || path.join(appDirectory, 'ssr.tsx') - const apiEntry = opts.routers?.api?.entry || path.join(appDirectory, 'api.ts') - const globalMiddlewareEntry = - opts.routers?.server?.globalMiddlewareEntry || - path.join(appDirectory, 'global-middleware.ts') - const apiEntryExists = existsSync(apiEntry) - - const viteConfig = getUserViteConfig(opts.vite) - - const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', - client: { - getRuntimeCode: () => - `import { createClientRpc } from '@tanstack/react-start/server-functions-client'`, - replacer: (opts) => - `createClientRpc('${opts.functionId}', '${serverBase}')`, - }, - ssr: { - getRuntimeCode: () => - `import { createSsrRpc } from '@tanstack/react-start/server-functions-ssr'`, - replacer: (opts) => `createSsrRpc('${opts.functionId}', '${serverBase}')`, - }, - server: { - getRuntimeCode: () => - `import { createServerRpc } from '@tanstack/react-start/server-functions-server'`, - replacer: (opts) => - `createServerRpc('${opts.functionId}', '${serverBase}', ${opts.fn})`, - }, - }) - - const TanStackStartPlugin = createTanStackStartPlugin({ - globalMiddlewareEntry, - }) - - // Create a dummy nitro app to get the resolved public output path - const dummyNitroApp = await createNitro({ - preset: deploymentPreset, - compatibilityDate: '2024-12-01', - }) - - const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir - await dummyNitroApp.close() - - let vinxiApp = createApp({ - server: { - ...serverOptions, - preset: deploymentPreset, - experimental: { - ...serverOptions.experimental, - asyncContext: true, - }, - }, - routers: [ - { - name: 'public', - type: 'static', - dir: publicDir, - base: publicBase, - }, - { - name: 'client', - type: 'client', - target: 'browser', - handler: clientEntry, - base: clientBase, - // @ts-expect-error - build: { - sourcemap: true, - }, - plugins: () => { - const routerType = 'client' - const clientViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-client', { - ...viteConfig.userConfig, - ...clientViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(clientViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - clientViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(clientViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: true, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.client, - TanStackServerFnsPlugin.client, - ...(viteConfig.plugins || []), - ...(clientViteConfig.plugins || []), - viteReact(opts.react), - // TODO: RSCS - enable this - // serverComponents.client(), - ] - }, - }, - { - name: 'ssr', - type: 'http', - target: 'server', - handler: ssrEntry, - middleware: ssrMiddleware, - // @ts-expect-error - link: { - client: 'client', - }, - plugins: () => { - const routerType = 'ssr' - const ssrViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-ssr', { - ...viteConfig.userConfig, - ...ssrViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(ssrViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - ssrViteConfig.userConfig.ssr, - { - noExternal, - external: ['@vinxi/react-server-dom/client'], - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(ssrViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.ssr, - TanStackServerFnsPlugin.ssr, - tsrRoutesManifest({ - tsrConfig, - clientBase, - }), - ...(getUserViteConfig(opts.vite).plugins || []), - ...(getUserViteConfig(opts.routers?.ssr?.vite).plugins || []), - viteReact(opts.react), - ] - }, - }, - { - name: 'server', - type: 'http', - target: 'server', - base: serverBase, - middleware: serverMiddleware, - // TODO: RSCS - enable this - // worker: true, - handler: importToProjectRelative( - '@tanstack/start-server-functions-handler', - ), - plugins: () => { - const routerType = 'server' - const serverViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-server', { - ...viteConfig.userConfig, - ...serverViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(serverViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_SERVER_FN_BASE', serverBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - serverViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(serverViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.server, - TanStackServerFnsPlugin.server, - // TODO: RSCS - remove this - // resolve: { - // conditions: [], - // }, - // TODO: RSCs - add this - // serverComponents.serverActions({ - // resolve: { - // conditions: [ - // 'react-server', - // // 'node', - // 'import', - // process.env.NODE_ENV, - // ], - // }, - // runtime: '@vinxi/react-server-dom/runtime', - // transpileDeps: ['react', 'react-dom', '@vinxi/react-server-dom'], - // }), - ...(viteConfig.plugins || []), - ...(serverViteConfig.plugins || []), - ] - }, - }, - ], - }) - - const noExternal = [ - '@tanstack/start', - '@tanstack/react-start', - '@tanstack/react-start/server', - '@tanstack/react-start-client', - '@tanstack/react-start-server', - '@tanstack/start-server-functions-fetcher', - '@tanstack/start-server-functions-handler', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-server-functions-server', - '@tanstack/react-start-router-manifest', - '@tanstack/react-start-config', - '@tanstack/start-api-routes', - '@tanstack/server-functions-plugin', - 'tsr:routes-manifest', - 'tsr:server-fn-manifest', - ] - - // If API routes handler exists, add a router for it - if (apiEntryExists) { - vinxiApp = vinxiApp.addRouter({ - name: 'api', - type: 'http', - target: 'server', - base: apiBase, - handler: apiEntry, - middleware: apiMiddleware, - routes: tanstackStartVinxiFileRouter({ tsrConfig, apiBase }), - plugins: () => { - const viteConfig = getUserViteConfig(opts.vite) - const apiViteConfig = getUserViteConfig(opts.routers?.api?.vite) - - return [ - config('tsr-vite-config-api', { - ...viteConfig.userConfig, - ...apiViteConfig.userConfig, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - apiViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(apiViteConfig.userConfig.optimizeDeps || {}), - }, - define: { - ...(viteConfig.userConfig.define || {}), - ...(apiViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - ...(viteConfig.plugins || []), - ...(apiViteConfig.plugins || []), - ] - }, - }) - } - - // Because Vinxi doesn't use the normal nitro dev server, it doesn't - // supply $fetch during dev. We need to hook into the dev server creation, - // nab the proper utils from the custom nitro instance that is used - // during dev and supply the $fetch to app. - // Hopefully and likely, this will just get removed when we move to - // Nitro directly. - vinxiApp.hooks.hook('app:dev:nitro:config', (devServer) => { - vinxiApp.hooks.hook( - 'app:dev:server:created', - ({ devApp: { localFetch } }) => { - const $fetch = createFetch({ - fetch: localFetch, - defaults: { - baseURL: devServer.nitro.options.runtimeConfig.app.baseURL, - }, - }) - - // @ts-expect-error - globalThis.$fetch = $fetch - }, - ) - }) - - return vinxiApp -} - -function importToProjectRelative(p: string) { - const resolved = fileURLToPath(resolve(p, import.meta.url)) - - const relative = path.relative(process.cwd(), resolved) - - return relative -} - -function tsrRoutesManifest(opts: { - tsrConfig: z.infer - clientBase: string -}): vite.Plugin { - let config: vite.ResolvedConfig - - return { - name: 'tsr-routes-manifest', - configResolved(resolvedConfig) { - config = resolvedConfig - }, - resolveId(id) { - if (id === 'tsr:routes-manifest') { - return id - } - return - }, - async load(id) { - if (id === 'tsr:routes-manifest') { - // If we're in development, return a dummy manifest - - if (config.command === 'serve') { - return `export default () => ({ - routes: {} - })` - } - - const clientViteManifestPath = path.resolve( - config.build.outDir, - `../client/${opts.clientBase}/.vite/manifest.json`, - ) - - type ViteManifest = Record< - string, - { - file: string - isEntry: boolean - imports: Array - } - > - - let manifest: ViteManifest - try { - manifest = JSON.parse(await readFile(clientViteManifestPath, 'utf-8')) - } catch (err) { - console.error(err) - throw new Error( - `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, - ) - } - - const routeTreePath = path.resolve(opts.tsrConfig.generatedRouteTree) - - let routeTreeContent: string - try { - routeTreeContent = readFileSync(routeTreePath, 'utf-8') - } catch (err) { - console.error(err) - throw new Error( - `Could not find the generated route tree at '${routeTreePath}'!`, - ) - } - - // Extract the routesManifest JSON from the route tree file. - // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. - - const routerManifest = JSON.parse( - routeTreeContent.match( - /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, - )?.[1] || '{ routes: {} }', - ) as Manifest - - const routes = routerManifest.routes - - let entryFile: - | { - file: string - imports: Array - } - | undefined - - const filesByRouteFilePath: ViteManifest = Object.fromEntries( - Object.entries(manifest).map(([k, v]) => { - if (v.isEntry) { - entryFile = v - } - - const rPath = k.split('?')[0] - - return [rPath, v] - }, {}), - ) - - // Add preloads to the routes from the vite manifest - Object.entries(routes).forEach(([k, v]) => { - const file = - filesByRouteFilePath[ - path.join(opts.tsrConfig.routesDirectory, v.filePath as string) - ] - - if (file) { - const preloads = file.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ) - - preloads.unshift(path.join(opts.clientBase, file.file)) - - routes[k] = { - ...v, - preloads, - } - } - }) - - if (entryFile) { - routes.__root__!.preloads = [ - path.join(opts.clientBase, entryFile.file), - ...entryFile.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ), - ] - } - - const recurseRoute = ( - route: { - preloads?: Array - children?: Array - }, - seenPreloads = {} as Record, - ) => { - route.preloads = route.preloads?.filter((preload) => { - if (seenPreloads[preload]) { - return false - } - seenPreloads[preload] = true - return true - }) - - if (route.children) { - route.children.forEach((child) => { - const childRoute = routes[child]! - recurseRoute(childRoute, { ...seenPreloads }) - }) - } - } - - // @ts-expect-error - recurseRoute(routes.__root__) - - const routesManifest = { - routes, - } - - if (process.env.TSR_VITE_DEBUG) { - console.info( - 'Routes Manifest: \n' + JSON.stringify(routesManifest, null, 2), - ) - } - - return `export default () => (${JSON.stringify(routesManifest)})` - } - return - }, - } -} - -function injectDefineEnv( - key: TKey, - value: TValue, -): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { - return { - [`process.env.${key}`]: JSON.stringify(value), - [`import.meta.env.${key}`]: JSON.stringify(value), - } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } -} diff --git a/packages/react-start-config/src/schema.ts b/packages/react-start-config/src/schema.ts deleted file mode 100644 index 516e4e86fa..0000000000 --- a/packages/react-start-config/src/schema.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { configSchema } from '@tanstack/router-generator' -import { z } from 'zod' -import type { PluginOption } from 'vite' -import type { AppOptions as VinxiAppOptions } from 'vinxi' -import type { NitroOptions } from 'nitropack' -import type { Options as ViteReactOptions } from '@vitejs/plugin-react' -import type { CustomizableConfig } from 'vinxi/dist/types/lib/vite-dev' - -type StartUserViteConfig = CustomizableConfig | (() => CustomizableConfig) - -export function getUserViteConfig(config?: StartUserViteConfig): { - plugins: Array | undefined - userConfig: CustomizableConfig -} { - const { plugins, ...userConfig } = - typeof config === 'function' ? config() : { ...config } - return { plugins, userConfig } -} - -/** - * Not all the deployment presets are fully functional or tested. - * @see https://github.com/TanStack/router/pull/2002 - */ -const vinxiDeploymentPresets = [ - 'alwaysdata', // untested - 'aws-amplify', // untested - 'aws-lambda', // untested - 'azure', // untested - 'azure-functions', // untested - 'base-worker', // untested - 'bun', // ✅ working - 'cleavr', // untested - 'cli', // untested - 'cloudflare', // untested - 'cloudflare-module', // untested - 'cloudflare-pages', // ✅ working - 'cloudflare-pages-static', // untested - 'deno', // untested - 'deno-deploy', // untested - 'deno-server', // untested - 'digital-ocean', // untested - 'edgio', // untested - 'firebase', // untested - 'flight-control', // untested - 'github-pages', // untested - 'heroku', // untested - 'iis', // untested - 'iis-handler', // untested - 'iis-node', // untested - 'koyeb', // untested - 'layer0', // untested - 'netlify', // ✅ working - 'netlify-builder', // untested - 'netlify-edge', // untested - 'netlify-static', // untested - 'nitro-dev', // untested - 'nitro-prerender', // untested - 'node', // partially working - 'node-cluster', // untested - 'node-server', // ✅ working - 'platform-sh', // untested - 'service-worker', // untested - 'static', // 🟧 partially working - 'stormkit', // untested - 'vercel', // ✅ working - 'vercel-edge', // untested - 'vercel-static', // untested - 'winterjs', // untested - 'zeabur', // untested - 'zeabur-static', // untested -] as const - -type DeploymentPreset = (typeof vinxiDeploymentPresets)[number] | (string & {}) - -const testedDeploymentPresets: Array = [ - 'bun', - 'netlify', - 'vercel', - 'cloudflare-pages', - 'node-server', -] - -export function checkDeploymentPresetInput(preset: string): DeploymentPreset { - if (!vinxiDeploymentPresets.includes(preset as any)) { - console.warn( - `Invalid deployment preset "${preset}". Available presets are: ${vinxiDeploymentPresets - .map((p) => `"${p}"`) - .join(', ')}.`, - ) - } - - if (!testedDeploymentPresets.includes(preset as any)) { - console.warn( - `The deployment preset '${preset}' is not fully supported yet and may not work as expected.`, - ) - } - - return preset -} - -type HTTPSOptions = { - cert?: string - key?: string - pfx?: string - passphrase?: string - validityDays?: number - domains?: Array -} - -type ServerOptions_ = VinxiAppOptions['server'] & { - https?: boolean | HTTPSOptions -} - -type ServerOptions = { - [K in keyof ServerOptions_]: ServerOptions_[K] -} - -export const serverSchema = z - .object({ - routeRules: z.custom().optional(), - preset: z.custom().optional(), - static: z.boolean().optional(), - prerender: z - .object({ - routes: z.array(z.string()), - ignore: z - .array( - z.custom< - string | RegExp | ((path: string) => undefined | null | boolean) - >(), - ) - .optional(), - crawlLinks: z.boolean().optional(), - }) - .optional(), - }) - .and(z.custom()) - -const viteSchema = z.custom() - -const viteReactSchema = z.custom() - -const routersSchema = z.object({ - ssr: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - client: z - .object({ - entry: z.string().optional(), - base: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - server: z - .object({ - base: z.string().optional(), - globalMiddlewareEntry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - api: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - public: z - .object({ - dir: z.string().optional(), - base: z.string().optional(), - }) - .optional(), -}) - -const tsrConfig = configSchema.partial().extend({ - appDirectory: z.string().optional(), -}) - -export const inlineConfigSchema = z.object({ - react: viteReactSchema.optional(), - vite: viteSchema.optional(), - tsr: tsrConfig.optional(), - routers: routersSchema.optional(), - server: serverSchema.optional(), -}) - -export type TanStackStartInputConfig = z.input -export type TanStackStartOutputConfig = z.infer diff --git a/packages/react-start-config/src/vinxi-file-router.ts b/packages/react-start-config/src/vinxi-file-router.ts deleted file mode 100644 index 9e6d829d1b..0000000000 --- a/packages/react-start-config/src/vinxi-file-router.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - BaseFileSystemRouter as VinxiBaseFileSystemRouter, - analyzeModule as vinxiFsRouterAnalyzeModule, - cleanPath as vinxiFsRouterCleanPath, -} from 'vinxi/fs-router' -import { - CONSTANTS as GENERATOR_CONSTANTS, - startAPIRouteSegmentsFromTSRFilePath, -} from '@tanstack/router-generator' -import type { configSchema } from '@tanstack/router-generator' -import type { - AppOptions as VinxiAppOptions, - RouterSchemaInput as VinxiRouterSchemaInput, -} from 'vinxi' -import type { z } from 'zod' - -export function tanstackStartVinxiFileRouter(opts: { - tsrConfig: z.infer - apiBase: string -}) { - const apiBaseSegment = opts.apiBase.split('/').filter(Boolean).join('/') - const isAPIPath = new RegExp(`/${apiBaseSegment}/`) - - return function (router: VinxiRouterSchemaInput, app: VinxiAppOptions) { - // Our own custom File Router that extends the VinxiBaseFileSystemRouter - // for splitting the API routes into its own "bundle" - // and adding the $APIRoute metadata to the route object - // This could be customized in future to support more complex splits - class TanStackStartFsRouter extends VinxiBaseFileSystemRouter { - toPath(src: string): string { - const inputPath = vinxiFsRouterCleanPath(src, this.config) - - const segments = startAPIRouteSegmentsFromTSRFilePath( - inputPath, - opts.tsrConfig, - ) - - const pathname = segments - .map((part) => { - if (part.type === 'splat') { - return `*splat` - } - - if (part.type === 'param') { - return `:${part.value}?` - } - - return part.value - }) - .join('/') - - return pathname.length > 0 ? `/${pathname}` : '/' - } - - toRoute(src: string) { - const webPath = this.toPath(src) - - const [_, exports] = vinxiFsRouterAnalyzeModule(src) - - const hasAPIRoute = exports.find( - (exp) => exp.n === GENERATOR_CONSTANTS.APIRouteExportVariable, - ) - - return { - path: webPath, - filePath: src, - $APIRoute: - isAPIPath.test(webPath) && hasAPIRoute - ? { - src, - pick: [GENERATOR_CONSTANTS.APIRouteExportVariable], - } - : undefined, - } - } - } - - return new TanStackStartFsRouter( - { - dir: opts.tsrConfig.routesDirectory, - extensions: ['js', 'jsx', 'ts', 'tsx'], - }, - router, - app, - ) - } -} diff --git a/packages/react-start-plugin/package.json b/packages/react-start-plugin/package.json index f13d4951cc..44e1194fb1 100644 --- a/packages/react-start-plugin/package.json +++ b/packages/react-start-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-plugin", - "version": "1.115.0", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,22 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "clean:snapshots": "rimraf **/*snapshot* --glob", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", @@ -72,15 +57,25 @@ "@babel/template": "^7.26.8", "@babel/traverse": "^7.26.8", "@babel/types": "^7.26.8", + "@tanstack/router-core": "workspace:^", + "@tanstack/router-plugin": "workspace:^", "@tanstack/router-utils": "workspace:^", - "babel-dead-code-elimination": "^1.0.10", - "tiny-invariant": "^1.3.3", - "vite": "6.1.4" - }, - "devDependencies": { + "@tanstack/server-functions-plugin": "workspace:^", + "@tanstack/start-plugin-core": "workspace:^", "@types/babel__code-frame": "^7.0.6", "@types/babel__core": "^7.20.5", "@types/babel__template": "^7.4.4", - "@types/babel__traverse": "^7.20.6" + "@types/babel__traverse": "^7.20.6", + "@vitejs/plugin-react": "^4.3.4", + "babel-dead-code-elimination": "^1.0.9", + "fast-glob": "^3.3.3", + "get-port": "^7.1.0", + "h3": "1.13.0", + "import-meta-resolve": "^4.1.0", + "nitropack": "^2.11.8", + "tiny-invariant": "^1.3.3", + "ufo": "^1.5.4", + "vite": "6.1.4", + "zod": "^3.24.2" } } diff --git a/packages/react-start-plugin/src/compilers.ts b/packages/react-start-plugin/src/compilers.ts index ca806fc991..76781498fd 100644 --- a/packages/react-start-plugin/src/compilers.ts +++ b/packages/react-start-plugin/src/compilers.ts @@ -1,584 +1,3 @@ -import * as babel from '@babel/core' -import * as t from '@babel/types' -import { codeFrameColumns } from '@babel/code-frame' -import { - deadCodeElimination, - findReferencedIdentifiers, -} from 'babel-dead-code-elimination' -import { generateFromAst, parseAst } from '@tanstack/router-utils' -import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' +import { compileStartOutputFactory } from '@tanstack/start-plugin-core' -// build these once and reuse them -const handleServerOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('server') -const handleClientOnlyCallExpression = - buildEnvOnlyCallExpressionHandler('client') - -type CompileOptions = ParseAstOptions & { - env: 'server' | 'client' | 'ssr' - dce?: boolean -} - -type IdentifierConfig = { - name: string - type: 'ImportSpecifier' | 'ImportNamespaceSpecifier' - namespaceId: string - handleCallExpression: ( - path: babel.NodePath, - opts: CompileOptions, - ) => void - paths: Array -} - -export function compileStartOutput(opts: CompileOptions): GeneratorResult { - const ast = parseAst(opts) - - const doDce = opts.dce ?? true - // find referenced identifiers *before* we transform anything - const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined - - babel.traverse(ast, { - Program: { - enter(programPath) { - const identifiers: { - createServerFn: IdentifierConfig - createMiddleware: IdentifierConfig - serverOnly: IdentifierConfig - clientOnly: IdentifierConfig - createIsomorphicFn: IdentifierConfig - } = { - createServerFn: { - name: 'createServerFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateServerFnCallExpression, - paths: [], - }, - createMiddleware: { - name: 'createMiddleware', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateMiddlewareCallExpression, - paths: [], - }, - serverOnly: { - name: 'serverOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleServerOnlyCallExpression, - paths: [], - }, - clientOnly: { - name: 'clientOnly', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleClientOnlyCallExpression, - paths: [], - }, - createIsomorphicFn: { - name: 'createIsomorphicFn', - type: 'ImportSpecifier', - namespaceId: '', - handleCallExpression: handleCreateIsomorphicFnCallExpression, - paths: [], - }, - } - - const identifierKeys = Object.keys(identifiers) as Array< - keyof typeof identifiers - > - - programPath.traverse({ - ImportDeclaration: (path) => { - if (path.node.source.value !== '@tanstack/react-start') { - return - } - - // handle a destructured imports being renamed like "import { createServerFn as myCreateServerFn } from '@tanstack/react-start';" - path.node.specifiers.forEach((specifier) => { - identifierKeys.forEach((identifierKey) => { - const identifier = identifiers[identifierKey] - - if ( - specifier.type === 'ImportSpecifier' && - specifier.imported.type === 'Identifier' - ) { - if (specifier.imported.name === identifierKey) { - identifier.name = specifier.local.name - identifier.type = 'ImportSpecifier' - } - } - - // handle namespace imports like "import * as TanStackStart from '@tanstack/react-start';" - if (specifier.type === 'ImportNamespaceSpecifier') { - identifier.type = 'ImportNamespaceSpecifier' - identifier.namespaceId = specifier.local.name - identifier.name = `${identifier.namespaceId}.${identifierKey}` - } - }) - }) - }, - CallExpression: (path) => { - identifierKeys.forEach((identifierKey) => { - // Check to see if the call expression is a call to the - // identifiers[identifierKey].name - if ( - t.isIdentifier(path.node.callee) && - path.node.callee.name === identifiers[identifierKey].name - ) { - // The identifier could be a call to the original function - // in the source code. If this is case, we need to ignore it. - // Check the scope to see if the identifier is a function declaration. - // if it is, then we can ignore it. - - if ( - path.scope.getBinding(identifiers[identifierKey].name)?.path - .node.type === 'FunctionDeclaration' - ) { - return - } - - return identifiers[identifierKey].paths.push(path) - } - - if (t.isMemberExpression(path.node.callee)) { - if ( - t.isIdentifier(path.node.callee.object) && - t.isIdentifier(path.node.callee.property) - ) { - const callname = [ - path.node.callee.object.name, - path.node.callee.property.name, - ].join('.') - - if (callname === identifiers[identifierKey].name) { - identifiers[identifierKey].paths.push(path) - } - } - } - - return - }) - }, - }) - - identifierKeys.forEach((identifierKey) => { - identifiers[identifierKey].paths.forEach((path) => { - identifiers[identifierKey].handleCallExpression( - path as babel.NodePath, - opts, - ) - }) - }) - }, - }, - }) - - if (doDce) { - deadCodeElimination(ast, refIdents) - } - - return generateFromAst(ast, { - sourceMaps: true, - sourceFileName: opts.filename, - filename: opts.filename, - }) -} - -function handleCreateServerFnCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - // The function is the 'fn' property of the object passed to createServerFn - - // const firstArg = path.node.arguments[0] - // if (t.isObjectExpression(firstArg)) { - // // Was called with some options - // } - - // Traverse the member expression and find the call expressions for - // the validator, handler, and middleware methods. Check to make sure they - // are children of the createServerFn call expression. - - const calledOptions = path.node.arguments[0] - ? (path.get('arguments.0') as babel.NodePath) - : null - - const shouldValidateClient = !!calledOptions?.node.properties.find((prop) => { - return ( - t.isObjectProperty(prop) && - t.isIdentifier(prop.key) && - prop.key.name === 'validateClient' && - t.isBooleanLiteral(prop.value) && - prop.value.value === true - ) - }) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - handler: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createServerFn call expression:', - // rootCallExpression.toString(), - // ) - - // Check if the call is assigned to a variable - if (!rootCallExpression.parentPath.isVariableDeclarator()) { - throw new Error('createServerFn must be assigned to a variable!') - } - - // Get the identifier name of the variable - const variableDeclarator = rootCallExpression.parentPath.node - const existingVariableName = (variableDeclarator.id as t.Identifier).name - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createServerFn().validator() must be called with a validator!', - ) - } - - // If we're on the client, and we're not validating the client, remove the validator call expression - if ( - opts.env === 'client' && - !shouldValidateClient && - t.isMemberExpression(callExpressionPaths.validator.node.callee) - ) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - - // First, we need to move the handler function to a nested function call - // that is applied to the arguments passed to the server function. - - const handlerFnPath = callExpressionPaths.handler?.get( - 'arguments.0', - ) as babel.NodePath - - if (!callExpressionPaths.handler || !handlerFnPath.node) { - throw codeFrameError( - opts.code, - path.node.callee.loc!, - `createServerFn must be called with a "handler" property!`, - ) - } - - const handlerFn = handlerFnPath.node - - // So, the way we do this is we give the handler function a way - // to access the serverFn ctx on the server via function scope. - // The 'use server' extracted function will be called with the - // payload from the client, then use the scoped serverFn ctx - // to execute the handler function. - // This way, we can do things like data and middleware validation - // in the __execute function without having to AST transform the - // handler function too much itself. - - // .handler((optsOut, ctx) => { - // return ((optsIn) => { - // 'use server' - // ctx.__execute(handlerFn, optsIn) - // })(optsOut) - // }) - - // If the handler function is an identifier and we're on the client, we need to - // remove the bound function from the file. - // If we're on the server, you can leave it, since it will get referenced - // as a second argument. - - if (t.isIdentifier(handlerFn)) { - if (opts.env === 'client' || opts.env === 'ssr') { - // Find the binding for the handler function - const binding = handlerFnPath.scope.getBinding(handlerFn.name) - // Remove it - if (binding) { - binding.path.remove() - } - } - // If the env is server, just leave it alone - } - - handlerFnPath.replaceWith( - t.arrowFunctionExpression( - [t.identifier('opts'), t.identifier('signal')], - t.blockStatement( - // Everything in here is server-only, since the client - // will strip out anything in the 'use server' directive. - [ - t.returnStatement( - t.callExpression( - t.identifier(`${existingVariableName}.__executeServer`), - [t.identifier('opts'), t.identifier('signal')], - ), - ), - ], - [t.directive(t.directiveLiteral('use server'))], - ), - ), - ) - - if (opts.env === 'server') { - callExpressionPaths.handler.node.arguments.push(handlerFn) - } -} - -function handleCreateMiddlewareCallExpression( - path: babel.NodePath, - opts: ParseAstOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createMiddleware call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - middleware: null as babel.NodePath | null, - validator: null as babel.NodePath | null, - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if (callExpressionPaths.validator) { - const innerInputExpression = callExpressionPaths.validator.node.arguments[0] - - if (!innerInputExpression) { - throw new Error( - 'createMiddleware().validator() must be called with a validator!', - ) - } - - // If we're on the client or ssr, remove the validator call expression - if (opts.env === 'client' || opts.env === 'ssr') { - if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) { - callExpressionPaths.validator.replaceWith( - callExpressionPaths.validator.node.callee.object, - ) - } - } - } - - const serverFnPath = callExpressionPaths.server?.get( - 'arguments.0', - ) as babel.NodePath - - if ( - callExpressionPaths.server && - serverFnPath.node && - (opts.env === 'client' || opts.env === 'ssr') - ) { - // If we're on the client, remove the server call expression - if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { - callExpressionPaths.server.replaceWith( - callExpressionPaths.server.node.callee.object, - ) - } - } -} - -function buildEnvOnlyCallExpressionHandler(env: 'client' | 'server') { - return function envOnlyCallExpressionHandler( - path: babel.NodePath, - opts: ParseAstOptions, - ) { - // if (debug) - // console.info(`Handling ${env}Only call expression:`, path.toString()) - - const isEnvMatch = - env === 'client' - ? opts.env === 'client' - : opts.env === 'server' || opts.env === 'ssr' - - if (isEnvMatch) { - // extract the inner function from the call expression - const innerInputExpression = path.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `${env}Only() functions must be called with a function!`, - ) - } - - path.replaceWith(innerInputExpression) - return - } - - // If we're on the wrong environment, replace the call expression - // with a function that always throws an error. - path.replaceWith( - t.arrowFunctionExpression( - [], - t.blockStatement([ - t.throwStatement( - t.newExpression(t.identifier('Error'), [ - t.stringLiteral( - `${env}Only() functions can only be called on the ${env}!`, - ), - ]), - ), - ]), - ), - ) - } -} - -function handleCreateIsomorphicFnCallExpression( - path: babel.NodePath, - opts: CompileOptions, -) { - const rootCallExpression = getRootCallExpression(path) - - // if (debug) - // console.info( - // 'Handling createIsomorphicFn call expression:', - // rootCallExpression.toString(), - // ) - - const callExpressionPaths = { - client: null as babel.NodePath | null, - server: null as babel.NodePath | null, - } - - const validMethods = Object.keys(callExpressionPaths) - - rootCallExpression.traverse({ - MemberExpression(memberExpressionPath) { - if (t.isIdentifier(memberExpressionPath.node.property)) { - const name = memberExpressionPath.node.property - .name as keyof typeof callExpressionPaths - - if ( - validMethods.includes(name) && - memberExpressionPath.parentPath.isCallExpression() - ) { - callExpressionPaths[name] = memberExpressionPath.parentPath - } - } - }, - }) - - if ( - validMethods.every( - (method) => - !callExpressionPaths[method as keyof typeof callExpressionPaths], - ) - ) { - const variableId = rootCallExpression.parentPath.isVariableDeclarator() - ? rootCallExpression.parentPath.node.id - : null - console.warn( - 'createIsomorphicFn called without a client or server implementation!', - 'This will result in a no-op function.', - 'Variable name:', - t.isIdentifier(variableId) ? variableId.name : 'unknown', - ) - } - - const resolvedEnv = opts.env === 'ssr' ? 'server' : opts.env - - const envCallExpression = callExpressionPaths[resolvedEnv] - - if (!envCallExpression) { - // if we don't have an implementation for this environment, default to a no-op - rootCallExpression.replaceWith( - t.arrowFunctionExpression([], t.blockStatement([])), - ) - return - } - - const innerInputExpression = envCallExpression.node.arguments[0] - - if (!t.isExpression(innerInputExpression)) { - throw new Error( - `createIsomorphicFn().${resolvedEnv}(func) must be called with a function!`, - ) - } - - rootCallExpression.replaceWith(innerInputExpression) -} - -function getRootCallExpression(path: babel.NodePath) { - // Find the highest callExpression parent - let rootCallExpression: babel.NodePath = path - - // Traverse up the chain of CallExpressions - while (rootCallExpression.parentPath.isMemberExpression()) { - const parent = rootCallExpression.parentPath - if (parent.parentPath.isCallExpression()) { - rootCallExpression = parent.parentPath - } - } - - return rootCallExpression -} - -function codeFrameError( - code: string, - loc: { - start: { line: number; column: number } - end: { line: number; column: number } - }, - message: string, -) { - const frame = codeFrameColumns( - code, - { - start: loc.start, - end: loc.end, - }, - { - highlightCode: true, - message, - }, - ) - - return new Error(frame) -} +export const compileStartOutput = compileStartOutputFactory('react'); \ No newline at end of file diff --git a/packages/react-start-plugin/src/index.ts b/packages/react-start-plugin/src/index.ts index 6ab529afca..c395458e1e 100644 --- a/packages/react-start-plugin/src/index.ts +++ b/packages/react-start-plugin/src/index.ts @@ -1,143 +1,183 @@ -import { fileURLToPath, pathToFileURL } from 'node:url' import path from 'node:path' -import { existsSync } from 'node:fs' -import { logDiff } from '@tanstack/router-utils' -import { compileStartOutput } from './compilers' -import type { Plugin } from 'vite' - -const debug = - process.env.TSR_VITE_DEBUG && - ['true', 'react-start-plugin'].includes(process.env.TSR_VITE_DEBUG) - -export type TanStackStartViteOptions = { - globalMiddlewareEntry: string -} - -const transformFuncs = [ - 'createServerFn', - 'createMiddleware', - 'serverOnly', - 'clientOnly', - 'createIsomorphicFn', -] -const tokenRegex = new RegExp(transformFuncs.join('|')) -// const eitherFuncRegex = new RegExp( -// `(function ${transformFuncs.join('|function ')})`, -// ) - -export function createTanStackStartPlugin(opts: TanStackStartViteOptions): { - client: Array - ssr: Array - server: Array -} { - const globalMiddlewarePlugin = (): Plugin => { - let entry: string | null = null - let resolvedGlobalMiddlewareEntry: string | null = null - let globalMiddlewareEntryExists = false - let ROOT: string = process.cwd() - return { - name: 'vite-plugin-tanstack-start-ensure-global-middleware', - enforce: 'pre', - configResolved: (config) => { - ROOT = config.root - entry = path.resolve(ROOT, (config as any).router.handler) - resolvedGlobalMiddlewareEntry = path.resolve( - ROOT, - opts.globalMiddlewareEntry, - ) - globalMiddlewareEntryExists = existsSync(resolvedGlobalMiddlewareEntry) - - if (!entry) { - throw new Error( - '@tanstack/react-start-plugin: No server entry found!', - ) +import { TanStackServerFnPluginEnv } from '@tanstack/server-functions-plugin' +import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import viteReact from '@vitejs/plugin-react' +import { createNitro } from 'nitropack' +import { getTanStackStartOptions } from './schema.js' +import { nitroPlugin } from './nitro/nitro-plugin.js' +import { startManifestPlugin } from './routesManifestPlugin.js' +import { TanStackStartCompilerPlugin } from './start-compiler-plugin.js' +import type { PluginOption } from 'vite' +import type { TanStackStartInputConfig, WithReactPlugin } from './schema.js' + +export type { + TanStackStartInputConfig, + TanStackStartOutputConfig, + WithReactPlugin, +} from './schema.js' + +export const clientDistDir = 'node_modules/.tanstack-start/client-dist' + +export function TanStackStartVitePlugin( + opts?: TanStackStartInputConfig & WithReactPlugin, +): Array { + type OptionsWithReact = ReturnType & WithReactPlugin; + const options: OptionsWithReact = getTanStackStartOptions(opts); + + return [ + { + name: 'tss-vite-config-client', + async config() { + const nitroOutputPublicDir = await (async () => { + // Create a dummy nitro app to get the resolved public output path + const dummyNitroApp = await createNitro({ + preset: options.target, + compatibilityDate: '2024-12-01', + }) + + const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir + await dummyNitroApp.close() + + return nitroOutputPublicDir + })() + + return { + environments: { + client: { + build: { + manifest: true, + rollupOptions: { + input: { + main: options.clientEntryPath, + }, + output: { + dir: path.resolve(options.root, clientDistDir), + }, + external: ['node:fs', 'node:path', 'node:os', 'node:crypto'], + }, + }, + }, + server: {}, + }, + resolve: { + noExternal: [ + '@tanstack/start', + '@tanstack/start/server', + '@tanstack/start-client', + '@tanstack/start-client-core', + '@tanstack/start-server', + '@tanstack/start-server-core', + '@tanstack/start-server-functions-fetcher', + '@tanstack/start-server-functions-client', + '@tanstack/start-server-functions-ssr', + '@tanstack/start-server-functions-server', + '@tanstack/start-router-manifest', + '@tanstack/start-config', + '@tanstack/start-api-routes', + '@tanstack/server-functions-plugin', + 'tsr:start-manifest', + 'tsr:server-fn-manifest', + ], + }, + /* prettier-ignore */ + define: { + ...injectDefineEnv('TSS_PUBLIC_BASE', options.public.base), + ...injectDefineEnv('TSS_CLIENT_BASE', options.client.base), + ...injectDefineEnv('TSS_CLIENT_ENTRY', options.clientEntryPath), + ...injectDefineEnv('TSS_SERVER_FN_BASE', options.serverFns.base), + ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), + }, } }, - transform(code, id) { - if (entry && id.includes(entry)) { - if (globalMiddlewareEntryExists) { - return { - code: `${code}\n\nimport '${path.resolve(ROOT, opts.globalMiddlewareEntry)}'`, - map: null, - } - } + resolveId(id) { + if ( + [ + '/~start/default-server-entry', + '/~start/default-client-entry', + ].includes(id) + ) { + return `${id}.tsx` } + return null }, - } - } - - return { - client: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'client' }), - ], - ssr: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'ssr' }), - ], - server: [ - globalMiddlewarePlugin(), - TanStackStartServerFnsAndMiddleware({ ...opts, env: 'server' }), - ], - } -} + load(id) { + const routerImportPath = JSON.stringify( + path.resolve(options.root, options.tsr.srcDirectory, 'router'), + ) -export function TanStackStartServerFnsAndMiddleware(opts: { - env: 'server' | 'ssr' | 'client' -}): Plugin { - let ROOT: string = process.cwd() + if (id === '/~start/default-client-entry.tsx') { + return ` +import { hydrateRoot } from 'react-dom/client' +import { StartClient } from '@tanstack/react-start' +import { createRouter } from ${routerImportPath} - return { - name: 'vite-plugin-tanstack-start-create-server-fn', - enforce: 'pre', - configResolved: (config) => { - ROOT = config.root - }, - transform(code, id) { - const url = pathToFileURL(id) - url.searchParams.delete('v') - id = fileURLToPath(url).replace(/\\/g, '/') - - const includesToken = tokenRegex.test(code) - // const includesEitherFunc = eitherFuncRegex.test(code) - - if ( - !includesToken - // includesEitherFunc - // /node_modules/.test(id) - ) { - return null - } - - if (code.includes('@react-refresh')) { - throw new Error( - `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/react-start-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: -e.g. - -plugins: [ - TanStackStartVite(), // Place this before viteReact() - viteReact(), -] -`, - ) - } +const router = createRouter() - if (debug) console.info(`${opts.env} Compiling Start: `, id) +hydrateRoot(document, ) +` + } - const compiled = compileStartOutput({ - code, - root: ROOT, - filename: id, - env: opts.env, - }) + if (id === '/~start/default-server-entry.tsx') { + return ` +import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server' +import { createRouter } from ${routerImportPath} - if (debug) { - logDiff(code, compiled.code) - console.log('Output:\n', compiled.code + '\n\n') - } +export default createStartHandler({ + createRouter, +})(defaultStreamHandler) +` + } - return compiled + return null + }, }, - } + TanStackStartCompilerPlugin(), + TanStackServerFnPluginEnv({ + // This is the ID that will be available to look up and import + // our server function manifest and resolve its module + manifestVirtualImportId: 'tsr:server-fn-manifest', + client: { + getRuntimeCode: () => + `import { createClientRpc } from '@tanstack/react-start/server-functions-client'`, + replacer: (d) => + `createClientRpc('${d.functionId}', '${options.serverFns.base}')`, + }, + server: { + getRuntimeCode: () => + `import { createServerRpc } from '@tanstack/react-start/server-functions-server'`, + replacer: (d) => + `createServerRpc('${d.functionId}', '${options.serverFns.base}', ${d.fn})`, + }, + }), + startManifestPlugin(options), + TanStackRouterVite({ + ...options.tsr, + target: 'react', + enableRouteGeneration: true, + __enableAPIRoutesGeneration: true, + autoCodeSplitting: true, + }), + viteReact(options.react), + nitroPlugin(options), + ] +} + +function injectDefineEnv( + key: TKey, + value: TValue, +): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { + return { + [`process.env.${key}`]: JSON.stringify(value), + [`import.meta.env.${key}`]: JSON.stringify(value), + } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } } + +// function isEmptyPrerenderRoutes(options?: Options): boolean { +// if (!options || isArrayWithElements(nitroConfig.prerender?.routes)) { +// return false +// } +// return !options.server.prerender?.routes +// } + +export { compileStartOutput } from './compilers' \ No newline at end of file diff --git a/packages/react-start-plugin/src/nitro/dev-server-plugin.ts b/packages/react-start-plugin/src/nitro/dev-server-plugin.ts new file mode 100644 index 0000000000..f3a4d27815 --- /dev/null +++ b/packages/react-start-plugin/src/nitro/dev-server-plugin.ts @@ -0,0 +1,174 @@ +// SSR dev server, middleware and error page source modified from +// https://github.com/solidjs/solid-start/blob/main/packages/start/dev/server.js + +import { createEvent, getHeader, sendWebResponse } from 'h3' +import { isRunnableDevEnvironment } from 'vite' +import { __internal_devHtmlUtils } from '@tanstack/router-core' +import type { ExtractedHtmlTagInfo } from '@tanstack/router-core' +import type { Connect, Environment, Plugin, ViteDevServer } from 'vite' +import type { TanStackStartOutputConfig } from '../schema.js' + +declare global { + // eslint-disable-next-line no-var + var TSS_INJECTED_HEAD_SCRIPTS_INFO: Array | undefined +} + +export function devServerPlugin(options: TanStackStartOutputConfig): Plugin { + // let config: UserConfig + let isTest = false + + return { + name: 'start-dev-ssr-plugin', + config(userConfig, { mode }) { + // config = userConfig + isTest = isTest ? isTest : mode === 'test' + + return { + resolve: { + alias: { + '/~start/ssr-entry': options.serverEntryPath, + }, + }, + } + }, + configureServer(viteDevServer) { + if (isTest) { + return + } + + ;(globalThis as any).viteDevServer = viteDevServer + + return () => { + remove_html_middlewares(viteDevServer.middlewares) + + viteDevServer.middlewares.use(async (req, res) => { + const event = createEvent(req, res) + const serverEnv = viteDevServer.environments['server'] as Environment + + try { + if (!isRunnableDevEnvironment(serverEnv)) { + throw new Error('Server environment not found') + } + + const templateHtml = `` + const transformedHtml = await viteDevServer.transformIndexHtml( + req.url || '/', + templateHtml, + ) + + const headScripts = __internal_devHtmlUtils.extractHtmlTagInfo( + 'script', + __internal_devHtmlUtils.extractHeadContent(transformedHtml), + ) + globalThis.TSS_INJECTED_HEAD_SCRIPTS_INFO = headScripts + + const serverEntry = + await serverEnv.runner.import('/~start/ssr-entry') + + const response = await serverEntry['default'](event) + + sendWebResponse(event, response) + } catch (e) { + console.error(e) + viteDevServer.ssrFixStacktrace(e as Error) + + if ( + getHeader(event, 'content-type')?.includes('application/json') + ) { + return sendWebResponse( + event, + new Response( + JSON.stringify( + { + status: 500, + error: 'Internal Server Error', + message: + 'An unexpected error occurred. Please try again later.', + timestamp: new Date().toISOString(), + }, + null, + 2, + ), + { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }, + ), + ) + } + + sendWebResponse( + event, + new Response( + ` + + + + + Error + + + + + + `, + { + status: 500, + headers: { + 'Content-Type': 'text/html', + }, + }, + ), + ) + } + }) + } + }, + } +} + +/** + * Removes Vite internal middleware + * + * @param server + */ +function remove_html_middlewares(server: ViteDevServer['middlewares']) { + const html_middlewares = [ + 'viteIndexHtmlMiddleware', + 'vite404Middleware', + 'viteSpaFallbackMiddleware', + ] + for (let i = server.stack.length - 1; i > 0; i--) { + if ( + html_middlewares.includes( + // @ts-expect-error + server.stack[i].handle.name, + ) + ) { + server.stack.splice(i, 1) + } + } +} + +/** + * Formats error for SSR message in error overlay + * @param req + * @param error + * @returns + */ +function prepareError(req: Connect.IncomingMessage, error: unknown) { + const e = error as Error + return { + message: `An error occured while server rendering ${req.url}:\n\n\t${ + typeof e === 'string' ? e : e.message + } `, + stack: typeof e === 'string' ? '' : e.stack, + } +} diff --git a/packages/react-start-plugin/src/nitro/nitro-plugin.ts b/packages/react-start-plugin/src/nitro/nitro-plugin.ts new file mode 100644 index 0000000000..1765022715 --- /dev/null +++ b/packages/react-start-plugin/src/nitro/nitro-plugin.ts @@ -0,0 +1,141 @@ +import { platform } from 'node:os' +import path from 'node:path' +import { createNitro } from 'nitropack' +import { normalizePath } from 'vite' + +import { getRollupConfig } from 'nitropack/rollup' +import { buildNitroEnvironment } from '@tanstack/start-plugin-core' +import { clientDistDir } from '../index.js' +import { prerender } from '../prerender.js' +import { devServerPlugin } from './dev-server-plugin.js' +import type { EnvironmentOptions, PluginOption } from 'vite' +import type { Nitro, NitroConfig } from 'nitropack' +import type { TanStackStartOutputConfig } from '../schema.js' + +export type { + TanStackStartInputConfig, + TanStackStartOutputConfig, +} from '../schema.js' + +const isWindows = platform() === 'win32' +const filePrefix = isWindows ? 'file:///' : '' + +export function nitroPlugin( + options: TanStackStartOutputConfig, +): Array { + let nitro: Nitro + let nitroRollupOptions: ReturnType + + const buildPreset = + process.env['START_TARGET'] ?? (options.target as string | undefined) + + const nitroConfig: NitroConfig = { + dev: false, + compatibilityDate: '2024-11-19', + srcDir: normalizePath(options.tsr.srcDirectory), + preset: buildPreset, + publicAssets: [ + { + dir: path.resolve(options.root, clientDistDir), + }, + ], + typescript: { + generateTsConfig: false, + }, + prerender: undefined, + renderer: options.serverEntryPath, + } + + return [ + devServerPlugin(options), + { + name: 'tanstack-vite-plugin-nitro', + async configEnvironment(name) { + nitro = await createNitro(nitroConfig) + + nitroRollupOptions = getRollupConfig(nitro) + + if (name === 'server') { + return { + build: { + commonjsOptions: { + include: [], + }, + ssr: true, + sourcemap: true, + rollupOptions: { + ...nitroRollupOptions, + output: { + ...nitroRollupOptions.output, + sourcemap: undefined, + }, + }, + }, + } satisfies EnvironmentOptions + } + + return null + }, + config() { + return { + builder: { + sharedPlugins: true, + async buildApp(builder) { + const clientEnv = builder.environments['client'] + const serverEnv = builder.environments['server'] + + if (!clientEnv) { + throw new Error('Client environment not found') + } + + if (!serverEnv) { + throw new Error('SSR environment not found') + } + + await builder.build(clientEnv) + await buildNitroEnvironment(nitro, () => builder.build(serverEnv)) + + if (options.prerender?.enabled) { + await prerender({ + options, + nitro, + builder, + }) + } + + // if (nitroConfig.prerender?.routes?.length && options.sitemap) { + // console.log('Building Sitemap...') + // // sitemap needs to be built after all directories are built + // await buildSitemap({ + // host: options.sitemap.host, + // routes: nitroConfig.prerender.routes, + // outputDir: resolve(options.root, 'dist/public'), + // }) + // } + + // console.log( + // `\n\n✅ Client and server bundles successfully built.`, + // ) + }, + }, + } + }, + // async buildStart() { + // await Promise.all( + // [ + // nitro.options.output.dir, + // nitro.options.output.serverDir, + // nitro.options.output.publicDir, + // ].map((dir) => { + // if (dir) { + // return promises.mkdir(dir, { + // recursive: true, + // }) + // } + // return + // }), + // ) + // }, + }, + ] +} diff --git a/packages/react-start-plugin/src/prerender.ts b/packages/react-start-plugin/src/prerender.ts new file mode 100644 index 0000000000..5af331ae9c --- /dev/null +++ b/packages/react-start-plugin/src/prerender.ts @@ -0,0 +1,243 @@ +import { promises as fsp } from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import { getRollupConfig } from 'nitropack/rollup' +import { createNitro } from 'nitropack' +import { joinURL, withBase, withoutBase } from 'ufo' +import { Queue, buildNitroEnvironment } from '@tanstack/start-plugin-core' +import type { Page} from '@tanstack/start-plugin-core'; +import type { ViteBuilder } from 'vite' +import type { $Fetch, Nitro } from 'nitropack' +import type { TanStackStartOutputConfig } from './schema.js' + +export async function prerender({ + options, + nitro, + builder, +}: { + options: TanStackStartOutputConfig + nitro: Nitro + builder: ViteBuilder +}) { + console.info('Prendering pages...') + + // If prerender is enabled but no pages are provided, default to prerendering the root page + if (options.prerender?.enabled && !options.pages.length) { + options.pages = [ + { + path: '/', + }, + ] + } + + const serverEnv = builder.environments['server'] + + if (!serverEnv) { + throw new Error(`Vite's "server" environment not found`) + } + + const prerenderOutputDir = path.resolve( + options.root, + 'node_modules/.tanstack-start/prerenderer', + ) + + const nodeNitro = await createNitro({ + ...nitro.options._config, + preset: 'nitro-prerender', + logLevel: 0, + output: { + dir: prerenderOutputDir, + serverDir: path.resolve(prerenderOutputDir, 'server'), + publicDir: path.resolve(prerenderOutputDir, 'public'), + }, + }) + + const nodeNitroRollupOptions = getRollupConfig(nodeNitro) + + const build = serverEnv.config.build + + build.outDir = prerenderOutputDir + + build.rollupOptions = { + ...build.rollupOptions, + ...nodeNitroRollupOptions, + output: { + ...build.rollupOptions.output, + ...nodeNitroRollupOptions.output, + sourcemap: undefined, + }, + } + + await buildNitroEnvironment(nodeNitro, () => builder.build(serverEnv)) + + // Import renderer entry + const serverFilename = + typeof nodeNitro.options.rollupConfig?.output.entryFileNames === 'string' + ? nodeNitro.options.rollupConfig.output.entryFileNames + : 'index.mjs' + + const serverEntrypoint = path.resolve( + nodeNitro.options.output.serverDir, + serverFilename, + ) + + const { closePrerenderer, localFetch } = (await import(serverEntrypoint)) as { + closePrerenderer: () => void + localFetch: $Fetch + } + + try { + // Crawl all pages + const pages = await prerenderPages() + + console.info(`Prerendered ${pages.length} pages:`) + pages.forEach((page) => { + console.info(`- ${page}`) + }) + + // TODO: Write the prerendered pages to the output directory + } catch (error) { + console.error(error) + } finally { + // Ensure server is always closed + // server.process.kill() + closePrerenderer() + } + + function extractLinks(html: string): Array { + const linkRegex = /]+href=["']([^"']+)["'][^>]*>/g + const links: Array = [] + let match + + while ((match = linkRegex.exec(html)) !== null) { + const href = match[1] + if (href && (href.startsWith('/') || href.startsWith('./'))) { + links.push(href) + } + } + + return links + } + + async function prerenderPages() { + const seen = new Set() + const retriesByPath = new Map() + const concurrency = options.prerender?.concurrency ?? os.cpus().length + console.info(`Concurrency: ${concurrency}`) + const queue = new Queue({ concurrency }) + + options.pages.forEach((_page) => { + let page = _page as Page + + if (typeof _page === 'string') { + page = { path: _page } + } + + addCrawlPageTask(page) + }) + + await queue.start() + + return Array.from(seen) + + function addCrawlPageTask(page: Page) { + // Was the page already seen? + if (seen.has(page.path)) return + + // Add the page to the seen set + seen.add(page.path) + + if (page.fromCrawl) { + options.pages.push(page) + } + + // If not enabled, skip + if (!(page.prerender?.enabled ?? true)) return + + // If there is a filter link, check if the page should be prerendered + if (options.prerender?.filter && !options.prerender.filter(page)) return + + // Resolve the merged default and page-specific prerender options + const prerenderOptions = { + ...options.prerender, + ...page.prerender, + } + + // Add the task + queue.add(async () => { + console.info(`Crawling: ${page.path}`) + const retries = retriesByPath.get(page.path) || 0 + try { + // Fetch the route + const encodedRoute = encodeURI(page.path) + + const res = await localFetch( + withBase(encodedRoute, nodeNitro.options.baseURL), + { + headers: { 'x-nitro-prerender': encodedRoute }, + }, + ) + + if (!res.ok) { + throw new Error(`Failed to fetch ${page.path}: ${res.statusText}`) + } + + // Guess route type and populate fileName + const contentType = res.headers.get('content-type') || '' + const isImplicitHTML = + !page.path.endsWith('.html') && contentType.includes('html') + // && + // !JsonSigRx.test(dataBuff.subarray(0, 32).toString('utf8')) + const routeWithIndex = page.path.endsWith('/') + ? page.path + 'index' + : page.path + + const htmlPath = + page.path.endsWith('/') || prerenderOptions.autoSubfolderIndex + ? joinURL(page.path, 'index.html') + : page.path + '.html' + + const filename = withoutBase( + isImplicitHTML ? htmlPath : routeWithIndex, + nitro.options.baseURL, + ) + + const html = await res.text() + + const filepath = path.join(nitro.options.output.publicDir, filename) + + await fsp.mkdir(path.dirname(filepath), { + recursive: true, + }) + + await fsp.writeFile(filepath, html) + + const newPage = await prerenderOptions.onSuccess?.({ page, html }) + + if (newPage) { + Object.assign(page, newPage) + } + + // Find new links + if (prerenderOptions.crawlLinks ?? true) { + const links = extractLinks(html) + for (const link of links) { + addCrawlPageTask({ path: link, fromCrawl: true }) + } + } + } catch (error) { + if (retries < (prerenderOptions.retryCount ?? 0)) { + console.warn(`Encountered error, retrying: ${page.path} in 500ms`) + await new Promise((resolve) => + setTimeout(resolve, prerenderOptions.retryDelay), + ) + retriesByPath.set(page.path, retries + 1) + addCrawlPageTask(page) + } else { + throw error + } + } + }) + } + } +} diff --git a/packages/react-start-plugin/src/routesManifestPlugin.ts b/packages/react-start-plugin/src/routesManifestPlugin.ts new file mode 100644 index 0000000000..f28dfcdb93 --- /dev/null +++ b/packages/react-start-plugin/src/routesManifestPlugin.ts @@ -0,0 +1,211 @@ +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { joinURL } from 'ufo' +import { rootRouteId } from '@tanstack/router-core' +import type { + PluginOption, + ResolvedConfig, + Manifest as ViteManifest, + ManifestChunk as ViteManifestChunk, +} from 'vite' +import type { Manifest, RouterManagedTag } from '@tanstack/router-core' +import type { TanStackStartOutputConfig } from './schema' + +export function startManifestPlugin( + opts: TanStackStartOutputConfig, +): PluginOption { + let config: ResolvedConfig + + return { + name: 'tsr-routes-manifest', + enforce: 'pre', + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + // configEnvironment(env, envConfig) { + // config = envConfig. + // }, + resolveId(id) { + if (id === 'tsr:start-manifest') { + return id + } + return + }, + load(id) { + if (id === 'tsr:start-manifest') { + // If we're in development, return a dummy manifest + + if (config.command === 'serve') { + return `export default () => ({ + entry: "$${process.env.TSS_CLIENT_BASE}/", + routes: {} + })` + } + + const clientViteManifestPath = path.resolve( + opts.root, + 'node_modules/.tanstack-start/client-dist/.vite/manifest.json', + ) + + let viteManifest: ViteManifest + try { + viteManifest = JSON.parse( + readFileSync(clientViteManifestPath, 'utf-8'), + ) + } catch (err) { + console.error(err) + throw new Error( + `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, + ) + } + + const routeTreePath = path.resolve(opts.tsr.generatedRouteTree) + + let routeTreeContent: string + try { + routeTreeContent = readFileSync(routeTreePath, 'utf-8') + } catch (err) { + console.error(err) + throw new Error( + `Could not find the generated route tree at '${routeTreePath}'!`, + ) + } + + // Extract the routesManifest JSON from the route tree file. + // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. + + const routerManifest = JSON.parse( + routeTreeContent.match( + /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, + )?.[1] || '{ routes: {} }', + ) as Manifest + + const routes = routerManifest.routes + + let entryFile: ViteManifestChunk | undefined + + const filesByRouteFilePath: ViteManifest = Object.fromEntries( + Object.entries(viteManifest).map(([k, v]) => { + if (v.isEntry) { + entryFile = v + } + + const rPath = k.split('?')[0] + + return [rPath, v] + }, {}), + ) + + const routesDirectoryFromRoot = path.relative( + opts.root, + opts.tsr.routesDirectory, + ) + + // Add preloads to the routes from the vite manifest + Object.entries(routes).forEach(([k, v]) => { + const file = + filesByRouteFilePath[ + path.join(routesDirectoryFromRoot, v.filePath as string) + ] + + if (file) { + const preloads = (file.imports ?? []).map((d) => + path.join('/', viteManifest[d]!.file), + ) + + if (file.file) { + preloads.unshift(path.join('/', file.file)) + } + + const cssFiles = file.css ?? [] + const cssAssetsList: Array = cssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[k] = { + ...v, + assets: [...(v.assets || []), ...cssAssetsList], + preloads, + } + } + }) + + if (entryFile) { + routes[rootRouteId]!.preloads = [ + path.join('/', entryFile.file), + ...(entryFile.imports?.map((d) => + path.join('/', viteManifest[d]!.file), + ) || []), + ] + + // Gather all the CSS files from the entry file in + // the `css` key and add them to the root route + const entryCssFiles = entryFile.css ?? [] + const entryCssAssetsList: Array = entryCssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[rootRouteId]!.assets = [ + ...(routes[rootRouteId]!.assets || []), + ...entryCssAssetsList, + { + tag: 'script', + attrs: { + src: joinURL('/', entryFile.file), + type: 'module', + }, + }, + ] + } + + const recurseRoute = ( + route: { + preloads?: Array + children?: Array + }, + seenPreloads = {} as Record, + ) => { + route.preloads = route.preloads?.filter((preload) => { + if (seenPreloads[preload]) { + return false + } + seenPreloads[preload] = true + return true + }) + + if (route.children) { + route.children.forEach((child) => { + const childRoute = routes[child]! + recurseRoute(childRoute, { ...seenPreloads }) + }) + } + } + + // @ts-expect-error + recurseRoute(routes[rootRouteId]) + + const routesManifest = { + routes, + } + + return `export default () => (${JSON.stringify(routesManifest)})` + } + return + }, + } +} diff --git a/packages/react-start-plugin/src/schema.ts b/packages/react-start-plugin/src/schema.ts new file mode 100644 index 0000000000..a49842f177 --- /dev/null +++ b/packages/react-start-plugin/src/schema.ts @@ -0,0 +1,28 @@ +import { z } from 'zod' +import { createTanStackConfig, createTanStackStartOptionsSchema } from '@tanstack/start-plugin-core' +import type { Options as ViteReactOptions } from '@vitejs/plugin-react' + +export type WithReactPlugin = { + react?: ViteReactOptions +} + +const frameworkPlugin = { + react: z.custom().optional() +} + +// eslint-disable-next-line unused-imports/no-unused-vars +const TanStackStartOptionsSchema = createTanStackStartOptionsSchema(frameworkPlugin) + +const defaultConfig = createTanStackConfig(frameworkPlugin) + +export function getTanStackStartOptions(opts?: TanStackStartInputConfig) { + return defaultConfig.parse(opts) +} + +export type TanStackStartInputConfig = z.input< + typeof TanStackStartOptionsSchema +> +export type TanStackStartOutputConfig = ReturnType< + typeof getTanStackStartOptions +> + diff --git a/packages/react-start-plugin/src/start-compiler-plugin.ts b/packages/react-start-plugin/src/start-compiler-plugin.ts new file mode 100644 index 0000000000..da9122d75b --- /dev/null +++ b/packages/react-start-plugin/src/start-compiler-plugin.ts @@ -0,0 +1,117 @@ +import { fileURLToPath, pathToFileURL } from 'node:url' +import { logDiff } from '@tanstack/router-utils' +import { compileStartOutput } from './compilers' + +import type { Plugin } from 'vite' + +const debug = + process.env.TSR_VITE_DEBUG && + ['true', 'start-plugin'].includes(process.env.TSR_VITE_DEBUG) + +export type TanStackStartViteOptions = { + globalMiddlewareEntry: string +} + +const transformFuncs = [ + 'createServerFn', + 'createMiddleware', + 'serverOnly', + 'clientOnly', + 'createIsomorphicFn', + 'createServerFileRoute', +] + +const tokenRegex = new RegExp(transformFuncs.join('|')) + +export function TanStackStartCompilerPlugin(opts?: { + client?: { + envName?: string + } + server?: { + envName?: string + } +}): Plugin { + opts = { + client: { + envName: 'client', + ...opts?.client, + }, + server: { + envName: 'server', + ...opts?.server, + }, + } + + return { + name: 'vite-plugin-tanstack-start-create-server-fn', + enforce: 'pre', + applyToEnvironment(env) { + return [opts.client?.envName, opts.server?.envName].includes(env.name) + }, + transform(code, id) { + const env = + this.environment.name === opts.client?.envName + ? 'client' + : this.environment.name === opts.server?.envName + ? 'server' + : (() => { + throw new Error( + `Environment ${this.environment.name} not configured`, + ) + })() + + return transformCode({ + code, + id, + env, + }) + }, + } +} + +function transformCode(opts: { + code: string + id: string + env: 'server' | 'client' +}) { + const { code, env } = opts + let { id } = opts + + const url = pathToFileURL(id) + url.searchParams.delete('v') + id = fileURLToPath(url).replace(/\\/g, '/') + + const includesToken = tokenRegex.test(code) + + if (!includesToken) { + return null + } + + if (code.includes('@react-refresh')) { + throw new Error( + `We detected that the '@vitejs/plugin-react' was passed before '@tanstack/start-plugin'. Please make sure that '@tanstack/router-vite-plugin' is passed before '@vitejs/plugin-react' and try again: + e.g. + + plugins: [ + TanStackStartVite(), // Place this before viteReact() + viteReact(), + ] + `, + ) + } + + if (debug) console.info(`${env} Compiling Start: `, id) + + const compiled = compileStartOutput({ + code, + filename: id, + env, + }) + + if (debug) { + logDiff(code, compiled.code) + console.log('Output:\n', compiled.code + '\n\n') + } + + return compiled +} diff --git a/packages/react-start-plugin/tsconfig.json b/packages/react-start-plugin/tsconfig.json index 37d21ef6ca..6c8c904b07 100644 --- a/packages/react-start-plugin/tsconfig.json +++ b/packages/react-start-plugin/tsconfig.json @@ -3,6 +3,9 @@ "include": ["src", "vite.config.ts", "tests"], "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { - "jsx": "react-jsx" + "rootDir": "src", + "outDir": "dist/esm", + "target": "esnext", + "noEmit": false } } diff --git a/packages/react-start-plugin/vite.config.ts b/packages/react-start-plugin/vite.config.ts index 5389f0f739..2c711fd181 100644 --- a/packages/react-start-plugin/vite.config.ts +++ b/packages/react-start-plugin/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', + outDir: './dist', }), ) diff --git a/packages/react-start-router-manifest/README.md b/packages/react-start-router-manifest/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/react-start-router-manifest/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/react-start-router-manifest/eslint.config.js b/packages/react-start-router-manifest/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/react-start-router-manifest/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/react-start-router-manifest/package.json b/packages/react-start-router-manifest/package.json deleted file mode 100644 index 6f1e283e78..0000000000 --- a/packages/react-start-router-manifest/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@tanstack/react-start-router-manifest", - "version": "1.115.0", - "description": "Modern and scalable routing for React applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/react-start-router-manifest" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "react", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "tsc" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/react-start-router-manifest/src/index.ts b/packages/react-start-router-manifest/src/index.ts deleted file mode 100644 index 3f0a37f609..0000000000 --- a/packages/react-start-router-manifest/src/index.ts +++ /dev/null @@ -1,88 +0,0 @@ -// @ts-expect-error -import tsrGetManifest from 'tsr:routes-manifest' -import { getManifest } from 'vinxi/manifest' -import { default as invariant } from 'tiny-invariant' -import type { Manifest } from '@tanstack/router-core' - -function sanitizeBase(base: string) { - return base.replace(/^\/|\/$/g, '') -} - -/** - * @description Returns the full, unfiltered router manifest. This includes relationships - * between routes, assets, and preloads and is NOT what you want to serialize and - * send to the client. - */ -export function getFullRouterManifest() { - const routerManifest = tsrGetManifest() as Manifest - - const rootRoute = (routerManifest.routes.__root__ = - routerManifest.routes.__root__ || {}) - - rootRoute.assets = rootRoute.assets || [] - - let script = '' - // Always fake that HMR is ready - if (process.env.NODE_ENV === 'development') { - const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') - - if (!CLIENT_BASE) { - throw new Error( - 'tanstack/start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', - ) - } - script = `import RefreshRuntime from "/${CLIENT_BASE}/@react-refresh"; - RefreshRuntime.injectIntoGlobalHook(window) - window.$RefreshReg$ = () => {} - window.$RefreshSig$ = () => (type) => type - window.__vite_plugin_react_preamble_installed__ = true;` - } - - // Get the entry for the client from vinxi - const vinxiClientManifest = getManifest('client') - - const importPath = - vinxiClientManifest.inputs[vinxiClientManifest.handler]?.output.path - if (!importPath) { - invariant(importPath, 'Could not find client entry in vinxi manifest') - } - - rootRoute.assets.push({ - tag: 'script', - attrs: { - type: 'module', - suppressHydrationWarning: true, - async: true, - }, - children: `${script}import("${importPath}")`, - }) - - return routerManifest -} - -/** - * @description Returns the router manifest that should be sent to the client. - * This includes only the assets and preloads for the current route and any - * special assets that are needed for the client. It does not include relationships - * between routes or any other data that is not needed for the client. - */ -export function getRouterManifest() { - const routerManifest = getFullRouterManifest() - - // Strip out anything that isn't needed for the client - return { - ...routerManifest, - routes: Object.fromEntries( - Object.entries(routerManifest.routes).map(([k, v]: any) => { - const { preloads, assets } = v - return [ - k, - { - preloads, - assets, - }, - ] - }), - ), - } -} diff --git a/packages/react-start-router-manifest/tsconfig.json b/packages/react-start-router-manifest/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/react-start-router-manifest/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/react-start-router-manifest/vite.config.ts b/packages/react-start-router-manifest/vite.config.ts deleted file mode 100644 index d6472068fb..0000000000 --- a/packages/react-start-router-manifest/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - externalDeps: ['tsr:routes-manifest'], - }), -) diff --git a/packages/react-start-server/package.json b/packages/react-start-server/package.json index af582f9d2e..448f38785a 100644 --- a/packages/react-start-server/package.json +++ b/packages/react-start-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start-server", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { @@ -68,6 +54,7 @@ "@tanstack/start-client-core": "workspace:^", "@tanstack/start-server-core": "workspace:^", "tiny-warning": "^1.0.3", + "tiny-invariant": "^1.3.3", "h3": "1.13.0", "isbot": "^5.1.22", "jsesc": "^3.1.0", diff --git a/packages/react-start-server/tsconfig.json b/packages/react-start-server/tsconfig.json index 134e51f065..b447592593 100644 --- a/packages/react-start-server/tsconfig.json +++ b/packages/react-start-server/tsconfig.json @@ -8,6 +8,6 @@ "src", "tests", "vite.config.ts", - "../start-client/src/tsrScript.ts" + "../start-server-core/src/server-functions-handler.ts" ] } diff --git a/packages/react-start-server/vite.config.ts b/packages/react-start-server/vite.config.ts index e05e5cc394..983ae16f57 100644 --- a/packages/react-start-server/vite.config.ts +++ b/packages/react-start-server/vite.config.ts @@ -19,5 +19,6 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: ['tsr:server-fn-manifest', 'tsr:start-manifest'], }), ) diff --git a/packages/react-start/package.json b/packages/react-start/package.json index e26ac09206..06628b4abe 100644 --- a/packages/react-start/package.json +++ b/packages/react-start/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-start", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,12 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:build", - "test:build": "exit 0; vitest", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/client.d.ts", "exports": { @@ -62,14 +57,14 @@ "default": "./dist/cjs/server.cjs" } }, - "./config": { + "./plugin": { "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" + "types": "./dist/esm/plugin.d.ts", + "default": "./dist/esm/plugin.js" }, "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" + "types": "./dist/cjs/plugin.d.cts", + "default": "./dist/cjs/plugin.cjs" } }, "./api": { @@ -82,16 +77,6 @@ "default": "./dist/cjs/api.cjs" } }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" - } - }, "./server-functions-client": { "import": { "types": "./dist/esm/server-functions-client.d.ts", @@ -112,16 +97,6 @@ "default": "./dist/cjs/server-functions-server.cjs" } }, - "./server-functions-handler": { - "import": { - "types": "./dist/esm/server-functions-handler.d.ts", - "default": "./dist/esm/server-functions-handler.js" - }, - "require": { - "types": "./dist/cjs/server-functions-handler.d.cts", - "default": "./dist/cjs/server-functions-handler.cjs" - } - }, "./server-functions-ssr": { "import": { "types": "./dist/esm/server-functions-ssr.d.ts", @@ -145,11 +120,9 @@ "dependencies": { "@tanstack/react-start-client": "workspace:^", "@tanstack/react-start-server": "workspace:^", - "@tanstack/react-start-config": "workspace:^", - "@tanstack/react-start-router-manifest": "workspace:^", + "@tanstack/react-start-plugin": "workspace:^", "@tanstack/start-server-functions-client": "workspace:^", "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", "@tanstack/start-server-functions-ssr": "workspace:^", "@tanstack/start-api-routes": "workspace:^" }, diff --git a/packages/react-start/src/config.tsx b/packages/react-start/src/config.tsx deleted file mode 100644 index 57a7ae394d..0000000000 --- a/packages/react-start/src/config.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/react-start-config' diff --git a/packages/react-start/src/plugin.ts b/packages/react-start/src/plugin.ts new file mode 100644 index 0000000000..d991c3b71c --- /dev/null +++ b/packages/react-start/src/plugin.ts @@ -0,0 +1 @@ +export * from '@tanstack/react-start-plugin' diff --git a/packages/react-start/src/router-manifest.tsx b/packages/react-start/src/router-manifest.tsx deleted file mode 100644 index ce430d7884..0000000000 --- a/packages/react-start/src/router-manifest.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/react-start-router-manifest' diff --git a/packages/react-start/src/server-functions-handler.tsx b/packages/react-start/src/server-functions-handler.tsx deleted file mode 100644 index c3cc9770d2..0000000000 --- a/packages/react-start/src/server-functions-handler.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/react-start/vite.config.ts b/packages/react-start/vite.config.ts index 46bc2ea875..36c303fb37 100644 --- a/packages/react-start/vite.config.ts +++ b/packages/react-start/vite.config.ts @@ -17,8 +17,7 @@ export default mergeConfig( entry: [ './src/client.tsx', './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', + './src/plugin.ts', './src/server-functions-client.tsx', './src/server-functions-server.tsx', './src/server-functions-ssr.tsx', @@ -27,8 +26,7 @@ export default mergeConfig( externalDeps: [ '@tanstack/react-start-client', '@tanstack/react-start-server', - '@tanstack/react-start-config', - '@tanstack/react-start-router-manifest', + '@tanstack/react-start-plugin', '@tanstack/start-server-functions-client', '@tanstack/start-server-functions-server', '@tanstack/start-server-functions-ssr', diff --git a/packages/router-cli/package.json b/packages/router-cli/package.json index 59e23bed71..05e70b0678 100644 --- a/packages/router-cli/package.json +++ b/packages/router-cli/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-cli", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,19 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/router-core/package.json b/packages/router-core/package.json index 940b885ba5..826544bafa 100644 --- a/packages/router-core/package.json +++ b/packages/router-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/router-core", - "version": "1.115.0", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -18,21 +18,7 @@ "history", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/router-core/src/dev-html.ts b/packages/router-core/src/dev-html.ts new file mode 100644 index 0000000000..ab6db327c1 --- /dev/null +++ b/packages/router-core/src/dev-html.ts @@ -0,0 +1,151 @@ +export interface ExtractedHtmlTagInfo { + attributes: Record + content: string +} + +/** + * Extracts specified HTML tags from content along with their attributes and inner content + * @internal + * @param tagName - Name of the HTML tag to extract (e.g., 'script', 'meta', 'div') + * @param htmlContent - String containing HTML content + * @returns Array of objects with tag attributes and content + */ +function extractHtmlTagInfo( + tagName: string, + htmlContent: string, +): Array { + const tags: Array = [] + // Create a regex pattern based on the provided tag name + // This regex will match both self-closing tags and tags with content + const tagRegex = new RegExp( + `<${tagName}\\b([^>]*?)(?:>([\\s\\S]*?)|\\s*/?>)`, + 'gi', + ) + + let match + while ((match = tagRegex.exec(htmlContent)) !== null) { + const attributesString = match[1] || '' + // For self-closing tags or tags with no content, this will be undefined + const content = match[2] || '' + + // Parse attributes + const attributes: Record = {} + const attributeRegex = /(\w+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s>]*))?)?/g + let attrMatch + + while ((attrMatch = attributeRegex.exec(attributesString)) !== null) { + const attrName = attrMatch[1] + if (!attrName) { + continue + } + + // Check if this is a valueless attribute (no value or empty string) + if ( + attrMatch[2] === undefined && + attrMatch[3] === undefined && + attrMatch[4] === undefined + ) { + // Valueless attribute with no value, like + + + + + `, + { + status: 500, + headers: { + 'Content-Type': 'text/html', + }, + }, + ), + ) + } + }) + } + }, + } +} + +/** + * Removes Vite internal middleware + * + * @param server + */ +function remove_html_middlewares(server: ViteDevServer['middlewares']) { + const html_middlewares = [ + 'viteIndexHtmlMiddleware', + 'vite404Middleware', + 'viteSpaFallbackMiddleware', + ] + for (let i = server.stack.length - 1; i > 0; i--) { + if ( + html_middlewares.includes( + // @ts-expect-error + server.stack[i].handle.name, + ) + ) { + server.stack.splice(i, 1) + } + } +} + +/** + * Formats error for SSR message in error overlay + * @param req + * @param error + * @returns + */ +function prepareError(req: Connect.IncomingMessage, error: unknown) { + const e = error as Error + return { + message: `An error occured while server rendering ${req.url}:\n\n\t${ + typeof e === 'string' ? e : e.message + } `, + stack: typeof e === 'string' ? '' : e.stack, + } +} diff --git a/packages/solid-start-plugin/src/nitro/nitro-plugin.ts b/packages/solid-start-plugin/src/nitro/nitro-plugin.ts new file mode 100644 index 0000000000..1765022715 --- /dev/null +++ b/packages/solid-start-plugin/src/nitro/nitro-plugin.ts @@ -0,0 +1,141 @@ +import { platform } from 'node:os' +import path from 'node:path' +import { createNitro } from 'nitropack' +import { normalizePath } from 'vite' + +import { getRollupConfig } from 'nitropack/rollup' +import { buildNitroEnvironment } from '@tanstack/start-plugin-core' +import { clientDistDir } from '../index.js' +import { prerender } from '../prerender.js' +import { devServerPlugin } from './dev-server-plugin.js' +import type { EnvironmentOptions, PluginOption } from 'vite' +import type { Nitro, NitroConfig } from 'nitropack' +import type { TanStackStartOutputConfig } from '../schema.js' + +export type { + TanStackStartInputConfig, + TanStackStartOutputConfig, +} from '../schema.js' + +const isWindows = platform() === 'win32' +const filePrefix = isWindows ? 'file:///' : '' + +export function nitroPlugin( + options: TanStackStartOutputConfig, +): Array { + let nitro: Nitro + let nitroRollupOptions: ReturnType + + const buildPreset = + process.env['START_TARGET'] ?? (options.target as string | undefined) + + const nitroConfig: NitroConfig = { + dev: false, + compatibilityDate: '2024-11-19', + srcDir: normalizePath(options.tsr.srcDirectory), + preset: buildPreset, + publicAssets: [ + { + dir: path.resolve(options.root, clientDistDir), + }, + ], + typescript: { + generateTsConfig: false, + }, + prerender: undefined, + renderer: options.serverEntryPath, + } + + return [ + devServerPlugin(options), + { + name: 'tanstack-vite-plugin-nitro', + async configEnvironment(name) { + nitro = await createNitro(nitroConfig) + + nitroRollupOptions = getRollupConfig(nitro) + + if (name === 'server') { + return { + build: { + commonjsOptions: { + include: [], + }, + ssr: true, + sourcemap: true, + rollupOptions: { + ...nitroRollupOptions, + output: { + ...nitroRollupOptions.output, + sourcemap: undefined, + }, + }, + }, + } satisfies EnvironmentOptions + } + + return null + }, + config() { + return { + builder: { + sharedPlugins: true, + async buildApp(builder) { + const clientEnv = builder.environments['client'] + const serverEnv = builder.environments['server'] + + if (!clientEnv) { + throw new Error('Client environment not found') + } + + if (!serverEnv) { + throw new Error('SSR environment not found') + } + + await builder.build(clientEnv) + await buildNitroEnvironment(nitro, () => builder.build(serverEnv)) + + if (options.prerender?.enabled) { + await prerender({ + options, + nitro, + builder, + }) + } + + // if (nitroConfig.prerender?.routes?.length && options.sitemap) { + // console.log('Building Sitemap...') + // // sitemap needs to be built after all directories are built + // await buildSitemap({ + // host: options.sitemap.host, + // routes: nitroConfig.prerender.routes, + // outputDir: resolve(options.root, 'dist/public'), + // }) + // } + + // console.log( + // `\n\n✅ Client and server bundles successfully built.`, + // ) + }, + }, + } + }, + // async buildStart() { + // await Promise.all( + // [ + // nitro.options.output.dir, + // nitro.options.output.serverDir, + // nitro.options.output.publicDir, + // ].map((dir) => { + // if (dir) { + // return promises.mkdir(dir, { + // recursive: true, + // }) + // } + // return + // }), + // ) + // }, + }, + ] +} diff --git a/packages/solid-start-plugin/src/prerender.ts b/packages/solid-start-plugin/src/prerender.ts new file mode 100644 index 0000000000..5af331ae9c --- /dev/null +++ b/packages/solid-start-plugin/src/prerender.ts @@ -0,0 +1,243 @@ +import { promises as fsp } from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import { getRollupConfig } from 'nitropack/rollup' +import { createNitro } from 'nitropack' +import { joinURL, withBase, withoutBase } from 'ufo' +import { Queue, buildNitroEnvironment } from '@tanstack/start-plugin-core' +import type { Page} from '@tanstack/start-plugin-core'; +import type { ViteBuilder } from 'vite' +import type { $Fetch, Nitro } from 'nitropack' +import type { TanStackStartOutputConfig } from './schema.js' + +export async function prerender({ + options, + nitro, + builder, +}: { + options: TanStackStartOutputConfig + nitro: Nitro + builder: ViteBuilder +}) { + console.info('Prendering pages...') + + // If prerender is enabled but no pages are provided, default to prerendering the root page + if (options.prerender?.enabled && !options.pages.length) { + options.pages = [ + { + path: '/', + }, + ] + } + + const serverEnv = builder.environments['server'] + + if (!serverEnv) { + throw new Error(`Vite's "server" environment not found`) + } + + const prerenderOutputDir = path.resolve( + options.root, + 'node_modules/.tanstack-start/prerenderer', + ) + + const nodeNitro = await createNitro({ + ...nitro.options._config, + preset: 'nitro-prerender', + logLevel: 0, + output: { + dir: prerenderOutputDir, + serverDir: path.resolve(prerenderOutputDir, 'server'), + publicDir: path.resolve(prerenderOutputDir, 'public'), + }, + }) + + const nodeNitroRollupOptions = getRollupConfig(nodeNitro) + + const build = serverEnv.config.build + + build.outDir = prerenderOutputDir + + build.rollupOptions = { + ...build.rollupOptions, + ...nodeNitroRollupOptions, + output: { + ...build.rollupOptions.output, + ...nodeNitroRollupOptions.output, + sourcemap: undefined, + }, + } + + await buildNitroEnvironment(nodeNitro, () => builder.build(serverEnv)) + + // Import renderer entry + const serverFilename = + typeof nodeNitro.options.rollupConfig?.output.entryFileNames === 'string' + ? nodeNitro.options.rollupConfig.output.entryFileNames + : 'index.mjs' + + const serverEntrypoint = path.resolve( + nodeNitro.options.output.serverDir, + serverFilename, + ) + + const { closePrerenderer, localFetch } = (await import(serverEntrypoint)) as { + closePrerenderer: () => void + localFetch: $Fetch + } + + try { + // Crawl all pages + const pages = await prerenderPages() + + console.info(`Prerendered ${pages.length} pages:`) + pages.forEach((page) => { + console.info(`- ${page}`) + }) + + // TODO: Write the prerendered pages to the output directory + } catch (error) { + console.error(error) + } finally { + // Ensure server is always closed + // server.process.kill() + closePrerenderer() + } + + function extractLinks(html: string): Array { + const linkRegex = /]+href=["']([^"']+)["'][^>]*>/g + const links: Array = [] + let match + + while ((match = linkRegex.exec(html)) !== null) { + const href = match[1] + if (href && (href.startsWith('/') || href.startsWith('./'))) { + links.push(href) + } + } + + return links + } + + async function prerenderPages() { + const seen = new Set() + const retriesByPath = new Map() + const concurrency = options.prerender?.concurrency ?? os.cpus().length + console.info(`Concurrency: ${concurrency}`) + const queue = new Queue({ concurrency }) + + options.pages.forEach((_page) => { + let page = _page as Page + + if (typeof _page === 'string') { + page = { path: _page } + } + + addCrawlPageTask(page) + }) + + await queue.start() + + return Array.from(seen) + + function addCrawlPageTask(page: Page) { + // Was the page already seen? + if (seen.has(page.path)) return + + // Add the page to the seen set + seen.add(page.path) + + if (page.fromCrawl) { + options.pages.push(page) + } + + // If not enabled, skip + if (!(page.prerender?.enabled ?? true)) return + + // If there is a filter link, check if the page should be prerendered + if (options.prerender?.filter && !options.prerender.filter(page)) return + + // Resolve the merged default and page-specific prerender options + const prerenderOptions = { + ...options.prerender, + ...page.prerender, + } + + // Add the task + queue.add(async () => { + console.info(`Crawling: ${page.path}`) + const retries = retriesByPath.get(page.path) || 0 + try { + // Fetch the route + const encodedRoute = encodeURI(page.path) + + const res = await localFetch( + withBase(encodedRoute, nodeNitro.options.baseURL), + { + headers: { 'x-nitro-prerender': encodedRoute }, + }, + ) + + if (!res.ok) { + throw new Error(`Failed to fetch ${page.path}: ${res.statusText}`) + } + + // Guess route type and populate fileName + const contentType = res.headers.get('content-type') || '' + const isImplicitHTML = + !page.path.endsWith('.html') && contentType.includes('html') + // && + // !JsonSigRx.test(dataBuff.subarray(0, 32).toString('utf8')) + const routeWithIndex = page.path.endsWith('/') + ? page.path + 'index' + : page.path + + const htmlPath = + page.path.endsWith('/') || prerenderOptions.autoSubfolderIndex + ? joinURL(page.path, 'index.html') + : page.path + '.html' + + const filename = withoutBase( + isImplicitHTML ? htmlPath : routeWithIndex, + nitro.options.baseURL, + ) + + const html = await res.text() + + const filepath = path.join(nitro.options.output.publicDir, filename) + + await fsp.mkdir(path.dirname(filepath), { + recursive: true, + }) + + await fsp.writeFile(filepath, html) + + const newPage = await prerenderOptions.onSuccess?.({ page, html }) + + if (newPage) { + Object.assign(page, newPage) + } + + // Find new links + if (prerenderOptions.crawlLinks ?? true) { + const links = extractLinks(html) + for (const link of links) { + addCrawlPageTask({ path: link, fromCrawl: true }) + } + } + } catch (error) { + if (retries < (prerenderOptions.retryCount ?? 0)) { + console.warn(`Encountered error, retrying: ${page.path} in 500ms`) + await new Promise((resolve) => + setTimeout(resolve, prerenderOptions.retryDelay), + ) + retriesByPath.set(page.path, retries + 1) + addCrawlPageTask(page) + } else { + throw error + } + } + }) + } + } +} diff --git a/packages/solid-start-plugin/src/routesManifestPlugin.ts b/packages/solid-start-plugin/src/routesManifestPlugin.ts new file mode 100644 index 0000000000..f28dfcdb93 --- /dev/null +++ b/packages/solid-start-plugin/src/routesManifestPlugin.ts @@ -0,0 +1,211 @@ +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { joinURL } from 'ufo' +import { rootRouteId } from '@tanstack/router-core' +import type { + PluginOption, + ResolvedConfig, + Manifest as ViteManifest, + ManifestChunk as ViteManifestChunk, +} from 'vite' +import type { Manifest, RouterManagedTag } from '@tanstack/router-core' +import type { TanStackStartOutputConfig } from './schema' + +export function startManifestPlugin( + opts: TanStackStartOutputConfig, +): PluginOption { + let config: ResolvedConfig + + return { + name: 'tsr-routes-manifest', + enforce: 'pre', + + configResolved(resolvedConfig) { + config = resolvedConfig + }, + // configEnvironment(env, envConfig) { + // config = envConfig. + // }, + resolveId(id) { + if (id === 'tsr:start-manifest') { + return id + } + return + }, + load(id) { + if (id === 'tsr:start-manifest') { + // If we're in development, return a dummy manifest + + if (config.command === 'serve') { + return `export default () => ({ + entry: "$${process.env.TSS_CLIENT_BASE}/", + routes: {} + })` + } + + const clientViteManifestPath = path.resolve( + opts.root, + 'node_modules/.tanstack-start/client-dist/.vite/manifest.json', + ) + + let viteManifest: ViteManifest + try { + viteManifest = JSON.parse( + readFileSync(clientViteManifestPath, 'utf-8'), + ) + } catch (err) { + console.error(err) + throw new Error( + `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, + ) + } + + const routeTreePath = path.resolve(opts.tsr.generatedRouteTree) + + let routeTreeContent: string + try { + routeTreeContent = readFileSync(routeTreePath, 'utf-8') + } catch (err) { + console.error(err) + throw new Error( + `Could not find the generated route tree at '${routeTreePath}'!`, + ) + } + + // Extract the routesManifest JSON from the route tree file. + // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. + + const routerManifest = JSON.parse( + routeTreeContent.match( + /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, + )?.[1] || '{ routes: {} }', + ) as Manifest + + const routes = routerManifest.routes + + let entryFile: ViteManifestChunk | undefined + + const filesByRouteFilePath: ViteManifest = Object.fromEntries( + Object.entries(viteManifest).map(([k, v]) => { + if (v.isEntry) { + entryFile = v + } + + const rPath = k.split('?')[0] + + return [rPath, v] + }, {}), + ) + + const routesDirectoryFromRoot = path.relative( + opts.root, + opts.tsr.routesDirectory, + ) + + // Add preloads to the routes from the vite manifest + Object.entries(routes).forEach(([k, v]) => { + const file = + filesByRouteFilePath[ + path.join(routesDirectoryFromRoot, v.filePath as string) + ] + + if (file) { + const preloads = (file.imports ?? []).map((d) => + path.join('/', viteManifest[d]!.file), + ) + + if (file.file) { + preloads.unshift(path.join('/', file.file)) + } + + const cssFiles = file.css ?? [] + const cssAssetsList: Array = cssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[k] = { + ...v, + assets: [...(v.assets || []), ...cssAssetsList], + preloads, + } + } + }) + + if (entryFile) { + routes[rootRouteId]!.preloads = [ + path.join('/', entryFile.file), + ...(entryFile.imports?.map((d) => + path.join('/', viteManifest[d]!.file), + ) || []), + ] + + // Gather all the CSS files from the entry file in + // the `css` key and add them to the root route + const entryCssFiles = entryFile.css ?? [] + const entryCssAssetsList: Array = entryCssFiles.map( + (cssFile) => ({ + tag: 'link', + attrs: { + rel: 'stylesheet', + href: joinURL('/', cssFile), + type: 'text/css', + }, + }), + ) + + routes[rootRouteId]!.assets = [ + ...(routes[rootRouteId]!.assets || []), + ...entryCssAssetsList, + { + tag: 'script', + attrs: { + src: joinURL('/', entryFile.file), + type: 'module', + }, + }, + ] + } + + const recurseRoute = ( + route: { + preloads?: Array + children?: Array + }, + seenPreloads = {} as Record, + ) => { + route.preloads = route.preloads?.filter((preload) => { + if (seenPreloads[preload]) { + return false + } + seenPreloads[preload] = true + return true + }) + + if (route.children) { + route.children.forEach((child) => { + const childRoute = routes[child]! + recurseRoute(childRoute, { ...seenPreloads }) + }) + } + } + + // @ts-expect-error + recurseRoute(routes[rootRouteId]) + + const routesManifest = { + routes, + } + + return `export default () => (${JSON.stringify(routesManifest)})` + } + return + }, + } +} diff --git a/packages/solid-start-plugin/src/schema.ts b/packages/solid-start-plugin/src/schema.ts new file mode 100644 index 0000000000..4cc6394c54 --- /dev/null +++ b/packages/solid-start-plugin/src/schema.ts @@ -0,0 +1,28 @@ +import { z } from 'zod' +import { createTanStackConfig, createTanStackStartOptionsSchema } from '@tanstack/start-plugin-core' +import type { Options as ViteSolidOptions } from 'vite-plugin-solid' + +export type WithSolidPlugin = { + solid?: ViteSolidOptions +} + +const frameworkPlugin = { + solid: z.custom().optional() +} + +// eslint-disable-next-line unused-imports/no-unused-vars +const TanStackStartOptionsSchema = createTanStackStartOptionsSchema(frameworkPlugin) + +const defaultConfig = createTanStackConfig(frameworkPlugin) + +export function getTanStackStartOptions(opts?: TanStackStartInputConfig) { + return defaultConfig.parse(opts) +} + +export type TanStackStartInputConfig = z.input< + typeof TanStackStartOptionsSchema +> +export type TanStackStartOutputConfig = ReturnType< + typeof getTanStackStartOptions +> + diff --git a/packages/solid-start-plugin/src/start-compiler-plugin.ts b/packages/solid-start-plugin/src/start-compiler-plugin.ts new file mode 100644 index 0000000000..b2425cadde --- /dev/null +++ b/packages/solid-start-plugin/src/start-compiler-plugin.ts @@ -0,0 +1,104 @@ +import { fileURLToPath, pathToFileURL } from 'node:url' +import { logDiff } from '@tanstack/router-utils' +import { compileStartOutput } from './compilers' + +import type { Plugin } from 'vite' + +const debug = + process.env.TSR_VITE_DEBUG && + ['true', 'start-plugin'].includes(process.env.TSR_VITE_DEBUG) + +export type TanStackStartViteOptions = { + globalMiddlewareEntry: string +} + +const transformFuncs = [ + 'createServerFn', + 'createMiddleware', + 'serverOnly', + 'clientOnly', + 'createIsomorphicFn', + 'createServerFileRoute', +] + +const tokenRegex = new RegExp(transformFuncs.join('|')) + +export function TanStackStartCompilerPlugin(opts?: { + client?: { + envName?: string + } + server?: { + envName?: string + } +}): Plugin { + opts = { + client: { + envName: 'client', + ...opts?.client, + }, + server: { + envName: 'server', + ...opts?.server, + }, + } + + return { + name: 'vite-plugin-tanstack-start-create-server-fn', + enforce: 'pre', + applyToEnvironment(env) { + return [opts.client?.envName, opts.server?.envName].includes(env.name) + }, + transform(code, id) { + const env = + this.environment.name === opts.client?.envName + ? 'client' + : this.environment.name === opts.server?.envName + ? 'server' + : (() => { + throw new Error( + `Environment ${this.environment.name} not configured`, + ) + })() + + return transformCode({ + code, + id, + env, + }) + }, + } +} + +function transformCode(opts: { + code: string + id: string + env: 'server' | 'client' +}) { + const { code, env } = opts + let { id } = opts + + const url = pathToFileURL(id) + url.searchParams.delete('v') + id = fileURLToPath(url).replace(/\\/g, '/') + + const includesToken = tokenRegex.test(code) + + if (!includesToken) { + return null + } + + if (debug) console.info(`${env} Compiling Start: `, id) + + const compiled = compileStartOutput({ + code, + filename: id, + env, + }) + + if (debug) { + logDiff(code, compiled.code) + console.log('Output:\n', compiled.code + '\n\n') + } + + return compiled +} diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts b/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts deleted file mode 100644 index 9d1e78228e..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { afterAll, describe, expect, test, vi } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('createIsomorphicFn compiles correctly', async () => { - const noImplWarning = - 'createIsomorphicFn called without a client or server implementation!' - - const originalConsoleWarn = console.warn - const consoleSpy = vi.spyOn(console, 'warn').mockImplementation((...args) => { - // we want to avoid sending this warning to the console, we know about it - if (args[0] === noImplWarning) { - return - } - originalConsoleWarn(...args) - }) - - afterAll(() => { - consoleSpy.mockRestore() - }) - - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - test('should error if implementation not provided', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const clientOnly = createIsomorphicFn().client()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - expect(() => { - compileStartOutput({ - env: 'server', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const serverOnly = createIsomorphicFn().server()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - test('should warn to console if no implementations provided', () => { - compileStartOutput({ - env: 'client', - code: ` - import { createIsomorphicFn } from '@tanstack/solid-start' - const noImpl = createIsomorphicFn()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - expect(consoleSpy).toHaveBeenCalledWith( - noImplWarning, - 'This will result in a no-op function.', - 'Variable name:', - 'noImpl', - ) - }) -}) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 269cab1607..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 3c5c041e90..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 5b90ddeaf1..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => {}; -const clientOnlyFn = () => 'client'; -const serverThenClientFn = () => 'client'; -const clientThenServerFn = () => 'client'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = () => {}; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = abstractedClientFn; -const serverThenClientFnAbstracted = abstractedClientFn; -const clientThenServerFnAbstracted = abstractedClientFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 126e2404c5..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 442156f4e3..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 318745b993..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -const noImpl = () => {}; -const serverOnlyFn = () => 'server'; -const clientOnlyFn = () => {}; -const serverThenClientFn = () => 'server'; -const clientThenServerFn = () => 'server'; -function abstractedServerFn() { - return 'server'; -} -const serverOnlyFnAbstracted = abstractedServerFn; -function abstractedClientFn() { - return 'client'; -} -const clientOnlyFnAbstracted = () => {}; -const serverThenClientFnAbstracted = abstractedServerFn; -const clientThenServerFnAbstracted = abstractedServerFn; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx deleted file mode 100644 index 51263bea85..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createIsomorphicFn } from '@tanstack/solid-start' - -const noImpl = createIsomorphicFn() - -const serverOnlyFn = createIsomorphicFn().server(() => 'server') - -const clientOnlyFn = createIsomorphicFn().client(() => 'client') - -const serverThenClientFn = createIsomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = createIsomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = createIsomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = createIsomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = createIsomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = createIsomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx deleted file mode 100644 index 6606a86c50..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createIsomorphicFn as isomorphicFn } from '@tanstack/solid-start' - -const noImpl = isomorphicFn() - -const serverOnlyFn = isomorphicFn().server(() => 'server') - -const clientOnlyFn = isomorphicFn().client(() => 'client') - -const serverThenClientFn = isomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = isomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = isomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = isomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = isomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = isomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx b/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx deleted file mode 100644 index 9ca4b15b94..0000000000 --- a/packages/solid-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' - -const noImpl = TanStackStart.createIsomorphicFn() - -const serverOnlyFn = TanStackStart.createIsomorphicFn().server(() => 'server') - -const clientOnlyFn = TanStackStart.createIsomorphicFn().client(() => 'client') - -const serverThenClientFn = TanStackStart.createIsomorphicFn() - .server(() => 'server') - .client(() => 'client') - -const clientThenServerFn = TanStackStart.createIsomorphicFn() - .client(() => 'client') - .server(() => 'server') - -function abstractedServerFn() { - return 'server' -} - -const serverOnlyFnAbstracted = - TanStackStart.createIsomorphicFn().server(abstractedServerFn) - -function abstractedClientFn() { - return 'client' -} - -const clientOnlyFnAbstracted = - TanStackStart.createIsomorphicFn().client(abstractedClientFn) - -const serverThenClientFnAbstracted = TanStackStart.createIsomorphicFn() - .server(abstractedServerFn) - .client(abstractedClientFn) - -const clientThenServerFnAbstracted = TanStackStart.createIsomorphicFn() - .client(abstractedClientFn) - .server(abstractedServerFn) diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx deleted file mode 100644 index ac0d1d2a9a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}); -export const withVariable = createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 3e917e901f..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}); -export const withVariable = middlewareFn({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx deleted file mode 100644 index 00d22094e8..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx deleted file mode 100644 index 40a49dca05..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx deleted file mode 100644 index dda24f7c4e..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).server(async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = createMiddleware({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 7fcc6b7b5a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = middlewareFn({ - id: 'test' -}).server(async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = middlewareFn({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = middlewareFn({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = middlewareFn({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx deleted file mode 100644 index 92047bfa0a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(async function () { - 'use server'; - - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test' -}).server(async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = TanStackStart.createMiddleware({ - id: 'test' -}).server(abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test' -}).server(zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx deleted file mode 100644 index eb3d933b77..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createMiddleware({ - id: 'test' -}).validator(z.number()).server(({ - input -}) => input + 1); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx deleted file mode 100644 index 595099cdbe..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createMiddleware({ - id: 'test', -}).server(async function () { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withoutUseServer = createMiddleware({ - id: 'test', -}).server(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = createMiddleware({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = createMiddleware({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx deleted file mode 100644 index 700da4fe63..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createMiddleware as middlewareFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = middlewareFn({ - id: 'test', -}).server(async function () { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withoutUseServer = middlewareFn({ - id: 'test', -}).server(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = middlewareFn({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = middlewareFn({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx deleted file mode 100644 index 315d29e1c7..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = TanStackStart.createMiddleware({ - id: 'test', -}).server(async function () { - 'use server' - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withoutUseServer = TanStackStart.createMiddleware({ - id: 'test', -}).server(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = TanStackStart.createMiddleware({ - id: 'test', -}).server(abstractedFunction) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = TanStackStart.createMiddleware({ - id: 'test', -}).server( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx b/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx deleted file mode 100644 index 62ea02b36a..0000000000 --- a/packages/solid-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { createMiddleware } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createMiddleware({ - id: 'test', -}) - .validator(z.number()) - .server(({ input }) => input + 1) diff --git a/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts b/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts deleted file mode 100644 index 8d30fee5ad..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/createServerFn.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { describe, expect, test } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('createServerFn compiles correctly', async () => { - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - - test('should error if created without a handler', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createServerFn } from '@tanstack/solid-start' - createServerFn()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - - test('should be assigned to a variable', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { createServerFn } from '@tanstack/solid-start' - createServerFn().handler(async () => {})`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) - - test('should work with identifiers of functions', () => { - const code = ` - import { createServerFn } from '@tanstack/solid-start' - const myFunc = () => { - return 'hello from the server' - } - const myServerFn = createServerFn().handler(myFunc)` - - const compiledResultClient = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'client', - dce: false, - }) - - const compiledResultServer = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'server', - dce: false, - }) - - expect(compiledResultClient.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const myServerFn = createServerFn().handler((opts, signal) => { - "use server"; - - return myServerFn.__executeServer(opts, signal); - });" - `) - - expect(compiledResultServer.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const myFunc = () => { - return 'hello from the server'; - }; - const myServerFn = createServerFn().handler((opts, signal) => { - "use server"; - - return myServerFn.__executeServer(opts, signal); - }, myFunc);" - `) - }) - - test('should use dce by default', () => { - const code = ` - import { createServerFn } from '@tanstack/solid-start' - const exportedVar = 'exported' - export const exportedFn = createServerFn().handler(async () => { - return exportedVar - }) - const nonExportedVar = 'non-exported' - const nonExportedFn = createServerFn().handler(async () => { - return nonExportedVar - })` - - // Client - const compiledResult = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'client', - dce: true, - }) - - expect(compiledResult.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - export const exportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return exportedFn.__executeServer(opts, signal); - }); - const nonExportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return nonExportedFn.__executeServer(opts, signal); - });" - `) - - // Server - const compiledResultServer = compileStartOutput({ - root: '/test', - filename: 'test.ts', - code, - env: 'server', - dce: true, - }) - - expect(compiledResultServer.code).toMatchInlineSnapshot(` - "import { createServerFn } from '@tanstack/solid-start'; - const exportedVar = 'exported'; - export const exportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return exportedFn.__executeServer(opts, signal); - }, async () => { - return exportedVar; - }); - const nonExportedVar = 'non-exported'; - const nonExportedFn = createServerFn().handler((opts, signal) => { - "use server"; - - return nonExportedFn.__executeServer(opts, signal); - }, async () => { - return nonExportedVar; - });" - `) - }) -}) diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx deleted file mode 100644 index d8105165f0..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withArrowFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunction.__executeServer(opts, signal); -}); -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunctionAndFunction.__executeServer(opts, signal); -}); -export const withoutUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); -export const withValidatorFn = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withValidatorFn.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx deleted file mode 100644 index e7d1010563..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withoutUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx deleted file mode 100644 index e2735ea5d1..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}); -export const withVariable = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}); -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx deleted file mode 100644 index f43f06ee88..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx deleted file mode 100644 index 673c4e90fe..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withArrowFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunction.__executeServer(opts, signal); -}, async () => null); -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withArrowFunctionAndFunction.__executeServer(opts, signal); -}, async () => test()); -export const withoutUseServer = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); -export const withValidatorFn = createServerFn({ - method: 'GET' -}).validator(z.number()).handler((opts, signal) => { - "use server"; - - return withValidatorFn.__executeServer(opts, signal); -}, async ({ - input -}) => { - return null; -}); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx deleted file mode 100644 index d9902417f5..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = serverFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx deleted file mode 100644 index 83964ecc5c..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, async function () { - 'use server'; - - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withoutUseServer.__executeServer(opts, signal); -}, async () => { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -}); -export const withVariable = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withVariable.__executeServer(opts, signal); -}, abstractedFunction); -async function abstractedFunction() { - console.info('Fetching posts...'); - await new Promise(r => setTimeout(r, 500)); - return axios.get>('https://jsonplaceholder.typicode.com/posts').then(r => r.data.slice(0, 10)); -} -function zodValidator(schema: TSchema, fn: (input: z.output) => TResult) { - return async (input: unknown) => { - return fn(schema.parse(input)); - }; -} -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET' -}).handler((opts, signal) => { - "use server"; - - return withZodValidator.__executeServer(opts, signal); -}, zodValidator(z.number(), input => { - return { - 'you gave': input - }; -})); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx deleted file mode 100644 index 364f8354fa..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start'; -import { z } from 'zod'; -export const withUseServer = createServerFn({ - method: 'GET' -}).validator(z.number()).handler((opts, signal) => { - "use server"; - - return withUseServer.__executeServer(opts, signal); -}, ({ - input -}) => input + 1); \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx deleted file mode 100644 index fd7f48510d..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createServerFn({ - method: 'GET', -}).handler(async function () { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withArrowFunction = createServerFn({ - method: 'GET', -}).handler(async () => null) - -export const withArrowFunctionAndFunction = createServerFn({ - method: 'GET', -}).handler(async () => test()) - -export const withoutUseServer = createServerFn({ - method: 'GET', -}).handler(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = createServerFn({ - method: 'GET', -}).handler(abstractedFunction) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = createServerFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) - -export const withValidatorFn = createServerFn({ - method: 'GET', -}) - .validator(z.number()) - .handler(async ({ input }) => { - return null - }) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx deleted file mode 100644 index 823339b3ac..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { createServerFn as serverFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = serverFn({ - method: 'GET', -}).handler(async function () { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withoutUseServer = serverFn({ - method: 'GET', -}).handler(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = serverFn({ method: 'GET' }).handler( - abstractedFunction, -) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = serverFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx deleted file mode 100644 index d4ecddb304..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as TanStackStart from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = TanStackStart.createServerFn({ - method: 'GET', -}).handler(async function () { - 'use server' - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withoutUseServer = TanStackStart.createServerFn({ - method: 'GET', -}).handler(async () => { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -}) - -export const withVariable = TanStackStart.createServerFn({ - method: 'GET', -}).handler(abstractedFunction) - -async function abstractedFunction() { - console.info('Fetching posts...') - await new Promise((r) => setTimeout(r, 500)) - return axios - .get>('https://jsonplaceholder.typicode.com/posts') - .then((r) => r.data.slice(0, 10)) -} - -function zodValidator( - schema: TSchema, - fn: (input: z.output) => TResult, -) { - return async (input: unknown) => { - return fn(schema.parse(input)) - } -} - -export const withZodValidator = TanStackStart.createServerFn({ - method: 'GET', -}).handler( - zodValidator(z.number(), (input) => { - return { 'you gave': input } - }), -) diff --git a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx b/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx deleted file mode 100644 index 0d535eb369..0000000000 --- a/packages/solid-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { createServerFn } from '@tanstack/solid-start' -import { z } from 'zod' - -export const withUseServer = createServerFn({ - method: 'GET', -}) - .validator(z.number()) - .handler(({ input }) => input + 1) diff --git a/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts b/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts deleted file mode 100644 index 00c9786170..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/envOnly.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { readFile, readdir } from 'node:fs/promises' -import path from 'node:path' -import { describe, expect, test } from 'vitest' - -import { compileStartOutput } from '../../src/compilers' - -async function getFilenames() { - return await readdir(path.resolve(import.meta.dirname, './test-files')) -} - -describe('envOnly functions compile correctly', async () => { - const filenames = await getFilenames() - - describe.each(filenames)('should handle "%s"', async (filename) => { - const file = await readFile( - path.resolve(import.meta.dirname, `./test-files/${filename}`), - ) - const code = file.toString() - - test.each(['client', 'server'] as const)( - `should compile for ${filename} %s`, - async (env) => { - const compiledResult = compileStartOutput({ - env, - code, - root: './test-files', - filename, - dce: false, - }) - - await expect(compiledResult.code).toMatchFileSnapshot( - `./snapshots/${env}/${filename}`, - ) - }, - ) - }) - test('should error if implementation not provided', () => { - expect(() => { - compileStartOutput({ - env: 'client', - code: ` - import { clientOnly } from '@tanstack/solid-start' - const fn = clientOnly()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - expect(() => { - compileStartOutput({ - env: 'server', - code: ` - import { serverOnly } from '@tanstack/solid-start' - const fn = serverOnly()`, - root: './test-files', - filename: 'no-fn.ts', - dce: false, - }) - }).toThrowError() - }) -}) diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx deleted file mode 100644 index 8080d677e6..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx deleted file mode 100644 index c3e67e045b..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly as serverFn, clientOnly as clientFn } from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx deleted file mode 100644 index d860ab6d21..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start'; -const serverFunc = () => { - throw new Error("serverOnly() functions can only be called on the server!"); -}; -const clientFunc = () => 'client'; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx deleted file mode 100644 index 35bf2907cc..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx deleted file mode 100644 index 31c1c2a23b..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly as serverFn, clientOnly as clientFn } from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx deleted file mode 100644 index 318b47dd64..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start'; -const serverFunc = () => 'server'; -const clientFunc = () => { - throw new Error("clientOnly() functions can only be called on the client!"); -}; \ No newline at end of file diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx deleted file mode 100644 index c4513f737d..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { serverOnly, clientOnly } from '@tanstack/solid-start' - -const serverFunc = serverOnly(() => 'server') - -const clientFunc = clientOnly(() => 'client') diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx deleted file mode 100644 index 4b48ba3b58..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { - serverOnly as serverFn, - clientOnly as clientFn, -} from '@tanstack/solid-start' - -const serverFunc = serverFn(() => 'server') - -const clientFunc = clientFn(() => 'client') diff --git a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx b/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx deleted file mode 100644 index adeab52616..0000000000 --- a/packages/solid-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import * as TanstackStart from '@tanstack/solid-start' - -const serverFunc = TanstackStart.serverOnly(() => 'server') - -const clientFunc = TanstackStart.clientOnly(() => 'client') diff --git a/packages/solid-start-plugin/tsconfig.json b/packages/solid-start-plugin/tsconfig.json index 37d21ef6ca..6c8c904b07 100644 --- a/packages/solid-start-plugin/tsconfig.json +++ b/packages/solid-start-plugin/tsconfig.json @@ -3,6 +3,9 @@ "include": ["src", "vite.config.ts", "tests"], "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { - "jsx": "react-jsx" + "rootDir": "src", + "outDir": "dist/esm", + "target": "esnext", + "noEmit": false } } diff --git a/packages/solid-start-plugin/vite.config.ts b/packages/solid-start-plugin/vite.config.ts index 5389f0f739..2c711fd181 100644 --- a/packages/solid-start-plugin/vite.config.ts +++ b/packages/solid-start-plugin/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', + outDir: './dist', }), ) diff --git a/packages/solid-start-router-manifest/README.md b/packages/solid-start-router-manifest/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/solid-start-router-manifest/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/solid-start-router-manifest/eslint.config.js b/packages/solid-start-router-manifest/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/solid-start-router-manifest/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/solid-start-router-manifest/package.json b/packages/solid-start-router-manifest/package.json deleted file mode 100644 index 23785d8993..0000000000 --- a/packages/solid-start-router-manifest/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "@tanstack/solid-start-router-manifest", - "version": "1.115.0", - "description": "Modern and scalable routing for Solid applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "solid", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "tsc" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/router-core": "workspace:^", - "tiny-invariant": "^1.3.3", - "vinxi": "0.5.3" - }, - "devDependencies": { - "typescript": "^5.7.2" - } -} diff --git a/packages/solid-start-router-manifest/src/index.ts b/packages/solid-start-router-manifest/src/index.ts deleted file mode 100644 index 9a41e3f788..0000000000 --- a/packages/solid-start-router-manifest/src/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-expect-error -import tsrGetManifest from 'tsr:routes-manifest' -import { getManifest } from 'vinxi/manifest' -import { default as invariant } from 'tiny-invariant' -import type { Manifest } from '@tanstack/router-core' - -function sanitizeBase(base: string) { - return base.replace(/^\/|\/$/g, '') -} - -/** - * @description Returns the full, unfiltered router manifest. This includes relationships - * between routes, assets, and preloads and is NOT what you want to serialize and - * send to the client. - */ -export function getFullRouterManifest() { - const routerManifest = tsrGetManifest() as Manifest - - const rootRoute = (routerManifest.routes.__root__ = - routerManifest.routes.__root__ || {}) - - rootRoute.assets = rootRoute.assets || [] - - const script = '' - // Always fake that HMR is ready - if (process.env.NODE_ENV === 'development') { - const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') - - if (!CLIENT_BASE) { - throw new Error( - 'tanstack/solid-start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', - ) - } - } - - // Get the entry for the client from vinxi - const vinxiClientManifest = getManifest('client') - - const importPath = - vinxiClientManifest.inputs[vinxiClientManifest.handler]?.output.path - if (!importPath) { - invariant(importPath, 'Could not find client entry in vinxi manifest') - } - - rootRoute.assets.push({ - tag: 'script', - attrs: { - type: 'module', - suppressHydrationWarning: true, - async: true, - }, - children: `${script}import("${importPath}")`, - }) - - return routerManifest -} - -/** - * @description Returns the router manifest that should be sent to the client. - * This includes only the assets and preloads for the current route and any - * special assets that are needed for the client. It does not include relationships - * between routes or any other data that is not needed for the client. - */ -export function getRouterManifest() { - const routerManifest = getFullRouterManifest() - - // Strip out anything that isn't needed for the client - return { - ...routerManifest, - routes: Object.fromEntries( - Object.entries(routerManifest.routes).map(([k, v]: any) => { - const { preloads, assets } = v - return [ - k, - { - preloads, - assets, - }, - ] - }), - ), - } -} diff --git a/packages/solid-start-router-manifest/tsconfig.json b/packages/solid-start-router-manifest/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/solid-start-router-manifest/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/solid-start-server/package.json b/packages/solid-start-server/package.json index a1d3950548..47f1001272 100644 --- a/packages/solid-start-server/package.json +++ b/packages/solid-start-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-start-server", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { diff --git a/packages/solid-start-server/src/index.tsx b/packages/solid-start-server/src/index.tsx index f4573955c8..b0dda10b7a 100644 --- a/packages/solid-start-server/src/index.tsx +++ b/packages/solid-start-server/src/index.tsx @@ -1,4 +1,5 @@ export { StartServer } from './StartServer' export { defaultStreamHandler } from './defaultStreamHandler' export { defaultRenderHandler } from './defaultRenderHandler' + export * from '@tanstack/start-server-core' diff --git a/packages/solid-start-server/vite.config.ts b/packages/solid-start-server/vite.config.ts index c0a7454291..79bf665097 100644 --- a/packages/solid-start-server/vite.config.ts +++ b/packages/solid-start-server/vite.config.ts @@ -22,5 +22,6 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: ['tsr:server-fn-manifest', 'tsr:start-manifest'], }), ) diff --git a/packages/solid-start/package.json b/packages/solid-start/package.json index f9b192c4e9..edfed83ba7 100644 --- a/packages/solid-start/package.json +++ b/packages/solid-start/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-start", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,12 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:build", - "test:build": "exit 0; vitest", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/client.d.ts", "exports": { @@ -62,14 +57,14 @@ "default": "./dist/cjs/server.cjs" } }, - "./config": { + "./plugin": { "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" + "types": "./dist/esm/plugin.d.ts", + "default": "./dist/esm/plugin.js" }, "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" + "types": "./dist/cjs/plugin.d.cts", + "default": "./dist/cjs/plugin.cjs" } }, "./api": { @@ -82,16 +77,6 @@ "default": "./dist/cjs/api.cjs" } }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" - } - }, "./server-functions-client": { "import": { "types": "./dist/esm/server-functions-client.d.ts", @@ -145,11 +130,9 @@ "dependencies": { "@tanstack/solid-start-client": "workspace:^", "@tanstack/solid-start-server": "workspace:^", - "@tanstack/solid-start-config": "workspace:^", - "@tanstack/solid-start-router-manifest": "workspace:^", + "@tanstack/solid-start-plugin": "workspace:^", "@tanstack/start-server-functions-client": "workspace:^", "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", "@tanstack/start-server-functions-ssr": "workspace:^", "@tanstack/start-api-routes": "workspace:^" }, diff --git a/packages/solid-start/src/config.tsx b/packages/solid-start/src/config.tsx deleted file mode 100644 index 5a71360c3a..0000000000 --- a/packages/solid-start/src/config.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/solid-start-config' diff --git a/packages/solid-start/src/plugin.tsx b/packages/solid-start/src/plugin.tsx new file mode 100644 index 0000000000..24c76d5516 --- /dev/null +++ b/packages/solid-start/src/plugin.tsx @@ -0,0 +1 @@ +export * from '@tanstack/solid-start-plugin' diff --git a/packages/solid-start/src/router-manifest.tsx b/packages/solid-start/src/router-manifest.tsx deleted file mode 100644 index 4e939be275..0000000000 --- a/packages/solid-start/src/router-manifest.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/solid-start-router-manifest' diff --git a/packages/solid-start/src/server-functions-handler.tsx b/packages/solid-start/src/server-functions-handler.tsx deleted file mode 100644 index c3cc9770d2..0000000000 --- a/packages/solid-start/src/server-functions-handler.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/solid-start/vite.config.ts b/packages/solid-start/vite.config.ts index dfcd5b4b41..262e126d5c 100644 --- a/packages/solid-start/vite.config.ts +++ b/packages/solid-start/vite.config.ts @@ -17,8 +17,7 @@ export default mergeConfig( entry: [ './src/client.tsx', './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', + './src/plugin.tsx', './src/server-functions-client.tsx', './src/server-functions-server.tsx', './src/server-functions-ssr.tsx', @@ -27,8 +26,7 @@ export default mergeConfig( externalDeps: [ '@tanstack/solid-start-client', '@tanstack/solid-start-server', - '@tanstack/solid-start-config', - '@tanstack/solid-start-router-manifest', + '@tanstack/solid-start-plugin', '@tanstack/start-server-functions-client', '@tanstack/start-server-functions-server', '@tanstack/start-server-functions-ssr', diff --git a/packages/start-api-routes/package.json b/packages/start-api-routes/package.json index e9c2630a09..6cc752382b 100644 --- a/packages/start-api-routes/package.json +++ b/packages/start-api-routes/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-api-routes", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { @@ -63,8 +49,7 @@ }, "dependencies": { "@tanstack/router-core": "workspace:^", - "@tanstack/start-server-core": "workspace:^", - "vinxi": "0.5.3" + "@tanstack/start-server-core": "workspace:^" }, "devDependencies": { "typescript": "^5.7.2" diff --git a/packages/start-api-routes/src/index.ts b/packages/start-api-routes/src/index.ts index dbfba63cce..a7ee29cda3 100644 --- a/packages/start-api-routes/src/index.ts +++ b/packages/start-api-routes/src/index.ts @@ -1,369 +1,44 @@ -import { eventHandler, toWebRequest } from '@tanstack/start-server-core' -import vinxiFileRoutes from 'vinxi/routes' -import type { ResolveParams } from '@tanstack/router-core' - -export type StartAPIHandlerCallback = (ctx: { - request: Request -}) => Response | Promise - -export type StartAPIMethodCallback = (ctx: { - request: Request - params: ResolveParams -}) => Response | Promise - -const HTTP_API_METHODS = [ - 'GET', - 'POST', - 'PUT', - 'PATCH', - 'DELETE', - 'OPTIONS', - 'HEAD', -] as const -export type HTTP_API_METHOD = (typeof HTTP_API_METHODS)[number] - /** - * - * @param cb The callback function that will be called when the API handler is invoked - * @returns The response from the callback function + * @deprecated Use createFileRoute().server() or createRoute().server() instead. */ -export function createStartAPIHandler(cb: StartAPIHandlerCallback) { - return eventHandler(async (event) => { - const request = toWebRequest(event)! - const res = await cb({ request }) - return res - }) +export function createStartAPIHandler() { + console.warn( + 'createStartAPIHandler is deprecated. Use createFileRoute().server() or createRoute().server() instead.', + ) } -type APIRoute = { - path: TPath - methods: Partial>> -} - -type CreateAPIRouteFn = ( - methods: Partial>>, -) => APIRoute - -type CreateAPIRoute = ( - path: TPath, -) => CreateAPIRouteFn - -type APIRouteReturnType = ReturnType> - -/** - * This function is used to create an API route that will be listening on a specific path when you are not using the file-based routes. - * - * @param path The path that the API route will be listening on. You need to make sure that this is a valid TanStack Router path in order for the route to be matched. This means that you can use the following syntax: - * /api/foo/$bar/name/$ - * - The `$bar` is a parameter that will be extracted from the URL and passed to the handler - * - The `$` is a wildcard that will match any number of segments in the URL - * @returns A function that takes the methods that the route will be listening on and returns the API route object - */ -export const createAPIRoute: CreateAPIRoute = (path) => (methods) => ({ - path, - methods, -}) - -/** - * This function is used to create an API route that will be listening on a specific path when you are using the file-based routes. - * - * @param filePath The path that the API file route will be listening on. This filePath should automatically be generated by the TSR plugin and should be a valid TanStack Router path - * @returns A function that takes the methods that the route will be listening on and returns the API route object - */ -export const createAPIFileRoute: CreateAPIRoute = (filePath) => (methods) => ({ - path: filePath, - methods, -}) - /** - * This function takes a URL object and a list of routes and finds the route that matches the URL. - * - * @param url URL object - * @param entryRoutes List of routes entries in the TSR format to find the current match by the URL - * @returns Returns the route that matches the URL or undefined if no route matches + * @deprecated Use createFileRoute().server() or createRoute().server() instead. */ -function findRoute( - url: URL, - entryRoutes: Array<{ routePath: string; payload: TPayload }>, -): - | { - routePath: string - params: Record - payload: TPayload - } - | undefined { - const urlSegments = url.pathname.split('/').filter(Boolean) - - const routes = entryRoutes - .sort((a, b) => { - const aParts = a.routePath.split('/').filter(Boolean) - const bParts = b.routePath.split('/').filter(Boolean) - - return bParts.length - aParts.length - }) - .filter((r) => { - const routeSegments = r.routePath.split('/').filter(Boolean) - return urlSegments.length >= routeSegments.length - }) - - for (const route of routes) { - const routeSegments = route.routePath.split('/').filter(Boolean) - const params: Record = {} - let matches = true - for (let i = 0; i < routeSegments.length; i++) { - const routeSegment = routeSegments[i] as string - const urlSegment = urlSegments[i] as string - if (routeSegment.startsWith('$')) { - if (routeSegment === '$') { - const wildcardValue = urlSegments.slice(i).join('/') - if (wildcardValue !== '') { - params['*'] = wildcardValue - params['_splat'] = wildcardValue - } else { - matches = false - break - } - } else { - const paramName = routeSegment.slice(1) - params[paramName] = urlSegment - } - } else if (routeSegment !== urlSegment) { - matches = false - break - } - } - if (matches) { - return { routePath: route.routePath, params, payload: route.payload } - } - } - - return undefined +export function createAPIRoute() { + console.warn( + 'createAPIRoute is deprecated. Use createFileRoute().server() or createRoute().server() instead.', + ) } /** - * You should only be using this function if you are not using the file-based routes. - * - * - * @param opts - A map of TSR routes with the values being the route handlers - * @returns The handler for the incoming request - * - * @example - * ```ts - * // app/foo.ts - * import { createAPIRoute } from '@tanstack/start-api-routes' - * const fooBarRoute = createAPIRoute('/api/foo/$bar')({ - * GET: ({ params }) => { - * return new Response(JSON.stringify({ params })) - * } - * }) - * - * // app/api.ts - * import { - * createStartAPIHandler, - * defaultAPIRoutesHandler - * } from '@tanstack/start-api-routes' - * - * export default createStartAPIHandler( - * defaultAPIRoutesHandler({ - * '/api/foo/$bar': fooBarRoute - * }) - * ) - * ``` + * @deprecated Use createFileRoute().server() or createRoute().server() instead. */ -export const defaultAPIRoutesHandler: (opts: { - routes: { [TPath in string]: APIRoute } -}) => StartAPIHandlerCallback = (opts) => { - return async ({ request }) => { - if (!HTTP_API_METHODS.includes(request.method as HTTP_API_METHOD)) { - return new Response('Method not allowed', { status: 405 }) - } - - const url = new URL(request.url, 'http://localhost:3000') - - const routes = Object.entries(opts.routes).map(([routePath, route]) => ({ - routePath, - payload: route, - })) - - // Find the route that matches the request by the request URL - const match = findRoute(url, routes) - - // If we don't have a route that could possibly handle the request, return a 404 - if (!match) { - return new Response('Not found', { status: 404 }) - } - - // If the route path doesn't match the payload path, return a 404 - if (match.routePath !== match.payload.path) { - console.error( - `Route path mismatch: ${match.routePath} !== ${match.payload.path}. Please make sure that the route path in \`createAPIRoute\` matches the path in the handler map in \`defaultAPIRoutesHandler\``, - ) - return new Response('Not found', { status: 404 }) - } - - const method = request.method as HTTP_API_METHOD - - // Get the handler for the request method based on the Request Method - const handler = match.payload.methods[method] - - // If the handler is not defined, return a 405 - if (!handler) { - return new Response('Method not allowed', { status: 405 }) - } - - return await handler({ request, params: match.params }) - } -} - -interface CustomizedVinxiFileRoute { - path: string // this path adheres to the h3 router path format - filePath: string // this is the file path on the system - $APIRoute?: { - src: string // this is the path to the source file - import: () => Promise<{ - APIRoute: APIRouteReturnType - }> - } +export function createAPIFileRoute() { + console.warn( + 'createAPIFileRoute is deprecated. Use createFileRoute().server() or createRoute().server() instead.', + ) } /** - * This is populated by the work done in the config file using the tsrFileRouter - */ -const vinxiRoutes = ( - vinxiFileRoutes as unknown as Array -).filter((route) => route['$APIRoute']) - -/** - * This function takes the vinxi routes and interpolates them into a format that can be worked with in the API handler - * - * @param routes The vinxi routes that have been filtered to only include those with a $APIRoute property - * @returns An array of objects where the path `key` is interpolated to a valid TanStack Router path, with the `payload` being the original route object - * - * @example - * ``` - * const input = [ - * { - * path: '/api/boo/:$id?/name/*splat', - * filePath: '..../code/tanstack/router/examples/react/start-basic/app/routes/api.boo.$id.name.$.tsx', - * '$APIRoute': [Object] - * } - * ] - * - * toTSRFileBasedRoutes(input) - * [ - * { - * path: '/api/boo/$id/name/$', - * route: { - * path: '/api/boo/:$id?/name/*splat', - * filePath: '..../code/tanstack/router/examples/react/start-basic/app/routes/api.boo.$id.name.$.tsx', - * '$APIRoute': [Object] - * } - * } - * ] - * ``` + * @deprecated Use createFileRoute().server() or createRoute().server() instead. */ -function toTSRFileBasedRoutes( - routes: Array, -): Array<{ routePath: string; payload: CustomizedVinxiFileRoute }> { - const pairs: Array<{ - routePath: string - payload: CustomizedVinxiFileRoute - }> = [] - - routes.forEach((route) => { - const parts = route.path.split('/').filter(Boolean) - - const path = parts - .map((part) => { - if (part === '*splat') { - return '$' - } - - if (part.startsWith(':$') && part.endsWith('?')) { - return part.slice(1, -1) - } - - return part - }) - .join('/') - - pairs.push({ routePath: `/${path}`, payload: route }) - }) - - return pairs +export function defaultAPIRoutesHandler() { + console.warn( + 'defaultAPIRoutesHandler is deprecated. Use createFileRoute().server() or createRoute().server() instead.', + ) } /** - * This function is the default handler for the API routes when using file-based routes. - * - * @param StartAPIHandlerCallbackContext - * @returns The handler for the incoming request - * - * @example - * ```ts - * // app/api.ts - * import { - * createStartAPIHandler, - * defaultAPIFileRouteHandler - * } from '@tanstack/start-api-routes' - * - * export default createStartAPIHandler(defaultAPIFileRouteHandler) - * ``` + * @deprecated Use createFileRoute().server() or createRoute().server() instead. */ -export const defaultAPIFileRouteHandler: StartAPIHandlerCallback = async ({ - request, -}) => { - // Simple early abort if there are no routes - if (!vinxiRoutes.length) { - return new Response('No routes found', { status: 404 }) - } - - if (!HTTP_API_METHODS.includes(request.method as HTTP_API_METHOD)) { - return new Response('Method not allowed', { status: 405 }) - } - - const routes = toTSRFileBasedRoutes(vinxiRoutes) - - const url = new URL(request.url, 'http://localhost:3000') - - // Find the route that file that matches the request by the request URL - const match = findRoute(url, routes) - - // If we don't have a route that could possibly handle the request, return a 404 - if (!match) { - return new Response('Not found', { status: 404 }) - } - - // The action is the route file that we need to import - // which contains the possible handlers for the incoming request - let action: APIRouteReturnType | undefined = undefined - - try { - // We can guarantee that action is defined since we filtered for it earlier - action = await match.payload.$APIRoute!.import().then((m) => m.APIRoute) - } catch (err) { - // If we can't import the route file, return a 500 - console.error('Error importing route file:', err) - return new Response('Internal server error', { status: 500 }) - } - - // If we don't have an action, return a 500 - if (!action) { - return new Response('Internal server error', { status: 500 }) - } - - const method = request.method as HTTP_API_METHOD - - // Get the handler for the request method based on the Request Method - const handler = action.methods[method] - - // If the handler is not defined, return a 405 - // What this means is that we have a route that matches the request - // but we don't have a handler for the request method - // i.e we have a route that matches /api/foo/$ but we don't have a POST handler - if (!handler) { - return new Response('Method not allowed', { status: 405 }) - } - - return await handler({ request, params: match.params }) +export function defaultAPIFileRouteHandler() { + console.warn( + 'defaultAPIFileRouteHandler is deprecated. Use createFileRoute().server() or createRoute().server() instead.', + ) } diff --git a/packages/start-client-core/package.json b/packages/start-client-core/package.json index fa231eee23..93c37f08c0 100644 --- a/packages/start-client-core/package.json +++ b/packages/start-client-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-client-core", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,22 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:deps && pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", - "test:unit:dev": "vitest --watch", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { diff --git a/packages/start-client-core/src/createMiddleware.ts b/packages/start-client-core/src/createMiddleware.ts index 654fe78271..001643a61f 100644 --- a/packages/start-client-core/src/createMiddleware.ts +++ b/packages/start-client-core/src/createMiddleware.ts @@ -108,24 +108,24 @@ export type IntersectAllMiddleware< export type IntersectAllValidatorInputs = unknown extends TValidator ? TValidator - : IntersectAssign< - IntersectAllMiddleware, - TValidator extends undefined - ? undefined - : ResolveValidatorInput - > + : TValidator extends undefined + ? IntersectAllMiddleware + : IntersectAssign< + IntersectAllMiddleware, + ResolveValidatorInput + > /** * Recursively merge the output type produced by a sequence of middleware */ export type IntersectAllValidatorOutputs = unknown extends TValidator ? TValidator - : IntersectAssign< - IntersectAllMiddleware, - TValidator extends undefined - ? undefined - : ResolveValidatorOutput - > + : TValidator extends undefined + ? IntersectAllMiddleware + : IntersectAssign< + IntersectAllMiddleware, + ResolveValidatorOutput + > export interface MiddlewareOptions< in out TMiddlewares, diff --git a/packages/start-client-core/src/createServerFn.ts b/packages/start-client-core/src/createServerFn.ts index 890345f2df..f0c8ac2c40 100644 --- a/packages/start-client-core/src/createServerFn.ts +++ b/packages/start-client-core/src/createServerFn.ts @@ -469,9 +469,17 @@ export type ValidatorSerializerStringify = Validator< any > +export type ValidatorInputSerializerStringify = + SerializerStringifyBy< + ResolveValidatorInput, + Date | undefined | FormData + > + export type ConstrainValidator = unknown extends TValidator ? TValidator - : Constrain> + : ResolveValidatorInput extends ValidatorInputSerializerStringify + ? TValidator | ValidatorSerializerStringify + : ValidatorSerializerStringify export interface ServerFnMiddleware< TMethod extends Method, diff --git a/packages/start-client-core/src/index.tsx b/packages/start-client-core/src/index.tsx index 5be7fcc4e4..35d6f7f5ea 100644 --- a/packages/start-client-core/src/index.tsx +++ b/packages/start-client-core/src/index.tsx @@ -32,7 +32,6 @@ export { type MiddlewareValidator, type MiddlewareServer, type MiddlewareAfterClient, - type MiddlewareAfterMiddleware, type MiddlewareAfterServer, type Middleware, type MiddlewareClientFnOptions, @@ -84,3 +83,43 @@ export { flattenMiddlewares, serverFnStaticCache, } from './createServerFn' +export { createServerFileRoute, getServerFileRouteApi } from './serverRoute' +export type { + ServerRouteVerb, + ServerRouteVerbs, + ServerRoute, + ServerRouteAfterMethods, + ServerRouteAfterMiddleware, + ServerRouteMethod, + ServerRouteMethodBuilderAfterHandler, + ServerRouteMethodBuilderAfterValidator, + ServerRouteMethodBuilderHandler, + ServerRouteMethodBuilderValidator, + ServerRouteMethods, + ServerRouteMethodHandlerCtx, + ServerRouteMethodHandlerFn, + ServerRouteOptions, + ServerRouteMethodBuilder, + ServerRouteMethodBuilderMiddleware, + CreateServerFileRoute, + AnyRouteMethodsBuilder, + AnyServerRouteWithTypes, + AssignAllMethodContext, + MergeMethodMiddlewares, + ResolveAllMethodValidatorOutputs, + ServerRouteMethodBuilderAfterMiddleware, + ServerRouteMethodBuilderWithTypes, + ServerRouteMethodClientResponse, + ResolveAllServerContext, + ResolveMethods, + ServerRouteMethodBuilderTypes, + ServerRouteMethodClient, + ServerRouteMethodClientResult, + ServerRouteMethodRecordValue, + ServerRouteMethodsClient, + ServerRouteMethodsOptions, + ServerRouteMethodsRecord, + ServerRouteMiddleware, + ServerRouteTypes, + ServerRouteWithTypes, +} from './serverRoute' diff --git a/packages/start-client-core/src/serverRoute.ts b/packages/start-client-core/src/serverRoute.ts new file mode 100644 index 0000000000..393e8da5f7 --- /dev/null +++ b/packages/start-client-core/src/serverRoute.ts @@ -0,0 +1,979 @@ +import type { + AnyMiddleware, + AssignAllServerContext, + IntersectAllValidatorInputs, + IntersectAllValidatorOutputs, + Middleware, +} from './createMiddleware' +import type { + AnyRouter, + Assign, + Constrain, + Expand, + InferFileRouteTypes, + IntersectAssign, + LooseAsyncReturnType, + LooseReturnType, + RegisteredRouter, + ResolveParams, + ResolveValidatorInput, + RouteConstraints, + Validator, +} from '@tanstack/router-core' +import type { ConstrainValidator, JsonResponse } from './createServerFn' + +type TODO = any + +export function createServerFileRoute< + TFilePath extends string, + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +>( + __?: never, + __compiledOpts?: { manifest: ServerRouteManifest }, +): ServerRoute { + return createServerRoute( + undefined, + __compiledOpts as ServerRouteOptions< + TParentRoute, + TId, + TPath, + TFullPath, + undefined + >, + ) +} + +export type ServerRouteManifest = { + middleware: boolean + methods: Record +} + +export function createServerRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +>( + __?: never, + __opts?: ServerRouteOptions, +): ServerRoute { + const resolvedOpts = (__opts || {}) as ServerRouteOptions< + TParentRoute, + TId, + TPath, + TFullPath, + undefined + > + + return { + options: resolvedOpts, + _types: {} as TODO, + middleware: (middlewares: TODO) => + createServerRoute(undefined, { + ...resolvedOpts, + middleware: middlewares, + }) as TODO, + methods: (methodsOrGetMethods: TODO) => { + const methods = (() => { + if (typeof methodsOrGetMethods === 'function') { + return methodsOrGetMethods(createMethodBuilder()) + } + + return methodsOrGetMethods + })() + + return createServerRoute(undefined, { + ...__opts, + methods, + } as TODO) as TODO + }, + client: new Proxy( + {}, + { + get(target, propKey) { + return (...args: Array) => { + if (typeof propKey === 'string') { + const upperPropKey = propKey.toUpperCase() + const method = resolvedOpts.manifest?.methods[ + upperPropKey as keyof typeof resolvedOpts.methods + ] as ((...args: Array) => any) | undefined + if (method) { + return fetch( + new URL(`${resolvedOpts.pathname}/${propKey}`, args[0].url), + { + method: upperPropKey, + ...args[0], + }, + ) + } + } + throw new Error(`Method ${String(propKey)} not found`) + } + }, + }, + ), + } as ServerRoute +} + +const createMethodBuilder = < + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, +>( + __opts?: TODO, +): ServerRouteMethodBuilder => { + return { + _options: __opts || {}, + _types: {} as TODO, + middleware: (middlewares) => + createMethodBuilder({ + ...__opts, + middlewares, + }) as TODO, + validator: (validator) => + createMethodBuilder({ + ...__opts, + validator, + }) as TODO, + handler: (handler) => + createMethodBuilder({ + ...__opts, + handler, + }) as TODO, + } +} + +export type CreateServerFileRoute< + TFilePath extends string, + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +> = (options?: undefined) => ServerRoute + +export type AnyServerRouteWithTypes = ServerRouteWithTypes< + any, + any, + any, + any, + any, + any +> + +export interface ServerRouteWithTypes< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, +> { + _types: ServerRouteTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods + > +} + +export interface ServerRouteTypes< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, +> { + id: TId + path: TPath + fullPath: TFullPath + middlewares: TMiddlewares + methods: TMethods + parentRoute: TParentRoute + allContext: ResolveAllServerContext + allOutput: ResolveAllValidatorOutput + allInput: ResolveAllValidatorInput +} + +export type ResolveAllServerContext< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, +> = unknown extends TParentRoute + ? AssignAllServerContext + : Assign< + TParentRoute['_types']['allContext'], + AssignAllServerContext + > + +export type ResolveAllValidatorOutput< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TValidator = undefined, +> = unknown extends TParentRoute + ? IntersectAllValidatorOutputs + : IntersectAllValidatorOutputs extends undefined + ? TParentRoute['_types']['allOutput'] + : IntersectAssign< + TParentRoute['_types']['allOutput'], + IntersectAllValidatorOutputs + > + +export type ResolveAllValidatorInput< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TValidator = undefined, +> = unknown extends TParentRoute + ? IntersectAllValidatorInputs + : IntersectAllValidatorInputs extends undefined + ? TParentRoute['_types']['allInput'] + : IntersectAssign< + TParentRoute['_types']['allInput'], + IntersectAllValidatorInputs + > + +export interface ServerRoute< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + undefined, + undefined + >, + ServerRouteMiddleware, + ServerRouteMethods {} + +export interface ServerRouteMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], +> { + middleware: ( + middleware: Constrain>, + ) => ServerRouteAfterMiddleware< + TParentRoute, + TId, + TPath, + TFullPath, + TNewMiddleware + > +} + +export interface ServerRouteAfterMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + undefined + >, + ServerRouteMethods {} + +export interface ServerRouteMethods< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, +> { + methods: ( + methodsOrGetMethods: Constrain< + TMethods, + ServerRouteMethodsOptions + >, + ) => ServerRouteAfterMethods< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods + > +} + +export type ServerRouteMethodsOptions< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> = + | ServerRouteMethodsRecord + | (( + api: ServerRouteMethodBuilder, + ) => ServerRouteMethodsRecord) + +export interface ServerRouteMethodsRecord< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, +> { + GET?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'GET', + TMiddlewares + > + POST?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'POST', + TMiddlewares + > + PUT?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'PUT', + TMiddlewares + > + PATCH?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'PATCH', + TMiddlewares + > + DELETE?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'DELETE', + TMiddlewares + > + OPTIONS?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'OPTIONS', + TMiddlewares + > + HEAD?: ServerRouteMethodRecordValue< + TParentRoute, + TFullPath, + 'HEAD', + TMiddlewares + > +} + +export type ServerRouteMethodRecordValue< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, +> = + | ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + undefined, + undefined, + any + > + | AnyRouteMethodsBuilder + +export type ServerRouteVerb = (typeof ServerRouteVerbs)[number] + +export const ServerRouteVerbs = [ + 'GET', + 'POST', + 'PUT', + 'PATCH', + 'DELETE', + 'OPTIONS', + 'HEAD', +] as const + +export type ServerRouteMethodHandlerFn< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse, +> = ( + ctx: ServerRouteMethodHandlerCtx< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator + >, +) => TResponse | Promise + +export interface ServerRouteMethodHandlerCtx< + in out TParentRoute extends AnyServerRouteWithTypes, + in out TFullPath extends string, + in out TVerb extends ServerRouteVerb, + in out TMiddlewares, + in out TMethodMiddlewares, + in out TValidator, +> { + data: Expand< + ResolveAllMethodValidatorOutputs< + TParentRoute, + TMiddlewares, + TMethodMiddlewares, + TValidator + > + > + context: Expand< + AssignAllMethodContext + > + request: Request + params: ResolveParams + pathname: TFullPath +} + +export type ResolveAllMethodValidatorOutputs< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TMethodMiddlewares, + TValidator, +> = ResolveAllValidatorOutput< + TParentRoute, + MergeMethodMiddlewares, + TValidator +> + +export type MergeMethodMiddlewares = + TMiddlewares extends ReadonlyArray + ? TMethodMiddlewares extends ReadonlyArray + ? readonly [...TMiddlewares, ...TMethodMiddlewares] + : TMiddlewares + : TMethodMiddlewares + +export type AssignAllMethodContext< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TMethodMiddlewares, +> = ResolveAllServerContext< + TParentRoute, + MergeMethodMiddlewares +> + +export type AnyRouteMethodsBuilder = ServerRouteMethodBuilderWithTypes< + any, + any, + any, + any, + any, + any +> + +export interface ServerRouteMethodBuilder< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, +> extends ServerRouteMethodBuilderWithTypes< + TParentRoute, + TFullPath, + TMiddlewares, + undefined, + undefined, + undefined + >, + ServerRouteMethodBuilderMiddleware< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares + >, + ServerRouteMethodBuilderValidator< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + undefined + >, + ServerRouteMethodBuilderHandler< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + undefined, + undefined + > {} + +export interface ServerRouteMethodBuilderWithTypes< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse, +> { + _options: TODO + _types: ServerRouteMethodBuilderTypes< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse + > +} + +export interface ServerRouteMethodBuilderTypes< + in out TParentRoute extends AnyServerRouteWithTypes, + in out TFullPath extends string, + in out TMiddlewares, + in out TMethodMiddlewares, + in out TValidator, + in out TResponse, +> { + middlewares: TMiddlewares + methodMiddleware: TMethodMiddlewares + validator: TValidator + fullPath: TFullPath + response: TResponse + allInput: ResolveAllMethodValidatorInput< + TParentRoute, + TMiddlewares, + TMethodMiddlewares, + TValidator + > +} + +export type ResolveAllMethodValidatorInput< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TMethodMiddlewares, + TValidator, +> = ResolveAllValidatorInput< + TParentRoute, + MergeMethodMiddlewares, + TValidator +> + +export interface ServerRouteMethodBuilderMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, +> { + middleware: ( + middleware: Constrain>, + ) => ServerRouteMethodBuilderAfterMiddleware< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TNewMethodMiddlewares + > +} + +export interface ServerRouteMethodBuilderAfterMiddleware< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, +> extends ServerRouteMethodBuilderWithTypes< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + undefined, + undefined + >, + ServerRouteMethodBuilderValidator< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares + >, + ServerRouteMethodBuilderHandler< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + undefined + > {} + +export interface ServerRouteMethodBuilderValidator< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddleware, + TMethodMiddlewares, +> { + validator: ( + validator: ValidateServerRouteValidator, + ) => ServerRouteMethodBuilderAfterValidator< + TParentRoute, + TFullPath, + TVerb, + TMiddleware, + TMethodMiddlewares, + TValidator + > +} + +export type ValidateServerRouteValidator< + TValidator, + TFullPath extends string, +> = unknown extends TValidator + ? TValidator + : ResolveValidatorInput extends ValidatorInput + ? ConstrainValidator + : Validator, any> + +export interface ValidatorInput { + params?: ResolveParams + search?: Record + headers?: Record + body?: unknown +} + +export interface ServerRouteMethodBuilderAfterValidator< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, +> extends ServerRouteMethodBuilderWithTypes< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TValidator, + undefined + >, + ServerRouteMethodBuilderHandler< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator + > {} + +export interface ServerRouteMethodBuilderHandler< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, +> { + handler: ( + handler: ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse + >, + ) => ServerRouteMethodBuilderAfterHandler< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse + > +} + +export interface ServerRouteMethodBuilderAfterHandler< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse, +> extends ServerRouteMethodBuilderWithTypes< + TParentRoute, + TFullPath, + TMiddlewares, + TMethodMiddlewares, + TValidator, + TResponse + > { + opts: ServerRouteMethod< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator + > +} + +export interface ServerRouteMethod< + TParentRoute extends AnyServerRouteWithTypes, + TFullPath extends string, + TVerb extends ServerRouteVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, +> { + middleware?: Constrain> + validator?: ConstrainValidator + handler?: ServerRouteMethodHandlerFn< + TParentRoute, + TFullPath, + TVerb, + TMiddlewares, + TMethodMiddlewares, + TValidator, + undefined + > +} + +export interface ServerRouteAfterMethods< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, + TMethods, +> extends ServerRouteWithTypes< + TParentRoute, + TId, + TPath, + TFullPath, + TMiddlewares, + TMethods + > { + options: ServerRouteOptions + client: ServerRouteMethodsClient< + TParentRoute, + TMiddlewares, + TFullPath, + TMethods + > +} + +export interface ServerRouteOptions< + TParentRoute extends AnyServerRouteWithTypes, + TId extends RouteConstraints['TId'], + TPath extends RouteConstraints['TPath'], + TFullPath extends RouteConstraints['TFullPath'], + TMiddlewares, +> { + pathname: TFullPath + middleware: Constrain> + methods: ServerRouteMethods< + TParentRoute, + TId, + TPath, + TFullPath, + ReadonlyArray + > + manifest?: ServerRouteManifest +} + +export type ServerRouteMethodsClient< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TFullPath extends string, + TMethods, +> = { + [TKey in keyof ResolveMethods & + ServerRouteVerb as Lowercase]: ServerRouteMethodClient< + TParentRoute, + TMiddlewares, + TFullPath, + ResolveMethods[TKey] + > +} + +export type ResolveMethods = TMethods extends ( + ...args: Array +) => infer TMethods + ? TMethods + : TMethods + +export interface ServerRouteMethodClient< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TFullPath extends string, + TMethod, +> { + returns: ServerRouteMethodClientResult + ( + ...args: ServerRouteMethodClientOptions< + TParentRoute, + TMiddlewares, + TFullPath, + TMethod + > + ): ServerRouteMethodClientResult +} + +export type ServerRouteMethodClientResult = + ServerRouteMethodClientResponseJson extends Promise + ? ServerRouteMethodClientResponseJson + : Promise> + +export type ServerRouteMethodClientResponseJson = + ServerRouteMethodClientResponse extends JsonResponse + ? LooseReturnType['json']> + : ServerRouteMethodClientResponse + +export type ServerRouteMethodClientResponse = + TMethod extends AnyRouteMethodsBuilder + ? Awaited + : LooseAsyncReturnType + +export type ServerRouteMethodClientOptions< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TFullPath extends string, + TMethod, +> = + {} extends ServerRouteMethodClientInput< + TParentRoute, + TMiddlewares, + TFullPath, + TMethod + > + ? [ + options?: Expand< + ServerRouteMethodClientInput< + TParentRoute, + TMiddlewares, + TFullPath, + TMethod + > + >, + ] + : [ + options: Expand< + ServerRouteMethodClientInput< + TParentRoute, + TMiddlewares, + TFullPath, + TMethod + > + >, + ] + +export type ServerRouteMethodClientInput< + TParentRoute extends AnyServerRouteWithTypes, + TMiddlewares, + TFullPath extends string, + TMethod, +> = ServerRouteMethodClientInputBuilder< + TFullPath, + TMethod extends AnyRouteMethodsBuilder + ? TMethod['_types']['allInput'] + : ResolveAllValidatorInput +> + +export type ServerRouteMethodClientInputBuilder< + TFullPath extends string, + TInput, +> = TInput extends any + ? ServerRouteMethodClientParamsInput & + ServerRouteMethodClientSearchInput & + ServerRouteMethodClientBodyInput & + ServerRouteMethodClientHeadersInput + : never + +export type ServerRouteMethodClientParamsInput< + TFullPath extends string, + TInput, +> = TInput extends { params: infer TParams } + ? RequiredOrOptionalRecord<'params', TParams> + : DefaultServerRouteMethodClientParamsInput + +export type RequiredOrOptionalRecord< + TKey extends string, + TValue, +> = {} extends TValue ? { [K in TKey]?: TValue } : { [K in TKey]: TValue } + +export type DefaultServerRouteMethodClientParamsInput< + TFullPath extends string, +> = RequiredOrOptionalRecord<'params', ResolveParams> + +export type ServerRouteMethodClientSearchInput = TInput extends { + search: infer TSearch +} + ? RequiredOrOptionalRecord<'search', Expand> + : DefaultServerRouteMethodClientSearchInput + +export interface DefaultServerRouteMethodClientSearchInput { + search?: Record +} + +export type ServerRouteMethodClientBodyInput = TInput extends { + body: infer TBody +} + ? RequiredOrOptionalRecord<'body', Expand> + : DefaultServerRouteMethodClientBodyInput + +export interface DefaultServerRouteMethodClientBodyInput { + body?: unknown +} + +export type ServerRouteMethodClientHeadersInput = TInput extends { + headers: infer THeaders +} + ? RequiredOrOptionalRecord<'headers', Expand> + : DefaultServerRouteMethodClientHeadersInput + +export interface DefaultServerRouteMethodClientHeadersInput { + headers?: Record +} + +export const getServerFileRouteApi: GetServerFileRouteApiFn = () => { + return undefined as TODO +} + +export type GetServerFileRouteApiFn = < + TRouter extends RegisteredRouter, + TId extends keyof ServerRoutesById, +>( + id: TId, +) => ServerRouteApi + +export type ServerRoutesById = InferFileRouteTypes< + TRouter['routeTree'] +>['serverFileRoutesById'] + +export interface ServerRouteApi< + TRouter extends AnyRouter, + TId extends keyof ServerRoutesById, +> { + client: ServerRouteApiClient +} + +export type ServerRouteApiClient< + TRouter extends AnyRouter, + TId extends keyof ServerRoutesById, + TRoute extends AnyServerRouteWithTypes = ServerRouteById, +> = ServerRouteMethodsClient< + TRoute['_types']['parentRoute'], + TRoute['_types']['middlewares'], + TRoute['_types']['fullPath'], + TRoute['_types']['methods'] +> + +export type ServerRouteById< + TRouter extends AnyRouter, + TId extends keyof ServerRoutesById, +> = ServerRoutesById[TId] diff --git a/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts b/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts index 22caa76e3d..3edd81e503 100644 --- a/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts +++ b/packages/start-client-core/src/tests/createServerMiddleware.test-d.ts @@ -609,3 +609,17 @@ test('createMiddleware can validate FormData', () => { > >() }) + +test('createMiddleware merging from parent with undefined validator', () => { + const middleware1 = createMiddleware().validator( + (input: { test: string }) => input.test, + ) + + createMiddleware() + .middleware([middleware1]) + .server((ctx) => { + expectTypeOf(ctx.data).toEqualTypeOf() + + return ctx.next() + }) +}) diff --git a/packages/start-client-core/src/tests/serverRoute.test-d.ts b/packages/start-client-core/src/tests/serverRoute.test-d.ts new file mode 100644 index 0000000000..ad1cc2e083 --- /dev/null +++ b/packages/start-client-core/src/tests/serverRoute.test-d.ts @@ -0,0 +1,1185 @@ +import { expectTypeOf, test } from 'vitest' +import { json } from '../json' +import { createMiddleware } from '../createMiddleware' +import { getServerFileRouteApi } from '../serverRoute' +import type { CreateServerFileRoute } from '../serverRoute' +import type { + Route, + RouterCore, + TrailingSlashOption, +} from '@tanstack/router-core' + +test('createServerFileRoute with methods with no middleware', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverFileRoute = createServerFileRoute() + + expectTypeOf(serverFileRoute).toHaveProperty('methods') + expectTypeOf(serverFileRoute).toHaveProperty('middleware') + + const serverFileRouteWithMethods1 = serverFileRoute.methods({ + GET: async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }, + }) + + const serverFileRouteWithMethods2 = serverFileRoute.methods((r) => ({ + GET: r.handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) + + expectTypeOf< + keyof typeof serverFileRouteWithMethods1.client + >().toEqualTypeOf<'get'>() + + expectTypeOf< + keyof typeof serverFileRouteWithMethods2.client + >().toEqualTypeOf<'get'>() + + expectTypeOf(serverFileRouteWithMethods1.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverFileRouteWithMethods1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(serverFileRouteWithMethods2.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverFileRouteWithMethods2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with methods and route middleware context', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const routeMiddleware = createMiddleware().server(({ next }) => + next({ context: { a: 'a' } }), + ) + + const serverFileRoute = createServerFileRoute().middleware([routeMiddleware]) + + const serverFileRouteWithMethods1 = serverFileRoute.methods({ + GET: async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: { a: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }, + }) + + expectTypeOf(serverFileRouteWithMethods1.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + const serverFileRouteWithMethods2 = serverFileRoute.methods((r) => ({ + GET: r.handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: { a: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) + + expectTypeOf(serverFileRouteWithMethods1.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverFileRouteWithMethods1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(serverFileRouteWithMethods2.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverFileRouteWithMethods2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with methods middleware and route middleware', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const routeMiddleware = createMiddleware().server(({ next }) => + next({ context: { a: 'a' } }), + ) + + const serverFileRoute = createServerFileRoute().middleware([routeMiddleware]) + + const methodMiddleware = createMiddleware().server(({ next }) => + next({ context: { b: 'b' } }), + ) + + const serverRoute = serverFileRoute.methods((r) => ({ + GET: r.middleware([methodMiddleware]).handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: { a: string; b: string } + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ + test: 'test', + }) + }), + })) + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute methods validator with no input', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverRoute = createServerFileRoute().methods((r) => ({ + GET: r + .validator(() => ({ a: 'a' })) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() +}) + +test('createServerFileRoute methods validator with search input', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverRoute = createServerFileRoute().methods((r) => ({ + GET: r + .validator((input: { search: { query: string } }) => ({ + a: input.search.query, + })) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search: { query: string } + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() +}) + +test('createServerFileRoute methods validator with body input', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverRoute = createServerFileRoute().methods((r) => ({ + GET: r + .validator((input: { body: { query: string } }) => ({ + a: input.body.query, + })) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body: { query: string } + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() +}) + +test('createServerFileRoute methods validator with headers input', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverRoute = createServerFileRoute().methods((r) => ({ + GET: r + .validator((input: { headers: { query: string } }) => ({ + a: input.headers.query, + })) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body?: unknown + headers: { query: string } + }, + ] + >() + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() +}) + +test('createServerFileRoute methods validator with a complex union', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const serverRoute = createServerFileRoute().methods((r) => ({ + GET: r + .validator( + ( + input: + | { + search: { type: 'a' } + body: { bodyA: 'a' } + headers: { headerA: 'a' } + } + | { + search: { type: 'b' } + body: { bodyB: 'b' } + headers: { bodyB: 'b' } + }, + ) => input, + ) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: + | { + search: { type: 'a' } + body: { bodyA: 'a' } + headers: { headerA: 'a' } + } + | { + search: { type: 'b' } + body: { bodyB: 'b' } + headers: { bodyB: 'b' } + } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: + | { + params: { detailId: string } + search: { type: 'a' } + body: { bodyA: 'a' } + headers: { headerA: 'a' } + } + | { + params: { detailId: string } + search: { type: 'b' } + body: { bodyB: 'b' } + headers: { bodyB: 'b' } + }, + ] + >() + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() +}) + +test('createServerFileRoute with route middleware validator', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const routeMiddleware = createMiddleware().validator(() => ({ a: 'a' })) + + createServerFileRoute() + .middleware([routeMiddleware]) + .methods({ + GET: async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) +}) + +test('createServerFileRoute with route middleware validator, methods middleware validator and methods validator', () => { + type Path = '$detailId' + const createServerFileRoute: CreateServerFileRoute< + Path, + any, + Path, + Path, + Path + > = undefined as any + + const routeMiddleware = createMiddleware().validator(() => ({ a: 'a' })) + + const methodMiddleware = createMiddleware().validator(() => ({ b: 'b' })) + + const serverRoute = createServerFileRoute() + .middleware([routeMiddleware]) + .methods((r) => ({ + GET: r + .middleware([methodMiddleware]) + .validator(() => { + return { c: 'c' } + }) + .handler(async (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: { a: string; b: string; c: string } + context: undefined + params: { detailId: string } + pathname: '$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(serverRoute.client.get).returns.toEqualTypeOf< + Promise<{ + test: string + }> + >() + + expectTypeOf(serverRoute.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + headers?: Record + body?: unknown + }, + ] + >() +}) + +test('createServerFileRoute with a parent middleware context', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details', + any, + 'details', + 'details', + 'details' + > = undefined as any + + const routeMiddleware1 = createMiddleware().server(({ next }) => { + return next({ context: { a: 'a' } }) + }) + + const detailsServerRoute = createDetailsServerFileRoute().middleware([ + routeMiddleware1, + ]) + + const createDetailServerFileRoute: CreateServerFileRoute< + 'details/$detailId', + typeof detailsServerRoute, + 'details/$detailId', + '$detailId', + 'details/$detailId' + > = undefined as any + + const routeMiddleware2 = createMiddleware().server(({ next }) => { + return next({ context: { b: 'b' } }) + }) + + const detailServerRoute1 = createDetailServerFileRoute() + .middleware([routeMiddleware2]) + .methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: { a: string; b: string } + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const methodMiddleware = createMiddleware().server(({ next }) => { + return next({ context: { c: 'c' } }) + }) + + const detailServerRoute2 = createDetailServerFileRoute() + .middleware([routeMiddleware2]) + .methods((r) => ({ + GET: r.middleware([methodMiddleware]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: { a: string; b: string; c: string } + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with parent middleware params', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + '$userId', + any, + '$userId', + '$userId', + '$userId' + > = undefined as any + + const detailsServerRoute = createDetailsServerFileRoute() + + const createDetailServerFileRoute: CreateServerFileRoute< + '$userId/$detailId', + typeof detailsServerRoute, + '$userId/$detailId', + '$detailId', + '$userId/$detailId' + > = undefined as any + + const detailServerRoute1 = createDetailServerFileRoute().methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: { userId: string; detailId: string } + pathname: '$userId/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const detailServerRoute2 = createDetailServerFileRoute().methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: { userId: string; detailId: string } + pathname: '$userId/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { userId: string; detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { userId: string; detailId: string } + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with no params', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details', + any, + 'details', + 'details', + 'details' + > = undefined as any + + const detailServerRoute1 = createDetailsServerFileRoute().methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: {} + pathname: 'details' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const detailServerRoute2 = createDetailsServerFileRoute().methods((r) => ({ + GET: r.handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: undefined + context: undefined + params: {} + pathname: 'details' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options?: { + params?: {} + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options?: { + params?: {} + search?: Record | undefined + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with parent middleware search', () => { + const middleware1 = createMiddleware().validator( + (input: { search: { query: string } }) => { + return input.search.query + }, + ) + + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details', + any, + 'details', + 'details', + 'details' + > = undefined as any + + const detailsServerRoute = createDetailsServerFileRoute().middleware([ + middleware1, + ]) + + const createDetailServerFileRoute: CreateServerFileRoute< + 'details/$detailId', + typeof detailsServerRoute, + 'details/$detailId', + '$detailId', + 'details/$detailId' + > = undefined as any + + const middleware2 = createMiddleware().validator( + (input: { search: { type: string } }) => { + return Number(input.search.type) + }, + ) + + const detailServerRoute1 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: number + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const middleware3 = createMiddleware().validator( + (input: { search: { slug: string } }) => input.search.slug, + ) + + const detailServerRoute2 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods((r) => ({ + GET: r.middleware([middleware3]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: string + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search: { query: string; type: string } + body?: unknown + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search: { query: string; slug: string; type: string } + body?: unknown + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with parent middleware body', () => { + const middleware1 = createMiddleware().validator( + (input: { body: { query: string } }) => { + return input.body.query + }, + ) + + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details', + any, + 'details', + 'details', + 'details' + > = undefined as any + + const detailsServerRoute = createDetailsServerFileRoute().middleware([ + middleware1, + ]) + + const createDetailServerFileRoute: CreateServerFileRoute< + 'details/$detailId', + typeof detailsServerRoute, + 'details/$detailId', + '$detailId', + 'details/$detailId' + > = undefined as any + + const middleware2 = createMiddleware().validator( + (input: { body: { type: string } }) => { + return Number(input.body.type) + }, + ) + + const detailServerRoute1 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: number + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const middleware3 = createMiddleware().validator( + (input: { body: { slug: string } }) => input.body.slug, + ) + + const detailServerRoute2 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods((r) => ({ + GET: r.middleware([middleware3]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: string + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body: { query: string; type: string } + headers?: Record | undefined + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body: { query: string; type: string; slug: string } + headers?: Record | undefined + }, + ] + >() +}) + +test('createServerFileRoute with parent middleware headers', () => { + const middleware1 = createMiddleware().validator( + (input: { headers: { query: string } }) => { + return input.headers.query + }, + ) + + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details', + any, + 'details', + 'details', + 'details' + > = undefined as any + + const detailsServerRoute = createDetailsServerFileRoute().middleware([ + middleware1, + ]) + + const createDetailServerFileRoute: CreateServerFileRoute< + 'details/$detailId', + typeof detailsServerRoute, + 'details/$detailId', + '$detailId', + 'details/$detailId' + > = undefined as any + + const middleware2 = createMiddleware().validator( + (input: { headers: { type: string } }) => { + return Number(input.headers.type) + }, + ) + + const detailServerRoute1 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods({ + GET: (ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: number + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }, + }) + + const middleware3 = createMiddleware().validator( + (input: { headers: { slug: string } }) => input.headers.slug, + ) + + const detailServerRoute2 = createDetailServerFileRoute() + .middleware([middleware2]) + .methods((r) => ({ + GET: r.middleware([middleware3]).handler((ctx) => { + expectTypeOf(ctx).toEqualTypeOf<{ + data: string + context: undefined + params: { detailId: string } + pathname: 'details/$detailId' + request: Request + }>() + + return json({ test: 'test' }) + }), + })) + + expectTypeOf(detailServerRoute1.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body?: unknown + headers: { query: string; type: string } + }, + ] + >() + + expectTypeOf(detailServerRoute2.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search?: Record + body?: unknown + headers: { query: string; type: string; slug: string } + }, + ] + >() +}) + +test('getServerFileRouteApi', () => { + const createDetailsServerFileRoute: CreateServerFileRoute< + 'details/$detailId', + any, + 'details', + 'details', + 'details/$detailId' + > = undefined as any + + const detailsServerRoute = createDetailsServerFileRoute().methods((api) => ({ + GET: api + .validator( + (input: { + search: { queryA: string } + body: { inputA: string } + headers: { headerA: 'a' } + }) => input, + ) + .handler(() => { + return { + a: 'data', + } + }), + POST: api + .validator( + (input: { + search: { queryB: string } + body: { inputB: string } + headers: { headerB: 'b' } + }) => input, + ) + .handler(() => { + return { + b: 'data', + } + }), + })) + + interface FileRoutesByFullPath {} + + interface FileRoutesByTo {} + + interface FileRoutesById {} + + interface ServerFileRoutesById { + '/details/$detailId': typeof detailsServerRoute + } + + interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: never + fileRoutesByTo: FileRoutesByTo + to: never + id: never + fileRoutesById: FileRoutesById + serverFileRoutesById: ServerFileRoutesById + } + + type AppRoute = Route< + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + any, + FileRouteTypes + > + type AppRouter = RouterCore + + const api = getServerFileRouteApi( + '/details/$detailId', + ) + + expectTypeOf(api.client).toHaveProperty('get') + + expectTypeOf(api.client.get).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search: { queryA: string } + body: { inputA: string } + headers: { headerA: 'a' } + }, + ] + >() + expectTypeOf(api.client.get).returns.toEqualTypeOf>() + + expectTypeOf(api.client).toHaveProperty('post') + + expectTypeOf(api.client.post).parameters.toEqualTypeOf< + [ + options: { + params: { detailId: string } + search: { queryB: string } + body: { inputB: string } + headers: { headerB: 'b' } + }, + ] + >() + expectTypeOf(api.client.post).returns.toEqualTypeOf>() +}) diff --git a/packages/start-client-core/vite.config.ts b/packages/start-client-core/vite.config.ts index ac2026fbb7..fb0b2664aa 100644 --- a/packages/start-client-core/vite.config.ts +++ b/packages/start-client-core/vite.config.ts @@ -16,5 +16,6 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + // externalDeps: ['node:fs', 'node:path', 'node:os', 'node:crypto'], }), ) diff --git a/packages/start-config/README.md b/packages/start-config/README.md deleted file mode 100644 index e3131543bd..0000000000 --- a/packages/start-config/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React applications! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-config/eslint.config.js b/packages/start-config/eslint.config.js deleted file mode 100644 index 931f0ec774..0000000000 --- a/packages/start-config/eslint.config.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check - -import pluginReact from '@eslint-react/eslint-plugin' -import pluginReactHooks from 'eslint-plugin-react-hooks' -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - ...pluginReact.configs.recommended, - files: ['**/*.{ts,tsx}'], - }, - { - plugins: { - 'react-hooks': pluginReactHooks, - }, - rules: { - '@eslint-react/no-unstable-context-value': 'off', - '@eslint-react/no-unstable-default-props': 'off', - '@eslint-react/dom/no-missing-button-type': 'off', - 'react-hooks/exhaustive-deps': 'error', - 'react-hooks/rules-of-hooks': 'error', - }, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-config/package.json b/packages/start-config/package.json deleted file mode 100644 index 41edd37000..0000000000 --- a/packages/start-config/package.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "name": "@tanstack/start-config", - "version": "1.115.2", - "description": "Modern and scalable routing for React applications", - "author": "Tanner Linsley", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/TanStack/router.git", - "directory": "packages/start-config" - }, - "homepage": "https://tanstack.com/start", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "keywords": [ - "react", - "location", - "router", - "routing", - "async", - "async router", - "typescript" - ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "build": "tsc", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0;vitest", - "test:eslint": "eslint ./src", - "test:types": "exit 0; vitest" - }, - "type": "module", - "types": "dist/esm/index.d.ts", - "exports": { - ".": { - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - } - }, - "./package.json": "./package.json" - }, - "sideEffects": false, - "files": [ - "dist", - "src" - ], - "engines": { - "node": ">=12" - }, - "dependencies": { - "@tanstack/react-router": "workspace:^", - "@tanstack/router-generator": "workspace:^", - "@tanstack/router-plugin": "workspace:^", - "@tanstack/server-functions-plugin": "workspace:^", - "@tanstack/react-start-plugin": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", - "@vitejs/plugin-react": "^4.3.4", - "import-meta-resolve": "^4.1.0", - "nitropack": "^2.10.4", - "ofetch": "^1.4.1", - "vite": "^6.1.0", - "vinxi": "0.5.3", - "zod": "^3.24.2" - }, - "peerDependencies": { - "react": ">=18.0.0 || >=19.0.0", - "react-dom": ">=18.0.0 || >=19.0.0", - "vite": "^6.0.0" - } -} diff --git a/packages/start-config/src/index.ts b/packages/start-config/src/index.ts deleted file mode 100644 index 60043bfa9c..0000000000 --- a/packages/start-config/src/index.ts +++ /dev/null @@ -1,665 +0,0 @@ -import path from 'node:path' -import { existsSync, readFileSync } from 'node:fs' -import { readFile } from 'node:fs/promises' -import { fileURLToPath } from 'node:url' -import viteReact from '@vitejs/plugin-react' -import { resolve } from 'import-meta-resolve' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import { getConfig } from '@tanstack/router-generator' -import { createApp } from 'vinxi' -import { config } from 'vinxi/plugins/config' -// // @ts-expect-error -// import { serverComponents } from '@vinxi/server-components/plugin' -import { createTanStackServerFnPlugin } from '@tanstack/server-functions-plugin' -import { createTanStackStartPlugin } from '@tanstack/react-start-plugin' -import { createFetch } from 'ofetch' -import { createNitro } from 'nitropack' -import { tanstackStartVinxiFileRouter } from './vinxi-file-router.js' -import { - checkDeploymentPresetInput, - getUserViteConfig, - inlineConfigSchema, - serverSchema, -} from './schema.js' -import type { configSchema } from '@tanstack/router-generator' -import type { z } from 'zod' -import type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' -import type { App as VinxiApp } from 'vinxi' -import type { Manifest } from '@tanstack/react-router' -import type * as vite from 'vite' - -export type { - TanStackStartInputConfig, - TanStackStartOutputConfig, -} from './schema.js' - -function setTsrDefaults(config: TanStackStartOutputConfig['tsr']) { - // Normally these are `./src/___`, but we're using `./app/___` for Start stuff - const appDirectory = config?.appDirectory ?? './app' - return { - ...config, - appDirectory: config?.appDirectory ?? appDirectory, - routesDirectory: - config?.routesDirectory ?? path.join(appDirectory, 'routes'), - generatedRouteTree: - config?.generatedRouteTree ?? path.join(appDirectory, 'routeTree.gen.ts'), - } -} - -function mergeSsrOptions(options: Array) { - let ssrOptions: vite.SSROptions = {} - let noExternal: vite.SSROptions['noExternal'] = [] - for (const option of options) { - if (!option) { - continue - } - - if (option.noExternal) { - if (option.noExternal === true) { - noExternal = true - } else if (noExternal !== true) { - if (Array.isArray(option.noExternal)) { - noExternal.push(...option.noExternal) - } else { - noExternal.push(option.noExternal) - } - } - } - - ssrOptions = { - ...ssrOptions, - ...option, - noExternal, - } - } - - return ssrOptions -} - -export async function defineConfig( - inlineConfig: TanStackStartInputConfig = {}, -): Promise { - const opts = inlineConfigSchema.parse(inlineConfig) - - const { preset: configDeploymentPreset, ...serverOptions } = - serverSchema.parse(opts.server || {}) - - const deploymentPreset = checkDeploymentPresetInput( - configDeploymentPreset || 'node-server', - ) - const tsr = setTsrDefaults(opts.tsr) - const tsrConfig = getConfig(tsr) - - const appDirectory = tsr.appDirectory - const publicDir = opts.routers?.public?.dir || './public' - - const publicBase = opts.routers?.public?.base || '/' - const clientBase = opts.routers?.client?.base || '/_build' - const apiBase = opts.tsr?.apiBase || '/api' - const serverBase = opts.routers?.server?.base || '/_server' - - const apiMiddleware = opts.routers?.api?.middleware || undefined - const serverMiddleware = opts.routers?.server?.middleware || undefined - const ssrMiddleware = opts.routers?.ssr?.middleware || undefined - - const clientEntry = - opts.routers?.client?.entry || path.join(appDirectory, 'client.tsx') - const ssrEntry = - opts.routers?.ssr?.entry || path.join(appDirectory, 'ssr.tsx') - const apiEntry = opts.routers?.api?.entry || path.join(appDirectory, 'api.ts') - const globalMiddlewareEntry = - opts.routers?.server?.globalMiddlewareEntry || - path.join(appDirectory, 'global-middleware.ts') - const apiEntryExists = existsSync(apiEntry) - - const viteConfig = getUserViteConfig(opts.vite) - - const TanStackServerFnsPlugin = createTanStackServerFnPlugin({ - // This is the ID that will be available to look up and import - // our server function manifest and resolve its module - manifestVirtualImportId: 'tsr:server-fn-manifest', - client: { - getRuntimeCode: () => - `import { createClientRpc } from '@tanstack/start/server-functions-client'`, - replacer: (opts) => - `createClientRpc('${opts.functionId}', '${serverBase}')`, - }, - ssr: { - getRuntimeCode: () => - `import { createSsrRpc } from '@tanstack/start/server-functions-ssr'`, - replacer: (opts) => `createSsrRpc('${opts.functionId}', '${serverBase}')`, - }, - server: { - getRuntimeCode: () => - `import { createServerRpc } from '@tanstack/start/server-functions-server'`, - replacer: (opts) => - `createServerRpc('${opts.functionId}', '${serverBase}', ${opts.fn})`, - }, - }) - - const TanStackStartPlugin = createTanStackStartPlugin({ - globalMiddlewareEntry, - }) - - // Create a dummy nitro app to get the resolved public output path - const dummyNitroApp = await createNitro({ - preset: deploymentPreset, - compatibilityDate: '2024-12-01', - }) - - const nitroOutputPublicDir = dummyNitroApp.options.output.publicDir - await dummyNitroApp.close() - - let vinxiApp = createApp({ - server: { - ...serverOptions, - preset: deploymentPreset, - experimental: { - ...serverOptions.experimental, - asyncContext: true, - }, - }, - routers: [ - { - name: 'public', - type: 'static', - dir: publicDir, - base: publicBase, - }, - { - name: 'client', - type: 'client', - target: 'browser', - handler: clientEntry, - base: clientBase, - // @ts-expect-error - build: { - sourcemap: true, - }, - plugins: () => { - const routerType = 'client' - const clientViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-client', { - ...viteConfig.userConfig, - ...clientViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(clientViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - clientViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(clientViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: true, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.client, - TanStackServerFnsPlugin.client, - ...(viteConfig.plugins || []), - ...(clientViteConfig.plugins || []), - viteReact(opts.react), - // TODO: RSCS - enable this - // serverComponents.client(), - ] - }, - }, - { - name: 'ssr', - type: 'http', - target: 'server', - handler: ssrEntry, - middleware: ssrMiddleware, - // @ts-expect-error - link: { - client: 'client', - }, - plugins: () => { - const routerType = 'ssr' - const ssrViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-ssr', { - ...viteConfig.userConfig, - ...ssrViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(ssrViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - ssrViteConfig.userConfig.ssr, - { - noExternal, - external: ['@vinxi/react-server-dom/client'], - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(ssrViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.ssr, - TanStackServerFnsPlugin.ssr, - tsrRoutesManifest({ - tsrConfig, - clientBase, - }), - ...(getUserViteConfig(opts.vite).plugins || []), - ...(getUserViteConfig(opts.routers?.ssr?.vite).plugins || []), - viteReact(opts.react), - ] - }, - }, - { - name: 'server', - type: 'http', - target: 'server', - base: serverBase, - middleware: serverMiddleware, - // TODO: RSCS - enable this - // worker: true, - handler: importToProjectRelative( - '@tanstack/start-server-functions-handler', - ), - plugins: () => { - const routerType = 'server' - const serverViteConfig = getUserViteConfig( - opts.routers?.[routerType]?.vite, - ) - - return [ - config('tss-vite-config-server', { - ...viteConfig.userConfig, - ...serverViteConfig.userConfig, - define: { - ...(viteConfig.userConfig.define || {}), - ...(serverViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_SERVER_FN_BASE', serverBase), - ...injectDefineEnv( - 'TSS_OUTPUT_PUBLIC_DIR', - nitroOutputPublicDir, - ), - }, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - serverViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(serverViteConfig.userConfig.optimizeDeps || {}), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - TanStackStartPlugin.server, - TanStackServerFnsPlugin.server, - // TODO: RSCS - remove this - // resolve: { - // conditions: [], - // }, - // TODO: RSCs - add this - // serverComponents.serverActions({ - // resolve: { - // conditions: [ - // 'react-server', - // // 'node', - // 'import', - // process.env.NODE_ENV, - // ], - // }, - // runtime: '@vinxi/react-server-dom/runtime', - // transpileDeps: ['react', 'react-dom', '@vinxi/react-server-dom'], - // }), - ...(viteConfig.plugins || []), - ...(serverViteConfig.plugins || []), - ] - }, - }, - ], - }) - - const noExternal = [ - '@tanstack/start', - '@tanstack/react-start', - '@tanstack/react-start/server', - '@tanstack/react-start-client', - '@tanstack/react-start-server', - '@tanstack/start-server-functions-fetcher', - '@tanstack/start-server-functions-handler', - '@tanstack/start-server-functions-client', - '@tanstack/start-server-functions-ssr', - '@tanstack/start-server-functions-server', - '@tanstack/react-start-router-manifest', - '@tanstack/start-config', - '@tanstack/start-api-routes', - '@tanstack/server-functions-plugin', - 'tsr:routes-manifest', - 'tsr:server-fn-manifest', - ] - - // If API routes handler exists, add a router for it - if (apiEntryExists) { - vinxiApp = vinxiApp.addRouter({ - name: 'api', - type: 'http', - target: 'server', - base: apiBase, - handler: apiEntry, - middleware: apiMiddleware, - routes: tanstackStartVinxiFileRouter({ tsrConfig, apiBase }), - plugins: () => { - const viteConfig = getUserViteConfig(opts.vite) - const apiViteConfig = getUserViteConfig(opts.routers?.api?.vite) - - return [ - config('tsr-vite-config-api', { - ...viteConfig.userConfig, - ...apiViteConfig.userConfig, - ssr: mergeSsrOptions([ - viteConfig.userConfig.ssr, - apiViteConfig.userConfig.ssr, - { - noExternal, - }, - ]), - optimizeDeps: { - entries: [], - ...(viteConfig.userConfig.optimizeDeps || {}), - ...(apiViteConfig.userConfig.optimizeDeps || {}), - }, - define: { - ...(viteConfig.userConfig.define || {}), - ...(apiViteConfig.userConfig.define || {}), - ...injectDefineEnv('TSS_PUBLIC_BASE', publicBase), - ...injectDefineEnv('TSS_CLIENT_BASE', clientBase), - ...injectDefineEnv('TSS_API_BASE', apiBase), - ...injectDefineEnv('TSS_OUTPUT_PUBLIC_DIR', nitroOutputPublicDir), - }, - }), - TanStackRouterVite({ - ...tsrConfig, - enableRouteGeneration: false, - autoCodeSplitting: true, - __enableAPIRoutesGeneration: true, - experimental: { - ...tsrConfig.experimental, - }, - }), - ...(viteConfig.plugins || []), - ...(apiViteConfig.plugins || []), - ] - }, - }) - } - - // Because Vinxi doesn't use the normal nitro dev server, it doesn't - // supply $fetch during dev. We need to hook into the dev server creation, - // nab the proper utils from the custom nitro instance that is used - // during dev and supply the $fetch to app. - // Hopefully and likely, this will just get removed when we move to - // Nitro directly. - vinxiApp.hooks.hook('app:dev:nitro:config', (devServer) => { - vinxiApp.hooks.hook( - 'app:dev:server:created', - ({ devApp: { localFetch } }) => { - const $fetch = createFetch({ - fetch: localFetch, - defaults: { - baseURL: devServer.nitro.options.runtimeConfig.app.baseURL, - }, - }) - - // @ts-expect-error - globalThis.$fetch = $fetch - }, - ) - }) - - return vinxiApp -} - -function importToProjectRelative(p: string) { - const resolved = fileURLToPath(resolve(p, import.meta.url)) - - const relative = path.relative(process.cwd(), resolved) - - return relative -} - -function tsrRoutesManifest(opts: { - tsrConfig: z.infer - clientBase: string -}): vite.Plugin { - let config: vite.ResolvedConfig - - return { - name: 'tsr-routes-manifest', - configResolved(resolvedConfig) { - config = resolvedConfig - }, - resolveId(id) { - if (id === 'tsr:routes-manifest') { - return id - } - return - }, - async load(id) { - if (id === 'tsr:routes-manifest') { - // If we're in development, return a dummy manifest - - if (config.command === 'serve') { - return `export default () => ({ - routes: {} - })` - } - - const clientViteManifestPath = path.resolve( - config.build.outDir, - `../client/${opts.clientBase}/.vite/manifest.json`, - ) - - type ViteManifest = Record< - string, - { - file: string - isEntry: boolean - imports: Array - } - > - - let manifest: ViteManifest - try { - manifest = JSON.parse(await readFile(clientViteManifestPath, 'utf-8')) - } catch (err) { - console.error(err) - throw new Error( - `Could not find the production client vite manifest at '${clientViteManifestPath}'!`, - ) - } - - const routeTreePath = path.resolve(opts.tsrConfig.generatedRouteTree) - - let routeTreeContent: string - try { - routeTreeContent = readFileSync(routeTreePath, 'utf-8') - } catch (err) { - console.error(err) - throw new Error( - `Could not find the generated route tree at '${routeTreePath}'!`, - ) - } - - // Extract the routesManifest JSON from the route tree file. - // It's located between the /* ROUTE_MANIFEST_START and ROUTE_MANIFEST_END */ comment block. - - const routerManifest = JSON.parse( - routeTreeContent.match( - /\/\* ROUTE_MANIFEST_START([\s\S]*?)ROUTE_MANIFEST_END \*\//, - )?.[1] || '{ routes: {} }', - ) as Manifest - - const routes = routerManifest.routes - - let entryFile: - | { - file: string - imports: Array - } - | undefined - - const filesByRouteFilePath: ViteManifest = Object.fromEntries( - Object.entries(manifest).map(([k, v]) => { - if (v.isEntry) { - entryFile = v - } - - const rPath = k.split('?')[0] - - return [rPath, v] - }, {}), - ) - - // Add preloads to the routes from the vite manifest - Object.entries(routes).forEach(([k, v]) => { - const file = - filesByRouteFilePath[ - path.join(opts.tsrConfig.routesDirectory, v.filePath as string) - ] - - if (file) { - const preloads = file.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ) - - preloads.unshift(path.join(opts.clientBase, file.file)) - - routes[k] = { - ...v, - preloads, - } - } - }) - - if (entryFile) { - routes.__root__!.preloads = [ - path.join(opts.clientBase, entryFile.file), - ...entryFile.imports.map((d) => - path.join(opts.clientBase, manifest[d]!.file), - ), - ] - } - - const recurseRoute = ( - route: { - preloads?: Array - children?: Array - }, - seenPreloads = {} as Record, - ) => { - route.preloads = route.preloads?.filter((preload) => { - if (seenPreloads[preload]) { - return false - } - seenPreloads[preload] = true - return true - }) - - if (route.children) { - route.children.forEach((child) => { - const childRoute = routes[child]! - recurseRoute(childRoute, { ...seenPreloads }) - }) - } - } - - // @ts-expect-error - recurseRoute(routes.__root__) - - const routesManifest = { - routes, - } - - if (process.env.TSR_VITE_DEBUG) { - console.info( - 'Routes Manifest: \n' + JSON.stringify(routesManifest, null, 2), - ) - } - - return `export default () => (${JSON.stringify(routesManifest)})` - } - return - }, - } -} - -function injectDefineEnv( - key: TKey, - value: TValue, -): { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } { - return { - [`process.env.${key}`]: JSON.stringify(value), - [`import.meta.env.${key}`]: JSON.stringify(value), - } as { [P in `process.env.${TKey}` | `import.meta.env.${TKey}`]: TValue } -} diff --git a/packages/start-config/src/schema.ts b/packages/start-config/src/schema.ts deleted file mode 100644 index 516e4e86fa..0000000000 --- a/packages/start-config/src/schema.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { configSchema } from '@tanstack/router-generator' -import { z } from 'zod' -import type { PluginOption } from 'vite' -import type { AppOptions as VinxiAppOptions } from 'vinxi' -import type { NitroOptions } from 'nitropack' -import type { Options as ViteReactOptions } from '@vitejs/plugin-react' -import type { CustomizableConfig } from 'vinxi/dist/types/lib/vite-dev' - -type StartUserViteConfig = CustomizableConfig | (() => CustomizableConfig) - -export function getUserViteConfig(config?: StartUserViteConfig): { - plugins: Array | undefined - userConfig: CustomizableConfig -} { - const { plugins, ...userConfig } = - typeof config === 'function' ? config() : { ...config } - return { plugins, userConfig } -} - -/** - * Not all the deployment presets are fully functional or tested. - * @see https://github.com/TanStack/router/pull/2002 - */ -const vinxiDeploymentPresets = [ - 'alwaysdata', // untested - 'aws-amplify', // untested - 'aws-lambda', // untested - 'azure', // untested - 'azure-functions', // untested - 'base-worker', // untested - 'bun', // ✅ working - 'cleavr', // untested - 'cli', // untested - 'cloudflare', // untested - 'cloudflare-module', // untested - 'cloudflare-pages', // ✅ working - 'cloudflare-pages-static', // untested - 'deno', // untested - 'deno-deploy', // untested - 'deno-server', // untested - 'digital-ocean', // untested - 'edgio', // untested - 'firebase', // untested - 'flight-control', // untested - 'github-pages', // untested - 'heroku', // untested - 'iis', // untested - 'iis-handler', // untested - 'iis-node', // untested - 'koyeb', // untested - 'layer0', // untested - 'netlify', // ✅ working - 'netlify-builder', // untested - 'netlify-edge', // untested - 'netlify-static', // untested - 'nitro-dev', // untested - 'nitro-prerender', // untested - 'node', // partially working - 'node-cluster', // untested - 'node-server', // ✅ working - 'platform-sh', // untested - 'service-worker', // untested - 'static', // 🟧 partially working - 'stormkit', // untested - 'vercel', // ✅ working - 'vercel-edge', // untested - 'vercel-static', // untested - 'winterjs', // untested - 'zeabur', // untested - 'zeabur-static', // untested -] as const - -type DeploymentPreset = (typeof vinxiDeploymentPresets)[number] | (string & {}) - -const testedDeploymentPresets: Array = [ - 'bun', - 'netlify', - 'vercel', - 'cloudflare-pages', - 'node-server', -] - -export function checkDeploymentPresetInput(preset: string): DeploymentPreset { - if (!vinxiDeploymentPresets.includes(preset as any)) { - console.warn( - `Invalid deployment preset "${preset}". Available presets are: ${vinxiDeploymentPresets - .map((p) => `"${p}"`) - .join(', ')}.`, - ) - } - - if (!testedDeploymentPresets.includes(preset as any)) { - console.warn( - `The deployment preset '${preset}' is not fully supported yet and may not work as expected.`, - ) - } - - return preset -} - -type HTTPSOptions = { - cert?: string - key?: string - pfx?: string - passphrase?: string - validityDays?: number - domains?: Array -} - -type ServerOptions_ = VinxiAppOptions['server'] & { - https?: boolean | HTTPSOptions -} - -type ServerOptions = { - [K in keyof ServerOptions_]: ServerOptions_[K] -} - -export const serverSchema = z - .object({ - routeRules: z.custom().optional(), - preset: z.custom().optional(), - static: z.boolean().optional(), - prerender: z - .object({ - routes: z.array(z.string()), - ignore: z - .array( - z.custom< - string | RegExp | ((path: string) => undefined | null | boolean) - >(), - ) - .optional(), - crawlLinks: z.boolean().optional(), - }) - .optional(), - }) - .and(z.custom()) - -const viteSchema = z.custom() - -const viteReactSchema = z.custom() - -const routersSchema = z.object({ - ssr: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - client: z - .object({ - entry: z.string().optional(), - base: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - server: z - .object({ - base: z.string().optional(), - globalMiddlewareEntry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - api: z - .object({ - entry: z.string().optional(), - middleware: z.string().optional(), - vite: viteSchema.optional(), - }) - .optional(), - public: z - .object({ - dir: z.string().optional(), - base: z.string().optional(), - }) - .optional(), -}) - -const tsrConfig = configSchema.partial().extend({ - appDirectory: z.string().optional(), -}) - -export const inlineConfigSchema = z.object({ - react: viteReactSchema.optional(), - vite: viteSchema.optional(), - tsr: tsrConfig.optional(), - routers: routersSchema.optional(), - server: serverSchema.optional(), -}) - -export type TanStackStartInputConfig = z.input -export type TanStackStartOutputConfig = z.infer diff --git a/packages/start-config/src/vinxi-file-router.ts b/packages/start-config/src/vinxi-file-router.ts deleted file mode 100644 index 9e6d829d1b..0000000000 --- a/packages/start-config/src/vinxi-file-router.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - BaseFileSystemRouter as VinxiBaseFileSystemRouter, - analyzeModule as vinxiFsRouterAnalyzeModule, - cleanPath as vinxiFsRouterCleanPath, -} from 'vinxi/fs-router' -import { - CONSTANTS as GENERATOR_CONSTANTS, - startAPIRouteSegmentsFromTSRFilePath, -} from '@tanstack/router-generator' -import type { configSchema } from '@tanstack/router-generator' -import type { - AppOptions as VinxiAppOptions, - RouterSchemaInput as VinxiRouterSchemaInput, -} from 'vinxi' -import type { z } from 'zod' - -export function tanstackStartVinxiFileRouter(opts: { - tsrConfig: z.infer - apiBase: string -}) { - const apiBaseSegment = opts.apiBase.split('/').filter(Boolean).join('/') - const isAPIPath = new RegExp(`/${apiBaseSegment}/`) - - return function (router: VinxiRouterSchemaInput, app: VinxiAppOptions) { - // Our own custom File Router that extends the VinxiBaseFileSystemRouter - // for splitting the API routes into its own "bundle" - // and adding the $APIRoute metadata to the route object - // This could be customized in future to support more complex splits - class TanStackStartFsRouter extends VinxiBaseFileSystemRouter { - toPath(src: string): string { - const inputPath = vinxiFsRouterCleanPath(src, this.config) - - const segments = startAPIRouteSegmentsFromTSRFilePath( - inputPath, - opts.tsrConfig, - ) - - const pathname = segments - .map((part) => { - if (part.type === 'splat') { - return `*splat` - } - - if (part.type === 'param') { - return `:${part.value}?` - } - - return part.value - }) - .join('/') - - return pathname.length > 0 ? `/${pathname}` : '/' - } - - toRoute(src: string) { - const webPath = this.toPath(src) - - const [_, exports] = vinxiFsRouterAnalyzeModule(src) - - const hasAPIRoute = exports.find( - (exp) => exp.n === GENERATOR_CONSTANTS.APIRouteExportVariable, - ) - - return { - path: webPath, - filePath: src, - $APIRoute: - isAPIPath.test(webPath) && hasAPIRoute - ? { - src, - pick: [GENERATOR_CONSTANTS.APIRouteExportVariable], - } - : undefined, - } - } - } - - return new TanStackStartFsRouter( - { - dir: opts.tsrConfig.routesDirectory, - extensions: ['js', 'jsx', 'ts', 'tsx'], - }, - router, - app, - ) - } -} diff --git a/packages/start-config/tsconfig.json b/packages/start-config/tsconfig.json deleted file mode 100644 index 940a9cce0a..0000000000 --- a/packages/start-config/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": ["src/index.ts"], - "compilerOptions": { - "rootDir": "src", - "outDir": "dist/esm", - "target": "esnext", - "noEmit": false - } -} diff --git a/packages/start-plugin-core/eslint.config.js b/packages/start-plugin-core/eslint.config.js new file mode 100644 index 0000000000..8ce6ad05fc --- /dev/null +++ b/packages/start-plugin-core/eslint.config.js @@ -0,0 +1,5 @@ +// @ts-check + +import rootConfig from '../../eslint.config.js' + +export default [...rootConfig] diff --git a/packages/start-server-functions-handler/package.json b/packages/start-plugin-core/package.json similarity index 61% rename from packages/start-server-functions-handler/package.json rename to packages/start-plugin-core/package.json index 0bc0da8cf9..6262282cb2 100644 --- a/packages/start-server-functions-handler/package.json +++ b/packages/start-plugin-core/package.json @@ -1,13 +1,13 @@ { - "name": "@tanstack/start-server-functions-handler", - "version": "1.115.1", - "description": "Modern and scalable routing for applications", + "name": "@tanstack/start-plugin-core", + "version": "1.114.12", + "description": "Modern and scalable routing for Solid applications", "author": "Tanner Linsley", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/TanStack/router.git", - "directory": "packages/start-server-functions-handler" + "directory": "packages/start-plugin-core" }, "homepage": "https://tanstack.com/start", "funding": { @@ -15,7 +15,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "keywords": [ - "react", + "solid", "location", "router", "routing", @@ -25,8 +25,9 @@ ], "scripts": { "clean": "rimraf ./dist && rimraf ./coverage", + "clean:snapshots": "rimraf **/*snapshot* --glob", "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", + "test:unit": "vitest", "test:eslint": "eslint ./src", "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", @@ -40,6 +41,8 @@ }, "type": "module", "types": "dist/esm/index.d.ts", + "main": "dist/cjs/index.cjs", + "module": "dist/esm/index.js", "exports": { ".": { "import": { @@ -62,12 +65,24 @@ "node": ">=12" }, "dependencies": { - "@tanstack/router-core": "workspace:^", - "@tanstack/start-client-core": "workspace:^", - "@tanstack/start-server-core": "workspace:^", - "tiny-invariant": "^1.3.3" - }, - "devDependencies": { - "typescript": "^5.7.2" + "@babel/code-frame": "7.26.2", + "@babel/core": "^7.26.8", + "@babel/plugin-syntax-typescript": "^7.25.9", + "@babel/template": "^7.26.8", + "@babel/traverse": "^7.26.8", + "@babel/types": "^7.26.8", + "@tanstack/router-generator": "workspace:^", + "@tanstack/router-utils": "workspace:^", + "@types/babel__code-frame": "^7.0.6", + "@types/babel__core": "^7.20.5", + "@types/babel__template": "^7.4.4", + "@types/babel__traverse": "^7.20.6", + "babel-dead-code-elimination": "^1.0.9", + "import-meta-resolve": "^4.1.0", + "nitropack": "^2.11.8", + "tiny-invariant": "^1.3.3", + "vite": "6.1.5", + "xmlbuilder2": "^3.1.1", + "zod": "^3.24.2" } } diff --git a/packages/start-plugin-core/src/compilers.ts b/packages/start-plugin-core/src/compilers.ts new file mode 100644 index 0000000000..a9d53b8fcc --- /dev/null +++ b/packages/start-plugin-core/src/compilers.ts @@ -0,0 +1,763 @@ +import * as babel from '@babel/core' +import * as t from '@babel/types' +import { codeFrameColumns } from '@babel/code-frame' + +import { + deadCodeElimination, + findReferencedIdentifiers, +} from 'babel-dead-code-elimination' +import { generateFromAst, parseAst } from '@tanstack/router-utils' +import type { GeneratorResult, ParseAstOptions } from '@tanstack/router-utils' + +type CompileStartFrameworkOptions = 'react' | 'solid' + +export function compileStartOutputFactory( + framework: CompileStartFrameworkOptions, +) { + return function compileStartOutput(opts: CompileOptions): GeneratorResult { + const ast = parseAst(opts) + + const doDce = opts.dce ?? true + // find referenced identifiers *before* we transform anything + const refIdents = doDce ? findReferencedIdentifiers(ast) : undefined + + babel.traverse(ast, { + Program: { + enter(programPath) { + const identifiers: { + createServerFileRoute: IdentifierConfig + createServerFn: IdentifierConfig + createMiddleware: IdentifierConfig + serverOnly: IdentifierConfig + clientOnly: IdentifierConfig + createIsomorphicFn: IdentifierConfig + } = { + createServerFileRoute: { + name: 'createServerFileRoute', + handleCallExpression: + handleCreateServerFileRouteCallExpressionFactory(framework), + paths: [], + }, + createServerFn: { + name: 'createServerFn', + handleCallExpression: handleCreateServerFnCallExpression, + paths: [], + }, + createMiddleware: { + name: 'createMiddleware', + handleCallExpression: handleCreateMiddlewareCallExpression, + paths: [], + }, + serverOnly: { + name: 'serverOnly', + handleCallExpression: handleServerOnlyCallExpression, + paths: [], + }, + clientOnly: { + name: 'clientOnly', + handleCallExpression: handleClientOnlyCallExpression, + paths: [], + }, + createIsomorphicFn: { + name: 'createIsomorphicFn', + handleCallExpression: handleCreateIsomorphicFnCallExpression, + paths: [], + }, + } + + const identifierKeys = Object.keys(identifiers) as Array< + keyof typeof identifiers + > + + programPath.traverse({ + ImportDeclaration: (path) => { + if ( + path.node.source.value !== '@tanstack/react-start' && + path.node.source.value !== '@tanstack/solid-start' + ) { + return + } + + // handle a destructured imports being renamed like "import { createServerFn as myCreateServerFn } from '@tanstack/react-start';" + path.node.specifiers.forEach((specifier) => { + identifierKeys.forEach((identifierKey) => { + const identifier = identifiers[identifierKey] + + if ( + specifier.type === 'ImportSpecifier' && + specifier.imported.type === 'Identifier' + ) { + if (specifier.imported.name === identifierKey) { + identifier.name = specifier.local.name + } + } + + // handle namespace imports like "import * as TanStackStart from '@tanstack/react-start';" + if (specifier.type === 'ImportNamespaceSpecifier') { + identifier.name = `${specifier.local.name}.${identifierKey}` + } + }) + }) + }, + CallExpression: (path) => { + identifierKeys.forEach((identifierKey) => { + // Check to see if the call expression is a call to the + // identifiers[identifierKey].name + if ( + t.isIdentifier(path.node.callee) && + path.node.callee.name === identifiers[identifierKey].name + ) { + // The identifier could be a call to the original function + // in the source code. If this is case, we need to ignore it. + // Check the scope to see if the identifier is a function declaration. + // if it is, then we can ignore it. + + if ( + path.scope.getBinding(identifiers[identifierKey].name)?.path + .node.type === 'FunctionDeclaration' + ) { + return + } + + return identifiers[identifierKey].paths.push(path) + } + + if (t.isMemberExpression(path.node.callee)) { + if ( + t.isIdentifier(path.node.callee.object) && + t.isIdentifier(path.node.callee.property) + ) { + const callname = [ + path.node.callee.object.name, + path.node.callee.property.name, + ].join('.') + + if (callname === identifiers[identifierKey].name) { + identifiers[identifierKey].paths.push(path) + } + } + } + + return + }) + }, + }) + + identifierKeys.forEach((identifierKey) => { + identifiers[identifierKey].paths.forEach((path) => { + identifiers[identifierKey].handleCallExpression( + path as babel.NodePath, + opts, + ) + }) + }) + }, + }, + }) + + if (doDce) { + deadCodeElimination(ast, refIdents) + } + + return generateFromAst(ast, { + sourceMaps: true, + sourceFileName: opts.filename, + filename: opts.filename, + }) + } +} + +function handleCreateServerFileRouteCallExpressionFactory( + factory: CompileStartFrameworkOptions, +) { + return function handleCreateServerFileRouteCallExpression( + path: babel.NodePath, + opts: CompileOptions, + ) { + const PACKAGES = { start: `@tanstack/${factory}-start` } + + let highestParent: babel.NodePath = path + + while (highestParent.parentPath && !highestParent.parentPath.isProgram()) { + highestParent = highestParent.parentPath + } + + const programPath = highestParent.parentPath as babel.NodePath + + // Find the root call expression and all of the methods that are called on it + const rootCallExpression = getRootCallExpression(path) + + const callExpressionPaths = { + validator: null as babel.NodePath | null, + middleware: null as babel.NodePath | null, + methods: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + const manifest = { middleware: false, methods: {} as any } + + Object.entries(callExpressionPaths).forEach(([key, callPath]) => { + if (callPath && t.isMemberExpression(callPath.node.callee)) { + if (key === 'middleware') { + manifest.middleware = true + } else if (key === 'methods') { + // Get the methods object from the methods call + const methodsArg = callPath.node.arguments[0] + + // Handle the case where methods is a function that returns an object + if ( + t.isArrowFunctionExpression(methodsArg) && + t.isObjectExpression(methodsArg.body) + ) { + methodsArg.body.properties.forEach((prop) => { + if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + const methodName = prop.key.name + manifest.methods[methodName] = { + validator: false, + middleware: false, + } + + // Check if this method has a validator or middleware + if (t.isCallExpression(prop.value)) { + const method = prop.value + method.arguments.forEach((arg) => { + if (t.isObjectExpression(arg)) { + arg.properties.forEach((methodProp) => { + if ( + t.isObjectProperty(methodProp) && + t.isIdentifier(methodProp.key) + ) { + if (methodProp.key.name === 'validator') { + manifest.methods[methodName].validator = true + } + if (methodProp.key.name === 'middleware') { + manifest.methods[methodName].middleware = true + } + } + }) + } + }) + } + } + }) + } + // Handle the case where methods is a direct object + else if (t.isObjectExpression(methodsArg)) { + methodsArg.properties.forEach((prop) => { + if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) { + const methodName = prop.key.name + manifest.methods[methodName] = { + validator: false, + middleware: false, + } + } + }) + } + } + + if (opts.env === 'client') { + callPath.replaceWith(callPath.node.callee.object) + } + } + }) + + console.debug('createServerFileRoute -> manifest:\n', manifest) + + path.replaceWith( + t.callExpression(t.identifier('createServerFileRoute'), [ + t.identifier('undefined'), + t.callExpression( + t.memberExpression(t.identifier('Object'), t.identifier('assign')), + [ + t.objectExpression( + path.node.arguments + .map((arg) => { + if (t.isIdentifier(arg)) { + return t.objectProperty(t.identifier(arg.name), arg) + } + // Handle other cases or return a default value if necessary + return null // or throw an error, or handle accordingly + }) + .filter( + (property): property is t.ObjectProperty => property !== null, + ), + ), + t.objectExpression([ + t.objectProperty( + t.identifier('manifest'), + t.valueToNode(manifest), + ), + ]), + ], + ), + ]), + ) + + let isCreateServerFileRouteImported = false as boolean + + programPath.traverse({ + ImportDeclaration(importPath) { + const importSource = importPath.node.source.value + if (importSource === PACKAGES.start) { + const specifiers = importPath.node.specifiers + isCreateServerFileRouteImported = specifiers.some((specifier) => { + return ( + t.isImportSpecifier(specifier) && + t.isIdentifier(specifier.imported) && + specifier.imported.name === 'createServerFileRoute' + ) + }) + } + }, + }) + + if (!isCreateServerFileRouteImported) { + const importDeclaration = t.importDeclaration( + [ + t.importSpecifier( + t.identifier('createServerFileRoute'), + t.identifier('createServerFileRoute'), + ), + ], + t.stringLiteral(PACKAGES.start), + ) + programPath.node.body.unshift(importDeclaration) + } + } +} + +// build these once and reuse them +export const handleServerOnlyCallExpression = + buildEnvOnlyCallExpressionHandler('server') +export const handleClientOnlyCallExpression = + buildEnvOnlyCallExpressionHandler('client') + +export type CompileOptions = ParseAstOptions & { + env: 'server' | 'client' | 'ssr' + dce?: boolean + filename: string +} + +export type IdentifierConfig = { + name: string + handleCallExpression: ( + path: babel.NodePath, + opts: CompileOptions, + ) => void + paths: Array +} + +export function handleCreateServerFnCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + // The function is the 'fn' property of the object passed to createServerFn + + // const firstArg = path.node.arguments[0] + // if (t.isObjectExpression(firstArg)) { + // // Was called with some options + // } + + // Traverse the member expression and find the call expressions for + // the validator, handler, and middleware methods. Check to make sure they + // are children of the createServerFn call expression. + + const calledOptions = path.node.arguments[0] + ? (path.get('arguments.0') as babel.NodePath) + : null + + const shouldValidateClient = !!calledOptions?.node.properties.find((prop) => { + return ( + t.isObjectProperty(prop) && + t.isIdentifier(prop.key) && + prop.key.name === 'validateClient' && + t.isBooleanLiteral(prop.value) && + prop.value.value === true + ) + }) + + const callExpressionPaths = { + middleware: null as babel.NodePath | null, + validator: null as babel.NodePath | null, + handler: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createServerFn call expression:', + // rootCallExpression.toString(), + // ) + + // Check if the call is assigned to a variable + if (!rootCallExpression.parentPath.isVariableDeclarator()) { + throw new Error('createServerFn must be assigned to a variable!') + } + + // Get the identifier name of the variable + const variableDeclarator = rootCallExpression.parentPath.node + const existingVariableName = (variableDeclarator.id as t.Identifier).name + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if (callExpressionPaths.validator) { + const innerInputExpression = callExpressionPaths.validator.node.arguments[0] + + if (!innerInputExpression) { + throw new Error( + 'createServerFn().validator() must be called with a validator!', + ) + } + + // If we're on the client, and we're not validating the client, remove the validator call expression + if ( + opts.env === 'client' && + !shouldValidateClient && + t.isMemberExpression(callExpressionPaths.validator.node.callee) + ) { + callExpressionPaths.validator.replaceWith( + callExpressionPaths.validator.node.callee.object, + ) + } + } + + // First, we need to move the handler function to a nested function call + // that is applied to the arguments passed to the server function. + + const handlerFnPath = callExpressionPaths.handler?.get( + 'arguments.0', + ) as babel.NodePath + + if (!callExpressionPaths.handler || !handlerFnPath.node) { + throw codeFrameError( + opts.code, + path.node.callee.loc!, + `createServerFn must be called with a "handler" property!`, + ) + } + + const handlerFn = handlerFnPath.node + + // So, the way we do this is we give the handler function a way + // to access the serverFn ctx on the server via function scope. + // The 'use server' extracted function will be called with the + // payload from the client, then use the scoped serverFn ctx + // to execute the handler function. + // This way, we can do things like data and middleware validation + // in the __execute function without having to AST transform the + // handler function too much itself. + + // .handler((optsOut, ctx) => { + // return ((optsIn) => { + // 'use server' + // ctx.__execute(handlerFn, optsIn) + // })(optsOut) + // }) + + // If the handler function is an identifier and we're on the client, we need to + // remove the bound function from the file. + // If we're on the server, you can leave it, since it will get referenced + // as a second argument. + + if (t.isIdentifier(handlerFn)) { + if (opts.env === 'client' || opts.env === 'ssr') { + // Find the binding for the handler function + const binding = handlerFnPath.scope.getBinding(handlerFn.name) + // Remove it + if (binding) { + binding.path.remove() + } + } + // If the env is server, just leave it alone + } + + handlerFnPath.replaceWith( + t.arrowFunctionExpression( + [t.identifier('opts'), t.identifier('signal')], + t.blockStatement( + // Everything in here is server-only, since the client + // will strip out anything in the 'use server' directive. + [ + t.returnStatement( + t.callExpression( + t.identifier(`${existingVariableName}.__executeServer`), + [t.identifier('opts'), t.identifier('signal')], + ), + ), + ], + [t.directive(t.directiveLiteral('use server'))], + ), + ), + ) + + if (opts.env === 'server') { + callExpressionPaths.handler.node.arguments.push(handlerFn) + } +} + +export function handleCreateMiddlewareCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createMiddleware call expression:', + // rootCallExpression.toString(), + // ) + + const callExpressionPaths = { + middleware: null as babel.NodePath | null, + validator: null as babel.NodePath | null, + client: null as babel.NodePath | null, + server: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if (callExpressionPaths.validator) { + const innerInputExpression = callExpressionPaths.validator.node.arguments[0] + + if (!innerInputExpression) { + throw new Error( + 'createMiddleware().validator() must be called with a validator!', + ) + } + + // If we're on the client or ssr, remove the validator call expression + if (opts.env === 'client' || opts.env === 'ssr') { + if (t.isMemberExpression(callExpressionPaths.validator.node.callee)) { + callExpressionPaths.validator.replaceWith( + callExpressionPaths.validator.node.callee.object, + ) + } + } + } + + const serverFnPath = callExpressionPaths.server?.get( + 'arguments.0', + ) as babel.NodePath + + if ( + callExpressionPaths.server && + serverFnPath.node && + (opts.env === 'client' || opts.env === 'ssr') + ) { + // If we're on the client, remove the server call expression + if (t.isMemberExpression(callExpressionPaths.server.node.callee)) { + callExpressionPaths.server.replaceWith( + callExpressionPaths.server.node.callee.object, + ) + } + } +} + +function buildEnvOnlyCallExpressionHandler(env: 'client' | 'server') { + return function envOnlyCallExpressionHandler( + path: babel.NodePath, + opts: CompileOptions, + ) { + // if (debug) + // console.info(`Handling ${env}Only call expression:`, path.toString()) + + const isEnvMatch = + env === 'client' + ? opts.env === 'client' + : opts.env === 'server' || opts.env === 'ssr' + + if (isEnvMatch) { + // extract the inner function from the call expression + const innerInputExpression = path.node.arguments[0] + + if (!t.isExpression(innerInputExpression)) { + throw new Error( + `${env}Only() functions must be called with a function!`, + ) + } + + path.replaceWith(innerInputExpression) + return + } + + // If we're on the wrong environment, replace the call expression + // with a function that always throws an error. + path.replaceWith( + t.arrowFunctionExpression( + [], + t.blockStatement([ + t.throwStatement( + t.newExpression(t.identifier('Error'), [ + t.stringLiteral( + `${env}Only() functions can only be called on the ${env}!`, + ), + ]), + ), + ]), + ), + ) + } +} + +export function handleCreateIsomorphicFnCallExpression( + path: babel.NodePath, + opts: CompileOptions, +) { + const rootCallExpression = getRootCallExpression(path) + + // if (debug) + // console.info( + // 'Handling createIsomorphicFn call expression:', + // rootCallExpression.toString(), + // ) + + const callExpressionPaths = { + client: null as babel.NodePath | null, + server: null as babel.NodePath | null, + } + + const validMethods = Object.keys(callExpressionPaths) + + rootCallExpression.traverse({ + MemberExpression(memberExpressionPath) { + if (t.isIdentifier(memberExpressionPath.node.property)) { + const name = memberExpressionPath.node.property + .name as keyof typeof callExpressionPaths + + if ( + validMethods.includes(name) && + memberExpressionPath.parentPath.isCallExpression() + ) { + callExpressionPaths[name] = memberExpressionPath.parentPath + } + } + }, + }) + + if ( + validMethods.every( + (method) => + !callExpressionPaths[method as keyof typeof callExpressionPaths], + ) + ) { + const variableId = rootCallExpression.parentPath.isVariableDeclarator() + ? rootCallExpression.parentPath.node.id + : null + console.warn( + 'createIsomorphicFn called without a client or server implementation!', + 'This will result in a no-op function.', + 'Variable name:', + t.isIdentifier(variableId) ? variableId.name : 'unknown', + ) + } + + const resolvedEnv = opts.env === 'ssr' ? 'server' : opts.env + + const envCallExpression = callExpressionPaths[resolvedEnv] + + if (!envCallExpression) { + // if we don't have an implementation for this environment, default to a no-op + rootCallExpression.replaceWith( + t.arrowFunctionExpression([], t.blockStatement([])), + ) + return + } + + const innerInputExpression = envCallExpression.node.arguments[0] + + if (!t.isExpression(innerInputExpression)) { + throw new Error( + `createIsomorphicFn().${resolvedEnv}(func) must be called with a function!`, + ) + } + + rootCallExpression.replaceWith(innerInputExpression) +} + +export function getRootCallExpression(path: babel.NodePath) { + // Find the highest callExpression parent + let rootCallExpression: babel.NodePath = path + + // Traverse up the chain of CallExpressions + while (rootCallExpression.parentPath.isMemberExpression()) { + const parent = rootCallExpression.parentPath + if (parent.parentPath.isCallExpression()) { + rootCallExpression = parent.parentPath + } + } + + return rootCallExpression +} + +function codeFrameError( + code: string, + loc: { + start: { line: number; column: number } + end: { line: number; column: number } + }, + message: string, +) { + const frame = codeFrameColumns( + code, + { + start: loc.start, + end: loc.end, + }, + { + highlightCode: true, + message, + }, + ) + + return new Error(frame) +} diff --git a/packages/start-plugin-core/src/index.ts b/packages/start-plugin-core/src/index.ts new file mode 100644 index 0000000000..a68ec71b18 --- /dev/null +++ b/packages/start-plugin-core/src/index.ts @@ -0,0 +1,15 @@ +export type { CompileOptions, IdentifierConfig } from './compilers' + +export { compileStartOutputFactory } from './compilers' +export { Queue } from './queue' +export { buildNitroEnvironment } from './nitro/build-nitro' + +export type { PagesJson } from './nitro/build-sitemap' +export { buildSitemap } from './nitro/build-sitemap' + +export { + createTanStackConfig, + createTanStackStartOptionsSchema, + pageSchema +} from './schema' +export type { Page } from './schema' diff --git a/packages/start-plugin-core/src/nitro/build-nitro.ts b/packages/start-plugin-core/src/nitro/build-nitro.ts new file mode 100644 index 0000000000..e123499f4f --- /dev/null +++ b/packages/start-plugin-core/src/nitro/build-nitro.ts @@ -0,0 +1,60 @@ +import { promises as fsp } from 'node:fs' +import path from 'node:path' +import { version } from 'nitropack/meta' +import { copyPublicAssets, prepare } from 'nitropack' +import type { Nitro } from 'nitropack' + +export async function buildNitroEnvironment( + nitro: Nitro, + build: () => Promise, +) { + await prepare(nitro) + await copyPublicAssets(nitro) + await build() + + const presetsWithConfig = [ + 'awsAmplify', + 'awsLambda', + 'azure', + 'cloudflare', + 'firebase', + 'netlify', + 'vercel', + ] + + const buildInfo = { + date: /* @__PURE__ */ new Date().toJSON(), + preset: nitro.options.preset, + framework: nitro.options.framework, + versions: { + nitro: version, + }, + commands: { + preview: nitro.options.commands.preview, + deploy: nitro.options.commands.deploy, + }, + config: { + ...Object.fromEntries( + presetsWithConfig.map((key) => [key, (nitro.options as any)[key]]), + ), + }, + } + + const buildInfoPath = path.resolve(nitro.options.output.dir, 'nitro.json') + + await fsp.writeFile(buildInfoPath, JSON.stringify(buildInfo, null, 2)) + + const publicDir = nitro.options.output.publicDir + + // As a part of the build process, the `.vite/` directory + // is copied over from `node_modules/.tanstack-start/client-dist/` + // to the `publicDir` (e.g. `.output/public/`). + // This directory (containing the vite manifest) should not be + // included in the final build, so we remove it here. + const viteDir = path.resolve(publicDir, '.vite') + if (await fsp.stat(viteDir).catch(() => false)) { + await fsp.rm(viteDir, { recursive: true, force: true }) + } + + await nitro.close() +} diff --git a/packages/start-plugin-core/src/nitro/build-sitemap.ts b/packages/start-plugin-core/src/nitro/build-sitemap.ts new file mode 100644 index 0000000000..c06ed77d0e --- /dev/null +++ b/packages/start-plugin-core/src/nitro/build-sitemap.ts @@ -0,0 +1,79 @@ +import { writeFileSync } from 'node:fs' +import { resolve } from 'node:path' +import { create } from 'xmlbuilder2' +import type { XMLBuilder } from 'xmlbuilder2/lib/interfaces' + +export type PagesJson = { + page: string + lastMod: string +} + +export async function buildSitemap({ + host, + routes, + outputDir, +}: { + host: string + routes: Array | (() => Promise>) + outputDir: string +}) { + const routeList: Array = await optionHasRoutes(routes) + + if (routeList.length) { + const slash = checkSlash(host) + const sitemapData: Array = routeList.map((page: string) => ({ + page: `${host}${slash}${page.replace(/^\/+/g, '')}`, + lastMod: new Date().toISOString().split('T')[0]!, + })) + + const sitemap = createXml('urlset') + + for (const item of sitemapData) { + const page = sitemap.ele('url') + page.ele('loc').txt(item.page) + page.ele('lastmod').txt(item.lastMod) + } + + const mapPath = `${resolve(outputDir)}/sitemap.xml` + try { + console.log(`Writing sitemap at ${mapPath}`) + writeFileSync(mapPath, sitemap.end({ prettyPrint: true })) + } catch (e) { + console.error(`Unable to write file at ${mapPath}`, e) + } + } +} + +function createXml(elementName: 'urlset' | 'sitemapindex'): XMLBuilder { + return create({ version: '1.0', encoding: 'UTF-8' }) + .ele(elementName, { + xmlns: 'https://www.sitemaps.org/schemas/sitemap/0.9', + }) + .com(`This file was automatically generated by Analog.`) +} + +function checkSlash(host: string): string { + const finalChar = host.slice(-1) + return finalChar === '/' ? '' : '/' +} + +async function optionHasRoutes( + routes: + | Array + | (() => Promise>), +): Promise> { + let routeList: Array + + if (typeof routes === 'function') { + // returns an array or undefined + routeList = await routes() + } else if (Array.isArray(routes)) { + // returns an array of strings + routeList = routes + } else { + // default it to an empty of array + routeList = [] + } + + return routeList.filter(Boolean) as Array +} diff --git a/packages/start-plugin-core/src/queue.ts b/packages/start-plugin-core/src/queue.ts new file mode 100644 index 0000000000..279146fdb2 --- /dev/null +++ b/packages/start-plugin-core/src/queue.ts @@ -0,0 +1,153 @@ +interface PoolConfig { + concurrency?: number + started?: boolean + tasks?: Array<() => Promise> +} + +const defaultConfig: PoolConfig = { + concurrency: 5, + started: false, + tasks: [], +} + +export class Queue { + private onSettles: Array<(res: any, error: any) => void> = [] + private onErrors: Array<(error: any, task: () => Promise) => void> = [] + private onSuccesses: Array<(result: any, task: () => Promise) => void> = + [] + private running: boolean + private active: Array<() => Promise> = [] + private pending: Array<() => Promise> + private currentConcurrency: number + + constructor(config: PoolConfig = defaultConfig) { + const { concurrency, started, tasks } = { + ...defaultConfig, + ...config, + } + this.running = started! + this.pending = tasks as Array<() => Promise> + this.currentConcurrency = concurrency! + } + + private tick() { + if (!this.running) { + return + } + while ( + this.active.length < this.currentConcurrency && + this.pending.length + ) { + const nextFn = this.pending.shift() + if (!nextFn) { + throw new Error('Found task that is not a function') + } + this.active.push(nextFn) + ;(async () => { + let success = false + let res!: T + let error: any + try { + res = await nextFn() + success = true + } catch (e) { + error = e + } + this.active = this.active.filter((d) => d !== nextFn) + if (success) { + this.onSuccesses.forEach((d) => d(res, nextFn)) + } else { + this.onErrors.forEach((d) => d(error, nextFn)) + } + this.onSettles.forEach((d) => d(res, error)) + this.tick() + })() + } + } + + add(fn: () => Promise | T, { priority }: { priority?: boolean } = {}) { + return new Promise((resolve, reject) => { + const task = () => + Promise.resolve(fn()) + .then((res) => { + resolve(res) + return res + }) + .catch((err) => { + reject(err) + throw err + }) + if (priority) { + this.pending.unshift(task) + } else { + this.pending.push(task) + } + this.tick() + }) + } + + throttle(n: number) { + this.currentConcurrency = n + } + + onSettled(cb: () => void) { + this.onSettles.push(cb) + return () => { + this.onSettles = this.onSettles.filter((d) => d !== cb) + } + } + + onError(cb: (error: any, task: () => Promise) => void) { + this.onErrors.push(cb) + return () => { + this.onErrors = this.onErrors.filter((d) => d !== cb) + } + } + + onSuccess(cb: (result: any, task: () => Promise) => void) { + this.onSuccesses.push(cb) + return () => { + this.onSuccesses = this.onSuccesses.filter((d) => d !== cb) + } + } + + stop() { + this.running = false + } + + start() { + this.running = true + this.tick() + return new Promise((resolve) => { + this.onSettled(() => { + if (this.isSettled()) { + resolve() + } + }) + }) + } + + clear() { + this.pending = [] + } + + getActive() { + return this.active + } + + getPending() { + return this.pending + } + + getAll() { + return [...this.active, ...this.pending] + } + + isRunning() { + return this.running + } + + isSettled() { + return !this.active.length && !this.pending.length + } +} diff --git a/packages/start-plugin-core/src/schema.ts b/packages/start-plugin-core/src/schema.ts new file mode 100644 index 0000000000..fa87efce14 --- /dev/null +++ b/packages/start-plugin-core/src/schema.ts @@ -0,0 +1,188 @@ +import path from 'node:path' +import { existsSync } from 'node:fs' +import { z } from 'zod' +import { configSchema, getConfig } from '@tanstack/router-generator' +import type { NitroConfig } from 'nitropack' + +const tsrConfig = configSchema.partial().extend({ + srcDirectory: z.string().optional().default('src'), +}) + +export function createTanStackConfig>(frameworkPlugin: TFrameworkPlugin) { + const schema = createTanStackStartOptionsSchema(frameworkPlugin) + + return { + schema, + parse: (opts?: z.input) => { + const options = schema.parse(opts) + + const srcDirectory = options.tsr.srcDirectory + + const routesDirectory = + options.tsr.routesDirectory ?? path.join(srcDirectory, 'routes') + + const generatedRouteTree = + options.tsr.generatedRouteTree ?? + path.join(srcDirectory, 'routeTree.gen.ts') + + const clientEntryPath = (() => { + if (options.client.entry) { + return path.join(srcDirectory, options.client.entry) + } + + if (existsSync(path.join(srcDirectory, 'client.tsx'))) { + return path.join(srcDirectory, 'client.tsx') + } + + return '/~start/default-client-entry' + })() + + const serverEntryPath = (() => { + if (options.server.entry) { + return path.join(srcDirectory, options.server.entry) + } + + if (existsSync(path.join(srcDirectory, 'server.tsx'))) { + return path.join(srcDirectory, 'server.tsx') + } + + return '/~start/default-server-entry' + })() + + return { + ...options, + tsr: { + ...options.tsr, + ...getConfig({ + ...options.tsr, + routesDirectory, + generatedRouteTree, + }), + }, + clientEntryPath, + serverEntryPath, + } + }, + } +} + +export function createTanStackStartOptionsSchema(frameworkPlugin: Record = {}) { + return z + .object({ + root: z.string().optional().default(process.cwd()), + target: z.custom().optional(), + ...frameworkPlugin, + tsr: tsrConfig.optional().default({}), + client: z + .object({ + entry: z.string().optional(), + base: z.string().optional().default('/_build'), + }) + .optional() + .default({}), + server: z + .object({ + entry: z.string().optional(), + }) + .optional() + .default({}), + serverFns: z + .object({ + base: z.string().optional().default('/_server'), + }) + .optional() + .default({}), + public: z + .object({ + dir: z.string().optional().default('public'), + base: z.string().optional().default('/'), + }) + .optional() + .default({}), + pages: z + .array(z.union([z.string(), pageSchema])) + .optional() + .default([]), + sitemap: pagePrerenderOptionsSchema + .extend({ + host: z.string().optional(), + }) + .optional(), + prerender: z + .object({ + enabled: z.boolean().optional(), + concurrency: z.number().optional(), + filter: z.function().args(pageSchema).returns(z.any()).optional(), + failOnError: z.boolean().optional(), + }) + .and(pagePrerenderOptionsSchema.optional()) + .optional(), + }) + .optional() + .default({}) +} + +const pageSitemapOptionsSchema = z.object({ + exclude: z.boolean().optional(), + priority: z.number().min(0).max(1).optional(), + changefreq: z + .enum(['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never']) + .optional(), + lastmod: z.union([z.string(), z.date()]).optional(), + alternateRefs: z + .array( + z.object({ + href: z.string(), + hreflang: z.string(), + }), + ) + .optional(), + images: z + .array( + z.object({ + loc: z.string(), + caption: z.string().optional(), + title: z.string().optional(), + }), + ) + .optional(), + news: z + .object({ + publication: z.object({ + name: z.string(), + language: z.string(), + }), + publicationDate: z.union([z.string(), z.date()]), + title: z.string(), + }) + .optional(), +}) + +const pageBaseSchema = z.object({ + path: z.string(), + sitemap: pageSitemapOptionsSchema.optional(), + fromCrawl: z.boolean().optional(), +}) + +const pagePrerenderOptionsSchema = z.object({ + enabled: z.boolean().optional(), + autoSubfolderIndex: z.boolean().optional(), + crawlLinks: z.boolean().optional(), + retryCount: z.number().optional(), + retryDelay: z.number().optional(), + onSuccess: z + .function() + .args( + z.object({ + page: pageBaseSchema, + html: z.string(), + }), + ) + .returns(z.any()), +}) + +export const pageSchema = pageBaseSchema.extend({ + prerender: pagePrerenderOptionsSchema.optional(), +}) + +export type Page = z.infer \ No newline at end of file diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts b/packages/start-plugin-core/tests/createIsomorphicFn/createIsomorphicFn.test.ts similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/createIsomorphicFn.test.ts rename to packages/start-plugin-core/tests/createIsomorphicFn/createIsomorphicFn.test.ts diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/client/createIsomorphicFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/snapshots/server/createIsomorphicFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx b/packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx rename to packages/start-plugin-core/tests/createIsomorphicFn/test-files/createIsomorphicFnStarImport.tsx diff --git a/packages/solid-start-plugin/tests/createMiddleware/createMiddleware.test.ts b/packages/start-plugin-core/tests/createMiddleware/createMiddleware.test.ts similarity index 100% rename from packages/solid-start-plugin/tests/createMiddleware/createMiddleware.test.ts rename to packages/start-plugin-core/tests/createMiddleware/createMiddleware.test.ts diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/client/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/snapshots/server/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructured.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareStarImport.tsx diff --git a/packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx b/packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/test-files/createMiddlewareValidator.tsx rename to packages/start-plugin-core/tests/createMiddleware/test-files/createMiddlewareValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/createServerFn.test.ts b/packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/createServerFn.test.ts rename to packages/start-plugin-core/tests/createServerFn/createServerFn.test.ts diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/client/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/client/createServerFnValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/snapshots/server/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/snapshots/server/createServerFnValidator.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructured.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructured.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnStarImport.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnStarImport.tsx diff --git a/packages/react-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx b/packages/start-plugin-core/tests/createServerFn/test-files/createServerFnValidator.tsx similarity index 100% rename from packages/react-start-plugin/tests/createServerFn/test-files/createServerFnValidator.tsx rename to packages/start-plugin-core/tests/createServerFn/test-files/createServerFnValidator.tsx diff --git a/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.d.ts b/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.d.ts new file mode 100644 index 0000000000..cb0ff5c3b5 --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/react-start-plugin/tests/createMiddleware/createMiddleware.test.ts b/packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.ts similarity index 100% rename from packages/react-start-plugin/tests/createMiddleware/createMiddleware.test.ts rename to packages/start-plugin-core/tests/createServerRoute/createServerRoute.test.ts diff --git a/packages/start-plugin-core/tests/createServerRoute/snapshots/client/nonImported.tsx b/packages/start-plugin-core/tests/createServerRoute/snapshots/client/nonImported.tsx new file mode 100644 index 0000000000..b33fbc93fa --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/snapshots/client/nonImported.tsx @@ -0,0 +1,3 @@ +import { createServerFileRoute } from "@tanstack/react-start"; +import { z } from 'zod'; +export const ServerRoute = createServerFileRoute(); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx b/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx new file mode 100644 index 0000000000..374525f157 --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/snapshots/server/nonImported.tsx @@ -0,0 +1,11 @@ +import { createServerFileRoute } from "@tanstack/react-start"; +import { z } from 'zod'; +export const ServerRoute = createServerFileRoute().validator(z.number()).middleware(({ + input +}) => input + 1).methods({ + GET: async ({ + input + }) => { + return input + 1; + } +}); \ No newline at end of file diff --git a/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx b/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx new file mode 100644 index 0000000000..d782a05448 --- /dev/null +++ b/packages/start-plugin-core/tests/createServerRoute/test-files/nonImported.tsx @@ -0,0 +1,10 @@ +import { z } from 'zod' + +export const ServerRoute = createServerFileRoute() + .validator(z.number()) + .middleware(({ input }) => input + 1) + .methods({ + GET: async ({ input }) => { + return input + 1 + }, + }) diff --git a/packages/react-start-plugin/tests/envOnly/envOnly.test.ts b/packages/start-plugin-core/tests/envOnly/envOnly.test.ts similarity index 100% rename from packages/react-start-plugin/tests/envOnly/envOnly.test.ts rename to packages/start-plugin-core/tests/envOnly/envOnly.test.ts diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/client/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/client/envOnlyStarImport.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/snapshots/server/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/snapshots/server/envOnlyStarImport.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructured.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructured.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructured.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructuredRename.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyDestructuredRename.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyDestructuredRename.tsx diff --git a/packages/react-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx b/packages/start-plugin-core/tests/envOnly/test-files/envOnlyStarImport.tsx similarity index 100% rename from packages/react-start-plugin/tests/envOnly/test-files/envOnlyStarImport.tsx rename to packages/start-plugin-core/tests/envOnly/test-files/envOnlyStarImport.tsx diff --git a/packages/react-start-config/tsconfig.json b/packages/start-plugin-core/tsconfig.json similarity index 58% rename from packages/react-start-config/tsconfig.json rename to packages/start-plugin-core/tsconfig.json index 940a9cce0a..6c8c904b07 100644 --- a/packages/react-start-config/tsconfig.json +++ b/packages/start-plugin-core/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../../tsconfig.json", - "include": ["src/index.ts"], + "include": ["src", "vite.config.ts", "tests"], + "exclude": ["tests/**/test-files/**", "tests/**/snapshots/**"], "compilerOptions": { "rootDir": "src", "outDir": "dist/esm", diff --git a/packages/solid-start-router-manifest/vite.config.ts b/packages/start-plugin-core/vite.config.ts similarity index 69% rename from packages/solid-start-router-manifest/vite.config.ts rename to packages/start-plugin-core/vite.config.ts index d6472068fb..2c711fd181 100644 --- a/packages/solid-start-router-manifest/vite.config.ts +++ b/packages/start-plugin-core/vite.config.ts @@ -1,14 +1,13 @@ import { defineConfig, mergeConfig } from 'vitest/config' import { tanstackViteConfig } from '@tanstack/config/vite' import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], test: { name: packageJson.name, + dir: './tests', watch: false, - environment: 'jsdom', + typecheck: { enabled: true }, }, }) @@ -17,6 +16,6 @@ export default mergeConfig( tanstackViteConfig({ entry: './src/index.ts', srcDir: './src', - externalDeps: ['tsr:routes-manifest'], + outDir: './dist', }), ) diff --git a/packages/start-server-core/package.json b/packages/start-server-core/package.json index b2cf5f1f2e..f5fe940664 100644 --- a/packages/start-server-core/package.json +++ b/packages/start-server-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-core", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { @@ -65,10 +51,11 @@ "@tanstack/history": "workspace:^", "@tanstack/router-core": "workspace:^", "@tanstack/start-client-core": "workspace:^", - "tiny-warning": "^1.0.3", "h3": "1.13.0", "isbot": "^5.1.22", "jsesc": "^3.1.0", + "tiny-invariant": "^1.3.3", + "tiny-warning": "^1.0.3", "unctx": "^2.4.1" }, "devDependencies": { diff --git a/packages/start-server-core/src/createStartHandler.ts b/packages/start-server-core/src/createStartHandler.ts index 7604efbdef..6d21910ed0 100644 --- a/packages/start-server-core/src/createStartHandler.ts +++ b/packages/start-server-core/src/createStartHandler.ts @@ -1,25 +1,52 @@ +import path from 'node:path' import { createMemoryHistory } from '@tanstack/history' -import { mergeHeaders } from '@tanstack/start-client-core' import { eventHandler, getResponseHeaders, toWebRequest } from 'h3' +import { mergeHeaders } from '@tanstack/start-client-core' import { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server' -import type { HandlerCallback } from './handlerCallback' +import { serverFunctionsHandler } from './server-functions-handler' +import { getStartManifest } from './router-manifest' import type { EventHandlerResponse, H3Event } from 'h3' -import type { AnyRouter, Manifest } from '@tanstack/router-core' +import type { AnyRouter } from '@tanstack/router-core' +import type { HandlerCallback } from './handlerCallback' export type CustomizeStartHandler< TRouter extends AnyRouter, TResponse extends EventHandlerResponse = EventHandlerResponse, > = (cb: HandlerCallback) => ReturnType +export function getStartResponseHeaders(opts: { + event: H3Event + router: AnyRouter +}) { + let headers = mergeHeaders( + getResponseHeaders(opts.event), + (opts.event as any).___ssrRpcResponseHeaders, + { + 'Content-Type': 'text/html; charset=UTF-8', + }, + ...opts.router.state.matches.map((match) => { + return match.headers + }), + ) + + // Handle Redirects + const { redirect } = opts.router.state + + if (redirect) { + headers = mergeHeaders(headers, redirect.headers, { + Location: redirect.href, + }) + } + return headers +} + export function createStartHandler< TRouter extends AnyRouter, TResponse extends EventHandlerResponse = EventHandlerResponse, >({ createRouter, - getRouterManifest, }: { createRouter: () => TRouter - getRouterManifest?: () => Manifest | Promise }): CustomizeStartHandler { return (cb) => { return eventHandler(async (event) => { @@ -28,6 +55,27 @@ export function createStartHandler< const url = new URL(request.url) const href = url.href.replace(url.origin, '') + if (!process.env.TSS_SERVER_FN_BASE) { + throw new Error( + 'tanstack/start-server-core: TSS_SERVER_FN_BASE must be defined in your environment for createStartHandler()', + ) + } + + // Handle server functions + if ( + href.startsWith(path.join('/', process.env.TSS_SERVER_FN_BASE, '/')) + ) { + return await serverFunctionsHandler(event) + } + + // Handle API routes + // handleApiRoutes(event) + // if (event.handled) { + // return + // } + + // If no API routes returned, then fallback to SSR on the router + // Create a history for the router const history = createMemoryHistory({ initialEntries: [href], @@ -35,13 +83,28 @@ export function createStartHandler< const router = createRouter() - attachRouterServerSsrUtils(router, await getRouterManifest?.()) + attachRouterServerSsrUtils(router, getStartManifest()) // Update the router with the history and context router.update({ history, }) + // Normally, you could call router.load() directly, but because we're going to + // handle server routes, we need to prime the router with the matches + // so we can find any matching server routes + router.beforeLoad() + + console.log( + href, + router.state.pendingMatches?.map((d) => { + const staticData = router.looseRoutesById[d.routeId]?.options + .staticData as undefined | { serverRoute: any } + + return [d.routeId, staticData?.serverRoute] + }), + ) + await router.load() dehydrateRouter(router) @@ -57,26 +120,3 @@ export function createStartHandler< }) } } - -function getStartResponseHeaders(opts: { event: H3Event; router: AnyRouter }) { - let headers = mergeHeaders( - getResponseHeaders(opts.event), - (opts.event as any).___ssrRpcResponseHeaders, - { - 'Content-Type': 'text/html; charset=UTF-8', - }, - ...opts.router.state.matches.map((match) => { - return match.headers - }), - ) - - // Handle Redirects - const { redirect } = opts.router.state - - if (redirect) { - headers = mergeHeaders(headers, redirect.headers, { - Location: redirect.href, - }) - } - return headers -} diff --git a/packages/start-server-core/src/h3.ts b/packages/start-server-core/src/h3.ts index d5a2c94844..8e7dbc049c 100644 --- a/packages/start-server-core/src/h3.ts +++ b/packages/start-server-core/src/h3.ts @@ -11,7 +11,9 @@ import { clearResponseHeaders as _clearResponseHeaders, clearSession as _clearSession, defaultContentType as _defaultContentType, + defineEventHandler as _defineEventHandler, deleteCookie as _deleteCookie, + eventHandler as _eventHandler, fetchWithEvent as _fetchWithEvent, getCookie as _getCookie, getHeader as _getHeader, @@ -66,15 +68,18 @@ import { useSession as _useSession, writeEarlyHints as _writeEarlyHints, } from 'h3' -import { getContext as getUnctxContext } from 'unctx' + import type { Encoding, + EventHandler, HTTPHeaderName, InferEventInput, _RequestMiddleware, _ResponseMiddleware, } from 'h3' +const eventStorage = new AsyncLocalStorage() + function _setContext(event: H3Event, key: string, value: any) { event.context[key] = value } @@ -140,7 +145,6 @@ export { createAppEventHandler, createEvent, createRouter, - defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, @@ -148,7 +152,6 @@ export { defineResponseMiddleware, dynamicEventHandler, defineWebSocket, - eventHandler, splitCookiesString, fromNodeMiddleware, fromPlainHandler, @@ -221,8 +224,33 @@ export { type _ResponseMiddleware, } from 'h3' -function getHTTPEvent() { - return getEvent() +export function defineEventHandler(handler: EventHandler) { + return _defineEventHandler((event) => { + return runWithEvent(event, () => handler(event)) + }) +} + +export function eventHandler(handler: EventHandler) { + return _eventHandler((event) => { + return runWithEvent(event, () => handler(event)) + }) +} + +export async function runWithEvent( + event: H3Event, + fn: () => T | Promise, +): Promise { + return eventStorage.run(event, fn) +} + +export function getEvent() { + const event = eventStorage.getStore() as H3Event | undefined + if (!event) { + throw new Error( + `No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`, + ) + } + return event } export const HTTPEventSymbol = Symbol('$HTTPEvent') @@ -262,12 +290,7 @@ function createWrapperFunction) => any>( return function (...args: Array) { const event = args[0] if (!isEvent(event)) { - if (!(globalThis as any).app.config.server.experimental?.asyncContext) { - throw new Error( - 'AsyncLocalStorage was not enabled. Use the `server.experimental.asyncContext: true` option in your app configuration to enable it. Or, pass the instance of HTTPEvent that you have as the first argument to the function.', - ) - } - args.unshift(getHTTPEvent()) + args.unshift(getEvent()) } else { args[0] = event instanceof H3Event || (event as any).__is_event__ @@ -463,37 +486,5 @@ export const readValidatedBody: PrependOverload< export const removeResponseHeader = createWrapperFunction(_removeResponseHeader) export const getContext = createWrapperFunction(_getContext) export const setContext = createWrapperFunction(_setContext) - export const clearResponseHeaders = createWrapperFunction(_clearResponseHeaders) - export const getWebRequest = createWrapperFunction(toWebRequest) - -export { createApp as createServer } from 'h3' - -function getNitroAsyncContext() { - const nitroAsyncContext = getUnctxContext('nitro-app', { - asyncContext: (globalThis as any).app.config.server.experimental - ?.asyncContext - ? true - : false, - AsyncLocalStorage, - }) - - return nitroAsyncContext -} - -export function getEvent() { - const event = (getNitroAsyncContext().use() as any).event as - | H3Event - | undefined - if (!event) { - throw new Error( - `No HTTPEvent found in AsyncLocalStorage. Make sure you are using the function within the server runtime.`, - ) - } - return event -} - -export async function handleHTTPEvent(event: H3Event) { - return await (globalThis as any).$handle(event) -} diff --git a/packages/start-server-core/src/index.tsx b/packages/start-server-core/src/index.tsx index d24477934d..8a14cde194 100644 --- a/packages/start-server-core/src/index.tsx +++ b/packages/start-server-core/src/index.tsx @@ -3,10 +3,19 @@ export { transformPipeableStreamWithRouter, } from './transformStreamWithRouter' -export { createStartHandler } from './createStartHandler' +export { + getStartResponseHeaders, + createStartHandler, +} from './createStartHandler' +export type { CustomizeStartHandler } from './createStartHandler' export { createRequestHandler } from './createRequestHandler' export { defineHandlerCallback } from './handlerCallback' export type { HandlerCallback } from './handlerCallback' +export { attachRouterServerSsrUtils, dehydrateRouter } from './ssr-server' +export { serverFunctionsHandler } from './server-functions-handler' + +export { getStartManifest } from './router-manifest' + export * from './h3' diff --git a/packages/start-server-core/src/router-manifest.ts b/packages/start-server-core/src/router-manifest.ts new file mode 100644 index 0000000000..ba2bdb7afc --- /dev/null +++ b/packages/start-server-core/src/router-manifest.ts @@ -0,0 +1,76 @@ +// @ts-expect-error +import tsrStartManifest from 'tsr:start-manifest' +import { rootRouteId } from '@tanstack/router-core' +import type { Manifest } from '@tanstack/router-core' + +/** + * @description Returns the router manifest that should be sent to the client. + * This includes only the assets and preloads for the current route and any + * special assets that are needed for the client. It does not include relationships + * between routes or any other data that is not needed for the client. + */ +export function getStartManifest() { + const startManifest = tsrStartManifest() as Manifest + + const rootRoute = (startManifest.routes[rootRouteId] = + startManifest.routes[rootRouteId] || {}) + + rootRoute.assets = rootRoute.assets || [] + + // Get the entry for the client from vinxi + // const vinxiClientManifest = getManifest('client') + + // const importPath = + // vinxiClientManifest.inputs[vinxiClientManifest.handler]?.output.path + // if (!importPath) { + // invariant(importPath, 'Could not find client entry in vinxi manifest') + // } + + if (process.env.NODE_ENV === 'development' && !process.env.TSS_CLIENT_ENTRY) { + throw new Error( + 'tanstack/start-server-core: TSS_CLIENT_ENTRY must be defined in your environment for getStartManifest()', + ) + } + + if (process.env.NODE_ENV === 'development') { + // Always fake that HMR is ready + // const CLIENT_BASE = sanitizeBase(process.env.TSS_CLIENT_BASE || '') + + // if (!CLIENT_BASE) { + // throw new Error( + // 'tanstack/start-router-manifest: TSS_CLIENT_BASE must be defined in your environment for getFullRouterManifest()', + // ) + // } + + const script = `import(${JSON.stringify(process.env.TSS_CLIENT_ENTRY)})` + + rootRoute.assets.push({ + tag: 'script', + attrs: { + type: 'module', + suppressHydrationWarning: true, + async: true, + }, + children: script, + }) + } + + const manifest = { + ...startManifest, + routes: Object.fromEntries( + Object.entries(startManifest.routes).map(([k, v]) => { + const { preloads, assets } = v + return [ + k, + { + preloads, + assets, + }, + ] + }), + ), + } + + // Strip out anything that isn't needed for the client + return manifest +} diff --git a/packages/start-server-functions-handler/src/index.ts b/packages/start-server-core/src/server-functions-handler.ts similarity index 85% rename from packages/start-server-functions-handler/src/index.ts rename to packages/start-server-core/src/server-functions-handler.ts index 85cbe87783..714cc4ce37 100644 --- a/packages/start-server-functions-handler/src/index.ts +++ b/packages/start-server-core/src/server-functions-handler.ts @@ -1,21 +1,16 @@ import { isNotFound, isRedirect } from '@tanstack/router-core' import invariant from 'tiny-invariant' -import { - eventHandler, - getEvent, - getResponseStatus, - toWebRequest, -} from '@tanstack/start-server-core' import { startSerializer } from '@tanstack/start-client-core' // @ts-expect-error import _serverFnManifest from 'tsr:server-fn-manifest' -import type { H3Event } from '@tanstack/start-server-core' +import { eventHandler, getEvent, getResponseStatus, toWebRequest } from './h3' +import type { H3Event } from './h3' // NOTE: This is a dummy export to silence warnings about // only having a default export. -export const dummy = 1 +export const dummy = 2 -export default eventHandler(handleServerAction) +export const serverFunctionsHandler = eventHandler(handleServerAction) const serverFnManifest = _serverFnManifest as Record< string, @@ -84,33 +79,32 @@ async function handleServerRequest({ const serverFnInfo = serverFnManifest[serverFnId] if (!serverFnInfo) { - console.log('serverFnManifest', serverFnManifest) + console.info('serverFnManifest', serverFnManifest) throw new Error('Server function info not found for ' + serverFnId) } - if (process.env.NODE_ENV === 'development') - console.info(`\nServerFn Request: ${serverFnId}`) - let fnModule: undefined | { [key: string]: any } if (process.env.NODE_ENV === 'development') { - fnModule = await (globalThis as any).app - .getRouter('server') - .internals.devServer.ssrLoadModule(serverFnInfo.extractedFilename) + const serverEnv = (globalThis as any).viteDevServer.environments['server'] + if (!serverEnv) { + throw new Error(`'server' vite dev environment not found`) + } + fnModule = await serverEnv.runner.import(serverFnInfo.extractedFilename) } else { fnModule = await serverFnInfo.importer() } if (!fnModule) { - console.log('serverFnManifest', serverFnManifest) + console.info('serverFnInfo', serverFnInfo) throw new Error('Server function module not resolved for ' + serverFnId) } const action = fnModule[serverFnInfo.functionName] if (!action) { - console.log('serverFnManifest', serverFnManifest) - console.log('fnModule', fnModule) + console.info('serverFnInfo', serverFnInfo) + console.info('fnModule', fnModule) throw new Error( `Server function module export not resolved for serverFn ID: ${serverFnId}`, ) @@ -208,11 +202,11 @@ async function handleServerRequest({ // return result.result // } - // TODO: RSCs + // TODO: RSCs Where are we getting this package? // if (isValidElement(result)) { // const { renderToPipeableStream } = await import( // // @ts-expect-error - // '@vinxi/react-server-dom/server' + // 'react-server-dom/server' // ) // const pipeableStream = renderToPipeableStream(result) @@ -280,20 +274,6 @@ async function handleServerRequest({ if (isRaw) { return response } - if (process.env.NODE_ENV === 'development') - console.info(`ServerFn Response: ${response.status}`) - - if (response.headers.get('Content-Type') === 'application/json') { - const cloned = response.clone() - const text = await cloned.text() - const payload = text ? JSON.stringify(JSON.parse(text)) : 'undefined' - - if (process.env.NODE_ENV === 'development') - console.info( - ` - Payload: ${payload.length > 100 ? payload.substring(0, 100) + '...' : payload}`, - ) - } - if (process.env.NODE_ENV === 'development') console.info() return response } diff --git a/packages/start-server-core/src/ssr-server.ts b/packages/start-server-core/src/ssr-server.ts index a7f8378310..5de5a2fdb5 100644 --- a/packages/start-server-core/src/ssr-server.ts +++ b/packages/start-server-core/src/ssr-server.ts @@ -1,6 +1,7 @@ import { default as warning } from 'tiny-warning' import { TSR_DEFERRED_PROMISE, + __internal_devHtmlUtils, defer, isPlainArray, isPlainObject, @@ -19,6 +20,7 @@ import type { AnyRouteMatch, AnyRouter, DeferredPromise, + ExtractedHtmlTagInfo, Manifest, } from '@tanstack/router-core' @@ -41,6 +43,11 @@ export interface ServerExtractedPromise extends ServerExtractedBaseEntry { promise: DeferredPromise } +declare global { + // eslint-disable-next-line no-var + var TSS_INJECTED_HEAD_SCRIPTS_INFO: Array | undefined +} + export function attachRouterServerSsrUtils( router: AnyRouter, manifest: Manifest | undefined, @@ -99,6 +106,14 @@ ${jsesc(script, { quotes: 'backtick' })}\`)` router.serverSsr.injectScript(() => minifiedTsrBootStrapScript, { logScript: false, }) + + const INJECTED_HEAD_SCRIPTS = globalThis.TSS_INJECTED_HEAD_SCRIPTS_INFO + if (INJECTED_HEAD_SCRIPTS) { + for (const tagInfo of INJECTED_HEAD_SCRIPTS) { + const htmlTag = __internal_devHtmlUtils.buildHtmlTag('script', tagInfo) + router.serverSsr.injectHtml(() => htmlTag) + } + } } export function dehydrateRouter(router: AnyRouter) { diff --git a/packages/start-server-core/vite.config.ts b/packages/start-server-core/vite.config.ts index 2f1ffffb80..a0d6d819fb 100644 --- a/packages/start-server-core/vite.config.ts +++ b/packages/start-server-core/vite.config.ts @@ -19,5 +19,6 @@ export default mergeConfig( tanstackViteConfig({ srcDir: './src', entry: './src/index.tsx', + externalDeps: ['tsr:server-fn-manifest', 'tsr:start-manifest'], }), ) diff --git a/packages/start-server-functions-client/package.json b/packages/start-server-functions-client/package.json index fc861b7144..b0e267247e 100644 --- a/packages/start-server-functions-client/package.json +++ b/packages/start-server-functions-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-client", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { diff --git a/packages/start-server-functions-fetcher/package.json b/packages/start-server-functions-fetcher/package.json index 5d72b3481e..e5a94edbbe 100644 --- a/packages/start-server-functions-fetcher/package.json +++ b/packages/start-server-functions-fetcher/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-fetcher", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { diff --git a/packages/start-server-functions-handler/README.md b/packages/start-server-functions-handler/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start-server-functions-handler/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-server-functions-handler/eslint.config.js b/packages/start-server-functions-handler/eslint.config.js deleted file mode 100644 index bd7118fa1a..0000000000 --- a/packages/start-server-functions-handler/eslint.config.js +++ /dev/null @@ -1,20 +0,0 @@ -// @ts-check - -import rootConfig from '../../eslint.config.js' - -export default [ - ...rootConfig, - { - files: ['**/*.{ts,tsx}'], - }, - { - plugins: {}, - rules: {}, - }, - { - files: ['**/__tests__/**'], - rules: { - '@typescript-eslint/no-unnecessary-condition': 'off', - }, - }, -] diff --git a/packages/start-server-functions-handler/tsconfig.json b/packages/start-server-functions-handler/tsconfig.json deleted file mode 100644 index 0484835e6b..0000000000 --- a/packages/start-server-functions-handler/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "module": "esnext" - }, - "include": ["src", "vite.config.ts"] -} diff --git a/packages/start-server-functions-handler/vite.config.ts b/packages/start-server-functions-handler/vite.config.ts deleted file mode 100644 index cc9124d7d8..0000000000 --- a/packages/start-server-functions-handler/vite.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { defineConfig, mergeConfig } from 'vitest/config' -import { tanstackViteConfig } from '@tanstack/config/vite' -import packageJson from './package.json' -import type { ViteUserConfig } from 'vitest/config' - -const config = defineConfig({ - plugins: [] as ViteUserConfig['plugins'], - test: { - name: packageJson.name, - watch: false, - environment: 'jsdom', - }, -}) - -export default mergeConfig( - config, - tanstackViteConfig({ - entry: './src/index.ts', - srcDir: './src', - externalDeps: ['tsr:server-fn-manifest'], - }), -) diff --git a/packages/start-server-functions-server/package.json b/packages/start-server-functions-server/package.json index 4700c48e1f..11c904d2cd 100644 --- a/packages/start-server-functions-server/package.json +++ b/packages/start-server-functions-server/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-server", - "version": "1.115.0", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { @@ -63,7 +49,8 @@ }, "dependencies": { "@tanstack/server-functions-plugin": "workspace:^", - "tiny-invariant": "^1.3.3" + "tiny-invariant": "^1.3.3", + "vite": "6.1.5" }, "devDependencies": { "typescript": "^5.7.2" diff --git a/packages/start-server-functions-ssr/README.md b/packages/start-server-functions-ssr/README.md deleted file mode 100644 index bb009b0c87..0000000000 --- a/packages/start-server-functions-ssr/README.md +++ /dev/null @@ -1,33 +0,0 @@ -> 🤫 we're cooking up something special! - - - -# TanStack Start - -![TanStack Router Header](https://github.com/tanstack/router/raw/main/media/header.png) - -🤖 Type-safe router w/ built-in caching & URL state management for React! - - - #TanStack - - - - - - - - semantic-release - - Join the discussion on Github -Best of JS - - - - - - - -Enjoy this library? Try the entire [TanStack](https://tanstack.com)! [React Query](https://github.com/tannerlinsley/react-query), [React Table](https://github.com/tanstack/react-table), [React Charts](https://github.com/tannerlinsley/react-charts), [React Virtual](https://github.com/tannerlinsley/react-virtual) - -## Visit [tanstack.com/router](https://tanstack.com/router) for docs, guides, API and more! diff --git a/packages/start-server-functions-ssr/package.json b/packages/start-server-functions-ssr/package.json index 115a083aa0..fe72d1feb4 100644 --- a/packages/start-server-functions-ssr/package.json +++ b/packages/start-server-functions-ssr/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start-server-functions-ssr", - "version": "1.115.1", + "version": "1.116.0", "description": "Modern and scalable routing for applications", "author": "Tanner Linsley", "license": "MIT", @@ -22,21 +22,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:eslint && pnpm test:types && pnpm test:build && pnpm test:unit", - "test:unit": "exit 0; vitest", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "exports": { diff --git a/packages/start/package.json b/packages/start/package.json index 73a397945d..c7be2f333f 100644 --- a/packages/start/package.json +++ b/packages/start/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/start", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,12 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test": "pnpm test:build", - "test:build": "exit 0; vitest", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/client.d.ts", "exports": { @@ -62,14 +57,14 @@ "default": "./dist/cjs/server.cjs" } }, - "./config": { + "./plugin": { "import": { - "types": "./dist/esm/config.d.ts", - "default": "./dist/esm/config.js" + "types": "./dist/esm/plugin.d.ts", + "default": "./dist/esm/plugin.js" }, "require": { - "types": "./dist/cjs/config.d.cts", - "default": "./dist/cjs/config.cjs" + "types": "./dist/cjs/plugin.d.cts", + "default": "./dist/cjs/plugin.cjs" } }, "./api": { @@ -82,16 +77,6 @@ "default": "./dist/cjs/api.cjs" } }, - "./router-manifest": { - "import": { - "types": "./dist/esm/router-manifest.d.ts", - "default": "./dist/esm/router-manifest.js" - }, - "require": { - "types": "./dist/cjs/router-manifest.d.cts", - "default": "./dist/cjs/router-manifest.cjs" - } - }, "./server-functions-client": { "import": { "types": "./dist/esm/server-functions-client.d.ts", @@ -112,16 +97,6 @@ "default": "./dist/cjs/server-functions-server.cjs" } }, - "./server-functions-handler": { - "import": { - "types": "./dist/esm/server-functions-handler.d.ts", - "default": "./dist/esm/server-functions-handler.js" - }, - "require": { - "types": "./dist/cjs/server-functions-handler.d.cts", - "default": "./dist/cjs/server-functions-handler.cjs" - } - }, "./server-functions-ssr": { "import": { "types": "./dist/esm/server-functions-ssr.d.ts", @@ -145,11 +120,9 @@ "dependencies": { "@tanstack/react-start-client": "workspace:^", "@tanstack/react-start-server": "workspace:^", - "@tanstack/start-config": "workspace:^", - "@tanstack/react-start-router-manifest": "workspace:^", + "@tanstack/react-start-plugin": "workspace:^", "@tanstack/start-server-functions-client": "workspace:^", "@tanstack/start-server-functions-server": "workspace:^", - "@tanstack/start-server-functions-handler": "workspace:^", "@tanstack/start-server-functions-ssr": "workspace:^", "@tanstack/start-api-routes": "workspace:^" } diff --git a/packages/start/src/config.tsx b/packages/start/src/config.tsx deleted file mode 100644 index 262bac966c..0000000000 --- a/packages/start/src/config.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-config' diff --git a/packages/start/src/plugin.tsx b/packages/start/src/plugin.tsx new file mode 100644 index 0000000000..d991c3b71c --- /dev/null +++ b/packages/start/src/plugin.tsx @@ -0,0 +1 @@ +export * from '@tanstack/react-start-plugin' diff --git a/packages/start/src/router-manifest.tsx b/packages/start/src/router-manifest.tsx deleted file mode 100644 index 10e98ba06d..0000000000 --- a/packages/start/src/router-manifest.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/react-start-router-manifest' diff --git a/packages/start/src/server-functions-handler.tsx b/packages/start/src/server-functions-handler.tsx deleted file mode 100644 index 9e7afcffff..0000000000 --- a/packages/start/src/server-functions-handler.tsx +++ /dev/null @@ -1,4 +0,0 @@ -console.warn( - '[@tanstack/start] Warning: This package has moved to @tanstack/react-start. Please switch to the new package, as this package will be dropped soon.', -) -export * from '@tanstack/start-server-functions-handler' diff --git a/packages/start/vite.config.ts b/packages/start/vite.config.ts index 7c6fa9afe4..386d563255 100644 --- a/packages/start/vite.config.ts +++ b/packages/start/vite.config.ts @@ -17,8 +17,7 @@ export default mergeConfig( entry: [ './src/client.tsx', './src/server.tsx', - './src/config.tsx', - './src/router-manifest.tsx', + './src/plugin.tsx', './src/server-functions-client.tsx', './src/server-functions-server.tsx', './src/server-functions-ssr.tsx', @@ -27,8 +26,7 @@ export default mergeConfig( externalDeps: [ '@tanstack/react-start-client', '@tanstack/react-start-server', - '@tanstack/start-config', - '@tanstack/react-start-router-manifest', + '@tanstack/react-start-plugin', '@tanstack/start-server-functions-client', '@tanstack/start-server-functions-server', '@tanstack/start-server-functions-ssr', diff --git a/packages/valibot-adapter/package.json b/packages/valibot-adapter/package.json index 73853f41f9..71f445d5f9 100644 --- a/packages/valibot-adapter/package.json +++ b/packages/valibot-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/valibot-adapter", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch --typecheck", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/packages/zod-adapter/package.json b/packages/zod-adapter/package.json index e6a8e3bf1e..867e8c6a08 100644 --- a/packages/zod-adapter/package.json +++ b/packages/zod-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/zod-adapter", - "version": "1.115.2", + "version": "1.116.0", "description": "Modern and scalable routing for React applications", "author": "Tanner Linsley", "license": "MIT", @@ -23,21 +23,7 @@ "async router", "typescript" ], - "scripts": { - "clean": "rimraf ./dist && rimraf ./coverage", - "test:eslint": "eslint ./src", - "test:types": "pnpm run \"/^test:types:ts[0-9]{2}$/\"", - "test:types:ts53": "node ../../node_modules/typescript53/lib/tsc.js", - "test:types:ts54": "node ../../node_modules/typescript54/lib/tsc.js", - "test:types:ts55": "node ../../node_modules/typescript55/lib/tsc.js", - "test:types:ts56": "node ../../node_modules/typescript56/lib/tsc.js", - "test:types:ts57": "node ../../node_modules/typescript57/lib/tsc.js", - "test:types:ts58": "tsc", - "test:unit": "vitest", - "test:unit:dev": "pnpm run test:unit --watch --typecheck", - "test:build": "publint --strict && attw --ignore-rules no-resolution --pack .", - "build": "vite build" - }, + "scripts": {}, "type": "module", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.cjs", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21f3bf7301..bd62830674 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,10 +43,10 @@ overrides: '@tanstack/solid-start-server': workspace:* '@tanstack/start-api-routes': workspace:* '@tanstack/start-server-functions-fetcher': workspace:* - '@tanstack/start-server-functions-handler': workspace:* '@tanstack/start-server-functions-client': workspace:* '@tanstack/start-server-functions-ssr': workspace:* '@tanstack/start-server-functions-server': workspace:* + '@tanstack/start-plugin-core': workspace:* '@tanstack/start-client-core': workspace:* '@tanstack/start-server-core': workspace:* '@tanstack/eslint-plugin-router': workspace:* @@ -69,7 +69,7 @@ importers: version: 1.50.1 '@tanstack/config': specifier: ^0.16.1 - version: 0.16.1(@types/node@22.13.4)(esbuild@0.25.0)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: 0.16.1(@types/node@22.13.4)(esbuild@0.25.2)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) '@tanstack/react-query': specifier: 5.66.0 version: 5.66.0(react@19.0.0) @@ -238,7 +238,7 @@ importers: version: 19.0.3(@types/react@19.0.8) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 e2e/react-router/basic-file-based: dependencies: @@ -954,9 +954,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1027,9 +1024,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@playwright/test': specifier: ^1.50.1 @@ -1097,9 +1091,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@playwright/test': specifier: ^1.50.1 @@ -1161,9 +1152,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -1204,9 +1192,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@tanstack/router-e2e-utils': specifier: workspace:^ @@ -1250,9 +1235,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@playwright/test': specifier: ^1.50.1 @@ -1314,9 +1296,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1384,9 +1363,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1454,9 +1430,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -1564,10 +1537,10 @@ importers: version: link:../../e2e-utils esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 esbuild-plugin-solid: specifier: ^0.6.0 - version: 0.6.0(esbuild@0.25.0)(solid-js@1.9.5) + version: 0.6.0(esbuild@0.25.2)(solid-js@1.9.5) e2e/solid-router/basic-file-based: dependencies: @@ -2045,7 +2018,7 @@ importers: version: 2.6.0 vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2097,7 +2070,7 @@ importers: version: 1.9.5 vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@tanstack/router-e2e-utils': specifier: workspace:^ @@ -2134,7 +2107,7 @@ importers: version: 2.6.0 vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2195,7 +2168,7 @@ importers: version: 2.6.0 vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -2256,7 +2229,7 @@ importers: version: 2.6.0 vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -3290,7 +3263,7 @@ importers: dependencies: '@radix-ui/react-dialog': specifier: ^1.1.6 - version: 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 1.1.7(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) '@tanstack/react-query': specifier: 5.66.0 version: 5.66.0(react@19.0.0) @@ -3453,7 +3426,7 @@ importers: version: 19.0.3(@types/react@19.0.8) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 examples/react/quickstart-file-based: dependencies: @@ -3585,7 +3558,7 @@ importers: version: 5.8.2 webpack: specifier: ^5.97.1 - version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) @@ -4258,9 +4231,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4310,9 +4280,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4368,9 +4338,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4429,9 +4396,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4484,9 +4448,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -4533,9 +4494,6 @@ importers: tailwind-merge: specifier: ^2.5.5 version: 2.6.0 - vinxi: - specifier: 0.5.1 - version: 0.5.1(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4588,9 +4546,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4670,9 +4625,6 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4716,9 +4668,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4762,9 +4711,6 @@ importers: valibot: specifier: ^1.0.0-beta.15 version: 1.0.0-beta.15(typescript@5.8.2) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/node': specifier: ^22.5.4 @@ -4828,7 +4774,7 @@ importers: version: 19.0.0(react@19.0.0) vinxi: specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + version: 0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -4872,9 +4818,6 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -4942,9 +4885,6 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5000,9 +4940,9 @@ importers: react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: '@types/react': specifier: ^19.0.8 @@ -5162,9 +5102,6 @@ importers: tailwindcss: specifier: ^3.4.17 version: 3.4.17 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5226,9 +5163,6 @@ importers: tailwindcss: specifier: ^3.4.17 version: 3.4.17 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5246,7 +5180,7 @@ importers: examples/solid/basic: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5286,7 +5220,7 @@ importers: examples/solid/basic-devtools-panel: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5320,7 +5254,7 @@ importers: examples/solid/basic-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5360,7 +5294,7 @@ importers: examples/solid/basic-non-nested-devtools: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5406,7 +5340,7 @@ importers: specifier: ^5.71.9 version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5449,7 +5383,7 @@ importers: specifier: ^5.71.9 version: 5.71.9(@tanstack/solid-query@5.71.9(solid-js@1.9.5))(solid-js@1.9.5) '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5489,7 +5423,7 @@ importers: examples/solid/kitchen-sink-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5532,7 +5466,7 @@ importers: examples/solid/quickstart-file-based: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5572,7 +5506,7 @@ importers: examples/solid/start-bare: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5589,9 +5523,9 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: specifier: ^3.24.2 version: 3.24.2 @@ -5621,7 +5555,7 @@ importers: examples/solid/start-basic: dependencies: '@tanstack/solid-router': - specifier: ^1.115.0 + specifier: ^1.116.0 version: link:../../../packages/solid-router '@tanstack/solid-router-devtools': specifier: workspace:^ @@ -5638,9 +5572,6 @@ importers: tailwind-merge: specifier: ^2.6.0 version: 2.6.0 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) vite: specifier: 6.1.4 version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) @@ -5752,7 +5683,7 @@ importers: version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) webpack: specifier: ^5.94.0 - version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: specifier: ^5.1.4 version: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) @@ -5835,9 +5766,6 @@ importers: validate-npm-package-name: specifier: ^6.0.0 version: 6.0.0 - vinxi: - specifier: 0.5.1 - version: 0.5.1(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) vite: specifier: 6.1.4 version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) @@ -6025,12 +5953,9 @@ importers: '@tanstack/react-start-client': specifier: workspace:* version: link:../react-start-client - '@tanstack/react-start-config': - specifier: workspace:* - version: link:../react-start-config - '@tanstack/react-start-router-manifest': + '@tanstack/react-start-plugin': specifier: workspace:* - version: link:../react-start-router-manifest + version: link:../react-start-plugin '@tanstack/react-start-server': specifier: workspace:* version: link:../react-start-server @@ -6040,9 +5965,6 @@ importers: '@tanstack/start-server-functions-client': specifier: workspace:* version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler '@tanstack/start-server-functions-server': specifier: workspace:* version: link:../start-server-functions-server @@ -6061,7 +5983,7 @@ importers: devDependencies: esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 packages/react-start-client: dependencies: @@ -6092,9 +6014,6 @@ importers: tiny-warning: specifier: ^1.0.3 version: 1.0.3 - vinxi: - specifier: ^0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@testing-library/react': specifier: ^16.2.0 @@ -6106,54 +6025,6 @@ importers: specifier: ^4.3.4 version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - packages/react-start-config: - dependencies: - '@tanstack/react-start-plugin': - specifier: workspace:* - version: link:../react-start-plugin - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/router-generator': - specifier: workspace:* - version: link:../router-generator - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../router-plugin - '@tanstack/server-functions-plugin': - specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - import-meta-resolve: - specifier: ^4.1.0 - version: 4.1.0 - nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - zod: - specifier: ^3.24.2 - version: 3.24.2 - packages/react-start-plugin: dependencies: '@babel/code-frame': @@ -6177,19 +6048,21 @@ importers: '@babel/types': specifier: ^7.26.8 version: 7.26.8 + '@tanstack/router-core': + specifier: workspace:* + version: link:../router-core + '@tanstack/router-plugin': + specifier: workspace:* + version: link:../router-plugin '@tanstack/router-utils': specifier: workspace:* version: link:../router-utils - babel-dead-code-elimination: - specifier: ^1.0.10 - version: 1.0.10 - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - devDependencies: + '@tanstack/server-functions-plugin': + specifier: workspace:* + version: link:../server-functions-plugin + '@tanstack/start-plugin-core': + specifier: workspace:* + version: link:../start-plugin-core '@types/babel__code-frame': specifier: ^7.0.6 version: 7.0.6 @@ -6202,22 +6075,39 @@ importers: '@types/babel__traverse': specifier: ^7.20.6 version: 7.20.6 - - packages/react-start-router-manifest: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + babel-dead-code-elimination: + specifier: ^1.0.9 + version: 1.0.10 + fast-glob: + specifier: ^3.3.3 + version: 3.3.3 + get-port: + specifier: ^7.1.0 + version: 7.1.0 + h3: + specifier: 1.13.0 + version: 1.13.0 + import-meta-resolve: + specifier: ^4.1.0 + version: 4.1.0 + nitropack: + specifier: ^2.11.8 + version: 2.11.8 tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 + ufo: + specifier: ^1.5.4 + version: 1.5.4 + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + zod: + specifier: ^3.24.2 + version: 3.24.2 packages/react-start-server: dependencies: @@ -6245,6 +6135,9 @@ importers: jsesc: specifier: ^3.1.0 version: 3.1.0 + tiny-invariant: + specifier: ^1.3.3 + version: 1.3.3 tiny-warning: specifier: ^1.0.3 version: 1.0.3 @@ -6260,7 +6153,7 @@ importers: version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 react: specifier: ^19.0.0 version: 19.0.0 @@ -6425,7 +6318,7 @@ importers: version: 3.6.0 unplugin: specifier: ^2.1.2 - version: 2.1.2 + version: 2.2.2 vite: specifier: 6.1.4 version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) @@ -6434,7 +6327,7 @@ importers: version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) webpack: specifier: '>=5.92.0' - version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0) + version: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2) zod: specifier: ^3.24.2 version: 3.24.2 @@ -6595,12 +6488,9 @@ importers: '@tanstack/solid-start-client': specifier: workspace:* version: link:../solid-start-client - '@tanstack/solid-start-config': - specifier: workspace:* - version: link:../solid-start-config - '@tanstack/solid-start-router-manifest': + '@tanstack/solid-start-plugin': specifier: workspace:* - version: link:../solid-start-router-manifest + version: link:../solid-start-plugin '@tanstack/solid-start-server': specifier: workspace:* version: link:../solid-start-server @@ -6610,9 +6500,6 @@ importers: '@tanstack/start-server-functions-client': specifier: workspace:* version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler '@tanstack/start-server-functions-server': specifier: workspace:* version: link:../start-server-functions-server @@ -6628,7 +6515,7 @@ importers: devDependencies: esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 packages/solid-start-client: dependencies: @@ -6656,9 +6543,6 @@ importers: tiny-warning: specifier: ^1.0.3 version: 1.0.3 - vinxi: - specifier: ^0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: '@solidjs/testing-library': specifier: ^0.8.10 @@ -6673,51 +6557,6 @@ importers: specifier: ^2.11.2 version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - packages/solid-start-config: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/router-generator': - specifier: workspace:* - version: link:../router-generator - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../router-plugin - '@tanstack/server-functions-plugin': - specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/solid-start-plugin': - specifier: workspace:* - version: link:../solid-start-plugin - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler - import-meta-resolve: - specifier: ^4.1.0 - version: 4.1.0 - nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - solid-js: - specifier: '>=1.0.0' - version: 1.9.5 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - vite-plugin-solid: - specifier: ^2.11.2 - version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) - zod: - specifier: ^3.24.2 - version: 3.24.2 - packages/solid-start-plugin: dependencies: '@babel/code-frame': @@ -6741,19 +6580,21 @@ importers: '@babel/types': specifier: ^7.26.8 version: 7.26.8 + '@tanstack/router-core': + specifier: workspace:* + version: link:../router-core + '@tanstack/router-plugin': + specifier: workspace:* + version: link:../router-plugin '@tanstack/router-utils': specifier: workspace:* version: link:../router-utils - babel-dead-code-elimination: - specifier: ^1.0.9 - version: 1.0.10 - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - vite: - specifier: 6.1.4 - version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - devDependencies: + '@tanstack/server-functions-plugin': + specifier: workspace:* + version: link:../server-functions-plugin + '@tanstack/start-plugin-core': + specifier: workspace:* + version: link:../start-plugin-core '@types/babel__code-frame': specifier: ^7.0.6 version: 7.0.6 @@ -6766,22 +6607,39 @@ importers: '@types/babel__traverse': specifier: ^7.20.6 version: 7.20.6 - - packages/solid-start-router-manifest: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core + babel-dead-code-elimination: + specifier: ^1.0.9 + version: 1.0.10 + fast-glob: + specifier: ^3.3.3 + version: 3.3.3 + get-port: + specifier: ^7.1.0 + version: 7.1.0 + h3: + specifier: 1.13.0 + version: 1.13.0 + import-meta-resolve: + specifier: ^4.1.0 + version: 4.1.0 + nitropack: + specifier: ^2.11.8 + version: 2.11.8 tiny-invariant: specifier: ^1.3.3 version: 1.3.3 - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 + ufo: + specifier: ^1.5.4 + version: 1.5.4 + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + vite-plugin-solid: + specifier: ^2.11.6 + version: 2.11.6(@testing-library/jest-dom@6.6.3)(solid-js@1.9.5)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + zod: + specifier: ^3.24.2 + version: 3.24.2 packages/solid-start-server: dependencies: @@ -6824,7 +6682,7 @@ importers: version: 3.0.3 esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 solid-js: specifier: ^1.9.5 version: 1.9.5 @@ -6840,24 +6698,18 @@ importers: '@tanstack/react-start-client': specifier: workspace:* version: link:../react-start-client - '@tanstack/react-start-router-manifest': + '@tanstack/react-start-plugin': specifier: workspace:* - version: link:../react-start-router-manifest + version: link:../react-start-plugin '@tanstack/react-start-server': specifier: workspace:* version: link:../react-start-server '@tanstack/start-api-routes': specifier: workspace:* version: link:../start-api-routes - '@tanstack/start-config': - specifier: workspace:^ - version: link:../start-config '@tanstack/start-server-functions-client': specifier: workspace:* version: link:../start-server-functions-client - '@tanstack/start-server-functions-handler': - specifier: workspace:* - version: link:../start-server-functions-handler '@tanstack/start-server-functions-server': specifier: workspace:* version: link:../start-server-functions-server @@ -6873,9 +6725,6 @@ importers: '@tanstack/start-server-core': specifier: workspace:* version: link:../start-server-core - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) devDependencies: typescript: specifier: ^5.7.2 @@ -6896,50 +6745,62 @@ importers: specifier: ^1.0.3 version: 1.0.3 - packages/start-config: + packages/start-plugin-core: dependencies: - '@tanstack/react-router': - specifier: workspace:* - version: link:../react-router - '@tanstack/react-start-plugin': - specifier: workspace:* - version: link:../react-start-plugin + '@babel/code-frame': + specifier: 7.26.2 + version: 7.26.2 + '@babel/core': + specifier: ^7.26.8 + version: 7.26.8 + '@babel/plugin-syntax-typescript': + specifier: ^7.25.9 + version: 7.25.9(@babel/core@7.26.8) + '@babel/template': + specifier: ^7.26.8 + version: 7.26.8 + '@babel/traverse': + specifier: ^7.26.8 + version: 7.26.8 + '@babel/types': + specifier: ^7.26.8 + version: 7.26.8 '@tanstack/router-generator': specifier: workspace:* version: link:../router-generator - '@tanstack/router-plugin': - specifier: workspace:* - version: link:../router-plugin - '@tanstack/server-functions-plugin': - specifier: workspace:* - version: link:../server-functions-plugin - '@tanstack/start-server-functions-handler': + '@tanstack/router-utils': specifier: workspace:* - version: link:../start-server-functions-handler - '@vitejs/plugin-react': - specifier: ^4.3.4 - version: 4.3.4(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)) + version: link:../router-utils + '@types/babel__code-frame': + specifier: ^7.0.6 + version: 7.0.6 + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 + '@types/babel__template': + specifier: ^7.4.4 + version: 7.4.4 + '@types/babel__traverse': + specifier: ^7.20.6 + version: 7.20.6 + babel-dead-code-elimination: + specifier: ^1.0.9 + version: 1.0.10 import-meta-resolve: specifier: ^4.1.0 version: 4.1.0 nitropack: - specifier: ^2.10.4 - version: 2.10.4(typescript@5.8.2) - ofetch: - specifier: ^1.4.1 - version: 1.4.1 - react: - specifier: ^19.0.0 - version: 19.0.0 - react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) - vinxi: - specifier: 0.5.3 - version: 0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0) + specifier: ^2.11.8 + version: 2.11.8 + tiny-invariant: + specifier: ^1.3.3 + version: 1.3.3 vite: specifier: 6.1.4 version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) + xmlbuilder2: + specifier: ^3.1.1 + version: 3.1.1 zod: specifier: ^3.24.2 version: 3.24.2 @@ -6964,6 +6825,9 @@ importers: jsesc: specifier: ^3.1.0 version: 3.1.0 + tiny-invariant: + specifier: ^1.3.3 + version: 1.3.3 tiny-warning: specifier: ^1.0.3 version: 1.0.3 @@ -6976,7 +6840,7 @@ importers: version: 3.0.3 esbuild: specifier: ^0.25.0 - version: 0.25.0 + version: 0.25.2 typescript: specifier: ^5.7.2 version: 5.8.2 @@ -7007,25 +6871,6 @@ importers: specifier: ^5.7.2 version: 5.8.2 - packages/start-server-functions-handler: - dependencies: - '@tanstack/router-core': - specifier: workspace:* - version: link:../router-core - '@tanstack/start-client-core': - specifier: workspace:* - version: link:../start-client-core - '@tanstack/start-server-core': - specifier: workspace:* - version: link:../start-server-core - tiny-invariant: - specifier: ^1.3.3 - version: 1.3.3 - devDependencies: - typescript: - specifier: ^5.7.2 - version: 5.8.2 - packages/start-server-functions-server: dependencies: '@tanstack/server-functions-plugin': @@ -7034,6 +6879,9 @@ importers: tiny-invariant: specifier: ^1.3.3 version: 1.3.3 + vite: + specifier: 6.1.4 + version: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) devDependencies: typescript: specifier: ^5.7.2 @@ -7351,9 +7199,9 @@ packages: resolution: {integrity: sha512-b4LR3Xsegqe0S6ZkaSJ1skO5a36EIiYRCFBzrJIbJX58vh25FFbOs4VHcK71uCLGJ1Jm1bViPi8QPGYoqYAUuw==} engines: {node: '>=18.17.0'} - '@cloudflare/kv-asset-handler@0.3.4': - resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} - engines: {node: '>=16.13'} + '@cloudflare/kv-asset-handler@0.4.0': + resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} + engines: {node: '>=18.0.0'} '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -7503,8 +7351,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.25.0': - resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} + '@esbuild/aix-ppc64@0.25.2': + resolution: {integrity: sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -7533,8 +7381,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.0': - resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} + '@esbuild/android-arm64@0.25.2': + resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -7563,8 +7411,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.0': - resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} + '@esbuild/android-arm@0.25.2': + resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -7593,8 +7441,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.0': - resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} + '@esbuild/android-x64@0.25.2': + resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -7623,8 +7471,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.0': - resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} + '@esbuild/darwin-arm64@0.25.2': + resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -7653,8 +7501,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.0': - resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} + '@esbuild/darwin-x64@0.25.2': + resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -7683,8 +7531,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.0': - resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} + '@esbuild/freebsd-arm64@0.25.2': + resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -7713,8 +7561,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.0': - resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} + '@esbuild/freebsd-x64@0.25.2': + resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -7743,8 +7591,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.0': - resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} + '@esbuild/linux-arm64@0.25.2': + resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -7773,8 +7621,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.0': - resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} + '@esbuild/linux-arm@0.25.2': + resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -7803,8 +7651,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.0': - resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} + '@esbuild/linux-ia32@0.25.2': + resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -7833,8 +7681,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.0': - resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} + '@esbuild/linux-loong64@0.25.2': + resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -7863,8 +7711,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.0': - resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} + '@esbuild/linux-mips64el@0.25.2': + resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -7893,8 +7741,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.0': - resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} + '@esbuild/linux-ppc64@0.25.2': + resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -7923,8 +7771,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.0': - resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} + '@esbuild/linux-riscv64@0.25.2': + resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -7953,8 +7801,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.0': - resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} + '@esbuild/linux-s390x@0.25.2': + resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -7983,8 +7831,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.0': - resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} + '@esbuild/linux-x64@0.25.2': + resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -7995,8 +7843,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.25.0': - resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} + '@esbuild/netbsd-arm64@0.25.2': + resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -8025,8 +7873,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.0': - resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} + '@esbuild/netbsd-x64@0.25.2': + resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -8049,8 +7897,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.25.0': - resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} + '@esbuild/openbsd-arm64@0.25.2': + resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -8079,8 +7927,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.0': - resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} + '@esbuild/openbsd-x64@0.25.2': + resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -8109,8 +7957,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.0': - resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} + '@esbuild/sunos-x64@0.25.2': + resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -8139,8 +7987,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.0': - resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} + '@esbuild/win32-arm64@0.25.2': + resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -8169,8 +8017,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.0': - resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} + '@esbuild/win32-ia32@0.25.2': + resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -8199,8 +8047,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.0': - resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} + '@esbuild/win32-x64@0.25.2': + resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -8806,16 +8654,12 @@ packages: '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} - '@netlify/functions@2.8.2': - resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==} - engines: {node: '>=14.0.0'} - - '@netlify/node-cookies@0.1.0': - resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} - engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/functions@3.0.4': + resolution: {integrity: sha512-Ox8+ABI+nsLK+c4/oC5dpquXuEIjzfTlJrdQKgQijCsDQoje7inXFAtKDLvvaGvuvE+PVpMLwQcIUL6P9Ob1hQ==} + engines: {node: '>=18.0.0'} - '@netlify/serverless-functions-api@1.26.1': - resolution: {integrity: sha512-q3L9i3HoNfz0SGpTIS4zTcKBbRkxzCRpd169eyiTuk3IwcPC3/85mzLHranlKo2b+HYT0gu37YxGB45aD8A3Tw==} + '@netlify/serverless-functions-api@1.36.0': + resolution: {integrity: sha512-z6okREyK8in0486a22Oro0k+YsuyEjDXJt46FpgeOgXqKJ9ElM8QPll0iuLBkpbH33ENiNbIPLd1cuClRQnhiw==} engines: {node: '>=18.0.0'} '@nodelib/fs.scandir@2.1.5': @@ -8893,6 +8737,22 @@ packages: cpu: [x64] os: [win32] + '@oozcitak/dom@1.15.10': + resolution: {integrity: sha512-0JT29/LaxVgRcGKvHmSrUTEvZ8BXvZhGl2LASRUgHqDTC1M5g1pLmVv56IYNyt3bG2CUjDkc67wnyZC14pbQrQ==} + engines: {node: '>=8.0'} + + '@oozcitak/infra@1.0.8': + resolution: {integrity: sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==} + engines: {node: '>=6.0'} + + '@oozcitak/url@1.0.4': + resolution: {integrity: sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==} + engines: {node: '>=8.0'} + + '@oozcitak/util@8.3.8': + resolution: {integrity: sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==} + engines: {node: '>=8.0'} + '@open-draft/deferred-promise@2.2.0': resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} @@ -9022,6 +8882,17 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@poppinss/colors@4.1.4': + resolution: {integrity: sha512-FA+nTU8p6OcSH4tLDY5JilGYr1bVWHpNmcLr7xmMEdbWmKHa+3QZ+DqefrXKmdjO/brHTnQZo20lLSjaO7ydog==} + engines: {node: '>=18.16.0'} + + '@poppinss/dumper@0.6.3': + resolution: {integrity: sha512-iombbn8ckOixMtuV1p3f8jN6vqhXefNjJttoPaJDMeIk/yIGhkkL3OrHkEjE9SRsgoAx1vBUU2GtgggjvA5hCA==} + + '@poppinss/exception@1.2.1': + resolution: {integrity: sha512-aQypoot0HPSJa6gDPEPTntc1GT6QINrSbgRlRhadGW2WaYqUK3tK4Bw9SBMZXhmxd3GeAlZjVcODHgiu+THY7A==} + engines: {node: '>=18'} + '@prisma/client@5.22.0': resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==} engines: {node: '>=16.13'} @@ -9086,9 +8957,6 @@ packages: '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - '@radix-ui/primitive@1.1.1': - resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} - '@radix-ui/primitive@1.1.2': resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} @@ -9209,15 +9077,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-compose-refs@1.1.1': - resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: @@ -9240,15 +9099,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-context@1.1.1': - resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-context@1.1.2': resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: @@ -9258,53 +9108,27 @@ packages: '@types/react': optional: true - '@radix-ui/react-dialog@1.1.6': - resolution: {integrity: sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-dialog@1.1.7': resolution: {integrity: sha512-EIdma8C0C/I6kL6sO02avaCRqi3fmWJpxH6mqbVScorW6nNktzKJT/le7VPho3o/7wCsyRg3z0+Q+Obr0Gy/VQ==} peerDependencies: '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': ^19.0.8 + '@types/react-dom': ^19.0.3 react: ^19.0.0 + react-dom: ^19.0.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true - '@radix-ui/react-dismissable-layer@1.1.5': - resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==} + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 react: ^19.0.0 - react-dom: ^19.0.0 peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true '@radix-ui/react-dismissable-layer@1.1.6': resolution: {integrity: sha512-7gpgMT2gyKym9Jz2ZhlRXSg2y6cNQIK8d/cqBZ0RBCaps8pFryCWXiUKI+uHGFrhMrbGUP7U6PWgiXzIxoyF3Q==} @@ -9332,15 +9156,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-focus-guards@1.1.1': - resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-focus-guards@1.1.2': resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} peerDependencies: @@ -9350,19 +9165,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-focus-scope@1.1.2': - resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-focus-scope@1.1.3': resolution: {integrity: sha512-4XaDlq0bPt7oJwR+0k0clCiCO/7lO7NKZTAaJBYxDNQT/vj4ig0/UvctrRscZaFREpRvUTkpKR96ov1e6jptQg==} peerDependencies: @@ -9402,15 +9204,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-id@1.1.0': - resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: @@ -9498,19 +9291,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-portal@1.1.4': - resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-portal@1.1.5': resolution: {integrity: sha512-ps/67ZqsFm+Mb6lSPJpfhRLrVL2i2fntgCmGMqqth4eaGUf+knAuuRtWVJrNjUhExgmdRqftSgzpf0DF0n6yXA==} peerDependencies: @@ -9524,19 +9304,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-presence@1.1.2': - resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-presence@1.1.3': resolution: {integrity: sha512-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA==} peerDependencies: @@ -9550,19 +9317,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-primitive@2.0.2': - resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==} - peerDependencies: - '@types/react': ^19.0.8 - '@types/react-dom': ^19.0.3 - react: ^19.0.0 - react-dom: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-primitive@2.0.3': resolution: {integrity: sha512-Pf/t/GkndH7CQ8wE2hbkXA+WyZ83fhQQn5DDmwDiDo6AwN/fhaH8oqZ0jRjMrO2iaMhDi6P1HRx6AZwyMinY1g==} peerDependencies: @@ -9667,15 +9421,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slot@1.1.2': - resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-slot@1.2.0': resolution: {integrity: sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==} peerDependencies: @@ -9776,15 +9521,6 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-use-callback-ref@1.1.0': - resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-callback-ref@1.1.1': resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: @@ -9794,15 +9530,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-controllable-state@1.1.0': - resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-controllable-state@1.1.1': resolution: {integrity: sha512-YnEXIy8/ga01Y1PN0VfaNH//MhA91JlEGVBDxDzROqwrAtG5Yr2QGEPz8A/rJA3C7ZAHryOYGaUv8fLSW2H/mg==} peerDependencies: @@ -9812,15 +9539,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-escape-keydown@1.1.0': - resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-escape-keydown@1.1.1': resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: @@ -9830,15 +9548,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-layout-effect@1.1.0': - resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} - peerDependencies: - '@types/react': ^19.0.8 - react: ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@radix-ui/react-use-layout-effect@1.1.1': resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: @@ -9904,16 +9613,6 @@ packages: '@types/react-dom': optional: true - '@redocly/ajv@8.11.2': - resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} - - '@redocly/config@0.20.3': - resolution: {integrity: sha512-Nyyv1Bj7GgYwj/l46O0nkH1GTKWbO3Ixe7KFcn021aZipkZd+z8Vlu1BwkhqtVgivcKaClaExtWU/lDHkjBzag==} - - '@redocly/openapi-core@1.28.0': - resolution: {integrity: sha512-jnUsOFnz8w71l14Ww34Iswlj0AI4e/R0C5+K2W4v4GaY/sUkpH/145gHLJYlG4XV0neET4lNIptd4I8+yLyEHQ==} - engines: {node: '>=18.17.0', npm: '>=10.8.2'} - '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} @@ -9936,8 +9635,8 @@ packages: rollup: optional: true - '@rollup/plugin-commonjs@28.0.2': - resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} + '@rollup/plugin-commonjs@28.0.3': + resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==} engines: {node: '>=16.0.0 || 14 >= 14.17'} peerDependencies: rollup: ^2.68.0||^3.0.0||^4.0.0 @@ -9963,17 +9662,8 @@ packages: rollup: optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-node-resolve@16.0.0': - resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==} + '@rollup/plugin-node-resolve@16.0.1': + resolution: {integrity: sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -10365,6 +10055,10 @@ packages: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} + '@sindresorhus/is@7.0.1': + resolution: {integrity: sha512-QWLl2P+rsCJeofkDNIT3WFmb6NrRud1SUYW8dIhXK/46XFV8Q/g7Bsvib0Askb0reRLe+WYPeeE+l5cH7SlkuQ==} + engines: {node: '>=18'} + '@sindresorhus/merge-streams@2.3.0': resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} engines: {node: '>=18'} @@ -10469,6 +10163,9 @@ packages: '@solidjs/router': optional: true + '@speed-highlight/core@1.2.7': + resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@stylistic/eslint-plugin-js@2.13.0': resolution: {integrity: sha512-GPPDK4+fcbsQD58a3abbng2Dx+jBoxM5cnYjBM4T24WFZRZdlNSKvR19TxP8CPevzMOodQ9QVzNeqWvMXzfJRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -11087,9 +10784,9 @@ packages: resolution: {integrity: sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vercel/nft@0.27.10': - resolution: {integrity: sha512-zbaF9Wp/NsZtKLE4uVmL3FyfFwlpDyuymQM1kPbeT0mVOHKDQQNjnnfslB3REg3oZprmNFJuh3pkHBk2qAaizg==} - engines: {node: '>=16'} + '@vercel/nft@0.29.2': + resolution: {integrity: sha512-A/Si4mrTkQqJ6EXJKv5EYCDQ3NL6nJXxG8VGXePsaiQigsomHYQC9xSpX8qGk7AEZk4b1ssbYIqJ0ISQQ7bfcA==} + engines: {node: '>=18'} hasBin: true '@vinxi/listhen@1.5.6': @@ -11305,8 +11002,8 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} engines: {node: '>=0.4.0'} hasBin: true @@ -11589,8 +11286,8 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - c12@2.0.1: - resolution: {integrity: sha512-Z4JgsKXHG37C6PYUtIxCfLJZvo6FyhHJoClwwb9ftUkLpPSkuYqn6Tr+vnaN8hymm0kIbcg6Ey3kv/Q71k5w/A==} + c12@3.0.2: + resolution: {integrity: sha512-6Tzk1/TNeI3WBPpK0j/Ss4+gPj3PUJYbWl/MWDJBThFvwNGNkXtd7Cz8BJtD4aRwoGHtzQD0SnxamgUiBH0/Nw==} peerDependencies: magicast: ^0.3.5 peerDependenciesMeta: @@ -11646,9 +11343,6 @@ packages: resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -11668,10 +11362,6 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -11833,12 +11523,15 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + confbox@0.2.1: + resolution: {integrity: sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==} + connect-history-api-fallback@2.0.0: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} - consola@3.4.0: - resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} content-disposition@0.5.4: @@ -11886,6 +11579,9 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} @@ -11936,8 +11632,8 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crossws@0.3.3: - resolution: {integrity: sha512-/71DJT3xJlqSnBr83uGJesmVHSzZEvgxHt/fIKxBAAngqMHmnBWQNxCphVxxJ2XL3xleu5+hJD6IQ3TglBedcw==} + crossws@0.3.4: + resolution: {integrity: sha512-uj0O1ETYX1Bh6uSgktfPvwDiPYGQ3aI4qVsaC/LWpkIzGj1nUYm5FK3K+t11oOlpN01lGbprFCH4wBlKdJjVgw==} crypto-random-string@4.0.0: resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} @@ -12019,8 +11715,8 @@ packages: dax-sh@0.39.2: resolution: {integrity: sha512-gpuGEkBQM+5y6p4cWaw9+ePy5TNon+fdwFVtTI8leU3UhwhsBfPewRxMXGuQNC+M2b/MDGMlfgpqynkcd0C3FQ==} - db0@0.2.3: - resolution: {integrity: sha512-PunuHESDNefmwVy1LDpY663uWwKt2ogLGoB6NOz2sflGREWqDreMwDgF8gfkXxgNXW+dqviyiJGm924H1BaGiw==} + db0@0.3.1: + resolution: {integrity: sha512-3RogPLE2LLq6t4YiFCREyl572aBjkfMvfwPyN51df00TbPbryL3XqBYuJ/j6mgPssPK8AKfYdLxizaO5UG10sA==} peerDependencies: '@electric-sql/pglite': '*' '@libsql/client': '*' @@ -12303,6 +11999,9 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} @@ -12352,8 +12051,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.25.0: - resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} + esbuild@0.25.2: + resolution: {integrity: sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==} engines: {node: '>=18'} hasBin: true @@ -12588,6 +12287,9 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + exsolve@1.0.4: + resolution: {integrity: sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -12768,10 +12470,6 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -12822,8 +12520,8 @@ packages: get-tsconfig@4.10.0: resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} - giget@1.2.4: - resolution: {integrity: sha512-Wv+daGyispVoA31TrWAVR+aAdP7roubTPEM/8JzRnqXhLbdJH0T9eQyXVFF8fjk3WKTsctII6QcyxILYgNp2DA==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true glob-parent@5.1.2: @@ -12878,8 +12576,8 @@ packages: resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} engines: {node: '>=8'} - globby@14.0.2: - resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} engines: {node: '>=18'} globrex@0.1.2: @@ -12915,6 +12613,9 @@ packages: h3@1.13.0: resolution: {integrity: sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg==} + h3@1.15.1: + resolution: {integrity: sha512-+ORaOBttdUm1E2Uu/obAyCguiI7MbBvsLTndc3gyK3zU+SYLoZXlyCP9Xgy0gikkGufFLTZXCXD6+4BsufnmHA==} + handle-thing@2.0.1: resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} @@ -13059,6 +12760,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.3: + resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + engines: {node: '>= 4'} + immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} @@ -13086,10 +12791,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - index-to-position@0.1.2: - resolution: {integrity: sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g==} - engines: {node: '>=18'} - inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -13110,8 +12811,8 @@ packages: resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} engines: {node: '>=10.13.0'} - ioredis@5.4.2: - resolution: {integrity: sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==} + ioredis@5.6.0: + resolution: {integrity: sha512-tBZlIIWbndeWBWCXWZiqtOF/yxf6yZX3tAlTJ7nfo5jhd6dctNxF7QnYlZLZ1a0o0pDoen7CgZqO+zjNaFbJAg==} engines: {node: '>=12.22.0'} ipaddr.js@1.9.1: @@ -13348,10 +13049,6 @@ packages: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} engines: {node: '>=14'} - js-levenshtein@1.1.6: - resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} - engines: {node: '>=0.10.0'} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -13426,6 +13123,10 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} @@ -13551,8 +13252,8 @@ packages: resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} engines: {node: '>=14'} - local-pkg@1.0.0: - resolution: {integrity: sha512-bbgPw/wmroJsil/GgL4qjDzs5YLTBMQ99weRsok1XCDccQeehbHA/I1oRvk2NPtr7KGZgT/Y5tPRnAtMqeG2Kg==} + local-pkg@1.1.1: + resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==} engines: {node: '>=14'} locate-path@5.0.0: @@ -13773,35 +13474,18 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - minipass@4.2.8: resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} engines: {node: '>=8'} - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - minizlib@3.0.1: resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} engines: {node: '>= 18'} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -13895,8 +13579,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nitropack@2.10.4: - resolution: {integrity: sha512-sJiG/MIQlZCVSw2cQrFG1H6mLeSqHlYfFerRjLKz69vUfdu0EL2l0WdOxlQbzJr3mMv/l4cOlCCLzVRzjzzF/g==} + nitropack@2.11.8: + resolution: {integrity: sha512-ummTu4R8Lhd1nO3nWrW7eeiHA2ey3ntbWFKkYakm4rcbvT6meWp+oykyrYBNFQKhobQl9CydmUWlCyztYXFPJw==} engines: {node: ^16.11.0 || >=17.0.0} hasBin: true peerDependencies: @@ -13946,6 +13630,9 @@ packages: node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} + node-mock-http@1.0.0: + resolution: {integrity: sha512-0uGYQ1WQL1M5kKvGRXWQ3uZCHtLTO8hln3oBjIusM75WoesZ909uQJs/Hb946i2SS+Gsrhkaa6iAO17jRIv6DQ==} + node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} @@ -13988,8 +13675,8 @@ packages: '@swc/core': optional: true - nypm@0.5.2: - resolution: {integrity: sha512-AHzvnyUJYSrrphPhRWWZNcoZfArGNp3Vrc4pm/ZurO74tYNTgAPrEyBQEKy+qioqmWlPXwvMZCG2wOaHlPG0Pw==} + nypm@0.6.0: + resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} engines: {node: ^14.16.0 || >=16.10.0} hasBin: true @@ -14022,6 +13709,9 @@ packages: ohash@1.1.4: resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -14049,12 +13739,6 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-typescript@7.6.0: - resolution: {integrity: sha512-p/xxKcWFR7aZDOAdnqYBQ1NdNyWdine+gHKHKvjxGXmlq8JT1G9+SkY8I5csKaktLHMbDDH6ZDeWQpydwBHa+Q==} - hasBin: true - peerDependencies: - typescript: ^5.x - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -14115,10 +13799,6 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-json@8.1.0: - resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} - engines: {node: '>=18'} - parse-passwd@1.0.0: resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} engines: {node: '>=0.10.0'} @@ -14190,9 +13870,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - path-type@5.0.0: - resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} - engines: {node: '>=12'} + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -14233,6 +13913,9 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.1.0: + resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==} + playwright-core@1.50.1: resolution: {integrity: sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==} engines: {node: '>=18'} @@ -14546,6 +14229,9 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + quansync@0.2.10: + resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -14868,8 +14554,8 @@ packages: engines: {node: '>=10'} hasBin: true - semver@7.7.0: - resolution: {integrity: sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==} + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} hasBin: true @@ -15049,8 +14735,8 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} - std-env@3.8.0: - resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} + std-env@3.8.1: + resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==} streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -15103,8 +14789,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} style-to-object@1.0.8: resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} @@ -15127,6 +14813,10 @@ packages: resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} engines: {node: '>=16'} + supports-color@10.0.0: + resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -15135,10 +14825,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-color@9.4.0: - resolution: {integrity: sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==} - engines: {node: '>=12'} - supports-hyperlinks@3.1.0: resolution: {integrity: sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==} engines: {node: '>=14.18'} @@ -15192,10 +14878,6 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - tar@7.4.3: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} @@ -15480,6 +15162,9 @@ packages: ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + ultrahtml@1.5.3: + resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==} + unbuild@3.3.1: resolution: {integrity: sha512-/5OeeHmW1JlWEyQw3SPkB9BV16lzr6C5i8D+O17NLx6ETgvCZ3ZlyXfWkVVfG2YCsv8xAVQCqJNJtbEAGwHg7A==} hasBin: true @@ -15508,16 +15193,20 @@ packages: unenv@1.10.0: resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} + unenv@2.0.0-rc.15: + resolution: {integrity: sha512-J/rEIZU8w6FOfLNz/hNKsnY+fFHWnu9MH4yRbSZF3xbbGHovcetXPs7sD+9p8L6CeNC//I9bhRYAOsBt2u7/OA==} + unicode-emoji-modifier-base@1.0.0: resolution: {integrity: sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==} engines: {node: '>=4'} - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} engines: {node: '>=18'} - unimport@3.14.6: - resolution: {integrity: sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==} + unimport@4.1.3: + resolution: {integrity: sha512-H+IVJ7rAkE3b+oC8rSJ2FsPaVsweeMC8eKZc+C6Mz7+hxDF45AnrY/tVCNRBvzMwWNcJEV67WdAVcal27iMjOw==} + engines: {node: '>=18.12.0'} unique-string@3.0.0: resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} @@ -15539,6 +15228,10 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin-utils@0.2.4: + resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} + engines: {node: '>=18.12.0'} + unplugin@1.0.1: resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} @@ -15546,31 +15239,31 @@ packages: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} - unplugin@2.1.2: - resolution: {integrity: sha512-Q3LU0e4zxKfRko1wMV2HmP8lB9KWislY7hxXpxd+lGx0PRInE4vhMBVEZwpdVYHvtqzhSrzuIfErsob6bQfCzw==} + unplugin@2.2.2: + resolution: {integrity: sha512-Qp+iiD+qCRnUek+nDoYvtWX7tfnYyXsrOnJ452FRTgOyKmTM7TUJ3l+PLPJOOWPTUyKISKp4isC5JJPSXUjGgw==} engines: {node: '>=18.12.0'} - unstorage@1.14.4: - resolution: {integrity: sha512-1SYeamwuYeQJtJ/USE1x4l17LkmQBzg7deBJ+U9qOBoHo15d1cDxG4jM31zKRgF7pG0kirZy4wVMX6WL6Zoscg==} + unstorage@1.15.0: + resolution: {integrity: sha512-m40eHdGY/gA6xAPqo8eaxqXgBuzQTlAKfmB1iF7oCKXE1HfwHwzDJBywK+qQGn52dta+bPlZluPF7++yR3p/bg==} peerDependencies: '@azure/app-configuration': ^1.8.0 '@azure/cosmos': ^4.2.0 '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.5.0 + '@azure/identity': ^4.6.0 '@azure/keyvault-secrets': ^4.9.0 '@azure/storage-blob': ^12.26.0 '@capacitor/preferences': ^6.0.3 - '@deno/kv': '>=0.8.4' + '@deno/kv': '>=0.9.0' '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 '@planetscale/database': ^1.19.0 '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.0' + '@vercel/blob': '>=0.27.1' '@vercel/kv': ^1.0.1 aws4fetch: ^1.0.20 db0: '>=0.2.1' idb-keyval: ^6.2.1 ioredis: ^5.4.2 - uploadthing: ^7.4.1 + uploadthing: ^7.4.4 peerDependenciesMeta: '@azure/app-configuration': optional: true @@ -15617,6 +15310,10 @@ packages: resolution: {integrity: sha512-eL/8PlhLcMmlMDtNPKhyyz9kEBDS3Uk4yMu/ewlkT2WFbtzScjHWPJLdQLmaGPUKjXzwe9MumOtOgc4Fro96Kg==} hasBin: true + untyped@2.0.0: + resolution: {integrity: sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==} + hasBin: true + unwasm@0.3.9: resolution: {integrity: sha512-LDxTx/2DkFURUd+BU1vUsF/moj0JsoTvl+2tcg2AUOiEzVturhGGx17/IMgGvKUYdZwr33EJHtChCJuhu9Ouvg==} @@ -15633,18 +15330,12 @@ packages: uqr@0.1.2: resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - uri-js-replace@1.0.1: - resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@8.0.2: - resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} - use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -15711,10 +15402,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vinxi@0.5.1: - resolution: {integrity: sha512-jvl2hJ0fyWwfDVQdDDHCJiVxqU4k0A6kFAnljS0kIjrGfhdTvKEWIoj0bcJgMyrKhxNMoZZGmHZsstQgjDIL3g==} - hasBin: true - vinxi@0.5.3: resolution: {integrity: sha512-4sL2SMrRzdzClapP44oXdGjCE1oq7/DagsbjY5A09EibmoIO4LP8ScRVdh03lfXxKRk7nCWK7n7dqKvm+fp/9w==} hasBin: true @@ -16040,6 +15727,10 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xmlbuilder2@3.1.1: + resolution: {integrity: sha512-WCSfbfZnQDdLQLiMdGUQpMxxckeQ4oZNMNhLVkcekTu7xhD4tuUDyAPoY8CwXvBYE6LwBHd6QW2WZXlOWr1vCw==} + engines: {node: '>=12.0'} + xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -16057,9 +15748,6 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml-ast-parser@0.0.43: - resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} - yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -16101,6 +15789,14 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + youch-core@0.3.2: + resolution: {integrity: sha512-fusrlIMLeRvTFYLUjJ9KzlGC3N+6MOPJ68HNj/yJv2nz7zq8t4HEviLms2gkdRPUS7F5rZ5n+pYx9r88m6IE1g==} + engines: {node: '>=18'} + + youch@4.1.0-beta.6: + resolution: {integrity: sha512-y1aNsEeoLXnWb6pI9TvfNPIxySyo4Un3OGxKn7rsNj8+tgSquzXEWkzfA5y6gU0fvzmQgvx3JBn/p51qQ8Xg9A==} + engines: {node: '>=18'} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -16129,7 +15825,7 @@ snapshots: commander: 10.0.1 marked: 9.1.6 marked-terminal: 7.3.0(marked@9.1.6) - semver: 7.7.0 + semver: 7.7.1 '@arethetypeswrong/core@0.17.3': dependencies: @@ -16137,7 +15833,7 @@ snapshots: cjs-module-lexer: 1.4.3 fflate: 0.8.2 lru-cache: 10.4.3 - semver: 7.7.0 + semver: 7.7.1 typescript: 5.6.1-rc validate-npm-package-name: 5.0.1 @@ -16177,7 +15873,7 @@ snapshots: '@babel/types': 7.26.8 '@types/gensync': 1.0.4 convert-source-map: 2.0.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -16372,7 +16068,7 @@ snapshots: '@babel/parser': 7.26.8 '@babel/template': 7.26.8 '@babel/types': 7.26.8 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -16420,7 +16116,7 @@ snapshots: dequal: 2.0.3 glob-to-regexp: 0.4.1 js-cookie: 3.0.5 - std-env: 3.8.0 + std-env: 3.8.1 swr: 2.3.0(react@19.0.0) optionalDependencies: react: 19.0.0 @@ -16442,7 +16138,7 @@ snapshots: dependencies: csstype: 3.1.3 - '@cloudflare/kv-asset-handler@0.3.4': + '@cloudflare/kv-asset-handler@0.4.0': dependencies: mime: 3.0.0 @@ -16606,7 +16302,7 @@ snapshots: '@esbuild/aix-ppc64@0.24.2': optional: true - '@esbuild/aix-ppc64@0.25.0': + '@esbuild/aix-ppc64@0.25.2': optional: true '@esbuild/android-arm64@0.20.2': @@ -16621,7 +16317,7 @@ snapshots: '@esbuild/android-arm64@0.24.2': optional: true - '@esbuild/android-arm64@0.25.0': + '@esbuild/android-arm64@0.25.2': optional: true '@esbuild/android-arm@0.20.2': @@ -16636,7 +16332,7 @@ snapshots: '@esbuild/android-arm@0.24.2': optional: true - '@esbuild/android-arm@0.25.0': + '@esbuild/android-arm@0.25.2': optional: true '@esbuild/android-x64@0.20.2': @@ -16651,7 +16347,7 @@ snapshots: '@esbuild/android-x64@0.24.2': optional: true - '@esbuild/android-x64@0.25.0': + '@esbuild/android-x64@0.25.2': optional: true '@esbuild/darwin-arm64@0.20.2': @@ -16666,7 +16362,7 @@ snapshots: '@esbuild/darwin-arm64@0.24.2': optional: true - '@esbuild/darwin-arm64@0.25.0': + '@esbuild/darwin-arm64@0.25.2': optional: true '@esbuild/darwin-x64@0.20.2': @@ -16681,7 +16377,7 @@ snapshots: '@esbuild/darwin-x64@0.24.2': optional: true - '@esbuild/darwin-x64@0.25.0': + '@esbuild/darwin-x64@0.25.2': optional: true '@esbuild/freebsd-arm64@0.20.2': @@ -16696,7 +16392,7 @@ snapshots: '@esbuild/freebsd-arm64@0.24.2': optional: true - '@esbuild/freebsd-arm64@0.25.0': + '@esbuild/freebsd-arm64@0.25.2': optional: true '@esbuild/freebsd-x64@0.20.2': @@ -16711,7 +16407,7 @@ snapshots: '@esbuild/freebsd-x64@0.24.2': optional: true - '@esbuild/freebsd-x64@0.25.0': + '@esbuild/freebsd-x64@0.25.2': optional: true '@esbuild/linux-arm64@0.20.2': @@ -16726,7 +16422,7 @@ snapshots: '@esbuild/linux-arm64@0.24.2': optional: true - '@esbuild/linux-arm64@0.25.0': + '@esbuild/linux-arm64@0.25.2': optional: true '@esbuild/linux-arm@0.20.2': @@ -16741,7 +16437,7 @@ snapshots: '@esbuild/linux-arm@0.24.2': optional: true - '@esbuild/linux-arm@0.25.0': + '@esbuild/linux-arm@0.25.2': optional: true '@esbuild/linux-ia32@0.20.2': @@ -16756,7 +16452,7 @@ snapshots: '@esbuild/linux-ia32@0.24.2': optional: true - '@esbuild/linux-ia32@0.25.0': + '@esbuild/linux-ia32@0.25.2': optional: true '@esbuild/linux-loong64@0.20.2': @@ -16771,7 +16467,7 @@ snapshots: '@esbuild/linux-loong64@0.24.2': optional: true - '@esbuild/linux-loong64@0.25.0': + '@esbuild/linux-loong64@0.25.2': optional: true '@esbuild/linux-mips64el@0.20.2': @@ -16786,7 +16482,7 @@ snapshots: '@esbuild/linux-mips64el@0.24.2': optional: true - '@esbuild/linux-mips64el@0.25.0': + '@esbuild/linux-mips64el@0.25.2': optional: true '@esbuild/linux-ppc64@0.20.2': @@ -16801,7 +16497,7 @@ snapshots: '@esbuild/linux-ppc64@0.24.2': optional: true - '@esbuild/linux-ppc64@0.25.0': + '@esbuild/linux-ppc64@0.25.2': optional: true '@esbuild/linux-riscv64@0.20.2': @@ -16816,7 +16512,7 @@ snapshots: '@esbuild/linux-riscv64@0.24.2': optional: true - '@esbuild/linux-riscv64@0.25.0': + '@esbuild/linux-riscv64@0.25.2': optional: true '@esbuild/linux-s390x@0.20.2': @@ -16831,7 +16527,7 @@ snapshots: '@esbuild/linux-s390x@0.24.2': optional: true - '@esbuild/linux-s390x@0.25.0': + '@esbuild/linux-s390x@0.25.2': optional: true '@esbuild/linux-x64@0.20.2': @@ -16846,13 +16542,13 @@ snapshots: '@esbuild/linux-x64@0.24.2': optional: true - '@esbuild/linux-x64@0.25.0': + '@esbuild/linux-x64@0.25.2': optional: true '@esbuild/netbsd-arm64@0.24.2': optional: true - '@esbuild/netbsd-arm64@0.25.0': + '@esbuild/netbsd-arm64@0.25.2': optional: true '@esbuild/netbsd-x64@0.20.2': @@ -16867,7 +16563,7 @@ snapshots: '@esbuild/netbsd-x64@0.24.2': optional: true - '@esbuild/netbsd-x64@0.25.0': + '@esbuild/netbsd-x64@0.25.2': optional: true '@esbuild/openbsd-arm64@0.23.0': @@ -16879,7 +16575,7 @@ snapshots: '@esbuild/openbsd-arm64@0.24.2': optional: true - '@esbuild/openbsd-arm64@0.25.0': + '@esbuild/openbsd-arm64@0.25.2': optional: true '@esbuild/openbsd-x64@0.20.2': @@ -16894,7 +16590,7 @@ snapshots: '@esbuild/openbsd-x64@0.24.2': optional: true - '@esbuild/openbsd-x64@0.25.0': + '@esbuild/openbsd-x64@0.25.2': optional: true '@esbuild/sunos-x64@0.20.2': @@ -16909,7 +16605,7 @@ snapshots: '@esbuild/sunos-x64@0.24.2': optional: true - '@esbuild/sunos-x64@0.25.0': + '@esbuild/sunos-x64@0.25.2': optional: true '@esbuild/win32-arm64@0.20.2': @@ -16924,7 +16620,7 @@ snapshots: '@esbuild/win32-arm64@0.24.2': optional: true - '@esbuild/win32-arm64@0.25.0': + '@esbuild/win32-arm64@0.25.2': optional: true '@esbuild/win32-ia32@0.20.2': @@ -16939,7 +16635,7 @@ snapshots: '@esbuild/win32-ia32@0.24.2': optional: true - '@esbuild/win32-ia32@0.25.0': + '@esbuild/win32-ia32@0.25.2': optional: true '@esbuild/win32-x64@0.20.2': @@ -16954,7 +16650,7 @@ snapshots: '@esbuild/win32-x64@0.24.2': optional: true - '@esbuild/win32-x64@0.25.0': + '@esbuild/win32-x64@0.25.2': optional: true '@eslint-community/eslint-utils@4.4.1(eslint@9.22.0(jiti@2.4.2))': @@ -17060,7 +16756,7 @@ snapshots: '@eslint/config-array@0.19.2': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -17074,7 +16770,7 @@ snapshots: '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -17644,7 +17340,7 @@ snapshots: '@kwsites/file-exists@1.1.1': dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -17654,12 +17350,12 @@ snapshots: '@mapbox/node-pre-gyp@2.0.0': dependencies: - consola: 3.4.0 + consola: 3.4.2 detect-libc: 2.0.3 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + https-proxy-agent: 7.0.6 node-fetch: 2.7.0 nopt: 8.1.0 - semver: 7.7.0 + semver: 7.7.1 tar: 7.4.3 transitivePeerDependencies: - encoding @@ -17839,16 +17535,11 @@ snapshots: '@emnapi/runtime': 1.3.1 '@tybys/wasm-util': 0.9.0 - '@netlify/functions@2.8.2': + '@netlify/functions@3.0.4': dependencies: - '@netlify/serverless-functions-api': 1.26.1 + '@netlify/serverless-functions-api': 1.36.0 - '@netlify/node-cookies@0.1.0': {} - - '@netlify/serverless-functions-api@1.26.1': - dependencies: - '@netlify/node-cookies': 0.1.0 - urlpattern-polyfill: 8.0.2 + '@netlify/serverless-functions-api@1.36.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -17894,6 +17585,23 @@ snapshots: '@nx/nx-win32-x64-msvc@20.4.2': optional: true + '@oozcitak/dom@1.15.10': + dependencies: + '@oozcitak/infra': 1.0.8 + '@oozcitak/url': 1.0.4 + '@oozcitak/util': 8.3.8 + + '@oozcitak/infra@1.0.8': + dependencies: + '@oozcitak/util': 8.3.8 + + '@oozcitak/url@1.0.4': + dependencies: + '@oozcitak/infra': 1.0.8 + '@oozcitak/util': 8.3.8 + + '@oozcitak/util@8.3.8': {} + '@open-draft/deferred-promise@2.2.0': {} '@open-draft/logger@0.3.0': @@ -18002,6 +17710,18 @@ snapshots: '@popperjs/core@2.11.8': {} + '@poppinss/colors@4.1.4': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.3': + dependencies: + '@poppinss/colors': 4.1.4 + '@sindresorhus/is': 7.0.1 + supports-color: 10.0.0 + + '@poppinss/exception@1.2.1': {} + '@prisma/client@5.22.0(prisma@5.22.0)': optionalDependencies: prisma: 5.22.0 @@ -18056,8 +17776,6 @@ snapshots: '@radix-ui/number@1.1.1': {} - '@radix-ui/primitive@1.1.1': {} - '@radix-ui/primitive@1.1.2': {} '@radix-ui/react-accessible-icon@1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': @@ -18174,12 +17892,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 @@ -18200,40 +17912,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-context@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-context@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-dialog@1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.8)(react@19.0.0) - aria-hidden: 1.2.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-remove-scroll: 2.6.3(@types/react@19.0.8)(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-dialog@1.1.7(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -18262,19 +17946,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-dismissable-layer@1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/primitive': 1.1.2 @@ -18303,29 +17974,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-focus-guards@1.1.2(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-focus-scope@1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.8)(react@19.0.0) @@ -18368,13 +18022,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-id@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-id@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -18490,38 +18137,18 @@ snapshots: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.8)(react@19.0.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.8)(react@19.0.0) '@radix-ui/react-use-rect': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/rect': 1.1.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - - '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - - '@radix-ui/react-portal@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.8)(react@19.0.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.0.8)(react@19.0.0) + '@radix-ui/rect': 1.1.1 react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-portal@1.1.5(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.8)(react@19.0.0) + '@radix-ui/react-primitive': 2.0.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.8)(react@19.0.0) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) optionalDependencies: @@ -18538,15 +18165,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - optionalDependencies: - '@types/react': 19.0.8 - '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-primitive@2.0.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': dependencies: '@radix-ui/react-slot': 1.2.0(@types/react@19.0.8)(react@19.0.0) @@ -18675,13 +18293,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-slot@1.1.2(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-slot@1.2.0(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.8)(react@19.0.0) @@ -18801,25 +18412,12 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-controllable-state@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -18827,13 +18425,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.8)(react@19.0.0) - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.8)(react@19.0.0) @@ -18841,12 +18432,6 @@ snapshots: optionalDependencies: '@types/react': 19.0.8 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.8)(react@19.0.0)': - dependencies: - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.8 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.8)(react@19.0.0)': dependencies: react: 19.0.0 @@ -18896,29 +18481,6 @@ snapshots: '@types/react': 19.0.8 '@types/react-dom': 19.0.3(@types/react@19.0.8) - '@redocly/ajv@8.11.2': - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js-replace: 1.0.1 - - '@redocly/config@0.20.3': {} - - '@redocly/openapi-core@1.28.0(supports-color@9.4.0)': - dependencies: - '@redocly/ajv': 8.11.2 - '@redocly/config': 0.20.3 - colorette: 1.4.0 - https-proxy-agent: 7.0.6(supports-color@9.4.0) - js-levenshtein: 1.1.6 - js-yaml: 4.1.0 - minimatch: 5.1.6 - pluralize: 8.0.0 - yaml-ast-parser: 0.0.43 - transitivePeerDependencies: - - supports-color - '@rollup/plugin-alias@5.1.1(rollup@4.39.0)': optionalDependencies: rollup: 4.39.0 @@ -18934,7 +18496,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@rollup/plugin-commonjs@28.0.2(rollup@4.39.0)': + '@rollup/plugin-commonjs@28.0.3(rollup@4.39.0)': dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.39.0) commondir: 1.0.1 @@ -18960,17 +18522,7 @@ snapshots: optionalDependencies: rollup: 4.39.0 - '@rollup/plugin-node-resolve@15.3.1(rollup@4.39.0)': - dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - '@types/resolve': 1.20.2 - deepmerge: 4.3.1 - is-module: 1.0.0 - resolve: 1.22.10 - optionalDependencies: - rollup: 4.39.0 - - '@rollup/plugin-node-resolve@16.0.0(rollup@4.39.0)': + '@rollup/plugin-node-resolve@16.0.1(rollup@4.39.0)': dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.39.0) '@types/resolve': 1.20.2 @@ -19359,6 +18911,8 @@ snapshots: '@sindresorhus/is@4.6.0': {} + '@sindresorhus/is@7.0.1': {} + '@sindresorhus/merge-streams@2.3.0': {} '@solid-devtools/debugger@0.26.0(solid-js@1.9.5)': @@ -19485,6 +19039,8 @@ snapshots: '@testing-library/dom': 10.4.0 solid-js: 1.9.5 + '@speed-highlight/core@1.2.7': {} + '@stylistic/eslint-plugin-js@2.13.0(eslint@9.22.0(jiti@2.4.2))': dependencies: eslint: 9.22.0(jiti@2.4.2) @@ -19657,13 +19213,13 @@ snapshots: tailwindcss: 4.0.8 vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - '@tanstack/config@0.16.1(@types/node@22.13.4)(esbuild@0.25.0)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': + '@tanstack/config@0.16.1(@types/node@22.13.4)(esbuild@0.25.2)(eslint@9.22.0(jiti@2.4.2))(rollup@4.39.0)(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0))': dependencies: '@commitlint/parse': 19.5.0 '@eslint/js': 9.22.0 '@stylistic/eslint-plugin-js': 2.13.0(eslint@9.22.0(jiti@2.4.2)) commander: 13.1.0 - esbuild-register: 3.6.0(esbuild@0.25.0) + esbuild-register: 3.6.0(esbuild@0.25.2) eslint-plugin-import-x: 4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) eslint-plugin-n: 17.15.1(eslint@9.22.0(jiti@2.4.2)) globals: 15.14.0 @@ -19672,7 +19228,7 @@ snapshots: liftoff: 5.0.0 minimist: 1.2.8 rollup-plugin-preserve-directives: 0.4.0(rollup@4.39.0) - semver: 7.7.0 + semver: 7.7.1 simple-git: 3.27.0 typedoc: 0.27.6(typescript@5.8.2) typedoc-plugin-frontmatter: 1.1.2(typedoc-plugin-markdown@4.4.1(typedoc@0.27.6(typescript@5.8.2))) @@ -20079,7 +19635,7 @@ snapshots: '@typescript-eslint/types': 8.22.0 '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.8.2) '@typescript-eslint/visitor-keys': 8.22.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) typescript: 5.8.2 transitivePeerDependencies: @@ -20093,7 +19649,7 @@ snapshots: eslint: 9.22.0(jiti@2.4.2) json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - semver: 7.7.0 + semver: 7.7.1 transitivePeerDependencies: - supports-color - typescript @@ -20112,7 +19668,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.22.0(typescript@5.8.2) '@typescript-eslint/utils': 8.22.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 @@ -20123,7 +19679,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.23.0(typescript@5.8.2) '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 @@ -20138,11 +19694,11 @@ snapshots: dependencies: '@typescript-eslint/types': 8.22.0 '@typescript-eslint/visitor-keys': 8.22.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 transitivePeerDependencies: @@ -20152,11 +19708,11 @@ snapshots: dependencies: '@typescript-eslint/types': 8.23.0 '@typescript-eslint/visitor-keys': 8.23.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 ts-api-utils: 2.0.1(typescript@5.8.2) typescript: 5.8.2 transitivePeerDependencies: @@ -20194,16 +19750,16 @@ snapshots: '@typescript-eslint/types': 8.23.0 eslint-visitor-keys: 4.2.0 - '@vercel/nft@0.27.10(rollup@4.39.0)': + '@vercel/nft@0.29.2(rollup@4.39.0)': dependencies: '@mapbox/node-pre-gyp': 2.0.0 '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - acorn: 8.14.0 - acorn-import-attributes: 1.9.5(acorn@8.14.0) + acorn: 8.14.1 + acorn-import-attributes: 1.9.5(acorn@8.14.1) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 - glob: 7.2.3 + glob: 10.4.5 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 picomatch: 4.0.2 @@ -20219,7 +19775,7 @@ snapshots: '@parcel/watcher-wasm': 2.3.0 citty: 0.1.6 clipboardy: 4.0.0 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 get-port-please: 3.1.2 h3: 1.13.0 @@ -20228,7 +19784,7 @@ snapshots: mlly: 1.7.4 node-forge: 1.3.1 pathe: 1.1.2 - std-env: 3.8.0 + std-env: 3.8.1 ufo: 1.5.4 untun: 0.1.3 uqr: 0.1.2 @@ -20453,17 +20009,17 @@ snapshots: '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.0)(webpack@5.97.1)': dependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) optionalDependencies: webpack-dev-server: 5.2.0(webpack-cli@5.1.4)(webpack@5.97.1) @@ -20510,19 +20066,19 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 - acorn-import-attributes@1.9.5(acorn@8.14.0): + acorn-import-attributes@1.9.5(acorn@8.14.1): dependencies: - acorn: 8.14.0 + acorn: 8.14.1 - acorn-jsx@5.3.2(acorn@8.14.0): + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: - acorn: 8.14.0 + acorn: 8.14.1 - acorn@8.14.0: {} + acorn@8.14.1: {} agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -20831,19 +20387,19 @@ snapshots: bytes@3.1.2: {} - c12@2.0.1(magicast@0.3.5): + c12@3.0.2(magicast@0.3.5): dependencies: chokidar: 4.0.3 confbox: 0.1.8 defu: 6.1.4 dotenv: 16.4.7 - giget: 1.2.4 + exsolve: 1.0.4 + giget: 2.0.0 jiti: 2.4.2 - mlly: 1.7.4 - ohash: 1.1.4 - pathe: 1.1.2 + ohash: 2.0.11 + pathe: 2.0.3 perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + pkg-types: 2.1.0 rc9: 2.1.2 optionalDependencies: magicast: 0.3.5 @@ -20900,8 +20456,6 @@ snapshots: chalk@5.4.1: {} - change-case@5.4.4: {} - char-regex@1.0.2: {} chardet@0.7.0: {} @@ -20924,15 +20478,13 @@ snapshots: dependencies: readdirp: 4.1.1 - chownr@2.0.0: {} - chownr@3.0.0: {} chrome-trace-event@1.0.4: {} citty@0.1.6: dependencies: - consola: 3.4.0 + consola: 3.4.2 cjs-module-lexer@1.4.3: {} @@ -21082,9 +20634,11 @@ snapshots: confbox@0.1.8: {} + confbox@0.2.1: {} + connect-history-api-fallback@2.0.0: {} - consola@3.4.0: {} + consola@3.4.2: {} content-disposition@0.5.4: dependencies: @@ -21119,6 +20673,8 @@ snapshots: cookie-es@1.2.2: {} + cookie-es@2.0.0: {} + cookie-signature@1.0.6: {} cookie@0.5.0: {} @@ -21160,7 +20716,7 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - crossws@0.3.3: + crossws@0.3.4: dependencies: uncrypto: 0.1.3 @@ -21275,7 +20831,7 @@ snapshots: '@deno/shim-deno': 0.19.2 undici-types: 5.28.4 - db0@0.2.3: {} + db0@0.3.1: {} de-indent@1.0.2: {} @@ -21287,11 +20843,9 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0(supports-color@9.4.0): + debug@4.4.0: dependencies: ms: 2.1.3 - optionalDependencies: - supports-color: 9.4.0 decimal.js@10.5.0: {} @@ -21481,6 +21035,8 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser-es@1.0.5: {} + error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 @@ -21495,20 +21051,20 @@ snapshots: dependencies: es-errors: 1.3.0 - esbuild-plugin-solid@0.6.0(esbuild@0.25.0)(solid-js@1.9.5): + esbuild-plugin-solid@0.6.0(esbuild@0.25.2)(solid-js@1.9.5): dependencies: '@babel/core': 7.26.8 '@babel/preset-typescript': 7.26.0(@babel/core@7.26.8) babel-preset-solid: 1.9.3(@babel/core@7.26.8) - esbuild: 0.25.0 + esbuild: 0.25.2 solid-js: 1.9.5 transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.25.0): + esbuild-register@3.6.0(esbuild@0.25.2): dependencies: - debug: 4.4.0(supports-color@9.4.0) - esbuild: 0.25.0 + debug: 4.4.0 + esbuild: 0.25.2 transitivePeerDependencies: - supports-color @@ -21620,33 +21176,33 @@ snapshots: '@esbuild/win32-ia32': 0.24.2 '@esbuild/win32-x64': 0.24.2 - esbuild@0.25.0: + esbuild@0.25.2: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.0 - '@esbuild/android-arm': 0.25.0 - '@esbuild/android-arm64': 0.25.0 - '@esbuild/android-x64': 0.25.0 - '@esbuild/darwin-arm64': 0.25.0 - '@esbuild/darwin-x64': 0.25.0 - '@esbuild/freebsd-arm64': 0.25.0 - '@esbuild/freebsd-x64': 0.25.0 - '@esbuild/linux-arm': 0.25.0 - '@esbuild/linux-arm64': 0.25.0 - '@esbuild/linux-ia32': 0.25.0 - '@esbuild/linux-loong64': 0.25.0 - '@esbuild/linux-mips64el': 0.25.0 - '@esbuild/linux-ppc64': 0.25.0 - '@esbuild/linux-riscv64': 0.25.0 - '@esbuild/linux-s390x': 0.25.0 - '@esbuild/linux-x64': 0.25.0 - '@esbuild/netbsd-arm64': 0.25.0 - '@esbuild/netbsd-x64': 0.25.0 - '@esbuild/openbsd-arm64': 0.25.0 - '@esbuild/openbsd-x64': 0.25.0 - '@esbuild/sunos-x64': 0.25.0 - '@esbuild/win32-arm64': 0.25.0 - '@esbuild/win32-ia32': 0.25.0 - '@esbuild/win32-x64': 0.25.0 + '@esbuild/aix-ppc64': 0.25.2 + '@esbuild/android-arm': 0.25.2 + '@esbuild/android-arm64': 0.25.2 + '@esbuild/android-x64': 0.25.2 + '@esbuild/darwin-arm64': 0.25.2 + '@esbuild/darwin-x64': 0.25.2 + '@esbuild/freebsd-arm64': 0.25.2 + '@esbuild/freebsd-x64': 0.25.2 + '@esbuild/linux-arm': 0.25.2 + '@esbuild/linux-arm64': 0.25.2 + '@esbuild/linux-ia32': 0.25.2 + '@esbuild/linux-loong64': 0.25.2 + '@esbuild/linux-mips64el': 0.25.2 + '@esbuild/linux-ppc64': 0.25.2 + '@esbuild/linux-riscv64': 0.25.2 + '@esbuild/linux-s390x': 0.25.2 + '@esbuild/linux-x64': 0.25.2 + '@esbuild/netbsd-arm64': 0.25.2 + '@esbuild/netbsd-x64': 0.25.2 + '@esbuild/openbsd-arm64': 0.25.2 + '@esbuild/openbsd-x64': 0.25.2 + '@esbuild/sunos-x64': 0.25.2 + '@esbuild/win32-arm64': 0.25.2 + '@esbuild/win32-ia32': 0.25.2 + '@esbuild/win32-x64': 0.25.2 escalade@3.2.0: {} @@ -21661,7 +21217,7 @@ snapshots: eslint-compat-utils@0.5.1(eslint@9.22.0(jiti@2.4.2)): dependencies: eslint: 9.22.0(jiti@2.4.2) - semver: 7.7.0 + semver: 7.7.1 eslint-import-resolver-node@0.3.9: dependencies: @@ -21683,7 +21239,7 @@ snapshots: '@types/doctrine': 0.0.9 '@typescript-eslint/scope-manager': 8.23.0 '@typescript-eslint/utils': 8.23.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 doctrine: 3.0.0 enhanced-resolve: 5.18.1 eslint: 9.22.0(jiti@2.4.2) @@ -21691,7 +21247,7 @@ snapshots: get-tsconfig: 4.10.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 stable-hash: 0.0.4 tslib: 2.8.1 transitivePeerDependencies: @@ -21708,7 +21264,7 @@ snapshots: globals: 15.14.0 ignore: 5.3.2 minimatch: 9.0.5 - semver: 7.7.0 + semver: 7.7.1 eslint-plugin-react-debug@1.26.2(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2): dependencies: @@ -21891,7 +21447,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 escape-string-regexp: 4.0.0 eslint-scope: 8.3.0 eslint-visitor-keys: 4.2.0 @@ -21917,14 +21473,14 @@ snapshots: espree@10.3.0: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 4.2.0 espree@9.6.1: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -22011,6 +21567,8 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.0.4: {} + extend@3.0.2: {} external-editor@3.1.0: @@ -22218,10 +21776,6 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -22266,16 +21820,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - giget@1.2.4: + giget@2.0.0: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 node-fetch-native: 1.6.6 - nypm: 0.5.2 - ohash: 1.1.4 + nypm: 0.6.0 pathe: 2.0.3 - tar: 6.2.1 glob-parent@5.1.2: dependencies: @@ -22352,14 +21904,14 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@14.0.2: + globby@14.1.0: dependencies: '@sindresorhus/merge-streams': 2.3.0 fast-glob: 3.3.3 - ignore: 5.3.2 - path-type: 5.0.0 + ignore: 7.0.3 + path-type: 6.0.0 slash: 5.1.0 - unicorn-magic: 0.1.0 + unicorn-magic: 0.3.0 globrex@0.1.2: {} @@ -22387,7 +21939,7 @@ snapshots: h3@1.13.0: dependencies: cookie-es: 1.2.2 - crossws: 0.3.3 + crossws: 0.3.4 defu: 6.1.4 destr: 2.0.3 iron-webcrypto: 1.2.1 @@ -22397,6 +21949,18 @@ snapshots: uncrypto: 0.1.3 unenv: 1.10.0 + h3@1.15.1: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.4 + defu: 6.1.4 + destr: 2.0.3 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.0 + radix3: 1.1.2 + ufo: 1.5.4 + uncrypto: 0.1.3 + handle-thing@2.0.1: {} has-flag@4.0.0: {} @@ -22459,7 +22023,7 @@ snapshots: tapable: 2.2.1 optionalDependencies: '@rspack/core': 1.2.2(@swc/helpers@0.5.15) - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -22490,7 +22054,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -22519,14 +22083,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6(supports-color@9.4.0): + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.3 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -22550,6 +22114,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.3: {} + immer@10.1.1: {} import-fresh@3.3.0: @@ -22570,8 +22136,6 @@ snapshots: indent-string@4.0.0: {} - index-to-position@0.1.2: {} - inflight@1.0.6: dependencies: once: 1.4.0 @@ -22587,11 +22151,11 @@ snapshots: interpret@3.1.1: {} - ioredis@5.4.2: + ioredis@5.6.0: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -22785,8 +22349,6 @@ snapshots: js-cookie@3.0.5: {} - js-levenshtein@1.1.6: {} - js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -22808,7 +22370,7 @@ snapshots: form-data: 4.0.1 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6(supports-color@9.4.0) + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.16 parse5: 7.2.1 @@ -22866,6 +22428,8 @@ snapshots: kind-of@6.0.3: {} + kleur@4.1.5: {} + klona@2.0.6: {} knitwork@1.2.0: {} @@ -22963,8 +22527,8 @@ snapshots: '@parcel/watcher-wasm': 2.5.1 citty: 0.1.6 clipboardy: 4.0.0 - consola: 3.4.0 - crossws: 0.3.3 + consola: 3.4.2 + crossws: 0.3.4 defu: 6.1.4 get-port-please: 3.1.2 h3: 1.13.0 @@ -22973,7 +22537,7 @@ snapshots: mlly: 1.7.4 node-forge: 1.3.1 pathe: 1.1.2 - std-env: 3.8.0 + std-env: 3.8.1 ufo: 1.5.4 untun: 0.1.3 uqr: 0.1.2 @@ -22985,10 +22549,11 @@ snapshots: mlly: 1.7.4 pkg-types: 1.3.1 - local-pkg@1.0.0: + local-pkg@1.1.1: dependencies: mlly: 1.7.4 - pkg-types: 1.3.1 + pkg-types: 2.1.0 + quansync: 0.2.10 locate-path@5.0.0: dependencies: @@ -23173,28 +22738,15 @@ snapshots: minimist@1.2.8: {} - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - minipass@4.2.8: {} - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - minizlib@3.0.1: dependencies: minipass: 7.1.2 rimraf: 5.0.10 - mkdirp@1.0.4: {} - mkdirp@3.0.1: {} mkdist@2.2.0(typescript@5.8.2)(vue-tsc@2.0.29(typescript@5.8.2)): @@ -23210,7 +22762,7 @@ snapshots: pkg-types: 1.3.1 postcss: 8.5.3 postcss-nested: 7.0.2(postcss@8.5.3) - semver: 7.7.0 + semver: 7.7.1 tinyglobby: 0.2.12 optionalDependencies: typescript: 5.8.2 @@ -23218,7 +22770,7 @@ snapshots: mlly@1.7.4: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.5.4 @@ -23289,44 +22841,42 @@ snapshots: neo-async@2.6.2: {} - nitropack@2.10.4(typescript@5.8.2): + nitropack@2.11.8: dependencies: - '@cloudflare/kv-asset-handler': 0.3.4 - '@netlify/functions': 2.8.2 + '@cloudflare/kv-asset-handler': 0.4.0 + '@netlify/functions': 3.0.4 '@rollup/plugin-alias': 5.1.1(rollup@4.39.0) - '@rollup/plugin-commonjs': 28.0.2(rollup@4.39.0) + '@rollup/plugin-commonjs': 28.0.3(rollup@4.39.0) '@rollup/plugin-inject': 5.0.5(rollup@4.39.0) '@rollup/plugin-json': 6.1.0(rollup@4.39.0) - '@rollup/plugin-node-resolve': 15.3.1(rollup@4.39.0) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.39.0) '@rollup/plugin-replace': 6.0.2(rollup@4.39.0) '@rollup/plugin-terser': 0.4.4(rollup@4.39.0) - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - '@types/http-proxy': 1.17.15 - '@vercel/nft': 0.27.10(rollup@4.39.0) + '@vercel/nft': 0.29.2(rollup@4.39.0) archiver: 7.0.1 - c12: 2.0.1(magicast@0.3.5) - chokidar: 3.6.0 + c12: 3.0.2(magicast@0.3.5) + chokidar: 4.0.3 citty: 0.1.6 compatx: 0.1.8 - confbox: 0.1.8 - consola: 3.4.0 - cookie-es: 1.2.2 + confbox: 0.2.1 + consola: 3.4.2 + cookie-es: 2.0.0 croner: 9.0.0 - crossws: 0.3.3 - db0: 0.2.3 + crossws: 0.3.4 + db0: 0.3.1 defu: 6.1.4 destr: 2.0.3 dot-prop: 9.0.0 - esbuild: 0.24.2 + esbuild: 0.25.2 escape-string-regexp: 5.0.0 etag: 1.8.1 - fs-extra: 11.3.0 - globby: 14.0.2 + exsolve: 1.0.4 + globby: 14.1.0 gzip-size: 7.0.0 - h3: 1.13.0 + h3: 1.15.1 hookable: 5.5.3 httpxy: 0.1.7 - ioredis: 5.4.2 + ioredis: 5.6.0 jiti: 2.4.2 klona: 2.0.6 knitwork: 1.2.0 @@ -23336,29 +22886,34 @@ snapshots: mime: 4.0.6 mlly: 1.7.4 node-fetch-native: 1.6.6 + node-mock-http: 1.0.0 ofetch: 1.4.1 - ohash: 1.1.4 - openapi-typescript: 7.6.0(typescript@5.8.2) - pathe: 1.1.2 + ohash: 2.0.11 + pathe: 2.0.3 perfect-debounce: 1.0.0 - pkg-types: 1.3.1 + pkg-types: 2.1.0 pretty-bytes: 6.1.1 radix3: 1.1.2 rollup: 4.39.0 rollup-plugin-visualizer: 5.14.0(rollup@4.39.0) scule: 1.3.0 - semver: 7.7.0 + semver: 7.7.1 serve-placeholder: 2.0.2 serve-static: 1.16.2 - std-env: 3.8.0 + source-map: 0.7.4 + std-env: 3.8.1 ufo: 1.5.4 + ultrahtml: 1.5.3 uncrypto: 0.1.3 unctx: 2.4.1 - unenv: 1.10.0 - unimport: 3.14.6(rollup@4.39.0) - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) - untyped: 1.5.2 + unenv: 2.0.0-rc.15 + unimport: 4.1.3 + unplugin-utils: 0.2.4 + unstorage: 1.15.0(db0@0.3.1)(ioredis@5.6.0) + untyped: 2.0.0 unwasm: 0.3.9 + youch: 4.1.0-beta.6 + youch-core: 0.3.2 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23384,7 +22939,6 @@ snapshots: - rolldown - sqlite3 - supports-color - - typescript - uploadthing no-case@3.0.4: @@ -23421,6 +22975,8 @@ snapshots: node-machine-id@1.1.12: {} + node-mock-http@1.0.0: {} + node-releases@2.0.19: {} nopt@8.1.0: @@ -23472,7 +23028,7 @@ snapshots: open: 8.4.2 ora: 5.3.0 resolve.exports: 2.0.3 - semver: 7.7.0 + semver: 7.7.1 string-width: 4.2.3 tar-stream: 2.2.0 tmp: 0.2.3 @@ -23496,14 +23052,13 @@ snapshots: transitivePeerDependencies: - debug - nypm@0.5.2: + nypm@0.6.0: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 pathe: 2.0.3 - pkg-types: 1.3.1 + pkg-types: 2.1.0 tinyexec: 0.3.2 - ufo: 1.5.4 object-assign@4.1.1: {} @@ -23532,6 +23087,8 @@ snapshots: ohash@1.1.4: {} + ohash@2.0.11: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -23563,16 +23120,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-typescript@7.6.0(typescript@5.8.2): - dependencies: - '@redocly/openapi-core': 1.28.0(supports-color@9.4.0) - ansi-colors: 4.1.3 - change-case: 5.4.4 - parse-json: 8.1.0 - supports-color: 9.4.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -23647,12 +23194,6 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-json@8.1.0: - dependencies: - '@babel/code-frame': 7.26.2 - index-to-position: 0.1.2 - type-fest: 4.33.0 - parse-passwd@1.0.0: {} parse5-htmlparser2-tree-adapter@6.0.1: @@ -23708,7 +23249,7 @@ snapshots: path-type@4.0.0: {} - path-type@5.0.0: {} + path-type@6.0.0: {} pathe@1.1.2: {} @@ -23738,6 +23279,12 @@ snapshots: mlly: 1.7.4 pathe: 2.0.3 + pkg-types@2.1.0: + dependencies: + confbox: 0.2.1 + exsolve: 1.0.4 + pathe: 2.0.3 + playwright-core@1.50.1: {} playwright@1.50.1: @@ -24034,6 +23581,8 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@0.2.10: {} + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -24409,7 +23958,7 @@ snapshots: dependencies: lru-cache: 6.0.0 - semver@7.7.0: {} + semver@7.7.1: {} send@0.19.0: dependencies: @@ -24518,7 +24067,7 @@ snapshots: dependencies: '@kwsites/file-exists': 1.1.1 '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -24589,7 +24138,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -24600,7 +24149,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -24624,7 +24173,7 @@ snapshots: statuses@2.0.1: {} - std-env@3.8.0: {} + std-env@3.8.1: {} streamx@2.22.0: dependencies: @@ -24677,7 +24226,7 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@2.1.1: + strip-literal@3.0.0: dependencies: js-tokens: 9.0.1 @@ -24707,6 +24256,8 @@ snapshots: dependencies: copy-anything: 3.0.5 + supports-color@10.0.0: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -24715,8 +24266,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@9.4.0: {} - supports-hyperlinks@3.1.0: dependencies: has-flag: 4.0.0 @@ -24738,7 +24287,7 @@ snapshots: dependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) '@swc/counter': 0.1.3 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) swr@2.3.0(react@19.0.0): dependencies: @@ -24797,15 +24346,6 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.22.0 - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - tar@7.4.3: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -24824,34 +24364,34 @@ snapshots: type-fest: 2.19.0 unique-string: 3.0.0 - terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)): + terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2) optionalDependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) - esbuild: 0.25.0 + esbuild: 0.25.2 - terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1): + terser-webpack-plugin@5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.37.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.10.15(@swc/helpers@0.5.15) - esbuild: 0.25.0 + esbuild: 0.25.2 terser@5.37.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.0 + acorn: 8.14.1 commander: 2.20.3 source-map-support: 0.5.21 @@ -25045,16 +24585,18 @@ snapshots: ufo@1.5.4: {} + ultrahtml@1.5.3: {} + unbuild@3.3.1(typescript@5.8.2)(vue-tsc@2.0.29(typescript@5.8.2)): dependencies: '@rollup/plugin-alias': 5.1.1(rollup@4.39.0) - '@rollup/plugin-commonjs': 28.0.2(rollup@4.39.0) + '@rollup/plugin-commonjs': 28.0.3(rollup@4.39.0) '@rollup/plugin-json': 6.1.0(rollup@4.39.0) - '@rollup/plugin-node-resolve': 16.0.0(rollup@4.39.0) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.39.0) '@rollup/plugin-replace': 6.0.2(rollup@4.39.0) '@rollup/pluginutils': 5.1.4(rollup@4.39.0) citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 esbuild: 0.24.2 hookable: 5.5.3 @@ -25084,10 +24626,10 @@ snapshots: unctx@2.4.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 estree-walker: 3.0.3 magic-string: 0.30.17 - unplugin: 2.1.2 + unplugin: 2.2.2 undici-types@5.28.4: {} @@ -25095,34 +24637,40 @@ snapshots: unenv@1.10.0: dependencies: - consola: 3.4.0 + consola: 3.4.2 defu: 6.1.4 mime: 3.0.0 node-fetch-native: 1.6.6 pathe: 1.1.2 + unenv@2.0.0-rc.15: + dependencies: + defu: 6.1.4 + exsolve: 1.0.4 + ohash: 2.0.11 + pathe: 2.0.3 + ufo: 1.5.4 + unicode-emoji-modifier-base@1.0.0: {} - unicorn-magic@0.1.0: {} + unicorn-magic@0.3.0: {} - unimport@3.14.6(rollup@4.39.0): + unimport@4.1.3: dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) - acorn: 8.14.0 + acorn: 8.14.1 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 - fast-glob: 3.3.3 - local-pkg: 1.0.0 + local-pkg: 1.1.1 magic-string: 0.30.17 mlly: 1.7.4 pathe: 2.0.3 picomatch: 4.0.2 - pkg-types: 1.3.1 + pkg-types: 2.1.0 scule: 1.3.0 - strip-literal: 2.1.1 - unplugin: 1.16.1 - transitivePeerDependencies: - - rollup + strip-literal: 3.0.0 + tinyglobby: 0.2.12 + unplugin: 2.2.2 + unplugin-utils: 0.2.4 unique-string@3.0.0: dependencies: @@ -25136,41 +24684,46 @@ snapshots: unpipe@1.0.0: {} + unplugin-utils@0.2.4: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.2 + unplugin@1.0.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 unplugin@1.16.1: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 webpack-virtual-modules: 0.6.2 - unplugin@2.1.2: + unplugin@2.2.2: dependencies: - acorn: 8.14.0 + acorn: 8.14.1 webpack-virtual-modules: 0.6.2 - unstorage@1.14.4(db0@0.2.3)(ioredis@5.4.2): + unstorage@1.15.0(db0@0.3.1)(ioredis@5.6.0): dependencies: anymatch: 3.1.3 - chokidar: 3.6.0 + chokidar: 4.0.3 destr: 2.0.3 - h3: 1.13.0 + h3: 1.15.1 lru-cache: 10.4.3 node-fetch-native: 1.6.6 ofetch: 1.4.1 ufo: 1.5.4 optionalDependencies: - db0: 0.2.3 - ioredis: 5.4.2 + db0: 0.3.1 + ioredis: 5.6.0 untun@0.1.3: dependencies: citty: 0.1.6 - consola: 3.4.0 + consola: 3.4.2 pathe: 1.1.2 untyped@1.5.2: @@ -25186,6 +24739,14 @@ snapshots: transitivePeerDependencies: - supports-color + untyped@2.0.0: + dependencies: + citty: 0.1.6 + defu: 6.1.4 + jiti: 2.4.2 + knitwork: 1.2.0 + scule: 1.3.0 + unwasm@0.3.9: dependencies: knitwork: 1.2.0 @@ -25205,8 +24766,6 @@ snapshots: uqr@0.1.2: {} - uri-js-replace@1.0.1: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -25216,8 +24775,6 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - urlpattern-polyfill@8.0.2: {} - use-callback-ref@1.3.3(@types/react@19.0.8)(react@19.0.0): dependencies: react: 19.0.0 @@ -25259,86 +24816,7 @@ snapshots: vary@1.1.2: {} - vinxi@0.5.1(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0): - dependencies: - '@babel/core': 7.26.8 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.8) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.8) - '@types/micromatch': 4.0.9 - '@vinxi/listhen': 1.5.6 - boxen: 7.1.1 - chokidar: 3.6.0 - citty: 0.1.6 - consola: 3.4.0 - crossws: 0.3.3 - dax-sh: 0.39.2 - defu: 6.1.4 - es-module-lexer: 1.6.0 - esbuild: 0.20.2 - fast-glob: 3.3.3 - get-port-please: 3.1.2 - h3: 1.13.0 - hookable: 5.5.3 - http-proxy: 1.18.1 - micromatch: 4.0.8 - nitropack: 2.10.4(typescript@5.8.2) - node-fetch-native: 1.6.6 - path-to-regexp: 6.3.0 - pathe: 1.1.2 - radix3: 1.1.2 - resolve: 1.22.10 - serve-placeholder: 2.0.2 - serve-static: 1.16.2 - ufo: 1.5.4 - unctx: 2.4.1 - unenv: 1.10.0 - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) - vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) - zod: 3.24.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@libsql/client' - - '@netlify/blobs' - - '@planetscale/database' - - '@types/node' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - better-sqlite3 - - db0 - - debug - - drizzle-orm - - encoding - - idb-keyval - - ioredis - - jiti - - less - - lightningcss - - mysql2 - - rolldown - - sass - - sass-embedded - - sqlite3 - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - uploadthing - - xml2js - - yaml - - vinxi@0.5.3(@types/node@22.13.4)(db0@0.2.3)(ioredis@5.4.2)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(typescript@5.8.2)(yaml@2.7.0): + vinxi@0.5.3(@types/node@22.13.4)(db0@0.3.1)(ioredis@5.6.0)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: '@babel/core': 7.26.8 '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.8) @@ -25348,8 +24826,8 @@ snapshots: boxen: 7.1.1 chokidar: 3.6.0 citty: 0.1.6 - consola: 3.4.0 - crossws: 0.3.3 + consola: 3.4.2 + crossws: 0.3.4 dax-sh: 0.39.2 defu: 6.1.4 es-module-lexer: 1.6.0 @@ -25360,7 +24838,7 @@ snapshots: hookable: 5.5.3 http-proxy: 1.18.1 micromatch: 4.0.8 - nitropack: 2.10.4(typescript@5.8.2) + nitropack: 2.11.8 node-fetch-native: 1.6.6 path-to-regexp: 6.3.0 pathe: 1.1.2 @@ -25371,7 +24849,7 @@ snapshots: ufo: 1.5.4 unctx: 2.4.1 unenv: 1.10.0 - unstorage: 1.14.4(db0@0.2.3)(ioredis@5.4.2) + unstorage: 1.15.0(db0@0.3.1)(ioredis@5.6.0) vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) zod: 3.24.2 transitivePeerDependencies: @@ -25412,7 +24890,6 @@ snapshots: - supports-color - terser - tsx - - typescript - uploadthing - xml2js - yaml @@ -25420,7 +24897,7 @@ snapshots: vite-node@3.0.6(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0): dependencies: cac: 6.7.14 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 es-module-lexer: 1.6.0 pathe: 2.0.3 vite: 6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0) @@ -25445,7 +24922,7 @@ snapshots: '@volar/typescript': 2.4.11 '@vue/language-core': 2.0.29(typescript@5.8.2) compare-versions: 6.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 kolorist: 1.8.0 local-pkg: 0.5.1 magic-string: 0.30.17 @@ -25465,7 +24942,7 @@ snapshots: '@volar/typescript': 2.4.11 '@vue/language-core': 2.2.0(typescript@5.8.2) compare-versions: 6.1.1 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 kolorist: 1.8.0 local-pkg: 0.5.1 magic-string: 0.30.17 @@ -25498,7 +24975,7 @@ snapshots: vite-tsconfig-paths@5.1.4(typescript@5.8.2)(vite@6.1.4(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(terser@5.37.0)(tsx@4.19.2)(yaml@2.7.0)): dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 globrex: 0.1.2 tsconfck: 3.1.4(typescript@5.8.2) optionalDependencies: @@ -25535,11 +25012,11 @@ snapshots: '@vitest/spy': 3.0.6 '@vitest/utils': 3.0.6 chai: 5.2.0 - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 expect-type: 1.1.0 magic-string: 0.30.17 pathe: 2.0.3 - std-env: 3.8.0 + std-env: 3.8.1 tinybench: 2.9.0 tinyexec: 0.3.2 tinypool: 1.0.2 @@ -25570,14 +25047,14 @@ snapshots: vue-eslint-parser@9.4.3(eslint@9.22.0(jiti@2.4.2)): dependencies: - debug: 4.4.0(supports-color@9.4.0) + debug: 4.4.0 eslint: 9.22.0(jiti@2.4.2) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.6.0 lodash: 4.17.21 - semver: 7.7.0 + semver: 7.7.1 transitivePeerDependencies: - supports-color @@ -25585,7 +25062,7 @@ snapshots: dependencies: '@volar/typescript': 2.4.11 '@vue/language-core': 2.0.29(typescript@5.8.2) - semver: 7.7.0 + semver: 7.7.1 typescript: 5.8.2 w3c-xmlserializer@5.0.0: @@ -25635,7 +25112,7 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: webpack-dev-server: 5.2.0(webpack-cli@5.1.4)(webpack@5.97.1) @@ -25649,7 +25126,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.0 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-dev-server@5.2.0(webpack-cli@5.1.4)(webpack@5.97.1): dependencies: @@ -25681,7 +25158,7 @@ snapshots: webpack-dev-middleware: 7.4.2(webpack@5.97.1) ws: 8.18.0 optionalDependencies: - webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack: 5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.0)(webpack@5.97.1) transitivePeerDependencies: - bufferutil @@ -25701,14 +25178,14 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0): + webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.7 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 + acorn: 8.14.1 browserslist: 4.24.4 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.1 @@ -25723,7 +25200,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -25731,14 +25208,14 @@ snapshots: - esbuild - uglify-js - webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack-cli@5.1.4): + webpack@5.97.1(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.7 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 + acorn: 8.14.1 browserslist: 4.24.4 chrome-trace-event: 1.0.4 enhanced-resolve: 5.18.1 @@ -25753,7 +25230,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.0)(webpack@5.97.1) + terser-webpack-plugin: 5.3.11(@swc/core@1.10.15(@swc/helpers@0.5.15))(esbuild@0.25.2)(webpack@5.97.1) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: @@ -25840,6 +25317,13 @@ snapshots: xml-name-validator@5.0.0: {} + xmlbuilder2@3.1.1: + dependencies: + '@oozcitak/dom': 1.15.10 + '@oozcitak/infra': 1.0.8 + '@oozcitak/util': 8.3.8 + js-yaml: 3.14.1 + xmlchars@2.2.0: {} y18n@5.0.8: {} @@ -25850,8 +25334,6 @@ snapshots: yallist@5.0.0: {} - yaml-ast-parser@0.0.43: {} - yaml@1.10.2: {} yaml@2.7.0: {} @@ -25890,6 +25372,18 @@ snapshots: yoctocolors@2.1.1: {} + youch-core@0.3.2: + dependencies: + '@poppinss/exception': 1.2.1 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.6: + dependencies: + '@poppinss/dumper': 0.6.3 + '@speed-highlight/core': 1.2.7 + cookie: 1.0.2 + youch-core: 0.3.2 + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 diff --git a/scripts/publish.js b/scripts/publish.js index 1d55ca6ddc..5457d9c7f8 100644 --- a/scripts/publish.js +++ b/scripts/publish.js @@ -100,21 +100,13 @@ await publish({ name: '@tanstack/solid-start', packageDir: 'packages/solid-start', }, - { - name: '@tanstack/solid-start-client', - packageDir: 'packages/solid-start-client', - }, - { - name: '@tanstack/solid-start-config', - packageDir: 'packages/solid-start-config', - }, { name: '@tanstack/solid-start-plugin', packageDir: 'packages/solid-start-plugin', }, { - name: '@tanstack/solid-start-router-manifest', - packageDir: 'packages/solid-start-router-manifest', + name: '@tanstack/solid-start-client', + packageDir: 'packages/solid-start-client', }, { name: '@tanstack/solid-start-server', @@ -144,14 +136,6 @@ await publish({ name: '@tanstack/react-start-server', packageDir: 'packages/react-start-server', }, - { - name: '@tanstack/start-config', - packageDir: 'packages/start-config', - }, - { - name: '@tanstack/react-start-config', - packageDir: 'packages/react-start-config', - }, { name: '@tanstack/start-api-routes', packageDir: 'packages/start-api-routes', @@ -160,10 +144,6 @@ await publish({ name: '@tanstack/start-server-functions-fetcher', packageDir: 'packages/start-server-functions-fetcher', }, - { - name: '@tanstack/start-server-functions-handler', - packageDir: 'packages/start-server-functions-handler', - }, { name: '@tanstack/start-server-functions-client', packageDir: 'packages/start-server-functions-client', @@ -176,10 +156,6 @@ await publish({ name: '@tanstack/start-server-functions-server', packageDir: 'packages/start-server-functions-server', }, - { - name: '@tanstack/react-start-router-manifest', - packageDir: 'packages/react-start-router-manifest', - }, { name: '@tanstack/start', packageDir: 'packages/start',