Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .claude/skills/upgrade-npm-packages/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: upgrade-npm-packages
description: A skill that helps users upgrade their npm packages to the latest versions.
---

# Upgrade NPM Packages Skill

## Instructions

[Clear, step-by-step guidance for Claude to follow]

1. Open `packages/create-vitnode-app/src/create/package-versions.ts` file and read it.
2. Run `pnpm outdated` to check for outdated packages in the project - do it for all projects in the turborepo (monorepo) including with root.
3. For each outdated package, run `pnpm up <package-name>@<version>` to upgrade it.
4. For each package, check if there are any breaking changes in the new version. If there are, ask the user if they want to proceed with the upgrade or skip it.
5. After upgrading all packages, update the `package-versions.ts` file with the new versions of the packages.
6. Run `pnpm install` to ensure all dependencies are correctly installed.

## Examples

I'm working on a project that uses a monorepo structure with multiple packages. I want to ensure that all my npm packages are up-to-date. I will use the "upgrade-npm-packages" skill to check for outdated packages, upgrade them, and handle any breaking changes appropriately.
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The repository is a monorepo for the VitNode framework, which includes a backend
- TanStack Start on Vite, file-based routes under `apps/web/src/routes/`
- Navigation: use `@vitnode/core/tanstack/layout`'s `RouterLink`, or TanStack
Router's own `Link` / `useNavigate`.
- Forms: Use `react-hook-form@7`, `createServerFn` for mutations
- Forms: Use `@tanstack/react-form@1`, `createServerFn` for mutations
- UI: Shadcn UI, Tailwind CSS 4, dark/light mode with system detection
- i18n: Use `use-intl`, `t('key')` for translations, `createTranslator`
(server), `useTranslations` (client)
Expand Down Expand Up @@ -53,7 +53,7 @@ The repository is a monorepo for the VitNode framework, which includes a backend
## Integration & Conventions

- **External:**
- TanStack Start, TanStack Router, TanStack Query, Hono.js, Drizzle ORM, Zod, react-hook-form, Shadcn UI, Tailwind, use-intl
- TanStack Start, TanStack Router, TanStack Query, TanStack Form, Hono.js, Drizzle ORM, Zod, Shadcn UI, Tailwind, use-intl
- **Internal:**
- Navigation, config, API, middleware, plugin system
- **Security:**
Expand Down
40 changes: 20 additions & 20 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,38 @@
"i18n:update:ai": "vitnode i18n:update:ai"
},
"dependencies": {
"@ai-sdk/anthropic": "^4.0.20",
"@ai-sdk/google": "^4.0.24",
"@hono/zod-openapi": "^1.5.1",
"@hono/zod-validator": "^0.9.0",
"@ai-sdk/anthropic": "^4.0.53",
"@ai-sdk/google": "^4.0.69",
"@hono/zod-openapi": "^1.6.3",
"@hono/zod-validator": "^0.9.1",
"@vitnode/core": "workspace:*",
"@vitnode/node-cron": "workspace:*",
"@vitnode/supabase-storage": "workspace:*",
"drizzle-kit": "1.0.0-rc.4",
"drizzle-orm": "1.0.0-rc.4",
"hono": "^4.12.31",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"use-intl": "^4.13.7",
"ws": "^8.21.1",
"zod": "^4.4.3"
"hono": "^4.13.7",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"use-intl": "^4.14.4",
"ws": "^8.21.3",
"zod": "^4.6.2"
},
"devDependencies": {
"@hono/node-server": "^2.0.11",
"@react-email/ui": "^6.9.0",
"@types/node": "^26.1.1",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@hono/node-server": "^2.1.1",
"@react-email/ui": "^6.9.5",
"@types/node": "^26.5.1",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@types/ws": "^8.18.1",
"@vitnode/blog": "workspace:*",
"@vitnode/example": "workspace:*",
"@vitnode/config": "workspace:*",
"@vitnode/example": "workspace:*",
"@vitnode/nodemailer": "workspace:*",
"dotenv": "^17.4.2",
"eslint": "^10.7.0",
"react-email": "^6.9.0",
"tsc-alias": "^1.9.1",
"tsx": "^4.23.1",
"eslint": "^10.10.0",
"react-email": "^6.9.5",
"tsc-alias": "^1.9.5",
"tsx": "^4.23.13",
"typescript": "^6.0.3"
}
}
72 changes: 56 additions & 16 deletions apps/web/content/docs/ui/auto-form.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Auto Form
description: Component creates form based on Zod schemas & react-hook-form with validation
description: Component creates form based on Zod schemas & TanStack Form with validation
---

