better-ts-stack 1.1.4 → 2.0.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 (161) hide show
  1. package/README.md +113 -82
  2. package/dist/args.d.ts +12 -0
  3. package/dist/args.d.ts.map +1 -0
  4. package/dist/args.js +90 -0
  5. package/dist/args.js.map +1 -0
  6. package/dist/builder/configGenerator.d.ts.map +1 -1
  7. package/dist/builder/configGenerator.js +10 -3
  8. package/dist/builder/configGenerator.js.map +1 -1
  9. package/dist/builder/dependencyInstaller.d.ts.map +1 -1
  10. package/dist/builder/dependencyInstaller.js +8 -14
  11. package/dist/builder/dependencyInstaller.js.map +1 -1
  12. package/dist/builder/gitInitializer.d.ts.map +1 -1
  13. package/dist/builder/gitInitializer.js +8 -41
  14. package/dist/builder/gitInitializer.js.map +1 -1
  15. package/dist/builder/index.d.ts.map +1 -1
  16. package/dist/builder/index.js +24 -63
  17. package/dist/builder/index.js.map +1 -1
  18. package/dist/builder/moduleSelector.d.ts +1 -4
  19. package/dist/builder/moduleSelector.d.ts.map +1 -1
  20. package/dist/builder/moduleSelector.js +11 -15
  21. package/dist/builder/moduleSelector.js.map +1 -1
  22. package/dist/builder/templateContext.d.ts +2 -17
  23. package/dist/builder/templateContext.d.ts.map +1 -1
  24. package/dist/builder/templateContext.js +6 -5
  25. package/dist/builder/templateContext.js.map +1 -1
  26. package/dist/index.js +45 -20
  27. package/dist/index.js.map +1 -1
  28. package/dist/output/nextSteps.d.ts +1 -2
  29. package/dist/output/nextSteps.d.ts.map +1 -1
  30. package/dist/output/nextSteps.js +10 -19
  31. package/dist/output/nextSteps.js.map +1 -1
  32. package/dist/prompts/index.d.ts +3 -3
  33. package/dist/prompts/index.d.ts.map +1 -1
  34. package/dist/prompts/index.js +22 -58
  35. package/dist/prompts/index.js.map +1 -1
  36. package/dist/prompts/stack.d.ts +3 -2
  37. package/dist/prompts/stack.d.ts.map +1 -1
  38. package/dist/prompts/stack.js +81 -70
  39. package/dist/prompts/stack.js.map +1 -1
  40. package/dist/types/index.d.ts +20 -42
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/types/index.js +40 -38
  43. package/dist/types/index.js.map +1 -1
  44. package/dist/ui/index.d.ts +3 -0
  45. package/dist/ui/index.d.ts.map +1 -0
  46. package/dist/ui/index.js +19 -0
  47. package/dist/ui/index.js.map +1 -0
  48. package/dist/ui/messages.d.ts +9 -0
  49. package/dist/ui/messages.d.ts.map +1 -0
  50. package/dist/ui/messages.js +100 -0
  51. package/dist/ui/messages.js.map +1 -0
  52. package/dist/ui/prompts.d.ts +20 -0
  53. package/dist/ui/prompts.d.ts.map +1 -0
  54. package/dist/ui/prompts.js +71 -0
  55. package/dist/ui/prompts.js.map +1 -0
  56. package/dist/ui/theme.d.ts +9 -0
  57. package/dist/ui/theme.d.ts.map +1 -0
  58. package/dist/ui/theme.js +24 -0
  59. package/dist/ui/theme.js.map +1 -0
  60. package/dist/validators/index.d.ts +1 -0
  61. package/dist/validators/index.d.ts.map +1 -1
  62. package/dist/validators/index.js +6 -0
  63. package/dist/validators/index.js.map +1 -1
  64. package/package.json +70 -66
  65. package/templates/backend/express/config.json +44 -44
  66. package/templates/backend/express/eslint.config.mjs +40 -40
  67. package/templates/backend/express/gitignore +36 -36
  68. package/templates/backend/express/src/index.ts +76 -76
  69. package/templates/backend/express/src/routes/health.ts +12 -12
  70. package/templates/backend/express/tsconfig.json +25 -25
  71. package/templates/backend/nestjs/.prettierignore +52 -0
  72. package/templates/backend/nestjs/.prettierrc +16 -0
  73. package/templates/backend/nestjs/config.json +44 -0
  74. package/templates/backend/nestjs/eslint.config.mjs +40 -0
  75. package/templates/backend/nestjs/gitignore +36 -0
  76. package/templates/backend/nestjs/nest-cli.json +9 -0
  77. package/templates/backend/nestjs/src/app.module.ts.hbs +34 -0
  78. package/templates/backend/nestjs/src/health/health.controller.ts +12 -0
  79. package/templates/backend/nestjs/src/main.ts +23 -0
  80. package/templates/backend/nestjs/tsconfig.eslint.json +9 -0
  81. package/templates/backend/nestjs/tsconfig.json +25 -0
  82. package/templates/frontend/nextjs/app/layout.tsx +13 -13
  83. package/templates/frontend/nextjs/app/page.tsx.hbs +97 -97
  84. package/templates/frontend/nextjs/components/ui/button.tsx +51 -51
  85. package/templates/frontend/nextjs/components/ui/card.tsx +60 -60
  86. package/templates/frontend/nextjs/components/ui/field.tsx +67 -67
  87. package/templates/frontend/nextjs/components/ui/input.tsx +18 -18
  88. package/templates/frontend/nextjs/components.json +19 -19
  89. package/templates/frontend/nextjs/config.json +38 -38
  90. package/templates/frontend/nextjs/eslint.config.mjs +11 -11
  91. package/templates/frontend/nextjs/gitignore +42 -42
  92. package/templates/frontend/nextjs/lib/utils.ts +6 -6
  93. package/templates/frontend/nextjs/next.config.ts.hbs +12 -12
  94. package/templates/frontend/nextjs/proxy.ts.hbs +24 -24
  95. package/templates/frontend/nextjs/tsconfig.json +34 -34
  96. package/templates/frontend/tanstack/config.json +48 -48
  97. package/templates/frontend/tanstack/src/routeTree.gen.ts +68 -68
  98. package/templates/frontend/tanstack/src/styles/app.css +85 -85
  99. package/templates/modules/auth/express/config.json +27 -26
  100. package/templates/modules/auth/express/src/controllers/authController.ts.hbs +116 -130
  101. package/templates/modules/auth/express/src/middleware/requireAuth.ts.hbs +26 -26
  102. package/templates/modules/auth/express/src/services/userStore.ts.hbs +117 -117
  103. package/templates/modules/auth/nestjs/config.json +24 -0
  104. package/templates/modules/auth/nestjs/src/auth/auth.controller.ts +46 -0
  105. package/templates/modules/auth/nestjs/src/auth/auth.guard.ts +36 -0
  106. package/templates/modules/auth/nestjs/src/auth/auth.module.ts.hbs +22 -0
  107. package/templates/modules/auth/nestjs/src/auth/auth.schemas.ts +35 -0
  108. package/templates/modules/auth/nestjs/src/auth/auth.service.ts +70 -0
  109. package/templates/modules/auth/nestjs/src/auth/jwt.ts +27 -0
  110. package/templates/modules/auth/nestjs/src/auth/users.service.ts.hbs +144 -0
  111. package/templates/modules/auth/nestjs/src/auth/zod-validation.pipe.ts +16 -0
  112. package/templates/modules/auth/nextjs/app/dashboard/page.tsx +96 -96
  113. package/templates/modules/auth/nextjs/app/sign-in/page.tsx +35 -35
  114. package/templates/modules/auth/nextjs/app/sign-up/page.tsx +35 -35
  115. package/templates/modules/auth/nextjs/components/auth/sign-in-form.tsx +132 -132
  116. package/templates/modules/auth/nextjs/components/auth/sign-out-button.tsx +50 -50
  117. package/templates/modules/auth/nextjs/components/auth/sign-up-form.tsx +152 -152
  118. package/templates/modules/auth/nextjs/config.json +31 -31
  119. package/templates/modules/auth/nextjs/lib/auth-schema.ts +39 -39
  120. package/templates/modules/auth/nextjs/lib/auth.ts.hbs +37 -37
  121. package/templates/modules/auth/tanstack/src/lib/auth-functions.ts +4 -4
  122. package/templates/modules/auth/tanstack/src/routeTree.gen.ts +140 -140
  123. package/templates/modules/docker/.dockerignore +14 -14
  124. package/templates/modules/docker/Dockerfile.hbs +137 -133
  125. package/templates/modules/docker/config.json +19 -19
  126. package/templates/modules/docker/docker-compose.yml.hbs +9 -9
  127. package/templates/modules/drizzle/express/config.json +27 -27
  128. package/templates/modules/drizzle/express/drizzle.config.ts +13 -13
  129. package/templates/modules/drizzle/express/src/lib/db.ts +13 -13
  130. package/templates/modules/drizzle/express/src/lib/schema.ts +10 -10
  131. package/templates/modules/drizzle/nestjs/config.json +27 -0
  132. package/templates/modules/drizzle/nestjs/drizzle.config.ts +13 -0
  133. package/templates/modules/drizzle/nestjs/src/database/database.module.ts +30 -0
  134. package/templates/modules/drizzle/nestjs/src/database/schema.ts +10 -0
  135. package/templates/modules/drizzle/nextjs/config.json +29 -29
  136. package/templates/modules/drizzle/nextjs/lib/db.ts +13 -13
  137. package/templates/modules/drizzle/nextjs/lib/schema.ts.hbs +84 -84
  138. package/templates/modules/mongoose/express/config.json +16 -16
  139. package/templates/modules/mongoose/nestjs/config.json +16 -0
  140. package/templates/modules/mongoose/nestjs/src/users/user.schema.ts +21 -0
  141. package/templates/modules/mongoose/nextjs/config.json +16 -16
  142. package/templates/modules/mongoose/nextjs/lib/db.ts +36 -36
  143. package/templates/modules/mongoose/tanstack/config.json +17 -17
  144. package/templates/modules/mongoose/tanstack/src/lib/db.ts +37 -37
  145. package/templates/modules/prisma/express/config.json +28 -28
  146. package/templates/modules/prisma/express/prisma/schema.prisma +1 -1
  147. package/templates/modules/prisma/express/prisma.config.ts +12 -12
  148. package/templates/modules/prisma/express/src/lib/prisma.ts +24 -24
  149. package/templates/modules/prisma/nestjs/config.json +28 -0
  150. package/templates/modules/prisma/nestjs/prisma/schema.prisma +23 -0
  151. package/templates/modules/prisma/nestjs/prisma.config.ts +12 -0
  152. package/templates/modules/prisma/nestjs/src/prisma/prisma.module.ts +11 -0
  153. package/templates/modules/prisma/nestjs/src/prisma/prisma.service.ts +17 -0
  154. package/templates/modules/prisma/nextjs/config.json +29 -29
  155. package/templates/modules/prisma/nextjs/prisma/schema.prisma.hbs +91 -91
  156. package/templates/modules/prisma/tanstack/config.json +5 -5
  157. package/dist/intro.d.ts +0 -2
  158. package/dist/intro.d.ts.map +0 -1
  159. package/dist/intro.js +0 -27
  160. package/dist/intro.js.map +0 -1
  161. package/templates/backend/express/.eslintrc.js +0 -24
