@ifecodes/backend-template 1.1.3 → 1.1.6

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 (86) hide show
  1. package/README.md +39 -18
  2. package/bin/cli.js +602 -101
  3. package/bin/lib/microservice-config.js +68 -14
  4. package/bin/lib/prompts.js +25 -6
  5. package/bin/lib/readme-generator.js +119 -29
  6. package/bin/lib/service-setup.js +401 -132
  7. package/package.json +2 -2
  8. package/template/base/js/.eslintrc.json +13 -0
  9. package/template/base/js/.prettierrc +7 -0
  10. package/template/base/js/eslint.config.js +31 -0
  11. package/template/base/js/package.json +28 -0
  12. package/template/base/js/src/app.js +15 -0
  13. package/template/base/js/src/config/db.js +8 -0
  14. package/template/base/js/src/config/env.js +14 -0
  15. package/template/base/js/src/config/index.js +7 -0
  16. package/template/base/js/src/middlewares/index.js +9 -0
  17. package/template/base/js/src/middlewares/method-not-allowed.middleware.js +13 -0
  18. package/template/base/js/src/middlewares/not-found.middleware.js +10 -0
  19. package/template/base/js/src/middlewares/root.middleware.js +16 -0
  20. package/template/base/js/src/modules/index.js +8 -0
  21. package/template/base/js/src/modules/v1/health/health.controller.js +21 -0
  22. package/template/base/js/src/modules/v1/health/health.route.js +9 -0
  23. package/template/base/js/src/modules/v1/health/index.js +5 -0
  24. package/template/base/js/src/modules/v1/index.js +8 -0
  25. package/template/base/js/src/routes.js +16 -0
  26. package/template/base/js/src/server.js +18 -0
  27. package/template/base/js/src/utils/http-error.js +53 -0
  28. package/template/base/js/src/utils/index.js +22 -0
  29. package/template/base/js/src/utils/logger.js +67 -0
  30. package/template/base/ts/.env.example +5 -0
  31. package/template/base/ts/.husky/pre-commit +13 -0
  32. package/template/base/ts/.prettierignore +47 -0
  33. package/template/base/ts/gitignore +31 -0
  34. package/template/base/ts/src/app.ts +15 -0
  35. package/template/base/{src → ts/src}/config/env.ts +10 -10
  36. package/template/base/{src → ts/src}/middlewares/index.ts +3 -3
  37. package/template/base/{src → ts/src}/middlewares/method-not-allowed.middleware.ts +16 -17
  38. package/template/base/{src → ts/src}/middlewares/root.middleware.ts +2 -2
  39. package/template/base/{src → ts/src}/modules/v1/health/health.controller.ts +18 -18
  40. package/template/base/{src → ts/src}/modules/v1/health/health.route.ts +9 -9
  41. package/template/base/{src → ts/src}/modules/v1/health/index.ts +1 -1
  42. package/template/base/{src → ts/src}/modules/v1/index.ts +8 -8
  43. package/template/base/{src → ts/src}/routes.ts +15 -15
  44. package/template/base/{src → ts/src}/utils/http-error.ts +45 -45
  45. package/template/base/{src → ts/src}/utils/logger.ts +23 -0
  46. package/template/features/auth/argon2/inject.js +29 -4
  47. package/template/features/auth/base/inject.js +108 -26
  48. package/template/features/auth/bcrypt/inject.js +25 -5
  49. package/template/features/auth/models/user.model.js +24 -0
  50. package/template/features/auth/modules/auth.controller.js +21 -0
  51. package/template/features/auth/modules/auth.routes.js +10 -0
  52. package/template/features/auth/modules/auth.service.js +29 -0
  53. package/template/features/auth/modules/index.js +1 -0
  54. package/template/features/auth/utils/jwt.js +12 -0
  55. package/template/features/cors/inject.js +4 -1
  56. package/template/features/helmet/inject.js +4 -1
  57. package/template/features/morgan/inject.js +4 -1
  58. package/template/features/rate-limit/inject.js +4 -1
  59. package/template/gateway/js/app.js +42 -0
  60. package/template/gateway/js/inject.js +31 -0
  61. package/template/gateway/js/server.js +19 -0
  62. package/template/gateway/ts/app.ts +43 -0
  63. package/template/gateway/ts/inject.js +32 -0
  64. package/template/gateway/{server.ts → ts/server.ts} +3 -3
  65. package/template/microservice/docker/.dockerignore +10 -0
  66. package/template/microservice/docker/Dockerfile +2 -1
  67. package/template/microservice/docker/docker-compose.yml +0 -1
  68. package/bin/lib/ts-to-js.js +0 -342
  69. package/template/base/src/app.ts +0 -8
  70. package/template/gateway/app.ts +0 -26
  71. package/template/gateway/inject.js +0 -27
  72. /package/template/base/{.env.example → js/.env.example} +0 -0
  73. /package/template/base/{.husky → js/.husky}/pre-commit +0 -0
  74. /package/template/base/{.prettierignore → js/.prettierignore} +0 -0
  75. /package/template/base/{gitignore → js/gitignore} +0 -0
  76. /package/template/base/{.eslintrc.json → ts/.eslintrc.json} +0 -0
  77. /package/template/base/{.prettierrc → ts/.prettierrc} +0 -0
  78. /package/template/base/{eslint.config.js → ts/eslint.config.js} +0 -0
  79. /package/template/base/{package.json → ts/package.json} +0 -0
  80. /package/template/base/{src → ts/src}/config/db.ts +0 -0
  81. /package/template/base/{src → ts/src}/config/index.ts +0 -0
  82. /package/template/base/{src → ts/src}/middlewares/not-found.middleware.ts +0 -0
  83. /package/template/base/{src → ts/src}/modules/index.ts +0 -0
  84. /package/template/base/{src → ts/src}/server.ts +0 -0
  85. /package/template/base/{src → ts/src}/utils/index.ts +0 -0
  86. /package/template/base/{tsconfig.json → ts/tsconfig.json} +0 -0
