create-better-t-stack 3.9.0 → 3.10.0

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 (64) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.mjs +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/dist/{src-DLvUK0Qf.mjs → src-QkFdHtZE.mjs} +17 -14
  5. package/package.json +38 -38
  6. package/templates/auth/better-auth/convex/backend/convex/auth.config.ts.hbs +5 -7
  7. package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +16 -16
  8. package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +4 -4
  9. package/templates/auth/better-auth/convex/web/react/next/src/app/api/auth/[...all]/route.ts.hbs +2 -2
  10. package/templates/auth/better-auth/convex/web/react/next/src/components/user-menu.tsx.hbs +10 -10
  11. package/templates/auth/better-auth/convex/web/react/next/src/lib/auth-server.ts.hbs +13 -5
  12. package/templates/auth/better-auth/convex/web/react/tanstack-router/src/components/user-menu.tsx.hbs +14 -12
  13. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/components/user-menu.tsx.hbs +13 -16
  14. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs +11 -5
  15. package/templates/auth/better-auth/convex/web/react/tanstack-start/src/routes/api/auth/$.ts.hbs +4 -4
  16. package/templates/auth/better-auth/fullstack/tanstack-start/src/routes/api/auth/$.ts.hbs +1 -1
  17. package/templates/auth/better-auth/web/react/next/src/components/user-menu.tsx.hbs +17 -15
  18. package/templates/auth/better-auth/web/react/react-router/src/components/user-menu.tsx.hbs +16 -15
  19. package/templates/auth/better-auth/web/react/{tanstack-start/src/components/user-menu.tsx → tanstack-router/src/components/user-menu.tsx.hbs} +16 -15
  20. package/templates/auth/better-auth/web/react/{tanstack-router/src/components/user-menu.tsx → tanstack-start/src/components/user-menu.tsx.hbs} +16 -15
  21. package/templates/backend/convex/packages/backend/convex/README.md +4 -4
  22. package/templates/backend/convex/packages/backend/convex/tsconfig.json.hbs +1 -1
  23. package/templates/frontend/react/next/package.json.hbs +8 -7
  24. package/templates/frontend/react/next/src/app/layout.tsx.hbs +28 -1
  25. package/templates/frontend/react/next/src/components/mode-toggle.tsx.hbs +4 -6
  26. package/templates/frontend/react/next/src/components/providers.tsx.hbs +14 -4
  27. package/templates/frontend/react/react-router/package.json.hbs +2 -1
  28. package/templates/frontend/react/{tanstack-router/src/components/mode-toggle.tsx → react-router/src/components/mode-toggle.tsx.hbs} +4 -6
  29. package/templates/frontend/react/tanstack-router/package.json.hbs +2 -1
  30. package/templates/frontend/react/{react-router/src/components/mode-toggle.tsx → tanstack-router/src/components/mode-toggle.tsx.hbs} +4 -6
  31. package/templates/frontend/react/tanstack-start/package.json.hbs +2 -1
  32. package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +6 -0
  33. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +13 -14
  34. package/templates/frontend/react/tanstack-start/vite.config.ts.hbs +5 -0
  35. package/templates/frontend/react/web-base/components.json +5 -2
  36. package/templates/frontend/react/web-base/src/components/ui/button.tsx.hbs +57 -0
  37. package/templates/frontend/react/web-base/src/components/ui/card.tsx.hbs +103 -0
  38. package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx.hbs +26 -0
  39. package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx.hbs +262 -0
  40. package/templates/frontend/react/web-base/src/components/ui/input.tsx.hbs +20 -0
  41. package/templates/frontend/react/web-base/src/components/ui/label.tsx.hbs +20 -0
  42. package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx.hbs +13 -0
  43. package/templates/frontend/react/web-base/src/components/ui/sonner.tsx.hbs +44 -0
  44. package/templates/frontend/react/web-base/src/index.css.hbs +57 -63
  45. package/templates/frontend/react/web-base/src/components/ui/button.tsx +0 -56
  46. package/templates/frontend/react/web-base/src/components/ui/card.tsx +0 -75
  47. package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx +0 -27
  48. package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx +0 -228
  49. package/templates/frontend/react/web-base/src/components/ui/input.tsx +0 -21
  50. package/templates/frontend/react/web-base/src/components/ui/label.tsx +0 -19
  51. package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx +0 -13
  52. package/templates/frontend/react/web-base/src/components/ui/sonner.tsx +0 -25
  53. /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  54. /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  55. /package/templates/auth/better-auth/web/react/tanstack-router/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  56. /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  57. /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  58. /package/templates/auth/better-auth/web/react/tanstack-start/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  59. /package/templates/auth/better-auth/web/solid/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
  60. /package/templates/auth/better-auth/web/solid/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
  61. /package/templates/auth/better-auth/web/solid/src/routes/{login.tsx → login.tsx.hbs} +0 -0
  62. /package/templates/frontend/react/react-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
  63. /package/templates/frontend/react/tanstack-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
  64. /package/templates/frontend/react/web-base/src/lib/{utils.ts → utils.ts.hbs} +0 -0
