stackkit 0.2.8 → 0.2.9

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 (61) hide show
  1. package/README.md +4 -0
  2. package/dist/lib/fs/files.js +1 -1
  3. package/dist/lib/generation/code-generator.d.ts +2 -7
  4. package/dist/lib/generation/code-generator.js +120 -56
  5. package/dist/lib/utils/fs-helpers.d.ts +1 -1
  6. package/modules/auth/authjs/generator.json +16 -16
  7. package/modules/auth/better-auth/files/express/middlewares/authorize.ts +121 -41
  8. package/modules/auth/better-auth/files/express/modules/auth/auth.controller.ts +257 -0
  9. package/modules/auth/better-auth/files/express/modules/auth/auth.interface.ts +23 -0
  10. package/modules/auth/better-auth/files/express/modules/auth/auth.route.ts +22 -0
  11. package/modules/auth/better-auth/files/express/modules/auth/auth.service.ts +403 -0
  12. package/modules/auth/better-auth/files/express/templates/google-redirect.ejs +91 -0
  13. package/modules/auth/better-auth/files/express/templates/otp.ejs +87 -0
  14. package/modules/auth/better-auth/files/express/types/express.d.ts +6 -8
  15. package/modules/auth/better-auth/files/express/utils/cookie.ts +19 -0
  16. package/modules/auth/better-auth/files/express/utils/jwt.ts +34 -0
  17. package/modules/auth/better-auth/files/express/utils/token.ts +66 -0
  18. package/modules/auth/better-auth/files/nextjs/api/auth/[...all]/route.ts +1 -1
  19. package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +11 -1
  20. package/modules/auth/better-auth/files/nextjs/templates/email-otp.tsx +74 -0
  21. package/modules/auth/better-auth/files/shared/config/env.ts +113 -0
  22. package/modules/auth/better-auth/files/shared/lib/auth-client.ts +1 -1
  23. package/modules/auth/better-auth/files/shared/lib/auth.ts +151 -62
  24. package/modules/auth/better-auth/files/shared/prisma/schema.prisma +22 -11
  25. package/modules/auth/better-auth/files/shared/utils/email.ts +71 -0
  26. package/modules/auth/better-auth/generator.json +159 -81
  27. package/modules/database/mongoose/generator.json +18 -18
  28. package/modules/database/prisma/generator.json +44 -44
  29. package/package.json +1 -1
  30. package/templates/express/env.example +2 -2
  31. package/templates/express/eslint.config.mjs +7 -0
  32. package/templates/express/node_modules/.bin/acorn +17 -0
  33. package/templates/express/node_modules/.bin/eslint +17 -0
  34. package/templates/express/node_modules/.bin/tsc +17 -0
  35. package/templates/express/node_modules/.bin/tsserver +17 -0
  36. package/templates/express/node_modules/.bin/tsx +17 -0
  37. package/templates/express/package.json +12 -6
  38. package/templates/express/src/app.ts +15 -7
  39. package/templates/express/src/config/cors.ts +8 -7
  40. package/templates/express/src/config/env.ts +26 -5
  41. package/templates/express/src/config/logger.ts +2 -2
  42. package/templates/express/src/config/rate-limit.ts +2 -2
  43. package/templates/express/src/modules/health/health.controller.ts +13 -11
  44. package/templates/express/src/routes/index.ts +1 -6
  45. package/templates/express/src/server.ts +12 -12
  46. package/templates/express/src/shared/errors/app-error.ts +16 -0
  47. package/templates/express/src/shared/middlewares/error.middleware.ts +154 -12
  48. package/templates/express/src/shared/middlewares/not-found.middleware.ts +2 -1
  49. package/templates/express/src/shared/utils/catch-async.ts +11 -0
  50. package/templates/express/src/shared/utils/pagination.ts +6 -1
  51. package/templates/express/src/shared/utils/send-response.ts +25 -0
  52. package/templates/nextjs/lib/env.ts +19 -8
  53. package/modules/auth/better-auth/files/shared/lib/email/email-service.ts +0 -33
  54. package/modules/auth/better-auth/files/shared/lib/email/email-templates.ts +0 -89
  55. package/templates/express/eslint.config.cjs +0 -42
  56. package/templates/express/src/config/helmet.ts +0 -5
  57. package/templates/express/src/modules/health/health.service.ts +0 -6
  58. package/templates/express/src/shared/errors/error-codes.ts +0 -9
  59. package/templates/express/src/shared/logger/logger.ts +0 -20
  60. package/templates/express/src/shared/utils/async-handler.ts +0 -9
  61. package/templates/express/src/shared/utils/response.ts +0 -9