@@ -1,18 +1,18 @@
1
- import { Request, Response } from "express";
2
- import { logger } from "@/utils";
3
-
4
- export const healthCheck = async (_: Request, res: Response) => {
5
- logger.info("Health", "healthy");
6
-
7
- return res.status(200).json({
8
- status: "healthy",
9
- uptime: process.uptime(),
10
- timestamp: new Date().toISOString(),
11
- services: {
12
- memory: {
13
- rss: process.memoryUsage().rss,
14
- heapUsed: process.memoryUsage().heapUsed,
15
- },
16
- },
17
- });
18
- };
1
+ import { Request, Response } from "express";
2
+ import { logger } from "@/utils";
3
+
4
+ export const healthCheck = async (_: Request, res: Response) => {
5
+ logger.info("Health", "healthy");
6
+
7
+ return res.status(200).json({
8
+ status: "healthy",
9
+ uptime: process.uptime(),
10
+ timestamp: new Date().toISOString(),
11
+ services: {
12
+ memory: {
13
+ rss: process.memoryUsage().rss,
14
+ heapUsed: process.memoryUsage().heapUsed,
15
+ },
16
+ },
17
+ });
18
+ };
@@ -1,9 +1,9 @@
1
- import { Router } from "express";
2
- import { healthCheck } from "./health.controller";
3
- import { methodNotAllowedHandler } from "@/middlewares";
4
-
5
- const router = Router();
6
- router.use(methodNotAllowedHandler(["GET"]));
7
- router.get("/", healthCheck);
8
-
9
- export default router;
1
+ import { Router } from "express";
2
+ import { healthCheck } from "./health.controller";
3
+ import { methodNotAllowedHandler } from "@/middlewares";
4
+
5
+ const router = Router();
6
+ router.use(methodNotAllowedHandler(["GET"]));
7
+ router.get("/", healthCheck);
8
+
9
+ export default router;
@@ -1 +1 @@
1
- export { default as healthRoutes } from "./health.route";
1
+ export { default as healthRoutes } from "./health.route";
@@ -1,8 +1,8 @@
1
- import { Router } from "express";
2
- import { healthRoutes } from "./health";
3
-
4
- const router = Router();
5
-
6
- router.use("/health", healthRoutes);
7
-
8
- export default router;
1
+ import { Router } from "express";
2
+ import { healthRoutes } from "./health";
3
+
4
+ const router = Router();
5
+
6
+ router.use("/health", healthRoutes);
7
+
8
+ export default router;
@@ -1,15 +1,15 @@
1
- import { Router } from "express";
2
- import modulesRouter from "./modules";
3
- import { notFound, rootHandler } from "./middlewares";
4
-
5
- const router = Router();
6
-
7
- // Root endpoint
8
- router.get("/", rootHandler);
9
-
10
- router.use("/", modulesRouter);
11
-
12
- // 404 handler - must be last
13
- router.use(notFound);
14
-
15
- export default router;
1
+ import { Router } from "express";
2
+ import modulesRouter from "./modules";
3
+ import { notFound, rootHandler } from "./middlewares";
4
+
5
+ const router = Router();
6
+
7
+ // Root endpoint
8
+ router.get("/", rootHandler);
9
+
10
+ router.use("/api", modulesRouter);
11
+
12
+ // 404 handler - must be last
13
+ router.use(notFound);
14
+
15
+ export default router;
@@ -1,45 +1,45 @@
1
- export class HttpError extends Error {
2
- public status: number;
3
-
4
- constructor(status: number, message: string) {
5
- super(message);
6
- this.status = status;
7
- Object.setPrototypeOf(this, new.target.prototype);
8
- }
9
- }
10
-
11
- export class BadRequestError extends HttpError {
12
- constructor(message = "Bad Request") {
13
- super(400, message);
14
- }
15
- }
16
-
17
- export class UnauthorizedError extends HttpError {
18
- constructor(message = "Unauthorized") {
19
- super(401, message);
20
- }
21
- }
22
-
23
- export class ForbiddenError extends HttpError {
24
- constructor(message = "Forbidden") {
25
- super(403, message);
26
- }
27
- }
28
-
29
- export class NotFoundError extends HttpError {
30
- constructor(message = "Not Found") {
31
- super(404, message);
32
- }
33
- }
34
-
35
- export class ConflictError extends HttpError {
36
- constructor(message = "Conflict") {
37
- super(409, message);
38
- }
39
- }
40
-
41
- export class InternalServerError extends HttpError {
42
- constructor(message = "Internal Server Error") {
43
- super(500, message);
44
- }
45
- }
1
+ export class HttpError extends Error {
2
+ public status: number;
3
+
4
+ constructor(status: number, message: string) {
5
+ super(message);
6
+ this.status = status;
7
+ Object.setPrototypeOf(this, new.target.prototype);
8
+ }
9
+ }
10
+
11
+ export class BadRequestError extends HttpError {
12
+ constructor(message = "Bad Request") {
13
+ super(400, message);
14
+ }
15
+ }
16
+
17
+ export class UnauthorizedError extends HttpError {
18
+ constructor(message = "Unauthorized") {
19
+ super(401, message);
20
+ }
21
+ }
22
+
23
+ export class ForbiddenError extends HttpError {
24
+ constructor(message = "Forbidden") {
25
+ super(403, message);
26
+ }
27
+ }
28
+
29
+ export class NotFoundError extends HttpError {
30
+ constructor(message = "Not Found") {
31
+ super(404, message);
32
+ }
33
+ }
34
+
35
+ export class ConflictError extends HttpError {
36
+ constructor(message = "Conflict") {
37
+ super(409, message);
38
+ }
39
+ }
40
+
41
+ export class InternalServerError extends HttpError {
42
+ constructor(message = "Internal Server Error") {
43
+ super(500, message);
44
+ }
45
+ }
@@ -20,6 +20,29 @@ function getEnvironment() {
20
20
  : ENV.NODE_ENV;
21
21
  }