@@ -1,16 +1,19 @@
1
+ import Link from "next/link";
2
+ import { useRouter } from "next/navigation";
3
+
1
4
  import {
2
5
  DropdownMenu,
3
6
  DropdownMenuContent,
7
+ DropdownMenuGroup,
4
8
  DropdownMenuItem,
5
9
  DropdownMenuLabel,
6
10
  DropdownMenuSeparator,
7
11
  DropdownMenuTrigger,
8
12
  } from "@/components/ui/dropdown-menu";
9
13
  import { authClient } from "@/lib/auth-client";
14
+
10
15
  import { Button } from "./ui/button";
11
16
  import { Skeleton } from "./ui/skeleton";
12
- import { useRouter } from "next/navigation";
13
- import Link from "next/link";
14
17
 
15
18
  export default function UserMenu() {
16
19
  const router = useRouter();
@@ -22,25 +25,24 @@ export default function UserMenu() {
22
25
 
23
26
  if (!session) {
24
27
  return (
25
- <Button variant="outline" asChild>
26
- <Link href="/login">Sign In</Link>
27
- </Button>
28
+ <Link href="/login">
29
+ <Button variant="outline">Sign In</Button>
30
+ </Link>
28
31
  );
29
32
  }
30
33
 
31
34
  return (
32
35
  <DropdownMenu>
33
- <DropdownMenuTrigger asChild>
34
- <Button variant="outline">{session.user.name}</Button>
36
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
37
+ {session.user.name}
35
38
  </DropdownMenuTrigger>
36
39
  <DropdownMenuContent className="bg-card">
37
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
38
- <DropdownMenuSeparator />
39
- <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
40
- <DropdownMenuItem asChild>
41
- <Button
40
+ <DropdownMenuGroup>
41
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
42
+ <DropdownMenuSeparator />
43
+ <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
44
+ <DropdownMenuItem
42
45
  variant="destructive"
43
- className="w-full"
44
46
  onClick={() => {
45
47
  authClient.signOut({
46
48
  fetchOptions: {
@@ -52,8 +54,8 @@ export default function UserMenu() {
52
54
  }}
53
55
  >
54
56
  Sign Out
55
- </Button>
56
- </DropdownMenuItem>
57
+ </DropdownMenuItem>
58
+ </DropdownMenuGroup>
57
59
  </DropdownMenuContent>
58
60
  </DropdownMenu>
59
61
  );
@@ -1,16 +1,18 @@
1
+ import { Link, useNavigate } from "react-router";
2
+
1
3
  import {
2
4
  DropdownMenu,
3
5
  DropdownMenuContent,
6
+ DropdownMenuGroup,
4
7
  DropdownMenuItem,
5
8
  DropdownMenuLabel,
6
9
  DropdownMenuSeparator,
7
10
  DropdownMenuTrigger,
8
11
  } from "@/components/ui/dropdown-menu";
9
12
  import { authClient } from "@/lib/auth-client";
10
- import { useNavigate } from "react-router";
13
+
11
14
  import { Button } from "./ui/button";
12
15
  import { Skeleton } from "./ui/skeleton";
13
- import { Link } from "react-router";
14
16
 
15
17
  export default function UserMenu() {
16
18
  const navigate = useNavigate();
@@ -22,25 +24,24 @@ export default function UserMenu() {
22
24
 
23
25
  if (!session) {
24
26
  return (
25
- <Button variant="outline" asChild>
26
- <Link to="/login">Sign In</Link>
27
- </Button>
27
+ <Link to="/login">
28
+ <Button variant="outline">Sign In</Button>
29
+ </Link>
28
30
  );
29
31
  }
30
32
 
31
33
  return (
32
34
  <DropdownMenu>
33
- <DropdownMenuTrigger asChild>
34
- <Button variant="outline">{session.user.name}</Button>
35
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
36
+ {session.user.name}
35
37
  </DropdownMenuTrigger>
36
38
  <DropdownMenuContent className="bg-card">
37
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
38
- <DropdownMenuSeparator />
39
- <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
40
- <DropdownMenuItem asChild>
41
- <Button
39
+ <DropdownMenuGroup>
40
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
41
+ <DropdownMenuSeparator />
42
+ <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
43
+ <DropdownMenuItem
42
44
  variant="destructive"
43
- className="w-full"
44
45
  onClick={() => {
45
46
  authClient.signOut({
46
47
  fetchOptions: {
@@ -52,8 +53,8 @@ export default function UserMenu() {
52
53
  }}
53
54
  >
54
55
  Sign Out
55
- </Button>
56
- </DropdownMenuItem>
56
+ </DropdownMenuItem>
57
+ </DropdownMenuGroup>
57
58
  </DropdownMenuContent>
58
59
  </DropdownMenu>
59
60
  );
@@ -1,16 +1,18 @@
1
+ import { Link, useNavigate } from "@tanstack/react-router";
2
+
1
3
  import {
2
4
  DropdownMenu,
3
5
  DropdownMenuContent,
6
+ DropdownMenuGroup,
4
7
  DropdownMenuItem,
5
8
  DropdownMenuLabel,
6
9
  DropdownMenuSeparator,
7
10
  DropdownMenuTrigger,
8
11
  } from "@/components/ui/dropdown-menu";
9
12
  import { authClient } from "@/lib/auth-client";
10
- import { useNavigate } from "@tanstack/react-router";
13
+
11
14
  import { Button } from "./ui/button";
12
15
  import { Skeleton } from "./ui/skeleton";
13
- import { Link } from "@tanstack/react-router";
14
16
 
15
17
  export default function UserMenu() {
16
18
  const navigate = useNavigate();
@@ -22,25 +24,24 @@ export default function UserMenu() {
22
24
 
23
25
  if (!session) {
24
26
  return (
25
- <Button variant="outline" asChild>
26
- <Link to="/login">Sign In</Link>
27
- </Button>
27
+ <Link to="/login">
28
+ <Button variant="outline">Sign In</Button>
29
+ </Link>
28
30
  );
29
31
  }
30
32
 
31
33
  return (
32
34
  <DropdownMenu>
33
- <DropdownMenuTrigger asChild>
34
- <Button variant="outline">{session.user.name}</Button>
35
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
36
+ {session.user.name}
35
37
  </DropdownMenuTrigger>
36
38
  <DropdownMenuContent className="bg-card">
37
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
38
- <DropdownMenuSeparator />
39
- <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
40
- <DropdownMenuItem asChild>
41
- <Button
39
+ <DropdownMenuGroup>
40
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
41
+ <DropdownMenuSeparator />
42
+ <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
43
+ <DropdownMenuItem
42
44
  variant="destructive"
43
- className="w-full"
44
45
  onClick={() => {
45
46
  authClient.signOut({
46
47
  fetchOptions: {
@@ -54,8 +55,8 @@ export default function UserMenu() {
54
55
  }}
55
56
  >
56
57
  Sign Out
57
- </Button>
58
- </DropdownMenuItem>
58
+ </DropdownMenuItem>
59
+ </DropdownMenuGroup>
59
60
  </DropdownMenuContent>
60
61
  </DropdownMenu>
61
62
  );
@@ -1,16 +1,18 @@
1
+ import { Link, useNavigate } from "@tanstack/react-router";
2
+
1
3
  import {
2
4
  DropdownMenu,
3
5
  DropdownMenuContent,
6
+ DropdownMenuGroup,
4
7
  DropdownMenuItem,
5
8
  DropdownMenuLabel,
6
9
  DropdownMenuSeparator,
7
10
  DropdownMenuTrigger,
8
11
  } from "@/components/ui/dropdown-menu";
9
12
  import { authClient } from "@/lib/auth-client";
10
- import { useNavigate } from "@tanstack/react-router";
13
+
11
14
  import { Button } from "./ui/button";
12
15
  import { Skeleton } from "./ui/skeleton";
13
- import { Link } from "@tanstack/react-router";
14
16
 
15
17
  export default function UserMenu() {
16
18
  const navigate = useNavigate();
@@ -22,25 +24,24 @@ export default function UserMenu() {
22
24
 
23
25
  if (!session) {
24
26
  return (
25
- <Button variant="outline" asChild>
26
- <Link to="/login">Sign In</Link>
27
- </Button>
27
+ <Link to="/login">
28
+ <Button variant="outline">Sign In</Button>
29
+ </Link>
28
30
  );
29
31
  }
30
32
 
31
33
  return (
32
34
  <DropdownMenu>
33
- <DropdownMenuTrigger asChild>
34
- <Button variant="outline">{session.user.name}</Button>
35
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
36
+ {session.user.name}
35
37
  </DropdownMenuTrigger>
36
38
  <DropdownMenuContent className="bg-card">
37
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
38
- <DropdownMenuSeparator />
39
- <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
40
- <DropdownMenuItem asChild>
41
- <Button
39
+ <DropdownMenuGroup>
40
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
41
+ <DropdownMenuSeparator />
42
+ <DropdownMenuItem>{session.user.email}</DropdownMenuItem>
43
+ <DropdownMenuItem
42
44
  variant="destructive"
43
- className="w-full"
44
45
  onClick={() => {
45
46
  authClient.signOut({
46
47
  fetchOptions: {
@@ -54,8 +55,8 @@ export default function UserMenu() {
54
55
  }}
55
56
  >
56
57
  Sign Out
57
- </Button>
58
- </DropdownMenuItem>
58
+ </DropdownMenuItem>
59
+ </DropdownMenuGroup>
59
60
  </DropdownMenuContent>
60
61
  </DropdownMenu>
61
62
  );
@@ -6,7 +6,7 @@ See https://docs.convex.dev/functions for more.
6
6
  A query function that takes two arguments looks like:
7
7
 
8
8
  ```ts
9
- // functions.js
9
+ // convex/myFunctions.ts
10
10
  import { query } from "./_generated/server";
11
11
  import { v } from "convex/values";
12
12
 
@@ -36,7 +36,7 @@ export const myQueryFunction = query({
36
36
  Using this query function in a React component looks like:
37
37
 
38
38
  ```ts
39
- const data = useQuery(api.functions.myQueryFunction, {
39
+ const data = useQuery(api.myFunctions.myQueryFunction, {
40
40
  first: 10,
41
41
  second: "hello",
42
42
  });
@@ -45,7 +45,7 @@ const data = useQuery(api.functions.myQueryFunction, {
45
45
  A mutation function looks like:
46
46
 
47
47
  ```ts
48
- // functions.js
48
+ // convex/myFunctions.ts
49
49
  import { mutation } from "./_generated/server";
50
50
  import { v } from "convex/values";
51
51
 
@@ -73,7 +73,7 @@ export const myMutationFunction = mutation({
73
73
  Using this mutation function in a React component looks like:
74
74
 
75
75
  ```ts
76
- const mutation = useMutation(api.functions.myMutationFunction);
76
+ const mutation = useMutation(api.myFunctions.myMutationFunction);
77
77
  function handleButtonPress() {
78
78
  // fire and forget, the most common way to use mutations
79
79
  mutation({ first: "Hello!", second: "me" });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  /* This TypeScript project config describes the environment that
3
3
  * Convex functions run in and is used to typecheck them.
4
- * You can modify it, but some settings required to use Convex.
4
+ * You can modify it, but some settings are required to use Convex.
5
5
  */
6
6
  "compilerOptions": {
7
7
  /* These settings are not required by Convex and can be modified. */
@@ -3,20 +3,21 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "scripts": {
6
- "dev": "next dev",
6
+ "dev": "next dev --port 3001",
7
7
  "build": "next build",
8
8
  "start": "next start"
9
9
  },
10
10
  "dependencies": {
11
- "radix-ui": "^1.4.2",
11
+ "@base-ui/react": "^1.0.0",
12
+ "shadcn": "^3.6.2",
12
13
  "@tanstack/react-form": "^1.27.3",
13
14
  "class-variance-authority": "^0.7.1",
14
15
  "clsx": "^2.1.1",
15
16
  "lucide-react": "^0.546.0",
16
- "next": "^16.0.10",
17
+ "next": "^16.1.0",
17
18
  "next-themes": "^0.4.6",
18
- "react": "19.2.3",
19
- "react-dom": "19.2.3",
19
+ "react": "^19.2.3",
20
+ "react-dom": "^19.2.3",
20
21
  "sonner": "^2.0.5",
21
22
  "tailwind-merge": "^3.3.1",
22
23
  "tw-animate-css": "^1.3.4",
@@ -25,8 +26,8 @@
25
26
  "devDependencies": {
26
27
  "@tailwindcss/postcss": "^4.1.10",
27
28
  "@types/node": "^20",
28
- "@types/react": "19.2.7",
29
- "@types/react-dom": "19.2.3",
29
+ "@types/react": "^19.2.7",
30
+ "@types/react-dom": "^19.2.3",
30
31
  "tailwindcss": "^4.1.10",
31
32
  "typescript": "^5"
32
33
  }
@@ -2,7 +2,10 @@ import type { Metadata } from "next";
2
2
  import { Geist, Geist_Mono } from "next/font/google";
3
3
  import "../index.css";
4
4
  {{#if (eq auth "clerk")}}{{#if (eq backend "convex")}}import { ClerkProvider } from "@clerk/nextjs";
5
- {{/if}}{{/if}}import Providers from "@/components/providers";
5
+ {{/if}}{{/if}}{{#if (and (eq backend "convex") (eq auth "better-auth"))}}
6
+ import { getToken } from "@/lib/auth-server";
7
+ {{/if}}
8
+ import Providers from "@/components/providers";
6
9
  import Header from "@/components/header";
7
10
 
8
11
  const geistSans = Geist({
@@ -20,6 +23,29 @@ export const metadata: Metadata = {
20
23
  description: "{{projectName}}",
21
24
  };
22
25
 
26
+ {{#if (and (eq backend "convex") (eq auth "better-auth"))}}
27
+ export default async function RootLayout({
28
+ children,
29
+ }: Readonly<{
30
+ children: React.ReactNode;
31
+ }>) {
32
+ const token = await getToken();
33
+ return (
34
+ <html lang="en" suppressHydrationWarning>
35
+ <body
36
+ className={`${geistSans.variable} ${geistMono.variable} antialiased`}
37
+ >
38
+ <Providers initialToken={token}>
39
+ <div className="grid grid-rows-[auto_1fr] h-svh">
40
+ <Header />
41
+ {children}
42
+ </div>
43
+ </Providers>
44
+ </body>
45
+ </html>
46
+ );
47
+ }
48
+ {{else}}
23
49
  export default function RootLayout({
24
50
  children,
25
51
  }: Readonly<{
@@ -47,3 +73,4 @@ export default function RootLayout({
47
73
  </html>
48
74
  );
49
75
  }
76
+ {{/if}}
@@ -16,12 +16,10 @@ export function ModeToggle() {
16
16
 
17
17
  return (
18
18
  <DropdownMenu>
19
- <DropdownMenuTrigger asChild>
20
- <Button variant="outline" size="icon">
21
- <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
22
- <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
23
- <span className="sr-only">Toggle theme</span>
24
- </Button>
19
+ <DropdownMenuTrigger render={<Button variant="outline" size="icon" />}>
20
+ <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
21
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
22
+ <span className="sr-only">Toggle theme</span>
25
23
  </DropdownMenuTrigger>
26
24
  <DropdownMenuContent align="end">
27
25
  <DropdownMenuItem onClick={() => setTheme("light")}>
@@ -6,7 +6,7 @@ import { useAuth } from "@clerk/nextjs";
6
6
  import { ConvexReactClient } from "convex/react";
7
7
  import { ConvexProviderWithClerk } from "convex/react-clerk";
8
8
  {{else if (eq auth "better-auth")}}
9
- import { ConvexProvider, ConvexReactClient } from "convex/react";
9
+ import { ConvexReactClient } from "convex/react";
10
10
  import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
11
11
  import { authClient } from "@/lib/auth-client";
12
12
  {{else}}
@@ -32,9 +32,15 @@ const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
32
32
  {{/if}}
33
33
 
34
34
  export default function Providers({
35
- children
35
+ children,
36
+ {{#if (and (eq backend "convex") (eq auth "better-auth"))}}
37
+ initialToken,
38
+ {{/if}}
36
39
  }: {
37
- children: React.ReactNode
40
+ children: React.ReactNode;
41
+ {{#if (and (eq backend "convex") (eq auth "better-auth"))}}
42
+ initialToken?: string | null;
43
+ {{/if}}
38
44
  }) {
39
45
  return (
40
46
  <ThemeProvider
@@ -49,7 +55,11 @@ export default function Providers({
49
55
  {children}
50
56
  </ConvexProviderWithClerk>
51
57
  {{else if (eq auth "better-auth")}}
52
- <ConvexBetterAuthProvider client={convex} authClient={authClient}>
58
+ <ConvexBetterAuthProvider
59
+ client={convex}
60
+ authClient={authClient}
61
+ initialToken={initialToken}
62
+ >
53
63
  {children}
54
64
  </ConvexBetterAuthProvider>
55
65
  {{else}}
@@ -9,7 +9,8 @@
9
9
  "typecheck": "react-router typegen && tsc"
10
10
  },
11
11
  "dependencies": {
12
- "radix-ui": "^1.4.2",
12
+ "@base-ui/react": "^1.0.0",
13
+ "shadcn": "^3.6.2",
13
14
  "@react-router/fs-routes": "^7.10.1",
14
15
  "@react-router/node": "^7.10.1",
15
16
  "@react-router/serve": "^7.10.1",
@@ -14,12 +14,10 @@ export function ModeToggle() {
14
14
 
15
15
  return (
16
16
  <DropdownMenu>
17
- <DropdownMenuTrigger asChild>
18
- <Button variant="outline" size="icon">
19
- <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
20
- <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
21
- <span className="sr-only">Toggle theme</span>
22
- </Button>
17
+ <DropdownMenuTrigger render={<Button variant="outline" size="icon" />}>
18
+ <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
19
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
20
+ <span className="sr-only">Toggle theme</span>
23
21
  </DropdownMenuTrigger>
24
22
  <DropdownMenuContent align="end">
25
23
  <DropdownMenuItem onClick={() => setTheme("light")}>Light</DropdownMenuItem>
@@ -12,7 +12,8 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@hookform/resolvers": "^5.1.1",
15
- "radix-ui": "^1.4.2",
15
+ "@base-ui/react": "^1.0.0",
16
+ "shadcn": "^3.6.2",
16
17
  "@tanstack/react-form": "^1.12.3",
17
18
  "@tailwindcss/vite": "^4.0.15",
18
19
  "@tanstack/react-router": "^1.141.1",
@@ -14,12 +14,10 @@ export function ModeToggle() {
14
14
 
15
15
  return (
16
16
  <DropdownMenu>
17
- <DropdownMenuTrigger asChild>
18
- <Button variant="outline" size="icon">
19
- <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
20
- <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
21
- <span className="sr-only">Toggle theme</span>
22
- </Button>
17
+ <DropdownMenuTrigger render={<Button variant="outline" size="icon" />}>
18
+ <Sun className="h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" />
19
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" />
20
+ <span className="sr-only">Toggle theme</span>
23
21
  </DropdownMenuTrigger>
24
22
  <DropdownMenuContent align="end">
25
23
  <DropdownMenuItem onClick={() => setTheme("light")}>Light</DropdownMenuItem>
@@ -8,7 +8,8 @@
8
8
  "dev": "vite dev"
9
9
  },
10
10
  "dependencies": {
11
- "radix-ui": "^1.4.2",
11
+ "@base-ui/react": "^1.0.0",
12
+ "shadcn": "^3.6.2",
12
13
  "@tanstack/react-form": "^1.23.5",
13
14
  "@tailwindcss/vite": "^4.1.8",
14
15
  "@tanstack/react-query": "^5.80.6",
@@ -35,7 +35,13 @@ export function getRouter() {
35
35
  unsavedChangesWarning: false,
36
36
  });
37
37
 
38
+ {{#if (eq auth "better-auth")}}
39
+ const convexQueryClient = new ConvexQueryClient(convex, {
40
+ expectAuth: true,
41
+ });
42
+ {{else}}
38
43
  const convexQueryClient = new ConvexQueryClient(convex);
44
+ {{/if}}
39
45
 
40
46
  const queryClient: QueryClient = new QueryClient({
41
47
  defaultOptions: {
@@ -37,20 +37,12 @@ const fetchClerkAuth = createServerFn({ method: "GET" }).handler(async () => {
37
37
  });
38
38
  {{else if (and (eq backend "convex") (eq auth "better-auth"))}}
39
39
  import { createServerFn } from "@tanstack/react-start";
40
- import { getRequest, getCookie } from "@tanstack/react-start/server";
41
40
  import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
42
- import { fetchSession, getCookieName } from "@convex-dev/better-auth/react-start";
43
41
  import { authClient } from "@/lib/auth-client";
44
- import { createAuth } from "@{{projectName}}/backend/convex/auth";
42
+ import { getToken } from "@/lib/auth-server";
45
43
 
46
- const fetchAuth = createServerFn({ method: "GET" }).handler(async () => {
47
- const { session } = await fetchSession(getRequest());
48
- const sessionCookieName = getCookieName(createAuth);
49
- const token = getCookie(sessionCookieName);
50
- return {
51
- userId: session?.user.id,
52
- token,
53
- };
44
+ const getAuth = createServerFn({ method: "GET" }).handler(async () => {
45
+ return await getToken();
54
46
  });
55
47
  {{/if}}
56
48
 
@@ -113,11 +105,14 @@ export const Route = createRootRouteWithContext<RouterAppContext>()({
113
105
  },
114
106
  {{else if (and (eq backend "convex") (eq auth "better-auth"))}}
115
107
  beforeLoad: async (ctx) => {
116
- const { userId, token } = await fetchAuth();
108
+ const token = await getAuth();
117
109
  if (token) {
118
110
  ctx.context.convexQueryClient.serverHttpClient?.setAuth(token);
119
111
  }
120
- return { userId, token };
112
+ return {
113
+ isAuthenticated: !!token,
114
+ token,
115
+ };
121
116
  },
122
117
  {{/if}}
123
118
  });
@@ -148,7 +143,11 @@ function RootDocument() {
148
143
  {{else if (and (eq backend "convex") (eq auth "better-auth"))}}
149
144
  const context = useRouteContext({ from: Route.id });
150
145
  return (
151
- <ConvexBetterAuthProvider client={context.convexClient} authClient={authClient}>
146
+ <ConvexBetterAuthProvider
147
+ client={context.convexClient}
148
+ authClient={authClient}
149
+ initialToken={context.token}
150
+ >
152
151
  <html lang="en" className="dark">
153
152
  <head>
154
153
  <HeadContent />
@@ -14,4 +14,9 @@ export default defineConfig({
14
14
  server: {
15
15
  port: 3001,
16
16
  },
17
+ {{#if (and (eq backend "convex") (eq auth "better-auth"))}}
18
+ ssr: {
19
+ noExternal: ["@convex-dev/better-auth"],
20
+ },
21
+ {{/if}}
17
22
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://ui.shadcn.com/schema.json",
3
- "style": "new-york",
3
+ "style": "base-lyra",
4
4
  "rsc": false,
5
5
  "tsx": true,
6
6
  "tailwind": {
@@ -10,6 +10,7 @@
10
10
  "cssVariables": true,
11
11
  "prefix": ""
12
12
  },
13
+ "iconLibrary": "lucide",
13
14
  "aliases": {
14
15
  "components": "@/components",
15
16
  "utils": "@/lib/utils",
@@ -17,5 +18,7 @@
17
18
  "lib": "@/lib",
18
19
  "hooks": "@/hooks"
19
20
  },
20
- "iconLibrary": "lucide"
21
+ "menuColor": "default",
22
+ "menuAccent": "subtle",
23
+ "registries": {}
21
24
  }