create-charcole 2.0.4 → 2.2.0
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.
- package/CHANGELOG.md +290 -14
- package/README.md +258 -312
- package/bin/index.js +392 -55
- package/bin/lib/pkgManager.js +8 -25
- package/bin/lib/templateHandler.js +5 -42
- package/create-charcole-2.1.0.tgz +0 -0
- package/package.json +2 -2
- package/packages/swagger/BACKWARD_COMPATIBILITY.md +145 -0
- package/packages/swagger/CHANGELOG.md +404 -0
- package/packages/swagger/README.md +578 -0
- package/packages/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/packages/swagger/package-lock.json +1715 -0
- package/packages/swagger/package.json +44 -0
- package/packages/swagger/src/helpers.js +427 -0
- package/packages/swagger/src/index.d.ts +126 -0
- package/packages/swagger/src/index.js +12 -0
- package/packages/swagger/src/setup.js +100 -0
- package/template/js/.env.example +8 -0
- package/template/js/README.md +128 -5
- package/template/js/basePackage.json +11 -13
- package/template/js/src/app.js +8 -2
- package/template/js/src/config/swagger.config.js +15 -0
- package/template/js/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
- package/template/js/src/modules/auth/auth.constants.js +3 -0
- package/template/js/src/modules/auth/auth.controller.js +29 -0
- package/template/js/src/modules/auth/auth.middlewares.js +19 -0
- package/template/js/src/modules/auth/auth.routes.js +131 -0
- package/template/js/src/modules/auth/auth.schemas.js +60 -0
- package/template/js/src/modules/auth/auth.service.js +67 -0
- package/template/js/src/modules/auth/package.json +6 -0
- package/template/js/src/modules/health/controller.js +104 -3
- package/template/js/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/template/js/src/modules/swagger/package.json +5 -0
- package/template/js/src/repositories/user.repo.js +19 -0
- package/template/js/src/routes/index.js +25 -0
- package/template/js/src/routes/protected.js +57 -0
- package/template/ts/.env.example +8 -0
- package/template/ts/README.md +128 -5
- package/template/ts/basePackage.json +19 -15
- package/template/ts/build.js +46 -0
- package/template/ts/src/app.ts +12 -7
- package/template/ts/src/config/swagger.config.ts +30 -0
- package/template/ts/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
- package/template/ts/src/middlewares/errorHandler.ts +15 -23
- package/template/ts/src/middlewares/requestLogger.ts +1 -1
- package/template/ts/src/middlewares/validateRequest.ts +1 -1
- package/template/ts/src/modules/auth/auth.constants.ts +6 -0
- package/template/ts/src/modules/auth/auth.controller.ts +32 -0
- package/template/ts/src/modules/auth/auth.middlewares.ts +46 -0
- package/template/ts/src/modules/auth/auth.routes.ts +52 -0
- package/template/ts/src/modules/auth/auth.schemas.ts +73 -0
- package/template/ts/src/modules/auth/auth.service.ts +106 -0
- package/template/ts/src/modules/auth/package.json +10 -0
- package/template/ts/src/modules/health/controller.ts +61 -45
- package/template/ts/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/template/ts/src/modules/swagger/package.json +5 -0
- package/template/ts/src/repositories/user.repo.ts +33 -0
- package/template/ts/src/routes/index.ts +24 -0
- package/template/ts/src/routes/protected.ts +46 -0
- package/template/ts/src/server.ts +3 -4
- package/template/ts/src/utils/logger.ts +1 -1
- package/template/ts/tsconfig.json +14 -7
- package/tmpclaude-1049-cwd +1 -0
- package/tmpclaude-3e37-cwd +1 -0
- package/tmpclaude-4d73-cwd +1 -0
- package/tmpclaude-8a8e-cwd +1 -0
- package/template/js/ARCHITECTURE_DIAGRAMS.md +0 -283
- package/template/js/CHECKLIST.md +0 -279
- package/template/js/COMPLETE.md +0 -405
- package/template/js/ERROR_HANDLING.md +0 -393
- package/template/js/IMPLEMENTATION.md +0 -368
- package/template/js/IMPLEMENTATION_COMPLETE.md +0 -363
- package/template/js/INDEX.md +0 -290
- package/template/js/QUICK_REFERENCE.md +0 -270
- package/template/js/package.json +0 -28
- package/template/js/src/routes.js +0 -17
- package/template/js/test-api.js +0 -100
- package/template/ts/ARCHITECTURE_DIAGRAMS.md +0 -283
- package/template/ts/CHECKLIST.md +0 -279
- package/template/ts/COMPLETE.md +0 -405
- package/template/ts/ERROR_HANDLING.md +0 -393
- package/template/ts/IMPLEMENTATION.md +0 -368
- package/template/ts/IMPLEMENTATION_COMPLETE.md +0 -363
- package/template/ts/INDEX.md +0 -290
- package/template/ts/QUICK_REFERENCE.md +0 -270
- package/template/ts/package.json +0 -32
- package/template/ts/src/app.js +0 -75
- package/template/ts/src/config/constants.js +0 -20
- package/template/ts/src/config/env.js +0 -26
- package/template/ts/src/middlewares/errorHandler.js +0 -180
- package/template/ts/src/middlewares/requestLogger.js +0 -33
- package/template/ts/src/middlewares/validateRequest.js +0 -42
- package/template/ts/src/modules/health/controller.js +0 -50
- package/template/ts/src/routes.js +0 -17
- package/template/ts/src/routes.ts +0 -16
- package/template/ts/src/server.js +0 -38
- package/template/ts/src/utils/AppError.js +0 -182
- package/template/ts/src/utils/logger.js +0 -73
- package/template/ts/src/utils/response.js +0 -51
- package/template/ts/test-api.js +0 -100
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { AuthController } from "./auth.controller.ts";
|
|
3
|
+
|
|
4
|
+
const router = Router();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @swagger
|
|
8
|
+
* /api/auth/register:
|
|
9
|
+
* post:
|
|
10
|
+
* summary: Register a new user
|
|
11
|
+
* description: Create a new user account with email and password
|
|
12
|
+
* tags:
|
|
13
|
+
* - Authentication
|
|
14
|
+
* requestBody:
|
|
15
|
+
* required: true
|
|
16
|
+
* content:
|
|
17
|
+
* application/json:
|
|
18
|
+
* schema:
|
|
19
|
+
* $ref: '#/components/schemas/registerSchema'
|
|
20
|
+
* responses:
|
|
21
|
+
* 201:
|
|
22
|
+
* $ref: '#/components/responses/Success'
|
|
23
|
+
* 400:
|
|
24
|
+
* $ref: '#/components/responses/ValidationError'
|
|
25
|
+
*/
|
|
26
|
+
router.post("/register", AuthController.register);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @swagger
|
|
30
|
+
* /api/auth/login:
|
|
31
|
+
* post:
|
|
32
|
+
* summary: Login user
|
|
33
|
+
* description: Authenticate user with email and password
|
|
34
|
+
* tags:
|
|
35
|
+
* - Authentication
|
|
36
|
+
* requestBody:
|
|
37
|
+
* required: true
|
|
38
|
+
* content:
|
|
39
|
+
* application/json:
|
|
40
|
+
* schema:
|
|
41
|
+
* $ref: '#/components/schemas/loginSchema'
|
|
42
|
+
* responses:
|
|
43
|
+
* 200:
|
|
44
|
+
* $ref: '#/components/responses/Success'
|
|
45
|
+
* 401:
|
|
46
|
+
* $ref: '#/components/responses/Unauthorized'
|
|
47
|
+
* 400:
|
|
48
|
+
* $ref: '#/components/responses/ValidationError'
|
|
49
|
+
*/
|
|
50
|
+
router.post("/login", AuthController.login);
|
|
51
|
+
|
|
52
|
+
export default router;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { USER_ROLES, AUTH_PROVIDERS } from "./auth.constants.ts";
|
|
3
|
+
|
|
4
|
+
export const emailSchema = z
|
|
5
|
+
.string()
|
|
6
|
+
.email("Invalid email address")
|
|
7
|
+
.toLowerCase();
|
|
8
|
+
|
|
9
|
+
export const passwordSchema = z
|
|
10
|
+
.string()
|
|
11
|
+
.min(8, "Password must be at least 8 characters")
|
|
12
|
+
.max(72, "Password too long");
|
|
13
|
+
|
|
14
|
+
export const userSchema = z.object({
|
|
15
|
+
id: z.string().uuid(),
|
|
16
|
+
email: emailSchema,
|
|
17
|
+
name: z.string().min(1).max(100),
|
|
18
|
+
role: z.enum(USER_ROLES).default("user"),
|
|
19
|
+
provider: z.enum(AUTH_PROVIDERS).default("credentials"),
|
|
20
|
+
|
|
21
|
+
passwordHash: z.string().optional(), // credentials only
|
|
22
|
+
isEmailVerified: z.boolean().default(false),
|
|
23
|
+
|
|
24
|
+
createdAt: z.date(),
|
|
25
|
+
updatedAt: z.date(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const registerSchema = z.object({
|
|
29
|
+
name: z.string().min(1, "Name is required"),
|
|
30
|
+
email: emailSchema,
|
|
31
|
+
password: passwordSchema,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const loginSchema = z.object({
|
|
35
|
+
email: emailSchema,
|
|
36
|
+
password: z.string().min(1, "Password is required"),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const jwtPayloadSchema = z.object({
|
|
40
|
+
sub: z.string().uuid(), // user id
|
|
41
|
+
email: emailSchema,
|
|
42
|
+
role: z.enum(USER_ROLES),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const forgotPasswordSchema = z.object({
|
|
46
|
+
email: emailSchema,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export const resetPasswordSchema = z.object({
|
|
50
|
+
token: z.string().min(1),
|
|
51
|
+
newPassword: passwordSchema,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const publicUserSchema = userSchema.omit({
|
|
55
|
+
passwordHash: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Generic validate function with proper typing
|
|
59
|
+
export const validate = <T extends z.ZodTypeAny>(
|
|
60
|
+
schema: T,
|
|
61
|
+
data: unknown,
|
|
62
|
+
): z.infer<T> => {
|
|
63
|
+
return schema.parse(data);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Export inferred types for use in other files
|
|
67
|
+
export type User = z.infer<typeof userSchema>;
|
|
68
|
+
export type RegisterInput = z.infer<typeof registerSchema>;
|
|
69
|
+
export type LoginInput = z.infer<typeof loginSchema>;
|
|
70
|
+
export type JwtPayload = z.infer<typeof jwtPayloadSchema>;
|
|
71
|
+
export type ForgotPasswordInput = z.infer<typeof forgotPasswordSchema>;
|
|
72
|
+
export type ResetPasswordInput = z.infer<typeof resetPasswordSchema>;
|
|
73
|
+
export type PublicUser = z.infer<typeof publicUserSchema>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import bcrypt from "bcryptjs";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
import { registerSchema, loginSchema } from "./auth.schemas.ts";
|
|
4
|
+
import type { z } from "zod";
|
|
5
|
+
|
|
6
|
+
const SALT_ROUNDS = 10;
|
|
7
|
+
const JWT_EXPIRES_IN = "7d";
|
|
8
|
+
|
|
9
|
+
// Type definitions
|
|
10
|
+
type RegisterInput = z.infer<typeof registerSchema>;
|
|
11
|
+
type LoginInput = z.infer<typeof loginSchema>;
|
|
12
|
+
|
|
13
|
+
type User = {
|
|
14
|
+
id: string;
|
|
15
|
+
email: string;
|
|
16
|
+
name: string;
|
|
17
|
+
passwordHash: string;
|
|
18
|
+
role: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type UserRepo = {
|
|
22
|
+
findByEmail(email: string): Promise<User | null>;
|
|
23
|
+
create(data: {
|
|
24
|
+
email: string;
|
|
25
|
+
name: string;
|
|
26
|
+
passwordHash: string;
|
|
27
|
+
}): Promise<User>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type JwtPayload = {
|
|
31
|
+
sub: string;
|
|
32
|
+
email: string;
|
|
33
|
+
role: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type LoginResult = {
|
|
37
|
+
user: User;
|
|
38
|
+
token: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const AuthService = {
|
|
42
|
+
async hashPassword(password: string): Promise<string> {
|
|
43
|
+
return bcrypt.hash(password, SALT_ROUNDS);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
async comparePassword(password: string, hash: string): Promise<boolean> {
|
|
47
|
+
return bcrypt.compare(password, hash);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
signToken(payload: JwtPayload): string {
|
|
51
|
+
const secret = process.env.JWT_SECRET;
|
|
52
|
+
|
|
53
|
+
if (!secret) {
|
|
54
|
+
throw new Error("JWT_SECRET environment variable is not defined");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return jwt.sign(payload, secret, {
|
|
58
|
+
expiresIn: JWT_EXPIRES_IN,
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
async register(data: unknown, userRepo: UserRepo): Promise<User> {
|
|
63
|
+
const input: RegisterInput = registerSchema.parse(data);
|
|
64
|
+
|
|
65
|
+
const existingUser = await userRepo.findByEmail(input.email);
|
|
66
|
+
if (existingUser) {
|
|
67
|
+
throw new Error("Email already in use");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const passwordHash = await this.hashPassword(input.password);
|
|
71
|
+
|
|
72
|
+
const user = await userRepo.create({
|
|
73
|
+
email: input.email,
|
|
74
|
+
name: input.name,
|
|
75
|
+
passwordHash,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return user;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async login(data: unknown, userRepo: UserRepo): Promise<LoginResult> {
|
|
82
|
+
const input: LoginInput = loginSchema.parse(data);
|
|
83
|
+
|
|
84
|
+
const user = await userRepo.findByEmail(input.email);
|
|
85
|
+
if (!user || !user.passwordHash) {
|
|
86
|
+
throw new Error("Invalid credentials");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const isValid = await this.comparePassword(
|
|
90
|
+
input.password,
|
|
91
|
+
user.passwordHash,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (!isValid) {
|
|
95
|
+
throw new Error("Invalid credentials");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const token = this.signToken({
|
|
99
|
+
sub: user.id,
|
|
100
|
+
email: user.email,
|
|
101
|
+
role: user.role,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
return { user, token };
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -1,64 +1,80 @@
|
|
|
1
1
|
import { Request, Response } from "express";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { sendSuccess } from "../../utils/response.
|
|
4
|
-
import { asyncHandler } from "../../middlewares/errorHandler.
|
|
5
|
-
import { validateRequest } from "../../middlewares/validateRequest.js";
|
|
6
|
-
|
|
7
|
-
const healthCheckSchema = z.object({
|
|
8
|
-
query: z.object({}),
|
|
9
|
-
params: z.object({}),
|
|
10
|
-
body: z.object({}),
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const createItemSchema = z.object({
|
|
14
|
-
body: z.object({
|
|
15
|
-
name: z.string().min(1, "Name is required").max(100),
|
|
16
|
-
description: z.string().optional(),
|
|
17
|
-
}),
|
|
18
|
-
query: z.object({}),
|
|
19
|
-
params: z.object({}),
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
type CreateItemBody = z.infer<typeof createItemSchema>["body"];
|
|
3
|
+
import { sendSuccess } from "../../utils/response.ts";
|
|
4
|
+
import { asyncHandler } from "../../middlewares/errorHandler.ts";
|
|
23
5
|
|
|
24
6
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
7
|
+
* @swagger
|
|
8
|
+
* /api/health:
|
|
9
|
+
* get:
|
|
10
|
+
* summary: Health check endpoint
|
|
11
|
+
* description: Returns the health status of the API
|
|
12
|
+
* tags:
|
|
13
|
+
* - Health
|
|
14
|
+
* responses:
|
|
15
|
+
* 200:
|
|
16
|
+
* $ref: '#/components/responses/Success'
|
|
27
17
|
*/
|
|
28
|
-
export const getHealth =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
export const getHealth = asyncHandler(async (req: Request, res: Response) => {
|
|
19
|
+
sendSuccess(
|
|
20
|
+
res,
|
|
21
|
+
{
|
|
32
22
|
status: "healthy" as const,
|
|
33
23
|
uptime: process.uptime(),
|
|
34
24
|
timestamp: new Date().toISOString(),
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
},
|
|
26
|
+
200,
|
|
27
|
+
"Service is healthy",
|
|
28
|
+
);
|
|
29
|
+
});
|
|
40
30
|
|
|
41
31
|
/**
|
|
42
32
|
* Example POST endpoint with validation
|
|
43
33
|
* Demonstrates proper error handling with Zod validation
|
|
44
34
|
*/
|
|
45
|
-
export const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
35
|
+
export const createItemSchema = z.object({
|
|
36
|
+
body: z.object({
|
|
37
|
+
name: z.string().min(1, "Name is required").max(100),
|
|
38
|
+
description: z.string().optional(),
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @swagger
|
|
44
|
+
* /api/items:
|
|
45
|
+
* post:
|
|
46
|
+
* summary: Create a new item
|
|
47
|
+
* description: Example endpoint demonstrating validation with Zod
|
|
48
|
+
* tags:
|
|
49
|
+
* - Items
|
|
50
|
+
* requestBody:
|
|
51
|
+
* required: true
|
|
52
|
+
* content:
|
|
53
|
+
* application/json:
|
|
54
|
+
* schema:
|
|
55
|
+
* $ref: '#/components/schemas/createItemSchema'
|
|
56
|
+
* responses:
|
|
57
|
+
* 201:
|
|
58
|
+
* $ref: '#/components/responses/Success'
|
|
59
|
+
* 400:
|
|
60
|
+
* $ref: '#/components/responses/ValidationError'
|
|
61
|
+
*/
|
|
62
|
+
export const createItem = asyncHandler(async (req: Request, res: Response) => {
|
|
63
|
+
const parsed = createItemSchema.parse({ body: req.body });
|
|
64
|
+
const { name, description } = parsed.body;
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
// Simulate some async work
|
|
67
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
52
68
|
|
|
53
|
-
|
|
69
|
+
sendSuccess(
|
|
70
|
+
res,
|
|
71
|
+
{
|
|
54
72
|
id: Math.random().toString(36).substr(2, 9),
|
|
55
73
|
name,
|
|
56
74
|
description: description || null,
|
|
57
75
|
createdAt: new Date().toISOString(),
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
export { createItemSchema };
|
|
76
|
+
},
|
|
77
|
+
201,
|
|
78
|
+
"Item created successfully",
|
|
79
|
+
);
|
|
80
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import type { User } from "../modules/auth/auth.schemas.ts";
|
|
3
|
+
|
|
4
|
+
const users: User[] = [];
|
|
5
|
+
|
|
6
|
+
type CreateUserData = {
|
|
7
|
+
email: string;
|
|
8
|
+
name: string;
|
|
9
|
+
passwordHash: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const userRepo = {
|
|
13
|
+
async findByEmail(email: string): Promise<User | undefined> {
|
|
14
|
+
return users.find((u) => u.email === email);
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
async create(data: CreateUserData): Promise<User> {
|
|
18
|
+
const user: User = {
|
|
19
|
+
id: randomUUID(),
|
|
20
|
+
email: data.email,
|
|
21
|
+
name: data.name,
|
|
22
|
+
passwordHash: data.passwordHash,
|
|
23
|
+
role: "user",
|
|
24
|
+
provider: "credentials",
|
|
25
|
+
isEmailVerified: false,
|
|
26
|
+
createdAt: new Date(),
|
|
27
|
+
updatedAt: new Date(),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
users.push(user);
|
|
31
|
+
return user;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import {
|
|
3
|
+
getHealth,
|
|
4
|
+
createItem,
|
|
5
|
+
createItemSchema,
|
|
6
|
+
} from "../modules/health/controller.ts";
|
|
7
|
+
import { validateRequest } from "../middlewares/validateRequest.ts";
|
|
8
|
+
import protectedRoutes from "./protected.ts";
|
|
9
|
+
import authRoutes from "../modules/auth/auth.routes.ts";
|
|
10
|
+
const router = Router();
|
|
11
|
+
|
|
12
|
+
// Health check
|
|
13
|
+
router.get("/health", getHealth);
|
|
14
|
+
|
|
15
|
+
// Example: Create item with validation
|
|
16
|
+
router.post("/items", validateRequest(createItemSchema), createItem);
|
|
17
|
+
|
|
18
|
+
// 🔐 Auth routes
|
|
19
|
+
router.use("/auth", authRoutes);
|
|
20
|
+
|
|
21
|
+
// 🔐 Protected routes (REQUIRED BEARER TOKEN FOR THEM)
|
|
22
|
+
router.use("/protected", protectedRoutes);
|
|
23
|
+
|
|
24
|
+
export default router;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { requireAuth } from "../modules/auth/auth.middlewares.ts";
|
|
3
|
+
|
|
4
|
+
const router = Router();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @swagger
|
|
8
|
+
* /api/protected/me:
|
|
9
|
+
* get:
|
|
10
|
+
* summary: Get current user profile
|
|
11
|
+
* description: Returns the authenticated user's information
|
|
12
|
+
* tags:
|
|
13
|
+
* - Protected
|
|
14
|
+
* security:
|
|
15
|
+
* - bearerAuth: []
|
|
16
|
+
* responses:
|
|
17
|
+
* 200:
|
|
18
|
+
* description: User profile retrieved successfully
|
|
19
|
+
* content:
|
|
20
|
+
* application/json:
|
|
21
|
+
* schema:
|
|
22
|
+
* type: object
|
|
23
|
+
* properties:
|
|
24
|
+
* message:
|
|
25
|
+
* type: string
|
|
26
|
+
* example: You are authenticated
|
|
27
|
+
* user:
|
|
28
|
+
* type: object
|
|
29
|
+
* properties:
|
|
30
|
+
* id:
|
|
31
|
+
* type: string
|
|
32
|
+
* example: user_123abc
|
|
33
|
+
* email:
|
|
34
|
+
* type: string
|
|
35
|
+
* example: user@example.com
|
|
36
|
+
* 401:
|
|
37
|
+
* description: Unauthorized - Invalid or missing token
|
|
38
|
+
*/
|
|
39
|
+
router.get("/me", requireAuth, (req, res) => {
|
|
40
|
+
res.json({
|
|
41
|
+
message: "You are authenticated",
|
|
42
|
+
user: req.user,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export default router;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { logger } from "./utils/logger.js";
|
|
2
|
+
import { app } from "./app.ts";
|
|
3
|
+
import { env } from "./config/env.ts";
|
|
4
|
+
import { logger } from "./utils/logger.ts";
|
|
6
5
|
|
|
7
6
|
const PORT = env.PORT;
|
|
8
7
|
|
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2020",
|
|
4
4
|
"module": "ESNext",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"outDir": "./dist",
|
|
7
8
|
"strict": true,
|
|
8
9
|
"esModuleInterop": true,
|
|
9
10
|
"forceConsistentCasingInFileNames": true,
|
|
10
11
|
"skipLibCheck": true,
|
|
11
|
-
"moduleResolution": "node",
|
|
12
12
|
"resolveJsonModule": true,
|
|
13
13
|
"allowJs": false,
|
|
14
|
-
"noEmitOnError":
|
|
15
|
-
"sourceMap": true
|
|
14
|
+
"noEmitOnError": false,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"declaration": false,
|
|
17
|
+
"allowImportingTsExtensions": true,
|
|
18
|
+
"noEmit": true
|
|
16
19
|
},
|
|
17
|
-
"include": ["src
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
20
|
+
"include": ["src/**/*"],
|
|
21
|
+
"exclude": ["node_modules", "dist"],
|
|
22
|
+
"ts-node": {
|
|
23
|
+
"esm": true,
|
|
24
|
+
"experimentalSpecifierResolution": "node"
|
|
25
|
+
}
|
|
19
26
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/e/SAFEZONE/charcole
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/e/SAFEZONE/charcole
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/e/SAFEZONE/charcole
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/e/SAFEZONE/charcole
|