@@ -0,0 +1,91 @@
1
+ <!doctype html>
2
+ <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
+
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
8
+ <title>
9
+ <%= appName || "Your App" %> - Continue with Google
10
+ </title>
11
+ </head>
12
+
13
+ <body style="margin:0; padding:0; background-color:#f3f4f6;">
14
+ <div style="display:none; max-height:0; overflow:hidden; opacity:0; color:transparent;">
15
+ Continue your Google sign-in securely.
16
+ </div>
17
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
18
+ style="background-color:#f3f4f6; padding:24px 12px;">
19
+ <tr>
20
+ <td align="center">
21
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
22
+ style="max-width:600px; background:#ffffff; border:1px solid #e5e7eb; border-radius:12px; overflow:hidden;">
23
+ <tr>
24
+ <td style="padding:28px 24px 16px 24px; font-family:Arial, Helvetica, sans-serif; color:#111827;">
25
+ <h1 style="margin:0; font-size:22px; line-height:30px; font-weight:700;">Continue with
26
+ Google</h1>
27
+ <p style="margin:14px 0 0; font-size:15px; line-height:24px; color:#374151;">
28
+ Hi <%= userName || "there" %>,
29
+ </p>
30
+ <p style="margin:10px 0 0; font-size:15px; line-height:24px; color:#374151;">
31
+ We received a request to continue authentication with Google for your <strong>
32
+ <%= appName || "account" %>
33
+ </strong>.
34
+ </p>
35
+ </td>
36
+ </tr>
37
+
38
+ <tr>
39
+ <td style="padding:0 24px 24px 24px; font-family:Arial, Helvetica, sans-serif;">
40
+ <table role="presentation" cellspacing="0" cellpadding="0" border="0">
41
+ <tr>
42
+ <td align="center" bgcolor="#111827" style="border-radius:8px;">
43
+ <a href="<%= redirectUrl %>" target="_blank"
44
+ style="display:inline-block; padding:12px 22px; font-size:15px; line-height:20px; font-weight:600; color:#ffffff; text-decoration:none;">
45
+ Continue Sign-in
46
+ </a>
47
+ </td>
48
+ </tr>
49
+ </table>
50
+
51
+ <p
52
+ style="margin:14px 0 0; font-size:13px; line-height:20px; color:#6b7280; word-break:break-word;">
53
+ Button not working? Copy and paste this URL into your browser:<br />
54
+ <a href="<%= redirectUrl %>" target="_blank"
55
+ style="color:#2563eb; text-decoration:underline;">
56
+ <%= redirectUrl %>
57
+ </a>
58
+ </p>
59
+ </td>
60
+ </tr>
61
+
62
+ <tr>
63
+ <td style="padding:0 24px 24px 24px; font-family:Arial, Helvetica, sans-serif; color:#4b5563;">
64
+ <p style="margin:0; font-size:14px; line-height:22px;">
65
+ If you didn’t request this, you can safely ignore this email. No changes will be made
66
+ unless you continue.
67
+ </p>
68
+ </td>
69
+ </tr>
70
+
71
+ <tr>
72
+ <td
73
+ style="padding:16px 24px 24px 24px; border-top:1px solid #e5e7eb; font-family:Arial, Helvetica, sans-serif; color:#6b7280;">
74
+ <p style="margin:0; font-size:12px; line-height:18px;">
75
+ Need help? Contact us at
76
+ <a href="mailto:<%= supportEmail || " support@example.com" %>" style="color:#2563eb;
77
+ text-decoration:underline;"><%= supportEmail || "support@example.com" %></a>.
78
+ </p>
79
+ <p style="margin:6px 0 0; font-size:12px; line-height:18px;">
80
+ © <%= year || new Date().getFullYear() %>
81
+ <%= appName || "Your App" %>. All rights reserved.
82
+ </p>
83
+ </td>
84
+ </tr>
85
+ </table>
86
+ </td>
87
+ </tr>
88
+ </table>
89
+ </body>
90
+
91
+ </html>
@@ -0,0 +1,87 @@
1
+ <!doctype html>
2
+ <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
+
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
8
+ <title>
9
+ <%= appName || "Your App" %> - Your OTP Code
10
+ </title>
11
+ </head>
12
+
13
+ <body style="margin:0; padding:0; background-color:#f3f4f6;">
14
+ <div style="display:none; max-height:0; overflow:hidden; opacity:0; color:transparent;">
15
+ Your one-time verification code is ready.
16
+ </div>
17
+
18
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
19
+ style="background-color:#f3f4f6; padding:24px 12px;">
20
+ <tr>
21
+ <td align="center">
22
+ <table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0"
23
+ style="max-width:600px; background:#ffffff; border:1px solid #e5e7eb; border-radius:12px; overflow:hidden;">
24
+ <tr>
25
+ <td
26
+ style="padding:28px 24px 16px 24px; font-family:Arial, Helvetica, sans-serif; color:#111827;">
27
+ <h1 style="margin:0; font-size:22px; line-height:30px; font-weight:700;">Verification Code
28
+ </h1>
29
+ <p style="margin:14px 0 0; font-size:15px; line-height:24px; color:#374151;">
30
+ Hi <%= userName || "there" %>,
31
+ </p>
32
+ <p style="margin:10px 0 0; font-size:15px; line-height:24px; color:#374151;">
33
+ Use the one-time password (OTP) below to verify your identity for <strong>
34
+ <%= appName || "your account" %>
35
+ </strong>.
36
+ </p>
37
+ </td>
38
+ </tr>
39
+
40
+ <tr>
41
+ <td align="center"
42
+ style="padding:8px 24px 20px 24px; font-family:Arial, Helvetica, sans-serif;">
43
+ <div
44
+ style="display:inline-block; padding:12px 20px; border-radius:10px; border:1px solid #d1d5db; background:#f9fafb; letter-spacing:7px; font-size:28px; line-height:34px; font-weight:700; color:#111827;">
45
+ <%= otp %>
46
+ </div>
47
+ </td>
48
+ </tr>
49
+
50
+ <tr>
51
+ <td style="padding:0 24px 22px 24px; font-family:Arial, Helvetica, sans-serif; color:#4b5563;">
52
+ <p style="margin:0; font-size:14px; line-height:22px;">
53
+ This code will expire in <strong>
54
+ <%= expiresInMinutes || 2 %> minutes
55
+ </strong>.
56
+ </p>
57
+ <p style="margin:10px 0 0; font-size:14px; line-height:22px;">
58
+ If you didn’t request this code, please ignore this email and consider changing your
59
+ password.
60
+ </p>
61
+ </td>
62
+ </tr>
63
+
64
+ <tr>
65
+ <td
66
+ style="padding:16px 24px 24px 24px; border-top:1px solid #e5e7eb; font-family:Arial, Helvetica, sans-serif; color:#6b7280;">
67
+ <p style="margin:0; font-size:12px; line-height:18px;">
68
+ For security, never share this OTP with anyone.
69
+ </p>
70
+ <p style="margin:6px 0 0; font-size:12px; line-height:18px;">
71
+ Need help? Contact
72
+ <a href="mailto:<%= supportEmail || " support@example.com" %>" style="color:#2563eb;
73
+ text-decoration:underline;"><%= supportEmail || "support@example.com" %></a>.
74
+ </p>
75
+ <p style="margin:6px 0 0; font-size:12px; line-height:18px;">
76
+ © <%= year || new Date().getFullYear() %>
77
+ <%= appName || "Your App" %>. All rights reserved.
78
+ </p>
79
+ </td>
80
+ </tr>
81
+ </table>
82
+ </td>
83
+ </tr>
84
+ </table>
85
+ </body>
86
+
87
+ </html>
@@ -1,16 +1,14 @@
1
1
  declare global {
2
2
  namespace Express {
3
3
  interface Request {
4
- user?: {
5
- id: string;
6
- email: string;
7
- name: string;
8
- role: string;
9
- emailVerified: boolean;
10
- }
4
+ user: {
5
+ id: string;
6
+ name: string;
7
+ email: string;
8
+ role: string;
9
+ };
11
10
  }
12
11
  }
13
12
  }
