@shipindays/shipindays 0.1.2 → 0.1.3

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.

Potentially problematic release.


This version of @shipindays/shipindays might be problematic. Click here for more details.

Files changed (25) hide show
  1. package/README.md +1 -1
  2. package/index.js +293 -241
  3. package/package.json +1 -27
  4. package/templates/blocks/auth/nextauth/package.json +8 -8
  5. package/templates/blocks/auth/nextauth/src/app/api/auth/[...nextauth]/route.ts +19 -0
  6. package/templates/blocks/auth/nextauth/src/app/api/auth/login/route.ts +40 -0
  7. package/templates/blocks/auth/nextauth/src/app/api/auth/logout/route.ts +12 -0
  8. package/templates/blocks/auth/nextauth/src/app/api/auth/signup/route.ts +61 -0
  9. package/templates/blocks/auth/nextauth/src/app/layout.tsx +35 -0
  10. package/templates/blocks/auth/nextauth/src/app/types/next-auth.d.ts +18 -0
  11. package/templates/blocks/auth/nextauth/src/lib/auth/index.ts +141 -0
  12. package/templates/blocks/auth/nextauth/src/middleware.ts +40 -0
  13. package/templates/blocks/auth/nextauth/src/types/next-auth.d.ts +0 -0
  14. package/templates/blocks/auth/supabase/package.json +5 -5
  15. package/templates/blocks/auth/supabase/src/app/api/auth/login/route.ts +28 -0
  16. package/templates/blocks/auth/supabase/src/app/api/auth/logout/route.ts +13 -0
  17. package/templates/blocks/auth/supabase/src/app/api/auth/signup/route.ts +42 -0
  18. package/templates/blocks/auth/supabase/src/lib/auth/index.ts +31 -54
  19. package/templates/blocks/auth/supabase/src/lib/supabase/client.ts +30 -0
  20. package/templates/blocks/auth/supabase/src/lib/supabase/server.ts +40 -0
  21. package/templates/blocks/auth/supabase/src/middleware.ts +27 -14
  22. package/templates/blocks/email/resend/{index.ts → src/lib/resend/index.ts} +27 -15
  23. package/templates/blocks/auth/nextauth/app/api/auth/[...nextauth]/route.ts +0 -19
  24. package/templates/blocks/auth/nextauth/lib/auth/index.ts +0 -98
  25. package/templates/blocks/auth/nextauth/middleware.ts +0 -30
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipindays/shipindays",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Scaffold a production ready Next.js SaaS in seconds. Pick your stack, get auth + payments + email wired up.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,23 +27,6 @@
27
27
  "type": "git",
28
28
  "url": "https://github.com/nikhilsaiankilla/shipindays"
29
29
  },
30
- "lint-staged": {
31
- "*.js": [
32
- "eslint --fix",
33
- "prettier --write"
34
- ],
35
- "*.ts": [
36
- "eslint --fix",
37
- "prettier --write"
38
- ],
39
- "*.tsx": [
40
- "eslint --fix",
41
- "prettier --write"
42
- ],
43
- "*.json": [
44
- "prettier --write"
45
- ]
46
- },
47
30
  "dependencies": {
48
31
  "@clack/prompts": "^0.9.1",
49
32
  "chalk": "^5.3.0",
@@ -51,14 +34,5 @@
51
34
  },
52
35
  "engines": {
53
36
  "node": ">=18.0.0"
54
- },
55
- "devDependencies": {
56
- "@commitlint/cli": "^20.5.0",
57
- "@commitlint/config-conventional": "^20.5.0",
58
- "husky": "^9.1.7",
59
- "lint-staged": "^16.4.0"
60
- },
61
- "scripts": {
62
- "prepare": "husky || true"
63
37
  }
64
38
  }
