@shipindays/shipindays 0.1.2 → 0.1.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.

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 +281 -252
  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
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ // FILE: src/lib/supabase/client.ts
4
+ // ROUTE: not a route — imported by "use client" components ONLY
5
+ // ROLE: creates a browser-side Supabase singleton
6
+ //
7
+ // Use this in:
8
+ // - Client components (anything with "use client" at the top)
9
+ // - Login/signup forms
10
+ // - OAuth buttons
11
+ //
12
+ // NEVER use this in server components or API routes — use server.ts instead.
13
+ // ─────────────────────────────────────────────────────────────────────────────
14
+
15
+ import { createBrowserClient } from "@supabase/ssr";
16
+
17
+ // Singleton — reuses the same instance across the app
18
+ // Prevents multiple GoTrue clients warning in dev
19
+ let client: ReturnType<typeof createBrowserClient> | undefined;
20
+
21
+ export function createSupabaseBrowserClient() {
22
+ if (client) return client;
23
+
24
+ client = createBrowserClient(
25
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
26
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
27
+ );
28
+
29
+ return client;
30
+ }
@@ -0,0 +1,40 @@
1
+ // FILE: src/lib/supabase/server.ts
2
+ // ROUTE: not a route — imported by server components and API routes ONLY
3
+ // ROLE: creates a Supabase client that reads session cookies server-side
4
+ //
5
+ // Use this in:
6
+ // - Server components (app/dashboard/page.tsx)
7
+ // - API routes (app/api/*)
8
+ // - middleware.ts
9
+ //
10
+ // NEVER use this in "use client" components — use client.ts instead.
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+
13
+ import { createServerClient } from "@supabase/ssr";
14
+ import { cookies } from "next/headers";
15
+
16
+ export async function createSupabaseServerClient() {
17
+ const cookieStore = await cookies();
18
+
19
+ return createServerClient(
20
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
21
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
22
+ {
23
+ cookies: {
24
+ getAll() {
25
+ return cookieStore.getAll();
26
+ },
27
+ setAll(cookiesToSet) {
28
+ try {
29
+ cookiesToSet.forEach(({ name, value, options }) =>
30
+ cookieStore.set(name, value, options),
31
+ );
32
+ } catch {
33
+ // called from a Server Component — safe to ignore
34
+ // middleware handles cookie refresh instead
35
+ }
36
+ },
37
+ },
38
+ },
39
+ );
40
+ }
@@ -1,9 +1,9 @@
1
1
  // FILE: src/middleware.ts
2
- // ROUTE: runs on every request before the page renders
2
+ // ROUTE: runs on every request before page renders
3
3
  // ROLE: Supabase Auth middleware
4
4
  //
5
5
  // INJECTED BY CLI when user picks "Supabase Auth"
6
- // Replaces base placeholder at src/middleware.ts
6
+ // Overwrites base placeholder at src/middleware.ts
7
7
  //
8
8
  // Does two things:
9
9
  // 1. Refreshes the Supabase session cookie on every request (required by Supabase SSR)