14
13
 
15
14
  export { };
16
-
@@ -0,0 +1,19 @@
1
+ import { CookieOptions, Request, Response } from "express";
2
+
3
+ const setCookie = (res: Response, key: string, value: string, options: CookieOptions) => {
4
+ res.cookie(key, value, options);
5
+ }
6
+
7
+ const getCookie = (req: Request, key: string) => {
8
+ return req.cookies[key];
9
+ }
10
+
11
+ const clearCookie = (res: Response, key: string, options: CookieOptions) => {
12
+ res.clearCookie(key, options);
13
+ }
14
+
15
+ export const cookieUtils = {
16
+ setCookie,
17
+ getCookie,
18
+ clearCookie,
19
+ }
@@ -0,0 +1,34 @@
1
+ import jwt, { JwtPayload, SignOptions } from "jsonwebtoken";
2
+
3
+ const createToken = (payload: JwtPayload, secret: string, { expiresIn }: SignOptions) => {
4
+ const token = jwt.sign(payload, secret, { expiresIn });
5
+ return token;
6
+ }
7
+
8
+ const verifyToken = (token: string, secret: string) => {
9
+ try {
10
+ const decoded = jwt.verify(token, secret) as JwtPayload;
11
+ return {
12
+ success: true,
13
+ data: decoded
14
+ }
15
+ } catch (error: unknown) {
16
+ const message = error instanceof Error ? error.message : "Unknown error";
17
+ return {
18
+ success: false,
19
+ message,
20
+ error
21
+ }
22
+ }
23
+ }
24
+
25
+ const decodeToken = (token: string) => {
26
+ const decoded = jwt.decode(token) as JwtPayload;
27
+ return decoded;
28
+ }
29
+
30
+ export const jwtUtils = {
31
+ createToken,
32
+ verifyToken,
33
+ decodeToken,
34
+ }
@@ -0,0 +1,66 @@
1
+ import { Response } from "express";
2
+ import { JwtPayload, SignOptions } from "jsonwebtoken";
3
+ import { envVars } from "../../config/env";
4
+ import { cookieUtils } from "./cookie";
5
+ import { jwtUtils } from "./jwt";
6
+
7
+ //Creating access token
8
+ const getAccessToken = (payload: JwtPayload) => {
9
+ const accessToken = jwtUtils.createToken(
10
+ payload,
11
+ envVars.ACCESS_TOKEN_SECRET,
12
+ { expiresIn: envVars.ACCESS_TOKEN_EXPIRES_IN } as SignOptions
13
+ );
14
+
15
+ return accessToken;
16
+ }
17
+
18
+ const getRefreshToken = (payload: JwtPayload) => {
19
+ const refreshToken = jwtUtils.createToken(
20
+ payload,
21
+ envVars.REFRESH_TOKEN_SECRET,
22
+ { expiresIn: envVars.REFRESH_TOKEN_EXPIRES_IN } as SignOptions
23
+ );
24
+ return refreshToken;
25
+ }
26
+
27
+ const setAccessTokenCookie = (res: Response, token: string) => {
28
+ cookieUtils.setCookie(res, 'accessToken', token, {
29
+ httpOnly: true,
30
+ secure: true,
31
+ sameSite: "none",
32
+ path: '/',
33
+ //1 day
34
+ maxAge: 60 * 60 * 24 * 1000,
35
+ });
36
+ }
37
+
38
+ const setRefreshTokenCookie = (res: Response, token: string) => {
39
+ cookieUtils.setCookie(res, 'refreshToken', token, {
40
+ httpOnly: true,
41
+ secure: true,
42
+ sameSite: "none",
43
+ path: '/',
44
+ //7d
45
+ maxAge: 60 * 60 * 24 * 1000 * 7,
46
+ });
47
+ }
48
+
49
+ const setBetterAuthSessionCookie = (res: Response, token: string) => {
50
+ cookieUtils.setCookie(res, "better-auth.session_token", token, {
51
+ httpOnly: true,
52
+ secure: true,
53
+ sameSite: "none",
54
+ path: '/',
55
+ //1 day
56
+ maxAge: 60 * 60 * 24 * 1000,
57
+ });
58
+ }
59
+
60
+ export const tokenUtils = {
61
+ getAccessToken,
62
+ getRefreshToken,
63
+ setAccessTokenCookie,
64
+ setRefreshTokenCookie,
65
+ setBetterAuthSessionCookie,
66
+ }
@@ -1,4 +1,4 @@
1
- import { auth } from "@/lib/auth";
1
+ import { auth } from "@/server/auth/auth";
2
2
  import { toNextJsHandler } from "better-auth/next-js";
