stackkit 0.3.4 → 0.3.5

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.
@@ -12,10 +12,10 @@ const router = Router()
12
12
 
13
13
  router.post("/register", authController.registerUser)
14
14
  router.post("/login", authController.loginUser)
15
- router.get("/me", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.getMe)
15
+ router.get("/me", authorize(Role.ADMIN, Role.USER), authController.getMe)
16
16
  router.post("/refresh-token", authController.getNewToken)
17
- router.post("/change-password", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.changePassword)
18
- router.post("/logout", authorize(Role.ADMIN, Role.USER, Role.SUPER_ADMIN), authController.logoutUser)
17
+ router.post("/change-password", authorize(Role.ADMIN, Role.USER), authController.changePassword)
18
+ router.post("/logout", authorize(Role.ADMIN, Role.USER), authController.logoutUser)
19
19
  router.post("/verify-email", authController.verifyEmail)
20
20
  router.post("/forget-password", authController.forgetPassword)
21
21
  router.post("/reset-password", authController.resetPassword)
@@ -24,6 +24,18 @@ import {
24
24
  const registerUser = async (payload: IRegisterUserPayload) => {
25
25
  const { name, email, password } = payload;
26
26
 
27
+ if (email) {
28
+ const existingUser = await prisma.user.findUnique({
29
+ where: {
30
+ email: email,
31
+ },
32
+ });
33
+
34
+ if (existingUser) {
35
+ throw new AppError(status.CONFLICT, "Email already exists");
36
+ }
37
+ }
38
+
27
39
  const data = await auth.api.signUpEmail({
28
40
  body: {
29
41
  name,
@@ -19,6 +19,6 @@
19
19
  <script>
20
20
  document.getElementById("social-login-form")?.submit();
21
21
  </script>
22
- </body>
22
+ </body>
23
23
 
24
24
  </html>
@@ -10,16 +10,6 @@ export async function getSession() {
10
10
  return session;
11
11
  }
12
12
 
13
- export async function requireSuperAdmin() {
14
- const session = await getSession();
15
-
16
- if (!session || session.user.role !== "SUPER_ADMIN") {
17
- redirect("/login");
18
- }
19
-
20
- return session.user;
21
- }
22
-
23
13
  export async function requireAdmin() {
24
14
  const session = await getSession();
25
15
 
@@ -1,23 +1,45 @@
1
- import { NextResponse, type NextRequest } from "next/server";
1
+ import { NextRequest, NextResponse } from "next/server";
2
2
 
3
- function isAuthenticated(req: NextRequest) {
4
- const token = req.cookies.get("better-auth.session_token")?.value;
3
+ export async function proxy(request: NextRequest) {
4
+ const { pathname, search } = request.nextUrl;
5
5
 
6
- return Boolean(token);
7
- }
6
+ let isAuthenticated = false;
7
+ let isAdmin = false;
8
+
9
+ // Mock user data for demonstration purposes replace this with actual authentication session logic
10
+ const data = {
11
+ name: "John Doe",
12
+ email: "john.doe@example.com",
13
+ role: "ADMIN",
14
+ };
15
+
16
+ if (data) {
17
+ isAuthenticated = true;
18
+ const role = data?.role;
19
+ isAdmin = role === "ADMIN";
20
+ }
8
21
 
9
- export function proxy(req: NextRequest) {
10
- const { pathname, search } = req.nextUrl;
11
- const authed = isAuthenticated(req);
22
+ if (
23
+ pathname === "/login" ||
24
+ pathname === "/register" ||
25
+ pathname === "/signup"
26
+ ) {
27
+ if (isAuthenticated) {
28
+ if (isAdmin) {
29
+ return NextResponse.redirect(new URL("/dashboard/admin", request.url));
30
+ }
12
31
 
13
- if (pathname === "/login" || pathname === "/signup") {
14
- if (authed) return NextResponse.redirect(new URL("/dashboard", req.url));
32
+ return NextResponse.redirect(new URL("/dashboard", request.url));
33
+ }
15
34
  return NextResponse.next();
16
35
  }
17
36
 
18
- if (pathname.startsWith("/dashboard") && !authed) {
37
+ if (pathname.startsWith("/dashboard") && !isAuthenticated) {
19
38
  const next = encodeURIComponent(pathname + (search || ""));
20
- return NextResponse.redirect(new URL(`/login?next=${next}`, req.url));
39
+ const res = NextResponse.redirect(
40
+ new URL(`/login?next=${next}`, request.url),
41
+ );
42
+ return res;
21
43
  }
22
44
 
23
45
  return NextResponse.next();
@@ -28,6 +50,7 @@ export const config = {
28
50
  "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
29
51
  "/(api|trpc)(.*)",
30
52
  "/login",
53
+ "/register",
31
54
  "/signup",
32
55
  "/dashboard/:path*",
33
56
  ],
@@ -8,6 +8,7 @@ dotenv.config({ path: path.join(process.cwd(), ".env") });
8
8
  {{/if}}
9
9
 
10
10
  interface EnvConfig {
11
+ APP_NAME?: string;
11
12
  APP_URL: string;
12
13
  {{#if framework == "nextjs"}}
13
14
  API_URL: string;
@@ -35,8 +36,6 @@ interface EnvConfig {
35
36
  ACCESS_TOKEN_EXPIRES_IN: string;
36
37
  REFRESH_TOKEN_SECRET: string;
37
38
  REFRESH_TOKEN_EXPIRES_IN: string;
38
- SUPER_ADMIN_EMAIL: string;
39
- SUPER_ADMIN_PASSWORD: string;
40
39
  {{/if}}
41
40
  }
42
41
 
@@ -67,8 +66,6 @@ const loadEnvVars = (): EnvConfig => {
67
66
  "ACCESS_TOKEN_EXPIRES_IN",
68
67
  "REFRESH_TOKEN_SECRET",
69
68
  "REFRESH_TOKEN_EXPIRES_IN",
70
- "SUPER_ADMIN_EMAIL",
71
- "SUPER_ADMIN_PASSWORD",
72
69
  {{/if}}
73
70
  ];
74
71
 
@@ -88,9 +85,10 @@ const loadEnvVars = (): EnvConfig => {
88
85
  });
89
86
 
90
87
  return {
91
- APP_URL: process.env.APP_URL as string,
92
88
  {{#if framework == "nextjs"}}
93
- API_URL: process.env.API_URL as string,
89
+ APP_NAME: process.env.NEXT_PUBLIC_APP_NAME ?? "Your App",
90
+ APP_URL: process.env.NEXT_PUBLIC_APP_URL as string,
91
+ API_URL: process.env.NEXT_PUBLIC_API_URL as string,
94
92
  {{/if}}
95
93
  DATABASE_URL: process.env.DATABASE_URL as string,
96
94
  FRONTEND_URL: process.env.FRONTEND_URL as string,
@@ -107,9 +105,11 @@ const loadEnvVars = (): EnvConfig => {
107
105
  SMTP_FROM: process.env.EMAIL_SENDER_SMTP_FROM as string,
108
106
  },
109
107
  {{#if framework == "express" }}
108
+ APP_NAME: process.env.APP_NAME ?? "Your App",
109
+ APP_URL: process.env.APP_URL as string,
110
110
  NODE_ENV: process.env.NODE_ENV as string,
111
111
  PORT: process.env.PORT as string,
112
- BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN: process.env
112
+ BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN: process.env
113
113
  .BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN as string,
114
114
  BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE: process.env
115
115
  .BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE as string,
@@ -117,8 +117,6 @@ const loadEnvVars = (): EnvConfig => {
117
117
  ACCESS_TOKEN_EXPIRES_IN: process.env.ACCESS_TOKEN_EXPIRES_IN as string,
118
118
  REFRESH_TOKEN_SECRET: process.env.REFRESH_TOKEN_SECRET as string,
119
119
  REFRESH_TOKEN_EXPIRES_IN: process.env.REFRESH_TOKEN_EXPIRES_IN as string,
120
- SUPER_ADMIN_EMAIL: process.env.SUPER_ADMIN_EMAIL as string,
121
- SUPER_ADMIN_PASSWORD: process.env.SUPER_ADMIN_PASSWORD as string,
122
120
  {{/if}}
123
121
  };
124
122
  };
@@ -133,20 +133,14 @@ export const auth = betterAuth({
133
133
  return;
134
134
  }
135
135
 
136
- if (user && user.role === Role.SUPER_ADMIN) {
137
- console.log(
138
- `User with email ${email} is a super admin. Skipping sending verification OTP.`,
139
- );
140
- return;
141
- }
142
-
143
136
  if (user && !user.emailVerified) {
144
137
  sendEmail({
145
138
  to: email,
146
139
  subject: "Verify your email",
147
140
  templateName: "otp",
148
141
  templateData: {
149
- name: user.name,
142
+ userName: user.name,
143
+ appName: envVars.APP_NAME as string,
150
144
  otp,
151
145
  },
152
146
  });
@@ -169,14 +163,15 @@ export const auth = betterAuth({
169
163
  subject: "Password Reset OTP",
170
164
  templateName: "otp",
171
165
  templateData: {
172
- name: user.name,
166
+ userName: user.name,
167
+ appName: envVars.APP_NAME as string,
173
168
  otp,
174
169
  },
175
170
  });
176
171
  }
177
172
  }
178
173
  },
179
- expiresIn: 2 * 60, // 2 minutes in seconds
174
+ expiresIn: 5 * 60, // 5 minutes in seconds
180
175
  otpLength: 6,
181
176
  }),
182
177
  ],
@@ -1,7 +1,6 @@
1
1
  export const Role = {
2
2
  ADMIN: "ADMIN",
3
3
  USER: "USER",
4
- SUPER_ADMIN: "SUPER_ADMIN",
5
4
  } as const;
6
5
 
7
6
  export const UserStatus = {
@@ -1,5 +1,4 @@
1
1
  enum Role {
2
- SUPER_ADMIN
3
2
  ADMIN
4
3
  USER
5
4
  }
@@ -21,6 +21,8 @@ const transporter = nodemailer.createTransport({
21
21
  port: Number(envVars.EMAIL_SENDER.SMTP_PORT),
22
22
  });
23
23
 
24
+ transporter.verify().catch(() => null);
25
+
24
26
  interface SendEmailOptions {
25
27
  to: string;
26
28
  subject: string;
@@ -42,12 +44,27 @@ export const sendEmail = async ({
42
44
  }: SendEmailOptions) => {
43
45
  try {
44
46
  {{#if framework == "express"}}
45
- const templatePath = path.resolve(
47
+ const templatePath = path.resolve(
46
48
  process.cwd(),
47
49
  `src/templates/${templateName}.ejs`,
48
50
  );
49
51
 
50
- const html = await ejs.renderFile(templatePath, templateData);
52
+ const td = templateData as Record<string, unknown>;
53
+ const expiresVal =
54
+ td && Object.prototype.hasOwnProperty.call(td, "expiresInMinutes")
55
+ ? td["expiresInMinutes"]
56
+ : undefined;
57
+ const expiresInMinutes = typeof expiresVal === "number" ? expiresVal : 5;
58
+
59
+ const templateDataWithDefaults: Record<string, unknown> = {
60
+ appName: envVars.APP_NAME ?? "Your App",
61
+ supportEmail: envVars.SUPER_ADMIN_EMAIL ?? "support@example.com",
62
+ year: new Date().getFullYear(),
63
+ expiresInMinutes,
64
+ ...td,
65
+ };
66
+
67
+ const html = await ejs.renderFile(templatePath, templateDataWithDefaults);
51
68
  {{/if}}
52
69
  {{#if framework == "nextjs"}}
53
70
  const html = renderEmailTemplate(templateName, templateData);
@@ -123,6 +123,7 @@
123
123
  "type": "add-env",
124
124
  "condition": { "framework": "express" },
125
125
  "envVars": {
126
+ "APP_NAME": "Your App",
126
127
  "BETTER_AUTH_URL": "http://localhost:3000",
127
128
  "BETTER_AUTH_SECRET": "your_better_auth_secret",
128
129
  "BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN": "1d",
@@ -138,9 +139,7 @@
138
139
  "EMAIL_SENDER_SMTP_PASS": "your_email_password",
139
140
  "EMAIL_SENDER_SMTP_HOST": "smtp.gmail.com",
140
141
  "EMAIL_SENDER_SMTP_PORT": "465",
141
- "EMAIL_SENDER_SMTP_FROM": "your_email@gmail.com",
142
- "SUPER_ADMIN_EMAIL": "your_email@gmail.com",
143
- "SUPER_ADMIN_PASSWORD": "your_super_admin_password"
142
+ "EMAIL_SENDER_SMTP_FROM": "your_email@gmail.com"
144
143
  }
145
144
  },
146
145
  {
@@ -201,6 +200,7 @@
201
200
  "type": "add-env",
202
201
  "condition": { "framework": "nextjs" },
203
202
  "envVars": {
203
+ "NEXT_PUBLIC_APP_NAME": "Your App",
204
204
  "NEXT_PUBLIC_APP_URL": "http://localhost:3000",
205
205
  "NEXT_PUBLIC_FRONTEND_URL": "http://localhost:3000",
206
206
  "NEXT_PUBLIC_BETTER_AUTH_URL": "http://localhost:3000",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Production-ready CLI to create and extend JavaScript or TypeScript apps with modular stacks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -1,17 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
- esac
7
-
8
- if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules"
10
- else
11
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/acorn@8.15.0/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules:$NODE_PATH"
12
- fi
13
- if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/bin/acorn" "$@"
15
- else
16
- exec node "$basedir/../../../../node_modules/.pnpm/acorn@8.15.0/node_modules/acorn/bin/acorn" "$@"
17
- fi
@@ -1,17 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
- esac
7
-
8
- if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules"
10
- else
11
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/eslint@9.39.2/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules:$NODE_PATH"
12
- fi
13
- if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/bin/eslint.js" "$@"
15
- else
16
- exec node "$basedir/../../../../node_modules/.pnpm/eslint@9.39.2/node_modules/eslint/bin/eslint.js" "$@"
17
- fi
@@ -1,17 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
- esac
7
-
8
- if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules"
10
- else
11
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules:$NODE_PATH"
12
- fi
13
- if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
15
- else
16
- exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsc" "$@"
17
- fi
@@ -1,17 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
- esac
7
-
8
- if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules"
10
- else
11
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/typescript@5.9.3/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules:$NODE_PATH"
12
- fi
13
- if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
15
- else
16
- exec node "$basedir/../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/bin/tsserver" "$@"
17
- fi
@@ -1,17 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
6
- esac
7
-
8
- if [ -z "$NODE_PATH" ]; then
9
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules"
10
- else
11
- export NODE_PATH="/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/tsx@4.21.0/node_modules:/home/tariqul/Projects/open-source/stackkit/node_modules/.pnpm/node_modules:$NODE_PATH"
12
- fi
13
- if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
15
- else
16
- exec node "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
17
- fi
@@ -1,6 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
4
-
5
- // NOTE: This file should not be edited
6
- // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.