22
22
 
23
+ console.log(
24
+ format("logger", colors.blue),
25
+ `Logger initialized for ${getEnvironment()} environment.`,
26
+ );
27
+
28
+ const requiredKeys = ENV && Object.keys(ENV).length ? Object.keys(ENV) : [];
29
+
30
+ const missing = requiredKeys.filter(
31
+ (k) => ENV == null || (ENV as Record<string, string | undefined>)[k] === undefined || (ENV as Record<string, string | undefined>)[k] === "",
32
+ );
33
+
34
+ if (missing.length === requiredKeys.length) {
35
+ console.warn(
36
+ format("logger", colors.yellow),
37
+ "ENV values missing — make sure to set up your environment variables correctly.",
38
+ );
39
+ } else if (missing.length > 0) {
40
+ console.warn(
41
+ format("logger", colors.yellow),
42
+ `Missing ENV keys: ${missing.join(", ")}`,
43
+ );
44
+ }
45
+
23
46
  const logger = {
24
47
  log(tag: string, ...args: unknown[]) {
25
48
  if (getEnvironment() !== "development") return;
@@ -1,8 +1,9 @@
1
1
  export const deps = ["argon2"];
2
2
 
3
- export const files = {
4
- "src/utils/hash.ts": `
5
- import argon2 from "argon2";
3
+ export const getFiles = (language = "typescript") => {
4
+ const ext = language === "javascript" ? ".js" : ".ts";
5
+
6
+ const tsContent = `import argon2 from "argon2";
6
7
 
7
8
  const HASH_OPTIONS = {
8
9
  type: argon2.argon2id,
@@ -21,5 +22,29 @@ export const verifyPassword = async (
21
22
  ): Promise<boolean> => {
22
23
  return argon2.verify(hash, password);
23
24
  };
24
- `
25
+ `;
26
+
27
+ const jsContent = `const argon2 = require("argon2");
28
+
29
+ const HASH_OPTIONS = {
30
+ type: argon2.argon2id,
31
+ memoryCost: 2 ** 16,
32
+ timeCost: 3,
33
+ parallelism: 1,
34
+ };
35
+
36
+ async function hashPassword(password) {
37
+ return argon2.hash(password, HASH_OPTIONS);
38
+ }
39
+
40
+ async function verifyPassword(hash, password) {
41
+ return argon2.verify(hash, password);
42
+ }
43
+
44
+ module.exports = { hashPassword, verifyPassword };
45
+ `;
46
+
47
+ return {
48
+ [`src/utils/hash${ext}`]: language === "javascript" ? jsContent : tsContent,
49
+ };
25
50
  };
@@ -9,45 +9,78 @@ const modulesDir = path.join(__dirname, "../modules");
9
9
  const modelsDir = path.join(__dirname, "../models");
10
10
  const utilsDir = path.join(__dirname, "../utils");
11
11
 
12
- const readDirFiles = (dir, prefix = "") => {
12
+ const readDirFiles = (dir, prefix = "", language = "typescript") => {
13
13
  const files = {};
14
14
  const items = fs.readdirSync(dir);
15
-
15
+ const ext = language === "javascript" ? ".js" : ".ts";
16
+
16
17
  for (const item of items) {
17
18
  const fullPath = path.join(dir, item);
18
- const relativePath = path.join(prefix, item);
19
-
20
- if (fs.statSync(fullPath).isDirectory()) {
21
- Object.assign(files, readDirFiles(fullPath, relativePath));
19
+ const isDir = fs.statSync(fullPath).isDirectory();
20
+ const desiredName = item.replace(/\.ts$|\.js$/, ext);
21
+ const chosenPath = isDir
22
+ ? fullPath
23
+ : fs.existsSync(path.join(dir, desiredName))
24
+ ? path.join(dir, desiredName)
25
+ : fullPath;
26
+
27
+ const relativePath = path.join(prefix, path.basename(desiredName));
28
+
29
+ if (isDir) {
30
+ Object.assign(files, readDirFiles(chosenPath, relativePath, language));
22
31
  } else {
23
- files[relativePath] = fs.readFileSync(fullPath, "utf8");
32
+ const content = fs.readFileSync(chosenPath, "utf8");
33
+ files[relativePath] = content;
24
34
  }
25
35
  }
26
-
36
+
27
37
  return files;
28
38
  };
29
39
 
30
- const moduleFiles = readDirFiles(modulesDir, "src/modules/v1/auth");
31
- const modelFiles = readDirFiles(modelsDir, "src/models");
32
- const utilFiles = readDirFiles(utilsDir, "src/utils");
33
-
34
- // Add MongoDB-enabled db.ts
35
- const dbContent = `import mongoose from "mongoose";
40
+ const getDbContent = (language) => {
41
+ const tsContent = `import mongoose from "mongoose";
36
42
  import { ENV } from "./env";
37
43
  import { logger } from "@/utils";
38
44
 
39
45
  export const connectDB = async () => {
40
- await mongoose.connect(ENV.MONGO_URI);
41
- logger.log("db", "MongoDB connected");
46
+ try {
47
+ await mongoose.connect(ENV.MONGO_URI);
48
+ logger.log("db", "MongoDB connected");
49
+ } catch (error) {
50
+ logger.error("db", "MongoDB connection failed", error);
51
+ process.exit(1);
52
+ }
42
53
  };
43
54
  `;
44
55
 
45
- // Add MongoDB health check
46
- const healthControllerContent = `import { Request, Response } from "express";
56
+ if (language === "javascript") {
57
+ return `const mongoose = require("mongoose");
58
+ const { ENV } = require("./env");
59
+ const { logger } = require("../utils");
60
+
61
+ async function connectDB() {
62
+ try {
63
+ await mongoose.connect(ENV.MONGO_URI);
64
+ logger.log("db", "MongoDB connected");
65
+ } catch (error) {
66
+ logger.error("db", "MongoDB connection failed", error);
67
+ process.exit(1);
68
+ }
69
+ }
70
+
71
+ module.exports = { connectDB };
72
+ `;
73
+ }
74
+
75
+ return tsContent;
76
+ };
77
+
78
+ const getHealthControllerContent = (language) => {
79
+ const tsContent = `import { Request, Response } from "express";
47
80
  import mongoose from "mongoose";
48
- import { logger } from "@/utils";
81
+ const { logger } = require("../../../utils");
49
82
 
50
- export const healthCheck = async (_: Request, res: Response) => {
83
+ export const healthCheck = async (_req: Request, res: Response) => {
51
84
  const mongoState = mongoose.connection.readyState;
52
85
  const healthy = mongoState === 1;
53
86
 
@@ -72,16 +105,65 @@ export const healthCheck = async (_: Request, res: Response) => {
72
105
  };
73
106
  `;
74
107
 
75
- export const files = {
76
- ...moduleFiles,
77
- ...modelFiles,
78
- ...utilFiles,
79
- "src/config/db.ts": dbContent,
80
- "src/modules/v1/health/health.controller.ts": healthControllerContent,
108
+ if (language === "javascript") {
109
+ return `const mongoose = require("mongoose");
110
+ const { logger } = require("../../../utils");
111
+
112
+ async function healthCheck(_req, res) {
113
+ const mongoState = mongoose.connection.readyState;
114
+ const healthy = mongoState === 1;
115
+
116
+ const failed = [];
117
+ if (mongoState !== 1) failed.push("mongodb");
118
+
119
+ logger.info("Health", healthy ? "healthy" : "unhealthy");
120
+
121
+ return res.status(healthy ? 200 : 503).json({
122
+ status: healthy ? "healthy" : "unhealthy",
123
+ uptime: process.uptime(),
124
+ timestamp: new Date().toISOString(),
125
+ services: {
126
+ mongodb: mongoState === 1 ? "connected" : "disconnected",
127
+ memory: {
128
+ rss: process.memoryUsage().rss,
129
+ heapUsed: process.memoryUsage().heapUsed,
130
+ },
131
+ },
132
+ failed,
133
+ });
134
+ }
135
+
136
+ module.exports = { healthCheck };
137
+ `;
138
+ }
139
+
140
+ return tsContent;
141
+ };
142
+
143
+ export const getFiles = (language = "typescript") => {
144
+ const ext = language === "javascript" ? ".js" : ".ts";
145
+ const moduleFiles = readDirFiles(modulesDir, "src/modules/v1/auth", language);
146
+ const modelFiles = readDirFiles(modelsDir, "src/models", language);
147
+ const utilFiles = readDirFiles(utilsDir, "src/utils", language);
148
+
149
+ return {
150
+ ...moduleFiles,
151
+ ...modelFiles,
152
+ ...utilFiles,
153
+ [`src/config/db${ext}`]: getDbContent(language),
154
+ [`src/modules/v1/health/health.controller${ext}`]: getHealthControllerContent(language),
155
+ };
81
156
  };
82
157
 
158
+ // For backward compatibility
159
+ export const files = getFiles("typescript");
160
+
83
161
  export const imports = `import { authRoutes } from "./auth";`;
84
162
 
163
+ export const getImports = (language) => language === "javascript"
164
+ ? `const { authRoutes } = require("./auth");`
165
+ : `import { authRoutes } from "./auth";`;
166
+
85
167
  export const middleware = `router.use("/auth", authRoutes);`;
86
168
 
87
169
  export const deps = ["jsonwebtoken", "mongoose"];
@@ -2,12 +2,14 @@ export const deps = ["bcrypt"];
2
2
 
3
3
  export const devDeps = ["@types/bcrypt"];
4
4
 
5
- export const files = {
6
- "src/utils/hash.ts": `
7
- import bcrypt from "bcrypt";
5
+ export const getFiles = (language = "typescript") => {
6
+ const ext = language === "javascript" ? ".js" : ".ts";
7
+
8
+ const tsContent = `import bcrypt from "bcrypt";
8
9
 
9
10
  export const hashPassword = async (password: string): Promise<string> => {
10
- return bcrypt.hash(password, 12);
11
+ const salt = await bcrypt.genSalt(10);
12
+ return bcrypt.hash(password, salt);
11
13
  };
12
14
 
13
15
  export const verifyPassword = async (
@@ -16,5 +18,23 @@ export const verifyPassword = async (
16
18
  ): Promise<boolean> => {
17
19
  return bcrypt.compare(password, hash);
18
20
  };
19
- `
21
+ `;
22
+
23
+ const jsContent = `const bcrypt = require("bcrypt");
24
+
25
+ async function hashPassword(password) {
26
+ const salt = await bcrypt.genSalt(10);
27
+ return bcrypt.hash(password, salt);
28
+ }
29
+
30
+ async function verifyPassword(hash, password) {
31
+ return bcrypt.compare(password, hash);
32
+ }
33
+
34
+ module.exports = { hashPassword, verifyPassword };
35
+ `;
36
+
37
+ return {
38
+ [`src/utils/hash${ext}`]: language === "javascript" ? jsContent : tsContent,
39
+ };
20
40
  };
@@ -0,0 +1,24 @@
1
+ const mongoose = require("mongoose");
2
+
3
+ const userSchema = new mongoose.Schema(
4
+ {
5
+ email: {
6
+ type: String,
7
+ required: true,
8
+ unique: true,
9
+ },
10
+ password: {
11
+ type: String,
12
+ required: true,
13
+ },
14
+ fullName: {
15
+ type: String,
16
+ required: true,
17
+ },
18
+ },
19
+ { timestamps: true },
20
+ );
21
+
22
+ const UserModel = mongoose.model("User", userSchema);
23
+
24
+ module.exports = { UserModel };
@@ -0,0 +1,21 @@
1
+ const { loginService, registerService } = require("./auth.service");
2
+
3
+ async function login(req, res, next) {
4
+ try {
5
+ const token = await loginService(req.body);
6
+ return res.status(200).json({ token });
7
+ } catch (err) {
8
+ return next(err);
9
+ }
10
+ }
11
+
12
+ async function register(req, res, next) {
13
+ try {
14
+ const token = await registerService(req.body);
15
+ return res.status(201).json({ token });
16
+ } catch (err) {
17
+ return next(err);
18
+ }
19
+ }
20
+
21
+ module.exports = { login, register };
@@ -0,0 +1,10 @@
1
+ const { Router } = require("express");
2
+ const { register, login } = require("./auth.controller");
3
+ const { methodNotAllowedHandler } = require("../../../middlewares");
4
+
5
+ const router = Router();
6
+ router.use(methodNotAllowedHandler(["POST"]));
7
+ router.post("/login", login);
8
+ router.post("/register", register);
9
+
10
+ module.exports = router;
@@ -0,0 +1,29 @@
1
+ const { generateToken } = require("../../../utils/jwt");
2
+ const { UserModel } = require("../../../models/user.model");
3
+ const { hashPassword, verifyPassword } = require("../../../utils/hash");
4
+ const {
5
+ UnauthorizedError,
6
+ ConflictError,
7
+ } = require("../../../utils/http-error");
8
+
9
+ async function loginService({ email, password }) {
10
+ const user = await UserModel.findOne({ email }).exec();
11
+ if (!user) throw new UnauthorizedError("User not found");
12
+
13
+ const match = await verifyPassword(user.password, password);
14
+ if (!match) throw new UnauthorizedError("Invalid credentials");
15
+
16
+ return generateToken({ email: user.email });
17
+ }
18
+
19
+ async function registerService({ email, password, fullName }) {
20
+ const exists = await UserModel.findOne({ email }).exec();
21
+ if (exists) throw new ConflictError("Email already registered");
22
+
23
+ const hashed = await hashPassword(password);
24
+ const user = await UserModel.create({ email, password: hashed, fullName });
25
+
26
+ return generateToken({ email: user.email });
27
+ }
28
+
29
+ module.exports = { loginService, registerService };
@@ -0,0 +1 @@
1
+ module.exports = { authRoutes: require("./auth.routes") };
@@ -0,0 +1,12 @@
1
+ const jwt = require("jsonwebtoken");
2
+ const { ENV } = require("../config");
3
+
4
+ async function generateToken(payload) {
5
+ return jwt.sign(payload, ENV.JWT_SECRET, { expiresIn: "7d" });
6
+ }
7
+
8
+ function verifyToken(token) {
9
+ return jwt.verify(token, ENV.JWT_SECRET);
10
+ }
11
+
12
+ module.exports = { generateToken, verifyToken };
@@ -1,6 +1,9 @@
1
1
  export const deps = ["cors"];
2
2
  export const devDeps = ["@types/cors"];
3
- export const imports = `import cors from "cors";\nimport { ENV } from "@/config";`;
3
+ export const getImports = (language) => language === "javascript"
4
+ ? `const cors = require("cors");\nconst { ENV } = require("./config");`
5
+ : `import cors from "cors";\nimport { ENV } from "@/config";`;
6
+ export const imports = getImports("typescript");
4
7
  export const middleware = `
5
8
  const corsOptions = {
6
9
  origin: ENV.ALLOWED_ORIGIN,
@@ -1,3 +1,6 @@
1
1
  export const deps = ["helmet"];
2
- export const imports = `import helmet from "helmet";`;
2
+ export const getImports = (language) => language === "javascript"
3
+ ? `const helmet = require("helmet");`
4
+ : `import helmet from "helmet";`;
5
+ export const imports = getImports("typescript");
3
6
  export const middleware = `app.use(helmet());`;
@@ -1,4 +1,7 @@
1
1
  export const deps = ["morgan"];
2
2
  export const devDeps = ["@types/morgan"];
3
- export const imports = `import morgan from "morgan";`;
3
+ export const getImports = (language) => language === "javascript"
4
+ ? `const morgan = require("morgan");`
5
+ : `import morgan from "morgan";`;
6
+ export const imports = getImports("typescript");
4
7
  export const middleware = `app.use(morgan("dev"));`;
@@ -1,3 +1,6 @@
1
1
  export const deps = ["express-rate-limit"];
2
- export const imports = `import rateLimit from "express-rate-limit";`;
2
+ export const getImports = (language) => language === "javascript"
3
+ ? `const rateLimit = require("express-rate-limit");`
4
+ : `import rateLimit from "express-rate-limit";`;
5
+ export const imports = getImports("typescript");
3
6
  export const middleware = `app.use(rateLimit({ windowMs: 15*60*1000, max: 100 }));`;