3
3
 
4
4
  export const { GET, POST } = toNextJsHandler(auth);
@@ -1,6 +1,6 @@
1
- import { auth } from "@/lib/auth";
2
1
  import { headers } from "next/headers";
3
2
  import { redirect } from "next/navigation";
3
+ import { auth } from "./auth";
4
4
 
5
5
  export async function getSession() {
6
6
  const session = await auth.api.getSession({
@@ -10,6 +10,16 @@ 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
+
13
23
  export async function requireAdmin() {
14
24
  const session = await getSession();
15
25
 
@@ -0,0 +1,74 @@
1
+ interface OtpTemplateProps {
2
+ name?: string | null;
3
+ otp: string;
4
+ }
5
+
6
+ const escapeHtml = (value: string) =>
7
+ value
8
+ .replaceAll("&", "&amp;")
9
+ .replaceAll("<", "&lt;")
10
+ .replaceAll(">", "&gt;")
11
+ .replaceAll('"', "&quot;")
12
+ .replaceAll("'", "&#39;");
13
+
14
+ const renderOtpTemplate = ({ name, otp }: OtpTemplateProps) => {
15
+ const safeName = name ? escapeHtml(name) : null;
16
+ const safeOtp = escapeHtml(otp);
17
+
18
+ return `<html>
19
+ <body
20
+ style="margin:0;padding:24px;background-color:#f8fafc;font-family:Arial,sans-serif;color:#0f172a;"
21
+ >
22
+ <table
23
+ role="presentation"
24
+ width="100%"
25
+ cellpadding="0"
26
+ cellspacing="0"
27
+ style="max-width:560px;margin:0 auto;background:#ffffff;"
28
+ >
29
+ <tbody>
30
+ <tr>
31
+ <td style="padding:28px 24px;">
32
+ <h2 style="margin:0 0 12px;font-size:22px;">Verification Code</h2>
33
+ <p style="margin:0 0 16px;font-size:15px;line-height:1.6;">
34
+ ${safeName ? `Hi ${safeName},` : "Hi,"}
35
+ </p>
36
+ <p style="margin:0 0 16px;font-size:15px;line-height:1.6;">
37
+ Use the OTP below to continue. This code will expire in 2 minutes.
38
+ </p>
39
+ <div
40
+ style="display:inline-block;padding:12px 18px;border:1px solid #e2e8f0;border-radius:8px;letter-spacing:6px;font-size:22px;font-weight:700;background-color:#f1f5f9;"
41
+ >
42
+ ${safeOtp}
43
+ </div>
44
+ <p style="margin:20px 0 0;font-size:13px;color:#475569;">
45
+ If you did not request this code, you can safely ignore this email.
46
+ </p>
47
+ </td>
48
+ </tr>
49
+ </tbody>
50
+ </table>
51
+ </body>
52
+ </html>`;
53
+ };
54
+
55
+ export const renderEmailTemplate = (
56
+ templateName: string,
57
+ templateData: Record<string, unknown>,
58
+ ) => {
59
+ switch (templateName) {
60
+ case "otp": {
61
+ const name =
62
+ typeof templateData.name === "string" ? templateData.name : null;
63
+ const otp = typeof templateData.otp === "string" ? templateData.otp : "";
64
+
65
+ if (!otp) {
66
+ throw new Error("OTP value is required for otp template");
67
+ }
68
+
69
+ return `<!DOCTYPE html>${renderOtpTemplate({ name, otp })}`;
70
+ }
71
+ default:
72
+ throw new Error(`Unknown email template: ${templateName}`);
73
+ }
74
+ };
@@ -0,0 +1,113 @@
1
+ {{#if framework == "express" }}
2
+ import dotenv from "dotenv";
3
+ import status from "http-status";
4
+ import path from "path";
5
+ import { AppError } from "../shared/errors/app-error";
6
+
7
+ dotenv.config({ path: path.join(process.cwd(), ".env") });
8
+ {{/if}}
9
+
10
+ interface EnvConfig {
11
+ APP_URL?: string;
12
+ FRONTEND_URL?: string;
13
+ BETTER_AUTH_URL: string;
14
+ BETTER_AUTH_SECRET: string;
15
+ GOOGLE_CLIENT_ID?: string;
16
+ GOOGLE_CLIENT_SECRET?: string;
17
+ GOOGLE_CALLBACK_URL: string;
18
+ EMAIL_SENDER: {
19
+ SMTP_USER: string;
20
+ SMTP_PASS: string;
21
+ SMTP_HOST: string;
22
+ SMTP_PORT: string;
23
+ SMTP_FROM: string;
24
+ };
25
+ {{#if framework == "express" }}
26
+ NODE_ENV: string;
27
+ PORT: string;
28
+ BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN: string;
29
+ BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE: string;
30
+ ACCESS_TOKEN_SECRET: string;
31
+ ACCESS_TOKEN_EXPIRES_IN: string;
32
+ REFRESH_TOKEN_SECRET: string;
33
+ REFRESH_TOKEN_EXPIRES_IN: string;
34
+ SUPER_ADMIN_EMAIL: string;
35
+ SUPER_ADMIN_PASSWORD: string;
36
+ {{/if}}
37
+ }
38
+
39
+ const loadEnvVars = (): EnvConfig => {
40
+ const requiredEnvVars = [
41
+ "FRONTEND_URL",
42
+ "BETTER_AUTH_URL",
43
+ "BETTER_AUTH_SECRET",
44
+ "GOOGLE_CLIENT_ID",
45
+ "GOOGLE_CLIENT_SECRET",
46
+ "GOOGLE_CALLBACK_URL",
47
+ "EMAIL_SENDER_SMTP_USER",
48
+ "EMAIL_SENDER_SMTP_PASS",
49
+ "EMAIL_SENDER_SMTP_HOST",
50
+ "EMAIL_SENDER_SMTP_PORT",
51
+ "EMAIL_SENDER_SMTP_FROM",
52
+ {{#if framework == "express" }}
53
+ "NODE_ENV",
54
+ "PORT",
55
+ "BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN",
56
+ "BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE",
57
+ "ACCESS_TOKEN_SECRET",
58
+ "ACCESS_TOKEN_EXPIRES_IN",
59
+ "REFRESH_TOKEN_SECRET",
60
+ "REFRESH_TOKEN_EXPIRES_IN",
61
+ "SUPER_ADMIN_EMAIL",
62
+ "SUPER_ADMIN_PASSWORD",
63
+ {{/if}}
64
+ ];
65
+
66
+ requiredEnvVars.forEach((varName) => {
67
+ if (!process.env[varName]) {
68
+ {{#if framework == "express" }}
69
+ throw new AppError(
70
+ status.INTERNAL_SERVER_ERROR,
71
+ `Environment variable ${varName} is required but not set in .env file.`,
72
+ );
73
+ {{else}}
74
+ throw new Error(
75
+ `Environment variable ${varName} is required but not defined.`,
76
+ );
77
+ {{/if}}
78
+ }
79
+ });
80
+
81
+ return {
82
+ APP_URL: process.env.APP_URL as string,
83
+ FRONTEND_URL: process.env.FRONTEND_URL as string,
84
+ BETTER_AUTH_URL: process.env.BETTER_AUTH_URL as string,
85
+ BETTER_AUTH_SECRET: process.env.BETTER_AUTH_SECRET as string,
86
+ GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
87
+ GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
88
+ GOOGLE_CALLBACK_URL: process.env.GOOGLE_CALLBACK_URL as string,
89
+ EMAIL_SENDER: {
90
+ SMTP_USER: process.env.EMAIL_SENDER_SMTP_USER as string,
91
+ SMTP_PASS: process.env.EMAIL_SENDER_SMTP_PASS as string,
92
+ SMTP_HOST: process.env.EMAIL_SENDER_SMTP_HOST as string,
93
+ SMTP_PORT: process.env.EMAIL_SENDER_SMTP_PORT as string,
94
+ SMTP_FROM: process.env.EMAIL_SENDER_SMTP_FROM as string,
95
+ },
96
+ {{#if framework == "express" }}
97
+ NODE_ENV: process.env.NODE_ENV as string,
98
+ PORT: process.env.PORT as string,
99
+ BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN: process.env
100
+ .BETTER_AUTH_SESSION_TOKEN_EXPIRES_IN as string,
101
+ BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE: process.env
102
+ .BETTER_AUTH_SESSION_TOKEN_UPDATE_AGE as string,
103
+ ACCESS_TOKEN_SECRET: process.env.ACCESS_TOKEN_SECRET as string,
104
+ ACCESS_TOKEN_EXPIRES_IN: process.env.ACCESS_TOKEN_EXPIRES_IN as string,
105
+ REFRESH_TOKEN_SECRET: process.env.REFRESH_TOKEN_SECRET as string,
106
+ REFRESH_TOKEN_EXPIRES_IN: process.env.REFRESH_TOKEN_EXPIRES_IN as string,
107
+ SUPER_ADMIN_EMAIL: process.env.SUPER_ADMIN_EMAIL as string,
108
+ SUPER_ADMIN_PASSWORD: process.env.SUPER_ADMIN_PASSWORD as string,
109
+ {{/if}}
110
+ };
111
+ };
112
+
113
+ export const envVars = loadEnvVars();
@@ -1,7 +1,7 @@
1
1
  import { createAuthClient } from "better-auth/react";
2
2
 
3
3
  export const authClient = createAuthClient({
4
- baseURL: process.env.BETTER_AUTH_URL || "http://localhost:4000",
4
+ baseURL: process.env.BETTER_AUTH_URL || "http://localhost:5000",
5
5
  });
6
6
 
7
7
  export const { signIn, signUp, signOut, useSession } = authClient;