authverse 1.0.4

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 (34) hide show
  1. package/README.md +90 -0
  2. package/dist/index.cjs +827 -0
  3. package/dist/index.d.cts +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +799 -0
  6. package/dist/template/api/route.ts +4 -0
  7. package/dist/template/app-auth-uiDesign/forget/page.tsx +7 -0
  8. package/dist/template/app-auth-uiDesign/layout.tsx +9 -0
  9. package/dist/template/app-auth-uiDesign/login/page.tsx +7 -0
  10. package/dist/template/app-auth-uiDesign/reset-password/page.tsx +7 -0
  11. package/dist/template/app-auth-uiDesign/signup/page.tsx +7 -0
  12. package/dist/template/components/ForgetComponent.tsx +121 -0
  13. package/dist/template/components/GithubProviders.tsx +21 -0
  14. package/dist/template/components/GoogleProviders.tsx +21 -0
  15. package/dist/template/components/LoginComponent.tsx +145 -0
  16. package/dist/template/components/Logout.tsx +21 -0
  17. package/dist/template/components/ResetComponent.tsx +150 -0
  18. package/dist/template/components/SingUpComponent.tsx +173 -0
  19. package/dist/template/config/drizzle.config.ts +13 -0
  20. package/dist/template/config/prisma.config.ts +12 -0
  21. package/dist/template/db/drizzle.ts +6 -0
  22. package/dist/template/db/schema.ts +68 -0
  23. package/dist/template/email/reset-password.tsx +132 -0
  24. package/dist/template/lib/Mongodb/auth.ts +20 -0
  25. package/dist/template/lib/Mysql/auth.ts +27 -0
  26. package/dist/template/lib/Postgresql/auth.ts +20 -0
  27. package/dist/template/lib/auth-client.ts +5 -0
  28. package/dist/template/lib/auth-drizzle.ts +16 -0
  29. package/dist/template/prisma/mongodb/schema.prisma +70 -0
  30. package/dist/template/prisma/mysql/schema.prisma +68 -0
  31. package/dist/template/prisma/postgresql/schema.prisma +68 -0
  32. package/dist/template/proxy/proxy.ts +15 -0
  33. package/dist/template/server/user.ts +49 -0
  34. package/package.json +62 -0