## Preview
Expand Down Expand Up @@ -378,7 +378,7 @@ the same tuple and return `{ languageCode, value }[]` - the shape

## Custom Fields

Because Auto Form fields are controlled entirely by the `component` property function, creating a custom field component is just a matter of rendering your own UI using the provided props. The props passed to the `component` function contain the field properties managed by `react-hook-form` along with Zod validation details.
Because Auto Form fields are controlled entirely by the `component` property function, creating a custom field component is just a matter of rendering your own UI using the provided props. The props passed to the `component` function contain the field properties managed by TanStack Form along with Zod validation details.

Here is an example of creating a custom color picker input:

Expand Down Expand Up @@ -557,9 +557,32 @@ To activate submit button and handle form submission with the `onSubmit` callbac
/>
```

### When Validation Messages Appear

Auto Form always knows whether the values satisfy the schema - that is what keeps the submit button disabled until they do - but it holds the messages back until they are useful. By default it says nothing until the first submit attempt. Pass `mode` to speak up sooner:

| `mode` | A field's message appears... |
| ------------------------- | --------------------------------- |
| `"onSubmit"` *(default)* | after the first submit attempt |
| `"onBlur"` / `"onTouched"`| once the field has been left |
| `"onChange"` / `"all"` | as soon as the field is edited |

```tsx
<AutoForm
fields={
[
/* ...field definitions */
]
}
formSchema={formSchema}
mode="all"
onSubmit={values => {}}
/>
```

### Accessing the Form Instance

The `onSubmit` callback provides access to the React Hook Form instance as a second parameter:
The `onSubmit` callback provides access to the TanStack Form instance as a second parameter, so you can read and write the form's state after the values have been handed over:

```tsx
<AutoForm
Expand All @@ -570,15 +593,32 @@ The `onSubmit` callback provides access to the React Hook Form instance as a sec
}
formSchema={formSchema}
onSubmit={(values, form) => {
// Access form methods
form.setError("username", {
type: "manual",
message: "Username already taken",
});
form.setFieldValue("username", values.username.trim());
form.reset();
}}
/>
```

### Showing a Refusal the Server Named

When the API turns a submission down for a reason it can point at a field - a username that is already taken, say - put that message on the field with `setFormFieldError`. It focuses the field, blocks submission while the rejected value is still in it, and clears itself the moment the field is edited:

```tsx
import { setFormFieldError } from "@vitnode/core/components/ui/form";

<AutoForm
fields={
[
/* ...field definitions */
]
}
formSchema={formSchema}
onSubmit={(values, form) => {
setFormFieldError(form, "username", "Username already taken");
}}
/>;
```

You can also define the submission handler separately:

```ts
Expand All @@ -587,15 +627,15 @@ import type { AutoFormOnSubmit } from "@vitnode/core/components/form/auto-form";