@@ -16,29 +16,35 @@ import { NextRequest, NextResponse } from "next/server";
16
16
  export async function middleware(req: NextRequest) {
17
17
  let res = NextResponse.next({ request: req });
18
18
 
19
- // Create Supabase client that can read + refresh session cookies
19
+ // Create Supabase client that can refresh session cookies
20
20
  const supabase = createServerClient(
21
21
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
22
22
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
23
23
  {
24
24
  cookies: {
25
- getAll() { return req.cookies.getAll(); },
26
- setAll(toSet) {
27
- // Update cookies on both the request and response
28
- toSet.forEach(({ name, value }) => req.cookies.set(name, value));
25
+ getAll() {
26
+ return req.cookies.getAll();
27
+ },
28
+ setAll(cookiesToSet) {
29
+ cookiesToSet.forEach(({ name, value }) =>
30
+ req.cookies.set(name, value),
31
+ );
29
32
  res = NextResponse.next({ request: req });
30
- toSet.forEach(({ name, value, options }) =>
31
- res.cookies.set(name, value, options)
33
+ cookiesToSet.forEach(({ name, value, options }) =>
34
+ res.cookies.set(name, value, options),
32
35
  );
33
36
  },
34
37
  },
35
- }
38
+ },
36
39
  );
37
40
 
38
- // IMPORTANT: always call getUser() in middleware — this refreshes the session
39
- const { data: { user } } = await supabase.auth.getUser();
41
+ // IMPORTANT: always call getUser() in middleware
42
+ // This refreshes the session and keeps cookies up to date
43
+ const {
44
+ data: { user },
45
+ } = await supabase.auth.getUser();
40
46
 
41
- // Protect /dashboard redirect to /login if not authenticated
47
+ // Protect /dashboard and all nested routes
42
48
  const isProtected = req.nextUrl.pathname.startsWith("/dashboard");
43
49
  if (isProtected && !user) {
44
50
  const loginUrl = new URL("/login", req.url);
@@ -46,9 +52,16 @@ export async function middleware(req: NextRequest) {
46
52
  return NextResponse.redirect(loginUrl);
47
53
  }
48
54
 
55
+ // Redirect logged-in users away from /login and /signup
56
+ const isAuthPage =
57
+ req.nextUrl.pathname === "/login" || req.nextUrl.pathname === "/signup";
58
+ if (isAuthPage && user) {
59
+ return NextResponse.redirect(new URL("/dashboard", req.url));
60
+ }
61
+
49
62
  return res;
50
63
  }
51
64
 
52
65
  export const config = {
53
66
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
54
- };
67
+ };
@@ -14,12 +14,18 @@ const resend = new Resend(process.env.RESEND_API_KEY);
14
14
  const FROM = "You <hello@yourdomain.com>"; // TODO: replace with your verified Resend domain
15
15
 
16
16
  // ─── sendWelcomeEmail ─────────────────────────────────────────────────────────
17
- export async function sendWelcomeEmail({ to, name }: { to: string; name: string }) {
18
- await resend.emails.send({
19
- from: FROM,
20
- to,
21
- subject: "Welcome! 🎉",
22
- html: `
17
+ export async function sendWelcomeEmail({
18
+ to,
19
+ name,
20
+ }: {
21
+ to: string;
22
+ name: string;
23
+ }) {
24
+ await resend.emails.send({
25
+ from: FROM,
26
+ to,
27
+ subject: "Welcome! 🎉",
28
+ html: `
23
29
  <div style="font-family:sans-serif;max-width:560px;margin:0 auto;padding:40px 20px">
24
30
  <h1 style="font-size:24px;color:#111">Hey ${name}, welcome aboard!</h1>
25
31
  <p style="color:#555;line-height:1.7">Your account is ready. Click below to get started.</p>
@@ -29,16 +35,22 @@ export async function sendWelcomeEmail({ to, name }: { to: string; name: string
29
35
  </a>
30
36
  </div>
31
37
  `,
32
- });
38
+ });
33
39
  }
34
40
 
35
41
  // ─── sendPasswordResetEmail ───────────────────────────────────────────────────
36
- export async function sendPasswordResetEmail({ to, resetUrl }: { to: string; resetUrl: string }) {
37
- await resend.emails.send({
38
- from: FROM,
39
- to,
40
- subject: "Reset your password",
41
- html: `
42
+ export async function sendPasswordResetEmail({
43
+ to,
44
+ resetUrl,
45
+ }: {
46
+ to: string;
47
+ resetUrl: string;
48
+ }) {
49
+ await resend.emails.send({
50
+ from: FROM,
51
+ to,
52
+ subject: "Reset your password",
53
+ html: `
42
54
  <div style="font-family:sans-serif;max-width:560px;margin:0 auto;padding:40px 20px">
43
55
  <h1 style="font-size:24px;color:#111">Reset your password</h1>
44
56
  <p style="color:#555;line-height:1.7">Click below to reset your password. Link expires in 1 hour.</p>
@@ -49,5 +61,5 @@ export async function sendPasswordResetEmail({ to, resetUrl }: { to: string; res
49
61
  <p style="margin-top:24px;color:#999;font-size:12px">If you didn't request this, ignore this email.</p>
50
62
  </div>
51
63
  `,
52
- });
53
- }
64
+ });
65
+ }
@@ -1,19 +0,0 @@
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 exists when user picks NextAuth.
6
- // Supabase block does NOT have this file so it never gets created.
7
- //
8
- // Handles all NextAuth endpoints automatically:
9
- // GET /api/auth/session
10
- // GET /api/auth/csrf
11
- // GET /api/auth/providers
12
- // POST /api/auth/signin
13
- // POST /api/auth/signout
14
- // GET /api/auth/callback/:provider ← OAuth redirect comes back here
15
- // ─────────────────────────────────────────────────────────────────────────────
16
-
17
- import { handlers } from "@/lib/auth";
18
-
19
- export const { GET, POST } = handlers;
@@ -1,98 +0,0 @@
1
- // FILE: src/lib/auth/index.ts
2
- // ROUTE: not a route — imported by middleware, dashboard, API routes
3
- // ROLE: NextAuth v5 implementation
4
- //
5
- // INJECTED BY CLI when user picks "NextAuth v5"
6
- // Replaces base placeholder at src/lib/auth/index.ts
7
- //
8
- // NextAuth DOES need an API route: src/app/api/auth/[...nextauth]/route.ts
9
- // That file is also included in this block and gets copied automatically.
10
- // ─────────────────────────────────────────────────────────────────────────────
11
-
12
- import NextAuth from "next-auth";
13
- import GitHub from "next-auth/providers/github";
14
- import Google from "next-auth/providers/google";
15
- import Credentials from "next-auth/providers/credentials";
16
- import { redirect } from "next/navigation";
17
-
18
- // ─── NextAuth config ──────────────────────────────────────────────────────────
19
- // handlers → used by /api/auth/[...nextauth]/route.ts
20
- // auth → used by middleware + server components to read the session
21
- // signIn → used by login page
22
- // signOut → used by logout button
23
- export const { handlers, auth, signIn: nextAuthSignIn, signOut: nextAuthSignOut } = NextAuth({
24
- providers: [
25
- Google({
26
- clientId: process.env.AUTH_GOOGLE_ID!,
27
- clientSecret: process.env.AUTH_GOOGLE_SECRET!,
28
- }),
29
- GitHub({
30
- clientId: process.env.AUTH_GITHUB_ID!,
31
- clientSecret: process.env.AUTH_GITHUB_SECRET!,
32
- }),
33
- Credentials({
34
- name: "credentials",
35
- credentials: {
36
- email: { label: "Email", type: "email" },
37
- password: { label: "Password", type: "password" },
38
- },
39
- async authorize(credentials) {
40
- // TODO: validate credentials against your database
41
- // Example with your User model:
42
- // const user = await User.findOne({ email: credentials.email })
43
- // const valid = await bcrypt.compare(credentials.password, user.password)
44
- // if (!valid) return null
45
- // return { id: user._id, email: user.email, name: user.name }
46
- return null;
47
- },
48
- }),
49
- ],
50
-
51
- callbacks: {
52
- // Attach user id to the JWT token so we can read it in session
53
- async jwt({ token, user }) {
54
- if (user) token.id = user.id;
55
- return token;
56
- },
57
- // Attach user id from token to the session object
58
- async session({ session, token }) {
59
- if (token && session.user) session.user.id = token.id as string;
60
- return session;
61
- },
62
- },
63
-
64
- pages: {
65
- signIn: "/login", // redirect here when auth is required
66
- error: "/login", // redirect here on auth errors
67
- },
68
-
69
- session: { strategy: "jwt" },
70
- secret: process.env.AUTH_SECRET,
71
- });
72
-
73
- // ─────────────────────────────────────────────────────────────────────────────
74
- // THE CONTRACT — same 3 functions as Supabase block
75
- // Rest of app calls these, never touches NextAuth directly
76
- // ─────────────────────────────────────────────────────────────────────────────
77
-
78
- // ─── getCurrentUser ───────────────────────────────────────────────────────────
79
- // Returns the logged-in user or null.
80
- export async function getCurrentUser() {
81
- const session = await auth();
82
- if (!session?.user) return null;
83
- return session.user;
84
- }
85
-
86
- // ─── requireUser ─────────────────────────────────────────────────────────────
87
- // Returns the logged-in user OR redirects to /login.
88
- export async function requireUser() {
89
- const user = await getCurrentUser();
90
- if (!user) redirect("/login");
91
- return user;
92
- }
93
-
94
- // ─── signOut ──────────────────────────────────────────────────────────────────
95
- // Signs the user out and redirects to home.
96
- export async function signOut() {
97
- await nextAuthSignOut({ redirectTo: "/" });
98
- }
@@ -1,30 +0,0 @@
1
- // FILE: src/middleware.ts
2
- // ROUTE: runs on every request before the page renders
3
- // ROLE: NextAuth v5 middleware
4
- //
5
- // INJECTED BY CLI when user picks "NextAuth v5"
6
- // Replaces base placeholder at src/middleware.ts
7
- //
8
- // Reads the NextAuth JWT and redirects unauthenticated users
9
- // away from /dashboard to /login.
10
- // ─────────────────────────────────────────────────────────────────────────────
11
-
12
- import { auth } from "@/lib/auth";
13
- import { NextResponse } from "next/server";
14
-
15
- export default auth((req) => {
16
- const isLoggedIn = !!req.auth?.user;
17
- const isProtected = req.nextUrl.pathname.startsWith("/dashboard");
18
-
19
- if (isProtected && !isLoggedIn) {
20
- const loginUrl = new URL("/login", req.url);
21
- loginUrl.searchParams.set("callbackUrl", req.nextUrl.pathname);
22
- return NextResponse.redirect(loginUrl);
23
- }
24
-
25
- return NextResponse.next();
26
- });
27
-
28
- export const config = {
29
- matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
30
- };