sk-test-node-deploy 1.0.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.
@@ -0,0 +1,47 @@
1
+ import mongoose, { Document, Schema } from 'mongoose';
2
+
3
+ export interface IUser extends Document {
4
+ name: string;
5
+ email: string;
6
+ password: string;
7
+ refreshToken?: string;
8
+ createdAt: Date;
9
+ updatedAt: Date;
10
+ }
11
+
12
+ const userSchema = new Schema<IUser>(
13
+ {
14
+ name: {
15
+ type: String,
16
+ required: [true, 'Name is required'],
17
+ trim: true,
18
+ minlength: [2, 'Name must be at least 2 characters'],
19
+ maxlength: [50, 'Name cannot exceed 50 characters']
20
+ },
21
+ email: {
22
+ type: String,
23
+ required: [true, 'Email is required'],
24
+ unique: true,
25
+ lowercase: true,
26
+ trim: true,
27
+ match: [/^\S+@\S+\.\S+$/, 'Please provide a valid email']
28
+ },
29
+ password: {
30
+ type: String,
31
+ required: [true, 'Password is required'],
32
+ minlength: [6, 'Password must be at least 6 characters'],
33
+ select: false
34
+ },
35
+ refreshToken: {
36
+ type: String,
37
+ select: false
38
+ }
39
+ },
40
+ {
41
+ timestamps: true
42
+ }
43
+ );
44
+
45
+ const User = mongoose.model<IUser>('User', userSchema);
46
+
47
+ export default User;
@@ -0,0 +1,15 @@
1
+ import { Router } from 'express';
2
+ import { authController } from '../controllers/auth.controller';
3
+ import { validate, registerSchema, loginSchema, refreshTokenSchema } from '../middlewares/validation.middleware';
4
+ import { authenticate } from '../middlewares/auth.middleware';
5
+
6
+ const authRoutes = Router();
7
+
8
+ authRoutes.post('/refresh', validate(refreshTokenSchema), authController.refreshToken);
9
+ authRoutes.post('/register', validate(registerSchema), authController.register);
10
+ authRoutes.post('/login', validate(loginSchema), authController.login);
11
+
12
+ authRoutes.post('/logout', authenticate, authController.logout);
13
+ authRoutes.get('/profile', authenticate, authController.getProfile);
14
+
15
+ export default authRoutes;
@@ -0,0 +1,11 @@
1
+ import { Router } from 'express';
2
+ import { fileController } from '../controllers/file.controller';
3
+ import { authenticate } from '../middlewares/auth.middleware';
4
+ import { uploadMiddleware } from '../middlewares/upload.middleware';
5
+
6
+ const fileRoutes = Router();
7
+
8
+ fileRoutes.use(authenticate);
9
+ fileRoutes.post('/upload', uploadMiddleware.single('file'), fileController.uploadFile);
10
+
11
+ export default fileRoutes;
@@ -0,0 +1,15 @@
1
+ import { Router } from 'express';
2
+ import { userController } from '../controllers/user.controller';
3
+ import { authenticate } from '../middlewares/auth.middleware';
4
+ import { validate, updateUserSchema } from '../middlewares/validation.middleware';
5
+
6
+ const userRoutes = Router();
7
+
8
+ userRoutes.use(authenticate);
9
+
10
+ userRoutes.get('/', userController.getAllUsers);
11
+ userRoutes.get('/:id', userController.getUserById);
12
+ userRoutes.put('/:id', validate(updateUserSchema), userController.updateUser);
13
+ userRoutes.delete('/:id', userController.deleteUser);
14
+
15
+ export default userRoutes;
@@ -0,0 +1,103 @@
1
+ import { Server, Socket } from 'socket.io';
2
+
3
+ interface Message {
4
+ username: string;
5
+ message: string;
6
+ timestamp: Date;
7
+ }
8
+
9
+ // Store active users
10
+ const activeUsers = new Map<string, string>();
11
+
12
+ export const initializeSocket = (io: Server) => {
13
+
14
+ io.on('connection', (socket: Socket) => {
15
+ console.log(`User connected: ${socket.id}`);
16
+
17
+ // Handle user joining
18
+ socket.on('join', (username: string) => {
19
+ activeUsers.set(socket.id, username);
20
+ console.log(`${username} joined the chat`);
21
+
22
+ // Notify all users
23
+ io.emit('user_joined', {
24
+ username,
25
+ timestamp: new Date(),
26
+ activeUsers: activeUsers.size
27
+ });
28
+
29
+ // Send active users list to the new user
30
+ socket.emit('active_users', {
31
+ count: activeUsers.size,
32
+ users: Array.from(activeUsers.values())
33
+ });
34
+ });
35
+
36
+ // Handle incoming messages
37
+ socket.on('message', (data: { username: string; message: string }) => {
38
+ const messageData: Message = {
39
+ username: data.username,
40
+ message: data.message,
41
+ timestamp: new Date()
42
+ };
43
+
44
+ console.log(`Message from ${data.username}: ${data.message}`);
45
+
46
+ // Broadcast message to all users
47
+ io.emit('message', messageData);
48
+ });
49
+
50
+ // Handle typing indicator
51
+ socket.on('typing', (data: { username: string; isTyping: boolean }) => {
52
+ socket.broadcast.emit('user_typing', data);
53
+ });
54
+
55
+ // Handle private messages
56
+ socket.on('private_message', (data: { to: string; message: string; from: string }) => {
57
+ // Find recipient socket
58
+ const recipientSocketId = Array.from(activeUsers.entries())
59
+ .find(([_, username]) => username === data.to)?.[0];
60
+
61
+ if (recipientSocketId) {
62
+ io.to(recipientSocketId).emit('private_message', {
63
+ from: data.from,
64
+ message: data.message,
65
+ timestamp: new Date()
66
+ });
67
+
68
+ // Send confirmation to sender
69
+ socket.emit('message_sent', {
70
+ to: data.to,
71
+ status: 'delivered'
72
+ });
73
+ } else {
74
+ socket.emit('message_sent', {
75
+ to: data.to,
76
+ status: 'user_not_found'
77
+ });
78
+ }
79
+ });
80
+
81
+ // Handle disconnection
82
+ socket.on('disconnect', () => {
83
+ const username = activeUsers.get(socket.id);
84
+ activeUsers.delete(socket.id);
85
+
86
+ console.log(`User disconnected: ${socket.id}`);
87
+
88
+ if (username) {
89
+ io.emit('user_left', {
90
+ username,
91
+ timestamp: new Date(),
92
+ activeUsers: activeUsers.size
93
+ });
94
+ }
95
+ });
96
+
97
+ // Handle errors
98
+ socket.on('error', (error) => {
99
+ console.error('Socket error:', error);
100
+ });
101
+ });
102
+
103
+ };
@@ -0,0 +1,10 @@
1
+ import { Request } from "express";
2
+
3
+ declare module "express-serve-static-core" {
4
+ interface Request {
5
+ user?: {
6
+ userId: string;
7
+ email: string;
8
+ };
9
+ }
10
+ }
@@ -0,0 +1,54 @@
1
+ import jwt from 'jsonwebtoken';
2
+
3
+ interface TokenPayload {
4
+ userId: string;
5
+ email: string;
6
+ }
7
+
8
+ export class JWTUtil {
9
+ private static secret = process.env.JWT_SECRET || 'JWT_SECRET';
10
+ private static expiresIn = (process.env.JWT_EXPIRE || '7d') as string;
11
+ private static refreshSecret = process.env.JWT_SECRET || 'JWT_SECRET';
12
+ private static refreshExpiresIn = (process.env.JWT_REFRESH_EXPIRE || '30d') as string;
13
+
14
+ // Generate access token
15
+ static generateToken(payload: TokenPayload): string {
16
+ return jwt.sign(payload, this.secret, {
17
+ expiresIn: this.expiresIn as jwt.SignOptions['expiresIn']
18
+ });
19
+ }
20
+
21
+ // Generate refresh token
22
+ static generateRefreshToken(payload: TokenPayload): string {
23
+ return jwt.sign(payload, this.refreshSecret, {
24
+ expiresIn: this.refreshExpiresIn as jwt.SignOptions['expiresIn']
25
+ });
26
+ }
27
+
28
+ // Verify access token
29
+ static verifyToken(token: string): TokenPayload | null {
30
+ try {
31
+ return jwt.verify(token, this.secret) as TokenPayload;
32
+ } catch (error) {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ // Verify refresh token
38
+ static verifyRefreshToken(token: string): TokenPayload | null {
39
+ try {
40
+ return jwt.verify(token, this.refreshSecret) as TokenPayload;
41
+ } catch (error) {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ // Decode token without verification
47
+ static decodeToken(token: string): any {
48
+ try {
49
+ return jwt.decode(token);
50
+ } catch (error) {
51
+ return null;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,27 @@
1
+ import Joi from 'joi';
2
+
3
+ export const registerSchema = Joi.object({
4
+ name: Joi.string().min(2).max(50).required().messages({
5
+ 'string.empty': 'Name is required',
6
+ 'string.min': 'Name must be at least 2 characters',
7
+ 'string.max': 'Name cannot exceed 50 characters'
8
+ }),
9
+ email: Joi.string().email().required().messages({
10
+ 'string.empty': 'Email is required',
11
+ 'string.email': 'Please provide a valid email address'
12
+ }),
13
+ password: Joi.string().min(6).required().messages({
14
+ 'string.empty': 'Password is required',
15
+ 'string.min': 'Password must be at least 6 characters'
16
+ })
17
+ });
18
+
19
+ export const loginSchema = Joi.object({
20
+ email: Joi.string().email().required().messages({
21
+ 'string.empty': 'Email is required',
22
+ 'string.email': 'Please provide a valid email address'
23
+ }),
24
+ password: Joi.string().required().messages({
25
+ 'string.empty': 'Password is required'
26
+ })
27
+ });
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": [
6
+ "ES2020"
7
+ ],
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "strict": true,
11
+ "esModuleInterop": true,
12
+ "skipLibCheck": true,
13
+ "forceConsistentCasingInFileNames": true,
14
+ "resolveJsonModule": true,
15
+ "moduleResolution": "node",
16
+ "typeRoots": [
17
+ "./node_modules/@types",
18
+ "./src/types",
19
+ "./types"
20
+ ]
21
+ },
22
+ "ts-node": {
23
+ "files": true
24
+ },
25
+ "include": [
26
+ "src/**/*"
27
+ ],
28
+ "exclude": [
29
+ "node_modules"
30
+ ]
31
+ }