```tsx
const onSubmit: AutoFormOnSubmit<typeof formSchema> = async (values, form) => {
try {
await saveData(values);
toast.success("Form submitted successfully");
} catch (error) {
form.setError("root", {
type: "manual",
message: "Failed to submit form",
});
const result = await saveData(values);

if (result.conflict) {
setFormFieldError(form, "username", "Username already taken");

return;
}

toast.success("Form submitted successfully");
};

// Then in your component
Expand Down
51 changes: 26 additions & 25 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,56 @@
"docs:check": "node scripts/check-docs.mjs"
},
"dependencies": {
"@hono/zod-openapi": "^1.5.1",
"@hono/zod-openapi": "^1.6.3",
"@tailwindcss/vite": "^4.1.18",
"@tanstack/react-devtools": "^0.10.12",
"@tanstack/react-form": "^1.33.5",
"@tanstack/react-query": "^5.102.8",
"@tanstack/react-query-devtools": "^5.102.3",
"@tanstack/react-router": "^1.170.32",
"@tanstack/react-query-devtools": "^5.102.8",
"@tanstack/react-router": "^1.170.35",
"@tanstack/react-router-devtools": "^1.167.1",
"@tanstack/react-router-ssr-query": "^1.167.2",
"@tanstack/react-start": "^1.168.49",
"@tanstack/react-start": "^1.168.52",
"@vitnode/blog": "workspace:*",
"@vitnode/core": "workspace:*",
"@vitnode/example": "workspace:*",
"@vitnode/supabase-storage": "workspace:*",
"dotenv": "^17.4.2",
"drizzle-kit": "1.0.0-rc.4",
"drizzle-orm": "1.0.0-rc.4",
"fumadocs-core": "^16.15.7",
"fumadocs-core": "^16.15.9",
"fumadocs-mdx": "^15.4.0",
"fumadocs-ui": "^16.15.7",
"hono": "^4.12.31",
"lucide-react": "^1.25.0",
"motion": "^12.42.2",
"nitro": "3.0.260610-beta",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"shadcn": "^4.14.0",
"sonner": "^2.0.7",
"fumadocs-ui": "^16.15.9",
"hono": "^4.13.7",
"lucide-react": "^1.45.0",
"motion": "^13.2.0",
"nitro": "3.0.260903-beta",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"shadcn": "^4.21.0",
"sonner": "^2.0.8",
"tailwindcss": "^4.1.18",
"tslib": "^2.8.1",
"use-intl": "^4.13.7",
"zod": "^4.4.3"
"use-intl": "^4.14.4",
"zod": "^4.6.2"
},
"devDependencies": {
"@tanstack/devtools-vite": "^0.8.5",
"@tanstack/eslint-config": "^0.4.0",
"@tanstack/router-cli": "^1.132.0",
"@tanstack/router-cli": "^1.167.35",
"@types/mdx": "^2.0.14",
"@types/node": "^22.10.2",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^6.0.4",
"@types/node": "^26.5.1",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.1",
"@vitnode/config": "workspace:*",
"cn": "^0.2.6",
"eslint": "^10.7.0",
"cn": "^0.3.0",
"eslint": "^10.10.0",
"jiti": "^2.7.0",
"jsdom": "^29.1.1",
"jsdom": "^30.0.1",
"tw-animate-css": "^1.4.0",
"typescript": "^6.0.2",
"vite": "^8.0.0"
"vite": "^8.3.0"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/routes/llms[.]txt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { source } from '@/docs/source.server'
export const Route = createFileRoute('/llms.txt')({
server: {
handlers: {
GET: () =>
new Response(llms(source).index(), {
GET: async () =>
new Response(await llms(source).index(), {
headers: { 'content-type': 'text/plain; charset=utf-8' },
}),
},
Expand Down
57 changes: 49 additions & 8 deletions apps/web/src/site/home/sections/logos/tanstack.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
export const TanStackLogo = () => (
<span className="flex flex-col items-center leading-tight">
<span className="text-xl font-bold">TanStack</span>
<span className="text-muted-foreground text-xs">
Start · Router · Query
</span>
</span>
)
export const TanStackLogo = () => {
return (
<svg
aria-label="TanStack logotype"
className="h-7 w-45"
viewBox="0 0 321.33 50"
xmlns="http://www.w3.org/2000/svg"
>
<title>TanStack logotype</title>
<path
d="M19.03,0c13.76,0,19.03,8.54,19.03,25s-5.27,25-19.03,25S0,41.46,0,25C0,8.54,5.27,0,19.03,0ZM25.32,36.42c-1.79,0-2.76.49-3.55.88-.68.34-1.21.61-2.38.61-1.17,0-1.71-.27-2.38-.61-.78-.39-1.76-.88-3.55-.88-1.79,0-2.76.49-3.55.88-.68.34-1.21.61-2.38.61v2.6c1.79,0,2.76-.49,3.55-.88.68-.34,1.21-.61,2.38-.61s1.71.27,2.38.61c.78.39,1.76.88,3.55.88s2.76-.49,3.55-.88c.68-.34,1.21-.61,2.38-.61s1.71.27,2.38.61c.78.39,1.76.88,3.55.88v-2.6c-1.17,0-1.71-.27-2.38-.61-.78-.39-1.76-.88-3.55-.88ZM26.17,10.31c1.35-1.22,0-3.43-1.69-2.76-.93.37-1.81.91-2.59,1.62-1.23,1.11-2.05,2.52-2.5,4.04-.44-1.53-1.27-2.93-2.5-4.04-.78-.7-1.66-1.25-2.6-1.62-1.69-.67-3.04,1.54-1.69,2.76l4.95,4.49c-1.62-1.1-3.56-1.75-5.67-1.75-1.15,0-2.25.19-3.28.54-1.73.59-1.25,3.19.57,3.19h6.91c-1.52.29-2.97.97-4.18,2.06-.78.7-1.4,1.53-1.87,2.43-.84,1.61,1.22,3.18,2.57,1.97l5.57-5.04-.42,13.87c0,.17-.1.33-.22.46-.18-.08-.35-.16-.53-.26-.78-.39-1.76-.88-3.55-.88s-2.76.49-3.55.88c-.68.34-1.21.61-2.38.61v2.6c1.79,0,2.76-.49,3.55-.88.68-.34,1.21-.61,2.38-.61s1.71.27,2.38.61c.78.39,1.76.88,3.55.88s2.76-.49,3.55-.88c.68-.34,1.21-.61,2.38-.61s1.71.27,2.38.61c.78.39,1.76.88,3.55.88v-2.6c-1.17,0-1.71-.27-2.38-.61h0c-.78-.4-1.76-.89-3.55-.89s-2.76.49-3.55.88c-.2.1-.39.2-.59.28-.15-.13-.24-.3-.25-.48l-.42-13.94,5.65,5.12c1.35,1.22,3.4-.35,2.57-1.97-.46-.89-1.08-1.72-1.87-2.43-1.21-1.1-2.65-1.77-4.18-2.06h6.91c1.83,0,2.3-2.6.57-3.19-1.03-.35-2.13-.54-3.28-.54-2.1,0-4.04.65-5.67,1.75l4.95-4.49Z"
fill="currentColor"
fillRule="evenodd"
/>
<path
d="M151.71,43.25h-12.45c-.67,0-1.28-.42-1.53-1.04l-2.55-6.55c-.65-1.7-3.15-1.22-3.17.58-.02,1.8-.02,3.53-.02,5.37,0,.9-.74,1.64-1.64,1.64h-10.47c-.92,0-1.64-.72-1.64-1.64V8.34c0-.9.72-1.64,1.64-1.64h12.43c.69-.02,1.28.41,1.53,1.04l2.61,6.84c.65,1.7,3.15,1.25,3.17-.57l.07-5.69c0-.9.74-1.63,1.64-1.63h10.4c.9,0,1.64.74,1.64,1.66v33.26c0,.92-.74,1.64-1.64,1.64l-.02-.02Z"
fill="currentColor"
/>
<path
d="M98.25,37.35l-3.85-.04c-.81,0-1.5.58-1.64,1.38l-.53,3.18c-.12.79-.81,1.38-1.62,1.38h-11.07c-1.07,0-1.85-.99-1.6-2.03l8.38-33.28c.18-.72.85-1.24,1.6-1.24h16.76c.76.02,1.41.53,1.58,1.27l8.4,33.25c.26,1.04-.51,2.05-1.58,2.05l-11.07.04c-.81,0-1.5-.58-1.62-1.38l-.53-3.16c-.12-.79-.81-1.38-1.6-1.38v-.04ZM97.94,27.4l-.85-4.19c-.18-.88-1.44-.88-1.62,0l-.76,4.2c-.19,1.02.62,1.98,1.65,1.94,1.02-.04,1.76-.97,1.57-1.98v.02Z"
fill="currentColor"
/>
<path
d="M69.77,43.23l-10.49.04c-.92,0-1.65-.74-1.65-1.64v-21.76c0-.9-.72-1.64-1.64-1.64h-5.39c-.9,0-1.64-.76-1.64-1.66v-8.2c0-.9.74-1.64,1.65-1.64h27.8c.9,0,1.64.74,1.64,1.64v8.2c0,.9-.72,1.64-1.64,1.64h-5.39c-.9,0-1.64.74-1.64,1.66v21.75c0,.9-.74,1.64-1.64,1.64l.02-.02Z"
fill="currentColor"
/>
<path
d="M311.9,24.92l9.21,15.85c.63,1.1-.14,2.47-1.41,2.47l-10.72.05c-.6,0-1.14-.32-1.44-.83l-4.07-7.21c-.6-1.08-2.24-.65-2.25.58l-.1,5.81c0,.9-.74,1.63-1.64,1.63h-10.47c-.92,0-1.64-.72-1.64-1.64V8.37c0-.9.72-1.64,1.64-1.64h10.49c.9,0,1.62.71,1.64,1.59l.11,4.26c.04,1.27,1.74,1.64,2.29.49l2.59-5.39c.28-.57.85-.94,1.48-.94h10.88c1.27-.02,2.06,1.34,1.43,2.44l-7.97,14.1c-.28.51-.28,1.13,0,1.64h-.02Z"
fill="currentColor"
/>
<path
d="M238.4,37.38l-3.85-.04c-.81,0-1.5.58-1.64,1.38l-.53,3.18c-.12.79-.81,1.38-1.62,1.38h-11.09c-1.07,0-1.85-.99-1.6-2.03l8.38-33.26c.18-.72.85-1.24,1.58-1.24h16.78c.76-.02,1.41.49,1.6,1.22l8.4,33.26c.26,1.04-.51,2.05-1.58,2.05h-11.07c-.81.04-1.5-.55-1.62-1.34l-.53-3.16c-.12-.79-.81-1.38-1.6-1.38v-.02ZM238.07,27.43l-.74-3.67c-.19-.99-1.62-.99-1.81.02l-.67,3.69c-.19,1.02.62,1.98,1.65,1.94,1.02-.04,1.76-.97,1.57-1.98Z"
fill="currentColor"
/>
<path
d="M189.42,33.35c-.99,11.71-17.78,12.35-29.17,8.2-.67-.25-1.11-.9-1.11-1.61v-9.57c0-1.31,1.37-2.14,2.52-1.5,3.68,2.01,7.39,3.44,11.6,4.29,0,0,1.39.11,1.9-.79.51-.9-.46-1.25-.88-1.61-8.01-3.48-17.32-5.53-16.49-14.59.97-10.48,16.83-11.75,27.62-8.39.7.21,1.18.9,1.18,1.64v9.38c0,1.24-1.27,2.07-2.41,1.57-5.16-2.28-12.16-4.29-11.81-2.95.9,3.39,18.06,3.76,17.04,15.9l.02.04Z"
fill="currentColor"
/>
<path
d="M271.32,29.38c2.8,2.33,6.25,2.44,9.22.94,1.41-.71,3.06.25,3.06,1.82l.05,8.37c0,.87-.51,1.68-1.34,1.96-8.08,2.86-17.55,1.24-23.25-5.81-5.7-7.05-5.42-16.91.23-23.62,5.65-6.71,15.03-8.27,23.01-5.55.83.28,1.36,1.1,1.36,1.98l-.05,8.37c0,1.57-1.65,2.53-3.06,1.84-2.94-1.47-6.28-1.47-9.12.79-2.48,1.98-2.75,6.69-.11,8.9Z"
fill="currentColor"
/>
<path
d="M210.7,43.24l-10.49.04c-.92,0-1.65-.74-1.65-1.64v-21.76c0-.9-.72-1.64-1.64-1.64h-5.39c-.9,0-1.64-.76-1.64-1.66v-8.2c0-.9.74-1.64,1.65-1.64h27.79c.9,0,1.64.74,1.64,1.64v8.2c0,.9-.72,1.64-1.64,1.64h-5.39c-.9,0-1.64.74-1.64,1.66v21.75c0,.9-.72,1.64-1.64,1.64l.02-.02Z"
fill="currentColor"
/>
</svg>
)
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
"i18n:update:ai": "turbo i18n:update:ai"
},
"devDependencies": {
"@types/node": "^26.1.1",
"@types/node": "^26.5.1",
"@vitnode/config": "workspace:*",
"prettier": "^3.9.6",
"prettier-plugin-tailwindcss": "^0.8.1",
"tsx": "^4.23.1",
"turbo": "^2.10.6",
"tsx": "^4.23.13",
"turbo": "^2.10.12",
"typescript": "^6.0.3",
"zod": "^4.4.3"
"zod": "^4.6.2"
},
"engines": {
"node": ">=22"
Expand Down
3 changes: 3 additions & 0 deletions packages/config/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default [
"@typescript-eslint/no-confusing-void-expression": "off",
"@typescript-eslint/no-unnecessary-type-parameters": "off",
"@typescript-eslint/no-misused-spread": "off",
"@typescript-eslint/no-generated-empty-object-type": "off",
"perfectionist/sort-decorators": "warn",
"perfectionist/sort-modules": "off",
"perfectionist/sort-switch-case": "warn",
Expand Down Expand Up @@ -78,6 +79,8 @@ export default [
{
ignoreRestSiblings: false,
caughtErrorsIgnorePattern: "^_",
varsIgnorePattern: "^_",
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-empty-function": "off",
Expand Down
Loading
Loading