@@ -1,50 +1,50 @@
1
- "use client";
2
-
3
- import { useRouter } from "next/navigation";
4
- import { useState, useTransition } from "react";
5
- import { LoaderCircle, LogOut } from "lucide-react";
6
-
7
- import { authClient } from "@/lib/auth-client";
8
- import { Button } from "@/components/ui/button";
9
-
10
- export function SignOutButton() {
11
- const router = useRouter();
12
- const [isPending, startTransition] = useTransition();
13
- const [error, setError] = useState<string | null>(null);
14
-
15
- return (
16
- <div className="space-y-2">
17
- <Button
18
- variant="outline"
19
- onClick={() => {
20
- setError(null);
21
- startTransition(async () => {
22
- const result = await authClient.signOut();
23
-
24
- if (result.error) {
25
- setError("Unable to sign out right now. Please try again.");
26
- return;
27
- }
28
-
29
- router.push("/sign-in");
30
- router.refresh();
31
- });
32
- }}
33
- disabled={isPending}
34
- >
35
- {isPending ? (
36
- <>
37
- <LoaderCircle className="mr-2 size-4 animate-spin" />
38
- Signing out
39
- </>
40
- ) : (
41
- <>
42
- <LogOut className="mr-2 size-4" />
43
- Sign out
44
- </>
45
- )}
46
- </Button>
47
- {error ? <p className="text-sm text-rose-600">{error}</p> : null}
48
- </div>
49
- );
50
- }
1
+ "use client";
2
+
3
+ import { useRouter } from "next/navigation";
4
+ import { useState, useTransition } from "react";
5
+ import { LoaderCircle, LogOut } from "lucide-react";
6
+
7
+ import { authClient } from "@/lib/auth-client";
8
+ import { Button } from "@/components/ui/button";
9
+
10
+ export function SignOutButton() {
11
+ const router = useRouter();
12
+ const [isPending, startTransition] = useTransition();
13
+ const [error, setError] = useState<string | null>(null);
14
+
15
+ return (
16
+ <div className="space-y-2">
17
+ <Button
18
+ variant="outline"
19
+ onClick={() => {
20
+ setError(null);
21
+ startTransition(async () => {
22
+ const result = await authClient.signOut();
23
+
24
+ if (result.error) {
25
+ setError("Unable to sign out right now. Please try again.");
26
+ return;
27
+ }
28
+
29
+ router.push("/sign-in");
30
+ router.refresh();
31
+ });
32
+ }}
33
+ disabled={isPending}
34
+ >
35
+ {isPending ? (
36
+ <>
37
+ <LoaderCircle className="mr-2 size-4 animate-spin" />
38
+ Signing out
39
+ </>
40
+ ) : (
41
+ <>
42
+ <LogOut className="mr-2 size-4" />
43
+ Sign out
44
+ </>
45
+ )}
46
+ </Button>
47
+ {error ? <p className="text-sm text-rose-600">{error}</p> : null}
48
+ </div>
49
+ );
50
+ }
@@ -1,152 +1,152 @@
1
- "use client";
2
-
3
- import Link from "next/link";
4
- import { useRouter } from "next/navigation";
5
- import { useState, useTransition } from "react";
6
- import { zodResolver } from "@hookform/resolvers/zod";
7
- import { LoaderCircle } from "lucide-react";
8
- import { useForm } from "react-hook-form";
9
-
10
- import { authClient } from "@/lib/auth-client";
11
- import {
12
- getAuthErrorMessage,
13
- signUpSchema,
14
- type SignUpValues,
15
- } from "@/lib/auth-schema";
16
- import { Button } from "@/components/ui/button";
17
- import {
18
- Card,
19
- CardContent,
20
- CardDescription,
21
- CardFooter,
22
- CardHeader,
23
- CardTitle,
24
- } from "@/components/ui/card";
25
- import {
26
- Field,
27
- FieldDescription,
28
- FieldError,
29
- FieldGroup,
30
- FieldLabel,
31
- } from "@/components/ui/field";
32
- import { Input } from "@/components/ui/input";
33
-
34
- export function SignUpForm() {
35
- const router = useRouter();
36
- const [isPending, startTransition] = useTransition();
37
- const [authError, setAuthError] = useState<string | null>(null);
38
- const form = useForm<SignUpValues>({
39
- resolver: zodResolver(signUpSchema),
40
- defaultValues: {
41
- name: "",
42
- email: "",
43
- password: "",
44
- },
45
- });
46
-
47
- const onSubmit = form.handleSubmit((values) => {
48
- setAuthError(null);
49
-
50
- startTransition(async () => {
51
- const result = await authClient.signUp.email({
52
- name: values.name,
53
- email: values.email,
54
- password: values.password,
55
- });
56
-
57
- if (result.error) {
58
- setAuthError(getAuthErrorMessage(result.error));
59
- return;
60
- }
61
-
62
- router.push("/dashboard");
63
- router.refresh();
64
- });
65
- });
66
-
67
- return (
68
- <Card className="border-white/80 bg-white/90 shadow-2xl shadow-slate-200/70 backdrop-blur">
69
- <CardHeader className="space-y-2">
70
- <CardTitle>Create your account</CardTitle>
71
- <CardDescription>
72
- Start with a simple email and password sign-up flow powered by Better
73
- Auth.
74
- </CardDescription>
75
- </CardHeader>
76
- <CardContent>
77
- <form className="space-y-6" onSubmit={onSubmit} noValidate>
78
- <FieldGroup>
79
- <Field data-invalid={Boolean(form.formState.errors.name)}>
80
- <FieldLabel htmlFor="name">Full name</FieldLabel>
81
- <Input
82
- id="name"
83
- autoComplete="name"
84
- aria-invalid={Boolean(form.formState.errors.name)}
85
- placeholder="Ada Lovelace"
86
- {...form.register("name")}
87
- />
88
- <FieldError errors={[form.formState.errors.name]} />
89
- </Field>
90
-
91
- <Field data-invalid={Boolean(form.formState.errors.email)}>
92
- <FieldLabel htmlFor="email">Email</FieldLabel>
93
- <Input
94
- id="email"
95
- type="email"
96
- autoComplete="email"
97
- aria-invalid={Boolean(form.formState.errors.email)}
98
- placeholder="you@example.com"
99
- {...form.register("email")}
100
- />
101
- <FieldDescription>
102
- This email will be used for future sign-ins.
103
- </FieldDescription>
104
- <FieldError errors={[form.formState.errors.email]} />
105
- </Field>
106
-
107
- <Field data-invalid={Boolean(form.formState.errors.password)}>
108
- <FieldLabel htmlFor="password">Password</FieldLabel>
109
- <Input
110
- id="password"
111
- type="password"
112
- autoComplete="new-password"
113
- aria-invalid={Boolean(form.formState.errors.password)}
114
- placeholder="Create a strong password"
115
- {...form.register("password")}
116
- />
117
- <FieldDescription>
118
- Use at least 8 characters for the generated starter flow.
119
- </FieldDescription>
120
- <FieldError errors={[form.formState.errors.password]} />
121
- </Field>
122
- </FieldGroup>
123
-
124
- {authError ? (
125
- <div className="rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
126
- {authError}
127
- </div>
128
- ) : null}
129
-
130
- <Button className="w-full" type="submit" disabled={isPending}>
131
- {isPending ? (
132
- <>
133
- <LoaderCircle className="mr-2 size-4 animate-spin" />
134
- Creating account
135
- </>
136
- ) : (
137
- "Signup"
138
- )}
139
- </Button>
140
- </form>
141
- </CardContent>
142
- <CardFooter className="justify-center">
143
- <p className="text-sm text-slate-600">
144
- Already have an account?{" "}
145
- <Link className="font-medium text-sky-700 hover:text-sky-800" href="/sign-in">
146
- Login
147
- </Link>
148
- </p>
149
- </CardFooter>
150
- </Card>
151
- );
152
- }
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { useRouter } from "next/navigation";
5
+ import { useState, useTransition } from "react";
6
+ import { zodResolver } from "@hookform/resolvers/zod";
7
+ import { LoaderCircle } from "lucide-react";
8
+ import { useForm } from "react-hook-form";
9
+
10
+ import { authClient } from "@/lib/auth-client";
11
+ import {
12
+ getAuthErrorMessage,
13
+ signUpSchema,
14
+ type SignUpValues,
15
+ } from "@/lib/auth-schema";
16
+ import { Button } from "@/components/ui/button";
17
+ import {
18
+ Card,
19
+ CardContent,
20
+ CardDescription,
21
+ CardFooter,
22
+ CardHeader,
23
+ CardTitle,
24
+ } from "@/components/ui/card";
25
+ import {
26
+ Field,
27
+ FieldDescription,
28
+ FieldError,
29
+ FieldGroup,
30
+ FieldLabel,
31
+ } from "@/components/ui/field";
32
+ import { Input } from "@/components/ui/input";
33
+
34
+ export function SignUpForm() {
35
+ const router = useRouter();
36
+ const [isPending, startTransition] = useTransition();
37
+ const [authError, setAuthError] = useState<string | null>(null);
38
+ const form = useForm<SignUpValues>({
39
+ resolver: zodResolver(signUpSchema),
40
+ defaultValues: {
41
+ name: "",
42
+ email: "",
43
+ password: "",
44
+ },
45
+ });
46
+
47
+ const onSubmit = form.handleSubmit((values) => {
48
+ setAuthError(null);
49
+
50
+ startTransition(async () => {
51
+ const result = await authClient.signUp.email({
52
+ name: values.name,
53
+ email: values.email,
54
+ password: values.password,
55
+ });
56
+
57
+ if (result.error) {
58
+ setAuthError(getAuthErrorMessage(result.error));
59
+ return;
60
+ }
61
+
62
+ router.push("/dashboard");
63
+ router.refresh();
64
+ });
65
+ });
66
+
67
+ return (
68
+ <Card className="border-white/80 bg-white/90 shadow-2xl shadow-slate-200/70 backdrop-blur">
69
+ <CardHeader className="space-y-2">
70
+ <CardTitle>Create your account</CardTitle>
71
+ <CardDescription>
72
+ Start with a simple email and password sign-up flow powered by Better
73
+ Auth.
74
+ </CardDescription>
75
+ </CardHeader>
76
+ <CardContent>
77
+ <form className="space-y-6" onSubmit={onSubmit} noValidate>
78
+ <FieldGroup>
79
+ <Field data-invalid={Boolean(form.formState.errors.name)}>
80
+ <FieldLabel htmlFor="name">Full name</FieldLabel>
81
+ <Input
82
+ id="name"
83
+ autoComplete="name"
84
+ aria-invalid={Boolean(form.formState.errors.name)}
85
+ placeholder="Ada Lovelace"
86
+ {...form.register("name")}
87
+ />
88
+ <FieldError errors={[form.formState.errors.name]} />
89
+ </Field>
90
+
91
+ <Field data-invalid={Boolean(form.formState.errors.email)}>
92
+ <FieldLabel htmlFor="email">Email</FieldLabel>
93
+ <Input
94
+ id="email"
95
+ type="email"
96
+ autoComplete="email"
97
+ aria-invalid={Boolean(form.formState.errors.email)}
98
+ placeholder="you@example.com"
99
+ {...form.register("email")}
100
+ />
101
+ <FieldDescription>
102
+ This email will be used for future sign-ins.
103
+ </FieldDescription>
104
+ <FieldError errors={[form.formState.errors.email]} />
105
+ </Field>
106
+
107
+ <Field data-invalid={Boolean(form.formState.errors.password)}>
108
+ <FieldLabel htmlFor="password">Password</FieldLabel>
109
+ <Input
110
+ id="password"
111
+ type="password"
112
+ autoComplete="new-password"
113
+ aria-invalid={Boolean(form.formState.errors.password)}
114
+ placeholder="Create a strong password"
115
+ {...form.register("password")}
116
+ />
117
+ <FieldDescription>
118
+ Use at least 8 characters for the generated starter flow.
119
+ </FieldDescription>
120
+ <FieldError errors={[form.formState.errors.password]} />
121
+ </Field>
122
+ </FieldGroup>
123
+
124
+ {authError ? (
125
+ <div className="rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-700">
126
+ {authError}
127
+ </div>
128
+ ) : null}
129
+
130
+ <Button className="w-full" type="submit" disabled={isPending}>
131
+ {isPending ? (
132
+ <>
133
+ <LoaderCircle className="mr-2 size-4 animate-spin" />
134
+ Creating account
135
+ </>
136
+ ) : (
137
+ "Signup"
138
+ )}
139
+ </Button>
140
+ </form>
141
+ </CardContent>
142
+ <CardFooter className="justify-center">
143
+ <p className="text-sm text-slate-600">
144
+ Already have an account?{" "}
145
+ <Link className="font-medium text-sky-700 hover:text-sky-800" href="/sign-in">
146
+ Login
147
+ </Link>
148
+ </p>
149
+ </CardFooter>
150
+ </Card>
151
+ );
152
+ }
@@ -1,31 +1,31 @@
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.1",
8
- "better-auth": "^1.7.3",
9
- "mongodb": "^7.6.0",
10
- "react-hook-form": "^7.87.0",
11
- "zod": "^4.5.4"
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
- "templateFiles": [
20
- "lib/auth.ts.hbs",
21
- "lib/auth-client.ts",
22
- "app/api/auth/[...all]/route.ts",
23
- "app/dashboard/page.tsx",
24
- "app/sign-in/page.tsx",
25
- "app/sign-up/page.tsx",
26
- "components/auth/sign-in-form.tsx",
27
- "components/auth/sign-up-form.tsx",
28
- "components/auth/sign-out-button.tsx",
29
- "lib/auth-schema.ts"
30
- ]
31
- }
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.1",
8
+ "better-auth": "^1.7.3",
9
+ "mongodb": "^7.6.0",
10
+ "react-hook-form": "^7.87.0",
11
+ "zod": "^4.5.4"
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
+ "templateFiles": [
20
+ "lib/auth.ts.hbs",
21
+ "lib/auth-client.ts",
22
+ "app/api/auth/[...all]/route.ts",
23
+ "app/dashboard/page.tsx",
24
+ "app/sign-in/page.tsx",
25
+ "app/sign-up/page.tsx",
26
+ "components/auth/sign-in-form.tsx",
27
+ "components/auth/sign-up-form.tsx",
28
+ "components/auth/sign-out-button.tsx",
29
+ "lib/auth-schema.ts"
30
+ ]
31
+ }
@@ -1,39 +1,39 @@
1
- import { z } from "zod";
2
-
3
- export const signInSchema = z.object({
4
- email: z.string().email("Enter a valid email address."),
5
- password: z.string().min(8, "Password must be at least 8 characters."),
6
- });
7
-
8
- export const signUpSchema = signInSchema.extend({
9
- name: z
10
- .string()
11
- .trim()
12
- .min(2, "Name must be at least 2 characters.")
13
- .max(50, "Name must be 50 characters or fewer."),
14
- });
15
-
16
- export type SignInValues = z.infer<typeof signInSchema>;
17
- export type SignUpValues = z.infer<typeof signUpSchema>;
18
-
19
- export function getAuthErrorMessage(error: unknown) {
20
- if (!error) {
21
- return "Something went wrong. Please try again.";
22
- }
23
-
24
- if (typeof error === "string") {
25
- return error;
26
- }
27
-
28
- if (typeof error === "object") {
29
- if ("message" in error && typeof error.message === "string") {
30
- return error.message;
31
- }
32
-
33
- if ("statusText" in error && typeof error.statusText === "string") {
34
- return error.statusText;
35
- }
36
- }
37
-
38
- return "Something went wrong. Please try again.";
39
- }
1
+ import { z } from "zod";
2
+
3
+ export const signInSchema = z.object({
4
+ email: z.string().email("Enter a valid email address."),
5
+ password: z.string().min(8, "Password must be at least 8 characters."),
6
+ });
7
+
8
+ export const signUpSchema = signInSchema.extend({
9
+ name: z
10
+ .string()
11
+ .trim()
12
+ .min(2, "Name must be at least 2 characters.")
13
+ .max(50, "Name must be 50 characters or fewer."),
14
+ });
15
+
16
+ export type SignInValues = z.infer<typeof signInSchema>;
17
+ export type SignUpValues = z.infer<typeof signUpSchema>;
18
+
19
+ export function getAuthErrorMessage(error: unknown) {
20
+ if (!error) {
21
+ return "Something went wrong. Please try again.";
22
+ }
23
+
24
+ if (typeof error === "string") {
25
+ return error;
26
+ }
27
+
28
+ if (typeof error === "object") {
29
+ if ("message" in error && typeof error.message === "string") {
30
+ return error.message;
31
+ }
32
+
33
+ if ("statusText" in error && typeof error.statusText === "string") {
34
+ return error.statusText;
35
+ }
36
+ }
37
+
38
+ return "Something went wrong. Please try again.";
39
+ }
@@ -1,37 +1,37 @@
1
- import { betterAuth } from "better-auth";
2
- import { nextCookies } from "better-auth/next-js";
3
- {{#if (eq database 'prisma')}}
4
- import { prismaAdapter } from "better-auth/adapters/prisma";
5
- import client from "./prisma";
6
- {{/if}}
7
- {{#if (eq database 'drizzle')}}
8
- import { drizzleAdapter } from "better-auth/adapters/drizzle";
9
- import { db } from "./db";
10
- {{/if}}
11
- {{#if (eq database 'mongoose')}}
12
- import { mongodbAdapter } from "better-auth/adapters/mongodb";
13
- import { MongoClient } from "mongodb";
14
-
15
- const client = new MongoClient(process.env.MONGODB_URI!);
16
- const db = client.db();
17
- {{/if}}
18
-
19
- export const auth = betterAuth({
20
- {{#if (eq database 'prisma')}}
21
- database: prismaAdapter(client, { provider: "postgresql" }),
22
- {{/if}}
23
- {{#if (eq database 'drizzle')}}
24
- database: drizzleAdapter(db, { provider: "pg" }),
25
- {{/if}}
26
- {{#if (eq database 'mongoose')}}
27
- // Transactions require a replica set. Create user/session/account/verification
28
- // collections before the first sign-up; see the database setup documentation.
29
- database: mongodbAdapter(db, { client }),
30
- {{/if}}
31
- emailAndPassword: {
32
- enabled: true,
33
- },
34
- plugins: [nextCookies()],
35
- secret: process.env.BETTER_AUTH_SECRET,
36
- baseURL: process.env.BETTER_AUTH_URL,
37
- });
1
+ import { betterAuth } from "better-auth";
2
+ import { nextCookies } from "better-auth/next-js";
3
+ {{#if (eq database 'prisma')}}
4
+ import { prismaAdapter } from "better-auth/adapters/prisma";
5
+ import client from "./prisma";
6
+ {{/if}}
7
+ {{#if (eq database 'drizzle')}}
8
+ import { drizzleAdapter } from "better-auth/adapters/drizzle";
9
+ import { db } from "./db";
10
+ {{/if}}
11
+ {{#if (eq database 'mongoose')}}
12
+ import { mongodbAdapter } from "better-auth/adapters/mongodb";
13
+ import { MongoClient } from "mongodb";
14
+
15
+ const client = new MongoClient(process.env.MONGODB_URI!);
16
+ const db = client.db();
17
+ {{/if}}
18
+
19
+ export const auth = betterAuth({
20
+ {{#if (eq database 'prisma')}}
21
+ database: prismaAdapter(client, { provider: "postgresql" }),
22
+ {{/if}}
23
+ {{#if (eq database 'drizzle')}}
24
+ database: drizzleAdapter(db, { provider: "pg" }),
25
+ {{/if}}
26
+ {{#if (eq database 'mongoose')}}
27
+ // Transactions require a replica set. Create user/session/account/verification
28
+ // collections before the first sign-up; see the database setup documentation.
29
+ database: mongodbAdapter(db, { client }),
30
+ {{/if}}
31
+ emailAndPassword: {
32
+ enabled: true,
33
+ },
34
+ plugins: [nextCookies()],
35
+ secret: process.env.BETTER_AUTH_SECRET,
36
+ baseURL: process.env.BETTER_AUTH_URL,
37
+ });
@@ -4,9 +4,9 @@ import { getRequestHeaders } from "@tanstack/react-start/server";
4
4
  import { auth } from "./auth";
5
5
 
6
6
  export const getSession = createServerFn({ method: "GET" }).handler(async () => {
7
- const session = await auth.api.getSession({
8
- headers: getRequestHeaders(),
9
- });
7
+ const session = await auth.api.getSession({
8
+ headers: getRequestHeaders(),
9
+ });
10
10
 
11
11
  return session;
12
- });
12
+ });