auth-simple 1.0.0 → 1.0.1

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.
@@ -0,0 +1,4 @@
1
+
2
+ import { handlers } from "@/auth";
3
+ export const { GET, POST } = handlers;
4
+
@@ -0,0 +1,49 @@
1
+
2
+ // app/api/users/[id]/route.js
3
+ import { NextResponse } from "next/server";
4
+ import { connectDB } from "@/lib/db";
5
+ import User from "@/models/User";
6
+
7
+ // READ ONE (GET /api/users/:id)
8
+ export async function GET(req, { params }) {
9
+ const { id } = await params;
10
+ try {
11
+ await connectDB();
12
+ const user = await User.findById(id).select("-passwordHash");
13
+ if (!user)
14
+ return NextResponse.json({ error: "User not found" }, { status: 404 });
15
+ return NextResponse.json(user);
16
+ } catch (error) {
17
+ return NextResponse.json({ error: error.message }, { status: 500 });
18
+ }
19
+ }
20
+
21
+ // UPDATE (PUT /api/users/:id)
22
+ export async function PUT(req, { params }) {
23
+ const { id } = await params;
24
+ try {
25
+ await connectDB();
26
+ const body = await req.json();
27
+ const user = await User.findByIdAndUpdate(id, body, { new: true });
28
+ if (!user)
29
+ return NextResponse.json({ error: "User not found" }, { status: 404 });
30
+ return NextResponse.json(user);
31
+ } catch (error) {
32
+ return NextResponse.json({ error: error.message }, { status: 400 });
33
+ }
34
+ }
35
+
36
+ // DELETE (DELETE /api/users/:id)
37
+ export async function DELETE(req, { params }) {
38
+ const { id } = await params;
39
+ try {
40
+ await connectDB();
41
+ const user = await User.findByIdAndDelete(id);
42
+ if (!user)
43
+ return NextResponse.json({ error: "User not found" }, { status: 404 });
44
+ return NextResponse.json({ message: "User deleted successfully" });
45
+ } catch (error) {
46
+ return NextResponse.json({ error: error.message }, { status: 500 });
47
+ }
48
+ }
49
+
@@ -0,0 +1,36 @@
1
+
2
+ import { NextResponse } from "next/server";
3
+ import { connectDB } from "@/lib/db";
4
+ import User from "@/models/User";
5
+ import bcrypt from "bcryptjs";
6
+
7
+ // CREATE (POST /api/users)
8
+ export async function POST(req) {
9
+ try {
10
+ await connectDB();
11
+ const body = await req.json();
12
+ const { email, password, image } = body;
13
+ const salt = await bcrypt.genSalt(10);
14
+ const hash = await bcrypt.hash(password, salt);
15
+ const user = await User.create({
16
+ email,
17
+ passwordHash: hash,
18
+ image: image || null,
19
+ });
20
+ return NextResponse.json(user, { status: 201 });
21
+ } catch (error) {
22
+ return NextResponse.json({ error: error.message }, { status: 400 });
23
+ }
24
+ }
25
+
26
+ // READ ALL (GET /api/users)
27
+ export async function GET() {
28
+ try {
29
+ await connectDB();
30
+ const users = await User.find().select("-passwordHash");
31
+ return NextResponse.json(users);
32
+ } catch (error) {
33
+ return NextResponse.json({ error: error.message }, { status: 500 });
34
+ }
35
+ }
36
+
@@ -0,0 +1,66 @@
1
+
2
+ "use client";
3
+
4
+ import { signIn } from "next-auth/react";
5
+ import { useState } from "react";
6
+
7
+ export default function Login() {
8
+ const [email, setEmail] = useState("");
9
+ const [password, setPassword] = useState("");
10
+
11
+ const handleSubmit = async (e) => {
12
+ e.preventDefault();
13
+ await signIn("credentials", {
14
+ email,
15
+ password,
16
+ redirect: true,
17
+ callbackUrl: "/",
18
+ });
19
+ };
20
+
21
+ return (
22
+ <div className="flex items-center justify-center min-h-screen">
23
+ <div className="w-sm shadow-2xl/50 rounded-lg p-6">
24
+ <h1 className="text-2xl flex justify-center py-2 border-b-2 border-black">
25
+ Login
26
+ </h1>
27
+ <form
28
+ onSubmit={handleSubmit}
29
+ className="flex flex-col gap-4 py-4 border-b-1 border-black mb-4"
30
+ >
31
+ <input
32
+ className="p-2 rounded outline-none focus:ring-0 focus:border-gray-500 border border-gray-300"
33
+ type="email"
34
+ placeholder="Email"
35
+ value={email}
36
+ onChange={(e) => setEmail(e.target.value)}
37
+ required
38
+ />
39
+ <input
40
+ className="p-2 rounded outline-none focus:ring-0 focus:border-gray-500 border border-gray-300"
41
+ type="password"
42
+ placeholder="Password"
43
+ value={password}
44
+ onChange={(e) => setPassword(e.target.value)}
45
+ required
46
+ />
47
+ <button
48
+ className="bg-gray-500 text-white p-2 rounded hover:bg-gray-600 cursor-pointer"
49
+ type="submit"
50
+ >
51
+ Login
52
+ </button>
53
+ </form>
54
+
55
+ <hr />
56
+ <button
57
+ onClick={() => signIn("google", { callbackUrl: "/" })}
58
+ className="bg-gray-500 text-white p-2 rounded hover:bg-gray-600 cursor-pointer w-full"
59
+ >
60
+ Sign in with Google
61
+ </button>
62
+ </div>
63
+ </div>
64
+ );
65
+ }
66
+
@@ -0,0 +1,75 @@
1
+
2
+ "use client";
3
+
4
+ import { useState } from "react";
5
+
6
+ export default function Register() {
7
+ const [email, setEmail] = useState("");
8
+ const [password, setPassword] = useState("");
9
+ const [image, setImage] = useState("");
10
+
11
+ const handleSubmit = async (e) => {
12
+ e.preventDefault();
13
+
14
+ const res = await fetch("/api/users", {
15
+ method: "POST",
16
+ headers: { "Content-Type": "application/json" },
17
+ body: JSON.stringify({
18
+ email,
19
+ password,
20
+ image: image || null,
21
+ }),
22
+ });
23
+
24
+ if (res.ok) {
25
+ alert("✅ User registered successfully!");
26
+ } else {
27
+ console.log("Registration failed", await res.json());
28
+ alert("❌ Registration failed");
29
+ }
30
+ };
31
+
32
+ return (
33
+ <div className="flex items-center justify-center min-h-screen">
34
+ <div className="w-sm shadow-2xl/50 rounded-lg p-6">
35
+ <h1 className="text-2xl flex justify-center py-2 border-b-2 border-black">
36
+ Register
37
+ </h1>
38
+ <form
39
+ className="flex flex-col gap-4 py-4 border-b-1 border-black mb-4"
40
+ onSubmit={handleSubmit}
41
+ >
42
+ <input
43
+ className="p-2 rounded outline-none focus:ring-0 focus:border-gray-500 border border-gray-300"
44
+ type="email"
45
+ placeholder="Email"
46
+ value={email}
47
+ onChange={(e) => setEmail(e.target.value)}
48
+ required
49
+ />
50
+ <input
51
+ className="p-2 rounded outline-none focus:ring-0 focus:border-gray-500 border border-gray-300"
52
+ type="password"
53
+ placeholder="Password"
54
+ value={password}
55
+ onChange={(e) => setPassword(e.target.value)}
56
+ required
57
+ />
58
+ <button
59
+ className="bg-gray-500 text-white p-2 rounded hover:bg-gray-600 cursor-pointer"
60
+ type="submit"
61
+ >
62
+ Register
63
+ </button>
64
+ </form>
65
+ <button
66
+ onClick={() => signIn("google", { callbackUrl: "/" })}
67
+ className="bg-gray-500 text-white p-2 rounded hover:bg-gray-600 cursor-pointer w-full"
68
+ >
69
+ Sign in with Google
70
+ </button>
71
+ </div>
72
+ </div>
73
+ );
74
+ }
75
+
package/111/auth.js ADDED
@@ -0,0 +1,88 @@
1
+
2
+ import NextAuth from "next-auth";
3
+ import CredentialsProvider from "next-auth/providers/credentials";
4
+ import GoogleProvider from "next-auth/providers/google";
5
+ import { connectDB } from "./lib/db";
6
+ import { MongoDBAdapter } from "@auth/mongodb-adapter";
7
+ import clientPromise from "@/lib/mongodb";
8
+ import User from "@/models/User";
9
+ import bcrypt from "bcryptjs";
10
+
11
+ export const { handlers, signIn, signOut, auth } = NextAuth({
12
+ adapter: MongoDBAdapter(clientPromise),
13
+ providers: [
14
+ GoogleProvider({
15
+ clientId: process.env.GOOGLE_CLIENT_ID,
16
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
17
+ }),
18
+ CredentialsProvider({
19
+ name: "Credentials",
20
+ credentials: {
21
+ email: { label: "Email", type: "text" },
22
+ password: { label: "Password", type: "password" },
23
+ },
24
+ async authorize(credentials) {
25
+ try {
26
+ await connectDB();
27
+ const user = await User.findOne({ email: credentials.email });
28
+ if (!user) throw new Error("No user found with this email");
29
+
30
+ const isValid = await bcrypt.compare(
31
+ credentials.password,
32
+ user.passwordHash,
33
+ );
34
+
35
+ if (!isValid) return null;
36
+
37
+ return {
38
+ id: user._id.toString(),
39
+ email: user.email,
40
+ role: user.role,
41
+ image: user.image,
42
+ };
43
+ } catch (err) {
44
+ console.error("Credentials.authorize error", err);
45
+ throw err;
46
+ }
47
+ },
48
+ }),
49
+ ],
50
+ callbacks: {
51
+ async jwt({ token, user }) {
52
+ if (user) {
53
+ token.id = user.id;
54
+ token.role = user.role || "user"; // Assign roles dynamically
55
+ }
56
+ return token;
57
+ },
58
+ async session({ session, token }) {
59
+ session.user.id = token.id;
60
+ session.user.role = token.role || "user"; // Ensure role is included in session
61
+ return session;
62
+ },
63
+ },
64
+ session: {
65
+ strategy: "jwt",
66
+ maxAge: 30 * 24 * 60 * 60, // 30 days
67
+ },
68
+ pages: {
69
+ signIn: "/auth/signin",
70
+ signOut: "/auth/signout",
71
+ error: "/auth/error",
72
+ },
73
+ events: {
74
+ async signIn({ user }) {
75
+ console.log("User signed in:", user);
76
+ },
77
+ async signOut({ token }) {
78
+ console.log("User signed out:", token);
79
+ },
80
+ },
81
+ debug: process.env.NODE_ENV === "development",
82
+ theme: {
83
+ colorScheme: "auto", // "auto", "dark", "light"
84
+ brandColor: "#0070f3",
85
+ logo: "/logo.png",
86
+ },
87
+ });
88
+
@@ -0,0 +1,37 @@
1
+
2
+ "use client";
3
+
4
+ import { signIn, signOut, useSession } from "next-auth/react";
5
+ import Link from "next/link";
6
+
7
+ export default function Menu() {
8
+ const { data: session, status } = useSession();
9
+
10
+ if (status === "loading") {
11
+ return <p>Loading...</p>;
12
+ }
13
+
14
+ return (
15
+ <nav className="fixed top-0 flex gap-1 items-center justify-end w-full p-4 bg-black/20">
16
+ {!session ? (
17
+ <>
18
+ <Link href="/login" className="text-gray-700 hover:text-gray-900 m-2">
19
+ Login
20
+ </Link>
21
+ <Link href="/register">Register</Link>
22
+ </>
23
+ ) : (
24
+ <>
25
+ <span>{session.user?.email}</span>
26
+ <button
27
+ onClick={() => signOut({ callbackUrl: "/" })}
28
+ className="bg-gray-500 text-white p-2 rounded hover:bg-gray-600 cursor-pointer ml-2"
29
+ >
30
+ Logout
31
+ </button>
32
+ </>
33
+ )}
34
+ </nav>
35
+ );
36
+ }
37
+
package/111/lib/db.js ADDED
@@ -0,0 +1,38 @@
1
+
2
+ import mongoose from "mongoose";
3
+
4
+ const MONGODB_URI = process.env.MONGODB_URI;
5
+
6
+ if (!MONGODB_URI) {
7
+ throw new Error(
8
+ "❌ Please define the MONGODB_URI environment variable inside .env.local",
9
+ );
10
+ }
11
+
12
+ /**
13
+ * Global cache to prevent multiple connections in dev mode
14
+ */
15
+ let cached = global.mongoose;
16
+
17
+ if (!cached) {
18
+ cached = global.mongoose = { conn: null, promise: null };
19
+ }
20
+
21
+ export async function connectDB() {
22
+ if (cached.conn) {
23
+ return cached.conn;
24
+ }
25
+
26
+ if (!cached.promise) {
27
+ cached.promise = mongoose
28
+ .connect(MONGODB_URI, {
29
+ bufferCommands: false,
30
+ })
31
+ .then((mongoose) => mongoose);
32
+ }
33
+
34
+ cached.conn = await cached.promise;
35
+ console.log("✅ MongoDB connected");
36
+ return cached.conn;
37
+ }
38
+
@@ -0,0 +1,27 @@
1
+
2
+ // lib/mongodb.js
3
+ import { MongoClient } from "mongodb";
4
+
5
+ const uri = process.env.MONGODB_URI;
6
+ const options = {};
7
+
8
+ let client;
9
+ let clientPromise;
10
+
11
+ if (!uri) {
12
+ throw new Error("❌ Please add your Mongo URI to .env.local");
13
+ }
14
+
15
+ if (process.env.NODE_ENV === "development") {
16
+ if (!global._mongoClientPromise) {
17
+ client = new MongoClient(uri, options);
18
+ global._mongoClientPromise = client.connect();
19
+ }
20
+ clientPromise = global._mongoClientPromise;
21
+ } else {
22
+ client = new MongoClient(uri, options);
23
+ clientPromise = client.connect();
24
+ }
25
+
26
+ export default clientPromise;
27
+
@@ -0,0 +1,29 @@
1
+
2
+ import mongoose from "mongoose";
3
+
4
+ const userSchema = new mongoose.Schema(
5
+ {
6
+ email: {
7
+ type: String,
8
+ required: true,
9
+ unique: true,
10
+ },
11
+ passwordHash: {
12
+ type: String,
13
+ required: true,
14
+ },
15
+ role: {
16
+ type: String,
17
+ enum: ["user", "admin"],
18
+ default: "user",
19
+ },
20
+ image: {
21
+ type: String,
22
+ default: null,
23
+ },
24
+ },
25
+ { timestamps: true },
26
+ );
27
+
28
+ export default mongoose.models.User || mongoose.model("User", userSchema);
29
+
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "111",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "type": "commonjs"
13
+ }
package/index.js CHANGED
@@ -2,9 +2,27 @@
2
2
 
3
3
  import { files } from "./files.js";
4
4
  import { createFile } from "./functions.js";
5
+ import { execSync } from "child_process";
5
6
 
6
7
  files.forEach(({ fileName, body }) => {
7
8
  createFile(fileName, body);
8
9
  });
9
10
 
10
11
  console.log("✅ All files created!");
12
+
13
+ const dependencies = [
14
+ "mongodb",
15
+ "mongoose",
16
+ "@auth/mongodb-adapter",
17
+ "next-auth",
18
+ "bcryptjs",
19
+ ];
20
+
21
+ console.log("📦 Installing dependencies...");
22
+
23
+ try {
24
+ execSync(`npm install ${dependencies.join(" ")}`, { stdio: "inherit" });
25
+ console.log("✅ Dependencies installed!");
26
+ } catch (error) {
27
+ console.error("❌ Failed to install dependencies:", error.message);
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-simple",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -12,6 +12,7 @@
12
12
  "type": "module",
13
13
  "dependencies": {
14
14
  "@auth/mongodb-adapter": "^3.11.1",
15
+ "auth-simple": "^1.0.0",
15
16
  "bcryptjs": "^3.0.3",
16
17
  "mongodb": "^7.1.0",
17
18
  "mongoose": "^9.2.3",