@@ -0,0 +1,173 @@
1
+ "use client";
2
+
3
+ import { Controller, useForm } from "react-hook-form";
4
+ import { toast } from "sonner";
5
+ import * as z from "zod";
6
+ import { zodResolver } from "@hookform/resolvers/zod";
7
+
8
+ import { Button } from "@/components/ui/button";
9
+ import {
10
+ Card,
11
+ CardContent,
12
+ CardDescription,
13
+ CardFooter,
14
+ CardHeader,
15
+ CardTitle,
16
+ } from "@/components/ui/card";
17
+ import {
18
+ Field,
19
+ FieldError,
20
+ FieldGroup,
21
+ FieldLabel,
22
+ } from "@/components/ui/field";
23
+ import { Input } from "@/components/ui/input";
24
+ import Link from "next/link";
25
+ import { useState } from "react";
26
+ import { signUp } from "@/server/user";
27
+ import { useRouter } from "next/navigation";
28
+
29
+ const formSchema = z.object({
30
+ name: z.string().min(3, {
31
+ message: "Name must be at least 3 characters",
32
+ }),
33
+ email: z.string().email(),
34
+ password: z.string().min(8, {
35
+ message: "Password must be at least 8 characters",
36
+ }),
37
+ });
38
+
39
+ const SingUpComponent = () => {
40
+ const [isLoading, setIsLoading] = useState(false);
41
+ const router = useRouter();
42
+
43
+ const form = useForm<z.infer<typeof formSchema>>({
44
+ resolver: zodResolver(formSchema),
45
+ defaultValues: {
46
+ name: "",
47
+ email: "",
48
+ password: "",
49
+ },
50
+ });
51
+
52
+ const onSubmit = async (data: z.infer<typeof formSchema>) => {
53
+ setIsLoading(true);
54
+ try {
55
+ const { success, message } = await signUp(
56
+ data.name,
57
+ data.email,
58
+ data.password
59
+ );
60
+
61
+ if (success === true) {
62
+ router.push("/");
63
+ toast.success(message);
64
+ } else {
65
+ toast.error(message);
66
+ }
67
+ setIsLoading(false);
68
+ } catch (error: any) {
69
+ toast.error(error.message);
70
+ setIsLoading(false);
71
+ }
72
+ };
73
+
74
+ return (
75
+ <Card className="w-full sm:max-w-md shadow-md">
76
+ <CardHeader>
77
+ <CardTitle className="text-2xl leading-4">Sign Up</CardTitle>
78
+ <CardDescription>Create an account</CardDescription>
79
+ </CardHeader>
80
+ <CardContent>
81
+ <form id="form-login" onSubmit={form.handleSubmit(onSubmit)}>
82
+ <FieldGroup>
83
+ <Controller
84
+ name="name"
85
+ control={form.control}
86
+ render={({ field, fieldState }) => (
87
+ <Field data-invalid={fieldState.invalid}>
88
+ <FieldLabel htmlFor="form-login-name">Name</FieldLabel>
89
+ <Input
90
+ {...field}
91
+ id="form-login-name"
92
+ aria-invalid={fieldState.invalid}
93
+ placeholder="Enter your name"
94
+ autoComplete="off"
95
+ disabled={isLoading}
96
+ />
97
+ {fieldState.invalid && (
98
+ <FieldError errors={[fieldState.error]} />
99
+ )}
100
+ </Field>
101
+ )}
102
+ />
103
+ <Controller
104
+ name="email"
105
+ control={form.control}
106
+ render={({ field, fieldState }) => (
107
+ <Field data-invalid={fieldState.invalid}>
108
+ <FieldLabel htmlFor="form-login-email">Email</FieldLabel>
109
+ <Input
110
+ {...field}
111
+ id="form-login-email"
112
+ aria-invalid={fieldState.invalid}
113
+ placeholder="example@domain.com"
114
+ autoComplete="off"
115
+ disabled={isLoading}
116
+ />
117
+ {fieldState.invalid && (
118
+ <FieldError errors={[fieldState.error]} />
119
+ )}
120
+ </Field>
121
+ )}
122
+ />
123
+ <Controller
124
+ name="password"
125
+ control={form.control}
126
+ render={({ field, fieldState }) => (
127
+ <Field data-invalid={fieldState.invalid}>
128
+ <FieldLabel htmlFor="form-login-password">
129
+ Password
130
+ </FieldLabel>
131
+ <Input
132
+ {...field}
133
+ id="form-login-password"
134
+ aria-invalid={fieldState.invalid}
135
+ placeholder="********"
136
+ autoComplete="off"
137
+ type="password"
138
+ disabled={isLoading}
139
+ />
140
+ {fieldState.invalid && (
141
+ <FieldError errors={[fieldState.error]} />
142
+ )}
143
+ </Field>
144
+ )}
145
+ />
146
+ </FieldGroup>
147
+ </form>
148
+ </CardContent>
149
+ <CardFooter>
150
+ <div className="w-full">
151
+ <Field orientation="horizontal">
152
+ <Button
153
+ type="submit"
154
+ form="form-login"
155
+ className="w-full"
156
+ disabled={isLoading}
157
+ >
158
+ {isLoading ? "Signing up..." : "Sign Up"}
159
+ </Button>
160
+ </Field>
161
+ <div className="w-full text-center pt-4 space-x-2">
162
+ <span>Already have an account?</span>
163
+ <Link href="/auth/login" className="underline">
164
+ Login
165
+ </Link>
166
+ </div>
167
+ </div>
168
+ </CardFooter>
169
+ </Card>
170
+ );
171
+ };
172
+
173
+ export default SingUpComponent;
@@ -0,0 +1,13 @@
1
+ import { config } from "dotenv";
2
+ import { defineConfig } from "drizzle-kit";
3
+
4
+ config({ path: ".env" });
5
+
6
+ export default defineConfig({
7
+ schema: "./db/schema.ts",
8
+ out: "./migrations",
9
+ dialect: "postgresql",
10
+ dbCredentials: {
11
+ url: process.env.DATABASE_URL!,
12
+ },
13
+ });
@@ -0,0 +1,12 @@
1
+ import "dotenv/config";
2
+ import { defineConfig, env } from "prisma/config";
3
+
4
+ export default defineConfig({
5
+ schema: "prisma/schema.prisma",
6
+ migrations: {
7
+ path: "prisma/migrations",
8
+ },
9
+ datasource: {
10
+ url: env("DATABASE_URL"),
11
+ },
12
+ });
@@ -0,0 +1,6 @@
1
+ import { config } from "dotenv";
2
+ import { drizzle } from "drizzle-orm/neon-http";
3
+
4
+ config({ path: ".env" }); // or .env.local
5
+
6
+ export const db = drizzle(process.env.DATABASE_URL!);
@@ -0,0 +1,68 @@
1
+ import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
2
+
3
+ export const user = pgTable("user", {
4
+ id: text("id").primaryKey(),
5
+ name: text("name").notNull(),
6
+ email: text("email").notNull().unique(),
7
+ emailVerified: boolean("email_verified").default(false).notNull(),
8
+ image: text("image"),
9
+ createdAt: timestamp("created_at").defaultNow().notNull(),
10
+ updatedAt: timestamp("updated_at")
11
+ .defaultNow()
12
+ .$onUpdate(() => /* @__PURE__ */ new Date())
13
+ .notNull(),
14
+ });
15
+
16
+ export const session = pgTable("session", {
17
+ id: text("id").primaryKey(),
18
+ expiresAt: timestamp("expires_at").notNull(),
19
+ token: text("token").notNull().unique(),
20
+ createdAt: timestamp("created_at").defaultNow().notNull(),
21
+ updatedAt: timestamp("updated_at")
22
+ .$onUpdate(() => /* @__PURE__ */ new Date())
23
+ .notNull(),
24
+ ipAddress: text("ip_address"),
25
+ userAgent: text("user_agent"),
26
+ userId: text("user_id")
27
+ .notNull()
28
+ .references(() => user.id, { onDelete: "cascade" }),
29
+ });
30
+
31
+ export const account = pgTable("account", {
32
+ id: text("id").primaryKey(),
33
+ accountId: text("account_id").notNull(),
34
+ providerId: text("provider_id").notNull(),
35
+ userId: text("user_id")
36
+ .notNull()
37
+ .references(() => user.id, { onDelete: "cascade" }),
38
+ accessToken: text("access_token"),
39
+ refreshToken: text("refresh_token"),
40
+ idToken: text("id_token"),
41
+ accessTokenExpiresAt: timestamp("access_token_expires_at"),
42
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
43
+ scope: text("scope"),
44
+ password: text("password"),
45
+ createdAt: timestamp("created_at").defaultNow().notNull(),
46
+ updatedAt: timestamp("updated_at")
47
+ .$onUpdate(() => /* @__PURE__ */ new Date())
48
+ .notNull(),
49
+ });
50
+
51
+ export const verification = pgTable("verification", {
52
+ id: text("id").primaryKey(),
53
+ identifier: text("identifier").notNull(),
54
+ value: text("value").notNull(),
55
+ expiresAt: timestamp("expires_at").notNull(),
56
+ createdAt: timestamp("created_at").defaultNow().notNull(),
57
+ updatedAt: timestamp("updated_at")
58
+ .defaultNow()
59
+ .$onUpdate(() => /* @__PURE__ */ new Date())
60
+ .notNull(),
61
+ });
62
+
63
+ export const schema = {
64
+ user,
65
+ session,
66
+ account,
67
+ verification,
68
+ };
@@ -0,0 +1,132 @@
1
+ import {
2
+ Body,
3
+ Button,
4
+ Container,
5
+ Head,
6
+ Heading,
7
+ Html,
8
+ Link,
9
+ Preview,
10
+ Section,
11
+ Text,
12
+ Tailwind,
13
+ } from "@react-email/components";
14
+
15
+ interface ForgotPasswordEmailProps {
16
+ username: string;
17
+ resetUrl: string;
18
+ userEmail: string;
19
+ }
20
+
21
+ const ForgotPasswordEmail = (props: ForgotPasswordEmailProps) => {
22
+ const { username, resetUrl, userEmail } = props;
23
+
24
+ return (
25
+ <Html lang="en" dir="ltr">
26
+ <Tailwind>
27
+ <Head />
28
+ <Preview>Reset your password - Action required</Preview>
29
+ <Body className="bg-gray-100 font-sans py-[40px]">
30
+ <Container className="bg-white rounded-[8px] shadow-sm max-w-[600px] mx-auto p-[40px]">
31
+ {/* Header */}
32
+ <Section className="text-center mb-[32px]">
33
+ <Heading className="text-[28px] font-bold text-gray-900 m-0 mb-[8px]">
34
+ Reset Your Password
35
+ </Heading>
36
+ <Text className="text-[16px] text-gray-600 m-0">
37
+ We received a request to reset your password
38
+ </Text>
39
+ </Section>
40
+
41
+ {/* Main Content */}
42
+ <Section className="mb-[32px]">
43
+ <Text className="text-[16px] text-gray-700 leading-[24px] m-0 mb-[16px]">
44
+ Hello, {username}
45
+ </Text>
46
+ <Text className="text-[16px] text-gray-700 leading-[24px] m-0 mb-[16px]">
47
+ We received a password reset request for your account associated
48
+ with <strong>{userEmail}</strong>.
49
+ </Text>
50
+ <Text className="text-[16px] text-gray-700 leading-[24px] m-0 mb-[24px]">
51
+ Click the button below to create a new password. This link will
52
+ expire in 24 hours for security reasons.
53
+ </Text>
54
+ </Section>
55
+
56
+ {/* Reset Button */}
57
+ <Section className="text-center mb-[32px]">
58
+ <Button
59
+ href={resetUrl}
60
+ className="bg-blue-600 text-white px-[32px] py-[16px] rounded-[8px] text-[16px] font-semibold no-underline box-border inline-block"
61
+ >
62
+ Reset Password
63
+ </Button>
64
+ </Section>
65
+
66
+ {/* Alternative Link */}
67
+ <Section className="mb-[32px]">
68
+ <Text className="text-[14px] text-gray-600 leading-[20px] m-0 mb-[8px]">
69
+ If the button doesn&apos;t work, copy and paste this link into
70
+ your browser:
71
+ </Text>
72
+ <Link
73
+ href={resetUrl}
74
+ className="text-blue-600 text-[14px] break-all"
75
+ >
76
+ {resetUrl}
77
+ </Link>
78
+ </Section>
79
+
80
+ {/* Security Notice */}
81
+ <Section className="bg-gray-50 p-[20px] rounded-[8px] mb-[32px]">
82
+ <Text className="text-[14px] text-gray-700 leading-[20px] m-0 mb-[8px] font-semibold">
83
+ Security Notice:
84
+ </Text>
85
+ <Text className="text-[14px] text-gray-600 leading-[20px] m-0 mb-[8px]">
86
+ • If you didn&apos;t request this password reset, please ignore
87
+ this email
88
+ </Text>
89
+ <Text className="text-[14px] text-gray-600 leading-[20px] m-0 mb-[8px]">
90
+ • This link will expire in 24 hours
91
+ </Text>
92
+ <Text className="text-[14px] text-gray-600 leading-[20px] m-0">
93
+ • For security, never share this link with anyone
94
+ </Text>
95
+ </Section>
96
+
97
+ {/* Help Section */}
98
+ <Section className="mb-[32px]">
99
+ <Text className="text-[14px] text-gray-600 leading-[20px] m-0">
100
+ Need help? Contact our support team at{" "}
101
+ <Link
102
+ href="mailto:support@company.com"
103
+ className="text-blue-600"
104
+ >
105
+ support@company.com
106
+ </Link>
107
+ </Text>
108
+ </Section>
109
+
110
+ {/* Footer */}
111
+ <Section className="border-t border-gray-200 pt-[24px]">
112
+ <Text className="text-[12px] text-gray-500 leading-[16px] m-0 mb-[8px]">
113
+ This email was sent to {userEmail}
114
+ </Text>
115
+ <Text className="text-[12px] text-gray-500 leading-[16px] m-0 mb-[8px]">
116
+ Company Name, 123 Business Street, City, State 12345
117
+ </Text>
118
+ <Text className="text-[12px] text-gray-500 leading-[16px] m-0">
119
+ © 2025 Company Name. All rights reserved.{" "}
120
+ <Link href="#" className="text-gray-500">
121
+ Unsubscribe
122
+ </Link>
123
+ </Text>
124
+ </Section>
125
+ </Container>
126
+ </Body>
127
+ </Tailwind>
128
+ </Html>
129
+ );
130
+ };
131
+
132
+ export default ForgotPasswordEmail;
@@ -0,0 +1,20 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { prismaAdapter } from "better-auth/adapters/prisma";
3
+ import { PrismaClient } from "@/generated/prisma/client";
4
+ import { nextCookies } from "better-auth/next-js";
5
+
6
+ const prisma = new PrismaClient();
7
+ export const auth = betterAuth({
8
+ database: prismaAdapter(prisma, {
9
+ provider: "mongodb",
10
+ }),
11
+ advanced: {
12
+ database: {
13
+ generateId: false,
14
+ },
15
+ },
16
+ emailAndPassword: {
17
+ enabled: true,
18
+ },
19
+ plugins: [nextCookies()],
20
+ });
@@ -0,0 +1,27 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { prismaAdapter } from "better-auth/adapters/prisma";
3
+ import { PrismaMariaDb } from "@prisma/adapter-mariadb";
4
+ import { PrismaClient } from "@/generated/prisma/client";
5
+ import { nextCookies } from "better-auth/next-js";
6
+
7
+ const url = new URL(process.env.DATABASE_URL!);
8
+
9
+ const adapter = new PrismaMariaDb({
10
+ host: url.hostname,
11
+ user: url.username,
12
+ password: url.password,
13
+ database: url.pathname.replace("/", ""),
14
+ port: Number(url.port),
15
+ });
16
+
17
+ const prisma = new PrismaClient({ adapter });
18
+
19
+ export const auth = betterAuth({
20
+ database: prismaAdapter(prisma, {
21
+ provider: "sqlite",
22
+ }),
23
+ emailAndPassword: {
24
+ enabled: true,
25
+ },
26
+ plugins: [nextCookies()],
27
+ });
@@ -0,0 +1,20 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { prismaAdapter } from "better-auth/adapters/prisma";
3
+ import { PrismaPg } from "@prisma/adapter-pg";
4
+ import { PrismaClient } from "@/generated/prisma/client";
5
+ import { nextCookies } from "better-auth/next-js";
6
+
7
+ const connectionString = `${process.env.DATABASE_URL}`;
8
+
9
+ const adapter = new PrismaPg({ connectionString });
10
+ const prisma = new PrismaClient({ adapter });
11
+
12
+ export const auth = betterAuth({
13
+ database: prismaAdapter(prisma, {
14
+ provider: "sqlite",
15
+ }),
16
+ emailAndPassword: {
17
+ enabled: true,
18
+ },
19
+ plugins: [nextCookies()],
20
+ });
@@ -0,0 +1,5 @@
1
+ import { createAuthClient } from "better-auth/react";
2
+
3
+ export const authClient = createAuthClient({
4
+ baseURL: process.env.BETTER_AUTH_URL,
5
+ });
@@ -0,0 +1,16 @@
1
+ import { betterAuth } from "better-auth";
2
+ import { drizzleAdapter } from "better-auth/adapters/drizzle";
3
+ import { db } from "@/db/drizzle";
4
+ import { schema } from "@/db/schema";
5
+ import { nextCookies } from "better-auth/next-js";
6
+
7
+ export const auth = betterAuth({
8
+ database: drizzleAdapter(db, {
9
+ provider: "pg",
10
+ schema,
11
+ }),
12
+ emailAndPassword: {
13
+ enabled: true,
14
+ },
15
+ plugins: [nextCookies()],
16
+ });
@@ -0,0 +1,70 @@
1
+ generator client {
2
+ provider = "prisma-client-js"
3
+ output = "../generated/prisma"
4
+ }
5
+
6
+ datasource db {
7
+ provider = "mongodb"
8
+ url = env("DATABASE_URL")
9
+ }
10
+
11
+ model User {
12
+ id String @id @default(auto()) @map("_id") @db.ObjectId
13
+ name String
14
+ email String
15
+ emailVerified Boolean @default(false)
16
+ image String?
17
+ createdAt DateTime @default(now())
18
+ updatedAt DateTime @updatedAt
19
+ sessions Session[]
20
+ accounts Account[]
21
+
22
+ @@unique([email])
23
+ @@map("users") // Typically plural for collections
24
+ }
25
+
26
+ model Session {
27
+ id String @id @default(auto()) @map("_id") @db.ObjectId
28
+ expiresAt DateTime
29
+ token String @unique
30
+ createdAt DateTime @default(now())
31
+ updatedAt DateTime @updatedAt
32
+ ipAddress String?
33
+ userAgent String?
34
+ userId String @db.ObjectId
35
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
36
+
37
+ @@map("sessions")
38
+ }
39
+
40
+ model Account {
41
+ id String @id @default(auto()) @map("_id") @db.ObjectId
42
+ accountId String
43
+ providerId String
44
+ userId String @db.ObjectId
45
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
46
+ accessToken String?
47
+ refreshToken String?
48
+ idToken String?
49
+ accessTokenExpiresAt DateTime?
50
+ refreshTokenExpiresAt DateTime?
51
+ scope String?
52
+ password String?
53
+ createdAt DateTime @default(now())
54
+ updatedAt DateTime @updatedAt
55
+
56
+ @@unique([providerId, accountId])
57
+ @@map("accounts")
58
+ }
59
+
60
+ model Verification {
61
+ id String @id @default(auto()) @map("_id") @db.ObjectId
62
+ identifier String
63
+ value String
64
+ expiresAt DateTime
65
+ createdAt DateTime? @default(now())
66
+ updatedAt DateTime? @updatedAt
67
+
68
+ @@unique([identifier, value])
69
+ @@map("verifications")
70
+ }
@@ -0,0 +1,68 @@
1
+ generator client {
2
+ provider = "prisma-client"
3
+ output = "../generated/prisma"
4
+ }
5
+
6
+ datasource db {
7
+ provider = "mysql"
8
+ }
9
+
10
+ model User {
11
+ id String @id @default(cuid())
12
+ name String
13
+ email String @unique
14
+ emailVerified Boolean @default(false)
15
+ image String?
16
+ createdAt DateTime @default(now())
17
+ updatedAt DateTime @updatedAt
18
+ sessions Session[]
19
+ accounts Account[]
20
+
21
+ @@map("users")
22
+ }
23
+
24
+ model Session {
25
+ id String @id @default(cuid())
26
+ expiresAt DateTime
27
+ token String @unique
28
+ createdAt DateTime @default(now())
29
+ updatedAt DateTime @updatedAt
30
+ ipAddress String?
31
+ userAgent String?
32
+ userId String
33
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
34
+
35
+ @@map("sessions")
36
+ }
37
+
38
+ model Account {
39
+ id String @id @default(cuid())
40
+ accountId String
41
+ providerId String
42
+ userId String
43
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
44
+ accessToken String?
45
+ refreshToken String?
46
+ idToken String?
47
+ accessTokenExpiresAt DateTime?
48
+ refreshTokenExpiresAt DateTime?
49
+ scope String?
50
+ password String?
51
+ createdAt DateTime @default(now())
52
+ updatedAt DateTime @updatedAt
53
+
54
+ @@unique([providerId, accountId])
55
+ @@map("accounts")
56
+ }
57
+
58
+ model Verification {
59
+ id String @id @default(cuid())
60
+ identifier String
61
+ value String
62
+ expiresAt DateTime
63
+ createdAt DateTime? @default(now())
64
+ updatedAt DateTime? @updatedAt
65
+
66
+ @@unique([identifier, value])
67
+ @@map("verifications")
68
+ }