@@ -1,9 +1,9 @@
1
1
  {
2
- "dependencies": {
3
- "next-auth": "^5.0.0-beta.22",
4
- "bcryptjs": "^2.4.3"
5
- },
6
- "devDependencies": {
7
- "@types/bcryptjs": "^2.4.6"
8
- }
9
- }
2
+ "dependencies": {
3
+ "next-auth": "^5.0.0-beta.22",
4
+ "bcryptjs": "^2.4.3"
5
+ },
6
+ "devDependencies": {
7
+ "@types/bcryptjs": "^2.4.6"
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ // FILE: src/app/api/auth/[...nextauth]/route.ts
2
+ // ROUTE: /api/auth/* (GET + POST)
3
+ // ROLE: NextAuth v5 route handler
4
+ //
5
+ // INJECTED BY CLI — ONLY the nextauth block has this file.
6
+ // Supabase block does NOT have this file — it never gets created for Supabase users.
7
+ //
8
+ // Handles all NextAuth endpoints automatically:
9
+ // GET /api/auth/session ← reads current session
10
+ // GET /api/auth/csrf ← CSRF token
11
+ // GET /api/auth/providers ← lists configured providers
12
+ // POST /api/auth/signin ← sign in
13
+ // POST /api/auth/signout ← sign out
14
+ // GET /api/auth/callback/:p ← OAuth redirect lands here
15
+ // ─────────────────────────────────────────────────────────────────────────────
16
+
17
+ import { handlers } from "@/src/lib/auth";
18
+
19
+ export const { GET, POST } = handlers;
@@ -0,0 +1,40 @@
1
+ // FILE: src/app/api/auth/login/route.ts
2
+ // ROUTE: POST /api/auth/login
3
+ // ROLE: handles login form submission — called by /login page
4
+ //
5
+ // Uses NextAuth signIn() server-side to authenticate with credentials.
6
+ // OAuth (Google, GitHub) is handled automatically by NextAuth at /api/auth/signin.
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+
9
+ import { NextRequest, NextResponse } from "next/server";
10
+ import { nextAuthSignIn } from "@/src/lib/auth";
11
+ import { AuthError } from "next-auth";
12
+
13
+ export async function POST(req: NextRequest) {
14
+ const { email, password } = await req.json();
15
+
16
+ if (!email || !password) {
17
+ return NextResponse.json(
18
+ { error: "Email and password are required." },
19
+ { status: 400 },
20
+ );
21
+ }
22
+
23
+ try {
24
+ await nextAuthSignIn("credentials", {
25
+ email,
26
+ password,
27
+ redirect: false,
28
+ });
29
+
30
+ return NextResponse.json({ success: true });
31
+ } catch (error) {
32
+ if (error instanceof AuthError) {
33
+ return NextResponse.json(
34
+ { error: "Invalid email or password." },
35
+ { status: 401 },
36
+ );
37
+ }
38
+ throw error;
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ // FILE: src/app/api/auth/logout/route.ts
2
+ // ROUTE: POST /api/auth/logout
3
+ // ROLE: signs the user out — called by LogoutButton component
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+
6
+ import { NextResponse } from "next/server";
7
+ import { nextAuthSignOut } from "@/src/lib/auth";
8
+
9
+ export async function POST() {
10
+ await nextAuthSignOut({ redirect: false });
11
+ return NextResponse.json({ success: true });
12
+ }
@@ -0,0 +1,61 @@
1
+ // FILE: src/app/api/auth/signup/route.ts
2
+ // ROUTE: POST /api/auth/signup
3
+ // ROLE: creates a new user account — called by /signup page
4
+ //
5
+ // Hashes the password with bcrypt and saves to your database.
6
+ // TODO: replace the DB save section with your actual DB (Mongoose or Drizzle).
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+
9
+ import { NextRequest, NextResponse } from "next/server";
10
+ import bcrypt from "bcryptjs";
11
+ import { nextAuthSignIn } from "@/src/lib/auth";
12
+
13
+ export async function POST(req: NextRequest) {
14
+ const { name, email, password } = await req.json();
15
+
16
+ if (!email || !password) {
17
+ return NextResponse.json(
18
+ { error: "Email and password are required." },
19
+ { status: 400 },
20
+ );
21
+ }
22
+
23
+ if (password.length < 8) {
24
+ return NextResponse.json(
25
+ { error: "Password must be at least 8 characters." },
26
+ { status: 400 },
27
+ );
28
+ }
29
+
30
+ // Hash password — never store plain text passwords
31
+ const hashedPassword = await bcrypt.hash(password, 12);
32
+
33
+ // ── TODO: Save user to your database ─────────────────────────────────────
34
+ // Replace this section with your actual DB call.
35
+ //
36
+ // Example with Mongoose:
37
+ // import User from "@/lib/db/models/User";
38
+ // import { connectDB } from "@/lib/db";
39
+ // await connectDB();
40
+ // const existing = await User.findOne({ email });
41
+ // if (existing) return NextResponse.json({ error: "Email already in use." }, { status: 409 });
42
+ // await User.create({ name, email, password: hashedPassword });
43
+ //
44
+ // Example with Drizzle:
45
+ // import { db } from "@/lib/db";
46
+ // import { users } from "@/lib/db/schema";
47
+ // import { eq } from "drizzle-orm";
48
+ // const [existing] = await db.select().from(users).where(eq(users.email, email));
49
+ // if (existing) return NextResponse.json({ error: "Email already in use." }, { status: 409 });
50
+ // await db.insert(users).values({ email, name, password: hashedPassword });
51
+ // ─────────────────────────────────────────────────────────────────────────
52
+
53
+ // Auto sign-in after signup
54
+ await nextAuthSignIn("credentials", {
55
+ email,
56
+ password, // use plain password here — authorize() will hash-compare
57
+ redirect: false,
58
+ });
59
+
60
+ return NextResponse.json({ success: true }, { status: 201 });
61
+ }
@@ -0,0 +1,35 @@
1
+ // FILE: src/app/layout.tsx
2
+ // ROUTE: wraps every single page in the app
3
+ // ROLE: root layout with SessionProvider for NextAuth
4
+ //
5
+ // INJECTED BY CLI — overwrites base layout.tsx
6
+ // NextAuth requires SessionProvider to make useSession() work in client components.
7
+ // Supabase does NOT need this — base layout.tsx is used as-is for Supabase.
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+
10
+ import type { Metadata } from "next";
11
+ import { Inter } from "next/font/google";
12
+ import { SessionProvider } from "next-auth/react";
13
+ import "../globals.css";
14
+
15
+ const inter = Inter({ subsets: ["latin"] });
16
+
17
+ export const metadata: Metadata = {
18
+ title: "My SaaS",
19
+ description: "Built with shipindays",
20
+ };
21
+
22
+ export default function RootLayout({
23
+ children,
24
+ }: {
25
+ children: React.ReactNode;
26
+ }) {
27
+ return (
28
+ <html lang="en" suppressHydrationWarning>
29
+ <body className={inter.className}>
30
+ {/* SessionProvider makes useSession() available in all client components */}
31
+ <SessionProvider>{children}</SessionProvider>
32
+ </body>
33
+ </html>
34
+ );
35
+ }
@@ -0,0 +1,18 @@
1
+ // FILE: src/types/next-auth.d.ts
2
+ // ROUTE: not a route — picked up automatically by TypeScript
3
+ // ROLE: augments NextAuth Session type to include user.id
4
+ // without this, session.user.id gives a TypeScript error
5
+ // ─────────────────────────────────────────────────────────────────────────────
6
+
7
+ import "next-auth";
8
+
9
+ declare module "next-auth" {
10
+ interface Session {
11
+ user: {
12
+ id: string;
13
+ email: string;
14
+ name?: string | null;
15
+ image?: string | null;
16
+ };
17
+ }
18
+ }
@@ -0,0 +1,141 @@
1
+ // FILE: src/lib/auth/index.ts
2
+ // ROUTE: not a route — imported everywhere auth is needed
3
+ // ROLE: NextAuth v5 implementation of the auth contract
4
+ //
5
+ // INJECTED BY CLI when user picks "NextAuth v5"
6
+ // Overwrites base placeholder at src/lib/auth/index.ts
7
+ //
8
+ // Exports the 3 contract functions every auth block must have:
9
+ // getCurrentUser() — returns user or null
10
+ // requireUser() — returns user or redirects to /login
11
+ // signOut() — signs out and redirects to /
12
+ // ─────────────────────────────────────────────────────────────────────────────
13
+
14
+ import NextAuth from "next-auth";
15
+ import GitHub from "next-auth/providers/github";
16
+ import Google from "next-auth/providers/google";
17
+ import Credentials from "next-auth/providers/credentials";
18
+ import bcrypt from "bcryptjs";
19
+ import { redirect } from "next/navigation";
20
+
21
+ // ─── NextAuth config ──────────────────────────────────────────────────────────
22
+ // handlers → used by /api/auth/[...nextauth]/route.ts
23
+ // auth → used by middleware + server components to read session
24
+ // signIn → used by login API route
25
+ // signOut → used by logout API route
26
+ export const {
27
+ handlers,
28
+ auth,
29
+ signIn: nextAuthSignIn,
30
+ signOut: nextAuthSignOut,
31
+ } = NextAuth({
32
+ providers: [
33
+ // ── Google OAuth ──────────────────────────────────────────────────────────
34
+ // Needs: AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET in .env.local
35
+ // Setup: console.cloud.google.com → APIs → Credentials → OAuth 2.0
36
+ Google({
37
+ clientId: process.env.AUTH_GOOGLE_ID!,
38
+ clientSecret: process.env.AUTH_GOOGLE_SECRET!,
39
+ }),
40
+
41
+ // ── GitHub OAuth ──────────────────────────────────────────────────────────
42
+ // Needs: AUTH_GITHUB_ID and AUTH_GITHUB_SECRET in .env.local
43
+ // Setup: github.com → Settings → Developer settings → OAuth Apps
44
+ GitHub({
45
+ clientId: process.env.AUTH_GITHUB_ID!,
46
+ clientSecret: process.env.AUTH_GITHUB_SECRET!,
47
+ }),
48
+
49
+ // ── Email + Password ──────────────────────────────────────────────────────
50
+ // Validates credentials against hashed password in DB
51
+ // TODO: swap the User.findOne() call with your actual DB query
52
+ Credentials({
53
+ name: "credentials",
54
+ credentials: {
55
+ email: { label: "Email", type: "email" },
56
+ password: { label: "Password", type: "password" },
57
+ },
58
+ async authorize(credentials) {
59
+ if (!credentials?.email || !credentials?.password) return null;
60
+
61
+ // TODO: replace this with your actual DB lookup
62
+ // Example with Mongoose:
63
+ // import User from "@/lib/db/models/User";
64
+ // const user = await User.findOne({ email: credentials.email }).select("+password");
65
+ // if (!user || !user.password) return null;
66
+ // const valid = await bcrypt.compare(credentials.password as string, user.password);
67
+ // if (!valid) return null;
68
+ // return { id: user._id.toString(), email: user.email, name: user.name };
69
+
70
+ // Example with Drizzle:
71
+ // import { db } from "@/lib/db";
72
+ // import { users } from "@/lib/db/schema";
73
+ // import { eq } from "drizzle-orm";
74
+ // const [user] = await db.select().from(users).where(eq(users.email, credentials.email as string));
75
+ // if (!user || !user.password) return null;
76
+ // const valid = await bcrypt.compare(credentials.password as string, user.password);
77
+ // if (!valid) return null;
78
+ // return { id: user.id, email: user.email, name: user.name };
79
+
80
+ return null; // replace this line with the above
81
+ },
82
+ }),
83
+ ],
84
+
85
+ callbacks: {
86
+ // ── JWT callback ──────────────────────────────────────────────────────────
87
+ // Runs when JWT is created or updated.
88
+ // Attach extra fields here to make them available in session.
89
+ async jwt({ token, user }) {
90
+ if (user) {
91
+ token.id = user.id;
92
+ token.name = user.name;
93
+ }
94
+ return token;
95
+ },
96
+
97
+ // ── Session callback ──────────────────────────────────────────────────────
98
+ // Runs whenever session is accessed.
99
+ // Pulls fields from JWT token into session.user.
100
+ async session({ session, token }) {
101
+ if (token && session.user) {
102
+ session.user.id = token.id as string;
103
+ session.user.name = token.name as string;
104
+ }
105
+ return session;
106
+ },
107
+ },
108
+
109
+ pages: {
110
+ signIn: "/login", // redirect here when auth is required
111
+ error: "/login", // redirect here on auth errors
112
+ },
113
+
114
+ session: { strategy: "jwt" },
115
+ secret: process.env.AUTH_SECRET,
116
+ });
117
+
118
+ // ─── getCurrentUser ───────────────────────────────────────────────────────────
119
+ // Returns the logged-in user or null.
120
+ // Use when you want to show different UI for logged-in vs logged-out users.
121
+ export async function getCurrentUser() {
122
+ const session = await auth();
123
+ if (!session?.user) return null;
124
+ return session.user;
125
+ }
126
+
127
+ // ─── requireUser ─────────────────────────────────────────────────────────────
128
+ // Returns the logged-in user OR redirects to /login.
129
+ // Use on any protected page — user is guaranteed after this call.
130
+ export async function requireUser() {
131
+ const user = await getCurrentUser();
132
+ if (!user) redirect("/login");
133
+ return user;
134
+ }
135
+
136
+ // ─── signOut ──────────────────────────────────────────────────────────────────
137
+ // Signs the user out and redirects to /.
138
+ // Called from /api/auth/logout route.
139
+ export async function signOut() {
140
+ await nextAuthSignOut({ redirectTo: "/" });
141
+ }
@@ -0,0 +1,40 @@
1
+ // FILE: src/middleware.ts
2
+ // ROUTE: runs on every request before page renders
3
+ // ROLE: NextAuth v5 middleware
4
+ //
5
+ // INJECTED BY CLI when user picks "NextAuth v5"
6
+ // Overwrites base placeholder at src/middleware.ts
7
+ //
8
+ // Does two things:
9
+ // 1. Reads the NextAuth JWT on every request
10
+ // 2. Redirects unauthenticated users away from /dashboard to /login
11
+ // 3. Redirects logged-in users away from /login and /signup to /dashboard
12
+ // ─────────────────────────────────────────────────────────────────────────────
13
+
14
+ import { auth } from "@/src/lib/auth";
15
+ import { NextResponse } from "next/server";
16
+
17
+ export default auth((req) => {
18
+ const isLoggedIn = !!req.auth?.user;
19
+ const { pathname } = req.nextUrl;
20
+
21
+ // Protect /dashboard and all nested routes
22
+ const isProtected = pathname.startsWith("/dashboard");
23
+ if (isProtected && !isLoggedIn) {
24
+ const loginUrl = new URL("/login", req.url);
25
+ loginUrl.searchParams.set("callbackUrl", pathname);
26
+ return NextResponse.redirect(loginUrl);
27
+ }
28
+
29
+ // Redirect logged-in users away from /login and /signup
30
+ const isAuthPage = pathname === "/login" || pathname === "/signup";
31
+ if (isAuthPage && isLoggedIn) {
32
+ return NextResponse.redirect(new URL("/dashboard", req.url));
33
+ }
34
+
35
+ return NextResponse.next();
36
+ });
37
+
38
+ export const config = {
39
+ matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
40
+ };
@@ -1,6 +1,6 @@
1
1
  {
2
- "dependencies": {
3
- "@supabase/ssr": "^0.5.1",
4
- "@supabase/supabase-js": "^2.45.4"
5
- }
6
- }
2
+ "dependencies": {
3
+ "@supabase/ssr": "^0.5.1",
4
+ "@supabase/supabase-js": "^2.45.4"
5
+ }
6
+ }
@@ -0,0 +1,28 @@
1
+ // FILE: src/app/api/auth/login/route.ts
2
+ // ROUTE: POST /api/auth/login
3
+ // ROLE: handles login form submission — called by /login page
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+
6
+ import { NextRequest, NextResponse } from "next/server";
7
+ import { createSupabaseServerClient } from "@/src/lib/supabase/server";
8
+
9
+ export async function POST(req: NextRequest) {
10
+ const { email, password } = await req.json();
11
+
12
+ if (!email || !password) {
13
+ return NextResponse.json(
14
+ { error: "Email and password are required." },
15
+ { status: 400 },
16
+ );
17
+ }
18
+
19
+ const supabase = await createSupabaseServerClient();
20
+
21
+ const { error } = await supabase.auth.signInWithPassword({ email, password });
22
+
23
+ if (error) {
24
+ return NextResponse.json({ error: error.message }, { status: 401 });
25
+ }
26
+
27
+ return NextResponse.json({ success: true });
28
+ }
@@ -0,0 +1,13 @@
1
+ // FILE: src/app/api/auth/logout/route.ts
2
+ // ROUTE: POST /api/auth/logout
3
+ // ROLE: signs the user out — called by LogoutButton component
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+
6
+ import { NextResponse } from "next/server";
7
+ import { createSupabaseServerClient } from "@/src/lib/supabase/server";
8
+
9
+ export async function POST() {
10
+ const supabase = await createSupabaseServerClient();
11
+ await supabase.auth.signOut();
12
+ return NextResponse.json({ success: true });
13
+ }
@@ -0,0 +1,42 @@
1
+ // FILE: src/app/api/auth/signup/route.ts
2
+ // ROUTE: POST /api/auth/signup
3
+ // ROLE: handles signup form submission — called by /signup page
4
+ // ─────────────────────────────────────────────────────────────────────────────
5
+
6
+ import { NextRequest, NextResponse } from "next/server";
7
+ import { createSupabaseServerClient } from "@/src/lib/supabase/server";
8
+
9
+ export async function POST(req: NextRequest) {
10
+ const { name, email, password } = await req.json();
11
+
12
+ if (!email || !password) {
13
+ return NextResponse.json(
14
+ { error: "Email and password are required." },
15
+ { status: 400 },
16
+ );
17
+ }
18
+
19
+ if (password.length < 8) {
20
+ return NextResponse.json(
21
+ { error: "Password must be at least 8 characters." },
22
+ { status: 400 },
23
+ );
24
+ }
25
+
26
+ const supabase = await createSupabaseServerClient();
27
+
28
+ const { error } = await supabase.auth.signUp({
29
+ email,
30
+ password,
31
+ options: {
32
+ data: { name }, // stored in user_metadata
33
+ emailRedirectTo: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard`,
34
+ },
35
+ });
36
+
37
+ if (error) {
38
+ return NextResponse.json({ error: error.message }, { status: 400 });
39
+ }
40
+
41
+ return NextResponse.json({ success: true }, { status: 201 });
42
+ }
@@ -1,75 +1,52 @@
1
1
  // FILE: src/lib/auth/index.ts
2
- // ROUTE: not a route — imported by middleware, dashboard, any protected page
3
- // ROLE: Supabase Auth implementation
2
+ // ROUTE: not a route — imported everywhere auth is needed
3
+ // ROLE: Supabase Auth implementation of the auth contract
4
4
  //
5
5
  // INJECTED BY CLI when user picks "Supabase Auth"
6
- // Replaces base placeholder at src/lib/auth/index.ts
6
+ // Overwrites base placeholder at src/lib/auth/index.ts
7
7
  //
8
- // NO API route needed Supabase handles sessions via cookies automatically.
8
+ // Exports the 3 contract functions every auth block must have:
9
+ // getCurrentUser() — returns user or null
10
+ // requireUser() — returns user or redirects to /login
11
+ // signOut() — signs out and redirects to /
9
12
  // ─────────────────────────────────────────────────────────────────────────────
10
13
 
11
- import { createServerClient } from "@supabase/ssr";
12
- import { cookies } from "next/headers";
14
+ import { createSupabaseServerClient } from "@/src/lib/supabase/server";
13
15
  import { redirect } from "next/navigation";
14
16
 
15
- // ─── Supabase server client ───────────────────────────────────────────────────
16
- // Creates a Supabase client that reads/writes session cookies server-side.
17
- // Called fresh on every request — cookies() gives us the current request's cookies.
18
- export async function createClient() {
19
- const cookieStore = await cookies();
20
-
21
- return createServerClient(
22
- process.env.NEXT_PUBLIC_SUPABASE_URL!,
23
- process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
24
- {
25
- cookies: {
26
- getAll() { return cookieStore.getAll(); },
27
- setAll(toSet) {
28
- try {
29
- toSet.forEach(({ name, value, options }) =>
30
- cookieStore.set(name, value, options)
31
- );
32
- } catch {
33
- // called from Server Component — safe to ignore
34
- }
35
- },
36
- },
37
- }
38
- );
39
- }
40
-
41
17
  // ─── getCurrentUser ───────────────────────────────────────────────────────────
42
- // Returns the logged-in user or null.
43
- // Use this when you want to show different UI for logged-in vs logged-out users.
18
+ // Returns the currently logged-in user, or null if not logged in.
44
19
  //
45
- // Usage in a server component:
20
+ // Use this when you want to show different UI for logged-in vs logged-out:
46
21
  // const user = await getCurrentUser();
47
- // if (user) { ... }
22
+ // if (user) { show dashboard link } else { show login link }
48
23
  export async function getCurrentUser() {
49
- const supabase = await createClient();
50
- const { data: { user }, error } = await supabase.auth.getUser();
51
- if (error || !user) return null;
52
- return user;
24
+ const supabase = await createSupabaseServerClient();
25
+ const {
26
+ data: { user },
27
+ error,
28
+ } = await supabase.auth.getUser();
29
+ if (error || !user) return null;
30
+ return user;
53
31
  }
54
32
 
55
33
  // ─── requireUser ─────────────────────────────────────────────────────────────
56
- // Returns the logged-in user OR redirects to /login.
57
- // Use this on any protected page/route.
34
+ // Returns the logged-in user OR redirects to /login if not authenticated.
58
35
  //
59
- // Usage in a server component:
60
- // const user = await requireUser(); // redirects if not logged in
61
- // // user is guaranteed to exist here
36
+ // Use this on any protected page:
37
+ // const user = await requireUser(); // if not logged in, redirects automatically
38
+ // // user is guaranteed here — safe to use
62
39
  export async function requireUser() {
63
- const user = await getCurrentUser();
64
- if (!user) redirect("/login");
65
- return user;
40
+ const user = await getCurrentUser();
41
+ if (!user) redirect("/login");
42
+ return user;
66
43
  }
67
44
 
68
45
  // ─── signOut ──────────────────────────────────────────────────────────────────
69
- // Signs the user out and redirects to home.
70
- // Call this from a server action or API route.
46
+ // Signs the user out and redirects to /.
47
+ // Called from /api/auth/logout route.
71
48
  export async function signOut() {
72
- const supabase = await createClient();
73
- await supabase.auth.signOut();
74
- redirect("/");
75
- }
49
+ const supabase = await createSupabaseServerClient();
50
+ await supabase.auth.signOut();
51
+ redirect("/");
52
+ }