better-ts-stack 2.1.1 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +21 -21
  2. package/dist/args.js +6 -0
  3. package/dist/builder/moduleSelector.js +6 -1
  4. package/dist/builder/readmeGenerator.js +6 -0
  5. package/dist/builder/templateContext.js +1 -0
  6. package/dist/prompts/stack.js +7 -0
  7. package/dist/types/index.js +2 -0
  8. package/dist/ui/messages.js +2 -0
  9. package/package.json +71 -71
  10. package/templates/backend/express/.prettierignore +52 -52
  11. package/templates/backend/express/.prettierrc +16 -16
  12. package/templates/backend/express/gitignore +3 -1
  13. package/templates/backend/express/tsconfig.eslint.json +9 -9
  14. package/templates/backend/nestjs/.prettierignore +52 -52
  15. package/templates/backend/nestjs/gitignore +3 -1
  16. package/templates/backend/nestjs/tsconfig.eslint.json +9 -9
  17. package/templates/frontend/nextjs/app/globals.css +89 -89
  18. package/templates/frontend/nextjs/app/layout.tsx +34 -34
  19. package/templates/frontend/nextjs/components/ui/button.tsx +51 -51
  20. package/templates/frontend/nextjs/components/ui/card.tsx +60 -60
  21. package/templates/frontend/nextjs/components/ui/field.tsx +67 -67
  22. package/templates/frontend/nextjs/components/ui/input.tsx +18 -18
  23. package/templates/frontend/nextjs/config.json +35 -35
  24. package/templates/frontend/nextjs/eslint.config.mjs +11 -11
  25. package/templates/frontend/nextjs/next.config.ts.hbs +12 -12
  26. package/templates/frontend/nextjs/postcss.config.mjs +7 -7
  27. package/templates/frontend/nextjs/public/file.svg +1 -1
  28. package/templates/frontend/nextjs/public/globe.svg +1 -1
  29. package/templates/frontend/nextjs/public/window.svg +1 -1
  30. package/templates/frontend/tanstack/components.json +18 -18
  31. package/templates/frontend/tanstack/eslint.config.mjs +23 -23
  32. package/templates/frontend/tanstack/gitignore +39 -39
  33. package/templates/frontend/tanstack/public/favicon.svg +7 -7
  34. package/templates/frontend/tanstack/src/components/ui/button.tsx +51 -51
  35. package/templates/frontend/tanstack/src/components/ui/card.tsx +60 -60
  36. package/templates/frontend/tanstack/src/components/ui/field.tsx +67 -67
  37. package/templates/frontend/tanstack/src/components/ui/input.tsx +18 -18
  38. package/templates/frontend/tanstack/src/lib/utils.ts +6 -6
  39. package/templates/frontend/tanstack/src/router.tsx +31 -31
  40. package/templates/frontend/tanstack/src/routes/__root.tsx +69 -69
  41. package/templates/frontend/tanstack/tsconfig.json +22 -22
  42. package/templates/modules/agents/AGENTS.md.hbs +237 -0
  43. package/templates/modules/agents/CLAUDE.md +1 -0
  44. package/templates/modules/agents/config.json +10 -0
  45. package/templates/modules/auth/express/src/lib/jwt.ts.hbs +27 -27
  46. package/templates/modules/auth/nextjs/app/api/auth/[...all]/route.ts +4 -4
  47. package/templates/modules/auth/nextjs/config.json +18 -18
  48. package/templates/modules/auth/nextjs/lib/auth-client.ts +3 -3
  49. package/templates/modules/auth/tanstack/config.json +18 -18
  50. package/templates/modules/auth/tanstack/src/lib/auth-client.ts +2 -2
  51. package/templates/modules/auth/tanstack/src/lib/auth-functions.ts +8 -8
  52. package/templates/modules/auth/tanstack/src/lib/auth.ts.hbs +37 -37
  53. package/templates/modules/auth/tanstack/src/routes/api/auth/$.ts +15 -15
  54. package/templates/modules/auth/tanstack/src/routes/dashboard.tsx +110 -110
  55. package/templates/modules/auth/tanstack/src/routes/sign-in.tsx +36 -36
  56. package/templates/modules/auth/tanstack/src/routes/sign-up.tsx +36 -36
  57. package/templates/modules/docker/.dockerignore +2 -0
  58. package/templates/modules/docker/config.json +15 -15
  59. package/templates/modules/drizzle/express/config.json +26 -26
  60. package/templates/modules/drizzle/nestjs/config.json +26 -26
  61. package/templates/modules/drizzle/nextjs/config.json +26 -26
  62. package/templates/modules/drizzle/nextjs/drizzle.config.ts +13 -13
  63. package/templates/modules/drizzle/tanstack/config.json +26 -26
  64. package/templates/modules/drizzle/tanstack/drizzle.config.ts +12 -12
  65. package/templates/modules/drizzle/tanstack/src/lib/db.ts +13 -13
  66. package/templates/modules/mongoose/express/config.json +15 -15
  67. package/templates/modules/mongoose/express/src/lib/db.ts +43 -43
  68. package/templates/modules/mongoose/express/src/models/User.ts +48 -48
  69. package/templates/modules/mongoose/nestjs/config.json +15 -15
  70. package/templates/modules/mongoose/nextjs/config.json +15 -15
  71. package/templates/modules/mongoose/nextjs/models/User.ts +48 -48
  72. package/templates/modules/mongoose/tanstack/config.json +16 -16
  73. package/templates/modules/mongoose/tanstack/src/models/User.ts +48 -48
  74. package/templates/modules/prisma/express/config.json +27 -27
  75. package/templates/modules/prisma/express/prisma/schema.prisma +23 -23
  76. package/templates/modules/prisma/nestjs/config.json +27 -27
  77. package/templates/modules/prisma/nextjs/config.json +28 -28
  78. package/templates/modules/prisma/nextjs/lib/prisma.ts +18 -18
  79. package/templates/modules/prisma/nextjs/prisma.config.ts +14 -14
  80. package/templates/modules/prisma/tanstack/config.json +28 -28
  81. package/templates/modules/prisma/tanstack/prisma/schema.prisma.hbs +91 -91
  82. package/templates/modules/prisma/tanstack/prisma.config.ts +14 -14
  83. package/templates/modules/prisma/tanstack/src/lib/prisma.ts +17 -17
  84. package/templates/modules/vscode/.vscode/extensions.json.hbs +29 -0
  85. package/templates/modules/vscode/.vscode/settings.json.hbs +22 -0
  86. package/templates/modules/vscode/config.json +10 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "id": "agents",
3
+ "name": "AI agent instructions",
4
+ "description": "An AGENTS.md that tells AI coding agents how this project is built, run, and checked, and a CLAUDE.md that points Claude Code to it",
5
+ "type": "feature",
6
+ "dependencies": {},
7
+ "devDependencies": {},
8
+ "scripts": {},
9
+ "envVars": {}
10
+ }
@@ -1,27 +1,27 @@
1
- import jwt, { type SignOptions } from "jsonwebtoken";
2
-
3
- export interface AuthTokenPayload {
4
- sub: string;
5
- email: string;
6
- name?: string | null;
7
- }
8
-
9
- const { JWT_SECRET, JWT_EXPIRES_IN } = process.env;
10
-
11
- function ensureSecret(): string {
12
- if (!JWT_SECRET) {
13
- throw new Error("JWT_SECRET is not set");
14
- }
15
- return JWT_SECRET;
16
- }
17
-
18
- export function signToken(payload: AuthTokenPayload): string {
19
- const secret = ensureSecret();
20
- const expiresIn = JWT_EXPIRES_IN || "1h";
21
- return jwt.sign(payload, secret, { expiresIn } as SignOptions);
22
- }
23
-
24
- export function verifyToken(token: string): AuthTokenPayload {
25
- const secret = ensureSecret();
26
- return jwt.verify(token, secret) as AuthTokenPayload;
27
- }
1
+ import jwt, { type SignOptions } from "jsonwebtoken";
2
+
3
+ export interface AuthTokenPayload {
4
+ sub: string;
5
+ email: string;
6
+ name?: string | null;
7
+ }
8
+
9
+ const { JWT_SECRET, JWT_EXPIRES_IN } = process.env;
10
+
11
+ function ensureSecret(): string {
12
+ if (!JWT_SECRET) {
13
+ throw new Error("JWT_SECRET is not set");
14
+ }
15
+ return JWT_SECRET;
16
+ }
17
+
18
+ export function signToken(payload: AuthTokenPayload): string {
19
+ const secret = ensureSecret();
20
+ const expiresIn = JWT_EXPIRES_IN || "1h";
21
+ return jwt.sign(payload, secret, { expiresIn } as SignOptions);
22
+ }
23
+
24
+ export function verifyToken(token: string): AuthTokenPayload {
25
+ const secret = ensureSecret();
26
+ return jwt.verify(token, secret) as AuthTokenPayload;
27
+ }
@@ -1,4 +1,4 @@
1
- import { auth } from "@/lib/auth";
2
- import { toNextJsHandler } from "better-auth/next-js";
3
-
4
- export const { GET, POST } = toNextJsHandler(auth);
1
+ import { auth } from "@/lib/auth";
2
+ import { toNextJsHandler } from "better-auth/next-js";
3
+
4
+ export const { GET, POST } = toNextJsHandler(auth);
@@ -1,18 +1,18 @@
1
- {
2
- "id": "auth",
3
- "name": "Better Auth",
4
- "description": "Better Auth for Next.js with optional Prisma or Drizzle adapter",
5
- "type": "feature",
6
- "dependencies": {
7
- "@hookform/resolvers": "^5.9.2",
8
- "better-auth": "^1.7.14",
9
- "react-hook-form": "^7.91.0",
10
- "zod": "^4.6.7"
11
- },
12
- "devDependencies": {},
13
- "scripts": {},
14
- "envVars": {
15
- "BETTER_AUTH_SECRET": "please-change-me-to-a-random-string",
16
- "BETTER_AUTH_URL": "http://localhost:3000"
17
- }
18
- }
1
+ {
2
+ "id": "auth",
3
+ "name": "Better Auth",
4
+ "description": "Better Auth for Next.js with optional Prisma or Drizzle adapter",
5
+ "type": "feature",
6
+ "dependencies": {
7
+ "@hookform/resolvers": "^5.9.2",
8
+ "better-auth": "^1.7.14",
9
+ "react-hook-form": "^7.91.0",
10
+ "zod": "^4.6.7"
11
+ },
12
+ "devDependencies": {},
13
+ "scripts": {},
14
+ "envVars": {
15
+ "BETTER_AUTH_SECRET": "please-change-me-to-a-random-string",
16
+ "BETTER_AUTH_URL": "http://localhost:3000"
17
+ }
18
+ }
@@ -1,3 +1,3 @@
1
- import { createAuthClient } from "better-auth/react";
2
-
3
- export const authClient = createAuthClient();
1
+ import { createAuthClient } from "better-auth/react";
2
+
3
+ export const authClient = createAuthClient();
@@ -1,19 +1,19 @@
1
- {
2
- "id": "auth",
3
- "name": "Better Auth",
4
- "description": "Better Auth for TanStack Start with optional Prisma, Drizzle, or MongoDB adapter",
5
- "type": "feature",
6
- "dependencies": {
7
- "@hookform/resolvers": "^5.9.2",
8
- "better-auth": "^1.7.14",
9
- "dotenv": "^17.4.2",
10
- "react-hook-form": "^7.91.0",
11
- "zod": "^4.6.7"
12
- },
13
- "devDependencies": {},
14
- "scripts": {},
15
- "envVars": {
16
- "BETTER_AUTH_SECRET": "please-change-me-to-a-random-string",
17
- "BETTER_AUTH_URL": "http://localhost:3000"
18
- }
1
+ {
2
+ "id": "auth",
3
+ "name": "Better Auth",
4
+ "description": "Better Auth for TanStack Start with optional Prisma, Drizzle, or MongoDB adapter",
5
+ "type": "feature",
6
+ "dependencies": {
7
+ "@hookform/resolvers": "^5.9.2",
8
+ "better-auth": "^1.7.14",
9
+ "dotenv": "^17.4.2",
10
+ "react-hook-form": "^7.91.0",
11
+ "zod": "^4.6.7"
12
+ },
13
+ "devDependencies": {},
14
+ "scripts": {},
15
+ "envVars": {
16
+ "BETTER_AUTH_SECRET": "please-change-me-to-a-random-string",
17
+ "BETTER_AUTH_URL": "http://localhost:3000"
18
+ }
19
19
  }
@@ -1,3 +1,3 @@
1
- import { createAuthClient } from "better-auth/react";
2
-
1
+ import { createAuthClient } from "better-auth/react";
2
+
3
3
  export const authClient = createAuthClient();
@@ -1,12 +1,12 @@
1
- import { createServerFn } from "@tanstack/react-start";
2
- import { getRequestHeaders } from "@tanstack/react-start/server";
3
-
4
- import { auth } from "./auth";
5
-
6
- export const getSession = createServerFn({ method: "GET" }).handler(async () => {
1
+ import { createServerFn } from "@tanstack/react-start";
2
+ import { getRequestHeaders } from "@tanstack/react-start/server";
3
+
4
+ import { auth } from "./auth";
5
+
6
+ export const getSession = createServerFn({ method: "GET" }).handler(async () => {
7
7
  const session = await auth.api.getSession({
8
8
  headers: getRequestHeaders(),
9
9
  });
10
-
11
- return session;
10
+
11
+ return session;
12
12
  });
@@ -1,38 +1,38 @@
1
- import "dotenv/config";
2
- import { betterAuth } from "better-auth";
3
- import { tanstackStartCookies } from "better-auth/tanstack-start";
4
- {{#if (eq database 'prisma')}}
5
- import { prismaAdapter } from "better-auth/adapters/prisma";
6
- import client from "./prisma";
7
- {{/if}}
8
- {{#if (eq database 'drizzle')}}
9
- import { drizzleAdapter } from "better-auth/adapters/drizzle";
10
- import { db } from "./db";
11
- {{/if}}
12
- {{#if (eq database 'mongoose')}}
13
- import { mongodbAdapter } from "better-auth/adapters/mongodb";
14
- import { MongoClient } from "mongodb";
15
-
16
- const client = new MongoClient(process.env.MONGODB_URI!);
17
- const db = client.db();
18
- {{/if}}
19
-
20
- export const auth = betterAuth({
21
- {{#if (eq database 'prisma')}}
22
- database: prismaAdapter(client, { provider: "postgresql" }),
23
- {{/if}}
24
- {{#if (eq database 'drizzle')}}
25
- database: drizzleAdapter(db, { provider: "pg" }),
26
- {{/if}}
27
- {{#if (eq database 'mongoose')}}
28
- // Transactions require a replica set. Create user/session/account/verification
29
- // collections before the first sign-up; see the database setup documentation.
30
- database: mongodbAdapter(db, { client }),
31
- {{/if}}
32
- emailAndPassword: {
33
- enabled: true,
34
- },
35
- plugins: [tanstackStartCookies()],
36
- secret: process.env.BETTER_AUTH_SECRET,
37
- baseURL: process.env.BETTER_AUTH_URL,
1
+ import "dotenv/config";
2
+ import { betterAuth } from "better-auth";
3
+ import { tanstackStartCookies } from "better-auth/tanstack-start";
4
+ {{#if (eq database 'prisma')}}
5
+ import { prismaAdapter } from "better-auth/adapters/prisma";
6
+ import client from "./prisma";
7
+ {{/if}}
8
+ {{#if (eq database 'drizzle')}}
9
+ import { drizzleAdapter } from "better-auth/adapters/drizzle";
10
+ import { db } from "./db";
11
+ {{/if}}
12
+ {{#if (eq database 'mongoose')}}
13
+ import { mongodbAdapter } from "better-auth/adapters/mongodb";
14
+ import { MongoClient } from "mongodb";
15
+
16
+ const client = new MongoClient(process.env.MONGODB_URI!);
17
+ const db = client.db();
18
+ {{/if}}
19
+
20
+ export const auth = betterAuth({
21
+ {{#if (eq database 'prisma')}}
22
+ database: prismaAdapter(client, { provider: "postgresql" }),
23
+ {{/if}}
24
+ {{#if (eq database 'drizzle')}}
25
+ database: drizzleAdapter(db, { provider: "pg" }),
26
+ {{/if}}
27
+ {{#if (eq database 'mongoose')}}
28
+ // Transactions require a replica set. Create user/session/account/verification
29
+ // collections before the first sign-up; see the database setup documentation.
30
+ database: mongodbAdapter(db, { client }),
31
+ {{/if}}
32
+ emailAndPassword: {
33
+ enabled: true,
34
+ },
35
+ plugins: [tanstackStartCookies()],
36
+ secret: process.env.BETTER_AUTH_SECRET,
37
+ baseURL: process.env.BETTER_AUTH_URL,
38
38
  });
@@ -1,16 +1,16 @@
1
- import { createFileRoute } from "@tanstack/react-router";
2
-
3
- import { auth } from "~/lib/auth";
4
-
5
- export const Route = createFileRoute("/api/auth/$")({
6
- server: {
7
- handlers: {
8
- GET: async ({ request }: { request: Request }) => {
9
- return await auth.handler(request);
10
- },
11
- POST: async ({ request }: { request: Request }) => {
12
- return await auth.handler(request);
13
- },
14
- },
15
- },
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+
3
+ import { auth } from "~/lib/auth";
4
+
5
+ export const Route = createFileRoute("/api/auth/$")({
6
+ server: {
7
+ handlers: {
8
+ GET: async ({ request }: { request: Request }) => {
9
+ return await auth.handler(request);
10
+ },
11
+ POST: async ({ request }: { request: Request }) => {
12
+ return await auth.handler(request);
13
+ },
14
+ },
15
+ },
16
16
  });
@@ -1,111 +1,111 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
2
- import { Link } from "@tanstack/react-router";
3
- import { ArrowRight, ShieldCheck } from "lucide-react";
4
-
5
- import { SignOutButton } from "~/components/auth/sign-out-button";
6
- import { buttonVariants } from "~/components/ui/button";
7
- import {
8
- Card,
9
- CardContent,
10
- CardDescription,
11
- CardHeader,
12
- CardTitle,
13
- } from "~/components/ui/card";
14
- import { getSession } from "~/lib/auth-functions";
15
- import { cn } from "~/lib/utils";
16
-
17
- export const Route = createFileRoute("/dashboard")({
18
- beforeLoad: async () => {
19
- const session = await getSession();
20
-
21
- if (!session) {
22
- throw redirect({ to: "/sign-in" });
23
- }
24
-
25
- return { user: session.user };
26
- },
27
- component: Dashboard,
28
- });
29
-
30
- function Dashboard() {
31
- const user = Route.useRouteContext({ select: (ctx) => ctx.user });
32
-
33
- return (
34
- <main className="min-h-screen bg-[linear-gradient(180deg,_#f8fafc_0%,_#eef2ff_100%)] px-6 py-16 sm:px-10">
35
- <div className="mx-auto max-w-5xl space-y-8">
36
- <header className="flex flex-col gap-6 rounded-[2rem] border border-white/70 bg-white/85 p-8 shadow-xl shadow-slate-200/60 backdrop-blur md:flex-row md:items-end md:justify-between">
37
- <div className="space-y-3">
38
- <span className="inline-flex items-center gap-2 rounded-full bg-emerald-50 px-3 py-1 text-xs font-medium uppercase tracking-[0.24em] text-emerald-700">
39
- <ShieldCheck className="size-4" />
40
- Authenticated session
41
- </span>
42
- <div className="space-y-1">
43
- <h1 className="text-3xl font-semibold tracking-tight text-slate-950">
44
- Welcome {user.name}
45
- </h1>
46
- <p className="text-sm text-slate-600">{user.email}</p>
47
- </div>
48
- </div>
49
- <SignOutButton />
50
- </header>
51
-
52
- <section className="grid gap-5 md:grid-cols-2">
53
- <Card>
54
- <CardHeader>
55
- <CardTitle>Protected route example</CardTitle>
56
- <CardDescription>
57
- This page verifies the session on the server before rendering any
58
- content.
59
- </CardDescription>
60
- </CardHeader>
61
- <CardContent className="space-y-4 text-sm text-slate-600">
62
- <p>
63
- The route guard calls{" "}
64
- <code className="font-mono text-slate-900">getSession()</code> in
65
- <code className="font-mono text-slate-900"> beforeLoad</code>,
66
- which reads the cookie headers server-side via{" "}
67
- <code className="font-mono text-slate-900">
68
- auth.api.getSession
69
- </code>{" "}
70
- on every render and navigation.
71
- </p>
72
- <p>
73
- That keeps route protection aligned with Better Auth&apos;s
74
- TanStack Start guidance while staying easy to extend.
75
- </p>
76
- </CardContent>
77
- </Card>
78
-
79
- <Card>
80
- <CardHeader>
81
- <CardTitle>Suggested next steps</CardTitle>
82
- <CardDescription>
83
- Keep the generated auth flow, then customize the app around your
84
- product.
85
- </CardDescription>
86
- </CardHeader>
87
- <CardContent className="space-y-3 text-sm text-slate-600">
88
- <p>
89
- Replace the demo dashboard with your first authenticated page.
90
- </p>
91
- <p>Extend the schema with profile or onboarding fields.</p>
92
- <p>
93
- Add provider-based auth or email verification later if needed.
94
- </p>
95
- <Link
96
- to="/"
97
- className={cn(
98
- buttonVariants({ variant: "outline" }),
99
- "w-fit gap-2"
100
- )}
101
- >
102
- Back to home
103
- <ArrowRight className="size-4" />
104
- </Link>
105
- </CardContent>
106
- </Card>
107
- </section>
108
- </div>
109
- </main>
110
- );
1
+ import { createFileRoute, redirect } from "@tanstack/react-router";
2
+ import { Link } from "@tanstack/react-router";
3
+ import { ArrowRight, ShieldCheck } from "lucide-react";
4
+
5
+ import { SignOutButton } from "~/components/auth/sign-out-button";
6
+ import { buttonVariants } from "~/components/ui/button";
7
+ import {
8
+ Card,
9
+ CardContent,
10
+ CardDescription,
11
+ CardHeader,
12
+ CardTitle,
13
+ } from "~/components/ui/card";
14
+ import { getSession } from "~/lib/auth-functions";
15
+ import { cn } from "~/lib/utils";
16
+
17
+ export const Route = createFileRoute("/dashboard")({
18
+ beforeLoad: async () => {
19
+ const session = await getSession();
20
+
21
+ if (!session) {
22
+ throw redirect({ to: "/sign-in" });
23
+ }
24
+
25
+ return { user: session.user };
26
+ },
27
+ component: Dashboard,
28
+ });
29
+
30
+ function Dashboard() {
31
+ const user = Route.useRouteContext({ select: (ctx) => ctx.user });
32
+
33
+ return (
34
+ <main className="min-h-screen bg-[linear-gradient(180deg,_#f8fafc_0%,_#eef2ff_100%)] px-6 py-16 sm:px-10">
35
+ <div className="mx-auto max-w-5xl space-y-8">
36
+ <header className="flex flex-col gap-6 rounded-[2rem] border border-white/70 bg-white/85 p-8 shadow-xl shadow-slate-200/60 backdrop-blur md:flex-row md:items-end md:justify-between">
37
+ <div className="space-y-3">
38
+ <span className="inline-flex items-center gap-2 rounded-full bg-emerald-50 px-3 py-1 text-xs font-medium uppercase tracking-[0.24em] text-emerald-700">
39
+ <ShieldCheck className="size-4" />
40
+ Authenticated session
41
+ </span>
42
+ <div className="space-y-1">
43
+ <h1 className="text-3xl font-semibold tracking-tight text-slate-950">
44
+ Welcome {user.name}
45
+ </h1>
46
+ <p className="text-sm text-slate-600">{user.email}</p>
47
+ </div>
48
+ </div>
49
+ <SignOutButton />
50
+ </header>
51
+
52
+ <section className="grid gap-5 md:grid-cols-2">
53
+ <Card>
54
+ <CardHeader>
55
+ <CardTitle>Protected route example</CardTitle>
56
+ <CardDescription>
57
+ This page verifies the session on the server before rendering any
58
+ content.
59
+ </CardDescription>
60
+ </CardHeader>
61
+ <CardContent className="space-y-4 text-sm text-slate-600">
62
+ <p>
63
+ The route guard calls{" "}
64
+ <code className="font-mono text-slate-900">getSession()</code> in
65
+ <code className="font-mono text-slate-900"> beforeLoad</code>,
66
+ which reads the cookie headers server-side via{" "}
67
+ <code className="font-mono text-slate-900">
68
+ auth.api.getSession
69
+ </code>{" "}
70
+ on every render and navigation.
71
+ </p>
72
+ <p>
73
+ That keeps route protection aligned with Better Auth&apos;s
74
+ TanStack Start guidance while staying easy to extend.
75
+ </p>
76
+ </CardContent>
77
+ </Card>
78
+
79
+ <Card>
80
+ <CardHeader>
81
+ <CardTitle>Suggested next steps</CardTitle>
82
+ <CardDescription>
83
+ Keep the generated auth flow, then customize the app around your
84
+ product.
85
+ </CardDescription>
86
+ </CardHeader>
87
+ <CardContent className="space-y-3 text-sm text-slate-600">
88
+ <p>
89
+ Replace the demo dashboard with your first authenticated page.
90
+ </p>
91
+ <p>Extend the schema with profile or onboarding fields.</p>
92
+ <p>
93
+ Add provider-based auth or email verification later if needed.
94
+ </p>
95
+ <Link
96
+ to="/"
97
+ className={cn(
98
+ buttonVariants({ variant: "outline" }),
99
+ "w-fit gap-2"
100
+ )}
101
+ >
102
+ Back to home
103
+ <ArrowRight className="size-4" />
104
+ </Link>
105
+ </CardContent>
106
+ </Card>
107
+ </section>
108
+ </div>
109
+ </main>
110
+ );
111
111
  }
@@ -1,37 +1,37 @@
1
- import { createFileRoute, redirect } from "@tanstack/react-router";
2
-
3
- import { SignInForm } from "~/components/auth/sign-in-form";
4
- import { getSession } from "~/lib/auth-functions";
5
-
6
- export const Route = createFileRoute("/sign-in")({
7
- beforeLoad: async () => {
8
- const session = await getSession();
9
-
10
- if (session) {
11
- throw redirect({ to: "/dashboard" });
12
- }
13
- },
14
- component: SignInPage,
15
- });
16
-
17
- function SignInPage() {
18
- return (
19
- <main className="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(14,165,233,0.16),_transparent_30%),linear-gradient(180deg,_#f8fafc_0%,_#eef2ff_100%)] px-6 py-16 sm:px-10">
20
- <div className="mx-auto flex min-h-[calc(100vh-8rem)] max-w-5xl items-center gap-12 lg:grid lg:grid-cols-[0.9fr_1.1fr]">
21
- <section className="hidden space-y-5 lg:block">
22
- <span className="inline-flex rounded-full border border-sky-200 bg-white/80 px-3 py-1 text-xs font-medium uppercase tracking-[0.24em] text-sky-700">
23
- Better Auth
24
- </span>
25
- <h1 className="text-4xl font-semibold tracking-tight text-slate-950">
26
- Welcome back.
27
- </h1>
28
- <p className="max-w-md text-base leading-7 text-slate-600">
29
- This generated starter includes protected routes, session-aware page
30
- guards, and reusable auth form primitives you can extend from here.
31
- </p>
32
- </section>
33
- <SignInForm />
34
- </div>
35
- </main>
36
- );
1
+ import { createFileRoute, redirect } from "@tanstack/react-router";
2
+
3
+ import { SignInForm } from "~/components/auth/sign-in-form";
4
+ import { getSession } from "~/lib/auth-functions";
5
+
6
+ export const Route = createFileRoute("/sign-in")({
7
+ beforeLoad: async () => {
8
+ const session = await getSession();
9
+
10
+ if (session) {
11
+ throw redirect({ to: "/dashboard" });
12
+ }
13
+ },
14
+ component: SignInPage,
15
+ });
16
+
17
+ function SignInPage() {
18
+ return (
19
+ <main className="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(14,165,233,0.16),_transparent_30%),linear-gradient(180deg,_#f8fafc_0%,_#eef2ff_100%)] px-6 py-16 sm:px-10">
20
+ <div className="mx-auto flex min-h-[calc(100vh-8rem)] max-w-5xl items-center gap-12 lg:grid lg:grid-cols-[0.9fr_1.1fr]">
21
+ <section className="hidden space-y-5 lg:block">
22
+ <span className="inline-flex rounded-full border border-sky-200 bg-white/80 px-3 py-1 text-xs font-medium uppercase tracking-[0.24em] text-sky-700">
23
+ Better Auth
24
+ </span>
25
+ <h1 className="text-4xl font-semibold tracking-tight text-slate-950">
26
+ Welcome back.
27
+ </h1>
28
+ <p className="max-w-md text-base leading-7 text-slate-600">
29
+ This generated starter includes protected routes, session-aware page
30
+ guards, and reusable auth form primitives you can extend from here.
31
+ </p>
32
+ </section>
33
+ <SignInForm />
34
+ </div>
35
+ </main>
36
+ );
37
37
  }